boris-behav-obs 9.6.5__tar.gz → 9.7__tar.gz
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_behav_obs-9.6.5 → boris_behav_obs-9.7}/PKG-INFO +5 -7
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/README.md +3 -5
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/cmd_arguments.py +1 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/connections.py +3 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/core.py +99 -79
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/core_ui.py +6 -2
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/event_operations.py +55 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/observation_operations.py +13 -8
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/plugins.py +5 -1
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/project_functions.py +43 -5
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/utilities.py +12 -4
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/version.py +2 -2
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris_behav_obs.egg-info/PKG-INFO +5 -7
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris_behav_obs.egg-info/requires.txt +1 -1
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/pyproject.toml +2 -2
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/LICENSE.TXT +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/MANIFEST.in +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/README.TXT +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/__init__.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/__main__.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/about.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/add_modifier.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/add_modifier_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/advanced_event_filtering.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/__init__.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/_latency.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/irr_cohen_kappa.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/irr_weighted_cohen_kappa.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/list_of_dataframe_columns.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/number_of_occurences.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/number_of_occurences_by_independent_variable.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/time_budget.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/behav_coding_map_creator.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/behavior_binary_table.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/behaviors_coding_map.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/boris_cli.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/coding_pad.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/config.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/config_file.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/converters.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/converters_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/cooccurence.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/core_qrc.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/db_functions.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/dev.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/dialog.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/duration_widget.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/edit_event.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/edit_event_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/events_cursor.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/events_snapshots.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/exclusion_matrix.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/export_events.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/export_observation.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/external_processes.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/geometric_measurement.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/gui_utilities.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/image_overlay.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/import_observations.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/irr.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/latency.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/measurement_widget.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/media_file.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/menu_options.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/modifier_coding_map_creator.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/modifiers_coding_map.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/mpv-1.0.3.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/mpv.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/mpv2.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/observation.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/observation_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/observations_list.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/otx_parser.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/param_panel.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/param_panel_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/player_dock_widget.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/plot_data_module.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/plot_events.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/plot_events_rt.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/plot_spectrogram_rt.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/plot_waveform_rt.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/portion/__init__.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/portion/const.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/portion/dict.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/portion/func.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/portion/interval.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/portion/io.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/preferences.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/preferences_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/project.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/project_import_export.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/project_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/qrc_boris.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/qrc_boris5.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/select_modifiers.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/select_observations.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/select_subj_behav.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/state_events.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/subjects_pad.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/synthetic_time_budget.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/time_budget_functions.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/time_budget_widget.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/transitions.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/video_equalizer.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/video_equalizer_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/video_operations.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/view_df.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/view_df_ui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/write_event.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris_behav_obs.egg-info/SOURCES.txt +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris_behav_obs.egg-info/dependency_links.txt +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris_behav_obs.egg-info/entry_points.txt +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris_behav_obs.egg-info/top_level.txt +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/setup.cfg +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_db_functions.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_export_observation.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_irr.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_observation_gui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_otx_parser.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_preferences_gui.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_project_functions.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_time_budget.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_utilities.py +0 -0
- {boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/tests/test_utilities2.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: boris-behav-obs
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.7
|
|
4
4
|
Summary: BORIS - Behavioral Observation Research Interactive Software
|
|
5
5
|
Author-email: Olivier Friard <olivier.friard@unito.it>
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -24,7 +24,7 @@ Requires-Dist: matplotlib==3.10.5
|
|
|
24
24
|
Requires-Dist: pandas==2.3.2
|
|
25
25
|
Requires-Dist: tablib[cli,html,ods,pandas,xls,xlsx]==3.8.0
|
|
26
26
|
Requires-Dist: pyreadr==0.5.3
|
|
27
|
-
Requires-Dist: pyside6==6.
|
|
27
|
+
Requires-Dist: pyside6==6.10
|
|
28
28
|
Requires-Dist: hachoir==3.3.0
|
|
29
29
|
Requires-Dist: scipy==1.16.1
|
|
30
30
|
Requires-Dist: scikit-learn==1.7.1
|
|
@@ -52,13 +52,15 @@ It provides also some analysis tools like time budget and some plotting function
|
|
|
52
52
|
<!-- The BO-RIS paper has more than [ citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
The BORIS paper has more than
|
|
55
|
+
The BORIS paper has more than 2337 citations in peer-reviewed scientific publications.
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
See the official [BORIS web site](https://www.boris.unito.it).
|
|
61
61
|
|
|
62
|
+
<a href="https://www.boris.unito.it" target="_blank"><img alt="Website" src="https://img.shields.io/website?url=https%3A%2F%2Fwww.boris.unito.it"></a>
|
|
63
|
+
<a href="https://www.boris.unito.it/user_guide/" target="_blank"><img alt="User guide" src="https://img.shields.io/badge/Documentation-orange"></a>
|
|
62
64
|
[](https://www.python.org)
|
|
63
65
|

|
|
64
66
|

|
|
@@ -136,7 +138,3 @@ GNU General Public License for more details.
|
|
|
136
138
|
Distributed with a [GPL v.3 license](LICENSE.TXT).
|
|
137
139
|
|
|
138
140
|
Copyright (C) 2012-2025 Olivier Friard
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
@@ -14,13 +14,15 @@ It provides also some analysis tools like time budget and some plotting function
|
|
|
14
14
|
<!-- The BO-RIS paper has more than [ citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
The BORIS paper has more than
|
|
17
|
+
The BORIS paper has more than 2337 citations in peer-reviewed scientific publications.
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
See the official [BORIS web site](https://www.boris.unito.it).
|
|
23
23
|
|
|
24
|
+
<a href="https://www.boris.unito.it" target="_blank"><img alt="Website" src="https://img.shields.io/website?url=https%3A%2F%2Fwww.boris.unito.it"></a>
|
|
25
|
+
<a href="https://www.boris.unito.it/user_guide/" target="_blank"><img alt="User guide" src="https://img.shields.io/badge/Documentation-orange"></a>
|
|
24
26
|
[](https://www.python.org)
|
|
25
27
|

|
|
26
28
|

|
|
@@ -98,7 +100,3 @@ GNU General Public License for more details.
|
|
|
98
100
|
Distributed with a [GPL v.3 license](LICENSE.TXT).
|
|
99
101
|
|
|
100
102
|
Copyright (C) 2012-2025 Olivier Friard
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
@@ -30,6 +30,7 @@ def parse_arguments():
|
|
|
30
30
|
parser = OptionParser(usage=usage)
|
|
31
31
|
|
|
32
32
|
parser.add_option("-d", "--debug", action="store_true", default=False, dest="debug", help="Use debugging mode")
|
|
33
|
+
parser.add_option("-q", "--quit", action="store_true", default=False, dest="quit", help="Quit after launch")
|
|
33
34
|
parser.add_option("-v", "--version", action="store_true", default=False, dest="version", help="Print version")
|
|
34
35
|
parser.add_option("-n", "--nosplashscreen", action="store_true", default=False, help="No splash screen")
|
|
35
36
|
parser.add_option("-p", "--project", action="store", default="", dest="project", help="Project file")
|
|
@@ -120,6 +120,7 @@ def connections(self):
|
|
|
120
120
|
self.actionSelect_observations.triggered.connect(lambda: event_operations.select_events_between_activated(self))
|
|
121
121
|
|
|
122
122
|
self.actionEdit_selected_events.triggered.connect(lambda: event_operations.edit_selected_events(self))
|
|
123
|
+
self.action_add_comment.triggered.connect(lambda: event_operations.add_comment(self))
|
|
123
124
|
self.actionEdit_event_time.triggered.connect(lambda: event_operations.edit_time_selected_events(self))
|
|
124
125
|
|
|
125
126
|
self.actionCopy_events.triggered.connect(lambda: event_operations.copy_selected_events(self))
|
|
@@ -343,6 +344,8 @@ def connections(self):
|
|
|
343
344
|
|
|
344
345
|
self.tv_events.addAction(self.actionAdd_event)
|
|
345
346
|
self.tv_events.addAction(self.actionEdit_selected_events)
|
|
347
|
+
self.tv_events.addAction(self.action_add_comment)
|
|
348
|
+
|
|
346
349
|
self.tv_events.addAction(self.actionEdit_event_time)
|
|
347
350
|
|
|
348
351
|
self.tv_events.addAction(self.actionCopy_events)
|
|
@@ -236,8 +236,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
236
236
|
processes: list = [] # list of QProcess processes
|
|
237
237
|
overlays: dict = {} # dict for storing video overlays
|
|
238
238
|
|
|
239
|
-
undo_queue = deque()
|
|
240
|
-
undo_description = deque()
|
|
239
|
+
undo_queue = deque() # queue for undoing event operations
|
|
240
|
+
undo_description = deque() # queue for description of event operations
|
|
241
241
|
|
|
242
242
|
current_player: int = 0 # id of the selected (left click) video player
|
|
243
243
|
|
|
@@ -3728,77 +3728,78 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3728
3728
|
QMessageBox.warning(self, cfg.programName, "Function not yet implemented")
|
|
3729
3729
|
return
|
|
3730
3730
|
|
|
3731
|
-
if not self.observationId:
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
if self.twEvents.selectedItems():
|
|
3736
|
-
row_s = self.twEvents.selectedItems()[0].row()
|
|
3737
|
-
row_e = self.twEvents.selectedItems()[-1].row()
|
|
3738
|
-
eventtime_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_s][0]
|
|
3739
|
-
eventtime_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_e][0]
|
|
3740
|
-
|
|
3741
|
-
durations = [] # in seconds
|
|
3742
|
-
|
|
3743
|
-
# TODO: check for 2nd player
|
|
3744
|
-
for mediaFile in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1]:
|
|
3745
|
-
durations.append(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]["length"][mediaFile])
|
|
3746
|
-
|
|
3747
|
-
mediaFileIdx_s = [idx1 for idx1, x in enumerate(durations) if eventtime_s >= sum(durations[0:idx1])][-1]
|
|
3748
|
-
media_path_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_s]
|
|
3749
|
-
|
|
3750
|
-
mediaFileIdx_e = [idx1 for idx1, x in enumerate(durations) if eventtime_e >= sum(durations[0:idx1])][-1]
|
|
3751
|
-
media_path_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_e]
|
|
3752
|
-
|
|
3753
|
-
# calculate time for current media file in case of many queued media files
|
|
3754
|
-
|
|
3755
|
-
eventtime_onmedia_s = round(eventtime_s - util.float2decimal(sum(durations[0:mediaFileIdx_s])), 3)
|
|
3756
|
-
eventtime_onmedia_e = round(eventtime_e - util.float2decimal(sum(durations[0:mediaFileIdx_e])), 3)
|
|
3757
|
-
|
|
3758
|
-
if media_path_s != media_path_e:
|
|
3759
|
-
return
|
|
3760
|
-
|
|
3761
|
-
media_path = media_path_s
|
|
3731
|
+
# if not self.observationId:
|
|
3732
|
+
# self.no_observation()
|
|
3733
|
+
# return
|
|
3762
3734
|
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3735
|
+
#
|
|
3736
|
+
# if self.twEvents.selectedItems():
|
|
3737
|
+
# row_s = self.twEvents.selectedItems()[0].row()
|
|
3738
|
+
# row_e = self.twEvents.selectedItems()[-1].row()
|
|
3739
|
+
# eventtime_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_s][0]
|
|
3740
|
+
# eventtime_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][row_e][0]
|
|
3741
|
+
#
|
|
3742
|
+
# durations = [] # in seconds
|
|
3743
|
+
#
|
|
3744
|
+
# # TODO: check for 2nd player
|
|
3745
|
+
# for mediaFile in self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1]:
|
|
3746
|
+
# durations.append(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO]["length"][mediaFile])
|
|
3747
|
+
#
|
|
3748
|
+
# mediaFileIdx_s = [idx1 for idx1, x in enumerate(durations) if eventtime_s >= sum(durations[0:idx1])][-1]
|
|
3749
|
+
# media_path_s = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_s]
|
|
3750
|
+
#
|
|
3751
|
+
# mediaFileIdx_e = [idx1 for idx1, x in enumerate(durations) if eventtime_e >= sum(durations[0:idx1])][-1]
|
|
3752
|
+
# media_path_e = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.FILE][cfg.PLAYER1][mediaFileIdx_e]
|
|
3753
|
+
#
|
|
3754
|
+
# # calculate time for current media file in case of many queued media files
|
|
3755
|
+
#
|
|
3756
|
+
# eventtime_onmedia_s = round(eventtime_s - util.float2decimal(sum(durations[0:mediaFileIdx_s])), 3)
|
|
3757
|
+
# eventtime_onmedia_e = round(eventtime_e - util.float2decimal(sum(durations[0:mediaFileIdx_e])), 3)
|
|
3758
|
+
#
|
|
3759
|
+
# if media_path_s != media_path_e:
|
|
3760
|
+
# return
|
|
3761
|
+
#
|
|
3762
|
+
# media_path = media_path_s
|
|
3763
|
+
#
|
|
3764
|
+
# # example of external command defined in environment:
|
|
3765
|
+
# # export BORISEXTERNAL="myprog -i {MEDIA_PATH} -s {START_S} -e {END_S} {DURATION_MS} --other"
|
|
3766
|
+
#
|
|
3767
|
+
# if "BORISEXTERNAL" in os.environ:
|
|
3768
|
+
# external_command_template = os.environ["BORISEXTERNAL"]
|
|
3769
|
+
# else:
|
|
3770
|
+
# return
|
|
3771
|
+
#
|
|
3772
|
+
# external_command = external_command_template.format(
|
|
3773
|
+
# OBS_ID=self.observationId,
|
|
3774
|
+
# MEDIA_PATH=f'"{media_path}"',
|
|
3775
|
+
# MEDIA_BASENAME=f'"{os.path.basename(media_path)}"',
|
|
3776
|
+
# START_S=eventtime_onmedia_s,
|
|
3777
|
+
# END_S=eventtime_onmedia_e,
|
|
3778
|
+
# START_MS=eventtime_onmedia_s * 1000,
|
|
3779
|
+
# END_MS=eventtime_onmedia_e * 1000,
|
|
3780
|
+
# DURATION_S=eventtime_onmedia_e - eventtime_onmedia_s,
|
|
3781
|
+
# DURATION_MS=(eventtime_onmedia_e - eventtime_onmedia_s) * 1000,
|
|
3782
|
+
# )
|
|
3783
|
+
#
|
|
3784
|
+
# print(external_command)
|
|
3785
|
+
# """
|
|
3786
|
+
# p = subprocess.Popen(external_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
|
3787
|
+
# """
|
|
3788
|
+
# """
|
|
3789
|
+
# if eventtimeS == eventtimeE:
|
|
3790
|
+
# q = []
|
|
3791
|
+
# else:
|
|
3792
|
+
# durationsec = eventtimeE-eventtimeS
|
|
3793
|
+
# q = ["--durationmsec",str(int(durationsec*1000))]
|
|
3794
|
+
# args = [ex, "-f",os.path.abspath(fn),"--seekmsec",str(int(eventtimeS*1000)),*q,*("--size 1 --track 1 --redetect 100")
|
|
3795
|
+
# .split(" ")]
|
|
3796
|
+
# if os.path.split(fn)[1].split("_")[0] in set(["A1","A2","A3","A4","A5","A6","A7","A8","A9","A10"]):
|
|
3797
|
+
# args.append("--flip")
|
|
3798
|
+
# args.append("2")
|
|
3799
|
+
# print (os.path.split(fn)[1].split("_")[0])
|
|
3800
|
+
# print ("running",ex,"with",args,"in",os.path.split(ex)[0])
|
|
3801
|
+
# #pid = subprocess.Popen(args,executable=ex,cwd=os.path.split(ex)[0])
|
|
3802
|
+
# """
|
|
3802
3803
|
|
|
3803
3804
|
def no_media(self):
|
|
3804
3805
|
QMessageBox.warning(self, cfg.programName, "There is no media available")
|
|
@@ -5666,16 +5667,31 @@ def main():
|
|
|
5666
5667
|
ret, msg = util.check_ffmpeg_path()
|
|
5667
5668
|
if not ret:
|
|
5668
5669
|
if sys.platform.startswith("win"):
|
|
5669
|
-
|
|
5670
|
+
import ctypes
|
|
5671
|
+
|
|
5672
|
+
MessageBoxTimeoutW = ctypes.windll.user32.MessageBoxTimeoutW
|
|
5673
|
+
MessageBoxTimeoutW.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint]
|
|
5674
|
+
ctypes.windll.user32.MessageBoxTimeoutW(
|
|
5670
5675
|
None,
|
|
5671
|
-
|
|
5672
|
-
"FFmpeg
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
+
"The FFmpeg framework is not available.\nIt will be downloaded from the BORIS GitHub repository.",
|
|
5677
|
+
"FFmpeg",
|
|
5678
|
+
0,
|
|
5679
|
+
0,
|
|
5680
|
+
10000,
|
|
5681
|
+
) # time out
|
|
5682
|
+
|
|
5683
|
+
# if (not options.nosplashscreen):
|
|
5684
|
+
# QMessageBox.warning(
|
|
5685
|
+
# None,
|
|
5686
|
+
# cfg.programName,
|
|
5687
|
+
# "FFmpeg is not available.<br>It will be downloaded from the BORIS GitHub repository",
|
|
5688
|
+
# QMessageBox.Ok | QMessageBox.Default,
|
|
5689
|
+
# QMessageBox.NoButton,
|
|
5690
|
+
# )
|
|
5691
|
+
logging.info("FFmpeg is not available. It will be downloaded from the BORIS GitHub repository")
|
|
5676
5692
|
|
|
5677
5693
|
# download ffmpeg and ffprobe from https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/
|
|
5678
|
-
url = "https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/"
|
|
5694
|
+
url: str = "https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/"
|
|
5679
5695
|
|
|
5680
5696
|
# search where to download ffmpeg
|
|
5681
5697
|
ffmpeg_dir = Path(__file__).parent / "misc"
|
|
@@ -5807,6 +5823,10 @@ def main():
|
|
|
5807
5823
|
if not options.nosplashscreen and (sys.platform != "darwin"):
|
|
5808
5824
|
splash.finish(window)
|
|
5809
5825
|
|
|
5826
|
+
# quit just after launch (used in the deployment procedure)
|
|
5827
|
+
if options.quit:
|
|
5828
|
+
sys.exit()
|
|
5829
|
+
|
|
5810
5830
|
return_code = app.exec()
|
|
5811
5831
|
|
|
5812
5832
|
del window
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
################################################################################
|
|
4
4
|
## Form generated from reading UI file 'core.ui'
|
|
5
5
|
##
|
|
6
|
-
## Created by: Qt User Interface Compiler version 6.
|
|
6
|
+
## Created by: Qt User Interface Compiler version 6.10.0
|
|
7
7
|
##
|
|
8
8
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
9
9
|
################################################################################
|
|
@@ -382,6 +382,9 @@ class Ui_MainWindow(object):
|
|
|
382
382
|
self.actionCreate_video_spectrogram.setObjectName(u"actionCreate_video_spectrogram")
|
|
383
383
|
self.action_change_time_offset_of_players = QAction(MainWindow)
|
|
384
384
|
self.action_change_time_offset_of_players.setObjectName(u"action_change_time_offset_of_players")
|
|
385
|
+
self.action_add_comment = QAction(MainWindow)
|
|
386
|
+
self.action_add_comment.setObjectName(u"action_add_comment")
|
|
387
|
+
self.action_add_comment.setMenuRole(QAction.MenuRole.NoRole)
|
|
385
388
|
self.centralwidget = QWidget(MainWindow)
|
|
386
389
|
self.centralwidget.setObjectName(u"centralwidget")
|
|
387
390
|
self.horizontalLayout_2 = QHBoxLayout(self.centralwidget)
|
|
@@ -488,7 +491,7 @@ class Ui_MainWindow(object):
|
|
|
488
491
|
MainWindow.setCentralWidget(self.centralwidget)
|
|
489
492
|
self.menubar = QMenuBar(MainWindow)
|
|
490
493
|
self.menubar.setObjectName(u"menubar")
|
|
491
|
-
self.menubar.setGeometry(QRect(0, 0, 1509,
|
|
494
|
+
self.menubar.setGeometry(QRect(0, 0, 1509, 20))
|
|
492
495
|
self.menuHelp = QMenu(self.menubar)
|
|
493
496
|
self.menuHelp.setObjectName(u"menuHelp")
|
|
494
497
|
self.menuFile = QMenu(self.menubar)
|
|
@@ -1037,6 +1040,7 @@ class Ui_MainWindow(object):
|
|
|
1037
1040
|
self.action_load_plugins.setText(QCoreApplication.translate("MainWindow", u"Load plugins", None))
|
|
1038
1041
|
self.actionCreate_video_spectrogram.setText(QCoreApplication.translate("MainWindow", u"Create video spectrogram", None))
|
|
1039
1042
|
self.action_change_time_offset_of_players.setText(QCoreApplication.translate("MainWindow", u"Change time offset of players", None))
|
|
1043
|
+
self.action_add_comment.setText(QCoreApplication.translate("MainWindow", u"Add/Edit comment", None))
|
|
1040
1044
|
self.lbLogoBoris.setText("")
|
|
1041
1045
|
self.lbLogoUnito.setText("")
|
|
1042
1046
|
self.lb_player_status.setText(QCoreApplication.translate("MainWindow", u"lb_player_status", None))
|
|
@@ -454,6 +454,61 @@ def select_events_between_activated(self):
|
|
|
454
454
|
self.tv_events.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
|
455
455
|
|
|
456
456
|
|
|
457
|
+
def add_comment(self):
|
|
458
|
+
"""
|
|
459
|
+
add a comment to the selected events
|
|
460
|
+
operation can be undone with Undo
|
|
461
|
+
"""
|
|
462
|
+
tvevents_rows_to_edit = set([index.row() for index in self.tv_events.selectionModel().selectedIndexes()])
|
|
463
|
+
if not len(tvevents_rows_to_edit):
|
|
464
|
+
QMessageBox.warning(self, cfg.programName, "No event selected!")
|
|
465
|
+
return
|
|
466
|
+
|
|
467
|
+
comment_str: str = ""
|
|
468
|
+
if len(tvevents_rows_to_edit) == 1:
|
|
469
|
+
pj_event_idx = self.tv_idx2events_idx[self.tv_events.selectionModel().selectedIndexes()[0].row()]
|
|
470
|
+
comment_str = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][pj_event_idx][
|
|
471
|
+
cfg.PJ_OBS_FIELDS[self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE]][cfg.COMMENT]
|
|
472
|
+
]
|
|
473
|
+
else:
|
|
474
|
+
# check if comment is the same in all selected events
|
|
475
|
+
|
|
476
|
+
if (
|
|
477
|
+
len(
|
|
478
|
+
set(
|
|
479
|
+
[
|
|
480
|
+
self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][self.tv_idx2events_idx[tvevents_row]][
|
|
481
|
+
cfg.PJ_OBS_FIELDS[self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE]][cfg.COMMENT]
|
|
482
|
+
]
|
|
483
|
+
for tvevents_row in tvevents_rows_to_edit
|
|
484
|
+
]
|
|
485
|
+
)
|
|
486
|
+
)
|
|
487
|
+
== 1
|
|
488
|
+
):
|
|
489
|
+
pj_event_idx = self.tv_idx2events_idx[self.tv_events.selectionModel().selectedIndexes()[0].row()]
|
|
490
|
+
comment_str = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][pj_event_idx][
|
|
491
|
+
cfg.PJ_OBS_FIELDS[self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE]][cfg.COMMENT]
|
|
492
|
+
]
|
|
493
|
+
|
|
494
|
+
new_comment, ok = QInputDialog.getText(self, "Add/Edit a comment", "Comment:", text=comment_str)
|
|
495
|
+
if not ok:
|
|
496
|
+
return
|
|
497
|
+
|
|
498
|
+
# fill the undo list
|
|
499
|
+
fill_events_undo_list(self, "Undo last comment operation")
|
|
500
|
+
|
|
501
|
+
for tvevents_row in tvevents_rows_to_edit:
|
|
502
|
+
pj_event_idx = self.tv_idx2events_idx[tvevents_row]
|
|
503
|
+
|
|
504
|
+
self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][pj_event_idx][
|
|
505
|
+
cfg.PJ_OBS_FIELDS[self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE]][cfg.COMMENT]
|
|
506
|
+
] = new_comment
|
|
507
|
+
|
|
508
|
+
# reload all events in tw
|
|
509
|
+
self.load_tw_events(self.observationId)
|
|
510
|
+
|
|
511
|
+
|
|
457
512
|
def edit_selected_events(self):
|
|
458
513
|
"""
|
|
459
514
|
edit one or more selected events for subject, behavior and/or comment
|
|
@@ -19,18 +19,19 @@ Copyright 2012-2025 Olivier Friard
|
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
from math import log2, floor
|
|
23
|
-
import os
|
|
24
22
|
import logging
|
|
25
|
-
import
|
|
26
|
-
import
|
|
23
|
+
from collections import deque
|
|
24
|
+
import datetime as dt
|
|
25
|
+
from decimal import Decimal as dec
|
|
27
26
|
import json
|
|
28
|
-
import
|
|
27
|
+
from math import log2, floor
|
|
28
|
+
import os
|
|
29
|
+
import pathlib as pl
|
|
29
30
|
import socket
|
|
31
|
+
import subprocess
|
|
30
32
|
import sys
|
|
31
|
-
|
|
32
|
-
import
|
|
33
|
-
import datetime as dt
|
|
33
|
+
import tempfile
|
|
34
|
+
import time
|
|
34
35
|
from typing import List, Tuple, Optional
|
|
35
36
|
|
|
36
37
|
|
|
@@ -1183,6 +1184,10 @@ def close_observation(self):
|
|
|
1183
1184
|
|
|
1184
1185
|
self.observationId = ""
|
|
1185
1186
|
|
|
1187
|
+
# delete undo queue
|
|
1188
|
+
self.undo_queue = deque()
|
|
1189
|
+
self.undo_description = deque()
|
|
1190
|
+
|
|
1186
1191
|
if self.playerType in (cfg.MEDIA, cfg.IMAGES):
|
|
1187
1192
|
"""
|
|
1188
1193
|
for idx, _ in enumerate(self.dw_player):
|
|
@@ -310,7 +310,11 @@ def run_plugin(self, plugin_name):
|
|
|
310
310
|
|
|
311
311
|
logging.info("preparing dataframe for plugin")
|
|
312
312
|
|
|
313
|
-
df = project_functions.project2dataframe(self.pj, selected_observations)
|
|
313
|
+
message, df = project_functions.project2dataframe(self.pj, selected_observations)
|
|
314
|
+
if message:
|
|
315
|
+
logging.critical(message)
|
|
316
|
+
QMessageBox.critical(self, cfg.programName, message)
|
|
317
|
+
return
|
|
314
318
|
|
|
315
319
|
logging.info("done")
|
|
316
320
|
|
|
@@ -466,7 +466,7 @@ def check_project_integrity(
|
|
|
466
466
|
out += "<br><br>" if out else ""
|
|
467
467
|
out += f"Observation: <b>{obs_id}</b><br>{msg}"
|
|
468
468
|
|
|
469
|
-
out_events = ""
|
|
469
|
+
out_events: str = ""
|
|
470
470
|
for obs_id in pj[cfg.OBSERVATIONS]:
|
|
471
471
|
# check if timestamp between -2147483647 and 2147483647
|
|
472
472
|
for event in pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]:
|
|
@@ -573,6 +573,41 @@ def check_project_integrity(
|
|
|
573
573
|
out += "<br><br>" if out else ""
|
|
574
574
|
out += tmp_out
|
|
575
575
|
|
|
576
|
+
# check if the number of coded modifiers correspond to the number of sets of modifier
|
|
577
|
+
obs_results: dict = {}
|
|
578
|
+
for obs_id in pj[cfg.OBSERVATIONS]:
|
|
579
|
+
for event_idx, event in enumerate(pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]):
|
|
580
|
+
# event[2]
|
|
581
|
+
for idx in pj[cfg.ETHOGRAM]:
|
|
582
|
+
if pj[cfg.ETHOGRAM][idx]["code"] == event[2]:
|
|
583
|
+
break
|
|
584
|
+
else:
|
|
585
|
+
raise
|
|
586
|
+
if (not event[3]) and not pj[cfg.ETHOGRAM][idx][cfg.MODIFIERS]:
|
|
587
|
+
continue
|
|
588
|
+
|
|
589
|
+
if len(event[3].split("|")) != len(pj[cfg.ETHOGRAM][idx][cfg.MODIFIERS]):
|
|
590
|
+
print("behavior", event[2])
|
|
591
|
+
print(f"modifier(s) #{event[3]}#", len(event[3].split("|")))
|
|
592
|
+
print(pj[cfg.ETHOGRAM][idx]["code"], pj[cfg.ETHOGRAM][idx][cfg.MODIFIERS])
|
|
593
|
+
print()
|
|
594
|
+
if obs_id not in obs_results:
|
|
595
|
+
obs_results[obs_id] = []
|
|
596
|
+
|
|
597
|
+
obs_results[obs_id].append(
|
|
598
|
+
(
|
|
599
|
+
f"Event #{event_idx}: the coded modifiers for {event[2]} are {len(event[3].split('|'))} "
|
|
600
|
+
f"but {len(pj[cfg.ETHOGRAM][idx][cfg.MODIFIERS])} sets were defined in ethogram."
|
|
601
|
+
)
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
if obs_results:
|
|
605
|
+
out += "<br><br>" if out else ""
|
|
606
|
+
for o in obs_results:
|
|
607
|
+
out += f"<br>Observation <b>{o}</b>:<br>"
|
|
608
|
+
out += "<br>".join(obs_results[o])
|
|
609
|
+
out += "<br><br>"
|
|
610
|
+
|
|
576
611
|
return out
|
|
577
612
|
|
|
578
613
|
|
|
@@ -1779,7 +1814,7 @@ def explore_project(self) -> None:
|
|
|
1779
1814
|
QMessageBox.information(self, cfg.programName, "No events found")
|
|
1780
1815
|
|
|
1781
1816
|
|
|
1782
|
-
def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
1817
|
+
def project2dataframe(pj: dict, observations_list: list = []) -> Tuple[str, pd.DataFrame]:
|
|
1783
1818
|
"""
|
|
1784
1819
|
returns a pandas dataframe containing observations data
|
|
1785
1820
|
"""
|
|
@@ -1950,7 +1985,10 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1950
1985
|
count_set = 0
|
|
1951
1986
|
for modifier_set in all_modifier_sets:
|
|
1952
1987
|
if event[2] == modifier_set[0]:
|
|
1953
|
-
|
|
1988
|
+
try:
|
|
1989
|
+
data[modifier_set].append(event[3].split("|")[count_set])
|
|
1990
|
+
except Exception:
|
|
1991
|
+
return f"Modifier error for {event[2]} in observation {obs_id}", pd.DataFrame()
|
|
1954
1992
|
count_set += 1
|
|
1955
1993
|
else:
|
|
1956
1994
|
data[modifier_set].append(np.nan)
|
|
@@ -1971,7 +2009,7 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1971
2009
|
data["Comment stop"].append(event2[4])
|
|
1972
2010
|
break
|
|
1973
2011
|
else:
|
|
1974
|
-
|
|
2012
|
+
return f"Some events are not paired in {obs_id}", pd.DataFrame()
|
|
1975
2013
|
|
|
1976
2014
|
else: # point
|
|
1977
2015
|
data["Stop (s)"].append(float(event[0]))
|
|
@@ -1985,4 +2023,4 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1985
2023
|
|
|
1986
2024
|
pd.DataFrame(data).info()
|
|
1987
2025
|
|
|
1988
|
-
return pd.DataFrame(data)
|
|
2026
|
+
return "", pd.DataFrame(data)
|
|
@@ -62,11 +62,19 @@ except Exception:
|
|
|
62
62
|
if sys.platform.startswith("win"):
|
|
63
63
|
import ctypes
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
logger.info("The MPV library was not found!\nIt will be downloaded from the BORIS GitHub repository")
|
|
66
|
+
# ctypes.windll.user32.MessageBoxW(0, "The MPV library was not found!\nIt will be downloaded.", "BORIS", 0)
|
|
66
67
|
|
|
67
|
-
#
|
|
68
|
+
# test if following function works on windows
|
|
69
|
+
MessageBoxTimeoutW = ctypes.windll.user32.MessageBoxTimeoutW
|
|
70
|
+
MessageBoxTimeoutW.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint]
|
|
71
|
+
ctypes.windll.user32.MessageBoxTimeoutW(
|
|
72
|
+
None, "The MPV library was not found.\nIt will be downloaded from the BORIS GitHub repository.", "MPV library", 0, 0, 10000
|
|
73
|
+
) # time out
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
# download libmpv2.dll from https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/
|
|
76
|
+
|
|
77
|
+
url: str = "https://github.com/boris-behav-obs/boris-behav-obs.github.io/releases/download/files/"
|
|
70
78
|
|
|
71
79
|
external_files_dir = ""
|
|
72
80
|
# search where to download libmpv-2.dll
|
|
@@ -91,7 +99,7 @@ except Exception:
|
|
|
91
99
|
try:
|
|
92
100
|
from . import mpv2 as mpv
|
|
93
101
|
except Exception:
|
|
94
|
-
logger.
|
|
102
|
+
logger.critical("MPV library not found after dowloading")
|
|
95
103
|
sys.exit(5)
|
|
96
104
|
|
|
97
105
|
elif sys.platform.startswith("linux"):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: boris-behav-obs
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.7
|
|
4
4
|
Summary: BORIS - Behavioral Observation Research Interactive Software
|
|
5
5
|
Author-email: Olivier Friard <olivier.friard@unito.it>
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -24,7 +24,7 @@ Requires-Dist: matplotlib==3.10.5
|
|
|
24
24
|
Requires-Dist: pandas==2.3.2
|
|
25
25
|
Requires-Dist: tablib[cli,html,ods,pandas,xls,xlsx]==3.8.0
|
|
26
26
|
Requires-Dist: pyreadr==0.5.3
|
|
27
|
-
Requires-Dist: pyside6==6.
|
|
27
|
+
Requires-Dist: pyside6==6.10
|
|
28
28
|
Requires-Dist: hachoir==3.3.0
|
|
29
29
|
Requires-Dist: scipy==1.16.1
|
|
30
30
|
Requires-Dist: scikit-learn==1.7.1
|
|
@@ -52,13 +52,15 @@ It provides also some analysis tools like time budget and some plotting function
|
|
|
52
52
|
<!-- The BO-RIS paper has more than [ citations](https://www.boris.unito.it/citations) in peer-reviewed scientific publications. -->
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
The BORIS paper has more than
|
|
55
|
+
The BORIS paper has more than 2337 citations in peer-reviewed scientific publications.
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
See the official [BORIS web site](https://www.boris.unito.it).
|
|
61
61
|
|
|
62
|
+
<a href="https://www.boris.unito.it" target="_blank"><img alt="Website" src="https://img.shields.io/website?url=https%3A%2F%2Fwww.boris.unito.it"></a>
|
|
63
|
+
<a href="https://www.boris.unito.it/user_guide/" target="_blank"><img alt="User guide" src="https://img.shields.io/badge/Documentation-orange"></a>
|
|
62
64
|
[](https://www.python.org)
|
|
63
65
|

|
|
64
66
|

|
|
@@ -136,7 +138,3 @@ GNU General Public License for more details.
|
|
|
136
138
|
Distributed with a [GPL v.3 license](LICENSE.TXT).
|
|
137
139
|
|
|
138
140
|
Copyright (C) 2012-2025 Olivier Friard
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "boris-behav-obs"
|
|
3
|
-
version = "9.
|
|
3
|
+
version = "9.7"
|
|
4
4
|
description = "BORIS - Behavioral Observation Research Interactive Software"
|
|
5
5
|
authors = [{ name="Olivier Friard", email="olivier.friard@unito.it" }]
|
|
6
6
|
readme = "README.md"
|
|
@@ -21,7 +21,7 @@ dependencies = [
|
|
|
21
21
|
"pandas==2.3.2",
|
|
22
22
|
"tablib[cli,html,ods,pandas,xls,xlsx]==3.8.0",
|
|
23
23
|
"pyreadr==0.5.3",
|
|
24
|
-
"pyside6==6.
|
|
24
|
+
"pyside6==6.10",
|
|
25
25
|
"hachoir==3.3.0",
|
|
26
26
|
"scipy==1.16.1",
|
|
27
27
|
"scikit-learn==1.7.1",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/irr_weighted_cohen_kappa.py
RENAMED
|
File without changes
|
|
File without changes
|
{boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/list_of_dataframe_columns.py
RENAMED
|
File without changes
|
{boris_behav_obs-9.6.5 → boris_behav_obs-9.7}/boris/analysis_plugins/number_of_occurences.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|