boris-behav-obs 8.16.6__py3-none-any.whl → 9.7.1__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.
Files changed (125) hide show
  1. boris/__init__.py +1 -1
  2. boris/__main__.py +1 -1
  3. boris/about.py +24 -40
  4. boris/add_modifier.py +88 -80
  5. boris/add_modifier_ui.py +235 -131
  6. boris/advanced_event_filtering.py +23 -29
  7. boris/analysis_plugins/__init__.py +0 -0
  8. boris/analysis_plugins/_latency.py +59 -0
  9. boris/analysis_plugins/irr_cohen_kappa.py +109 -0
  10. boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
  11. boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
  12. boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
  13. boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
  14. boris/analysis_plugins/number_of_occurences.py +22 -0
  15. boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
  16. boris/analysis_plugins/time_budget.py +61 -0
  17. boris/behav_coding_map_creator.py +228 -229
  18. boris/behavior_binary_table.py +33 -50
  19. boris/behaviors_coding_map.py +17 -18
  20. boris/boris_cli.py +6 -25
  21. boris/cmd_arguments.py +12 -1
  22. boris/coding_pad.py +16 -34
  23. boris/config.py +101 -49
  24. boris/config_file.py +55 -64
  25. boris/connections.py +105 -58
  26. boris/converters.py +13 -37
  27. boris/converters_ui.py +187 -110
  28. boris/cooccurence.py +250 -0
  29. boris/core.py +2108 -1275
  30. boris/core_qrc.py +15892 -10829
  31. boris/core_ui.py +941 -806
  32. boris/db_functions.py +17 -42
  33. boris/dev.py +134 -0
  34. boris/dialog.py +461 -242
  35. boris/duration_widget.py +9 -14
  36. boris/edit_event.py +61 -31
  37. boris/edit_event_ui.py +208 -97
  38. boris/event_operations.py +405 -281
  39. boris/events_cursor.py +25 -17
  40. boris/events_snapshots.py +36 -82
  41. boris/exclusion_matrix.py +4 -9
  42. boris/export_events.py +180 -203
  43. boris/export_observation.py +60 -73
  44. boris/external_processes.py +123 -98
  45. boris/geometric_measurement.py +427 -218
  46. boris/gui_utilities.py +91 -14
  47. boris/image_overlay.py +4 -4
  48. boris/import_observations.py +190 -98
  49. boris/ipc_mpv.py +304 -0
  50. boris/irr.py +20 -57
  51. boris/latency.py +31 -24
  52. boris/measurement_widget.py +14 -18
  53. boris/media_file.py +17 -19
  54. boris/menu_options.py +16 -6
  55. boris/modifier_coding_map_creator.py +1013 -0
  56. boris/modifiers_coding_map.py +7 -9
  57. boris/mpv2.py +127 -36
  58. boris/observation.py +493 -210
  59. boris/observation_operations.py +1010 -391
  60. boris/observation_ui.py +573 -363
  61. boris/observations_list.py +51 -58
  62. boris/otx_parser.py +74 -68
  63. boris/param_panel.py +45 -59
  64. boris/param_panel_ui.py +254 -138
  65. boris/player_dock_widget.py +91 -56
  66. boris/plot_data_module.py +18 -53
  67. boris/plot_events.py +56 -153
  68. boris/plot_events_rt.py +16 -30
  69. boris/plot_spectrogram_rt.py +80 -56
  70. boris/plot_waveform_rt.py +23 -48
  71. boris/plugins.py +431 -0
  72. boris/portion/__init__.py +18 -8
  73. boris/portion/const.py +35 -18
  74. boris/portion/dict.py +5 -5
  75. boris/portion/func.py +2 -2
  76. boris/portion/interval.py +21 -41
  77. boris/portion/io.py +41 -32
  78. boris/preferences.py +298 -123
  79. boris/preferences_ui.py +664 -225
  80. boris/project.py +293 -270
  81. boris/project_functions.py +610 -537
  82. boris/project_import_export.py +204 -213
  83. boris/project_ui.py +673 -441
  84. boris/qrc_boris.py +6 -3
  85. boris/qrc_boris5.py +6 -3
  86. boris/select_modifiers.py +62 -90
  87. boris/select_observations.py +19 -197
  88. boris/select_subj_behav.py +67 -39
  89. boris/state_events.py +51 -33
  90. boris/subjects_pad.py +6 -8
  91. boris/synthetic_time_budget.py +25 -17
  92. boris/time_budget_functions.py +169 -169
  93. boris/time_budget_widget.py +71 -86
  94. boris/transitions.py +41 -41
  95. boris/utilities.py +562 -222
  96. boris/version.py +3 -3
  97. boris/video_equalizer.py +16 -14
  98. boris/video_equalizer_ui.py +199 -130
  99. boris/video_operations.py +78 -28
  100. boris/view_df.py +104 -0
  101. boris/view_df_ui.py +75 -0
  102. boris/write_event.py +240 -136
  103. boris_behav_obs-9.7.1.dist-info/METADATA +140 -0
  104. boris_behav_obs-9.7.1.dist-info/RECORD +109 -0
  105. {boris_behav_obs-8.16.6.dist-info → boris_behav_obs-9.7.1.dist-info}/WHEEL +1 -1
  106. boris_behav_obs-9.7.1.dist-info/entry_points.txt +2 -0
  107. boris/README.TXT +0 -22
  108. boris/add_modifier.ui +0 -323
  109. boris/converters.ui +0 -289
  110. boris/core.qrc +0 -37
  111. boris/core.ui +0 -1571
  112. boris/edit_event.ui +0 -233
  113. boris/icons/logo_eye.ico +0 -0
  114. boris/map_creator.py +0 -982
  115. boris/observation.ui +0 -814
  116. boris/param_panel.ui +0 -379
  117. boris/preferences.ui +0 -537
  118. boris/project.ui +0 -1074
  119. boris/vlc_local.py +0 -90
  120. boris_behav_obs-8.16.6.dist-info/LICENSE.TXT +0 -674
  121. boris_behav_obs-8.16.6.dist-info/METADATA +0 -134
  122. boris_behav_obs-8.16.6.dist-info/RECORD +0 -106
  123. boris_behav_obs-8.16.6.dist-info/entry_points.txt +0 -2
  124. {boris → boris_behav_obs-9.7.1.dist-info/licenses}/LICENSE.TXT +0 -0
  125. {boris_behav_obs-8.16.6.dist-info → boris_behav_obs-9.7.1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  """
2
2
  BORIS
3
3
  Behavioral Observation Research Interactive Software
4
- Copyright 2012-2023 Olivier Friard
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 List, Tuple, Dict
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>" "What do you want to do?"),
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>" "What do you want to do?"),
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 flag_pyreadr_loaded and output_format == cfg.RDS_EXT:
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.HMTL_EXT):
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(f"error when loading aggregated events in DB")
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
- max_modifiers = 0
749
- for row in cursor.fetchall():
750
- if row["modifiers"]:
751
- max_modifiers = max(max_modifiers, row["modifiers"].count("|") + 1)
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
- f"{observation[cfg.MEDIA_INFO][cfg.FPS].get(media_file, cfg.NA):.3f}"
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")