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/config.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
  This file is part of BORIS.
7
7
 
@@ -22,8 +22,23 @@ This file is part of BORIS.
22
22
 
23
23
  programName: str = "BORIS"
24
24
 
25
+ # socket for MPV IPC mode
26
+ MPV_SOCKET = "/tmp/mpvsocket"
27
+
28
+
29
+ ETHOGRAM_REPOSITORY_URL = "https://www.boris.unito.it/static/ethograms"
30
+
25
31
  project_format_version: str = "7.0"
26
32
 
33
+ SECONDS_PER_DAY: int = 86_400
34
+
35
+ # cutoff value for displaying HH:MM:SS.zzz or YYYY-mm-DD HH:MM:SS:ZZZ
36
+ HOUR_CUTOFF: int = 7 * 24
37
+ DATE_CUTOFF: int = HOUR_CUTOFF * 60 * 60 # 1 week
38
+
39
+ # cutoff for displaying time in HH:MM:SS.zzz format
40
+ SMART_TIME_CUTOFF_DEFAULT: int = 300
41
+
27
42
  # minimal project version for handling observations from images
28
43
  IMAGES_OBS_PROJECT_MIN_VERSION: tuple = (8, 6)
29
44
 
@@ -37,9 +52,14 @@ MAX_UNDO_QUEUE: int = 25
37
52
 
38
53
  NA: str = "NA"
39
54
 
40
- CTRL_KEY = "Ctrl"
55
+ REALTIME_PLOT_CURSOR_COLOR: str = "red"
56
+
57
+ DARKER_DIFFERENCE = 5
41
58
 
42
- SPECTRO_TIMER = 500
59
+ CTRL_KEY: str = "Ctrl"
60
+ ALT_KEY: str = "Alt"
61
+
62
+ SPECTRO_TIMER: int = 500
43
63
 
44
64
  function_keys = {
45
65
  16777264: "F1",
@@ -68,10 +88,12 @@ EVENTS = "events"
68
88
  TIME_OFFSET = "time offset"
69
89
 
70
90
  CODING_MAP = "coding_map"
91
+ CODING_MAP_sp = "coding map" # space between words (no underscore)
71
92
  BEHAVIORS_CODING_MAP = "behaviors_coding_map"
72
93
  SUBJECTS = "subjects_conf"
73
94
  ETHOGRAM = "behaviors_conf"
74
95
  BEHAVIORAL_CATEGORIES = "behavioral_categories"
96
+ BEHAVIORAL_CATEGORIES_CONF = "behavioral_categories_config"
75
97
  CONVERTERS = "converters"
76
98
 
77
99
  OFFSET = "offset"
@@ -110,20 +132,34 @@ POINT_EVENT_PLOT_COLOR = "black"
110
132
 
111
133
  CHAR_FORBIDDEN_IN_MODIFIERS = "(|),`~"
112
134
 
135
+ FAST_FORWARD_DEFAULT_VALUE: float = 10.0
136
+
113
137
  ADAPT_FAST_JUMP = "adapt_fast_jump"
114
138
  ADAPT_FAST_JUMP_DEFAULT = False
115
139
 
140
+ TIME = "time"
141
+ BEHAVIOR_CODE = "code"
142
+ SUBJECT = "subject"
143
+ MODIFIER = "modifier"
144
+ COMMENT = "comment"
145
+ BEHAVIOR_KEY = "key"
146
+ SUBJECT_KEY = "key"
147
+ BEHAVIOR_CATEGORY = "category"
148
+
116
149
 
117
- subjectsFields = ["key", SUBJECT_NAME, DESCRIPTION]
150
+ subjectsFields = [SUBJECT_KEY, SUBJECT_NAME, DESCRIPTION]
118
151
 
119
152
  UNPAIRED = "UNPAIRED"
120
153
  DISPLAY_SUBTITLES = "display_subtitles"
154
+ CHECK_PROJECT_INTEGRITY = "check_project_integrity"
121
155
 
122
156
 
123
157
  YES = "Yes"
124
158
  NO = "No"
125
159
  CANCEL = "Cancel"
160
+ IGNORE = "Ignore"
126
161
  APPEND = "Append"
162
+ CLOSE = "Close"
127
163
  REPLACE = "Replace"
128
164
  REMOVE = "Remove"
129
165
  SAVE = "Save"
@@ -138,6 +174,7 @@ NO_FOCAL_SUBJECT = "No focal subject"
138
174
 
139
175
  TYPE = "type"
140
176
  FILE = "file"
177
+ COLOR = "color"
141
178
  DIRECTORIES_LIST = "directories_list"
142
179
 
143
180
  SAVE_DATASET = 32
@@ -167,13 +204,6 @@ DATA_PLOT_FIELDS = {
167
204
  }
168
205
  DATA_PLOT_STYLES = ["b-", "r-", "g-", "bo", "ro", "go"]
169
206
 
170
- TIME = "time"
171
- BEHAVIOR_CODE = "code"
172
- SUBJECT = "subject"
173
- MODIFIER = "modifier"
174
- COMMENT = "comment"
175
- BEHAVIOR_KEY = "key"
176
- BEHAVIOR_CATEGORY = "category"
177
207
 
178
208
  FILE_PATH = "file_path"
179
209
 
@@ -182,36 +212,29 @@ IMAGE_PATH = "image path"
182
212
  FRAME_INDEX = "frame index"
183
213
 
184
214
  ZOOM_LEVEL = "zoom level"
215
+ PAN_X = "pan-x"
216
+ PAN_Y = "pan-y"
185
217
  ROTATION_ANGLE = "rotation angle"
186
218
  DISPLAY_MEDIA_SUBTITLES = "display subtitles"
187
219
  OVERLAY = "video overlay"
188
220
 
189
221
 
190
222
  USE_EXIF_DATE = "use_exif_date"
223
+ SUBSTRACT_FIRST_EXIF_DATE = "substract_first_exif_date"
191
224
  TIME_LAPSE = "time_lapse_delay"
192
225
 
193
226
 
194
227
  # fields for event configuration
195
- """
196
- fields = {
197
- "type": 0,
198
- "key": 1,
199
- "code": 2,
200
- "description": 3,
201
- "modifiers": 4,
202
- "excluded": 5,
203
- "coding map": 6,
204
- }
205
- """
206
228
 
207
229
  ETHOGRAM_TABLE_COLUMNS: dict = {
208
230
  0: "key",
209
231
  1: "code",
210
232
  2: "type",
211
233
  3: "description",
212
- 4: "category",
213
- 5: "modifiers",
214
- 6: "excluded",
234
+ 4: "color",
235
+ 5: "category",
236
+ 6: "modifiers",
237
+ 7: "excluded",
215
238
  }
216
239
 
217
240
  # fields in ethogram table from project window
@@ -220,23 +243,12 @@ behavioursFields: dict = {
220
243
  "key": 1,
221
244
  "code": 2,
222
245
  "description": 3,
223
- "category": 4,
224
- "modifiers": 5,
225
- "excluded": 6,
226
- "coding map": 7,
246
+ "color": 4,
247
+ "category": 5,
248
+ "modifiers": 6,
249
+ "excluded": 7,
250
+ "coding map": 8,
227
251
  }
228
- """
229
- ETHOGRAM_FIELDS = [
230
- "type",
231
- "key",
232
- "code",
233
- "description",
234
- "category",
235
- "modifiers",
236
- "excluded",
237
- "coding map",
238
- ]
239
- """
240
252
  ETHOGRAM_EDITABLE_FIELDS: tuple = ("key", "code", "description")
241
253
 
242
254
  PROJECT_BEHAVIORS_KEY_FIELD_IDX = 1
@@ -246,13 +258,20 @@ MEDIA_FILE_PATH_IDX = 2
246
258
  HAS_AUDIO_IDX = 6
247
259
 
248
260
  STATE_EVENT = "State event"
261
+ STATE_EVENT_WITH_CODING_MAP = "State event with coding map"
262
+
263
+ STATE_EVENT_TYPES = [STATE_EVENT, STATE_EVENT_WITH_CODING_MAP]
264
+
249
265
  POINT_EVENT = "Point event"
266
+ POINT_EVENT_WITH_CODING_MAP = "Point event with coding map"
267
+
268
+ POINT_EVENT_TYPES = [POINT_EVENT, POINT_EVENT_WITH_CODING_MAP]
250
269
 
251
270
  BEHAVIOR_TYPES = [
252
- "Point event",
253
- "State event",
254
- "Point event with coding map",
255
- "State event with coding map",
271
+ POINT_EVENT,
272
+ STATE_EVENT,
273
+ POINT_EVENT_WITH_CODING_MAP,
274
+ STATE_EVENT_WITH_CODING_MAP,
256
275
  ]
257
276
 
258
277
  DEFAULT_BEHAVIOR_TYPE = "Point event"
@@ -264,7 +283,7 @@ MEDIA_TW_EVENTS_FIELDS_DEFAULT = ("time", FRAME_INDEX, "subject", "code", "type"
264
283
  MEDIA_TW_EVENTS_FIELDS = ("time", FRAME_INDEX, "subject", "code", "type", "modifier", "comment")
265
284
  # MEDIA_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment")
266
285
  LIVE_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment")
267
- IMAGES_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment", IMAGE_INDEX, "image path")
286
+ IMAGES_TW_EVENTS_FIELDS = ("time", "subject", "code", "type", "modifier", "comment", IMAGE_INDEX, IMAGE_PATH)
268
287
 
269
288
  TW_EVENTS_FIELDS = {
270
289
  MEDIA: MEDIA_TW_EVENTS_FIELDS,
@@ -286,7 +305,7 @@ for observation_type in TW_EVENTS_FIELDS:
286
305
  # fields for project events list
287
306
  MEDIA_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment", FRAME_INDEX)
288
307
  LIVE_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment")
289
- IMAGES_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment", "image index", "image path")
308
+ IMAGES_PJ_EVENTS_FIELDS = (TIME, "subject", "code", "modifier", "comment", IMAGE_INDEX, IMAGE_PATH)
290
309
 
291
310
  PJ_EVENTS_FIELDS = {
292
311
  MEDIA: MEDIA_PJ_EVENTS_FIELDS,
@@ -297,9 +316,6 @@ PJ_EVENTS_FIELDS = {
297
316
  VIEWER_IMAGES: IMAGES_PJ_EVENTS_FIELDS,
298
317
  }
299
318
 
300
- # fields for independent variable definition
301
- tw_indVarFields = ["label", "description", "type", "default value", "possible values"]
302
-
303
319
 
304
320
  PJ_OBS_FIELDS = {}
305
321
  for observation_type in PJ_EVENTS_FIELDS:
@@ -307,12 +323,17 @@ for observation_type in PJ_EVENTS_FIELDS:
307
323
  for idx, field in enumerate(PJ_EVENTS_FIELDS[observation_type]):
308
324
  PJ_OBS_FIELDS[observation_type][field] = idx
309
325
 
326
+
327
+ # fields for independent variable definition
328
+ tw_indVarFields = ["label", "description", "type", "default value", "possible values"]
329
+
330
+
310
331
  EVENT_TIME_FIELD_IDX = 0
311
332
  EVENT_SUBJECT_FIELD_IDX = 1
312
333
  EVENT_BEHAVIOR_FIELD_IDX = 2
313
334
  EVENT_MODIFIER_FIELD_IDX = 3
314
335
  EVENT_COMMENT_FIELD_IDX = 4
315
- EVENT_STATUS_FIELD_IDX = 5
336
+ EVENT_STATUS_FIELD_IDX = -1
316
337
  # EVENT_IMAGEIDX_FIELD_IDX = 6
317
338
  # EVENT_IMAGEPATH_FIELD_IDX = 7
318
339
 
@@ -337,6 +358,14 @@ START_FROM_CURRENT_EPOCH_TIME = "start_from_current_epoch_time"
337
358
 
338
359
  SCAN_SAMPLING_TIME = "scan_sampling_time"
339
360
 
361
+ POINT_OBJECT = "Point"
362
+ SEGMENT_OBJECT = "Segment"
363
+ ANGLE_OBJECT = "Angle"
364
+ ORIENTED_ANGLE_OBJECT = "Oriented angle"
365
+ POLYGON_OBJECT = "Polygon"
366
+ POLYLINE_OBJECT = "Polyline"
367
+
368
+
340
369
  NEW = "new"
341
370
  LIST = "list"
342
371
  EDIT = "edit"
@@ -356,6 +385,7 @@ SELECTED_BEHAVIORS = "selected behaviors"
356
385
  SELECTED_SUBJECTS = "selected subjects"
357
386
  INCLUDE_MODIFIERS = "include modifiers"
358
387
  EXCLUDE_BEHAVIORS = "exclude behaviors"
388
+ EXCLUDE_NON_CODED_MODIFIERS = "exclude_non_coded_modifiers"
359
389
  EXCLUDED_BEHAVIORS = "excluded behaviors"
360
390
  TIME_INTERVAL = "time"
361
391
  START_TIME = "start time"
@@ -373,6 +403,7 @@ TIMESTAMP_idx = 3
373
403
 
374
404
  TIME_FULL_OBS = "full obs"
375
405
  TIME_EVENTS = "limit to events"
406
+ TIME_OBS_INTERVAL = "interval of observation"
376
407
  TIME_ARBITRARY_INTERVAL = "time interval"
377
408
 
378
409
  AVAILABLE_INDEP_VAR_TYPES = [NUMERIC, TEXT, SET_OF_VALUES, TIMESTAMP]
@@ -382,16 +413,31 @@ OBSERVATIONS = "observations"
382
413
 
383
414
  CLOSE_BEHAVIORS_BETWEEN_VIDEOS = "close_behaviors_between_videos"
384
415
 
385
- MPV_HWDEC_OPTIONS = ("auto", "auto-safe", "no")
386
- MPV_HWDEC_DEFAULT_VALUE = "auto"
416
+ # MPV hardware decode
387
417
  MPV_HWDEC = "mpv_hwdec"
418
+ MPV_HWDEC_NO = "no"
419
+ MPV_HWDEC_AUTO = "auto"
420
+ MPV_HWDEC_AUTOSAFE = "auto-safe"
421
+ MPV_HWDEC_OPTIONS = (MPV_HWDEC_AUTO, MPV_HWDEC_AUTOSAFE, MPV_HWDEC_NO)
422
+ MPV_HWDEC_DEFAULT_VALUE = MPV_HWDEC_AUTO
423
+
424
+ # frame step size (disabled)
425
+ # FRAME_STEP_SIZE: str = "frame_step_size"
426
+ # FRAME_STEP_SIZE_DEFAULT_VALUE: int = 1
388
427
 
428
+ ANALYSIS_PLUGINS = "analysis_plugins"
429
+ EXCLUDED_PLUGINS = "excluded_plugins"
430
+ PERSONAL_PLUGINS_DIR = "personal_plugins_dir"
389
431
 
390
432
  PROJECT_FILE_INDENTATION = "project file indentation"
391
433
  PROJECT_FILE_INDENTATION_COMBO_OPTIONS = ("None", "Newline", "Tab", "2 spaces", "4 spaces")
392
434
  PROJECT_FILE_INDENTATION_OPTIONS = (None, 0, "\t", 2, 4)
393
435
  PROJECT_FILE_INDENTATION_DEFAULT_VALUE = None
394
436
 
437
+ TOOLBAR_ICON_SIZE = "toolbar icon size"
438
+ DEFAULT_TOOLBAR_ICON_SIZE_VALUE = 24
439
+
440
+
395
441
  VIDEO_VIEWER = 0
396
442
  PICTURE_VIEWER = 1
397
443
 
@@ -408,6 +454,7 @@ LENGTH = "length"
408
454
  FPS = "fps"
409
455
  HAS_AUDIO = "hasAudio"
410
456
  HAS_VIDEO = "hasVideo"
457
+ MEDIA_CREATION_TIME = "media_creation_time"
411
458
 
412
459
  STATE = "STATE"
413
460
  POINT = "POINT"
@@ -415,12 +462,15 @@ POINT = "POINT"
415
462
  START = "START"
416
463
  STOP = "STOP"
417
464
 
418
- PLAYER1, PLAYER2 = "1", "2"
465
+ PLAYER1 = "1"
466
+ PLAYER2 = "2"
419
467
  ALL_PLAYERS = [str(x + 1) for x in range(N_PLAYER)]
420
468
 
421
469
  VISUALIZE_SPECTROGRAM = "visualize_spectrogram"
422
470
  VISUALIZE_WAVEFORM = "visualize_waveform"
471
+ MEDIA_CREATION_DATE_AS_OFFSET = "media_creation_date_as_offset"
423
472
 
473
+ MEDIA_SCAN_SAMPLING_DURATION = "media_scan_sampling_duration"
424
474
  IMAGE_DISPLAY_DURATION = "image_display_duration"
425
475
 
426
476
  # plot type
@@ -428,6 +478,9 @@ WAVEFORM_PLOT = "waveform"
428
478
  SPECTROGRAM_PLOT = "spectrogram"
429
479
  EVENTS_PLOT = "plot_events"
430
480
 
481
+ PLAYING = "playing"
482
+ PAUSED = "paused"
483
+ STOPPED = "stopped"
431
484
 
432
485
  POINT_EVENT_ST_DURATION = 0.5
433
486
 
@@ -438,6 +491,8 @@ SLIDER_MAXIMUM = 1000
438
491
 
439
492
  FRAME_DEFAULT_CACHE_SIZE = 1
440
493
 
494
+ EXCLUDED = "excluded"
495
+
441
496
  # modifiers
442
497
  MODIFIERS = "modifiers"
443
498
  SINGLE_SELECTION = 0
@@ -481,6 +536,16 @@ NO_COLOR_CODING_PAD = "#777777"
481
536
  SPECTROGRAM_COLOR_MAPS = ["viridis", "inferno", "plasma", "magma", "gray", "YlOrRd"]
482
537
  SPECTROGRAM_DEFAULT_COLOR_MAP = "viridis"
483
538
  SPECTROGRAM_DEFAULT_TIME_INTERVAL = 10
539
+ SPECTROGRAM_WINDOW_TYPE = "SPECTROGRAM_WINDOW_TYPE"
540
+ SPECTROGRAM_DEFAULT_WINDOW_TYPE = "hanning"
541
+ SPECTROGRAM_NFFT = "SPECTROGRAM_NFFT"
542
+ SPECTROGRAM_DEFAULT_NFFT = "1024"
543
+ SPECTROGRAM_NOVERLAP = "SPECTROGRAM_NOVERLAP"
544
+ SPECTROGRAM_DEFAULT_NOVERLAP = 900
545
+ SPECTROGRAM_VMIN = "SPECTROGRAM_VMIN"
546
+ SPECTROGRAM_DEFAULT_VMIN = -100
547
+ SPECTROGRAM_VMAX = "SPECTROGRAM_VMAX"
548
+ SPECTROGRAM_DEFAULT_VMAX = -20
484
549
 
485
550
  # see matplotlib.colors.cnames.keys()
486
551
  # https://xkcd.com/color/rgb/
@@ -655,6 +720,7 @@ EMPTY_PROJECT = {
655
720
  ETHOGRAM: {},
656
721
  OBSERVATIONS: {},
657
722
  BEHAVIORAL_CATEGORIES: [],
723
+ BEHAVIORAL_CATEGORIES_CONF: {},
658
724
  INDEPENDENT_VARIABLES: {},
659
725
  CODING_MAP: {},
660
726
  BEHAVIORS_CODING_MAP: [],
@@ -670,10 +736,20 @@ INIT_PARAM = {
670
736
  MPV_HWDEC: MPV_HWDEC_DEFAULT_VALUE,
671
737
  PROJECT_FILE_INDENTATION: PROJECT_FILE_INDENTATION_DEFAULT_VALUE,
672
738
  f"{MEDIA} tw fields": MEDIA_TW_EVENTS_FIELDS_DEFAULT,
739
+ # FRAME_STEP_SIZE: FRAME_STEP_SIZE_DEFAULT_VALUE,
673
740
  }
674
741
 
675
742
  SDIS_EXT = "sds"
676
743
  TBS_EXT = "tbs"
744
+ TSV_EXT = "tsv"
745
+ CSV_EXT = "csv"
746
+ RDS_EXT = "rds"
747
+ PANDAS_DF_EXT = "pkl"
748
+ HTML_EXT = "html"
749
+ SQL_EXT = "sql"
750
+ ODS_EXT = "ods"
751
+ XLS_EXT = "xls"
752
+ XLSX_EXT = "xlsx"
677
753
 
678
754
  # Output format
679
755
  TSV = "Tab Separated Values (*.tsv)"
@@ -692,17 +768,17 @@ TBS = "Timed Behavioral Sequences (*.tbs)"
692
768
  TEXT_FILE = "Text file"
693
769
 
694
770
  FILE_NAME_SUFFIX = {
695
- TSV: "tsv",
696
- CSV: "csv",
697
- ODS: "ods",
698
- ODS_WB: "ods",
699
- XLSX: "xlsx",
700
- XLSX_WB: "xlsx",
701
- XLS: "xls",
702
- HTML: "html",
703
- PANDAS_DF: "pkl",
704
- RDS: "rds",
705
- SQL: "sql",
771
+ TSV: TSV_EXT,
772
+ CSV: CSV_EXT,
773
+ ODS: ODS_EXT,
774
+ ODS_WB: ODS_EXT,
775
+ XLSX: XLSX_EXT,
776
+ XLSX_WB: XLSX_EXT,
777
+ XLS: XLS_EXT,
778
+ HTML: HTML_EXT,
779
+ PANDAS_DF: PANDAS_DF_EXT,
780
+ RDS: RDS_EXT,
781
+ SQL: SQL_EXT,
706
782
  SDIS: SDIS_EXT,
707
783
  TBS: TBS_EXT,
708
784
  TEXT_FILE: "cli",
boris/config_file.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
  This file is part of BORIS.
7
7
 
@@ -18,21 +18,17 @@ This file is part of BORIS.
18
18
  You should have received a copy of the GNU General Public License
19
19
  along with this program; if not see <http://www.gnu.org/licenses/>.
20
20
 
21
- """
22
-
23
- """
24
21
  Read and write the BORIS config file
25
22
  """
26
23
 
27
24
  import pathlib as pl
28
25
  import logging
29
26
  import time
30
- import os
31
27
 
32
28
  from . import config as cfg
33
29
  from . import dialog
34
30
 
35
- from PyQt5.QtCore import QByteArray, QSettings
31
+ from PySide6.QtCore import QByteArray, QSettings
36
32
 
37
33
 
38
34
  def read(self):
@@ -40,19 +36,19 @@ def read(self):
40
36
  read config file
41
37
  """
42
38
 
43
- iniFilePath = pl.Path.home() / pl.Path(".boris")
39
+ ini_fil_p_pe_p_path = pl.Path.home() / pl.Path(".boris")
44
40
 
45
- logging.debug(f"read config file: {iniFilePath}")
41
+ logging.debug(f"read config file: {ini_fil_p_pe_p_path}")
46
42
 
47
- if iniFilePath.is_file():
48
- settings = QSettings(str(iniFilePath), QSettings.IniFormat)
43
+ if ini_fil_p_pe_p_path.is_file():
44
+ settings = QSettings(str(ini_fil_p_pe_p_path), QSettings.IniFormat)
49
45
 
50
46
  try:
51
47
  self.config_param = settings.value("config")
52
48
  except Exception:
53
- self.config_param = None
54
- pass
55
- if self.config_param is None:
49
+ self.config_param = {}
50
+
51
+ if self.config_param == {}:
56
52
  self.config_param = cfg.INIT_PARAM
57
53
 
58
54
  # for back compatibility
@@ -76,7 +72,7 @@ def read(self):
76
72
  if not isinstance(self.saved_state, QByteArray):
77
73
  self.saved_state = None
78
74
 
79
- logging.debug(f"saved state: {self.saved_state}")
75
+ # logging.debug(f"saved state: {self.saved_state}")
80
76
 
81
77
  self.timeFormat = cfg.HHMMSS
82
78
  try:
@@ -86,11 +82,11 @@ def read(self):
86
82
 
87
83
  logging.debug(f"time format: {self.timeFormat}")
88
84
 
89
- self.fast = 10
85
+ self.fast = cfg.FAST_FORWARD_DEFAULT_VALUE
90
86
  try:
91
- self.fast = int(settings.value("Time/fast_forward_speed"))
87
+ self.fast = float(settings.value("Time/fast_forward_speed"))
92
88
  except Exception:
93
- self.fast = 10
89
+ self.fast = cfg.FAST_FORWARD_DEFAULT_VALUE
94
90
 
95
91
  logging.debug(f"Time/fast_forward_speed: {self.fast}")
96
92
 
@@ -172,25 +168,27 @@ def read(self):
172
168
 
173
169
  # check for new version
174
170
  self.checkForNewVersion = False
175
- try:
176
- if settings.value("check_for_new_version") is None:
177
- self.checkForNewVersion = (
178
- dialog.MessageDialog(
179
- cfg.programName,
180
- (
181
- "Allow BORIS to automatically check for new version and news?\n"
182
- "(An internet connection is required)\n"
183
- "You can change this option in the Preferences (File > Preferences)"
184
- ),
185
- [cfg.YES, cfg.NO],
171
+
172
+ if not self.no_first_launch_dialog:
173
+ try:
174
+ if settings.value("check_for_new_version") is None:
175
+ self.checkForNewVersion = (
176
+ dialog.MessageDialog(
177
+ cfg.programName,
178
+ (
179
+ "Allow BORIS to automatically check for new version and news?\n"
180
+ "(An internet connection is required)\n"
181
+ "You can change this option in the Preferences (File > Preferences)"
182
+ ),
183
+ [cfg.YES, cfg.NO],
184
+ )
185
+ == cfg.YES
186
186
  )
187
- == cfg.YES
188
- )
189
- else:
190
- self.checkForNewVersion = settings.value("check_for_new_version") == "true"
191
- except Exception:
192
- self.checkForNewVersion = False
193
- logging.debug(f"check_for_new_version: {self.checkForNewVersion}")
187
+ else:
188
+ self.checkForNewVersion = settings.value("check_for_new_version") == "true"
189
+ except Exception:
190
+ self.checkForNewVersion = False
191
+ logging.debug(f"Automatic check for new version: {self.checkForNewVersion}")
194
192
 
195
193
  # pause before add event
196
194
  self.pause_before_addevent = False
@@ -203,11 +201,11 @@ def read(self):
203
201
 
204
202
  if self.checkForNewVersion:
205
203
  if settings.value("last_check_for_new_version") and (
206
- int(time.mktime(time.localtime())) - int(settings.value("last_check_for_new_version"))
207
- > cfg.CHECK_NEW_VERSION_DELAY
204
+ int(time.mktime(time.localtime())) - int(settings.value("last_check_for_new_version")) > cfg.CHECK_NEW_VERSION_DELAY
208
205
  ):
209
206
  self.actionCheckUpdate_activated(flagMsgOnlyIfNew=True)
210
- logging.debug(f"last_check_for_new_version: {settings.value('last_check_for_new_version')}")
207
+
208
+ logging.debug(f"last check for new version: {settings.value('last_check_for_new_version')}")
211
209
 
212
210
  self.ffmpeg_cache_dir = ""
213
211
  try:
@@ -245,10 +243,7 @@ def read(self):
245
243
  if (
246
244
  dialog.MessageDialog(
247
245
  cfg.programName,
248
- (
249
- "The colors list contain colors that are very light.\n"
250
- "Do you want to reload the default colors list?"
251
- ),
246
+ ("The colors list contain colors that are very light.\nDo you want to reload the default colors list?"),
252
247
  [cfg.NO, cfg.YES],
253
248
  )
254
249
  == cfg.YES
@@ -261,18 +256,11 @@ def read(self):
261
256
  except Exception:
262
257
  self.behav_category_colors = cfg.CATEGORY_COLORS_LIST
263
258
 
264
- if (
265
- "white" in self.behav_category_colors
266
- or "azure" in self.behav_category_colors
267
- or "snow" in self.behav_category_colors
268
- ):
259
+ if "white" in self.behav_category_colors or "azure" in self.behav_category_colors or "snow" in self.behav_category_colors:
269
260
  if (
270
261
  dialog.MessageDialog(
271
262
  cfg.programName,
272
- (
273
- "The colors list contain colors that are very light.\n"
274
- "Do you want to reload the default colors list?"
275
- ),
263
+ ("The colors list contain colors that are very light.\nDo you want to reload the default colors list?"),
276
264
  [cfg.NO, cfg.YES],
277
265
  )
278
266
  == cfg.YES
@@ -282,25 +270,28 @@ def read(self):
282
270
  else: # no .boris file found
283
271
  logging.info("No config file found")
284
272
  # ask user for checking for new version
285
- self.checkForNewVersion = (
286
- dialog.MessageDialog(
287
- cfg.programName,
288
- (
289
- "Allow BORIS to automatically check for new version?\n"
290
- "(An internet connection is required)\n"
291
- "You can change this option in the"
292
- " Preferences (File > Preferences)"
293
- ),
294
- [cfg.NO, cfg.YES],
273
+ if not self.no_first_launch_dialog:
274
+ self.checkForNewVersion = (
275
+ dialog.MessageDialog(
276
+ cfg.programName,
277
+ (
278
+ "Allow BORIS to automatically check for new version?\n"
279
+ "(An internet connection is required)\n"
280
+ "You can change this option in the"
281
+ " Preferences (File > Preferences)"
282
+ ),
283
+ [cfg.NO, cfg.YES],
284
+ )
285
+ == cfg.YES
295
286
  )
296
- == cfg.YES
297
- )
287
+ else:
288
+ self.checkForNewVersion = False
298
289
 
299
290
  # recent projects
300
- logging.info("read recent projects")
301
- iniFilePath = str(pl.Path.home() / ".boris_recent_projects")
302
- if os.path.isfile(iniFilePath):
303
- settings = QSettings(iniFilePath, QSettings.IniFormat)
291
+ logging.debug("read recent projects")
292
+ recent_projects_file_path = pl.Path.home() / ".boris_recent_projects"
293
+ if recent_projects_file_path.is_file():
294
+ settings = QSettings(str(recent_projects_file_path), QSettings.IniFormat)
304
295
  try:
305
296
  self.recent_projects = settings.value("recent_projects").split("|||")
306
297
  while "" in self.recent_projects: