boris-behav-obs 8.16.6__py3-none-any.whl → 9.7.1__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 +24 -40
- boris/add_modifier.py +88 -80
- boris/add_modifier_ui.py +235 -131
- boris/advanced_event_filtering.py +23 -29
- 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 +228 -229
- 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 +16 -34
- boris/config.py +101 -49
- boris/config_file.py +55 -64
- boris/connections.py +105 -58
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2108 -1275
- boris/core_qrc.py +15892 -10829
- boris/core_ui.py +941 -806
- boris/db_functions.py +17 -42
- boris/dev.py +134 -0
- 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 +304 -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 +127 -36
- boris/observation.py +493 -210
- boris/observation_operations.py +1010 -391
- 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 +18 -53
- boris/plot_events.py +56 -153
- boris/plot_events_rt.py +16 -30
- boris/plot_spectrogram_rt.py +80 -56
- boris/plot_waveform_rt.py +23 -48
- boris/plugins.py +431 -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 +298 -123
- boris/preferences_ui.py +664 -225
- boris/project.py +293 -270
- boris/project_functions.py +610 -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 +6 -8
- boris/synthetic_time_budget.py +25 -17
- boris/time_budget_functions.py +169 -169
- boris/time_budget_widget.py +71 -86
- boris/transitions.py +41 -41
- boris/utilities.py +562 -222
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +78 -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.1.dist-info/METADATA +140 -0
- boris_behav_obs-9.7.1.dist-info/RECORD +109 -0
- {boris_behav_obs-8.16.6.dist-info → boris_behav_obs-9.7.1.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.1.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.6.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.16.6.dist-info/METADATA +0 -134
- boris_behav_obs-8.16.6.dist-info/RECORD +0 -106
- boris_behav_obs-8.16.6.dist-info/entry_points.txt +0 -2
- {boris → boris_behav_obs-9.7.1.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.16.6.dist-info → boris_behav_obs-9.7.1.dist-info}/top_level.txt +0 -0
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")
|