boris-behav-obs 9.7.7__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.
- boris/__init__.py +26 -0
- boris/__main__.py +25 -0
- boris/about.py +143 -0
- boris/add_modifier.py +635 -0
- boris/add_modifier_ui.py +303 -0
- boris/advanced_event_filtering.py +455 -0
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_latency.py +59 -0
- boris/analysis_plugins/irr_cohen_kappa.py +109 -0
- boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
- boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
- boris/analysis_plugins/number_of_occurences.py +22 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
- boris/analysis_plugins/time_budget.py +61 -0
- boris/behav_coding_map_creator.py +1110 -0
- boris/behavior_binary_table.py +305 -0
- boris/behaviors_coding_map.py +239 -0
- boris/boris_cli.py +340 -0
- boris/cmd_arguments.py +49 -0
- boris/coding_pad.py +280 -0
- boris/config.py +785 -0
- boris/config_file.py +356 -0
- boris/connections.py +409 -0
- boris/converters.py +333 -0
- boris/converters_ui.py +225 -0
- boris/cooccurence.py +250 -0
- boris/core.py +5901 -0
- boris/core_qrc.py +15958 -0
- boris/core_ui.py +1107 -0
- boris/db_functions.py +324 -0
- boris/dev.py +134 -0
- boris/dialog.py +1108 -0
- boris/duration_widget.py +238 -0
- boris/edit_event.py +245 -0
- boris/edit_event_ui.py +233 -0
- boris/event_operations.py +1040 -0
- boris/events_cursor.py +61 -0
- boris/events_snapshots.py +596 -0
- boris/exclusion_matrix.py +141 -0
- boris/export_events.py +1006 -0
- boris/export_observation.py +1203 -0
- boris/external_processes.py +332 -0
- boris/geometric_measurement.py +941 -0
- boris/gui_utilities.py +135 -0
- boris/image_overlay.py +72 -0
- boris/import_observations.py +242 -0
- boris/ipc_mpv.py +325 -0
- boris/irr.py +634 -0
- boris/latency.py +244 -0
- boris/measurement_widget.py +161 -0
- boris/media_file.py +115 -0
- boris/menu_options.py +213 -0
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +157 -0
- boris/mpv.py +2016 -0
- boris/mpv2.py +2193 -0
- boris/observation.py +1453 -0
- boris/observation_operations.py +2538 -0
- boris/observation_ui.py +679 -0
- boris/observations_list.py +337 -0
- boris/otx_parser.py +442 -0
- boris/param_panel.py +201 -0
- boris/param_panel_ui.py +305 -0
- boris/player_dock_widget.py +198 -0
- boris/plot_data_module.py +536 -0
- boris/plot_events.py +634 -0
- boris/plot_events_rt.py +237 -0
- boris/plot_spectrogram_rt.py +316 -0
- boris/plot_waveform_rt.py +230 -0
- boris/plugins.py +431 -0
- boris/portion/__init__.py +31 -0
- boris/portion/const.py +95 -0
- boris/portion/dict.py +365 -0
- boris/portion/func.py +52 -0
- boris/portion/interval.py +581 -0
- boris/portion/io.py +181 -0
- boris/preferences.py +510 -0
- boris/preferences_ui.py +770 -0
- boris/project.py +2007 -0
- boris/project_functions.py +2041 -0
- boris/project_import_export.py +1096 -0
- boris/project_ui.py +794 -0
- boris/qrc_boris.py +10389 -0
- boris/qrc_boris5.py +2579 -0
- boris/select_modifiers.py +312 -0
- boris/select_observations.py +210 -0
- boris/select_subj_behav.py +286 -0
- boris/state_events.py +197 -0
- boris/subjects_pad.py +106 -0
- boris/synthetic_time_budget.py +290 -0
- boris/time_budget_functions.py +1136 -0
- boris/time_budget_widget.py +1039 -0
- boris/transitions.py +365 -0
- boris/utilities.py +1810 -0
- boris/version.py +24 -0
- boris/video_equalizer.py +159 -0
- boris/video_equalizer_ui.py +248 -0
- boris/video_operations.py +310 -0
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +538 -0
- boris_behav_obs-9.7.7.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.7.dist-info/RECORD +109 -0
- boris_behav_obs-9.7.7.dist-info/WHEEL +5 -0
- boris_behav_obs-9.7.7.dist-info/entry_points.txt +2 -0
- boris_behav_obs-9.7.7.dist-info/licenses/LICENSE.TXT +674 -0
- boris_behav_obs-9.7.7.dist-info/top_level.txt +1 -0
boris/config_file.py
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
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
|
+
Read and write the BORIS config file
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import pathlib as pl
|
|
25
|
+
import logging
|
|
26
|
+
import time
|
|
27
|
+
|
|
28
|
+
from . import config as cfg
|
|
29
|
+
from . import dialog
|
|
30
|
+
|
|
31
|
+
from PySide6.QtCore import QByteArray, QSettings
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def read(self):
|
|
35
|
+
"""
|
|
36
|
+
read config file
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
ini_fil_p_pe_p_path = pl.Path.home() / pl.Path(".boris")
|
|
40
|
+
|
|
41
|
+
logging.debug(f"read config file: {ini_fil_p_pe_p_path}")
|
|
42
|
+
|
|
43
|
+
if ini_fil_p_pe_p_path.is_file():
|
|
44
|
+
settings = QSettings(str(ini_fil_p_pe_p_path), QSettings.IniFormat)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
self.config_param = settings.value("config")
|
|
48
|
+
except Exception:
|
|
49
|
+
self.config_param = {}
|
|
50
|
+
|
|
51
|
+
if self.config_param == {}:
|
|
52
|
+
self.config_param = cfg.INIT_PARAM
|
|
53
|
+
|
|
54
|
+
# for back compatibility
|
|
55
|
+
# display subtitles
|
|
56
|
+
try:
|
|
57
|
+
self.config_param[cfg.DISPLAY_SUBTITLES] = settings.value(cfg.DISPLAY_SUBTITLES) == "true"
|
|
58
|
+
except Exception:
|
|
59
|
+
self.config_param[cfg.DISPLAY_SUBTITLES] = False
|
|
60
|
+
|
|
61
|
+
logging.debug(f"{cfg.DISPLAY_SUBTITLES}: {self.config_param[cfg.DISPLAY_SUBTITLES]}")
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
logging.debug("restore geometry")
|
|
65
|
+
|
|
66
|
+
self.restoreGeometry(settings.value("geometry"))
|
|
67
|
+
except Exception:
|
|
68
|
+
logging.warning("Error restoring geometry")
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
self.saved_state = settings.value("dockwidget_positions")
|
|
72
|
+
if not isinstance(self.saved_state, QByteArray):
|
|
73
|
+
self.saved_state = None
|
|
74
|
+
|
|
75
|
+
# logging.debug(f"saved state: {self.saved_state}")
|
|
76
|
+
|
|
77
|
+
self.timeFormat = cfg.HHMMSS
|
|
78
|
+
try:
|
|
79
|
+
self.timeFormat = settings.value("Time/Format")
|
|
80
|
+
except Exception:
|
|
81
|
+
self.timeFormat = cfg.HHMMSS
|
|
82
|
+
|
|
83
|
+
logging.debug(f"time format: {self.timeFormat}")
|
|
84
|
+
|
|
85
|
+
self.fast = cfg.FAST_FORWARD_DEFAULT_VALUE
|
|
86
|
+
try:
|
|
87
|
+
self.fast = float(settings.value("Time/fast_forward_speed"))
|
|
88
|
+
except Exception:
|
|
89
|
+
self.fast = cfg.FAST_FORWARD_DEFAULT_VALUE
|
|
90
|
+
|
|
91
|
+
logging.debug(f"Time/fast_forward_speed: {self.fast}")
|
|
92
|
+
|
|
93
|
+
self.repositioningTimeOffset = 0
|
|
94
|
+
try:
|
|
95
|
+
self.repositioningTimeOffset = int(settings.value("Time/Repositioning_time_offset"))
|
|
96
|
+
except Exception:
|
|
97
|
+
self.repositioningTimeOffset = 0
|
|
98
|
+
|
|
99
|
+
logging.debug(f"Time/Repositioning_time_offset: {self.repositioningTimeOffset}")
|
|
100
|
+
|
|
101
|
+
self.play_rate_step = 0.1
|
|
102
|
+
try:
|
|
103
|
+
self.play_rate_step = float(settings.value("Time/play_rate_step"))
|
|
104
|
+
except Exception:
|
|
105
|
+
self.play_rate_step = 0.1
|
|
106
|
+
|
|
107
|
+
logging.debug(f"Time/play_rate_step: {self.play_rate_step}")
|
|
108
|
+
|
|
109
|
+
self.automaticBackup = 0
|
|
110
|
+
try:
|
|
111
|
+
self.automaticBackup = int(settings.value("Automatic_backup"))
|
|
112
|
+
except Exception:
|
|
113
|
+
self.automaticBackup = 0
|
|
114
|
+
|
|
115
|
+
# activate or desactivate autosave timer
|
|
116
|
+
if self.automaticBackup:
|
|
117
|
+
self.automaticBackupTimer.start(self.automaticBackup * 60000)
|
|
118
|
+
else:
|
|
119
|
+
self.automaticBackupTimer.stop()
|
|
120
|
+
|
|
121
|
+
logging.debug(f"Autosave: {self.automaticBackup}")
|
|
122
|
+
|
|
123
|
+
self.behav_seq_separator = "|"
|
|
124
|
+
try:
|
|
125
|
+
self.behav_seq_separator = settings.value("behavioural_strings_separator")
|
|
126
|
+
if not self.behav_seq_separator:
|
|
127
|
+
self.behav_seq_separator = "|"
|
|
128
|
+
except Exception:
|
|
129
|
+
self.behav_seq_separator = "|"
|
|
130
|
+
|
|
131
|
+
logging.debug(f"behavioural_strings_separator: {self.behav_seq_separator}")
|
|
132
|
+
|
|
133
|
+
self.close_the_same_current_event = False
|
|
134
|
+
try:
|
|
135
|
+
self.close_the_same_current_event = settings.value("close_the_same_current_event") == "true"
|
|
136
|
+
except Exception:
|
|
137
|
+
self.close_the_same_current_event = False
|
|
138
|
+
|
|
139
|
+
logging.debug(f"close_the_same_current_event: {self.close_the_same_current_event}")
|
|
140
|
+
|
|
141
|
+
self.confirmSound = False
|
|
142
|
+
try:
|
|
143
|
+
self.confirmSound = settings.value("confirm_sound") == "true"
|
|
144
|
+
except Exception:
|
|
145
|
+
self.confirmSound = False
|
|
146
|
+
|
|
147
|
+
logging.debug(f"confirm_sound: {self.confirmSound}")
|
|
148
|
+
|
|
149
|
+
self.alertNoFocalSubject = False
|
|
150
|
+
try:
|
|
151
|
+
self.alertNoFocalSubject = settings.value("alert_nosubject") == "true"
|
|
152
|
+
except Exception:
|
|
153
|
+
self.alertNoFocalSubject = False
|
|
154
|
+
logging.debug(f"alert_nosubject: {self.alertNoFocalSubject}")
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
self.beep_every = int(settings.value("beep_every"))
|
|
158
|
+
except Exception:
|
|
159
|
+
self.beep_every = 0
|
|
160
|
+
logging.debug(f"beep_every: {self.beep_every}")
|
|
161
|
+
|
|
162
|
+
self.trackingCursorAboveEvent = False
|
|
163
|
+
try:
|
|
164
|
+
self.trackingCursorAboveEvent = settings.value("tracking_cursor_above_event") == "true"
|
|
165
|
+
except Exception:
|
|
166
|
+
self.trackingCursorAboveEvent = False
|
|
167
|
+
logging.debug(f"tracking_cursor_above_event: {self.trackingCursorAboveEvent}")
|
|
168
|
+
|
|
169
|
+
# check for new version
|
|
170
|
+
self.checkForNewVersion = False
|
|
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
|
+
)
|
|
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}")
|
|
192
|
+
|
|
193
|
+
# pause before add event
|
|
194
|
+
self.pause_before_addevent = False
|
|
195
|
+
try:
|
|
196
|
+
self.pause_before_addevent = settings.value("pause_before_addevent") == "true"
|
|
197
|
+
except Exception:
|
|
198
|
+
self.pause_before_addevent = False
|
|
199
|
+
|
|
200
|
+
logging.debug(f"pause_before_addevent: {self.pause_before_addevent}")
|
|
201
|
+
|
|
202
|
+
if self.checkForNewVersion:
|
|
203
|
+
if settings.value("last_check_for_new_version") and (
|
|
204
|
+
int(time.mktime(time.localtime())) - int(settings.value("last_check_for_new_version")) > cfg.CHECK_NEW_VERSION_DELAY
|
|
205
|
+
):
|
|
206
|
+
self.actionCheckUpdate_activated(flagMsgOnlyIfNew=True)
|
|
207
|
+
|
|
208
|
+
logging.debug(f"last check for new version: {settings.value('last_check_for_new_version')}")
|
|
209
|
+
|
|
210
|
+
self.ffmpeg_cache_dir = ""
|
|
211
|
+
try:
|
|
212
|
+
self.ffmpeg_cache_dir = settings.value("ffmpeg_cache_dir")
|
|
213
|
+
if not self.ffmpeg_cache_dir:
|
|
214
|
+
self.ffmpeg_cache_dir = ""
|
|
215
|
+
except Exception:
|
|
216
|
+
self.ffmpeg_cache_dir = ""
|
|
217
|
+
logging.debug(f"ffmpeg_cache_dir: {self.ffmpeg_cache_dir}")
|
|
218
|
+
|
|
219
|
+
# spectrogram
|
|
220
|
+
self.spectrogramHeight = 80
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
self.spectrogram_color_map = settings.value("spectrogram_color_map")
|
|
224
|
+
if self.spectrogram_color_map is None:
|
|
225
|
+
self.spectrogram_color_map = cfg.SPECTROGRAM_DEFAULT_COLOR_MAP
|
|
226
|
+
except Exception:
|
|
227
|
+
self.spectrogram_color_map = cfg.SPECTROGRAM_DEFAULT_COLOR_MAP
|
|
228
|
+
|
|
229
|
+
try:
|
|
230
|
+
self.spectrogram_time_interval = int(settings.value("spectrogram_time_interval"))
|
|
231
|
+
if not self.spectrogram_time_interval:
|
|
232
|
+
self.spectrogram_time_interval = cfg.SPECTROGRAM_DEFAULT_TIME_INTERVAL
|
|
233
|
+
except Exception:
|
|
234
|
+
self.spectrogram_time_interval = cfg.SPECTROGRAM_DEFAULT_TIME_INTERVAL
|
|
235
|
+
|
|
236
|
+
# plot colors
|
|
237
|
+
try:
|
|
238
|
+
self.plot_colors = settings.value("plot_colors").split("|")
|
|
239
|
+
except Exception:
|
|
240
|
+
self.plot_colors = cfg.BEHAVIORS_PLOT_COLORS
|
|
241
|
+
|
|
242
|
+
if "white" in self.plot_colors or "azure" in self.plot_colors or "snow" in self.plot_colors:
|
|
243
|
+
if (
|
|
244
|
+
dialog.MessageDialog(
|
|
245
|
+
cfg.programName,
|
|
246
|
+
("The colors list contain colors that are very light.\nDo you want to reload the default colors list?"),
|
|
247
|
+
[cfg.NO, cfg.YES],
|
|
248
|
+
)
|
|
249
|
+
== cfg.YES
|
|
250
|
+
):
|
|
251
|
+
self.plot_colors = cfg.BEHAVIORS_PLOT_COLORS
|
|
252
|
+
|
|
253
|
+
# behavioral categories colors
|
|
254
|
+
try:
|
|
255
|
+
self.behav_category_colors = settings.value("behav_category_colors").split("|")
|
|
256
|
+
except Exception:
|
|
257
|
+
self.behav_category_colors = cfg.CATEGORY_COLORS_LIST
|
|
258
|
+
|
|
259
|
+
if "white" in self.behav_category_colors or "azure" in self.behav_category_colors or "snow" in self.behav_category_colors:
|
|
260
|
+
if (
|
|
261
|
+
dialog.MessageDialog(
|
|
262
|
+
cfg.programName,
|
|
263
|
+
("The colors list contain colors that are very light.\nDo you want to reload the default colors list?"),
|
|
264
|
+
[cfg.NO, cfg.YES],
|
|
265
|
+
)
|
|
266
|
+
== cfg.YES
|
|
267
|
+
):
|
|
268
|
+
self.behav_category_colors = cfg.CATEGORY_COLORS_LIST
|
|
269
|
+
|
|
270
|
+
else: # no .boris file found
|
|
271
|
+
logging.info("No config file found")
|
|
272
|
+
# ask user for checking for new version
|
|
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
|
|
286
|
+
)
|
|
287
|
+
else:
|
|
288
|
+
self.checkForNewVersion = False
|
|
289
|
+
|
|
290
|
+
# recent projects
|
|
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)
|
|
295
|
+
try:
|
|
296
|
+
self.recent_projects = settings.value("recent_projects").split("|||")
|
|
297
|
+
while "" in self.recent_projects:
|
|
298
|
+
self.recent_projects.remove("")
|
|
299
|
+
self.set_recent_projects_menu()
|
|
300
|
+
except Exception:
|
|
301
|
+
self.recent_projects = []
|
|
302
|
+
else:
|
|
303
|
+
self.recent_projects = []
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def save(self, lastCheckForNewVersion=0):
|
|
307
|
+
"""
|
|
308
|
+
save config file in $HOME/.boris
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
file_path = pl.Path.home() / pl.Path(".boris")
|
|
312
|
+
|
|
313
|
+
logging.debug(f"save config file: {file_path}")
|
|
314
|
+
|
|
315
|
+
settings = QSettings(str(file_path), QSettings.IniFormat)
|
|
316
|
+
|
|
317
|
+
settings.setValue("config", self.config_param)
|
|
318
|
+
|
|
319
|
+
settings.setValue("geometry", self.saveGeometry())
|
|
320
|
+
|
|
321
|
+
if self.saved_state:
|
|
322
|
+
settings.setValue("dockwidget_positions", self.saved_state)
|
|
323
|
+
|
|
324
|
+
settings.setValue("Time/Format", self.timeFormat)
|
|
325
|
+
settings.setValue("Time/Repositioning_time_offset", self.repositioningTimeOffset)
|
|
326
|
+
settings.setValue("Time/fast_forward_speed", self.fast)
|
|
327
|
+
settings.setValue("Time/play_rate_step", self.play_rate_step)
|
|
328
|
+
settings.setValue("Automatic_backup", self.automaticBackup)
|
|
329
|
+
settings.setValue("behavioural_strings_separator", self.behav_seq_separator)
|
|
330
|
+
settings.setValue("close_the_same_current_event", self.close_the_same_current_event)
|
|
331
|
+
settings.setValue("confirm_sound", self.confirmSound)
|
|
332
|
+
settings.setValue("beep_every", self.beep_every)
|
|
333
|
+
settings.setValue("alert_nosubject", self.alertNoFocalSubject)
|
|
334
|
+
settings.setValue("tracking_cursor_above_event", self.trackingCursorAboveEvent)
|
|
335
|
+
settings.setValue("check_for_new_version", self.checkForNewVersion)
|
|
336
|
+
# settings.setValue(DISPLAY_SUBTITLES, self.config_param[DISPLAY_SUBTITLES])
|
|
337
|
+
settings.setValue("pause_before_addevent", self.pause_before_addevent)
|
|
338
|
+
|
|
339
|
+
if lastCheckForNewVersion:
|
|
340
|
+
settings.setValue("last_check_for_new_version", lastCheckForNewVersion)
|
|
341
|
+
|
|
342
|
+
# FFmpeg
|
|
343
|
+
settings.setValue("ffmpeg_cache_dir", self.ffmpeg_cache_dir)
|
|
344
|
+
# spectrogram
|
|
345
|
+
settings.setValue("spectrogram_color_map", self.spectrogram_color_map)
|
|
346
|
+
settings.setValue("spectrogram_time_interval", self.spectrogram_time_interval)
|
|
347
|
+
# plot colors
|
|
348
|
+
settings.setValue("plot_colors", "|".join(self.plot_colors))
|
|
349
|
+
# behavioral categories colors
|
|
350
|
+
settings.setValue("behav_category_colors", "|".join(self.behav_category_colors))
|
|
351
|
+
|
|
352
|
+
# recent projects
|
|
353
|
+
logging.debug("Save recent projects")
|
|
354
|
+
|
|
355
|
+
settings = QSettings(str(pl.Path.home() / ".boris_recent_projects"), QSettings.IniFormat)
|
|
356
|
+
settings.setValue("recent_projects", "|||".join(self.recent_projects))
|