boris-behav-obs 8.16.5__py3-none-any.whl → 9.7.12__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 +1 -1
- boris/__main__.py +1 -1
- boris/about.py +28 -40
- boris/add_modifier.py +88 -80
- boris/add_modifier_ui.py +266 -144
- boris/advanced_event_filtering.py +23 -29
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_export_to_feral.py +225 -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 +235 -236
- 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 +19 -36
- boris/config.py +109 -50
- boris/config_file.py +58 -67
- boris/connections.py +105 -58
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2174 -1303
- boris/core_qrc.py +15892 -10829
- boris/core_ui.py +941 -806
- boris/db_functions.py +17 -42
- boris/dev.py +27 -7
- boris/dialog.py +461 -242
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +405 -281
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +180 -203
- boris/export_observation.py +60 -73
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +427 -218
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +4 -4
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +325 -0
- boris/irr.py +20 -57
- boris/latency.py +31 -24
- boris/measurement_widget.py +14 -18
- boris/media_file.py +17 -19
- boris/menu_options.py +16 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv2.py +128 -35
- boris/observation.py +501 -211
- boris/observation_operations.py +1037 -393
- boris/observation_ui.py +573 -363
- boris/observations_list.py +51 -58
- boris/otx_parser.py +74 -68
- boris/param_panel.py +45 -59
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +91 -56
- boris/plot_data_module.py +20 -53
- boris/plot_events.py +56 -153
- boris/plot_events_rt.py +16 -30
- boris/plot_spectrogram_rt.py +83 -56
- boris/plot_waveform_rt.py +27 -49
- boris/plugins.py +468 -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 +307 -123
- boris/preferences_ui.py +686 -227
- boris/project.py +294 -271
- boris/project_functions.py +626 -537
- boris/project_import_export.py +204 -213
- boris/project_ui.py +673 -441
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +62 -90
- boris/select_observations.py +19 -197
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +51 -33
- boris/subjects_pad.py +7 -9
- boris/synthetic_time_budget.py +42 -26
- boris/time_budget_functions.py +169 -169
- boris/time_budget_widget.py +77 -89
- boris/transitions.py +41 -41
- boris/utilities.py +594 -226
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +86 -28
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +240 -136
- boris_behav_obs-9.7.12.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.12.dist-info/RECORD +110 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.12.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/converters.ui +0 -289
- boris/core.qrc +0 -37
- boris/core.ui +0 -1571
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -982
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1074
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.16.5.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.16.5.dist-info/METADATA +0 -134
- boris_behav_obs-8.16.5.dist-info/RECORD +0 -107
- boris_behav_obs-8.16.5.dist-info/entry_points.txt +0 -2
- {boris → boris_behav_obs-9.7.12.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.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
|
|
@@ -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
|
|
|
@@ -169,9 +166,7 @@ def export_events_jwatcher(
|
|
|
169
166
|
rows.append("#-----------------------------------------------------------")
|
|
170
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:
|
|
@@ -318,6 +313,7 @@ def export_tabular_events(
|
|
|
318
313
|
interval = parameters["time"]
|
|
319
314
|
|
|
320
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])
|
|
321
317
|
|
|
322
318
|
if interval == cfg.TIME_EVENTS:
|
|
323
319
|
min_time = start_coding
|
|
@@ -338,6 +334,12 @@ def export_tabular_events(
|
|
|
338
334
|
min_time = parameters[cfg.START_TIME]
|
|
339
335
|
max_time = parameters[cfg.END_TIME]
|
|
340
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
|
+
|
|
341
343
|
logging.debug(f"min_time: {min_time} max_time: {max_time}")
|
|
342
344
|
|
|
343
345
|
events_with_status = project_functions.events_start_stop(ethogram, observation[cfg.EVENTS], observation[cfg.TYPE])
|
|
@@ -366,6 +368,7 @@ def export_tabular_events(
|
|
|
366
368
|
"Observation duration": float,
|
|
367
369
|
"Observation type": str,
|
|
368
370
|
"Source": str,
|
|
371
|
+
"Time offset (s)": str,
|
|
369
372
|
}
|
|
370
373
|
if media_nb == 1:
|
|
371
374
|
fields_type["Media duration (s)"] = float
|
|
@@ -434,9 +437,7 @@ def export_tabular_events(
|
|
|
434
437
|
for media_file in observation[cfg.FILE][player]:
|
|
435
438
|
media_file_lst.append(media_file)
|
|
436
439
|
fps_lst.append(f"{observation[cfg.MEDIA_INFO][cfg.FPS].get(media_file, cfg.NA):.3f}")
|
|
437
|
-
media_durations_lst.append(
|
|
438
|
-
f"{observation[cfg.MEDIA_INFO][cfg.LENGTH].get(media_file, cfg.NA):.3f}"
|
|
439
|
-
)
|
|
440
|
+
media_durations_lst.append(f"{observation[cfg.MEDIA_INFO][cfg.LENGTH].get(media_file, cfg.NA):.3f}")
|
|
440
441
|
if player > "1":
|
|
441
442
|
media_file_str += "|"
|
|
442
443
|
fps_str += "|"
|
|
@@ -486,6 +487,9 @@ def export_tabular_events(
|
|
|
486
487
|
else:
|
|
487
488
|
fields.append("")
|
|
488
489
|
|
|
490
|
+
# time offset
|
|
491
|
+
fields.append(observation[cfg.TIME_OFFSET])
|
|
492
|
+
|
|
489
493
|
# media duration
|
|
490
494
|
fields.append(media_durations_str)
|
|
491
495
|
|
|
@@ -524,9 +528,7 @@ def export_tabular_events(
|
|
|
524
528
|
|
|
525
529
|
# check video file name containing the event
|
|
526
530
|
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
527
|
-
video_file_name = observation_operations.event2media_file_name(
|
|
528
|
-
observation, event[cfg.EVENT_TIME_FIELD_IDX]
|
|
529
|
-
)
|
|
531
|
+
video_file_name = observation_operations.event2media_file_name(observation, event[cfg.EVENT_TIME_FIELD_IDX])
|
|
530
532
|
if video_file_name is None:
|
|
531
533
|
video_file_name = "Not found"
|
|
532
534
|
|
|
@@ -571,9 +573,7 @@ def export_tabular_events(
|
|
|
571
573
|
return r, msg
|
|
572
574
|
|
|
573
575
|
|
|
574
|
-
def dataset_write(
|
|
575
|
-
dataset: tablib.Dataset, file_name: str, output_format: str, dtype: dict = {}
|
|
576
|
-
) -> tuple: # -> tuple[bool, str]:
|
|
576
|
+
def dataset_write(dataset: tablib.Dataset, file_name: str, output_format: str, dtype: dict = {}) -> tuple: # -> tuple[bool, str]:
|
|
577
577
|
"""
|
|
578
578
|
write a tablib dataset with aggregated events or tabular events to file in specified format (output_format)
|
|
579
579
|
|
|
@@ -593,7 +593,7 @@ def dataset_write(
|
|
|
593
593
|
try:
|
|
594
594
|
if output_format in (cfg.PANDAS_DF_EXT, cfg.RDS_EXT):
|
|
595
595
|
# build pandas dataframe from the tsv export of tablib dataset
|
|
596
|
-
date_type = []
|
|
596
|
+
date_type: list = []
|
|
597
597
|
for field_name in dtype:
|
|
598
598
|
if dtype[field_name] == dt.datetime:
|
|
599
599
|
date_type.append(field_name)
|
|
@@ -611,12 +611,12 @@ def dataset_write(
|
|
|
611
611
|
if output_format == cfg.PANDAS_DF_EXT:
|
|
612
612
|
df.to_pickle(file_name)
|
|
613
613
|
|
|
614
|
-
if
|
|
614
|
+
if output_format == cfg.RDS_EXT and flag_pyreadr_loaded:
|
|
615
615
|
pyreadr.write_rds(file_name, df)
|
|
616
616
|
|
|
617
617
|
return True, ""
|
|
618
618
|
|
|
619
|
-
if output_format in (cfg.CSV_EXT, cfg.TSV_EXT, cfg.
|
|
619
|
+
if output_format in (cfg.CSV_EXT, cfg.TSV_EXT, cfg.HTML_EXT):
|
|
620
620
|
with open(file_name, "wb") as f:
|
|
621
621
|
f.write(str.encode(dataset.export(output_format)))
|
|
622
622
|
return True, ""
|
|
@@ -634,7 +634,7 @@ def dataset_write(
|
|
|
634
634
|
return False, str(sys.exc_info()[1])
|
|
635
635
|
|
|
636
636
|
|
|
637
|
-
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]:
|
|
638
638
|
"""
|
|
639
639
|
export aggregated events of one observation
|
|
640
640
|
|
|
@@ -642,6 +642,7 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
642
642
|
pj (dict): BORIS project
|
|
643
643
|
parameters (dict): subjects, behaviors
|
|
644
644
|
obsId (str): observation id
|
|
645
|
+
force_number_modifiers (int): force the number of modifiers to return
|
|
645
646
|
|
|
646
647
|
Returns:
|
|
647
648
|
tablib.Dataset:
|
|
@@ -656,6 +657,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
656
657
|
data = tablib.Dataset()
|
|
657
658
|
|
|
658
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
|
+
|
|
659
662
|
if start_coding is None and end_coding is None: # no events
|
|
660
663
|
return data, 0
|
|
661
664
|
|
|
@@ -677,21 +680,22 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
677
680
|
min_time = float(parameters[cfg.START_TIME])
|
|
678
681
|
max_time = float(parameters[cfg.END_TIME])
|
|
679
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
|
+
|
|
680
689
|
logging.debug(f"min_time: {min_time} max_time: {max_time}")
|
|
681
690
|
|
|
682
691
|
# obs description
|
|
683
692
|
obs_description = util.eol2space(observation[cfg.DESCRIPTION])
|
|
684
693
|
|
|
685
|
-
"""
|
|
686
|
-
obs_length = observation_operations.observation_total_length(pj[cfg.OBSERVATIONS][obsId])
|
|
687
|
-
logging.debug(f"obs_length: {obs_length}")
|
|
688
|
-
"""
|
|
689
|
-
|
|
690
694
|
_, _, connector = db_functions.load_aggregated_events_in_db(
|
|
691
695
|
pj, parameters[cfg.SELECTED_SUBJECTS], [obsId], parameters[cfg.SELECTED_BEHAVIORS]
|
|
692
696
|
)
|
|
693
697
|
if connector is None:
|
|
694
|
-
logging.critical(
|
|
698
|
+
logging.critical("error when loading aggregated events in DB")
|
|
695
699
|
return data, 0
|
|
696
700
|
|
|
697
701
|
cursor = connector.cursor()
|
|
@@ -745,10 +749,14 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
745
749
|
behavioral_category = project_functions.behavior_category(pj[cfg.ETHOGRAM])
|
|
746
750
|
|
|
747
751
|
cursor.execute("SELECT DISTINCT modifiers FROM aggregated_events")
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
+
|
|
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
|
|
752
760
|
|
|
753
761
|
for subject in parameters[cfg.SELECTED_SUBJECTS]:
|
|
754
762
|
# calculate observation duration by subject (by obs)
|
|
@@ -785,6 +793,7 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
785
793
|
if observation[cfg.TYPE] == cfg.MEDIA:
|
|
786
794
|
observation_type = "Media file"
|
|
787
795
|
|
|
796
|
+
# get the media file name of the start of event
|
|
788
797
|
media_file_name = observation_operations.event2media_file_name(observation, row["start"])
|
|
789
798
|
if media_file_name is None:
|
|
790
799
|
media_file_name = "Not found"
|
|
@@ -796,12 +805,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
796
805
|
if observation[cfg.FILE][player]:
|
|
797
806
|
for media_file in observation[cfg.FILE][player]:
|
|
798
807
|
media_file_lst.append(media_file)
|
|
799
|
-
fps_lst.append(
|
|
800
|
-
|
|
801
|
-
)
|
|
802
|
-
media_durations_lst.append(
|
|
803
|
-
f"{observation[cfg.MEDIA_INFO][cfg.LENGTH].get(media_file, cfg.NA):.3f}"
|
|
804
|
-
)
|
|
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}")
|
|
805
810
|
if player > "1":
|
|
806
811
|
media_file_str += "|"
|
|
807
812
|
fps_str += "|"
|
|
@@ -833,7 +838,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
833
838
|
observation["date"].replace("T", " "),
|
|
834
839
|
obs_description,
|
|
835
840
|
observation_type,
|
|
836
|
-
media_file_str,
|
|
841
|
+
media_file_str, # list of media used in observation
|
|
842
|
+
pj[cfg.OBSERVATIONS][obsId][cfg.TIME_OFFSET],
|
|
837
843
|
f"{coding_duration:.3f}" if not coding_duration.is_nan() else cfg.NA,
|
|
838
844
|
media_durations_str,
|
|
839
845
|
fps_str,
|
|
@@ -843,13 +849,8 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
843
849
|
# independent variables
|
|
844
850
|
if cfg.INDEPENDENT_VARIABLES in pj:
|
|
845
851
|
for idx_var in util.sorted_keys(pj[cfg.INDEPENDENT_VARIABLES]):
|
|
846
|
-
if
|
|
847
|
-
pj[cfg.INDEPENDENT_VARIABLES][idx_var]["label"]
|
|
848
|
-
in observation[cfg.INDEPENDENT_VARIABLES]
|
|
849
|
-
):
|
|
850
|
-
var_value = observation[cfg.INDEPENDENT_VARIABLES][
|
|
851
|
-
pj[cfg.INDEPENDENT_VARIABLES][idx_var]["label"]
|
|
852
|
-
]
|
|
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"]]
|
|
853
854
|
if pj[cfg.INDEPENDENT_VARIABLES][idx_var]["type"] == "timestamp":
|
|
854
855
|
var_value = var_value.replace("T", " ")
|
|
855
856
|
|
|
@@ -892,9 +893,7 @@ def export_aggregated_events(pj: dict, parameters: dict, obsId: str) -> Tuple[ta
|
|
|
892
893
|
f"{row['start']:.3f}" if row["start"] is not None else cfg.NA,
|
|
893
894
|
f"{row['stop']:.3f}" if row["stop"] is not None else cfg.NA,
|
|
894
895
|
# duration
|
|
895
|
-
f"{row['stop'] - row['start']:.3f}"
|
|
896
|
-
if (row["stop"] is not None) and (row["start"] is not None)
|
|
897
|
-
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,
|
|
898
897
|
media_file_name, # Media file name
|
|
899
898
|
]
|
|
900
899
|
)
|
|
@@ -943,9 +942,7 @@ def events_to_behavioral_sequences(pj, obs_id: str, subj: str, parameters: dict,
|
|
|
943
942
|
if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] not in parameters[cfg.SELECTED_BEHAVIORS]:
|
|
944
943
|
continue
|
|
945
944
|
|
|
946
|
-
if event[cfg.EVENT_SUBJECT_FIELD_IDX] == subj or (
|
|
947
|
-
subj == cfg.NO_FOCAL_SUBJECT and event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""
|
|
948
|
-
):
|
|
945
|
+
if event[cfg.EVENT_SUBJECT_FIELD_IDX] == subj or (subj == cfg.NO_FOCAL_SUBJECT and event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""):
|
|
949
946
|
# if event[cfg.EVENT_STATUS_FIELD_IDX] == cfg.POINT:
|
|
950
947
|
if event[-1] == cfg.POINT: # status is last element
|
|
951
948
|
if current_states:
|
|
@@ -1000,9 +997,7 @@ def events_to_behavioral_sequences(pj, obs_id: str, subj: str, parameters: dict,
|
|
|
1000
997
|
return out
|
|
1001
998
|
|
|
1002
999
|
|
|
1003
|
-
def events_to_behavioral_sequences_all_subj(
|
|
1004
|
-
pj, obs_id: str, subjects_list: list, parameters: dict, behav_seq_separator: str
|
|
1005
|
-
) -> str:
|
|
1000
|
+
def events_to_behavioral_sequences_all_subj(pj, obs_id: str, subjects_list: list, parameters: dict, behav_seq_separator: str) -> str:
|
|
1006
1001
|
"""
|
|
1007
1002
|
return the behavioral sequences for all selected subjects in obs_id
|
|
1008
1003
|
|
|
@@ -1035,9 +1030,7 @@ def events_to_behavioral_sequences_all_subj(
|
|
|
1035
1030
|
|
|
1036
1031
|
if event[-1] == cfg.POINT:
|
|
1037
1032
|
if current_states[subject]:
|
|
1038
|
-
out += (
|
|
1039
|
-
f"[{subject}]" + "+".join(current_states[subject]) + "+" + event[cfg.EVENT_BEHAVIOR_FIELD_IDX]
|
|
1040
|
-
)
|
|
1033
|
+
out += f"[{subject}]" + "+".join(current_states[subject]) + "+" + event[cfg.EVENT_BEHAVIOR_FIELD_IDX]
|
|
1041
1034
|
else:
|
|
1042
1035
|
out += f"[{subject}]" + event[cfg.EVENT_BEHAVIOR_FIELD_IDX]
|
|
1043
1036
|
|
|
@@ -1139,9 +1132,7 @@ def events_to_timed_behavioral_sequences(
|
|
|
1139
1132
|
return out
|
|
1140
1133
|
|
|
1141
1134
|
|
|
1142
|
-
def observation_to_behavioral_sequences(
|
|
1143
|
-
pj, selected_observations, parameters, behaviors_separator, separated_subjects, timed, file_name
|
|
1144
|
-
):
|
|
1135
|
+
def observation_to_behavioral_sequences(pj, selected_observations, parameters, behaviors_separator, separated_subjects, timed, file_name):
|
|
1145
1136
|
try:
|
|
1146
1137
|
with open(file_name, "w", encoding="utf-8") as out_file:
|
|
1147
1138
|
for obs_id in selected_observations:
|
|
@@ -1179,9 +1170,7 @@ def observation_to_behavioral_sequences(
|
|
|
1179
1170
|
out_file.write("# Independent variables\n")
|
|
1180
1171
|
|
|
1181
1172
|
for variable in pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES]:
|
|
1182
|
-
out_file.write(
|
|
1183
|
-
f"# {variable}: {pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][variable]}\n"
|
|
1184
|
-
)
|
|
1173
|
+
out_file.write(f"# {variable}: {pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][variable]}\n")
|
|
1185
1174
|
out_file.write("\n")
|
|
1186
1175
|
|
|
1187
1176
|
# one sequence for all subjects
|
|
@@ -1202,9 +1191,7 @@ def observation_to_behavioral_sequences(
|
|
|
1202
1191
|
out = events_to_behavioral_sequences(pj, obs_id, subject, parameters, behaviors_separator)
|
|
1203
1192
|
|
|
1204
1193
|
if timed:
|
|
1205
|
-
out = events_to_timed_behavioral_sequences(
|
|
1206
|
-
pj, obs_id, subject, parameters, 0.001, behaviors_separator
|
|
1207
|
-
)
|
|
1194
|
+
out = events_to_timed_behavioral_sequences(pj, obs_id, subject, parameters, 0.001, behaviors_separator)
|
|
1208
1195
|
|
|
1209
1196
|
if out:
|
|
1210
1197
|
out_file.write(out + "\n")
|