boris-behav-obs 8.16.5__py3-none-any.whl → 9.7.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +28 -40
- boris/add_modifier.py +88 -80
- boris/add_modifier_ui.py +266 -144
- boris/advanced_event_filtering.py +23 -29
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_export_to_feral.py +225 -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 +235 -236
- boris/behavior_binary_table.py +33 -50
- boris/behaviors_coding_map.py +17 -18
- boris/boris_cli.py +6 -25
- boris/cmd_arguments.py +12 -1
- boris/coding_pad.py +19 -36
- boris/config.py +109 -50
- boris/config_file.py +58 -67
- boris/connections.py +105 -58
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2174 -1303
- boris/core_qrc.py +15892 -10829
- boris/core_ui.py +941 -806
- boris/db_functions.py +17 -42
- boris/dev.py +27 -7
- boris/dialog.py +461 -242
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +405 -281
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +180 -203
- boris/export_observation.py +60 -73
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +427 -218
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +4 -4
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +325 -0
- boris/irr.py +20 -57
- boris/latency.py +31 -24
- boris/measurement_widget.py +14 -18
- boris/media_file.py +17 -19
- boris/menu_options.py +16 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv2.py +128 -35
- boris/observation.py +501 -211
- boris/observation_operations.py +1037 -393
- boris/observation_ui.py +573 -363
- boris/observations_list.py +51 -58
- boris/otx_parser.py +74 -68
- boris/param_panel.py +45 -59
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +91 -56
- boris/plot_data_module.py +20 -53
- boris/plot_events.py +56 -153
- boris/plot_events_rt.py +16 -30
- boris/plot_spectrogram_rt.py +83 -56
- boris/plot_waveform_rt.py +27 -49
- boris/plugins.py +468 -0
- boris/portion/__init__.py +18 -8
- boris/portion/const.py +35 -18
- boris/portion/dict.py +5 -5
- boris/portion/func.py +2 -2
- boris/portion/interval.py +21 -41
- boris/portion/io.py +41 -32
- boris/preferences.py +307 -123
- boris/preferences_ui.py +686 -227
- boris/project.py +294 -271
- boris/project_functions.py +626 -537
- boris/project_import_export.py +204 -213
- boris/project_ui.py +673 -441
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +62 -90
- boris/select_observations.py +19 -197
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +51 -33
- boris/subjects_pad.py +7 -9
- boris/synthetic_time_budget.py +42 -26
- boris/time_budget_functions.py +169 -169
- boris/time_budget_widget.py +77 -89
- boris/transitions.py +41 -41
- boris/utilities.py +594 -226
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +86 -28
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +240 -136
- boris_behav_obs-9.7.12.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.12.dist-info/RECORD +110 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.12.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/converters.ui +0 -289
- boris/core.qrc +0 -37
- boris/core.ui +0 -1571
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -982
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1074
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.16.5.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.16.5.dist-info/METADATA +0 -134
- boris_behav_obs-8.16.5.dist-info/RECORD +0 -107
- boris_behav_obs-8.16.5.dist-info/entry_points.txt +0 -2
- {boris → boris_behav_obs-9.7.12.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.16.5.dist-info → boris_behav_obs-9.7.12.dist-info}/top_level.txt +0 -0
boris/latency.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This program is free software; you can redistribute it and/or modify
|
|
7
7
|
it under the terms of the GNU General Public License as published by
|
|
@@ -18,9 +18,7 @@ Copyright 2012-2023 Olivier Friard
|
|
|
18
18
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
|
|
21
|
-
"""
|
|
22
21
|
|
|
23
|
-
"""
|
|
24
22
|
Module for analyzing the latency of behaviors after another behavior(s) (marker)
|
|
25
23
|
|
|
26
24
|
"""
|
|
@@ -31,7 +29,7 @@ from . import dialog
|
|
|
31
29
|
from . import select_observations
|
|
32
30
|
from . import project_functions, observation_operations
|
|
33
31
|
|
|
34
|
-
from
|
|
32
|
+
from PySide6.QtWidgets import QMessageBox
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
def get_latency(self):
|
|
@@ -43,10 +41,9 @@ def get_latency(self):
|
|
|
43
41
|
None,
|
|
44
42
|
cfg.programName,
|
|
45
43
|
(
|
|
46
|
-
|
|
44
|
+
"This function is experimental. Please test it and report any bug at <br>"
|
|
47
45
|
'<a href="https://github.com/olivierfriard/BORIS/issues">'
|
|
48
46
|
"https://github.com/olivierfriard/BORIS/issues</a><br>"
|
|
49
|
-
"or by email (See the About page on the BORIS web site.<br><br>"
|
|
50
47
|
"Thank you for your collaboration!"
|
|
51
48
|
),
|
|
52
49
|
QMessageBox.Ok | QMessageBox.Default,
|
|
@@ -83,10 +80,10 @@ def get_latency(self):
|
|
|
83
80
|
)
|
|
84
81
|
return
|
|
85
82
|
|
|
86
|
-
parameters = select_subj_behav.choose_obs_subj_behav_category(
|
|
83
|
+
parameters: dict = select_subj_behav.choose_obs_subj_behav_category(
|
|
87
84
|
self,
|
|
88
85
|
selected_observations,
|
|
89
|
-
|
|
86
|
+
show_exclude_non_coded_behaviors=False,
|
|
90
87
|
window_title="Select the marker behaviors (stimulus)",
|
|
91
88
|
n_observations=len(selected_observations),
|
|
92
89
|
)
|
|
@@ -102,10 +99,10 @@ def get_latency(self):
|
|
|
102
99
|
marker_subjects = parameters[cfg.SELECTED_SUBJECTS]
|
|
103
100
|
include_marker_modifiers = parameters[cfg.INCLUDE_MODIFIERS]
|
|
104
101
|
|
|
105
|
-
|
|
102
|
+
print(f"{marker_behaviors=} {marker_subjects=} {include_marker_modifiers=}")
|
|
106
103
|
|
|
107
|
-
parameters = select_subj_behav.choose_obs_subj_behav_category(
|
|
108
|
-
self, selected_observations,
|
|
104
|
+
parameters: dict = select_subj_behav.choose_obs_subj_behav_category(
|
|
105
|
+
self, selected_observations, show_exclude_non_coded_behaviors=False, window_title="Select the latency behaviors"
|
|
109
106
|
)
|
|
110
107
|
if not parameters[cfg.SELECTED_SUBJECTS] or not parameters[cfg.SELECTED_BEHAVIORS]:
|
|
111
108
|
return
|
|
@@ -113,11 +110,11 @@ def get_latency(self):
|
|
|
113
110
|
latency_subjects = parameters[cfg.SELECTED_SUBJECTS]
|
|
114
111
|
include_latency_modifiers = parameters[cfg.INCLUDE_MODIFIERS]
|
|
115
112
|
|
|
116
|
-
|
|
113
|
+
print(f"{latency_behaviors=} {latency_subjects=} {include_latency_modifiers=}")
|
|
117
114
|
|
|
118
|
-
results = {}
|
|
115
|
+
results: dict = {}
|
|
119
116
|
for obs_id in selected_observations:
|
|
120
|
-
|
|
117
|
+
print(f"{obs_id=}")
|
|
121
118
|
|
|
122
119
|
events_with_status = project_functions.events_start_stop(
|
|
123
120
|
self.pj[cfg.ETHOGRAM],
|
|
@@ -125,7 +122,17 @@ def get_latency(self):
|
|
|
125
122
|
self.pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE],
|
|
126
123
|
)
|
|
127
124
|
|
|
125
|
+
print(f"{events_with_status=}")
|
|
126
|
+
|
|
128
127
|
for idx, event in enumerate(events_with_status):
|
|
128
|
+
print(f"{event=}")
|
|
129
|
+
|
|
130
|
+
print(f"{event[cfg.EVENT_STATUS_FIELD_IDX]=}")
|
|
131
|
+
|
|
132
|
+
print(f"{event[cfg.EVENT_BEHAVIOR_FIELD_IDX]=}")
|
|
133
|
+
|
|
134
|
+
print(f"{event[cfg.EVENT_SUBJECT_FIELD_IDX]=}")
|
|
135
|
+
|
|
129
136
|
if all(
|
|
130
137
|
(
|
|
131
138
|
event[cfg.EVENT_STATUS_FIELD_IDX] in (cfg.START, cfg.POINT),
|
|
@@ -138,11 +145,13 @@ def get_latency(self):
|
|
|
138
145
|
),
|
|
139
146
|
)
|
|
140
147
|
):
|
|
141
|
-
|
|
142
148
|
if include_marker_modifiers:
|
|
143
149
|
marker = event[cfg.EVENT_TIME_FIELD_IDX : cfg.EVENT_MODIFIER_FIELD_IDX + 1]
|
|
144
150
|
else:
|
|
145
151
|
marker = event[cfg.EVENT_TIME_FIELD_IDX : cfg.EVENT_BEHAVIOR_FIELD_IDX + 1]
|
|
152
|
+
|
|
153
|
+
print(f"{marker=}")
|
|
154
|
+
|
|
146
155
|
if marker not in results:
|
|
147
156
|
results[marker] = {}
|
|
148
157
|
|
|
@@ -164,20 +173,19 @@ def get_latency(self):
|
|
|
164
173
|
),
|
|
165
174
|
)
|
|
166
175
|
):
|
|
167
|
-
|
|
168
|
-
# print(event, event2)
|
|
176
|
+
print(event, event2)
|
|
169
177
|
if include_latency_modifiers:
|
|
170
178
|
latency = event2[cfg.EVENT_SUBJECT_FIELD_IDX : cfg.EVENT_MODIFIER_FIELD_IDX + 1]
|
|
171
179
|
else:
|
|
172
180
|
latency = event2[cfg.EVENT_SUBJECT_FIELD_IDX : cfg.EVENT_BEHAVIOR_FIELD_IDX + 1]
|
|
173
181
|
|
|
174
182
|
# print(f"{marker=}")
|
|
175
|
-
|
|
176
|
-
if not
|
|
183
|
+
print(f"{latency=}")
|
|
184
|
+
if latency not in results[marker]:
|
|
177
185
|
results[marker][latency] = []
|
|
178
|
-
results[marker][latency].append(
|
|
179
|
-
|
|
180
|
-
)
|
|
186
|
+
results[marker][latency].append(event2[cfg.EVENT_TIME_FIELD_IDX] - event[cfg.EVENT_TIME_FIELD_IDX])
|
|
187
|
+
|
|
188
|
+
print(f"{results[marker][latency]=}")
|
|
181
189
|
|
|
182
190
|
# check if new marker
|
|
183
191
|
if all(
|
|
@@ -208,7 +216,6 @@ def get_latency(self):
|
|
|
208
216
|
out = ""
|
|
209
217
|
|
|
210
218
|
for marker in sorted(results.keys()):
|
|
211
|
-
|
|
212
219
|
subject = cfg.NO_FOCAL_SUBJECT if marker[cfg.EVENT_SUBJECT_FIELD_IDX] == "" else marker[1]
|
|
213
220
|
if include_marker_modifiers:
|
|
214
221
|
out += f"Marker: <b>{marker[cfg.EVENT_BEHAVIOR_FIELD_IDX]}</b> at {marker[cfg.EVENT_TIME_FIELD_IDX]} s (subject: {subject} - modifiers: {marker[cfg.EVENT_MODIFIER_FIELD_IDX]})<br><br>"
|
|
@@ -223,7 +230,7 @@ def get_latency(self):
|
|
|
223
230
|
|
|
224
231
|
out += "first occurrence: "
|
|
225
232
|
out += f"{sorted(results[marker][behav])[0]} s<br>"
|
|
226
|
-
out +=
|
|
233
|
+
out += "all occurrences: "
|
|
227
234
|
|
|
228
235
|
out += ", ".join([f"{x} s" for x in sorted(results[marker][behav])])
|
|
229
236
|
out += "<br><br>"
|
boris/measurement_widget.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
"""
|
|
3
2
|
BORIS
|
|
4
3
|
Behavioral Observation Research Interactive Software
|
|
5
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
6
5
|
|
|
7
6
|
This file is part of BORIS.
|
|
8
7
|
|
|
@@ -23,10 +22,10 @@ This file is part of BORIS.
|
|
|
23
22
|
|
|
24
23
|
import logging
|
|
25
24
|
|
|
26
|
-
from
|
|
25
|
+
from PySide6.QtCore import Signal
|
|
27
26
|
|
|
28
|
-
# from
|
|
29
|
-
from
|
|
27
|
+
# from PySide6.QtGui import *
|
|
28
|
+
from PySide6.QtWidgets import (
|
|
30
29
|
QApplication,
|
|
31
30
|
QWidget,
|
|
32
31
|
QRadioButton,
|
|
@@ -40,14 +39,14 @@ from PyQt5.QtWidgets import (
|
|
|
40
39
|
QFileDialog,
|
|
41
40
|
QMessageBox,
|
|
42
41
|
)
|
|
43
|
-
from
|
|
44
|
-
from
|
|
42
|
+
from . import dialog
|
|
43
|
+
from . import config as cfg
|
|
45
44
|
|
|
46
45
|
|
|
47
46
|
class wgMeasurement(QWidget):
|
|
48
47
|
""" """
|
|
49
48
|
|
|
50
|
-
closeSignal, clearSignal =
|
|
49
|
+
closeSignal, clearSignal = Signal(), Signal()
|
|
51
50
|
flagSaved = True
|
|
52
51
|
draw_mem = []
|
|
53
52
|
|
|
@@ -112,7 +111,7 @@ class wgMeasurement(QWidget):
|
|
|
112
111
|
self.pbSave = QPushButton("Save results", clicked=self.pbSave_clicked)
|
|
113
112
|
hbox3.addWidget(self.pbSave)
|
|
114
113
|
|
|
115
|
-
self.pbClose = QPushButton(
|
|
114
|
+
self.pbClose = QPushButton(cfg.CLOSE, clicked=self.pbClose_clicked)
|
|
116
115
|
hbox3.addWidget(self.pbClose)
|
|
117
116
|
|
|
118
117
|
vbox.addLayout(hbox3)
|
|
@@ -128,13 +127,13 @@ class wgMeasurement(QWidget):
|
|
|
128
127
|
def pbClose_clicked(self):
|
|
129
128
|
if not self.flagSaved:
|
|
130
129
|
response = dialog.MessageDialog(
|
|
131
|
-
programName,
|
|
130
|
+
cfg.programName,
|
|
132
131
|
"The current results are not saved. Do you want to save results before closing?",
|
|
133
|
-
[YES, NO, CANCEL],
|
|
132
|
+
[cfg.YES, cfg.NO, cfg.CANCEL],
|
|
134
133
|
)
|
|
135
|
-
if response == YES:
|
|
134
|
+
if response == cfg.YES:
|
|
136
135
|
self.pbSave_clicked()
|
|
137
|
-
if response == CANCEL:
|
|
136
|
+
if response == cfg.CANCEL:
|
|
138
137
|
return
|
|
139
138
|
self.closeSignal.emit()
|
|
140
139
|
|
|
@@ -143,19 +142,16 @@ class wgMeasurement(QWidget):
|
|
|
143
142
|
save results
|
|
144
143
|
"""
|
|
145
144
|
if self.pte.toPlainText():
|
|
146
|
-
fileName, _ = QFileDialog().getSaveFileName(
|
|
147
|
-
self, "Save measurement results", "", "Text files (*.txt);;All files (*)"
|
|
148
|
-
)
|
|
145
|
+
fileName, _ = QFileDialog().getSaveFileName(self, "Save measurement results", "", "Text files (*.txt);;All files (*)")
|
|
149
146
|
if fileName:
|
|
150
147
|
with open(fileName, "w") as f:
|
|
151
148
|
f.write(self.pte.toPlainText())
|
|
152
149
|
self.flagSaved = True
|
|
153
150
|
else:
|
|
154
|
-
QMessageBox.information(self, programName, "There are no results to save")
|
|
151
|
+
QMessageBox.information(self, cfg.programName, "There are no results to save")
|
|
155
152
|
|
|
156
153
|
|
|
157
154
|
if __name__ == "__main__":
|
|
158
|
-
|
|
159
155
|
import sys
|
|
160
156
|
|
|
161
157
|
app = QApplication(sys.argv)
|
boris/media_file.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This file is part of BORIS.
|
|
7
7
|
|
|
@@ -20,13 +20,13 @@ This file is part of BORIS.
|
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
import
|
|
23
|
+
from PySide6.QtWidgets import QFileDialog
|
|
24
24
|
|
|
25
25
|
from . import config as cfg
|
|
26
26
|
from . import utilities as util
|
|
27
27
|
from . import dialog
|
|
28
28
|
from . import project_functions
|
|
29
|
-
from
|
|
29
|
+
from . import utilities as util
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def get_info(self) -> None:
|
|
@@ -34,22 +34,23 @@ def get_info(self) -> None:
|
|
|
34
34
|
show info about media file (current media file if an observation is opened)
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
def media_analysis_str(ffmpeg_bin, media_full_path):
|
|
38
|
-
|
|
37
|
+
def media_analysis_str(ffmpeg_bin: str, media_full_path: str) -> str:
|
|
39
38
|
r = util.accurate_media_analysis(ffmpeg_bin, media_full_path)
|
|
40
39
|
|
|
41
40
|
if "error" in r:
|
|
42
41
|
ffmpeg_output = f"File path: {media_full_path}<br><br>{r['error']}<br><br>"
|
|
43
42
|
else:
|
|
44
|
-
ffmpeg_output = f"<br><b>{r['analysis_program']
|
|
43
|
+
ffmpeg_output = f"<br><b>{r['analysis_program']} analysis</b><br>"
|
|
45
44
|
|
|
46
45
|
ffmpeg_output += (
|
|
47
46
|
f"File path: <b>{media_full_path}</b><br><br>"
|
|
48
47
|
f"Duration: {r['duration']} seconds ({util.convertTime(self.timeFormat, r['duration'])})<br>"
|
|
49
|
-
f"
|
|
48
|
+
f"FPS: {r['fps']}<br>"
|
|
49
|
+
f"Resolution: {r['resolution']} pixels<br>"
|
|
50
|
+
f"Format long name: {r.get('format_long_name', cfg.NA)}<br>"
|
|
51
|
+
f"Creation time: {r.get('creation_time', cfg.NA)}<br>"
|
|
50
52
|
f"Number of frames: {r['frames_number']}<br>"
|
|
51
53
|
f"Bitrate: {util.smart_size_format(r['bitrate'])} <br>"
|
|
52
|
-
f"FPS: {r['fps']}<br>"
|
|
53
54
|
f"Has video: {r['has_video']}<br>"
|
|
54
55
|
f"Has audio: {r['has_audio']}<br>"
|
|
55
56
|
f"File size: {util.smart_size_format(r.get('file size', cfg.NA))}<br>"
|
|
@@ -60,7 +61,6 @@ def get_info(self) -> None:
|
|
|
60
61
|
return ffmpeg_output
|
|
61
62
|
|
|
62
63
|
if self.observationId and self.playerType == cfg.MEDIA:
|
|
63
|
-
|
|
64
64
|
tot_output: str = ""
|
|
65
65
|
|
|
66
66
|
for i, dw in enumerate(self.dw_player):
|
|
@@ -72,6 +72,12 @@ def get_info(self) -> None:
|
|
|
72
72
|
|
|
73
73
|
mpv_output = (
|
|
74
74
|
"<b>MPV information</b><br>"
|
|
75
|
+
f"Duration: {dw.player.duration} seconds ({util.seconds2time(dw.player.duration)})<br>"
|
|
76
|
+
# "Position: {} %<br>"
|
|
77
|
+
f"FPS: {dw.player.container_fps}<br>"
|
|
78
|
+
# "Rate: {}<br>"
|
|
79
|
+
f"Resolution: {dw.player.width}x{dw.player.height} pixels<br>"
|
|
80
|
+
# "Scale: {}<br>"
|
|
75
81
|
f"Video format: {dw.player.video_format}<br>"
|
|
76
82
|
# "State: {}<br>"
|
|
77
83
|
# "Media Resource Location: {}<br>"
|
|
@@ -79,12 +85,6 @@ def get_info(self) -> None:
|
|
|
79
85
|
# "Track: {}/{}<br>"
|
|
80
86
|
f"Number of media in media list: {dw.player.playlist_count}<br>"
|
|
81
87
|
f"Current time position: {dw.player.time_pos}<br>"
|
|
82
|
-
f"duration: {dw.player.duration}<br>"
|
|
83
|
-
# "Position: {} %<br>"
|
|
84
|
-
f"FPS: {dw.player.container_fps}<br>"
|
|
85
|
-
# "Rate: {}<br>"
|
|
86
|
-
f"Video size: {dw.player.width}x{dw.player.height}<br>"
|
|
87
|
-
# "Scale: {}<br>"
|
|
88
88
|
f"Aspect ratio: {round(dw.player.width / dw.player.height, 3)}<br>"
|
|
89
89
|
# "is seekable? {}<br>"
|
|
90
90
|
# "has_vout? {}<br>"
|
|
@@ -101,9 +101,7 @@ def get_info(self) -> None:
|
|
|
101
101
|
tot_output += mpv_output + ffmpeg_output + "<br><hr>"
|
|
102
102
|
|
|
103
103
|
else: # no open observation
|
|
104
|
-
|
|
105
|
-
fn = QFileDialog().getOpenFileNames(self, "Select a media file", "", "Media files (*)")
|
|
106
|
-
file_paths = fn[0] if type(fn) is tuple else fn
|
|
104
|
+
file_paths, _ = QFileDialog().getOpenFileNames(self, "Select a media file", "", "Media files (*)")
|
|
107
105
|
if not file_paths:
|
|
108
106
|
return
|
|
109
107
|
|
|
@@ -112,6 +110,6 @@ def get_info(self) -> None:
|
|
|
112
110
|
tot_output += media_analysis_str(self.ffmpeg_bin, file_path)
|
|
113
111
|
|
|
114
112
|
self.results = dialog.Results_dialog()
|
|
115
|
-
self.results.setWindowTitle(cfg.programName
|
|
113
|
+
self.results.setWindowTitle(f"{cfg.programName} - Media file information")
|
|
116
114
|
self.results.ptText.appendHtml(tot_output)
|
|
117
115
|
self.results.show()
|
boris/menu_options.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This program is free software; you can redistribute it and/or modify
|
|
7
7
|
it under the terms of the GNU General Public License as published by
|
|
@@ -19,9 +19,9 @@ Copyright 2012-2023 Olivier Friard
|
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
import logging
|
|
24
23
|
from . import config as cfg
|
|
24
|
+
from PySide6.QtCore import QSize
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def update_windows_title(self):
|
|
@@ -57,6 +57,13 @@ def update_menu(self):
|
|
|
57
57
|
|
|
58
58
|
update_windows_title(self)
|
|
59
59
|
|
|
60
|
+
self.toolBar.setIconSize(
|
|
61
|
+
QSize(
|
|
62
|
+
self.config_param.get(cfg.TOOLBAR_ICON_SIZE, cfg.DEFAULT_TOOLBAR_ICON_SIZE_VALUE),
|
|
63
|
+
self.config_param.get(cfg.TOOLBAR_ICON_SIZE, cfg.DEFAULT_TOOLBAR_ICON_SIZE_VALUE),
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
|
|
60
67
|
# enabled if project loaded
|
|
61
68
|
for action in (
|
|
62
69
|
self.actionEdit_project,
|
|
@@ -65,9 +72,9 @@ def update_menu(self):
|
|
|
65
72
|
self.actionExport_project,
|
|
66
73
|
self.actionCheck_project,
|
|
67
74
|
self.actionClose_project,
|
|
68
|
-
self.actionSend_project,
|
|
69
75
|
self.actionNew_observation,
|
|
70
76
|
self.actionRemove_path_from_media_files,
|
|
77
|
+
self.action_create_observations,
|
|
71
78
|
self.action_obs_list,
|
|
72
79
|
self.actionExport_observations_list,
|
|
73
80
|
self.actionExplore_project,
|
|
@@ -136,6 +143,8 @@ def update_menu(self):
|
|
|
136
143
|
self.actionJumpForward,
|
|
137
144
|
self.actionJumpBackward,
|
|
138
145
|
self.actionJumpTo,
|
|
146
|
+
self.action_change_time_offset_of_players,
|
|
147
|
+
self.action_deinterlace,
|
|
139
148
|
self.actionZoom_level,
|
|
140
149
|
self.actionRotate_current_video,
|
|
141
150
|
self.actionDisplay_subtitles,
|
|
@@ -157,12 +166,12 @@ def update_menu(self):
|
|
|
157
166
|
self.menuImage_overlay_on_video_2,
|
|
158
167
|
self.actionAdd_image_overlay_on_video,
|
|
159
168
|
self.actionRemove_image_overlay,
|
|
169
|
+
self.actionAdd_frame_indexes,
|
|
160
170
|
):
|
|
161
|
-
|
|
162
171
|
action.setEnabled(self.playerType == cfg.MEDIA)
|
|
163
172
|
|
|
164
173
|
# geometric measurements
|
|
165
|
-
self.action_geometric_measurements.setEnabled(observation_is_active and self.geometric_measurements_mode
|
|
174
|
+
self.action_geometric_measurements.setEnabled(observation_is_active and self.geometric_measurements_mode is False)
|
|
166
175
|
self.actionCoding_pad.setEnabled(observation_is_active)
|
|
167
176
|
self.actionSubjects_pad.setEnabled(observation_is_active)
|
|
168
177
|
self.actionBehaviors_coding_map.setEnabled(observation_is_active)
|
|
@@ -188,6 +197,7 @@ def update_menu(self):
|
|
|
188
197
|
self.action_behavior_binary_table,
|
|
189
198
|
self.action_advanced_event_filtering,
|
|
190
199
|
self.action_latency,
|
|
200
|
+
self.action_cooccurence,
|
|
191
201
|
self.menuPlot_events,
|
|
192
202
|
self.menuInter_rater_reliability,
|
|
193
203
|
self.menuSimilarities,
|
|
@@ -197,7 +207,7 @@ def update_menu(self):
|
|
|
197
207
|
w.setEnabled(project_contains_obs)
|
|
198
208
|
|
|
199
209
|
# statusbar labels
|
|
200
|
-
for w in
|
|
210
|
+
for w in (self.lbTimeOffset, self.lb_obs_time_interval):
|
|
201
211
|
w.setVisible(self.playerType == cfg.MEDIA)
|
|
202
212
|
|
|
203
213
|
logging.debug("function: menu_options finished")
|