boris-behav-obs 8.12__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.

Files changed (128) hide show
  1. boris/__init__.py +1 -1
  2. boris/__main__.py +1 -1
  3. boris/about.py +28 -39
  4. boris/add_modifier.py +122 -109
  5. boris/add_modifier_ui.py +239 -135
  6. boris/advanced_event_filtering.py +81 -45
  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 +42 -49
  23. boris/config.py +141 -65
  24. boris/config_file.py +58 -67
  25. boris/connections.py +107 -61
  26. boris/converters.py +13 -37
  27. boris/converters_ui.py +187 -110
  28. boris/cooccurence.py +250 -0
  29. boris/core.py +2373 -1786
  30. boris/core_qrc.py +15895 -10743
  31. boris/core_ui.py +943 -798
  32. boris/db_functions.py +17 -42
  33. boris/dev.py +109 -8
  34. boris/dialog.py +482 -236
  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 +408 -293
  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 +184 -223
  43. boris/export_observation.py +74 -100
  44. boris/external_processes.py +123 -98
  45. boris/geometric_measurement.py +644 -290
  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 +325 -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 +17 -6
  55. boris/modifier_coding_map_creator.py +1013 -0
  56. boris/modifiers_coding_map.py +7 -9
  57. boris/mpv.py +1 -0
  58. boris/mpv2.py +732 -705
  59. boris/observation.py +533 -221
  60. boris/observation_operations.py +1025 -390
  61. boris/observation_ui.py +572 -362
  62. boris/observations_list.py +71 -53
  63. boris/otx_parser.py +74 -68
  64. boris/param_panel.py +31 -16
  65. boris/param_panel_ui.py +254 -138
  66. boris/player_dock_widget.py +90 -60
  67. boris/plot_data_module.py +25 -33
  68. boris/plot_events.py +127 -90
  69. boris/plot_events_rt.py +17 -31
  70. boris/plot_spectrogram_rt.py +95 -30
  71. boris/plot_waveform_rt.py +32 -21
  72. boris/plugins.py +431 -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 +306 -83
  80. boris/preferences_ui.py +684 -227
  81. boris/project.py +448 -293
  82. boris/project_functions.py +671 -238
  83. boris/project_import_export.py +213 -222
  84. boris/project_ui.py +674 -438
  85. boris/qrc_boris.py +6 -3
  86. boris/qrc_boris5.py +6 -3
  87. boris/select_modifiers.py +74 -48
  88. boris/select_observations.py +20 -198
  89. boris/select_subj_behav.py +67 -39
  90. boris/state_events.py +52 -35
  91. boris/subjects_pad.py +6 -9
  92. boris/synthetic_time_budget.py +45 -28
  93. boris/time_budget_functions.py +171 -171
  94. boris/time_budget_widget.py +84 -114
  95. boris/transitions.py +41 -47
  96. boris/utilities.py +627 -236
  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 +95 -29
  101. boris/view_df.py +104 -0
  102. boris/view_df_ui.py +75 -0
  103. boris/write_event.py +538 -0
  104. boris_behav_obs-9.7.6.dist-info/METADATA +139 -0
  105. boris_behav_obs-9.7.6.dist-info/RECORD +109 -0
  106. {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.dist-info}/WHEEL +1 -1
  107. boris_behav_obs-9.7.6.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 -36
  112. boris/core.ui +0 -1556
  113. boris/edit_event.ui +0 -233
  114. boris/icons/logo_eye.ico +0 -0
  115. boris/map_creator.py +0 -850
  116. boris/observation.ui +0 -814
  117. boris/param_panel.ui +0 -379
  118. boris/preferences.ui +0 -537
  119. boris/project.ui +0 -1069
  120. boris/project_server.py +0 -236
  121. boris/vlc.py +0 -10343
  122. boris/vlc_local.py +0 -90
  123. boris_behav_obs-8.12.dist-info/LICENSE.TXT +0 -674
  124. boris_behav_obs-8.12.dist-info/METADATA +0 -128
  125. boris_behav_obs-8.12.dist-info/RECORD +0 -108
  126. boris_behav_obs-8.12.dist-info/entry_points.txt +0 -3
  127. {boris → boris_behav_obs-9.7.6.dist-info/licenses}/LICENSE.TXT +0 -0
  128. {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.dist-info}/top_level.txt +0 -0
boris/ipc_mpv.py ADDED
@@ -0,0 +1,325 @@
1
+ """
2
+ BORIS
3
+ Behavioral Observation Research Interactive Software
4
+ Copyright 2012-2025 Olivier Friard
5
+
6
+ This file is part of BORIS.
7
+
8
+ BORIS is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 3 of the License, or
11
+ any later version.
12
+
13
+ BORIS is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program; if not see <http://www.gnu.org/licenses/>.
20
+
21
+ """
22
+
23
+ import socket
24
+ import json
25
+ import subprocess
26
+
27
+ import logging
28
+ import config as cfg
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ class IPC_MPV:
34
+ """
35
+ class for managing mpv through Inter Process Communication (IPC)
36
+ """
37
+
38
+ media_durations: list = []
39
+ cumul_media_durations: list = []
40
+ fps: list = []
41
+ _pause: bool = False
42
+
43
+ def __init__(self, socket_path: str = cfg.MPV_SOCKET, parent=None):
44
+ # print(f"{parent=}")
45
+ self.socket_path = socket_path
46
+ self.process = None
47
+ # self.sock = None
48
+ self.init_mpv()
49
+ # self.init_socket()
50
+
51
+ def init_mpv(self):
52
+ """
53
+ Start mpv process and embed it in the PySide6 application.
54
+ """
55
+ logger.info("Start mpv ipc process")
56
+ # print(f"{self.winId()=}")
57
+ self.process = subprocess.Popen(
58
+ [
59
+ "mpv",
60
+ "--ontop",
61
+ "--no-border",
62
+ "--osc=no", # no on screen commands
63
+ "--input-ipc-server=" + self.socket_path,
64
+ # "--wid=" + str(int(self.winId())), # Embed in the widget
65
+ "--idle", # Keeps mpv running with no video
66
+ "--input-default-bindings=no",
67
+ "--input-vo-keyboard=no",
68
+ ],
69
+ stdout=subprocess.PIPE,
70
+ stderr=subprocess.PIPE,
71
+ )
72
+
73
+ def send_command(self, command):
74
+ """
75
+ Send a JSON command to the mpv IPC server.
76
+ """
77
+ # print(f"send command: {command}")
78
+ try:
79
+ # Create a Unix socket
80
+ with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
81
+ # Connect to the MPV IPC server
82
+ client.connect(self.socket_path)
83
+ # Send the JSON command
84
+ # print(f"{json.dumps(command).encode('utf-8')=}")
85
+ client.sendall(json.dumps(command).encode("utf-8") + b"\n")
86
+ # Receive the response
87
+ response = client.recv(2000)
88
+
89
+ # print(f"{response=}")
90
+ # Parse the response as JSON
91
+ response_data = json.loads(response.decode("utf-8"))
92
+ if response_data["error"] != "success":
93
+ logging.warning(f"send command: {command} response data: {response_data}")
94
+ # Return the 'data' field which contains the playback position
95
+ return response_data.get("data")
96
+ except FileNotFoundError:
97
+ logger.critical("Error: Socket file not found.")
98
+ except Exception as e:
99
+ logger.critical(f"An error occurred: {e}")
100
+ return None
101
+
102
+ @property
103
+ def time_pos(self):
104
+ time_pos = self.send_command({"command": ["get_property", "time-pos"]})
105
+ return time_pos
106
+
107
+ @property
108
+ def duration(self):
109
+ duration_ = self.send_command({"command": ["get_property", "duration"]})
110
+ return duration_
111
+
112
+ @property
113
+ def video_zoom(self):
114
+ return self.send_command({"command": ["get_property", "video-zoom"]})
115
+
116
+ @video_zoom.setter
117
+ def video_zoom(self, value):
118
+ self.send_command({"command": ["set_property", "video-zoom", value]})
119
+ return
120
+
121
+ @property
122
+ def pause(self):
123
+ return self.send_command({"command": ["get_property", "pause"]})
124
+
125
+ @pause.setter
126
+ def pause(self, value):
127
+ return self.send_command({"command": ["set_property", "pause", value]})
128
+
129
+ @property
130
+ def estimated_frame_number(self):
131
+ return self.send_command({"command": ["get_property", "estimated-frame-number"]})
132
+
133
+ def stop(self):
134
+ self.send_command({"command": ["stop"]})
135
+ return
136
+
137
+ @property
138
+ def playlist(self):
139
+ return self.send_command({"command": ["get_property", "playlist"]})
140
+
141
+ def playlist_next(self):
142
+ self.send_command({"command": ["playlist-next"]})
143
+ return
144
+
145
+ def playlist_prev(self):
146
+ self.send_command({"command": ["playlist-prev"]})
147
+ return
148
+
149
+ @property
150
+ def playlist_pos(self):
151
+ return self.send_command({"command": ["get_property", "playlist-pos"]})
152
+
153
+ @playlist_pos.setter
154
+ def playlist_pos(self, value):
155
+ return self.send_command({"command": ["set_property", "playlist-pos", value]})
156
+
157
+ @property
158
+ def playlist_count(self):
159
+ return self.send_command({"command": ["get_property", "playlist-count"]})
160
+
161
+ def playlist_append(self, media):
162
+ return self.send_command({"command": ["loadfile", media, "append"]})
163
+
164
+ def wait_until_playing(self):
165
+ return
166
+
167
+ def seek(self, value, mode: str):
168
+ self.send_command({"command": ["seek", value, mode]})
169
+ return
170
+
171
+ @property
172
+ def playback_time(self):
173
+ playback_time_ = self.send_command({"command": ["get_property", "playback-time"]})
174
+ return playback_time_
175
+
176
+ def frame_step(self):
177
+ self.send_command({"command": ["frame-step"]})
178
+ return
179
+
180
+ def frame_back_step(self):
181
+ self.send_command({"command": ["frame-back-step"]})
182
+ return
183
+
184
+ def screenshot_to_file(self, value):
185
+ self.send_command({"command": ["screenshot-to-file", value, "video"]})
186
+ return
187
+
188
+ @property
189
+ def speed(self):
190
+ return self.send_command({"command": ["get_property", "speed"]})
191
+
192
+ @speed.setter
193
+ def speed(self, value):
194
+ self.send_command({"command": ["set_property", "speed", value]})
195
+ return
196
+
197
+ @property
198
+ def video_rotate(self):
199
+ return self.send_command({"command": ["get_property", "video-rotate"]})
200
+
201
+ @video_rotate.setter
202
+ def video_rotate(self, value):
203
+ self.send_command({"command": ["set_property", "video-rotate", value]})
204
+ return
205
+
206
+ @property
207
+ def sub_visibility(self):
208
+ return self.send_command({"command": ["get_property", "sub-visibility"]})
209
+
210
+ @sub_visibility.setter
211
+ def sub_visibility(self, value):
212
+ self.send_command({"command": ["set_property", "sub-visibility", value]})
213
+ return
214
+
215
+ @property
216
+ def brightness(self):
217
+ return self.send_command({"command": ["get_property", "brightness"]})
218
+
219
+ @brightness.setter
220
+ def brightness(self, value):
221
+ self.send_command({"command": ["set_property", "brightness", value]})
222
+ return
223
+
224
+ @property
225
+ def contrast(self):
226
+ return self.send_command({"command": ["get_property", "contrast"]})
227
+
228
+ @contrast.setter
229
+ def contrast(self, value):
230
+ self.send_command({"command": ["set_property", "contrast", value]})
231
+ return
232
+
233
+ @property
234
+ def saturation(self):
235
+ return self.send_command({"command": ["get_property", "saturation"]})
236
+
237
+ @saturation.setter
238
+ def saturation(self, value):
239
+ self.send_command({"command": ["set_property", "saturation", value]})
240
+ return
241
+
242
+ @property
243
+ def gamma(self):
244
+ return self.send_command({"command": ["get_property", "gamma"]})
245
+
246
+ @gamma.setter
247
+ def gamma(self, value):
248
+ self.send_command({"command": ["set_property", "gamma", value]})
249
+ return
250
+
251
+ @property
252
+ def hue(self):
253
+ return self.send_command({"command": ["get_property", "hue"]})
254
+
255
+ @hue.setter
256
+ def hue(self, value):
257
+ self.send_command({"command": ["set_property", "hue", value]})
258
+ return
259
+
260
+ @property
261
+ def container_fps(self):
262
+ return self.send_command({"command": ["get_property", "container-fps"]})
263
+
264
+ @property
265
+ def width(self):
266
+ return self.send_command({"command": ["get_property", "width"]})
267
+
268
+ @property
269
+ def height(self):
270
+ return self.send_command({"command": ["get_property", "height"]})
271
+
272
+ @property
273
+ def video_format(self):
274
+ return self.send_command({"command": ["get_property", "video-format"]})
275
+
276
+ @property
277
+ def deinterlace(self):
278
+ return self.send_command({"command": ["get_property", "deinterlace"]})
279
+
280
+ @deinterlace.setter
281
+ def deinterlace(self, value):
282
+ self.send_command({"command": ["set_property", "deinterlace", value]})
283
+ return
284
+
285
+ @property
286
+ def audio_bitrate(self):
287
+ return self.send_command({"command": ["get_property", "audio-bitrate"]})
288
+
289
+ @property
290
+ def eof_reached(self):
291
+ return self.send_command({"command": ["get_property", "eof-reached"]})
292
+
293
+ @property
294
+ def core_idle(self):
295
+ return self.send_command({"command": ["get_property", "core-idle"]})
296
+
297
+ @property
298
+ def video_pan_x(self):
299
+ return self.send_command({"command": ["get_property", "video-pan-x"]})
300
+
301
+ @video_pan_x.setter
302
+ def video_pan_x(self, value):
303
+ self.send_command({"command": ["set_property", "video-pan-x", value]})
304
+ return
305
+
306
+ @property
307
+ def video_pan_y(self):
308
+ return self.send_command({"command": ["get_property", "video-pan-y"]})
309
+
310
+ @video_pan_y.setter
311
+ def video_pan_y(self, value):
312
+ self.send_command({"command": ["set_property", "video-pan-y", value]})
313
+ return
314
+
315
+
316
+ """
317
+ @property
318
+ def xxx(self):
319
+ return self.send_command({"command": ["get_property", "xxx"]})
320
+
321
+ @xxx.setter
322
+ def xxx(self, value):
323
+ self.send_command({"command": ["set_property", "xxx", value]})
324
+ return
325
+ """
boris/irr.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
@@ -25,7 +25,7 @@ import logging
25
25
  from decimal import Decimal as dec
26
26
 
27
27
  import numpy as np
28
- from PyQt5.QtWidgets import QInputDialog, QMessageBox
28
+ from PySide6.QtWidgets import QInputDialog, QMessageBox
29
29
 
30
30
  from . import config as cfg
31
31
  from . import db_functions, dialog, project_functions, select_subj_behav
@@ -126,7 +126,7 @@ def cohen_kappa(cursor, obsid1: str, obsid2: str, interval: dec, selected_subjec
126
126
  first_event = cursor.execute(
127
127
  (
128
128
  "SELECT min(start) FROM aggregated_events "
129
- f"WHERE observation in (?, ?) AND subject in ({','.join('?'*len(selected_subjects))}) "
129
+ f"WHERE observation in (?, ?) AND subject in ({','.join('?' * len(selected_subjects))}) "
130
130
  ),
131
131
  (obsid1, obsid2) + tuple(selected_subjects),
132
132
  ).fetchone()[0]
@@ -134,27 +134,18 @@ def cohen_kappa(cursor, obsid1: str, obsid2: str, interval: dec, selected_subjec
134
134
  logging.debug(f"first_event: {first_event}")
135
135
 
136
136
  last_event = cursor.execute(
137
- (
138
- "SELECT max(stop) FROM aggregated_events "
139
- f"WHERE observation in (?, ?) AND subject in ({','.join('?'*len(selected_subjects))}) "
140
- ),
137
+ (f"SELECT max(stop) FROM aggregated_events WHERE observation in (?, ?) AND subject in ({','.join('?' * len(selected_subjects))}) "),
141
138
  (obsid1, obsid2) + tuple(selected_subjects),
142
139
  ).fetchone()[0]
143
140
 
144
141
  logging.debug(f"last_event: {last_event}")
145
142
 
146
143
  nb_events1 = cursor.execute(
147
- (
148
- "SELECT COUNT(*) FROM aggregated_events "
149
- f"WHERE observation = ? AND subject in ({','.join('?'*len(selected_subjects))}) "
150
- ),
144
+ (f"SELECT COUNT(*) FROM aggregated_events WHERE observation = ? AND subject in ({','.join('?' * len(selected_subjects))}) "),
151
145
  (obsid1,) + tuple(selected_subjects),
152
146
  ).fetchone()[0]
153
147
  nb_events2 = cursor.execute(
154
- (
155
- "SELECT COUNT(*) FROM aggregated_events "
156
- f"WHERE observation = ? AND subject in ({','.join('?'*len(selected_subjects))}) "
157
- ),
148
+ (f"SELECT COUNT(*) FROM aggregated_events WHERE observation = ? AND subject in ({','.join('?' * len(selected_subjects))}) "),
158
149
  (obsid2,) + tuple(selected_subjects),
159
150
  ).fetchone()[0]
160
151
 
@@ -162,10 +153,8 @@ def cohen_kappa(cursor, obsid1: str, obsid2: str, interval: dec, selected_subjec
162
153
 
163
154
  currentTime = dec(str(first_event))
164
155
  while currentTime <= last_event:
165
-
166
156
  for obsid in [obsid1, obsid2]:
167
157
  for subject in selected_subjects:
168
-
169
158
  s = subj_behav_modif(cursor, obsid, subject, currentTime, interval, include_modifiers)
170
159
 
171
160
  if s not in total_states:
@@ -185,11 +174,9 @@ def cohen_kappa(cursor, obsid1: str, obsid2: str, interval: dec, selected_subjec
185
174
  seq2 = {}
186
175
  currentTime = dec(str(first_event))
187
176
  while currentTime <= last_event:
188
-
189
177
  seq1[currentTime] = []
190
178
  seq2[currentTime] = []
191
179
  for subject in selected_subjects:
192
-
193
180
  s1 = subj_behav_modif(cursor, obsid1, subject, currentTime, interval, include_modifiers)
194
181
  s2 = subj_behav_modif(cursor, obsid2, subject, currentTime, interval, include_modifiers)
195
182
 
@@ -211,11 +198,7 @@ def cohen_kappa(cursor, obsid1: str, obsid2: str, interval: dec, selected_subjec
211
198
  logging.debug(f"contingency_table:\n {contingency_table}")
212
199
 
213
200
  template = (
214
- "Observation: {obsid1}\n"
215
- "number of events: {nb_events1}\n\n"
216
- "Observation: {obsid2}\n"
217
- "number of events: {nb_events2:.0f}\n\n"
218
- "K = {K:.3f}"
201
+ "Observation: {obsid1}\nnumber of events: {nb_events1}\n\nObservation: {obsid2}\nnumber of events: {nb_events2:.0f}\n\nK = {K:.3f}"
219
202
  )
220
203
 
221
204
  # out += "Observation length: <b>{:.3f} s</b><br>".format(self.observationTotalMediaLength(obsid1))
@@ -298,8 +281,8 @@ def irr_cohen_kappa(self):
298
281
  selected_observations,
299
282
  start_coding=dec("NaN"),
300
283
  end_coding=dec("NaN"),
301
- flagShowIncludeModifiers=True,
302
- flagShowExcludeBehaviorsWoEvents=False,
284
+ show_include_modifiers=True,
285
+ show_exclude_non_coded_behaviors=False,
303
286
  n_observations=len(selected_observations),
304
287
  )
305
288
  if parameters == {}:
@@ -309,9 +292,7 @@ def irr_cohen_kappa(self):
309
292
  return
310
293
 
311
294
  # ask for time slice
312
- i, ok = QInputDialog.getDouble(
313
- self, "IRR - Cohen's Kappa (time-unit)", "Time unit (in seconds):", 1.0, 0.001, 86400, 3
314
- )
295
+ i, ok = QInputDialog.getDouble(self, "IRR - Cohen's Kappa (time-unit)", "Time unit (in seconds):", 1.0, 0.001, 86400, 3)
315
296
  if not ok:
316
297
  return
317
298
  interval = util.float2decimal(i)
@@ -354,7 +335,7 @@ def irr_cohen_kappa(self):
354
335
  out2 += "\t".join(["%8.6f" % x for x in irr_results[r, :]]) + "\n"
355
336
 
356
337
  self.results = dialog.Results_dialog()
357
- self.results.setWindowTitle(f"BORIS - IRR - Cohen's Kappa (time-unit) analysis results")
338
+ self.results.setWindowTitle("BORIS - IRR - Cohen's Kappa (time-unit) analysis results")
358
339
  self.results.ptText.setReadOnly(True)
359
340
  if len(selected_observations) == 2:
360
341
  self.results.ptText.appendPlainText(out)
@@ -363,9 +344,7 @@ def irr_cohen_kappa(self):
363
344
  self.results.show()
364
345
 
365
346
 
366
- def needleman_wunsch_identity(
367
- cursor, obsid1: str, obsid2: str, interval, selected_subjects: list, include_modifiers: bool
368
- ):
347
+ def needleman_wunsch_identity(cursor, obsid1: str, obsid2: str, interval, selected_subjects: list, include_modifiers: bool):
369
348
  """
370
349
  Needleman - Wunsch identity between 2 observations
371
350
 
@@ -484,13 +463,12 @@ def needleman_wunsch_identity(
484
463
  first_event = cursor.execute(
485
464
  (
486
465
  "SELECT min(start) FROM aggregated_events "
487
- f"WHERE observation in (?, ?) AND subject in ({','.join('?'*len(selected_subjects))}) "
466
+ f"WHERE observation in (?, ?) AND subject in ({','.join('?' * len(selected_subjects))}) "
488
467
  ),
489
468
  (obsid1, obsid2) + tuple(selected_subjects),
490
469
  ).fetchone()[0]
491
470
 
492
471
  if first_event is None:
493
-
494
472
  logging.debug(f"An observation has no recorded events: {obsid1} or {obsid2}")
495
473
 
496
474
  return -100, f"An observation has no recorded events: {obsid1} {obsid2}"
@@ -498,28 +476,19 @@ def needleman_wunsch_identity(
498
476
  logging.debug(f"first_event: {first_event}")
499
477
 
500
478
  last_event = cursor.execute(
501
- (
502
- "SELECT max(stop) FROM aggregated_events "
503
- f"WHERE observation in (?, ?) AND subject in ({','.join('?'*len(selected_subjects))}) "
504
- ),
479
+ (f"SELECT max(stop) FROM aggregated_events WHERE observation in (?, ?) AND subject in ({','.join('?' * len(selected_subjects))}) "),
505
480
  (obsid1, obsid2) + tuple(selected_subjects),
506
481
  ).fetchone()[0]
507
482
 
508
483
  logging.debug(f"last_event: {last_event}")
509
484
 
510
485
  nb_events1 = cursor.execute(
511
- (
512
- "SELECT COUNT(*) FROM aggregated_events "
513
- f"WHERE observation = ? AND subject in ({','.join('?'*len(selected_subjects))}) "
514
- ),
486
+ (f"SELECT COUNT(*) FROM aggregated_events WHERE observation = ? AND subject in ({','.join('?' * len(selected_subjects))}) "),
515
487
  (obsid1,) + tuple(selected_subjects),
516
488
  ).fetchone()[0]
517
489
 
518
490
  nb_events2 = cursor.execute(
519
- (
520
- "SELECT COUNT(*) FROM aggregated_events "
521
- f"WHERE observation = ? AND subject in ({','.join('?'*len(selected_subjects))}) "
522
- ),
491
+ (f"SELECT COUNT(*) FROM aggregated_events WHERE observation = ? AND subject in ({','.join('?' * len(selected_subjects))}) "),
523
492
  (obsid2,) + tuple(selected_subjects),
524
493
  ).fetchone()[0]
525
494
 
@@ -528,11 +497,9 @@ def needleman_wunsch_identity(
528
497
 
529
498
  currentTime = dec(str(first_event))
530
499
  while currentTime <= last_event:
531
-
532
500
  seq1[currentTime], seq2[currentTime] = [], []
533
501
 
534
502
  for subject in selected_subjects:
535
-
536
503
  s1 = subj_behav_modif(cursor, obsid1, subject, currentTime, interval, include_modifiers)
537
504
  s2 = subj_behav_modif(cursor, obsid2, subject, currentTime, interval, include_modifiers)
538
505
 
@@ -574,9 +541,7 @@ def needleman_wunch(self):
574
541
  if not selected_observations:
575
542
  return
576
543
  if len(selected_observations) < 2:
577
- QMessageBox.information(
578
- self, cfg.programName, "You have to select at least 2 observations for Needleman-Wunsch similarity"
579
- )
544
+ QMessageBox.information(self, cfg.programName, "You have to select at least 2 observations for Needleman-Wunsch similarity")
580
545
  return
581
546
 
582
547
  # check if coded behaviors are defined in ethogram
@@ -606,8 +571,8 @@ def needleman_wunch(self):
606
571
  selected_observations,
607
572
  start_coding=dec("NaN"),
608
573
  end_coding=dec("NaN"),
609
- flagShowIncludeModifiers=True,
610
- flagShowExcludeBehaviorsWoEvents=False,
574
+ show_include_modifiers=True,
575
+ show_exclude_non_coded_behaviors=False,
611
576
  n_observations=len(selected_observations),
612
577
  )
613
578
 
@@ -631,9 +596,7 @@ def needleman_wunch(self):
631
596
 
632
597
  cursor = db_connector.cursor()
633
598
  out = (
634
- "Needleman-Wunsch similarity\n\n"
635
- f"Time unit: {interval:.3f} s\n"
636
- f"Selected subjects: {', '.join(parameters[cfg.SELECTED_SUBJECTS])}\n\n"
599
+ f"Needleman-Wunsch similarity\n\nTime unit: {interval:.3f} s\nSelected subjects: {', '.join(parameters[cfg.SELECTED_SUBJECTS])}\n\n"
637
600
  )
638
601
  mem_done = []
639
602
  nws_results = np.ones((len(selected_observations), len(selected_observations)))