boris-behav-obs 9.7.13__py3-none-any.whl → 9.8__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 +4 -3
- boris/add_modifier.py +1 -1
- boris/advanced_event_filtering.py +1 -1
- boris/analysis_plugins/export_to_feral.py +336 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +2 -2
- boris/behav_coding_map_creator.py +1 -1
- boris/behavior_binary_table.py +1 -1
- boris/behaviors_coding_map.py +1 -1
- boris/boris_cli.py +1 -1
- boris/cmd_arguments.py +1 -1
- boris/coding_pad.py +1 -1
- boris/config.py +8 -3
- boris/config_file.py +18 -19
- boris/connections.py +12 -13
- boris/converters.py +1 -1
- boris/converters_ui.py +2 -3
- boris/cooccurence.py +1 -1
- boris/core.py +167 -164
- boris/core_qrc.py +1830 -1967
- boris/core_ui.py +1 -1
- boris/db_functions.py +5 -14
- boris/dialog.py +1 -1
- boris/edit_event.py +1 -1
- boris/event_operations.py +1 -1
- boris/events_cursor.py +1 -1
- boris/events_snapshots.py +84 -60
- boris/exclusion_matrix.py +1 -1
- boris/export_events.py +49 -43
- boris/export_observation.py +1 -1
- boris/external_processes.py +1 -1
- boris/geometric_measurement.py +1 -1
- boris/gui_utilities.py +1 -1
- boris/image_overlay.py +1 -1
- boris/import_observations.py +1 -1
- boris/ipc_mpv.py +1 -1
- boris/irr.py +1 -1
- boris/latency.py +1 -1
- boris/measurement_widget.py +1 -1
- boris/media_file.py +1 -1
- boris/menu_options.py +14 -12
- boris/modifier_coding_map_creator.py +1 -1
- boris/modifiers_coding_map.py +1 -1
- boris/observation.py +13 -14
- boris/observation_operations.py +1 -1
- boris/observations_list.py +1 -1
- boris/otx_parser.py +1 -1
- boris/param_panel.py +1 -1
- boris/player_dock_widget.py +1 -1
- boris/plot_data_module.py +1 -1
- boris/plot_events.py +1 -1
- boris/plot_events_rt.py +1 -1
- boris/plot_spectrogram_rt.py +42 -73
- boris/plot_waveform_rt.py +1 -1
- boris/plugins.py +1 -1
- boris/preferences.py +35 -4
- boris/preferences_ui.py +48 -18
- boris/project.py +1 -1
- boris/project_functions.py +19 -22
- boris/project_import_export.py +1 -1
- boris/select_modifiers.py +1 -1
- boris/select_observations.py +22 -23
- boris/select_subj_behav.py +4 -4
- boris/state_events.py +1 -1
- boris/subjects_pad.py +1 -1
- boris/synthetic_time_budget.py +1 -1
- boris/time_budget_functions.py +1 -1
- boris/time_budget_widget.py +1 -1
- boris/transitions.py +1 -1
- boris/utilities.py +1 -1
- boris/version.py +3 -3
- boris/video_equalizer.py +1 -1
- boris/video_operations.py +1 -1
- boris/view_df.py +28 -4
- boris/write_event.py +1 -1
- {boris_behav_obs-9.7.13.dist-info → boris_behav_obs-9.8.dist-info}/METADATA +2 -2
- boris_behav_obs-9.8.dist-info/RECORD +110 -0
- {boris_behav_obs-9.7.13.dist-info → boris_behav_obs-9.8.dist-info}/WHEEL +1 -1
- boris/analysis_plugins/_export_to_feral.py +0 -225
- boris_behav_obs-9.7.13.dist-info/RECORD +0 -110
- {boris_behav_obs-9.7.13.dist-info → boris_behav_obs-9.8.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-9.7.13.dist-info → boris_behav_obs-9.8.dist-info}/licenses/LICENSE.TXT +0 -0
- {boris_behav_obs-9.7.13.dist-info → boris_behav_obs-9.8.dist-info}/top_level.txt +0 -0
boris/core_ui.py
CHANGED
|
@@ -912,7 +912,7 @@ class Ui_MainWindow(object):
|
|
|
912
912
|
self.actionEdit_selected_events.setText(QCoreApplication.translate("MainWindow", u"Edit selected event(s)", None))
|
|
913
913
|
self.actionShow_spectrogram.setText(QCoreApplication.translate("MainWindow", u"Show the sound spectrogram", None))
|
|
914
914
|
self.actionExport_events_as_Praat_TextGrid.setText(QCoreApplication.translate("MainWindow", u"as Praat TextGrid", None))
|
|
915
|
-
self.actionExtract_events_from_media_files.setText(QCoreApplication.translate("MainWindow", u"Extract
|
|
915
|
+
self.actionExtract_events_from_media_files.setText(QCoreApplication.translate("MainWindow", u"Extract clips from media files", None))
|
|
916
916
|
self.action_geometric_measurements.setText(QCoreApplication.translate("MainWindow", u"Geometric measurement", None))
|
|
917
917
|
self.actionFrame_forward.setText(QCoreApplication.translate("MainWindow", u"Frame forward", None))
|
|
918
918
|
self.actionFrame_backward.setText(QCoreApplication.translate("MainWindow", u"frame backward", None))
|
boris/db_functions.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2026 Olivier Friard
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
This program is free software; you can redistribute it and/or modify
|
|
@@ -21,12 +21,12 @@ Copyright 2012-2025 Olivier Friard
|
|
|
21
21
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
import sqlite3
|
|
25
24
|
import logging
|
|
25
|
+
import sqlite3
|
|
26
26
|
from typing import Optional, Tuple
|
|
27
|
+
|
|
27
28
|
from . import config as cfg
|
|
28
|
-
from . import project_functions
|
|
29
|
-
from . import event_operations
|
|
29
|
+
from . import event_operations, project_functions
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def load_events_in_db(
|
|
@@ -39,6 +39,7 @@ def load_events_in_db(
|
|
|
39
39
|
"""
|
|
40
40
|
populate a memory sqlite database with events from selected_observations,
|
|
41
41
|
selected_subjects and selected_behaviors
|
|
42
|
+
include modifiers
|
|
42
43
|
|
|
43
44
|
Args:
|
|
44
45
|
pj (dict): project dictionary
|
|
@@ -59,16 +60,6 @@ def load_events_in_db(
|
|
|
59
60
|
if cfg.STATE in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper() and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
|
|
60
61
|
]
|
|
61
62
|
|
|
62
|
-
# selected behaviors defined as point event
|
|
63
|
-
"""
|
|
64
|
-
point_behaviors_codes = [
|
|
65
|
-
pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
|
|
66
|
-
for x in pj[cfg.ETHOGRAM]
|
|
67
|
-
if cfg.POINT in pj[cfg.ETHOGRAM][x][cfg.TYPE].upper()
|
|
68
|
-
and pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE] in selected_behaviors
|
|
69
|
-
]
|
|
70
|
-
"""
|
|
71
|
-
|
|
72
63
|
db = sqlite3.connect(":memory:", isolation_level=None)
|
|
73
64
|
|
|
74
65
|
"""
|
boris/dialog.py
CHANGED
boris/edit_event.py
CHANGED
boris/event_operations.py
CHANGED
boris/events_cursor.py
CHANGED
boris/events_snapshots.py
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2026 Olivier Friard
|
|
5
5
|
|
|
6
|
+
This file is part of BORIS.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
BORIS is free software; you can redistribute it and/or modify
|
|
8
9
|
it under the terms of the GNU General Public License as published by
|
|
9
|
-
the Free Software Foundation; either version
|
|
10
|
-
|
|
10
|
+
the Free Software Foundation; either version 3 of the License, or
|
|
11
|
+
any later version.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
BORIS is distributed in the hope that it will be useful,
|
|
13
14
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
15
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
16
|
GNU General Public License for more details.
|
|
16
17
|
|
|
17
18
|
You should have received a copy of the GNU General Public License
|
|
18
|
-
along with this program; if not
|
|
19
|
-
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
20
|
-
MA 02110-1301, USA.
|
|
19
|
+
along with this program; if not see <http://www.gnu.org/licenses/>.
|
|
21
20
|
|
|
22
21
|
"""
|
|
23
22
|
|
|
@@ -34,10 +33,10 @@ from . import db_functions, dialog, project_functions, select_observations, sele
|
|
|
34
33
|
from . import utilities as util
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
def
|
|
36
|
+
def extract_media_snapshots(self):
|
|
38
37
|
"""
|
|
39
38
|
create snapshots corresponding to coded events
|
|
40
|
-
|
|
39
|
+
Observations must be from media file and media files must have video
|
|
41
40
|
"""
|
|
42
41
|
|
|
43
42
|
_, selected_observations = select_observations.select_observations2(
|
|
@@ -47,7 +46,7 @@ def events_snapshots(self):
|
|
|
47
46
|
return
|
|
48
47
|
|
|
49
48
|
# check if obs are MEDIA
|
|
50
|
-
live_images_obs_list = []
|
|
49
|
+
live_images_obs_list: list = []
|
|
51
50
|
for obs_id in selected_observations:
|
|
52
51
|
if self.pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] in [cfg.LIVE, cfg.IMAGES]:
|
|
53
52
|
live_images_obs_list.append(obs_id)
|
|
@@ -79,7 +78,7 @@ def events_snapshots(self):
|
|
|
79
78
|
selected_observations,
|
|
80
79
|
start_coding=dec("NaN"),
|
|
81
80
|
end_coding=dec("NaN"),
|
|
82
|
-
show_include_modifiers=
|
|
81
|
+
show_include_modifiers=True,
|
|
83
82
|
show_exclude_non_coded_behaviors=False,
|
|
84
83
|
n_observations=len(selected_observations),
|
|
85
84
|
)
|
|
@@ -94,7 +93,15 @@ def events_snapshots(self):
|
|
|
94
93
|
label_caption="Choose parameters",
|
|
95
94
|
elements_list=[
|
|
96
95
|
("dsb", "Time interval around the events (in seconds)", 0.0, 86400, 1, 0, 3),
|
|
97
|
-
(
|
|
96
|
+
(
|
|
97
|
+
"il",
|
|
98
|
+
"Bitmap format",
|
|
99
|
+
(
|
|
100
|
+
("JPG - small size / low quality", ""),
|
|
101
|
+
("PNG - big size / high quality", ""),
|
|
102
|
+
# ("WEBP - small size / high quality", "")
|
|
103
|
+
),
|
|
104
|
+
),
|
|
98
105
|
],
|
|
99
106
|
title="Extract frames",
|
|
100
107
|
)
|
|
@@ -105,6 +112,8 @@ def events_snapshots(self):
|
|
|
105
112
|
frame_bitmap_format = "jpg"
|
|
106
113
|
elif "PNG" in ib.elements["Bitmap format"].currentText():
|
|
107
114
|
frame_bitmap_format = "png"
|
|
115
|
+
# elif "WEBP" in ib.elements["Bitmap format"].currentText():
|
|
116
|
+
# frame_bitmap_format = "webp"
|
|
108
117
|
else:
|
|
109
118
|
return
|
|
110
119
|
|
|
@@ -113,7 +122,7 @@ def events_snapshots(self):
|
|
|
113
122
|
self,
|
|
114
123
|
"Choose a directory to extract events",
|
|
115
124
|
os.path.expanduser("~"),
|
|
116
|
-
options=QFileDialog.ShowDirsOnly,
|
|
125
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
117
126
|
)
|
|
118
127
|
if not export_dir:
|
|
119
128
|
return
|
|
@@ -137,10 +146,13 @@ def events_snapshots(self):
|
|
|
137
146
|
for subject in parameters[cfg.SELECTED_SUBJECTS]:
|
|
138
147
|
for behavior in parameters[cfg.SELECTED_BEHAVIORS]:
|
|
139
148
|
cursor.execute(
|
|
140
|
-
"SELECT occurence FROM events WHERE observation = ? AND subject = ? AND code = ?",
|
|
149
|
+
"SELECT occurence, modifiers FROM events WHERE observation = ? AND subject = ? AND code = ?",
|
|
141
150
|
(obs_id, subject, behavior),
|
|
142
151
|
)
|
|
143
|
-
|
|
152
|
+
|
|
153
|
+
rows = tuple(
|
|
154
|
+
{"occurence": util.float2decimal(r["occurence"]), "modifiers": r[cfg.MODIFIERS]} for r in cursor.fetchall()
|
|
155
|
+
)
|
|
144
156
|
|
|
145
157
|
behavior_state = project_functions.event_type(behavior, self.pj[cfg.ETHOGRAM])
|
|
146
158
|
|
|
@@ -165,11 +177,11 @@ def events_snapshots(self):
|
|
|
165
177
|
"The following media file does not have video.<br>"
|
|
166
178
|
f"{self.pj[cfg.OBSERVATIONS][obs_id][cfg.FILE][nplayer][mediaFileIdx]}"
|
|
167
179
|
),
|
|
168
|
-
|
|
180
|
+
(cfg.OK, cfg.ABORT),
|
|
169
181
|
)
|
|
170
182
|
if response == cfg.OK:
|
|
171
183
|
continue
|
|
172
|
-
if response ==
|
|
184
|
+
if response == cfg.ABORT:
|
|
173
185
|
return
|
|
174
186
|
|
|
175
187
|
# check FPS
|
|
@@ -194,11 +206,11 @@ def events_snapshots(self):
|
|
|
194
206
|
"The FPS was not found for the following media file:<br>"
|
|
195
207
|
f"{self.pj[cfg.OBSERVATIONS][obs_id][cfg.FILE][nplayer][mediaFileIdx]}"
|
|
196
208
|
),
|
|
197
|
-
|
|
209
|
+
(cfg.OK, cfg.ABORT),
|
|
198
210
|
)
|
|
199
211
|
if response == cfg.OK:
|
|
200
212
|
continue
|
|
201
|
-
if response ==
|
|
213
|
+
if response == cfg.ABORT:
|
|
202
214
|
return
|
|
203
215
|
|
|
204
216
|
global_start = dec("0.000") if row["occurence"] < time_interval else round(row["occurence"] - time_interval, 3)
|
|
@@ -238,11 +250,11 @@ def events_snapshots(self):
|
|
|
238
250
|
"At the moment it no possible to extract frames "
|
|
239
251
|
"for this type of event.<br>"
|
|
240
252
|
),
|
|
241
|
-
|
|
253
|
+
(cfg.OK, cfg.ABORT),
|
|
242
254
|
)
|
|
243
255
|
if response == cfg.OK:
|
|
244
256
|
continue
|
|
245
|
-
if response ==
|
|
257
|
+
if response == cfg.ABORT:
|
|
246
258
|
return
|
|
247
259
|
|
|
248
260
|
# globalStop = round(rows[idx + 1]["occurence"] + time_interval, 3)
|
|
@@ -279,17 +291,23 @@ def events_snapshots(self):
|
|
|
279
291
|
else:
|
|
280
292
|
continue
|
|
281
293
|
|
|
282
|
-
ffmpeg_command = (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
294
|
+
ffmpeg_command = "".join(
|
|
295
|
+
[
|
|
296
|
+
f'"{self.ffmpeg_bin}" ',
|
|
297
|
+
f'-i "{media_path}" ',
|
|
298
|
+
f"-ss {start:.3f} ",
|
|
299
|
+
f"-vframes {vframes} ",
|
|
300
|
+
f'"{export_dir}{os.sep}',
|
|
301
|
+
f"{util.safeFileName(obs_id).replace(' ', '-')}",
|
|
302
|
+
f"_PLAYER{nplayer}",
|
|
303
|
+
f"_{util.safeFileName(subject).replace(' ', '-')}",
|
|
304
|
+
f"_{util.safeFileName(behavior).replace(' ', '-')}",
|
|
305
|
+
f"_{global_start:.3f}_%08d",
|
|
306
|
+
f"_{util.safeFileName(row[cfg.MODIFIERS].replace('|', '+')).replace(' ', '-')}"
|
|
307
|
+
if parameters[cfg.INCLUDE_MODIFIERS] and row[cfg.MODIFIERS]
|
|
308
|
+
else "",
|
|
309
|
+
f'.{frame_bitmap_format}"',
|
|
310
|
+
]
|
|
293
311
|
)
|
|
294
312
|
|
|
295
313
|
logging.debug(f"ffmpeg command: {ffmpeg_command}")
|
|
@@ -300,10 +318,10 @@ def events_snapshots(self):
|
|
|
300
318
|
self.statusbar.showMessage(f"Frames extracted in {export_dir}", 0)
|
|
301
319
|
|
|
302
320
|
|
|
303
|
-
def
|
|
321
|
+
def extract_media_clips(self):
|
|
304
322
|
"""
|
|
305
|
-
extract sub-sequences from media files corresponding to coded events
|
|
306
|
-
|
|
323
|
+
extract with FFmpeg sub-sequences from media files corresponding to coded events
|
|
324
|
+
In case of point event, from -n to +n seconds are extracted (n is asked to user)
|
|
307
325
|
"""
|
|
308
326
|
|
|
309
327
|
_, selected_observations = select_observations.select_observations2(
|
|
@@ -312,14 +330,14 @@ def extract_events(self):
|
|
|
312
330
|
if not selected_observations:
|
|
313
331
|
return
|
|
314
332
|
|
|
315
|
-
# check if obs are
|
|
316
|
-
live_images_obs_list = []
|
|
333
|
+
# check if obs are from media files
|
|
334
|
+
live_images_obs_list: list = []
|
|
317
335
|
for obs_id in selected_observations:
|
|
318
|
-
if self.pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] in
|
|
336
|
+
if self.pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] in (cfg.LIVE, cfg.IMAGES):
|
|
319
337
|
live_images_obs_list.append(obs_id)
|
|
320
338
|
|
|
321
339
|
if live_images_obs_list:
|
|
322
|
-
out = "The following observations are live observations or observation from pictures and will be removed
|
|
340
|
+
out = "The following observations are live observations or observation from pictures and will be removed<br><br>"
|
|
323
341
|
out += "<br>".join(live_images_obs_list)
|
|
324
342
|
results = dialog.Results_dialog()
|
|
325
343
|
results.setWindowTitle(cfg.programName)
|
|
@@ -345,7 +363,7 @@ def extract_events(self):
|
|
|
345
363
|
selected_observations,
|
|
346
364
|
start_coding=dec("NaN"),
|
|
347
365
|
end_coding=dec("NaN"),
|
|
348
|
-
show_include_modifiers=
|
|
366
|
+
show_include_modifiers=True,
|
|
349
367
|
show_exclude_non_coded_behaviors=False,
|
|
350
368
|
)
|
|
351
369
|
if parameters == {}:
|
|
@@ -377,7 +395,7 @@ def extract_events(self):
|
|
|
377
395
|
self,
|
|
378
396
|
"Choose a directory to extract events",
|
|
379
397
|
os.path.expanduser("~"),
|
|
380
|
-
options=QFileDialog.ShowDirsOnly,
|
|
398
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
381
399
|
)
|
|
382
400
|
if not export_dir:
|
|
383
401
|
return
|
|
@@ -393,7 +411,7 @@ def extract_events(self):
|
|
|
393
411
|
self.statusBar().showMessage("Extracting sequences from media files")
|
|
394
412
|
QApplication.processEvents()
|
|
395
413
|
|
|
396
|
-
ffmpeg_extract_command: str = '"{ffmpeg_bin}"
|
|
414
|
+
ffmpeg_extract_command: str = '"{ffmpeg_bin}"-i "{input_}" -ss {start} -y -t {duration} {codecs} '
|
|
397
415
|
mem_command: str = ""
|
|
398
416
|
for obs_id in selected_observations:
|
|
399
417
|
for nplayer in self.pj[cfg.OBSERVATIONS][obs_id][cfg.FILE]:
|
|
@@ -407,11 +425,12 @@ def extract_events(self):
|
|
|
407
425
|
for subject in parameters[cfg.SELECTED_SUBJECTS]:
|
|
408
426
|
for behavior in parameters[cfg.SELECTED_BEHAVIORS]:
|
|
409
427
|
cursor.execute(
|
|
410
|
-
"SELECT occurence FROM events WHERE observation = ? AND subject = ? AND code = ?",
|
|
428
|
+
"SELECT occurence, modifiers FROM events WHERE observation = ? AND subject = ? AND code = ?",
|
|
411
429
|
(obs_id, subject, behavior),
|
|
412
430
|
)
|
|
413
|
-
rows =
|
|
414
|
-
|
|
431
|
+
rows = tuple(
|
|
432
|
+
{"occurence": util.float2decimal(r["occurence"]), "modifiers": r[cfg.MODIFIERS]} for r in cursor.fetchall()
|
|
433
|
+
)
|
|
415
434
|
behavior_state = project_functions.event_type(behavior, self.pj[cfg.ETHOGRAM])
|
|
416
435
|
if behavior_state in cfg.STATE_EVENT_TYPES and len(rows) % 2: # unpaired events
|
|
417
436
|
continue
|
|
@@ -433,7 +452,7 @@ def extract_events(self):
|
|
|
433
452
|
dialog.MessageDialog(
|
|
434
453
|
cfg.programName,
|
|
435
454
|
f"The media file {self.pj[cfg.OBSERVATIONS][obs_id][cfg.FILE][nplayer][mediaFileIdx]} does not have a video stream",
|
|
436
|
-
|
|
455
|
+
("Continue", "Abort"),
|
|
437
456
|
)
|
|
438
457
|
== "Abort"
|
|
439
458
|
):
|
|
@@ -461,9 +480,9 @@ def extract_events(self):
|
|
|
461
480
|
dialog.MessageDialog(
|
|
462
481
|
cfg.programName,
|
|
463
482
|
f"The media file {self.pj[cfg.OBSERVATIONS][obs_id][cfg.FILE][nplayer][mediaFileIdx]} does not have an audio stream",
|
|
464
|
-
|
|
483
|
+
("Continue", cfg.ABORT),
|
|
465
484
|
)
|
|
466
|
-
==
|
|
485
|
+
== cfg.ABORT
|
|
467
486
|
):
|
|
468
487
|
return
|
|
469
488
|
else:
|
|
@@ -509,11 +528,11 @@ def extract_events(self):
|
|
|
509
528
|
"The event extends on 2 successive video. "
|
|
510
529
|
" At the moment it is not possible to extract this type of event.<br>"
|
|
511
530
|
),
|
|
512
|
-
|
|
531
|
+
(cfg.OK, cfg.ABORT),
|
|
513
532
|
)
|
|
514
533
|
if response == cfg.OK:
|
|
515
534
|
continue
|
|
516
|
-
if response ==
|
|
535
|
+
if response == cfg.ABORT:
|
|
517
536
|
return
|
|
518
537
|
|
|
519
538
|
globalStart = dec("0.000") if row["occurence"] < timeOffset else round(row["occurence"] - timeOffset, 3)
|
|
@@ -550,22 +569,27 @@ def extract_events(self):
|
|
|
550
569
|
continue
|
|
551
570
|
|
|
552
571
|
new_file_name = pl.Path(export_dir) / pl.Path(
|
|
553
|
-
(
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
572
|
+
"".join(
|
|
573
|
+
[
|
|
574
|
+
f"{util.safeFileName(obs_id).replace(' ', '-')}_",
|
|
575
|
+
f"PLAYER{nplayer}_",
|
|
576
|
+
f"{util.safeFileName(subject).replace(' ', '-')}_",
|
|
577
|
+
f"{util.safeFileName(behavior)}_",
|
|
578
|
+
f"{globalStart}-{globalStop}",
|
|
579
|
+
f"_{util.safeFileName(row[cfg.MODIFIERS].replace('|', '+')).replace(' ', '-')}"
|
|
580
|
+
if parameters[cfg.INCLUDE_MODIFIERS] and row[cfg.MODIFIERS]
|
|
581
|
+
else "",
|
|
582
|
+
f"{new_extension}",
|
|
583
|
+
]
|
|
560
584
|
)
|
|
561
|
-
)
|
|
585
|
+
)
|
|
562
586
|
|
|
563
587
|
if new_file_name.is_file():
|
|
564
588
|
if mem_command not in (cfg.OVERWRITE_ALL, cfg.SKIP_ALL):
|
|
565
589
|
mem_command = dialog.MessageDialog(
|
|
566
590
|
cfg.programName,
|
|
567
591
|
f"The file <b>{new_file_name}</b> already exists.",
|
|
568
|
-
|
|
592
|
+
(cfg.OVERWRITE, cfg.OVERWRITE_ALL, cfg.SKIP, cfg.SKIP_ALL, cfg.CANCEL),
|
|
569
593
|
)
|
|
570
594
|
if mem_command == cfg.CANCEL:
|
|
571
595
|
return
|