boris-behav-obs 8.9.16__py3-none-any.whl → 9.7.6__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.
Potentially problematic release.
This version of boris-behav-obs might be problematic. Click here for more details.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +36 -39
- boris/add_modifier.py +122 -109
- boris/add_modifier_ui.py +239 -135
- boris/advanced_event_filtering.py +81 -45
- 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 +228 -229
- boris/behavior_binary_table.py +33 -50
- boris/behaviors_coding_map.py +17 -18
- boris/boris_cli.py +6 -25
- boris/cmd_arguments.py +12 -1
- boris/coding_pad.py +42 -49
- boris/config.py +161 -77
- boris/config_file.py +63 -83
- boris/connections.py +112 -57
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2511 -1824
- boris/core_qrc.py +15895 -10185
- boris/core_ui.py +946 -792
- boris/db_functions.py +21 -41
- boris/dev.py +134 -0
- boris/dialog.py +505 -244
- boris/duration_widget.py +15 -20
- boris/edit_event.py +84 -28
- boris/edit_event_ui.py +214 -78
- boris/event_operations.py +517 -415
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +213 -583
- boris/export_observation.py +98 -611
- boris/external_processes.py +156 -97
- boris/geometric_measurement.py +652 -287
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +9 -9
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +325 -0
- boris/irr.py +26 -63
- boris/latency.py +34 -25
- boris/measurement_widget.py +14 -18
- boris/media_file.py +52 -84
- boris/menu_options.py +17 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv.py +1 -0
- boris/mpv2.py +732 -705
- boris/observation.py +655 -310
- boris/observation_operations.py +1036 -404
- boris/observation_ui.py +584 -356
- boris/observations_list.py +71 -53
- boris/otx_parser.py +74 -80
- boris/param_panel.py +31 -16
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +90 -60
- boris/plot_data_module.py +43 -46
- boris/plot_events.py +127 -90
- boris/plot_events_rt.py +17 -31
- boris/plot_spectrogram_rt.py +95 -30
- boris/plot_waveform_rt.py +32 -21
- boris/plugins.py +431 -0
- boris/portion/__init__.py +18 -8
- boris/portion/const.py +35 -18
- boris/portion/dict.py +5 -5
- boris/portion/func.py +2 -2
- boris/portion/interval.py +21 -41
- boris/portion/io.py +41 -32
- boris/preferences.py +306 -83
- boris/preferences_ui.py +685 -228
- boris/project.py +448 -293
- boris/project_functions.py +689 -254
- boris/project_import_export.py +213 -222
- boris/project_ui.py +674 -438
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +74 -48
- boris/select_observations.py +20 -199
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +53 -37
- boris/subjects_pad.py +6 -9
- boris/synthetic_time_budget.py +45 -28
- boris/time_budget_functions.py +171 -171
- boris/time_budget_widget.py +84 -114
- boris/transitions.py +41 -47
- boris/utilities.py +766 -266
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +125 -28
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +538 -0
- boris_behav_obs-9.7.6.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.6.dist-info/RECORD +109 -0
- {boris_behav_obs-8.9.16.dist-info → boris_behav_obs-9.7.6.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.6.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/boris_ui.py +0 -886
- boris/converters.ui +0 -289
- boris/core.qrc +0 -35
- boris/core.ui +0 -1543
- boris/edit_event.ui +0 -175
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -850
- boris/observation.ui +0 -773
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1069
- boris/project_server.py +0 -236
- boris/vlc.py +0 -10343
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.9.16.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.9.16.dist-info/METADATA +0 -129
- boris_behav_obs-8.9.16.dist-info/RECORD +0 -108
- boris_behav_obs-8.9.16.dist-info/entry_points.txt +0 -2
- {boris → boris_behav_obs-9.7.6.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.9.16.dist-info → boris_behav_obs-9.7.6.dist-info}/top_level.txt +0 -0
boris/export_observation.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This program is free software; you can redistribute it and/or modify
|
|
7
7
|
it under the terms of the GNU General Public License as published by
|
|
@@ -29,7 +29,7 @@ import math
|
|
|
29
29
|
import pathlib
|
|
30
30
|
from io import StringIO
|
|
31
31
|
import pandas as pd
|
|
32
|
-
from typing import
|
|
32
|
+
from typing import Tuple
|
|
33
33
|
|
|
34
34
|
try:
|
|
35
35
|
import pyreadr
|
|
@@ -44,6 +44,7 @@ from . import utilities as util
|
|
|
44
44
|
from . import project_functions
|
|
45
45
|
from . import observation_operations
|
|
46
46
|
from . import db_functions
|
|
47
|
+
from . import event_operations
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
def export_events_jwatcher(
|
|
@@ -65,7 +66,6 @@ def export_events_jwatcher(
|
|
|
65
66
|
str: error message
|
|
66
67
|
"""
|
|
67
68
|
for subject in parameters[cfg.SELECTED_SUBJECTS]:
|
|
68
|
-
|
|
69
69
|
# select events for current subject
|
|
70
70
|
events = []
|
|
71
71
|
for event in observation[cfg.EVENTS]:
|
|
@@ -79,9 +79,7 @@ def export_events_jwatcher(
|
|
|
79
79
|
|
|
80
80
|
total_length = 0 # in seconds
|
|
81
81
|
if observation[cfg.EVENTS]:
|
|
82
|
-
total_length =
|
|
83
|
-
observation[cfg.EVENTS][-1][0] - observation[cfg.EVENTS][0][0]
|
|
84
|
-
) # last event time - first event time
|
|
82
|
+
total_length = observation[cfg.EVENTS][-1][0] - observation[cfg.EVENTS][0][0] # last event time - first event time
|
|
85
83
|
|
|
86
84
|
file_name_subject = str(pathlib.Path(file_name).parent / pathlib.Path(file_name).stem) + "_" + subject + ".dat"
|
|
87
85
|
|
|
@@ -119,14 +117,13 @@ def export_events_jwatcher(
|
|
|
119
117
|
behav_code = event[cfg.EVENT_BEHAVIOR_FIELD_IDX]
|
|
120
118
|
|
|
121
119
|
try:
|
|
122
|
-
behavior_key = [
|
|
123
|
-
ethogram[k][cfg.BEHAVIOR_KEY] for k in ethogram if ethogram[k][cfg.BEHAVIOR_CODE] == behav_code
|
|
124
|
-
][0]
|
|
120
|
+
behavior_key = [ethogram[k][cfg.BEHAVIOR_KEY] for k in ethogram if ethogram[k][cfg.BEHAVIOR_CODE] == behav_code][0]
|
|
125
121
|
except Exception:
|
|
126
122
|
# coded behavior not defined in ethogram
|
|
127
123
|
continue
|
|
128
|
-
if [ethogram[k][cfg.TYPE] for k in ethogram if ethogram[k][cfg.BEHAVIOR_CODE] == behav_code]
|
|
129
|
-
cfg.STATE_EVENT
|
|
124
|
+
if [ethogram[k][cfg.TYPE] for k in ethogram if ethogram[k][cfg.BEHAVIOR_CODE] == behav_code] in [
|
|
125
|
+
[cfg.STATE_EVENT],
|
|
126
|
+
[cfg.STATE_EVENT_WITH_CODING_MAP],
|
|
130
127
|
]:
|
|
131
128
|
if behav_code in mem_number_of_state_events:
|
|
132
129
|
mem_number_of_state_events[behav_code] += 1
|
|
@@ -154,7 +151,7 @@ def export_events_jwatcher(
|
|
|
154
151
|
if fmf_file_path.exists():
|
|
155
152
|
fmf_creation_answer = dialog.MessageDialog(
|
|
156
153
|
cfg.programName,
|
|
157
|
-
(f"The {fmf_file_path} file already exists.<br>
|
|
154
|
+
(f"The {fmf_file_path} file already exists.<br>What do you want to do?"),
|
|
158
155
|
[cfg.OVERWRITE, "Skip file creation", cfg.CANCEL],
|
|
159
156
|
)
|
|
160
157
|
|
|
@@ -167,11 +164,9 @@ def export_events_jwatcher(
|
|
|
167
164
|
rows.append("# Format: Focal Master File 1.0")
|
|
168
165
|
rows.append(f"# Updated: {dt.datetime.now().isoformat()}")
|
|
169
166
|
rows.append("#-----------------------------------------------------------")
|
|
170
|
-
for
|
|
167
|
+
for behav, key in all_observed_behaviors:
|
|
171
168
|
rows.append(f"Behaviour.name.{key}={behav}")
|
|
172
|
-
behav_description = [
|
|
173
|
-
ethogram[k][cfg.DESCRIPTION] for k in ethogram if ethogram[k][cfg.BEHAVIOR_CODE] == behav
|
|
174
|
-
][0]
|
|
169
|
+
behav_description = [ethogram[k][cfg.DESCRIPTION] for k in ethogram if ethogram[k][cfg.BEHAVIOR_CODE] == behav][0]
|
|
175
170
|
rows.append(f"Behaviour.description.{key}={behav_description}")
|
|
176
171
|
|
|
177
172
|
rows.append(f"DurationMilliseconds={int(float(total_length) * 1000)}")
|
|
@@ -198,7 +193,7 @@ def export_events_jwatcher(
|
|
|
198
193
|
if faf_file_path.exists():
|
|
199
194
|
faf_creation_answer = dialog.MessageDialog(
|
|
200
195
|
cfg.programName,
|
|
201
|
-
(f"The {faf_file_path} file already exists.<br>
|
|
196
|
+
(f"The {faf_file_path} file already exists.<br>What do you want to do?"),
|
|
202
197
|
[cfg.OVERWRITE, "Skip file creation", cfg.CANCEL],
|
|
203
198
|
)
|
|
204
199
|
if faf_creation_answer == cfg.CANCEL:
|
|
@@ -275,7 +270,7 @@ def export_events_jwatcher(
|
|
|
275
270
|
rows.append("AllCodesMutuallyExclusive=true")
|
|
276
271
|
rows.append("")
|
|
277
272
|
|
|
278
|
-
for
|
|
273
|
+
for behav, key in all_observed_behaviors:
|
|
279
274
|
rows.append(f"Behavior.isModified.{key}=false")
|
|
280
275
|
rows.append(f"Behavior.isSubtracted.{key}=false")
|
|
281
276
|
rows.append(f"Behavior.isIgnored.{key}=false")
|
|
@@ -294,14 +289,14 @@ def export_events_jwatcher(
|
|
|
294
289
|
|
|
295
290
|
|
|
296
291
|
def export_tabular_events(
|
|
297
|
-
pj: dict, parameters: dict,
|
|
292
|
+
pj: dict, parameters: dict, obs_id: str, observation: dict, ethogram: dict, file_name: str, output_format: str
|
|
298
293
|
) -> Tuple[bool, str]:
|
|
299
294
|
"""
|
|
300
|
-
export events for one observation (
|
|
295
|
+
export events for one observation (obs_id)
|
|
301
296
|
|
|
302
297
|
Args:
|
|
303
298
|
parameters (dict): subjects, behaviors
|
|
304
|
-
|
|
299
|
+
obs_id (str): observation id
|
|
305
300
|
observation (dict): observation
|
|
306
301
|
ethogram (dict): ethogram of project
|
|
307
302
|
file_name (str): file name for exporting events
|
|
@@ -312,25 +307,21 @@ def export_tabular_events(
|
|
|
312
307
|
str: error message
|
|
313
308
|
"""
|
|
314
309
|
|
|
315
|
-
logging.debug(f"function: export tabular events for {
|
|
310
|
+
logging.debug(f"function: export tabular events for {obs_id}")
|
|
316
311
|
logging.debug(f"parameters: {parameters}")
|
|
317
312
|
|
|
318
313
|
interval = parameters["time"]
|
|
319
314
|
|
|
320
|
-
start_coding, end_coding, coding_duration = observation_operations.coding_time(pj[cfg.OBSERVATIONS], [
|
|
321
|
-
|
|
322
|
-
if start_coding is None and end_coding is None: # no events
|
|
323
|
-
return data, 0
|
|
324
|
-
"""
|
|
315
|
+
start_coding, end_coding, coding_duration = observation_operations.coding_time(pj[cfg.OBSERVATIONS], [obs_id])
|
|
316
|
+
start_interval, end_interval = observation_operations.time_intervals_range(pj[cfg.OBSERVATIONS], [obs_id])
|
|
325
317
|
|
|
326
318
|
if interval == cfg.TIME_EVENTS:
|
|
327
319
|
min_time = start_coding
|
|
328
320
|
max_time = end_coding
|
|
329
321
|
|
|
330
322
|
if interval == cfg.TIME_FULL_OBS:
|
|
331
|
-
|
|
332
323
|
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
333
|
-
max_media_duration, _ = observation_operations.media_duration(pj[cfg.OBSERVATIONS], [
|
|
324
|
+
max_media_duration, _ = observation_operations.media_duration(pj[cfg.OBSERVATIONS], [obs_id])
|
|
334
325
|
min_time = dec("0")
|
|
335
326
|
max_time = max_media_duration
|
|
336
327
|
coding_duration = max_media_duration
|
|
@@ -343,13 +334,19 @@ def export_tabular_events(
|
|
|
343
334
|
min_time = parameters[cfg.START_TIME]
|
|
344
335
|
max_time = parameters[cfg.END_TIME]
|
|
345
336
|
|
|
337
|
+
if interval == cfg.TIME_OBS_INTERVAL:
|
|
338
|
+
max_media_duration, _ = observation_operations.media_duration(pj[cfg.OBSERVATIONS], [obs_id])
|
|
339
|
+
min_time = start_interval
|
|
340
|
+
# Use max media duration for max time if no interval is defined (=0)
|
|
341
|
+
max_time = end_interval if end_interval != 0 else max_media_duration
|
|
342
|
+
|
|
346
343
|
logging.debug(f"min_time: {min_time} max_time: {max_time}")
|
|
347
344
|
|
|
348
|
-
|
|
345
|
+
events_with_status = project_functions.events_start_stop(ethogram, observation[cfg.EVENTS], observation[cfg.TYPE])
|
|
349
346
|
|
|
350
347
|
# check max number of modifiers
|
|
351
348
|
max_modifiers = 0
|
|
352
|
-
for event in
|
|
349
|
+
for event in events_with_status:
|
|
353
350
|
if not math.isnan(min_time) and not math.isnan(max_time): # obs not from pictures
|
|
354
351
|
if min_time <= event[cfg.EVENT_TIME_FIELD_IDX] <= max_time:
|
|
355
352
|
if event[cfg.EVENT_MODIFIER_FIELD_IDX]:
|
|
@@ -359,10 +356,7 @@ def export_tabular_events(
|
|
|
359
356
|
max_modifiers = max(max_modifiers, len(event[cfg.EVENT_MODIFIER_FIELD_IDX].split("|")))
|
|
360
357
|
|
|
361
358
|
# media file number
|
|
362
|
-
|
|
363
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
364
|
-
for player in observation[cfg.FILE]:
|
|
365
|
-
mediaNb += len(observation[cfg.FILE][player])
|
|
359
|
+
media_nb = util.count_media_file(observation[cfg.FILE])
|
|
366
360
|
|
|
367
361
|
rows: list = []
|
|
368
362
|
|
|
@@ -374,9 +368,14 @@ def export_tabular_events(
|
|
|
374
368
|
"Observation duration": float,
|
|
375
369
|
"Observation type": str,
|
|
376
370
|
"Source": str,
|
|
377
|
-
"
|
|
378
|
-
"FPS": float,
|
|
371
|
+
"Time offset (s)": str,
|
|
379
372
|
}
|
|
373
|
+
if media_nb == 1:
|
|
374
|
+
fields_type["Media duration (s)"] = float
|
|
375
|
+
fields_type["FPS"] = float
|
|
376
|
+
else:
|
|
377
|
+
fields_type["Media duration (s)"] = str
|
|
378
|
+
fields_type["FPS"] = str
|
|
380
379
|
|
|
381
380
|
# independent variables
|
|
382
381
|
if cfg.INDEPENDENT_VARIABLES in observation:
|
|
@@ -414,16 +413,15 @@ def export_tabular_events(
|
|
|
414
413
|
except KeyError:
|
|
415
414
|
pass
|
|
416
415
|
|
|
417
|
-
for event in
|
|
416
|
+
for event in events_with_status:
|
|
418
417
|
if (not math.isnan(min_time)) and not (min_time <= event[cfg.EVENT_TIME_FIELD_IDX] <= max_time):
|
|
419
418
|
continue
|
|
420
419
|
if (
|
|
421
420
|
(event[cfg.EVENT_SUBJECT_FIELD_IDX] in parameters[cfg.SELECTED_SUBJECTS])
|
|
422
421
|
or (event[cfg.EVENT_SUBJECT_FIELD_IDX] == "" and cfg.NO_FOCAL_SUBJECT in parameters[cfg.SELECTED_SUBJECTS])
|
|
423
422
|
) and (event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in parameters[cfg.SELECTED_BEHAVIORS]):
|
|
424
|
-
|
|
425
423
|
fields: list = []
|
|
426
|
-
fields.append(
|
|
424
|
+
fields.append(obs_id)
|
|
427
425
|
fields.append(observation.get("date", "").replace("T", " "))
|
|
428
426
|
fields.append(util.eol2space(observation.get(cfg.DESCRIPTION, "")))
|
|
429
427
|
# total length
|
|
@@ -439,9 +437,7 @@ def export_tabular_events(
|
|
|
439
437
|
for media_file in observation[cfg.FILE][player]:
|
|
440
438
|
media_file_lst.append(media_file)
|
|
441
439
|
fps_lst.append(f"{observation[cfg.MEDIA_INFO][cfg.FPS].get(media_file, cfg.NA):.3f}")
|
|
442
|
-
media_durations_lst.append(
|
|
443
|
-
f"{observation[cfg.MEDIA_INFO][cfg.LENGTH].get(media_file, cfg.NA):.3f}"
|
|
444
|
-
)
|
|
440
|
+
media_durations_lst.append(f"{observation[cfg.MEDIA_INFO][cfg.LENGTH].get(media_file, cfg.NA):.3f}")
|
|
445
441
|
if player > "1":
|
|
446
442
|
media_file_str += "|"
|
|
447
443
|
fps_str += "|"
|
|
@@ -491,6 +487,9 @@ def export_tabular_events(
|
|
|
491
487
|
else:
|
|
492
488
|
fields.append("")
|
|
493
489
|
|
|
490
|
+
# time offset
|
|
491
|
+
fields.append(observation[cfg.TIME_OFFSET])
|
|
492
|
+
|
|
494
493
|
# media duration
|
|
495
494
|
fields.append(media_durations_str)
|
|
496
495
|
|
|
@@ -525,14 +524,11 @@ def export_tabular_events(
|
|
|
525
524
|
fields.append(event[-1])
|
|
526
525
|
|
|
527
526
|
# time
|
|
528
|
-
# if event[cfg.EVENT_TIME_FIELD_IDX]
|
|
529
527
|
fields.append(util.convertTime(time_format=cfg.S, sec=event[cfg.EVENT_TIME_FIELD_IDX]))
|
|
530
528
|
|
|
531
529
|
# check video file name containing the event
|
|
532
530
|
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
533
|
-
video_file_name = observation_operations.event2media_file_name(
|
|
534
|
-
observation, event[cfg.EVENT_TIME_FIELD_IDX]
|
|
535
|
-
)
|
|
531
|
+
video_file_name = observation_operations.event2media_file_name(observation, event[cfg.EVENT_TIME_FIELD_IDX])
|
|
536
532
|
if video_file_name is None:
|
|
537
533
|
video_file_name = "Not found"
|
|
538
534
|
|
|
@@ -540,292 +536,17 @@ def export_tabular_events(
|
|
|
540
536
|
video_file_name = cfg.NA
|
|
541
537
|
fields.append(video_file_name)
|
|
542
538
|
|
|
543
|
-
# image file path
|
|
544
|
-
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
545
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_PATH]]) # image file path
|
|
546
|
-
elif observation[cfg.TYPE] in (cfg.LIVE, cfg.MEDIA):
|
|
547
|
-
fields.append(cfg.NA)
|
|
548
|
-
else:
|
|
549
|
-
fields.append("")
|
|
550
|
-
|
|
551
539
|
# image file index
|
|
552
540
|
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
553
541
|
fields.append(event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_INDEX]]) # image file index
|
|
554
|
-
elif observation[cfg.TYPE]
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
fields.append("")
|
|
558
|
-
|
|
559
|
-
# comment
|
|
560
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.COMMENT]].replace(os.linesep, " "))
|
|
561
|
-
|
|
562
|
-
rows.append(fields)
|
|
563
|
-
|
|
564
|
-
max_len = max([len(r) for r in rows])
|
|
565
|
-
data = tablib.Dataset()
|
|
566
|
-
|
|
567
|
-
data.title = util.safe_xl_worksheet_title(obsId, output_format)
|
|
568
|
-
|
|
569
|
-
for row in rows:
|
|
570
|
-
data.append(util.complete(row, max_len))
|
|
571
|
-
|
|
572
|
-
r, msg = dataset_write(data, file_name, output_format, dtype=fields_type)
|
|
573
|
-
|
|
574
|
-
return r, msg
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
'''
|
|
578
|
-
def export_tabular_events_old(
|
|
579
|
-
parameters: dict, obsId: str, observation: dict, ethogram: dict, file_name: str, output_format: str
|
|
580
|
-
) -> Tuple[bool, str]:
|
|
581
|
-
"""
|
|
582
|
-
export events for one observation (obsId)
|
|
583
|
-
|
|
584
|
-
Args:
|
|
585
|
-
parameters (dict): subjects, behaviors
|
|
586
|
-
obsId (str): observation id
|
|
587
|
-
observation (dict): observation
|
|
588
|
-
ethogram (dict): ethogram of project
|
|
589
|
-
file_name (str): file name for exporting events
|
|
590
|
-
output_format (str): output for exporting events
|
|
591
|
-
|
|
592
|
-
Returns:
|
|
593
|
-
bool: result: True if OK else False
|
|
594
|
-
str: error message
|
|
595
|
-
"""
|
|
596
|
-
|
|
597
|
-
logging.debug(f"function: export tabular events for {obsId} parameters: {parameters} ")
|
|
598
|
-
|
|
599
|
-
interval = parameters["time"]
|
|
600
|
-
start_time = parameters[cfg.START_TIME]
|
|
601
|
-
end_time = parameters[cfg.END_TIME]
|
|
602
|
-
|
|
603
|
-
total_length = observation_operations.observation_total_length(observation)
|
|
604
|
-
|
|
605
|
-
logging.debug(f"total_length: {total_length}")
|
|
606
|
-
|
|
607
|
-
if total_length == dec(-1): # media length not available
|
|
608
|
-
interval = cfg.TIME_EVENTS
|
|
609
|
-
|
|
610
|
-
if total_length == dec(-2): # obs without timestamp
|
|
611
|
-
interval = cfg.TIME_EVENTS
|
|
612
|
-
|
|
613
|
-
if interval == cfg.TIME_FULL_OBS:
|
|
614
|
-
min_time = float(0)
|
|
615
|
-
max_time = float(total_length)
|
|
616
|
-
total_length_str = f"{max_time - min_time:.3f}"
|
|
617
|
-
|
|
618
|
-
if interval == cfg.TIME_EVENTS:
|
|
619
|
-
start_coding, end_coding, _ = observation_operations.coding_time({obsId: observation}, [obsId])
|
|
620
|
-
if start_coding.is_nan():
|
|
621
|
-
total_length_str = cfg.NA
|
|
622
|
-
else:
|
|
623
|
-
min_time = float(start_coding)
|
|
624
|
-
max_time = float(end_coding)
|
|
625
|
-
total_length_str = f"{max_time - min_time:.3f}"
|
|
626
|
-
"""
|
|
627
|
-
try:
|
|
628
|
-
min_time = float(observation[cfg.EVENTS][0][0])
|
|
629
|
-
except Exception:
|
|
630
|
-
min_time = float(0)
|
|
631
|
-
try:
|
|
632
|
-
max_time = float(observation[cfg.EVENTS][-1][0])
|
|
633
|
-
except Exception:
|
|
634
|
-
max_time = float(total_length)
|
|
635
|
-
"""
|
|
636
|
-
|
|
637
|
-
if interval == cfg.TIME_ARBITRARY_INTERVAL:
|
|
638
|
-
min_time = float(start_time)
|
|
639
|
-
max_time = float(end_time)
|
|
640
|
-
total_length_str = f"{max_time - min_time:.3f}"
|
|
641
|
-
|
|
642
|
-
"""
|
|
643
|
-
if total_length == -2: # obs from pictures
|
|
644
|
-
total_length_str = cfg.NA
|
|
645
|
-
else:
|
|
646
|
-
total_length_str = f"{parameters[cfg.END_TIME] - parameters[cfg.START_TIME]:.3f}"
|
|
647
|
-
"""
|
|
648
|
-
|
|
649
|
-
eventsWithStatus = project_functions.events_start_stop(ethogram, observation[cfg.EVENTS])
|
|
650
|
-
|
|
651
|
-
# check max number of modifiers
|
|
652
|
-
max_modifiers = 0
|
|
653
|
-
for event in eventsWithStatus:
|
|
654
|
-
if total_length != dec(-2): # obs not from pictures
|
|
655
|
-
if min_time <= event[cfg.EVENT_TIME_FIELD_IDX] <= max_time:
|
|
656
|
-
if event[cfg.EVENT_MODIFIER_FIELD_IDX]:
|
|
657
|
-
max_modifiers = max(max_modifiers, len(event[cfg.EVENT_MODIFIER_FIELD_IDX].split("|")))
|
|
658
|
-
else:
|
|
659
|
-
if event[cfg.EVENT_MODIFIER_FIELD_IDX]:
|
|
660
|
-
max_modifiers = max(max_modifiers, len(event[cfg.EVENT_MODIFIER_FIELD_IDX].split("|")))
|
|
661
|
-
|
|
662
|
-
# media file number
|
|
663
|
-
mediaNb = 0
|
|
664
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
665
|
-
for player in observation[cfg.FILE]:
|
|
666
|
-
mediaNb += len(observation[cfg.FILE][player])
|
|
667
|
-
|
|
668
|
-
rows: list = []
|
|
669
|
-
|
|
670
|
-
# fields and type
|
|
671
|
-
fields_type: dict = {
|
|
672
|
-
"Observation id": str,
|
|
673
|
-
"Observation date": dt.datetime,
|
|
674
|
-
"Description": str,
|
|
675
|
-
"Observation duration": float,
|
|
676
|
-
"Observation type": str,
|
|
677
|
-
"Source": str,
|
|
678
|
-
"FPS": float,
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
# independent variables
|
|
682
|
-
if cfg.INDEPENDENT_VARIABLES in observation:
|
|
683
|
-
for variable in observation[cfg.INDEPENDENT_VARIABLES]:
|
|
684
|
-
# TODO check variable type
|
|
685
|
-
fields_type[variable] = str
|
|
686
|
-
|
|
687
|
-
fields_type.update({"Subject": str, "Behavior": str, "Behavioral category": str})
|
|
688
|
-
|
|
689
|
-
# modifiers
|
|
690
|
-
for idx in range(max_modifiers):
|
|
691
|
-
fields_type[f"Modifier #{idx + 1}"] = str
|
|
692
|
-
|
|
693
|
-
fields_type.update(
|
|
694
|
-
{
|
|
695
|
-
"Behavior type": str,
|
|
696
|
-
"Time": float,
|
|
697
|
-
"Media file name": str,
|
|
698
|
-
"Image index": float, # add image index and image file path to header
|
|
699
|
-
"Image file path": str,
|
|
700
|
-
"Comment": str,
|
|
701
|
-
}
|
|
702
|
-
)
|
|
703
|
-
|
|
704
|
-
# add header
|
|
705
|
-
rows.append(list(fields_type.keys()))
|
|
706
|
-
|
|
707
|
-
behavioral_category = project_functions.behavior_category(ethogram)
|
|
708
|
-
|
|
709
|
-
duration1 = [] # in seconds
|
|
710
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
711
|
-
try:
|
|
712
|
-
for mediaFile in observation[cfg.FILE][cfg.PLAYER1]:
|
|
713
|
-
duration1.append(observation[cfg.MEDIA_INFO][cfg.LENGTH][mediaFile])
|
|
714
|
-
except KeyError:
|
|
715
|
-
pass
|
|
716
|
-
|
|
717
|
-
for event in eventsWithStatus:
|
|
718
|
-
if (total_length != dec(-2)) and not (min_time <= event[cfg.EVENT_TIME_FIELD_IDX] <= max_time):
|
|
719
|
-
continue
|
|
720
|
-
if (
|
|
721
|
-
(event[cfg.EVENT_SUBJECT_FIELD_IDX] in parameters[cfg.SELECTED_SUBJECTS])
|
|
722
|
-
or (event[cfg.EVENT_SUBJECT_FIELD_IDX] == "" and cfg.NO_FOCAL_SUBJECT in parameters[cfg.SELECTED_SUBJECTS])
|
|
723
|
-
) and (event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in parameters[cfg.SELECTED_BEHAVIORS]):
|
|
724
|
-
|
|
725
|
-
fields: list = []
|
|
726
|
-
fields.append(obsId)
|
|
727
|
-
fields.append(observation.get("date", "").replace("T", " "))
|
|
728
|
-
fields.append(util.eol2space(observation.get("description", "")))
|
|
729
|
-
# total length
|
|
730
|
-
fields.append(total_length_str)
|
|
731
|
-
|
|
732
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
733
|
-
fields.append("Media file(s)")
|
|
734
|
-
|
|
735
|
-
media_file_str, fps_str = "", ""
|
|
736
|
-
# number of players
|
|
737
|
-
n_players = len([x for x in observation[cfg.FILE] if observation[cfg.FILE][x]])
|
|
738
|
-
for player in observation[cfg.FILE]:
|
|
739
|
-
if observation[cfg.FILE][player]:
|
|
740
|
-
if media_file_str:
|
|
741
|
-
media_file_str += " "
|
|
742
|
-
if fps_str:
|
|
743
|
-
fps_str += " "
|
|
744
|
-
if n_players > 1:
|
|
745
|
-
media_file_str += f"player #{player}: "
|
|
746
|
-
fps_str += f"player #{player}: "
|
|
747
|
-
media_list, fps_list = [], []
|
|
748
|
-
for media_file in observation[cfg.FILE][player]:
|
|
749
|
-
media_list.append(media_file)
|
|
750
|
-
fps_list.append(f"{observation[cfg.MEDIA_INFO][cfg.FPS].get(media_file, cfg.NA):.3f}")
|
|
751
|
-
media_file_str += ";".join(media_list)
|
|
752
|
-
fps_str += ";".join(fps_list)
|
|
753
|
-
|
|
754
|
-
fields.append(media_file_str)
|
|
755
|
-
|
|
542
|
+
elif observation[cfg.TYPE] == cfg.MEDIA:
|
|
543
|
+
frame_idx = event_operations.read_event_field(event, cfg.MEDIA, cfg.FRAME_INDEX)
|
|
544
|
+
fields.append(frame_idx) # frame index
|
|
756
545
|
elif observation[cfg.TYPE] == cfg.LIVE:
|
|
757
|
-
fields.append("Live observation")
|
|
758
546
|
fields.append(cfg.NA)
|
|
759
|
-
fps_str = cfg.NA
|
|
760
|
-
|
|
761
|
-
elif observation[cfg.TYPE] == cfg.IMAGES:
|
|
762
|
-
fields.append("From directories of images")
|
|
763
|
-
dir_list = []
|
|
764
|
-
for dir in observation[cfg.DIRECTORIES_LIST]:
|
|
765
|
-
dir_list.append(dir)
|
|
766
|
-
fields.append(";".join(dir_list))
|
|
767
|
-
fps_str = cfg.NA
|
|
768
|
-
|
|
769
547
|
else:
|
|
770
548
|
fields.append("")
|
|
771
549
|
|
|
772
|
-
# FPS
|
|
773
|
-
fields.append(fps_str)
|
|
774
|
-
|
|
775
|
-
# indep var
|
|
776
|
-
if cfg.INDEPENDENT_VARIABLES in observation:
|
|
777
|
-
for variable in observation[cfg.INDEPENDENT_VARIABLES]:
|
|
778
|
-
fields.append(observation[cfg.INDEPENDENT_VARIABLES][variable])
|
|
779
|
-
|
|
780
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.SUBJECT]])
|
|
781
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.BEHAVIOR_CODE]])
|
|
782
|
-
|
|
783
|
-
# behavioral category
|
|
784
|
-
try:
|
|
785
|
-
behav_category = behavioral_category[event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.BEHAVIOR_CODE]]]
|
|
786
|
-
except Exception:
|
|
787
|
-
behav_category = ""
|
|
788
|
-
fields.append(behav_category)
|
|
789
|
-
|
|
790
|
-
# modifiers
|
|
791
|
-
if max_modifiers:
|
|
792
|
-
modifiers = event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.MODIFIER]].split("|")
|
|
793
|
-
while len(modifiers) < max_modifiers:
|
|
794
|
-
modifiers.append("")
|
|
795
|
-
|
|
796
|
-
for m in modifiers:
|
|
797
|
-
fields.append(m)
|
|
798
|
-
|
|
799
|
-
# status (START/STOP)
|
|
800
|
-
fields.append(event[-1])
|
|
801
|
-
|
|
802
|
-
# time
|
|
803
|
-
# if event[cfg.EVENT_TIME_FIELD_IDX]
|
|
804
|
-
fields.append(util.convertTime(time_format=cfg.S, sec=event[cfg.EVENT_TIME_FIELD_IDX]))
|
|
805
|
-
|
|
806
|
-
# check video file name containing the event
|
|
807
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
808
|
-
cumul_media_durations = [0]
|
|
809
|
-
for media_file in observation[cfg.FILE]["1"]:
|
|
810
|
-
media_duration = observation[cfg.MEDIA_INFO][cfg.LENGTH][media_file]
|
|
811
|
-
cumul_media_durations.append(cumul_media_durations[-1] + media_duration)
|
|
812
|
-
|
|
813
|
-
player_idx_list = [
|
|
814
|
-
idx
|
|
815
|
-
for idx, x in enumerate(cumul_media_durations)
|
|
816
|
-
if cumul_media_durations[idx - 1] < event[cfg.EVENT_TIME_FIELD_IDX] <= x
|
|
817
|
-
]
|
|
818
|
-
if len(player_idx_list):
|
|
819
|
-
player_idx = player_idx_list[0] - 1
|
|
820
|
-
video_file_name = observation[cfg.FILE]["1"][player_idx]
|
|
821
|
-
else:
|
|
822
|
-
player_idx = -1
|
|
823
|
-
video_file_name = "Not found"
|
|
824
|
-
|
|
825
|
-
elif observation[cfg.TYPE] in (cfg.LIVE, cfg.IMAGES):
|
|
826
|
-
video_file_name = cfg.NA
|
|
827
|
-
fields.append(video_file_name)
|
|
828
|
-
|
|
829
550
|
# image file path
|
|
830
551
|
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
831
552
|
fields.append(event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_PATH]]) # image file path
|
|
@@ -834,14 +555,6 @@ def export_tabular_events_old(
|
|
|
834
555
|
else:
|
|
835
556
|
fields.append("")
|
|
836
557
|
|
|
837
|
-
# image file index
|
|
838
|
-
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
839
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_INDEX]]) # image file index
|
|
840
|
-
elif observation[cfg.TYPE] in (cfg.LIVE, cfg.MEDIA):
|
|
841
|
-
fields.append(cfg.NA)
|
|
842
|
-
else:
|
|
843
|
-
fields.append("")
|
|
844
|
-
|
|
845
558
|
# comment
|
|
846
559
|
fields.append(event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.COMMENT]].replace(os.linesep, " "))
|
|
847
560
|
|
|
@@ -850,7 +563,7 @@ def export_tabular_events_old(
|
|
|
850
563
|
max_len = max([len(r) for r in rows])
|
|
851
564
|
data = tablib.Dataset()
|
|
852
565
|
|
|
853
|
-
data.title = util.safe_xl_worksheet_title(
|
|
566
|
+
data.title = util.safe_xl_worksheet_title(obs_id, output_format)
|
|
854
567
|
|
|
855
568
|
for row in rows:
|
|
856
569
|
data.append(util.complete(row, max_len))
|
|
@@ -858,213 +571,9 @@ def export_tabular_events_old(
|
|
|
858
571
|
r, msg = dataset_write(data, file_name, output_format, dtype=fields_type)
|
|
859
572
|
|
|
860
573
|
return r, msg
|
|
861
|
-
'''
|
|
862
|
-
|
|
863
|
-
'''
|
|
864
|
-
def export_tabular_events_long_format(
|
|
865
|
-
parameters, obsId: str, observation: dict, ethogram: dict, file_name: str, output_format: str
|
|
866
|
-
) -> tuple: # -> tuple[bool, str]:
|
|
867
|
-
"""
|
|
868
|
-
export events
|
|
869
|
-
|
|
870
|
-
Args:
|
|
871
|
-
parameters (dict): subjects, behaviors
|
|
872
|
-
obsId (str): observation id
|
|
873
|
-
observation (dict): observation
|
|
874
|
-
ethogram (dict): ethogram of project
|
|
875
|
-
file_name (str): file name for exporting events
|
|
876
|
-
output_format (str): output for exporting events
|
|
877
|
-
|
|
878
|
-
Returns:
|
|
879
|
-
bool: result: True if OK else False
|
|
880
|
-
str: error message
|
|
881
|
-
"""
|
|
882
|
-
|
|
883
|
-
total_length = f"{observation_operations.observation_total_length(observation):.3f}"
|
|
884
|
-
|
|
885
|
-
eventsWithStatus = project_functions.events_start_stop(ethogram, observation[cfg.EVENTS])
|
|
886
|
-
|
|
887
|
-
# check max number of modifiers
|
|
888
|
-
max_modifiers = 0
|
|
889
|
-
for event in eventsWithStatus:
|
|
890
|
-
if event[cfg.EVENT_MODIFIER_FIELD_IDX]:
|
|
891
|
-
max_modifiers = max(max_modifiers, len(event[cfg.EVENT_MODIFIER_FIELD_IDX].split("|")))
|
|
892
|
-
|
|
893
|
-
# media file number
|
|
894
|
-
mediaNb = 0
|
|
895
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
896
|
-
for player in observation[cfg.FILE]:
|
|
897
|
-
mediaNb += len(observation[cfg.FILE][player])
|
|
898
|
-
|
|
899
|
-
rows = []
|
|
900
|
-
|
|
901
|
-
# observation id
|
|
902
|
-
rows.append(["Observation id", obsId])
|
|
903
|
-
rows.append([""])
|
|
904
|
-
|
|
905
|
-
# media file name
|
|
906
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
907
|
-
rows.append(["Media file(s)"])
|
|
908
|
-
elif observation[cfg.TYPE] == cfg.LIVE:
|
|
909
|
-
rows.append(["Live observation"])
|
|
910
|
-
elif observation[cfg.TYPE] == cfg.IMAGES:
|
|
911
|
-
rows.append(["From directories of images"])
|
|
912
|
-
else:
|
|
913
|
-
rows.append([""])
|
|
914
|
-
rows.append([""])
|
|
915
|
-
|
|
916
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
917
|
-
for player in sorted(list(observation[cfg.FILE].keys())):
|
|
918
|
-
for media in observation[cfg.FILE][player]:
|
|
919
|
-
rows.append([f"Player #{player}", media])
|
|
920
|
-
|
|
921
|
-
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
922
|
-
for dir in observation[cfg.DIRECTORIES_LIST]:
|
|
923
|
-
rows.append([f"Directory", dir])
|
|
924
|
-
|
|
925
|
-
rows.append([""])
|
|
926
|
-
|
|
927
|
-
# date
|
|
928
|
-
rows.append(["Observation date", observation.get("date", "").replace("T", " ")])
|
|
929
|
-
rows.append([""])
|
|
930
|
-
|
|
931
|
-
# description
|
|
932
|
-
rows.append(["Description", util.eol2space(observation.get("description", ""))])
|
|
933
|
-
rows.append([""])
|
|
934
|
-
|
|
935
|
-
# time offset
|
|
936
|
-
rows.append(["Time offset (s)", observation.get(cfg.TIME_OFFSET, 0)])
|
|
937
|
-
rows.append([""])
|
|
938
|
-
|
|
939
|
-
# independent variables
|
|
940
|
-
if cfg.INDEPENDENT_VARIABLES in observation:
|
|
941
|
-
rows.extend([["independent variables"], ["variable", "value"]])
|
|
942
|
-
|
|
943
|
-
for variable in observation[cfg.INDEPENDENT_VARIABLES]:
|
|
944
|
-
rows.append([variable, observation[cfg.INDEPENDENT_VARIABLES][variable]])
|
|
945
|
-
|
|
946
|
-
rows.append([""])
|
|
947
|
-
|
|
948
|
-
# write table header
|
|
949
|
-
col = 0
|
|
950
|
-
|
|
951
|
-
header = ["Time"]
|
|
952
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
953
|
-
header.extend(["Media file path", "Total length", "FPS"])
|
|
954
|
-
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
955
|
-
header.extend(
|
|
956
|
-
[
|
|
957
|
-
"Image file path",
|
|
958
|
-
"Image index",
|
|
959
|
-
]
|
|
960
|
-
)
|
|
961
|
-
if observation[cfg.TYPE] == cfg.LIVE:
|
|
962
|
-
header.extend(
|
|
963
|
-
[
|
|
964
|
-
"Total length",
|
|
965
|
-
]
|
|
966
|
-
)
|
|
967
|
-
|
|
968
|
-
header.extend(["Subject", "Behavior", "Behavioral category"])
|
|
969
|
-
|
|
970
|
-
behavioral_category = project_functions.behavior_category(ethogram)
|
|
971
|
-
|
|
972
|
-
for x in range(1, max_modifiers + 1):
|
|
973
|
-
header.append(f"Modifier {x}")
|
|
974
|
-
header.extend(["Comment", "Status"])
|
|
975
|
-
|
|
976
|
-
rows.append(header)
|
|
977
|
-
|
|
978
|
-
duration1 = [] # in seconds
|
|
979
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
980
|
-
try:
|
|
981
|
-
for mediaFile in observation[cfg.FILE][cfg.PLAYER1]:
|
|
982
|
-
duration1.append(observation[cfg.MEDIA_INFO][cfg.LENGTH][mediaFile])
|
|
983
|
-
except KeyError:
|
|
984
|
-
pass
|
|
985
|
-
|
|
986
|
-
for event in eventsWithStatus:
|
|
987
|
-
if (
|
|
988
|
-
(event[cfg.EVENT_SUBJECT_FIELD_IDX] in parameters[cfg.SELECTED_SUBJECTS])
|
|
989
|
-
or (event[cfg.EVENT_SUBJECT_FIELD_IDX] == "" and cfg.NO_FOCAL_SUBJECT in parameters[cfg.SELECTED_SUBJECTS])
|
|
990
|
-
) and (event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in parameters[cfg.SELECTED_BEHAVIORS]):
|
|
991
|
-
|
|
992
|
-
fields = []
|
|
993
|
-
fields.append(util.intfloatstr(str(event[cfg.EVENT_TIME_FIELD_IDX])))
|
|
994
|
-
|
|
995
|
-
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
996
|
-
|
|
997
|
-
time_ = event[cfg.EVENT_TIME_FIELD_IDX] - observation[cfg.TIME_OFFSET]
|
|
998
|
-
if time_ < 0:
|
|
999
|
-
time_ = 0
|
|
1000
|
-
|
|
1001
|
-
if duration1:
|
|
1002
|
-
mediaFileIdx = [idx1 for idx1, x in enumerate(duration1) if time_ >= sum(duration1[0:idx1])][-1]
|
|
1003
|
-
fields.append(observation[cfg.FILE][cfg.PLAYER1][mediaFileIdx])
|
|
1004
|
-
fields.append(total_length)
|
|
1005
|
-
# FPS
|
|
1006
|
-
try:
|
|
1007
|
-
fields.append(
|
|
1008
|
-
observation[cfg.MEDIA_INFO][cfg.FPS][observation[cfg.FILE][cfg.PLAYER1][mediaFileIdx]]
|
|
1009
|
-
) # fps
|
|
1010
|
-
except KeyError:
|
|
1011
|
-
fields.append(cfg.NA)
|
|
1012
|
-
else:
|
|
1013
|
-
fields.append(cfg.NA) # media file
|
|
1014
|
-
fields.append(cfg.NA) # FPS
|
|
1015
|
-
|
|
1016
|
-
if observation[cfg.TYPE] == cfg.LIVE:
|
|
1017
|
-
fields.append(total_length) # total length
|
|
1018
|
-
|
|
1019
|
-
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
1020
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_PATH]]) # image file path
|
|
1021
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_INDEX]]) # image file index
|
|
1022
|
-
|
|
1023
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.SUBJECT]])
|
|
1024
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.BEHAVIOR_CODE]])
|
|
1025
|
-
|
|
1026
|
-
# behavioral category
|
|
1027
|
-
|
|
1028
|
-
try:
|
|
1029
|
-
behav_category = behavioral_category[event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.BEHAVIOR_CODE]]]
|
|
1030
|
-
except Exception:
|
|
1031
|
-
behav_category = ""
|
|
1032
|
-
fields.append(behav_category)
|
|
1033
|
-
|
|
1034
|
-
# modifiers
|
|
1035
|
-
if max_modifiers:
|
|
1036
|
-
modifiers = event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.MODIFIER]].split("|")
|
|
1037
|
-
while len(modifiers) < max_modifiers:
|
|
1038
|
-
modifiers.append("")
|
|
1039
|
-
|
|
1040
|
-
for m in modifiers:
|
|
1041
|
-
fields.append(m)
|
|
1042
|
-
|
|
1043
|
-
# comment
|
|
1044
|
-
fields.append(event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.COMMENT]].replace(os.linesep, " "))
|
|
1045
|
-
# status
|
|
1046
|
-
fields.append(event[-1])
|
|
1047
|
-
|
|
1048
|
-
rows.append(fields)
|
|
1049
|
-
|
|
1050
|
-
maxLen = max([len(r) for r in rows])
|
|
1051
|
-
data = tablib.Dataset()
|
|
1052
|
-
|
|
1053
|
-
data.title = util.safe_xl_worksheet_title(obsId, output_format)
|
|
1054
|
-
|
|
1055
|
-
for row in rows:
|
|
1056
|
-
data.append(util.complete(row, maxLen))
|
|
1057
|
-
|
|
1058
|
-
r, msg = dataset_write(data, file_name, output_format)
|
|
1059
|
-
|
|
1060
|
-
return r, msg
|
|
1061
|
-
|
|
1062
|
-
'''
|
|
1063
574
|
|
|
1064
575
|
|
|
1065
|
-
def dataset_write(
|
|
1066
|
-
dataset: tablib.Dataset, file_name: str, output_format: str, dtype: dict = {}
|
|
1067
|
-
) -> tuple: # -> tuple[bool, str]:
|
|
576
|
+
def dataset_write(dataset: tablib.Dataset, file_name: str, output_format: str, dtype: dict = {}) -> tuple: # -> tuple[bool, str]:
|
|
1068
577
|
"""
|
|
1069
578
|
write a tablib dataset with aggregated events or tabular events to file in specified format (output_format)
|
|
1070
579
|
|
|
@@ -1072,6 +581,7 @@ def dataset_write(
|
|
|
1072
581
|
dataset (tablib.dataset): dataset to write
|
|
1073
582
|
file_name (str): file name
|
|
1074
583
|
output_format (str): format of output
|
|
584
|
+
dtype (dict): type of field
|
|
1075
585
|
|
|
1076
586
|
Returns:
|
|
1077
587
|
bool: result. True if OK else False
|
|
@@ -1081,11 +591,9 @@ def dataset_write(
|
|
|
1081
591
|
logging.debug("function: dataset_write")
|
|
1082
592
|
|
|
1083
593
|
try:
|
|
1084
|
-
|
|
1085
|
-
if output_format in ("pkl", "rds"):
|
|
1086
|
-
|
|
594
|
+
if output_format in (cfg.PANDAS_DF_EXT, cfg.RDS_EXT):
|
|
1087
595
|
# build pandas dataframe from the tsv export of tablib dataset
|
|
1088
|
-
date_type = []
|
|
596
|
+
date_type: list = []
|
|
1089
597
|
for field_name in dtype:
|
|
1090
598
|
if dtype[field_name] == dt.datetime:
|
|
1091
599
|
date_type.append(field_name)
|
|
@@ -1094,27 +602,26 @@ def dataset_write(
|
|
|
1094
602
|
del dtype[field_name]
|
|
1095
603
|
|
|
1096
604
|
df = pd.read_csv(
|
|
1097
|
-
StringIO(dataset.export(
|
|
605
|
+
StringIO(dataset.export(cfg.TSV_EXT)),
|
|
1098
606
|
sep="\t",
|
|
1099
607
|
dtype=dtype,
|
|
1100
608
|
parse_dates=date_type,
|
|
1101
609
|
)
|
|
1102
610
|
|
|
1103
|
-
if output_format ==
|
|
611
|
+
if output_format == cfg.PANDAS_DF_EXT:
|
|
1104
612
|
df.to_pickle(file_name)
|
|
1105
613
|
|
|
1106
|
-
if
|
|
614
|
+
if output_format == cfg.RDS_EXT and flag_pyreadr_loaded:
|
|
1107
615
|
pyreadr.write_rds(file_name, df)
|
|
1108
616
|
|
|
1109
617
|
return True, ""
|
|
1110
618
|
|
|
1111
|
-
if output_format in (
|
|
619
|
+
if output_format in (cfg.CSV_EXT, cfg.TSV_EXT, cfg.HTML_EXT):
|
|
1112
620
|
with open(file_name, "wb") as f:
|
|
1113
621
|
f.write(str.encode(dataset.export(output_format)))
|
|
1114
622
|
return True, ""
|
|
1115
623
|
|
|
1116
|
-
if output_format in (
|
|
1117
|
-
|
|
624
|
+
if output_format in (cfg.ODS_EXT, cfg.XLS_EXT, cfg.XLSX_EXT):
|
|
1118
625
|
dataset.title = util.safe_xl_worksheet_title(dataset.title, output_format)
|
|
1119
626
|
|
|
1120
627
|
with open(file_name, "wb") as f:
|
|
@@ -1127,7 +634,7 @@ def dataset_write(
|
|
|
1127
634
|
return False, str(sys.exc_info()[1])
|
|
1128
635
|
|
|
1129
636
|
|
|
1130
|
-
def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[tablib.Dataset, int]:
|
|
637
|
+
def export_aggregated_events(pj: dict, parameters: dict, obsId: str, force_number_modifiers: int = 0) -> Tuple[tablib.Dataset, int]:
|
|
1131
638
|
"""
|
|
1132
639
|
export aggregated events of one observation
|
|
1133
640
|
|
|
@@ -1135,6 +642,7 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1135
642
|
pj (dict): BORIS project
|
|
1136
643
|
parameters (dict): subjects, behaviors
|
|
1137
644
|
obsId (str): observation id
|
|
645
|
+
force_number_modifiers (int): force the number of modifiers to return
|
|
1138
646
|
|
|
1139
647
|
Returns:
|
|
1140
648
|
tablib.Dataset:
|
|
@@ -1149,6 +657,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1149
657
|
data = tablib.Dataset()
|
|
1150
658
|
|
|
1151
659
|
start_coding, end_coding, coding_duration = observation_operations.coding_time(pj[cfg.OBSERVATIONS], [obsId])
|
|
660
|
+
start_interval, end_interval = observation_operations.time_intervals_range(pj[cfg.OBSERVATIONS], [obsId])
|
|
661
|
+
|
|
1152
662
|
if start_coding is None and end_coding is None: # no events
|
|
1153
663
|
return data, 0
|
|
1154
664
|
|
|
@@ -1170,21 +680,22 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1170
680
|
min_time = float(parameters[cfg.START_TIME])
|
|
1171
681
|
max_time = float(parameters[cfg.END_TIME])
|
|
1172
682
|
|
|
683
|
+
if interval == cfg.TIME_OBS_INTERVAL:
|
|
684
|
+
max_media_duration, _ = observation_operations.media_duration(pj[cfg.OBSERVATIONS], [obsId])
|
|
685
|
+
min_time = float(start_interval)
|
|
686
|
+
# Use max media duration for max time if no interval is defined (=0)
|
|
687
|
+
max_time = float(end_interval) if end_interval != 0 else float(max_media_duration)
|
|
688
|
+
|
|
1173
689
|
logging.debug(f"min_time: {min_time} max_time: {max_time}")
|
|
1174
690
|
|
|
1175
691
|
# obs description
|
|
1176
692
|
obs_description = util.eol2space(observation[cfg.DESCRIPTION])
|
|
1177
693
|
|
|
1178
|
-
"""
|
|
1179
|
-
obs_length = observation_operations.observation_total_length(pj[cfg.OBSERVATIONS][obsId])
|
|
1180
|
-
logging.debug(f"obs_length: {obs_length}")
|
|
1181
|
-
"""
|
|
1182
|
-
|
|
1183
694
|
_, _, connector = db_functions.load_aggregated_events_in_db(
|
|
1184
695
|
pj, parameters[cfg.SELECTED_SUBJECTS], [obsId], parameters[cfg.SELECTED_BEHAVIORS]
|
|
1185
696
|
)
|
|
1186
697
|
if connector is None:
|
|
1187
|
-
logging.critical(
|
|
698
|
+
logging.critical("error when loading aggregated events in DB")
|
|
1188
699
|
return data, 0
|
|
1189
700
|
|
|
1190
701
|
cursor = connector.cursor()
|
|
@@ -1238,13 +749,16 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1238
749
|
behavioral_category = project_functions.behavior_category(pj[cfg.ETHOGRAM])
|
|
1239
750
|
|
|
1240
751
|
cursor.execute("SELECT DISTINCT modifiers FROM aggregated_events")
|
|
1241
|
-
max_modifiers = 0
|
|
1242
|
-
for row in cursor.fetchall():
|
|
1243
|
-
if row["modifiers"]:
|
|
1244
|
-
max_modifiers = max(max_modifiers, row["modifiers"].count("|") + 1)
|
|
1245
752
|
|
|
1246
|
-
|
|
753
|
+
if not force_number_modifiers:
|
|
754
|
+
max_modifiers: int = 0
|
|
755
|
+
for row in cursor.fetchall():
|
|
756
|
+
if row["modifiers"]:
|
|
757
|
+
max_modifiers = max(max_modifiers, row["modifiers"].count("|") + 1)
|
|
758
|
+
else:
|
|
759
|
+
max_modifiers = force_number_modifiers
|
|
1247
760
|
|
|
761
|
+
for subject in parameters[cfg.SELECTED_SUBJECTS]:
|
|
1248
762
|
# calculate observation duration by subject (by obs)
|
|
1249
763
|
cursor.execute(("SELECT SUM(stop - start) AS duration FROM aggregated_events WHERE subject = ? "), (subject,))
|
|
1250
764
|
duration_by_subject_by_obs = cursor.fetchone()["duration"]
|
|
@@ -1252,7 +766,6 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1252
766
|
duration_by_subject_by_obs = round(duration_by_subject_by_obs, 3)
|
|
1253
767
|
|
|
1254
768
|
for behavior in parameters[cfg.SELECTED_BEHAVIORS]:
|
|
1255
|
-
|
|
1256
769
|
cursor.execute(
|
|
1257
770
|
"SELECT DISTINCT modifiers FROM aggregated_events WHERE subject=? AND behavior=? ORDER BY modifiers",
|
|
1258
771
|
(
|
|
@@ -1264,7 +777,6 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1264
777
|
rows_distinct_modifiers = list(x[0] for x in cursor.fetchall())
|
|
1265
778
|
|
|
1266
779
|
for distinct_modifiers in rows_distinct_modifiers:
|
|
1267
|
-
|
|
1268
780
|
cursor.execute(
|
|
1269
781
|
(
|
|
1270
782
|
"SELECT start, stop, type, modifiers, comment, comment_stop, "
|
|
@@ -1276,12 +788,12 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1276
788
|
)
|
|
1277
789
|
|
|
1278
790
|
for row in cursor.fetchall():
|
|
1279
|
-
|
|
1280
791
|
media_file_name = cfg.NA
|
|
1281
792
|
|
|
1282
793
|
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
1283
794
|
observation_type = "Media file"
|
|
1284
795
|
|
|
796
|
+
# get the media file name of the start of event
|
|
1285
797
|
media_file_name = observation_operations.event2media_file_name(observation, row["start"])
|
|
1286
798
|
if media_file_name is None:
|
|
1287
799
|
media_file_name = "Not found"
|
|
@@ -1293,12 +805,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1293
805
|
if observation[cfg.FILE][player]:
|
|
1294
806
|
for media_file in observation[cfg.FILE][player]:
|
|
1295
807
|
media_file_lst.append(media_file)
|
|
1296
|
-
fps_lst.append(
|
|
1297
|
-
|
|
1298
|
-
)
|
|
1299
|
-
media_durations_lst.append(
|
|
1300
|
-
f"{observation[cfg.MEDIA_INFO][cfg.LENGTH].get(media_file, cfg.NA):.3f}"
|
|
1301
|
-
)
|
|
808
|
+
fps_lst.append(f"{observation[cfg.MEDIA_INFO][cfg.FPS].get(media_file, cfg.NA):.3f}")
|
|
809
|
+
media_durations_lst.append(f"{observation[cfg.MEDIA_INFO][cfg.LENGTH].get(media_file, cfg.NA):.3f}")
|
|
1302
810
|
if player > "1":
|
|
1303
811
|
media_file_str += "|"
|
|
1304
812
|
fps_str += "|"
|
|
@@ -1330,7 +838,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1330
838
|
observation["date"].replace("T", " "),
|
|
1331
839
|
obs_description,
|
|
1332
840
|
observation_type,
|
|
1333
|
-
media_file_str,
|
|
841
|
+
media_file_str, # list of media used in observation
|
|
842
|
+
pj[cfg.OBSERVATIONS][obsId][cfg.TIME_OFFSET],
|
|
1334
843
|
f"{coding_duration:.3f}" if not coding_duration.is_nan() else cfg.NA,
|
|
1335
844
|
media_durations_str,
|
|
1336
845
|
fps_str,
|
|
@@ -1340,13 +849,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1340
849
|
# independent variables
|
|
1341
850
|
if cfg.INDEPENDENT_VARIABLES in pj:
|
|
1342
851
|
for idx_var in util.sorted_keys(pj[cfg.INDEPENDENT_VARIABLES]):
|
|
1343
|
-
if
|
|
1344
|
-
pj[cfg.INDEPENDENT_VARIABLES][idx_var]["label"]
|
|
1345
|
-
in observation[cfg.INDEPENDENT_VARIABLES]
|
|
1346
|
-
):
|
|
1347
|
-
var_value = observation[cfg.INDEPENDENT_VARIABLES][
|
|
1348
|
-
pj[cfg.INDEPENDENT_VARIABLES][idx_var]["label"]
|
|
1349
|
-
]
|
|
852
|
+
if pj[cfg.INDEPENDENT_VARIABLES][idx_var]["label"] in observation[cfg.INDEPENDENT_VARIABLES]:
|
|
853
|
+
var_value = observation[cfg.INDEPENDENT_VARIABLES][pj[cfg.INDEPENDENT_VARIABLES][idx_var]["label"]]
|
|
1350
854
|
if pj[cfg.INDEPENDENT_VARIABLES][idx_var]["type"] == "timestamp":
|
|
1351
855
|
var_value = var_value.replace("T", " ")
|
|
1352
856
|
|
|
@@ -1389,9 +893,7 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
1389
893
|
f"{row['start']:.3f}" if row["start"] is not None else cfg.NA,
|
|
1390
894
|
f"{row['stop']:.3f}" if row["stop"] is not None else cfg.NA,
|
|
1391
895
|
# duration
|
|
1392
|
-
f"{row['stop'] - row['start']:.3f}"
|
|
1393
|
-
if (row["stop"] is not None) and (row["start"] is not None)
|
|
1394
|
-
else cfg.NA,
|
|
896
|
+
f"{row['stop'] - row['start']:.3f}" if (row["stop"] is not None) and (row["start"] is not None) else cfg.NA,
|
|
1395
897
|
media_file_name, # Media file name
|
|
1396
898
|
]
|
|
1397
899
|
)
|
|
@@ -1427,10 +929,12 @@ def events_to_behavioral_sequences(pj, obs_id: str, subj: str, parameters: dict,
|
|
|
1427
929
|
str: behavioral string for selected subject in selected observation
|
|
1428
930
|
"""
|
|
1429
931
|
|
|
1430
|
-
out = ""
|
|
1431
|
-
current_states = []
|
|
932
|
+
out: str = ""
|
|
933
|
+
current_states: list = []
|
|
1432
934
|
# add status (POINT, START, STOP) to event
|
|
1433
|
-
events_with_status = project_functions.events_start_stop(
|
|
935
|
+
events_with_status = project_functions.events_start_stop(
|
|
936
|
+
pj[cfg.ETHOGRAM], pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS], pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE]
|
|
937
|
+
)
|
|
1434
938
|
|
|
1435
939
|
for event in events_with_status:
|
|
1436
940
|
# check if event in selected behaviors
|
|
@@ -1438,10 +942,7 @@ def events_to_behavioral_sequences(pj, obs_id: str, subj: str, parameters: dict,
|
|
|
1438
942
|
if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] not in parameters[cfg.SELECTED_BEHAVIORS]:
|
|
1439
943
|
continue
|
|
1440
944
|
|
|
1441
|
-
if event[cfg.EVENT_SUBJECT_FIELD_IDX] == subj or (
|
|
1442
|
-
subj == cfg.NO_FOCAL_SUBJECT and event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""
|
|
1443
|
-
):
|
|
1444
|
-
|
|
945
|
+
if event[cfg.EVENT_SUBJECT_FIELD_IDX] == subj or (subj == cfg.NO_FOCAL_SUBJECT and event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""):
|
|
1445
946
|
# if event[cfg.EVENT_STATUS_FIELD_IDX] == cfg.POINT:
|
|
1446
947
|
if event[-1] == cfg.POINT: # status is last element
|
|
1447
948
|
if current_states:
|
|
@@ -1473,7 +974,6 @@ def events_to_behavioral_sequences(pj, obs_id: str, subj: str, parameters: dict,
|
|
|
1473
974
|
|
|
1474
975
|
# if event[cfg.EVENT_STATUS_FIELD_IDX] == cfg.STOP:
|
|
1475
976
|
if event[-1] == cfg.STOP:
|
|
1476
|
-
|
|
1477
977
|
if parameters[cfg.INCLUDE_MODIFIERS]:
|
|
1478
978
|
behav_modif = (
|
|
1479
979
|
f"{event[cfg.EVENT_BEHAVIOR_FIELD_IDX]}"
|
|
@@ -1497,9 +997,7 @@ def events_to_behavioral_sequences(pj, obs_id: str, subj: str, parameters: dict,
|
|
|
1497
997
|
return out
|
|
1498
998
|
|
|
1499
999
|
|
|
1500
|
-
def events_to_behavioral_sequences_all_subj(
|
|
1501
|
-
pj, obs_id: str, subjects_list: list, parameters: dict, behav_seq_separator: str
|
|
1502
|
-
) -> str:
|
|
1000
|
+
def events_to_behavioral_sequences_all_subj(pj, obs_id: str, subjects_list: list, parameters: dict, behav_seq_separator: str) -> str:
|
|
1503
1001
|
"""
|
|
1504
1002
|
return the behavioral sequences for all selected subjects in obs_id
|
|
1505
1003
|
|
|
@@ -1516,7 +1014,9 @@ def events_to_behavioral_sequences_all_subj(
|
|
|
1516
1014
|
|
|
1517
1015
|
out = ""
|
|
1518
1016
|
current_states = {i: [] for i in subjects_list}
|
|
1519
|
-
events_with_status = project_functions.events_start_stop(
|
|
1017
|
+
events_with_status = project_functions.events_start_stop(
|
|
1018
|
+
pj[cfg.ETHOGRAM], pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS], pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE]
|
|
1019
|
+
)
|
|
1520
1020
|
|
|
1521
1021
|
for event in events_with_status:
|
|
1522
1022
|
# check if event in selected behaviors
|
|
@@ -1526,14 +1026,11 @@ def events_to_behavioral_sequences_all_subj(
|
|
|
1526
1026
|
if (event[cfg.EVENT_SUBJECT_FIELD_IDX] in subjects_list) or (
|
|
1527
1027
|
event[cfg.EVENT_SUBJECT_FIELD_IDX] == "" and cfg.NO_FOCAL_SUBJECT in subjects_list
|
|
1528
1028
|
):
|
|
1529
|
-
|
|
1530
1029
|
subject = event[cfg.EVENT_SUBJECT_FIELD_IDX] if event[cfg.EVENT_SUBJECT_FIELD_IDX] else cfg.NO_FOCAL_SUBJECT
|
|
1531
1030
|
|
|
1532
1031
|
if event[-1] == cfg.POINT:
|
|
1533
1032
|
if current_states[subject]:
|
|
1534
|
-
out += (
|
|
1535
|
-
f"[{subject}]" + "+".join(current_states[subject]) + "+" + event[cfg.EVENT_BEHAVIOR_FIELD_IDX]
|
|
1536
|
-
)
|
|
1033
|
+
out += f"[{subject}]" + "+".join(current_states[subject]) + "+" + event[cfg.EVENT_BEHAVIOR_FIELD_IDX]
|
|
1537
1034
|
else:
|
|
1538
1035
|
out += f"[{subject}]" + event[cfg.EVENT_BEHAVIOR_FIELD_IDX]
|
|
1539
1036
|
|
|
@@ -1559,7 +1056,6 @@ def events_to_behavioral_sequences_all_subj(
|
|
|
1559
1056
|
out += behav_seq_separator
|
|
1560
1057
|
|
|
1561
1058
|
if event[-1] == cfg.STOP:
|
|
1562
|
-
|
|
1563
1059
|
if parameters[cfg.INCLUDE_MODIFIERS]:
|
|
1564
1060
|
behav_modif = (
|
|
1565
1061
|
f"{event[cfg.EVENT_BEHAVIOR_FIELD_IDX]}"
|
|
@@ -1601,9 +1097,7 @@ def events_to_timed_behavioral_sequences(
|
|
|
1601
1097
|
str: behavioral string for selected subject in selected observation
|
|
1602
1098
|
"""
|
|
1603
1099
|
|
|
1604
|
-
out = ""
|
|
1605
|
-
current_states = []
|
|
1606
|
-
# events_with_status = project_functions.events_start_stop(pj[ETHOGRAM], pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS])
|
|
1100
|
+
out: str = ""
|
|
1607
1101
|
|
|
1608
1102
|
state_behaviors_codes = util.state_behavior_codes(pj[cfg.ETHOGRAM])
|
|
1609
1103
|
delta = dec(str(round(precision, 3)))
|
|
@@ -1638,10 +1132,7 @@ def events_to_timed_behavioral_sequences(
|
|
|
1638
1132
|
return out
|
|
1639
1133
|
|
|
1640
1134
|
|
|
1641
|
-
def observation_to_behavioral_sequences(
|
|
1642
|
-
pj, selected_observations, parameters, behaviors_separator, separated_subjects, timed, file_name
|
|
1643
|
-
):
|
|
1644
|
-
|
|
1135
|
+
def observation_to_behavioral_sequences(pj, selected_observations, parameters, behaviors_separator, separated_subjects, timed, file_name):
|
|
1645
1136
|
try:
|
|
1646
1137
|
with open(file_name, "w", encoding="utf-8") as out_file:
|
|
1647
1138
|
for obs_id in selected_observations:
|
|
@@ -1679,9 +1170,7 @@ def observation_to_behavioral_sequences(
|
|
|
1679
1170
|
out_file.write("# Independent variables\n")
|
|
1680
1171
|
|
|
1681
1172
|
for variable in pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES]:
|
|
1682
|
-
out_file.write(
|
|
1683
|
-
f"# {variable}: {pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][variable]}\n"
|
|
1684
|
-
)
|
|
1173
|
+
out_file.write(f"# {variable}: {pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][variable]}\n")
|
|
1685
1174
|
out_file.write("\n")
|
|
1686
1175
|
|
|
1687
1176
|
# one sequence for all subjects
|
|
@@ -1702,9 +1191,7 @@ def observation_to_behavioral_sequences(
|
|
|
1702
1191
|
out = events_to_behavioral_sequences(pj, obs_id, subject, parameters, behaviors_separator)
|
|
1703
1192
|
|
|
1704
1193
|
if timed:
|
|
1705
|
-
out = events_to_timed_behavioral_sequences(
|
|
1706
|
-
pj, obs_id, subject, parameters, 0.001, behaviors_separator
|
|
1707
|
-
)
|
|
1194
|
+
out = events_to_timed_behavioral_sequences(pj, obs_id, subject, parameters, 0.001, behaviors_separator)
|
|
1708
1195
|
|
|
1709
1196
|
if out:
|
|
1710
1197
|
out_file.write(out + "\n")
|