boris-behav-obs 9.7.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- boris/__init__.py +26 -0
- boris/__main__.py +25 -0
- boris/about.py +143 -0
- boris/add_modifier.py +635 -0
- boris/add_modifier_ui.py +303 -0
- boris/advanced_event_filtering.py +455 -0
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_latency.py +59 -0
- boris/analysis_plugins/irr_cohen_kappa.py +109 -0
- boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
- boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
- boris/analysis_plugins/number_of_occurences.py +22 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
- boris/analysis_plugins/time_budget.py +61 -0
- boris/behav_coding_map_creator.py +1110 -0
- boris/behavior_binary_table.py +305 -0
- boris/behaviors_coding_map.py +239 -0
- boris/boris_cli.py +340 -0
- boris/cmd_arguments.py +49 -0
- boris/coding_pad.py +280 -0
- boris/config.py +785 -0
- boris/config_file.py +356 -0
- boris/connections.py +409 -0
- boris/converters.py +333 -0
- boris/converters_ui.py +225 -0
- boris/cooccurence.py +250 -0
- boris/core.py +5901 -0
- boris/core_qrc.py +15958 -0
- boris/core_ui.py +1107 -0
- boris/db_functions.py +324 -0
- boris/dev.py +134 -0
- boris/dialog.py +1108 -0
- boris/duration_widget.py +238 -0
- boris/edit_event.py +245 -0
- boris/edit_event_ui.py +233 -0
- boris/event_operations.py +1040 -0
- boris/events_cursor.py +61 -0
- boris/events_snapshots.py +596 -0
- boris/exclusion_matrix.py +141 -0
- boris/export_events.py +1006 -0
- boris/export_observation.py +1203 -0
- boris/external_processes.py +332 -0
- boris/geometric_measurement.py +941 -0
- boris/gui_utilities.py +135 -0
- boris/image_overlay.py +72 -0
- boris/import_observations.py +242 -0
- boris/ipc_mpv.py +325 -0
- boris/irr.py +634 -0
- boris/latency.py +244 -0
- boris/measurement_widget.py +161 -0
- boris/media_file.py +115 -0
- boris/menu_options.py +213 -0
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +157 -0
- boris/mpv.py +2016 -0
- boris/mpv2.py +2193 -0
- boris/observation.py +1453 -0
- boris/observation_operations.py +2538 -0
- boris/observation_ui.py +679 -0
- boris/observations_list.py +337 -0
- boris/otx_parser.py +442 -0
- boris/param_panel.py +201 -0
- boris/param_panel_ui.py +305 -0
- boris/player_dock_widget.py +198 -0
- boris/plot_data_module.py +536 -0
- boris/plot_events.py +634 -0
- boris/plot_events_rt.py +237 -0
- boris/plot_spectrogram_rt.py +316 -0
- boris/plot_waveform_rt.py +230 -0
- boris/plugins.py +431 -0
- boris/portion/__init__.py +31 -0
- boris/portion/const.py +95 -0
- boris/portion/dict.py +365 -0
- boris/portion/func.py +52 -0
- boris/portion/interval.py +581 -0
- boris/portion/io.py +181 -0
- boris/preferences.py +510 -0
- boris/preferences_ui.py +770 -0
- boris/project.py +2007 -0
- boris/project_functions.py +2041 -0
- boris/project_import_export.py +1096 -0
- boris/project_ui.py +794 -0
- boris/qrc_boris.py +10389 -0
- boris/qrc_boris5.py +2579 -0
- boris/select_modifiers.py +312 -0
- boris/select_observations.py +210 -0
- boris/select_subj_behav.py +286 -0
- boris/state_events.py +197 -0
- boris/subjects_pad.py +106 -0
- boris/synthetic_time_budget.py +290 -0
- boris/time_budget_functions.py +1136 -0
- boris/time_budget_widget.py +1039 -0
- boris/transitions.py +365 -0
- boris/utilities.py +1810 -0
- boris/version.py +24 -0
- boris/video_equalizer.py +159 -0
- boris/video_equalizer_ui.py +248 -0
- boris/video_operations.py +310 -0
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +538 -0
- boris_behav_obs-9.7.7.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.7.dist-info/RECORD +109 -0
- boris_behav_obs-9.7.7.dist-info/WHEEL +5 -0
- boris_behav_obs-9.7.7.dist-info/entry_points.txt +2 -0
- boris_behav_obs-9.7.7.dist-info/licenses/LICENSE.TXT +674 -0
- boris_behav_obs-9.7.7.dist-info/top_level.txt +1 -0
boris/db_functions.py
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BORIS
|
|
3
|
+
Behavioral Observation Research Interactive Software
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
This program is free software; you can redistribute it and/or modify
|
|
8
|
+
it under the terms of the GNU General Public License as published by
|
|
9
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
10
|
+
(at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program; if not, write to the Free Software
|
|
19
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
20
|
+
MA 02110-1301, USA.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import sqlite3
|
|
25
|
+
import logging
|
|
26
|
+
from typing import Optional, Tuple
|
|
27
|
+
from . import config as cfg
|
|
28
|
+
from . import project_functions
|
|
29
|
+
from . import event_operations
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def load_events_in_db(
|
|
33
|
+
pj: dict,
|
|
34
|
+
selected_subjects: list,
|
|
35
|
+
selected_observations: list,
|
|
36
|
+
selected_behaviors: list,
|
|
37
|
+
time_interval: str = cfg.TIME_FULL_OBS,
|
|
38
|
+
):
|
|
39
|
+
"""
|
|
40
|
+
populate a memory sqlite database with events from selected_observations,
|
|
41
|
+
selected_subjects and selected_behaviors
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
pj (dict): project dictionary
|
|
45
|
+
selected_observations (list):
|
|
46
|
+
selected_subjects (list):
|
|
47
|
+
selected_behaviors (list):
|
|
48
|
+
time_interval (str): time interval for loading events (cfg.TIME_FULL_OBS / TIME_cfg.EVENTS / TIME_ARBITRARY_INTERVAL)
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
database cursor:
|
|
52
|
+
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# selected behaviors defined as state event
|
|
56
|
+
state_behaviors_codes = [
|
|
57
|
+
pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
|
|
58
|
+
for x in pj[cfg.ETHOGRAM]
|
|
59
|
+
if cfg.STATE in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper() and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
# selected behaviors defined as point event
|
|
63
|
+
"""
|
|
64
|
+
point_behaviors_codes = [
|
|
65
|
+
pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
|
|
66
|
+
for x in pj[cfg.ETHOGRAM]
|
|
67
|
+
if cfg.POINT in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper()
|
|
68
|
+
and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
|
|
69
|
+
]
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
db = sqlite3.connect(":memory:", isolation_level=None)
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
import os
|
|
76
|
+
os.system("rm /tmp/ramdisk/events.sqlite")
|
|
77
|
+
db = sqlite3.connect("/tmp/ramdisk/events.sqlite", isolation_level=None)
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
db.row_factory = sqlite3.Row
|
|
81
|
+
cursor = db.cursor()
|
|
82
|
+
cursor.execute(
|
|
83
|
+
(
|
|
84
|
+
"CREATE TABLE events (observation TEXT, "
|
|
85
|
+
"subject TEXT, "
|
|
86
|
+
"code TEXT, "
|
|
87
|
+
"type TEXT, "
|
|
88
|
+
"modifiers TEXT, "
|
|
89
|
+
"occurence FLOAT, "
|
|
90
|
+
"comment TEXT,"
|
|
91
|
+
"image_index INTEGER,"
|
|
92
|
+
"image_path TEXT)"
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
cursor.execute("CREATE INDEX observation_idx ON events(observation)")
|
|
97
|
+
cursor.execute("CREATE INDEX subject_idx ON events(subject)")
|
|
98
|
+
cursor.execute("CREATE INDEX code_idx ON events(code)")
|
|
99
|
+
cursor.execute("CREATE INDEX modifiers_idx ON events(modifiers)")
|
|
100
|
+
|
|
101
|
+
for subject_to_analyze in selected_subjects:
|
|
102
|
+
for obs_id in selected_observations:
|
|
103
|
+
for event in pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]:
|
|
104
|
+
if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in selected_behaviors:
|
|
105
|
+
# extract time, code, modifier and comment (time:0, subject:1, code:2, modifier:3, comment:4)
|
|
106
|
+
if (subject_to_analyze == cfg.NO_FOCAL_SUBJECT and event[cfg.EVENT_SUBJECT_FIELD_IDX] == "") or (
|
|
107
|
+
event[cfg.EVENT_SUBJECT_FIELD_IDX] == subject_to_analyze
|
|
108
|
+
):
|
|
109
|
+
if pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
|
|
110
|
+
cursor.execute(
|
|
111
|
+
(
|
|
112
|
+
"INSERT INTO events "
|
|
113
|
+
"(observation, subject, code, type, modifiers, occurence, comment, image_index) "
|
|
114
|
+
"VALUES (?,?,?,?,?,?,?,?)"
|
|
115
|
+
),
|
|
116
|
+
(
|
|
117
|
+
obs_id,
|
|
118
|
+
cfg.NO_FOCAL_SUBJECT
|
|
119
|
+
if event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""
|
|
120
|
+
else event[cfg.EVENT_SUBJECT_FIELD_IDX],
|
|
121
|
+
event[cfg.EVENT_BEHAVIOR_FIELD_IDX],
|
|
122
|
+
cfg.STATE if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in state_behaviors_codes else cfg.POINT,
|
|
123
|
+
event[cfg.EVENT_MODIFIER_FIELD_IDX],
|
|
124
|
+
float(event[cfg.EVENT_TIME_FIELD_IDX]) if not event[cfg.EVENT_TIME_FIELD_IDX].is_nan() else None,
|
|
125
|
+
event[cfg.EVENT_COMMENT_FIELD_IDX],
|
|
126
|
+
# frame index or NA
|
|
127
|
+
event_operations.read_event_field(event, pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE], cfg.FRAME_INDEX),
|
|
128
|
+
),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] == cfg.IMAGES:
|
|
132
|
+
cursor.execute(
|
|
133
|
+
(
|
|
134
|
+
"INSERT INTO events "
|
|
135
|
+
"(observation, subject, code, type, modifiers, occurence, comment, image_index, image_path) "
|
|
136
|
+
"VALUES (?,?,?,?,?,?,?,?,?)"
|
|
137
|
+
),
|
|
138
|
+
(
|
|
139
|
+
obs_id,
|
|
140
|
+
cfg.NO_FOCAL_SUBJECT
|
|
141
|
+
if event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""
|
|
142
|
+
else event[cfg.EVENT_SUBJECT_FIELD_IDX],
|
|
143
|
+
event[cfg.EVENT_BEHAVIOR_FIELD_IDX],
|
|
144
|
+
cfg.STATE if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in state_behaviors_codes else cfg.POINT,
|
|
145
|
+
event[cfg.EVENT_MODIFIER_FIELD_IDX],
|
|
146
|
+
float(event[cfg.EVENT_TIME_FIELD_IDX]) if not event[cfg.EVENT_TIME_FIELD_IDX].is_nan() else None,
|
|
147
|
+
event[cfg.EVENT_COMMENT_FIELD_IDX],
|
|
148
|
+
event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_INDEX]],
|
|
149
|
+
event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_PATH]],
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
db.commit()
|
|
154
|
+
return cursor
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def load_aggregated_events_in_db(
|
|
158
|
+
pj: dict, selected_subjects: list, selected_observations: list, selected_behaviors: list
|
|
159
|
+
) -> Tuple[bool, str, Optional[sqlite3.Connection]]:
|
|
160
|
+
"""
|
|
161
|
+
populate a memory sqlite database with aggregated events from selected_observations, selected_subjects and selected_behaviors
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
pj (dict): project dictionary
|
|
165
|
+
selected_observations (list):
|
|
166
|
+
selected_subjects (list):
|
|
167
|
+
selected_behaviors (list):
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
bool: True if OK else False
|
|
171
|
+
str: error message
|
|
172
|
+
database connector: db connector if bool True else None
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
logging.debug("function: load_aggregated_events_in_db")
|
|
177
|
+
|
|
178
|
+
# if no observation selected select all
|
|
179
|
+
if not selected_observations:
|
|
180
|
+
selected_observations = sorted([x for x in pj[cfg.OBSERVATIONS]])
|
|
181
|
+
|
|
182
|
+
# if no subject selected select all
|
|
183
|
+
if not selected_subjects:
|
|
184
|
+
selected_subjects = sorted([pj[cfg.SUBJECTS][x][cfg.SUBJECT_NAME] for x in pj[cfg.SUBJECTS]] + [cfg.NO_FOCAL_SUBJECT])
|
|
185
|
+
|
|
186
|
+
# if no behavior selected select all
|
|
187
|
+
if not selected_behaviors:
|
|
188
|
+
selected_behaviors = sorted([pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] for x in pj[cfg.ETHOGRAM]])
|
|
189
|
+
|
|
190
|
+
# check if state events are paired
|
|
191
|
+
out: str = ""
|
|
192
|
+
for obs_id in selected_observations:
|
|
193
|
+
r, msg = project_functions.check_state_events_obs(obs_id, pj[cfg.ETHOGRAM], pj[cfg.OBSERVATIONS][obs_id], cfg.HHMMSS)
|
|
194
|
+
if not r:
|
|
195
|
+
out += f"Observation: <strong>{obs_id}</strong><br>{msg}<br>"
|
|
196
|
+
if out:
|
|
197
|
+
return False, out, None
|
|
198
|
+
|
|
199
|
+
# selected behaviors defined as state event
|
|
200
|
+
state_behaviors_codes = [
|
|
201
|
+
pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
|
|
202
|
+
for x in pj[cfg.ETHOGRAM]
|
|
203
|
+
if cfg.STATE in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper() and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
# selected behaviors defined as point event
|
|
207
|
+
point_behaviors_codes = [
|
|
208
|
+
pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
|
|
209
|
+
for x in pj[cfg.ETHOGRAM]
|
|
210
|
+
if cfg.POINT in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper() and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
db = sqlite3.connect(":memory:")
|
|
214
|
+
|
|
215
|
+
# only for debugging
|
|
216
|
+
"""
|
|
217
|
+
import os
|
|
218
|
+
os.system("rm /tmp/ramdisk/aggregated_events.sqlite")
|
|
219
|
+
db = sqlite3.connect("/tmp/ramdisk/aggregated_events.sqlite", isolation_level=None)
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
db.row_factory = sqlite3.Row
|
|
223
|
+
cursor2 = db.cursor()
|
|
224
|
+
cursor2.execute(
|
|
225
|
+
(
|
|
226
|
+
"CREATE TABLE aggregated_events "
|
|
227
|
+
"(id INTEGER PRIMARY KEY ASC, "
|
|
228
|
+
"observation TEXT, "
|
|
229
|
+
"subject TEXT, "
|
|
230
|
+
"behavior TEXT, "
|
|
231
|
+
"type TEXT, "
|
|
232
|
+
"modifiers TEXT, "
|
|
233
|
+
"start FLOAT, "
|
|
234
|
+
"stop FLOAT, "
|
|
235
|
+
"comment TEXT, "
|
|
236
|
+
"comment_stop TEXT,"
|
|
237
|
+
"image_index_start INTEGER,"
|
|
238
|
+
"image_index_stop INTEGER,"
|
|
239
|
+
"image_path_start TEXT,"
|
|
240
|
+
"image_path_stop TEXT)"
|
|
241
|
+
)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
cursor2.execute("CREATE INDEX observation_idx ON aggregated_events(observation)")
|
|
245
|
+
cursor2.execute("CREATE INDEX subject_idx ON aggregated_events(subject)")
|
|
246
|
+
cursor2.execute("CREATE INDEX behavior_idx ON aggregated_events(behavior)")
|
|
247
|
+
cursor2.execute("CREATE INDEX modifiers_idx ON aggregated_events(modifiers)")
|
|
248
|
+
|
|
249
|
+
# too slow! cursor1 = load_events_in_db(pj, selected_subjects, selected_observations, selected_behaviors)
|
|
250
|
+
|
|
251
|
+
insert_sql = (
|
|
252
|
+
"INSERT INTO aggregated_events (observation, subject, behavior, type, modifiers, "
|
|
253
|
+
" start, stop, comment, comment_stop, "
|
|
254
|
+
"image_index_start, image_index_stop, image_path_start, image_path_stop) "
|
|
255
|
+
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
for obs_id in selected_observations:
|
|
259
|
+
cursor1 = load_events_in_db(pj, selected_subjects, [obs_id], selected_behaviors)
|
|
260
|
+
|
|
261
|
+
for subject in selected_subjects:
|
|
262
|
+
for behavior in selected_behaviors:
|
|
263
|
+
cursor1.execute(
|
|
264
|
+
"SELECT DISTINCT modifiers FROM events WHERE subject=? AND code=? ORDER BY modifiers",
|
|
265
|
+
(
|
|
266
|
+
subject,
|
|
267
|
+
behavior,
|
|
268
|
+
),
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
rows_distinct_modifiers = list(x[0] for x in cursor1.fetchall())
|
|
272
|
+
|
|
273
|
+
for distinct_modifiers in rows_distinct_modifiers:
|
|
274
|
+
cursor1.execute(
|
|
275
|
+
(
|
|
276
|
+
"SELECT occurence, comment, image_index, image_path FROM events "
|
|
277
|
+
"WHERE subject = ? AND code = ? AND modifiers = ? ORDER by occurence"
|
|
278
|
+
),
|
|
279
|
+
(subject, behavior, distinct_modifiers),
|
|
280
|
+
)
|
|
281
|
+
rows = list(cursor1.fetchall())
|
|
282
|
+
|
|
283
|
+
for idx, row in enumerate(rows):
|
|
284
|
+
if behavior in point_behaviors_codes:
|
|
285
|
+
data = (
|
|
286
|
+
obs_id,
|
|
287
|
+
subject,
|
|
288
|
+
behavior,
|
|
289
|
+
cfg.POINT,
|
|
290
|
+
distinct_modifiers,
|
|
291
|
+
row["occurence"],
|
|
292
|
+
row["occurence"],
|
|
293
|
+
row["comment"],
|
|
294
|
+
"", # no stop comment for point event
|
|
295
|
+
row["image_index"],
|
|
296
|
+
row["image_index"],
|
|
297
|
+
row["image_path"],
|
|
298
|
+
row["image_path"],
|
|
299
|
+
)
|
|
300
|
+
cursor2.execute(insert_sql, data)
|
|
301
|
+
|
|
302
|
+
if behavior in state_behaviors_codes:
|
|
303
|
+
if idx % 2 == 0:
|
|
304
|
+
data = (
|
|
305
|
+
obs_id,
|
|
306
|
+
subject,
|
|
307
|
+
behavior,
|
|
308
|
+
cfg.STATE,
|
|
309
|
+
distinct_modifiers,
|
|
310
|
+
row["occurence"],
|
|
311
|
+
rows[idx + 1]["occurence"],
|
|
312
|
+
row["comment"],
|
|
313
|
+
rows[idx + 1]["comment"],
|
|
314
|
+
row["image_index"],
|
|
315
|
+
rows[idx + 1]["image_index"],
|
|
316
|
+
row["image_path"],
|
|
317
|
+
rows[idx + 1]["image_path"],
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
cursor2.execute(insert_sql, data)
|
|
321
|
+
|
|
322
|
+
db.commit()
|
|
323
|
+
|
|
324
|
+
return True, "", db
|
boris/dev.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import time
|
|
3
|
+
import pprint
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from . import project_functions
|
|
7
|
+
from . import config as cfg
|
|
8
|
+
from . import utilities as util
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def event_val(event, field, obs_type: str = cfg.MEDIA):
|
|
12
|
+
try:
|
|
13
|
+
return event[cfg.PJ_OBS_FIELDS[obs_type][field]]
|
|
14
|
+
except:
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_, _, pj, _ = project_functions.open_project_json(sys.argv[1])
|
|
19
|
+
|
|
20
|
+
# pprint.pprint(list(pj[cfg.OBSERVATIONS].keys()))
|
|
21
|
+
|
|
22
|
+
# print()
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
obs_id = "images NO TIME"
|
|
26
|
+
pprint.pprint(pj[cfg.OBSERVATIONS][obs_id])
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
state_events_list = util.state_behavior_codes(pj[cfg.ETHOGRAM])
|
|
30
|
+
|
|
31
|
+
df_def = {
|
|
32
|
+
"observation id": pd.Series(dtype="str"),
|
|
33
|
+
"observation type": pd.Series(dtype="str"),
|
|
34
|
+
"observation description": pd.Series(dtype="str"),
|
|
35
|
+
"subject": pd.Series(dtype="str"),
|
|
36
|
+
"behavior": pd.Series(dtype="str"),
|
|
37
|
+
"modifier": pd.Series(dtype="str"),
|
|
38
|
+
"start": pd.Series(dtype="float"),
|
|
39
|
+
"stop": pd.Series(dtype="float"),
|
|
40
|
+
"duration": pd.Series(dtype="float"),
|
|
41
|
+
}
|
|
42
|
+
df = pd.DataFrame(df_def)
|
|
43
|
+
l = []
|
|
44
|
+
# print(df.info)
|
|
45
|
+
|
|
46
|
+
for obs_id in pj[cfg.OBSERVATIONS]:
|
|
47
|
+
# print(obs_id)
|
|
48
|
+
obs_type = pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE]
|
|
49
|
+
obs_descr = pj[cfg.OBSERVATIONS][obs_id][cfg.DESCRIPTION]
|
|
50
|
+
mem_idx = []
|
|
51
|
+
for idx, event in enumerate(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]):
|
|
52
|
+
if idx in mem_idx:
|
|
53
|
+
continue
|
|
54
|
+
start = event_val(event, cfg.TIME)
|
|
55
|
+
subject = event_val(event, cfg.SUBJECT)
|
|
56
|
+
behavior = event_val(event, cfg.BEHAVIOR_CODE)
|
|
57
|
+
modifier = event_val(event, cfg.MODIFIER)
|
|
58
|
+
if behavior in state_events_list:
|
|
59
|
+
stop = None
|
|
60
|
+
for idx2, event2 in enumerate(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS][idx + 1 :], start=idx + 1):
|
|
61
|
+
subject2 = event_val(event2, cfg.SUBJECT)
|
|
62
|
+
behavior2 = event_val(event2, cfg.BEHAVIOR_CODE)
|
|
63
|
+
modifier2 = event_val(event2, cfg.MODIFIER)
|
|
64
|
+
if subject == subject2 and behavior == behavior2 and modifier == modifier2:
|
|
65
|
+
stop = event_val(event2, cfg.TIME)
|
|
66
|
+
mem_idx.append(idx2)
|
|
67
|
+
l.append([obs_id, obs_type, obs_descr, subject, behavior, modifier, start, stop, stop - start])
|
|
68
|
+
break
|
|
69
|
+
if stop is None:
|
|
70
|
+
print(obs_id, " not paired")
|
|
71
|
+
# print(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS])
|
|
72
|
+
# print(f"{l=}")
|
|
73
|
+
# print(f"{mem_idx=}")
|
|
74
|
+
|
|
75
|
+
sys.exit()
|
|
76
|
+
else:
|
|
77
|
+
l.append([obs_id, obs_type, obs_descr, subject, behavior, modifier, start, start, 0])
|
|
78
|
+
|
|
79
|
+
# print(pd.DataFrame(l))
|
|
80
|
+
df = pd.concat(
|
|
81
|
+
[
|
|
82
|
+
df,
|
|
83
|
+
pd.DataFrame(
|
|
84
|
+
l,
|
|
85
|
+
columns=[
|
|
86
|
+
"observation id",
|
|
87
|
+
"observation type",
|
|
88
|
+
"observation description",
|
|
89
|
+
"subject",
|
|
90
|
+
"behavior",
|
|
91
|
+
"modifier",
|
|
92
|
+
"start",
|
|
93
|
+
"stop",
|
|
94
|
+
"duration",
|
|
95
|
+
],
|
|
96
|
+
),
|
|
97
|
+
]
|
|
98
|
+
)
|
|
99
|
+
del l
|
|
100
|
+
print("=" * 30)
|
|
101
|
+
print("describe")
|
|
102
|
+
print(df.describe())
|
|
103
|
+
print("=" * 30)
|
|
104
|
+
|
|
105
|
+
# print(f'{df["subject"].value_counts()=}')
|
|
106
|
+
# print(f'{df["subject"].nunique()=}')
|
|
107
|
+
|
|
108
|
+
pd.set_option("display.max_rows", None, "display.max_columns", None)
|
|
109
|
+
|
|
110
|
+
print("=" * 30)
|
|
111
|
+
print("mean")
|
|
112
|
+
r = df.groupby(["subject", "behavior"])["duration"].mean()
|
|
113
|
+
print(r)
|
|
114
|
+
print("=" * 30)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
r = df.groupby(["observation id", "subject", "behavior"])
|
|
118
|
+
print(r["start"])
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
"""
|
|
122
|
+
# replace value (for selecting a time interval)
|
|
123
|
+
t1 = time.time()
|
|
124
|
+
df.loc[df["stop"] > 10, "stop"] = 10
|
|
125
|
+
print(time.time() - t1)
|
|
126
|
+
print(df)
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
t1 = 1
|
|
132
|
+
t2 = 2
|
|
133
|
+
print(df.query(f"`start` <= {t1} & `stop` >= {t2} & `duration` != 0"))
|
|
134
|
+
"""
|