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.
Files changed (126) hide show
  1. boris/__init__.py +1 -1
  2. boris/__main__.py +1 -1
  3. boris/about.py +28 -40
  4. boris/add_modifier.py +88 -80
  5. boris/add_modifier_ui.py +266 -144
  6. boris/advanced_event_filtering.py +23 -29
  7. boris/analysis_plugins/__init__.py +0 -0
  8. boris/analysis_plugins/_export_to_feral.py +225 -0
  9. boris/analysis_plugins/_latency.py +59 -0
  10. boris/analysis_plugins/irr_cohen_kappa.py +109 -0
  11. boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
  12. boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
  13. boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
  14. boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
  15. boris/analysis_plugins/number_of_occurences.py +22 -0
  16. boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
  17. boris/analysis_plugins/time_budget.py +61 -0
  18. boris/behav_coding_map_creator.py +235 -236
  19. boris/behavior_binary_table.py +33 -50
  20. boris/behaviors_coding_map.py +17 -18
  21. boris/boris_cli.py +6 -25
  22. boris/cmd_arguments.py +12 -1
  23. boris/coding_pad.py +19 -36
  24. boris/config.py +109 -50
  25. boris/config_file.py +58 -67
  26. boris/connections.py +105 -58
  27. boris/converters.py +13 -37
  28. boris/converters_ui.py +187 -110
  29. boris/cooccurence.py +250 -0
  30. boris/core.py +2174 -1303
  31. boris/core_qrc.py +15892 -10829
  32. boris/core_ui.py +941 -806
  33. boris/db_functions.py +17 -42
  34. boris/dev.py +27 -7
  35. boris/dialog.py +461 -242
  36. boris/duration_widget.py +9 -14
  37. boris/edit_event.py +61 -31
  38. boris/edit_event_ui.py +208 -97
  39. boris/event_operations.py +405 -281
  40. boris/events_cursor.py +25 -17
  41. boris/events_snapshots.py +36 -82
  42. boris/exclusion_matrix.py +4 -9
  43. boris/export_events.py +180 -203
  44. boris/export_observation.py +60 -73
  45. boris/external_processes.py +123 -98
  46. boris/geometric_measurement.py +427 -218
  47. boris/gui_utilities.py +91 -14
  48. boris/image_overlay.py +4 -4
  49. boris/import_observations.py +190 -98
  50. boris/ipc_mpv.py +325 -0
  51. boris/irr.py +20 -57
  52. boris/latency.py +31 -24
  53. boris/measurement_widget.py +14 -18
  54. boris/media_file.py +17 -19
  55. boris/menu_options.py +16 -6
  56. boris/modifier_coding_map_creator.py +1013 -0
  57. boris/modifiers_coding_map.py +7 -9
  58. boris/mpv2.py +128 -35
  59. boris/observation.py +501 -211
  60. boris/observation_operations.py +1037 -393
  61. boris/observation_ui.py +573 -363
  62. boris/observations_list.py +51 -58
  63. boris/otx_parser.py +74 -68
  64. boris/param_panel.py +45 -59
  65. boris/param_panel_ui.py +254 -138
  66. boris/player_dock_widget.py +91 -56
  67. boris/plot_data_module.py +20 -53
  68. boris/plot_events.py +56 -153
  69. boris/plot_events_rt.py +16 -30
  70. boris/plot_spectrogram_rt.py +83 -56
  71. boris/plot_waveform_rt.py +27 -49
  72. boris/plugins.py +468 -0
  73. boris/portion/__init__.py +18 -8
  74. boris/portion/const.py +35 -18
  75. boris/portion/dict.py +5 -5
  76. boris/portion/func.py +2 -2
  77. boris/portion/interval.py +21 -41
  78. boris/portion/io.py +41 -32
  79. boris/preferences.py +307 -123
  80. boris/preferences_ui.py +686 -227
  81. boris/project.py +294 -271
  82. boris/project_functions.py +626 -537
  83. boris/project_import_export.py +204 -213
  84. boris/project_ui.py +673 -441
  85. boris/qrc_boris.py +6 -3
  86. boris/qrc_boris5.py +6 -3
  87. boris/select_modifiers.py +62 -90
  88. boris/select_observations.py +19 -197
  89. boris/select_subj_behav.py +67 -39
  90. boris/state_events.py +51 -33
  91. boris/subjects_pad.py +7 -9
  92. boris/synthetic_time_budget.py +42 -26
  93. boris/time_budget_functions.py +169 -169
  94. boris/time_budget_widget.py +77 -89
  95. boris/transitions.py +41 -41
  96. boris/utilities.py +594 -226
  97. boris/version.py +3 -3
  98. boris/video_equalizer.py +16 -14
  99. boris/video_equalizer_ui.py +199 -130
  100. boris/video_operations.py +86 -28
  101. boris/view_df.py +104 -0
  102. boris/view_df_ui.py +75 -0
  103. boris/write_event.py +240 -136
  104. boris_behav_obs-9.7.12.dist-info/METADATA +139 -0
  105. boris_behav_obs-9.7.12.dist-info/RECORD +110 -0
  106. {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/WHEEL +1 -1
  107. boris_behav_obs-9.7.12.dist-info/entry_points.txt +2 -0
  108. boris/README.TXT +0 -22
  109. boris/add_modifier.ui +0 -323
  110. boris/converters.ui +0 -289
  111. boris/core.qrc +0 -37
  112. boris/core.ui +0 -1571
  113. boris/edit_event.ui +0 -233
  114. boris/icons/logo_eye.ico +0 -0
  115. boris/map_creator.py +0 -982
  116. boris/observation.ui +0 -814
  117. boris/param_panel.ui +0 -379
  118. boris/preferences.ui +0 -537
  119. boris/project.ui +0 -1074
  120. boris/vlc_local.py +0 -90
  121. boris_behav_obs-8.16.5.dist-info/LICENSE.TXT +0 -674
  122. boris_behav_obs-8.16.5.dist-info/METADATA +0 -134
  123. boris_behav_obs-8.16.5.dist-info/RECORD +0 -107
  124. boris_behav_obs-8.16.5.dist-info/entry_points.txt +0 -2
  125. {boris → boris_behav_obs-9.7.12.dist-info/licenses}/LICENSE.TXT +0 -0
  126. {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/top_level.txt +0 -0
boris/db_functions.py CHANGED
@@ -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
 
7
7
  This program is free software; you can redistribute it and/or modify
@@ -56,8 +56,7 @@ def load_events_in_db(
56
56
  state_behaviors_codes = [
57
57
  pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
58
58
  for x in pj[cfg.ETHOGRAM]
59
- if cfg.STATE in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper()
60
- and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
59
+ if cfg.STATE in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper() and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
61
60
  ]
62
61
 
63
62
  # selected behaviors defined as point event
@@ -71,6 +70,7 @@ def load_events_in_db(
71
70
  """
72
71
 
73
72
  db = sqlite3.connect(":memory:", isolation_level=None)
73
+
74
74
  """
75
75
  import os
76
76
  os.system("rm /tmp/ramdisk/events.sqlite")
@@ -99,20 +99,14 @@ def load_events_in_db(
99
99
  cursor.execute("CREATE INDEX modifiers_idx ON events(modifiers)")
100
100
 
101
101
  for subject_to_analyze in selected_subjects:
102
-
103
102
  for obs_id in selected_observations:
104
-
105
103
  for event in pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]:
106
-
107
104
  if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in selected_behaviors:
108
-
109
105
  # extract time, code, modifier and comment (time:0, subject:1, code:2, modifier:3, comment:4)
110
106
  if (subject_to_analyze == cfg.NO_FOCAL_SUBJECT and event[cfg.EVENT_SUBJECT_FIELD_IDX] == "") or (
111
107
  event[cfg.EVENT_SUBJECT_FIELD_IDX] == subject_to_analyze
112
108
  ):
113
-
114
109
  if pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
115
-
116
110
  cursor.execute(
117
111
  (
118
112
  "INSERT INTO events "
@@ -125,18 +119,12 @@ def load_events_in_db(
125
119
  if event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""
126
120
  else event[cfg.EVENT_SUBJECT_FIELD_IDX],
127
121
  event[cfg.EVENT_BEHAVIOR_FIELD_IDX],
128
- cfg.STATE
129
- if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in state_behaviors_codes
130
- else cfg.POINT,
122
+ cfg.STATE if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in state_behaviors_codes else cfg.POINT,
131
123
  event[cfg.EVENT_MODIFIER_FIELD_IDX],
132
- float(event[cfg.EVENT_TIME_FIELD_IDX])
133
- if not event[cfg.EVENT_TIME_FIELD_IDX].is_nan()
134
- else None,
124
+ float(event[cfg.EVENT_TIME_FIELD_IDX]) if not event[cfg.EVENT_TIME_FIELD_IDX].is_nan() else None,
135
125
  event[cfg.EVENT_COMMENT_FIELD_IDX],
136
126
  # frame index or NA
137
- event_operations.read_event_field(
138
- event, pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE], cfg.FRAME_INDEX
139
- ),
127
+ event_operations.read_event_field(event, pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE], cfg.FRAME_INDEX),
140
128
  ),
141
129
  )
142
130
 
@@ -153,13 +141,9 @@ def load_events_in_db(
153
141
  if event[cfg.EVENT_SUBJECT_FIELD_IDX] == ""
154
142
  else event[cfg.EVENT_SUBJECT_FIELD_IDX],
155
143
  event[cfg.EVENT_BEHAVIOR_FIELD_IDX],
156
- cfg.STATE
157
- if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in state_behaviors_codes
158
- else cfg.POINT,
144
+ cfg.STATE if event[cfg.EVENT_BEHAVIOR_FIELD_IDX] in state_behaviors_codes else cfg.POINT,
159
145
  event[cfg.EVENT_MODIFIER_FIELD_IDX],
160
- float(event[cfg.EVENT_TIME_FIELD_IDX])
161
- if not event[cfg.EVENT_TIME_FIELD_IDX].is_nan()
162
- else None,
146
+ float(event[cfg.EVENT_TIME_FIELD_IDX]) if not event[cfg.EVENT_TIME_FIELD_IDX].is_nan() else None,
163
147
  event[cfg.EVENT_COMMENT_FIELD_IDX],
164
148
  event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_INDEX]],
165
149
  event[cfg.PJ_OBS_FIELDS[cfg.IMAGES][cfg.IMAGE_PATH]],
@@ -189,7 +173,7 @@ def load_aggregated_events_in_db(
189
173
 
190
174
  """
191
175
 
192
- logging.debug(f"function: load_aggregated_events_in_db")
176
+ logging.debug("function: load_aggregated_events_in_db")
193
177
 
194
178
  # if no observation selected select all
195
179
  if not selected_observations:
@@ -197,20 +181,16 @@ def load_aggregated_events_in_db(
197
181
 
198
182
  # if no subject selected select all
199
183
  if not selected_subjects:
200
- selected_subjects = sorted(
201
- [pj[cfg.SUBJECTS][x][cfg.SUBJECT_NAME] for x in pj[cfg.SUBJECTS]] + [cfg.NO_FOCAL_SUBJECT]
202
- )
184
+ selected_subjects = sorted([pj[cfg.SUBJECTS][x][cfg.SUBJECT_NAME] for x in pj[cfg.SUBJECTS]] + [cfg.NO_FOCAL_SUBJECT])
203
185
 
204
186
  # if no behavior selected select all
205
187
  if not selected_behaviors:
206
188
  selected_behaviors = sorted([pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] for x in pj[cfg.ETHOGRAM]])
207
189
 
208
190
  # check if state events are paired
209
- out = ""
191
+ out: str = ""
210
192
  for obs_id in selected_observations:
211
- r, msg = project_functions.check_state_events_obs(
212
- obs_id, pj[cfg.ETHOGRAM], pj[cfg.OBSERVATIONS][obs_id], cfg.HHMMSS
213
- )
193
+ r, msg = project_functions.check_state_events_obs(obs_id, pj[cfg.ETHOGRAM], pj[cfg.OBSERVATIONS][obs_id], cfg.HHMMSS)
214
194
  if not r:
215
195
  out += f"Observation: <strong>{obs_id}</strong><br>{msg}<br>"
216
196
  if out:
@@ -220,24 +200,23 @@ def load_aggregated_events_in_db(
220
200
  state_behaviors_codes = [
221
201
  pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
222
202
  for x in pj[cfg.ETHOGRAM]
223
- if cfg.STATE in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper()
224
- and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
203
+ if cfg.STATE in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper() and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
225
204
  ]
226
205
 
227
206
  # selected behaviors defined as point event
228
207
  point_behaviors_codes = [
229
208
  pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
230
209
  for x in pj[cfg.ETHOGRAM]
231
- if cfg.POINT in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper()
232
- and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
210
+ if cfg.POINT in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper() and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
233
211
  ]
234
212
 
235
213
  db = sqlite3.connect(":memory:")
236
214
 
215
+ # only for debugging
237
216
  """
238
217
  import os
239
- os.system("rm /tmp/ramdisk/aggreg.sqlite")
240
- db = sqlite3.connect("/tmp/ramdisk/aggreg.sqlite", isolation_level=None)
218
+ os.system("rm /tmp/ramdisk/aggregated_events.sqlite")
219
+ db = sqlite3.connect("/tmp/ramdisk/aggregated_events.sqlite", isolation_level=None)
241
220
  """
242
221
 
243
222
  db.row_factory = sqlite3.Row
@@ -277,12 +256,10 @@ def load_aggregated_events_in_db(
277
256
  )
278
257
 
279
258
  for obs_id in selected_observations:
280
-
281
259
  cursor1 = load_events_in_db(pj, selected_subjects, [obs_id], selected_behaviors)
282
260
 
283
261
  for subject in selected_subjects:
284
262
  for behavior in selected_behaviors:
285
-
286
263
  cursor1.execute(
287
264
  "SELECT DISTINCT modifiers FROM events WHERE subject=? AND code=? ORDER BY modifiers",
288
265
  (
@@ -294,7 +271,6 @@ def load_aggregated_events_in_db(
294
271
  rows_distinct_modifiers = list(x[0] for x in cursor1.fetchall())
295
272
 
296
273
  for distinct_modifiers in rows_distinct_modifiers:
297
-
298
274
  cursor1.execute(
299
275
  (
300
276
  "SELECT occurence, comment, image_index, image_path FROM events "
@@ -305,7 +281,6 @@ def load_aggregated_events_in_db(
305
281
  rows = list(cursor1.fetchall())
306
282
 
307
283
  for idx, row in enumerate(rows):
308
-
309
284
  if behavior in point_behaviors_codes:
310
285
  data = (
311
286
  obs_id,
boris/dev.py CHANGED
@@ -47,22 +47,32 @@ for obs_id in pj[cfg.OBSERVATIONS]:
47
47
  # print(obs_id)
48
48
  obs_type = pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE]
49
49
  obs_descr = pj[cfg.OBSERVATIONS][obs_id][cfg.DESCRIPTION]
50
-
50
+ mem_idx = []
51
51
  for idx, event in enumerate(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]):
52
+ if idx in mem_idx:
53
+ continue
52
54
  start = event_val(event, cfg.TIME)
53
55
  subject = event_val(event, cfg.SUBJECT)
54
56
  behavior = event_val(event, cfg.BEHAVIOR_CODE)
55
57
  modifier = event_val(event, cfg.MODIFIER)
56
58
  if behavior in state_events_list:
57
- for idx2, event2 in enumerate(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS][idx + 1 :]):
59
+ stop = None
60
+ for idx2, event2 in enumerate(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS][idx + 1 :], start=idx + 1):
58
61
  subject2 = event_val(event2, cfg.SUBJECT)
59
62
  behavior2 = event_val(event2, cfg.BEHAVIOR_CODE)
60
63
  modifier2 = event_val(event2, cfg.MODIFIER)
61
64
  if subject == subject2 and behavior == behavior2 and modifier == modifier2:
62
65
  stop = event_val(event2, cfg.TIME)
66
+ mem_idx.append(idx2)
63
67
  l.append([obs_id, obs_type, obs_descr, subject, behavior, modifier, start, stop, stop - start])
64
68
  break
69
+ if stop is None:
70
+ print(obs_id, " not paired")
71
+ # print(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS])
72
+ # print(f"{l=}")
73
+ # print(f"{mem_idx=}")
65
74
 
75
+ sys.exit()
66
76
  else:
67
77
  l.append([obs_id, obs_type, obs_descr, subject, behavior, modifier, start, start, 0])
68
78
 
@@ -87,16 +97,26 @@ df = pd.concat(
87
97
  ]
88
98
  )
89
99
  del l
100
+ print("=" * 30)
101
+ print("describe")
90
102
  print(df.describe())
103
+ print("=" * 30)
91
104
 
92
- print(f'{df["subject"].value_counts()=}')
93
- print(f'{df["subject"].nunique()=}')
94
-
95
- r = df.groupby(["subject", "behavior"])["duration"].sum()
96
-
105
+ # print(f'{df["subject"].value_counts()=}')
106
+ # print(f'{df["subject"].nunique()=}')
97
107
 
98
108
  pd.set_option("display.max_rows", None, "display.max_columns", None)
109
+
110
+ print("=" * 30)
111
+ print("mean")
112
+ r = df.groupby(["subject", "behavior"])["duration"].mean()
99
113
  print(r)
114
+ print("=" * 30)
115
+
116
+
117
+ r = df.groupby(["observation id", "subject", "behavior"])
118
+ print(r["start"])
119
+
100
120
 
101
121
  """
102
122
  # replace value (for selecting a time interval)