boris-behav-obs 8.27.9__tar.gz → 9.0.1__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-8.27.9/boris_behav_obs.egg-info → boris_behav_obs-9.0.1}/PKG-INFO +4 -3
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/about.py +7 -5
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/add_modifier.py +35 -35
- boris_behav_obs-9.0.1/boris/add_modifier_ui.py +285 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/advanced_event_filtering.py +3 -3
- boris_behav_obs-9.0.1/boris/analysis_plugins/__init__.py +0 -0
- boris_behav_obs-9.0.1/boris/analysis_plugins/number_of_occurences.py +60 -0
- boris_behav_obs-9.0.1/boris/analysis_plugins/number_of_occurences_by_independent_variable.py +72 -0
- boris_behav_obs-9.0.1/boris/analysis_plugins/time_budget.py +95 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/behav_coding_map_creator.py +103 -108
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/behavior_binary_table.py +1 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/behaviors_coding_map.py +8 -8
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/coding_pad.py +6 -6
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/config.py +6 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/config_file.py +1 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/connections.py +4 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/converters.py +2 -3
- boris_behav_obs-9.0.1/boris/converters_ui.py +225 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/cooccurence.py +2 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/core.py +340 -94
- boris_behav_obs-9.0.1/boris/core_qrc.py +16159 -0
- boris_behav_obs-9.0.1/boris/core_ui.py +1095 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/db_functions.py +3 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/dialog.py +14 -13
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/duration_widget.py +5 -5
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/edit_event.py +1 -1
- boris_behav_obs-9.0.1/boris/edit_event_ui.py +200 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/event_operations.py +4 -25
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/events_cursor.py +17 -9
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/events_snapshots.py +5 -5
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/exclusion_matrix.py +1 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/export_events.py +38 -28
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/export_observation.py +1 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/external_processes.py +3 -5
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/geometric_measurement.py +49 -26
- boris_behav_obs-9.0.1/boris/gui_utilities.py +102 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/import_observations.py +2 -4
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/irr.py +1 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/latency.py +1 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/map_creator.py +77 -89
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/measurement_widget.py +4 -4
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/media_file.py +2 -4
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/menu_options.py +1 -3
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/modifiers_coding_map.py +4 -4
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/mpv2.py +0 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/observation.py +124 -29
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/observation_operations.py +18 -40
- boris_behav_obs-9.0.1/boris/observation_ui.py +679 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/observations_list.py +6 -6
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/param_panel.py +2 -2
- boris_behav_obs-9.0.1/boris/param_panel_ui.py +299 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/player_dock_widget.py +16 -21
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/plot_data_module.py +6 -6
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/plot_events_rt.py +7 -8
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/plot_spectrogram_rt.py +7 -8
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/plot_waveform_rt.py +6 -7
- boris_behav_obs-9.0.1/boris/plugins.py +79 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/preferences.py +127 -17
- boris_behav_obs-9.0.1/boris/preferences_ui.py +562 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/project.py +69 -72
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/project_functions.py +233 -31
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/project_import_export.py +59 -67
- boris_behav_obs-9.0.1/boris/project_ui.py +794 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/qrc_boris.py +6 -3
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/qrc_boris5.py +6 -3
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/select_modifiers.py +2 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/select_observations.py +2 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/select_subj_behav.py +3 -3
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/state_events.py +1 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/subjects_pad.py +5 -5
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/synthetic_time_budget.py +2 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/time_budget_functions.py +15 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/time_budget_widget.py +4 -4
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/transitions.py +34 -25
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/utilities.py +95 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/version.py +2 -2
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/video_equalizer.py +4 -4
- boris_behav_obs-9.0.1/boris/video_equalizer_ui.py +248 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/video_operations.py +1 -1
- boris_behav_obs-9.0.1/boris/view_df.py +106 -0
- boris_behav_obs-9.0.1/boris/view_df_ui.py +75 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/write_event.py +9 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1/boris_behav_obs.egg-info}/PKG-INFO +4 -3
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris_behav_obs.egg-info/SOURCES.txt +7 -18
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris_behav_obs.egg-info/requires.txt +2 -1
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/pyproject.toml +4 -3
- boris_behav_obs-8.27.9/boris/add_modifier_ui.py +0 -185
- boris_behav_obs-8.27.9/boris/converters_ui.py +0 -148
- boris_behav_obs-8.27.9/boris/core_qrc.py +0 -13317
- boris_behav_obs-8.27.9/boris/core_ui.py +0 -985
- boris_behav_obs-8.27.9/boris/edit_event_ui.py +0 -126
- boris_behav_obs-8.27.9/boris/gui_utilities.py +0 -101
- boris_behav_obs-8.27.9/boris/observation_ui.py +0 -487
- boris_behav_obs-8.27.9/boris/param_panel_ui.py +0 -194
- boris_behav_obs-8.27.9/boris/preferences_ui.py +0 -338
- boris_behav_obs-8.27.9/boris/project_ui.py +0 -562
- boris_behav_obs-8.27.9/boris/qdarkstyle/__init__.py +0 -479
- boris_behav_obs-8.27.9/boris/qdarkstyle/__main__.py +0 -66
- boris_behav_obs-8.27.9/boris/qdarkstyle/colorsystem.py +0 -38
- boris_behav_obs-8.27.9/boris/qdarkstyle/dark/__init__.py +0 -1
- boris_behav_obs-8.27.9/boris/qdarkstyle/dark/darkstyle_rc.py +0 -11379
- boris_behav_obs-8.27.9/boris/qdarkstyle/dark/palette.py +0 -38
- boris_behav_obs-8.27.9/boris/qdarkstyle/example/__init__.py +0 -4
- boris_behav_obs-8.27.9/boris/qdarkstyle/example/__main__.py +0 -386
- boris_behav_obs-8.27.9/boris/qdarkstyle/example/ui/__init__.py +0 -4
- boris_behav_obs-8.27.9/boris/qdarkstyle/light/__init__.py +0 -1
- boris_behav_obs-8.27.9/boris/qdarkstyle/light/lightstyle_rc.py +0 -11305
- boris_behav_obs-8.27.9/boris/qdarkstyle/light/palette.py +0 -37
- boris_behav_obs-8.27.9/boris/qdarkstyle/palette.py +0 -102
- boris_behav_obs-8.27.9/boris/qdarkstyle/utils/__init__.py +0 -73
- boris_behav_obs-8.27.9/boris/qdarkstyle/utils/__main__.py +0 -96
- boris_behav_obs-8.27.9/boris/qdarkstyle/utils/images.py +0 -449
- boris_behav_obs-8.27.9/boris/qdarkstyle/utils/scss.py +0 -318
- boris_behav_obs-8.27.9/boris/video_equalizer_ui.py +0 -179
- boris_behav_obs-8.27.9/boris/vlc_local.py +0 -83
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/MANIFEST.in +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/README.TXT +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/README.md +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/__init__.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/__main__.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/boris_cli.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/cmd_arguments.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/dev.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/image_overlay.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/mpv-1.0.3.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/mpv.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/otx_parser.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/plot_events.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/portion/__init__.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/portion/const.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/portion/dict.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/portion/func.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/portion/interval.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris/portion/io.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris_behav_obs.egg-info/dependency_links.txt +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris_behav_obs.egg-info/entry_points.txt +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/boris_behav_obs.egg-info/top_level.txt +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/setup.cfg +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_db_functions.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_export_observation.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_irr.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_observation_gui.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_otx_parser.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_preferences_gui.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_project_functions.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_time_budget.py +0 -0
- {boris_behav_obs-8.27.9 → boris_behav_obs-9.0.1}/tests/test_utilities.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: boris-behav-obs
|
|
3
|
-
Version:
|
|
3
|
+
Version: 9.0.1
|
|
4
4
|
Summary: BORIS - Behavioral Observation Research Interactive Software
|
|
5
5
|
Author-email: Olivier Friard <olivier.friard@unito.it>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -701,8 +701,9 @@ Requires-Dist: numpy>=1.26.4
|
|
|
701
701
|
Requires-Dist: matplotlib>=3.3.3
|
|
702
702
|
Requires-Dist: pandas>=2.2.2
|
|
703
703
|
Requires-Dist: tablib[cli,html,ods,pandas,xls,xlsx]>=3
|
|
704
|
-
Requires-Dist: pyqt5>=5.15
|
|
705
704
|
Requires-Dist: pyreadr
|
|
705
|
+
Requires-Dist: pyside6==6.8.0.2
|
|
706
|
+
Requires-Dist: hachoir>=3.3.0
|
|
706
707
|
Provides-Extra: dev
|
|
707
708
|
Requires-Dist: black; extra == "dev"
|
|
708
709
|
Requires-Dist: ruff; extra == "dev"
|
|
@@ -31,9 +31,9 @@ from . import config as cfg
|
|
|
31
31
|
from . import utilities as util
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
from
|
|
35
|
-
from
|
|
36
|
-
from
|
|
34
|
+
from PySide6.QtCore import qVersion
|
|
35
|
+
from PySide6.QtGui import QPixmap
|
|
36
|
+
from PySide6.QtWidgets import QMessageBox
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def actionAbout_activated(self):
|
|
@@ -41,6 +41,8 @@ def actionAbout_activated(self):
|
|
|
41
41
|
About dialog
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
+
import PySide6
|
|
45
|
+
|
|
44
46
|
programs_versions: list = ["MPV media player"]
|
|
45
47
|
|
|
46
48
|
mpv_lib_version, mpv_lib_file_path, mpv_api_version = util.mpv_lib_version()
|
|
@@ -112,7 +114,7 @@ def actionAbout_activated(self):
|
|
|
112
114
|
f"Operating system: {current_system.system} {current_system.release} {current_system.version} \n"
|
|
113
115
|
f"CPU: {current_system.machine} {current_system.processor}\n\n"
|
|
114
116
|
f"Python {platform.python_version()} ({'64-bit' if sys.maxsize > 2**32 else '32-bit'})"
|
|
115
|
-
f"
|
|
117
|
+
f"Qt {qVersion()} - PySide {PySide6.__version__}\n"
|
|
116
118
|
)
|
|
117
119
|
|
|
118
120
|
r, memory = util.mem_info()
|
|
@@ -137,4 +139,4 @@ def actionAbout_activated(self):
|
|
|
137
139
|
|
|
138
140
|
about_dialog.setDetailedText(details)
|
|
139
141
|
|
|
140
|
-
_ = about_dialog.
|
|
142
|
+
_ = about_dialog.exec()
|
|
@@ -16,15 +16,15 @@ This file is part of BORIS.
|
|
|
16
16
|
GNU General Public License for more details.
|
|
17
17
|
|
|
18
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/
|
|
19
|
+
along with this program; if not see <http://www.gnu.org/licPbehav_enses/>.
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
import logging
|
|
24
24
|
import json
|
|
25
25
|
|
|
26
|
-
from
|
|
27
|
-
from
|
|
26
|
+
from PySide6.QtGui import QIcon
|
|
27
|
+
from PySide6.QtWidgets import QDialog, QWidget, QFileDialog, QMessageBox
|
|
28
28
|
|
|
29
29
|
from . import dialog
|
|
30
30
|
from .add_modifier_ui import Ui_Dialog
|
|
@@ -158,38 +158,38 @@ class addModifierDialog(QDialog, Ui_Dialog):
|
|
|
158
158
|
add modifiers from file
|
|
159
159
|
"""
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
161
|
+
file_name, _ = QFileDialog.getOpenFileName(self, "Load modifiers from file", "", "All files (*)")
|
|
162
|
+
if not file_name:
|
|
163
|
+
return
|
|
164
|
+
try:
|
|
165
|
+
with open(file_name) as f_in:
|
|
166
|
+
for line in f_in:
|
|
167
|
+
if line.strip():
|
|
168
|
+
for c in cfg.CHAR_FORBIDDEN_IN_MODIFIERS:
|
|
169
|
+
if c in line.strip():
|
|
170
|
+
QMessageBox.critical(
|
|
171
|
+
self,
|
|
172
|
+
cfg.programName,
|
|
173
|
+
(
|
|
174
|
+
f"The character <b>{c}</b> is not allowed.<br>"
|
|
175
|
+
"The following characters are not allowed in modifiers:<br>"
|
|
176
|
+
f"<b>{cfg.CHAR_FORBIDDEN_IN_MODIFIERS}</b>"
|
|
177
|
+
),
|
|
178
|
+
)
|
|
179
|
+
break
|
|
180
|
+
else:
|
|
181
|
+
if line.strip() not in [self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())]:
|
|
182
|
+
if self.itemPositionMem != -1:
|
|
183
|
+
self.lwModifiers.insertItem(self.itemPositionMem, line.strip())
|
|
184
|
+
else:
|
|
185
|
+
self.lwModifiers.addItem(line.strip())
|
|
186
|
+
|
|
187
|
+
self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())]["values"] = [
|
|
188
|
+
self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())
|
|
189
|
+
]
|
|
190
|
+
except Exception:
|
|
191
|
+
QMessageBox.warning(self, cfg.programName, f"Error reading modifiers from file:<br>{file_name}")
|
|
192
|
+
logging.warning(f"Error reading modifiers from file<br>{file_name}")
|
|
193
193
|
|
|
194
194
|
def sort_modifiers(self):
|
|
195
195
|
"""
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
################################################################################
|
|
4
|
+
## Form generated from reading UI file 'add_modifier.ui'
|
|
5
|
+
##
|
|
6
|
+
## Created by: Qt User Interface Compiler version 6.8.0
|
|
7
|
+
##
|
|
8
|
+
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
9
|
+
################################################################################
|
|
10
|
+
|
|
11
|
+
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
|
12
|
+
QMetaObject, QObject, QPoint, QRect,
|
|
13
|
+
QSize, QTime, QUrl, Qt)
|
|
14
|
+
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
|
15
|
+
QFont, QFontDatabase, QGradient, QIcon,
|
|
16
|
+
QImage, QKeySequence, QLinearGradient, QPainter,
|
|
17
|
+
QPalette, QPixmap, QRadialGradient, QTransform)
|
|
18
|
+
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QDialog,
|
|
19
|
+
QHBoxLayout, QLabel, QLineEdit, QListWidget,
|
|
20
|
+
QListWidgetItem, QPushButton, QSizePolicy, QSpacerItem,
|
|
21
|
+
QTabWidget, QVBoxLayout, QWidget)
|
|
22
|
+
|
|
23
|
+
class Ui_Dialog(object):
|
|
24
|
+
def setupUi(self, Dialog):
|
|
25
|
+
if not Dialog.objectName():
|
|
26
|
+
Dialog.setObjectName(u"Dialog")
|
|
27
|
+
Dialog.resize(1088, 654)
|
|
28
|
+
self.verticalLayout_5 = QVBoxLayout(Dialog)
|
|
29
|
+
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
|
|
30
|
+
self.cb_ask_at_stop = QCheckBox(Dialog)
|
|
31
|
+
self.cb_ask_at_stop.setObjectName(u"cb_ask_at_stop")
|
|
32
|
+
|
|
33
|
+
self.verticalLayout_5.addWidget(self.cb_ask_at_stop)
|
|
34
|
+
|
|
35
|
+
self.verticalLayout_4 = QVBoxLayout()
|
|
36
|
+
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
|
37
|
+
self.horizontalLayout_5 = QHBoxLayout()
|
|
38
|
+
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
|
|
39
|
+
self.verticalLayout_2 = QVBoxLayout()
|
|
40
|
+
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
|
41
|
+
self.lbModifier = QLabel(Dialog)
|
|
42
|
+
self.lbModifier.setObjectName(u"lbModifier")
|
|
43
|
+
|
|
44
|
+
self.verticalLayout_2.addWidget(self.lbModifier)
|
|
45
|
+
|
|
46
|
+
self.leModifier = QLineEdit(Dialog)
|
|
47
|
+
self.leModifier.setObjectName(u"leModifier")
|
|
48
|
+
|
|
49
|
+
self.verticalLayout_2.addWidget(self.leModifier)
|
|
50
|
+
|
|
51
|
+
self.lbCode = QLabel(Dialog)
|
|
52
|
+
self.lbCode.setObjectName(u"lbCode")
|
|
53
|
+
|
|
54
|
+
self.verticalLayout_2.addWidget(self.lbCode)
|
|
55
|
+
|
|
56
|
+
self.leCode = QLineEdit(Dialog)
|
|
57
|
+
self.leCode.setObjectName(u"leCode")
|
|
58
|
+
|
|
59
|
+
self.verticalLayout_2.addWidget(self.leCode)
|
|
60
|
+
|
|
61
|
+
self.lbCodeHelp = QLabel(Dialog)
|
|
62
|
+
self.lbCodeHelp.setObjectName(u"lbCodeHelp")
|
|
63
|
+
self.lbCodeHelp.setWordWrap(True)
|
|
64
|
+
|
|
65
|
+
self.verticalLayout_2.addWidget(self.lbCodeHelp)
|
|
66
|
+
|
|
67
|
+
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
|
68
|
+
|
|
69
|
+
self.verticalLayout_2.addItem(self.verticalSpacer)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
self.horizontalLayout_5.addLayout(self.verticalLayout_2)
|
|
73
|
+
|
|
74
|
+
self.verticalLayout_3 = QVBoxLayout()
|
|
75
|
+
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
|
76
|
+
self.pbAddModifier = QPushButton(Dialog)
|
|
77
|
+
self.pbAddModifier.setObjectName(u"pbAddModifier")
|
|
78
|
+
|
|
79
|
+
self.verticalLayout_3.addWidget(self.pbAddModifier)
|
|
80
|
+
|
|
81
|
+
self.pbModifyModifier = QPushButton(Dialog)
|
|
82
|
+
self.pbModifyModifier.setObjectName(u"pbModifyModifier")
|
|
83
|
+
|
|
84
|
+
self.verticalLayout_3.addWidget(self.pbModifyModifier)
|
|
85
|
+
|
|
86
|
+
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
|
87
|
+
|
|
88
|
+
self.verticalLayout_3.addItem(self.verticalSpacer_2)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
self.horizontalLayout_5.addLayout(self.verticalLayout_3)
|
|
92
|
+
|
|
93
|
+
self.verticalLayout = QVBoxLayout()
|
|
94
|
+
self.verticalLayout.setObjectName(u"verticalLayout")
|
|
95
|
+
self.tabWidgetModifiersSets = QTabWidget(Dialog)
|
|
96
|
+
self.tabWidgetModifiersSets.setObjectName(u"tabWidgetModifiersSets")
|
|
97
|
+
self.tabWidgetModifiersSets.setMaximumSize(QSize(16777215, 30))
|
|
98
|
+
self.tabWidgetModifiersSets.setTabPosition(QTabWidget.North)
|
|
99
|
+
self.tabWidgetModifiersSets.setTabShape(QTabWidget.Rounded)
|
|
100
|
+
self.tabWidgetModifiersSets.setElideMode(Qt.ElideNone)
|
|
101
|
+
self.tabWidgetModifiersSets.setDocumentMode(True)
|
|
102
|
+
|
|
103
|
+
self.verticalLayout.addWidget(self.tabWidgetModifiersSets)
|
|
104
|
+
|
|
105
|
+
self.lb_name = QLabel(Dialog)
|
|
106
|
+
self.lb_name.setObjectName(u"lb_name")
|
|
107
|
+
|
|
108
|
+
self.verticalLayout.addWidget(self.lb_name)
|
|
109
|
+
|
|
110
|
+
self.le_name = QLineEdit(Dialog)
|
|
111
|
+
self.le_name.setObjectName(u"le_name")
|
|
112
|
+
|
|
113
|
+
self.verticalLayout.addWidget(self.le_name)
|
|
114
|
+
|
|
115
|
+
self.lb_description = QLabel(Dialog)
|
|
116
|
+
self.lb_description.setObjectName(u"lb_description")
|
|
117
|
+
|
|
118
|
+
self.verticalLayout.addWidget(self.lb_description)
|
|
119
|
+
|
|
120
|
+
self.le_description = QLineEdit(Dialog)
|
|
121
|
+
self.le_description.setObjectName(u"le_description")
|
|
122
|
+
|
|
123
|
+
self.verticalLayout.addWidget(self.le_description)
|
|
124
|
+
|
|
125
|
+
self.lbType = QLabel(Dialog)
|
|
126
|
+
self.lbType.setObjectName(u"lbType")
|
|
127
|
+
|
|
128
|
+
self.verticalLayout.addWidget(self.lbType)
|
|
129
|
+
|
|
130
|
+
self.cbType = QComboBox(Dialog)
|
|
131
|
+
self.cbType.addItem("")
|
|
132
|
+
self.cbType.addItem("")
|
|
133
|
+
self.cbType.addItem("")
|
|
134
|
+
self.cbType.addItem("")
|
|
135
|
+
self.cbType.setObjectName(u"cbType")
|
|
136
|
+
|
|
137
|
+
self.verticalLayout.addWidget(self.cbType)
|
|
138
|
+
|
|
139
|
+
self.lbValues = QLabel(Dialog)
|
|
140
|
+
self.lbValues.setObjectName(u"lbValues")
|
|
141
|
+
|
|
142
|
+
self.verticalLayout.addWidget(self.lbValues)
|
|
143
|
+
|
|
144
|
+
self.lwModifiers = QListWidget(Dialog)
|
|
145
|
+
self.lwModifiers.setObjectName(u"lwModifiers")
|
|
146
|
+
|
|
147
|
+
self.verticalLayout.addWidget(self.lwModifiers)
|
|
148
|
+
|
|
149
|
+
self.horizontalLayout = QHBoxLayout()
|
|
150
|
+
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
|
151
|
+
self.pbMoveUp = QPushButton(Dialog)
|
|
152
|
+
self.pbMoveUp.setObjectName(u"pbMoveUp")
|
|
153
|
+
|
|
154
|
+
self.horizontalLayout.addWidget(self.pbMoveUp)
|
|
155
|
+
|
|
156
|
+
self.pbMoveDown = QPushButton(Dialog)
|
|
157
|
+
self.pbMoveDown.setObjectName(u"pbMoveDown")
|
|
158
|
+
|
|
159
|
+
self.horizontalLayout.addWidget(self.pbMoveDown)
|
|
160
|
+
|
|
161
|
+
self.pbRemoveModifier = QPushButton(Dialog)
|
|
162
|
+
self.pbRemoveModifier.setObjectName(u"pbRemoveModifier")
|
|
163
|
+
|
|
164
|
+
self.horizontalLayout.addWidget(self.pbRemoveModifier)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
self.verticalLayout.addLayout(self.horizontalLayout)
|
|
168
|
+
|
|
169
|
+
self.pb_sort_modifiers = QPushButton(Dialog)
|
|
170
|
+
self.pb_sort_modifiers.setObjectName(u"pb_sort_modifiers")
|
|
171
|
+
|
|
172
|
+
self.verticalLayout.addWidget(self.pb_sort_modifiers)
|
|
173
|
+
|
|
174
|
+
self.horizontalLayout_3 = QHBoxLayout()
|
|
175
|
+
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
|
176
|
+
self.pbAddSet = QPushButton(Dialog)
|
|
177
|
+
self.pbAddSet.setObjectName(u"pbAddSet")
|
|
178
|
+
|
|
179
|
+
self.horizontalLayout_3.addWidget(self.pbAddSet)
|
|
180
|
+
|
|
181
|
+
self.pbRemoveSet = QPushButton(Dialog)
|
|
182
|
+
self.pbRemoveSet.setObjectName(u"pbRemoveSet")
|
|
183
|
+
|
|
184
|
+
self.horizontalLayout_3.addWidget(self.pbRemoveSet)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
|
188
|
+
|
|
189
|
+
self.horizontalLayout_4 = QHBoxLayout()
|
|
190
|
+
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
|
|
191
|
+
self.pbMoveSetLeft = QPushButton(Dialog)
|
|
192
|
+
self.pbMoveSetLeft.setObjectName(u"pbMoveSetLeft")
|
|
193
|
+
|
|
194
|
+
self.horizontalLayout_4.addWidget(self.pbMoveSetLeft)
|
|
195
|
+
|
|
196
|
+
self.pbMoveSetRight = QPushButton(Dialog)
|
|
197
|
+
self.pbMoveSetRight.setObjectName(u"pbMoveSetRight")
|
|
198
|
+
|
|
199
|
+
self.horizontalLayout_4.addWidget(self.pbMoveSetRight)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
self.verticalLayout.addLayout(self.horizontalLayout_4)
|
|
203
|
+
|
|
204
|
+
self.pb_add_subjects = QPushButton(Dialog)
|
|
205
|
+
self.pb_add_subjects.setObjectName(u"pb_add_subjects")
|
|
206
|
+
|
|
207
|
+
self.verticalLayout.addWidget(self.pb_add_subjects)
|
|
208
|
+
|
|
209
|
+
self.pb_load_file = QPushButton(Dialog)
|
|
210
|
+
self.pb_load_file.setObjectName(u"pb_load_file")
|
|
211
|
+
|
|
212
|
+
self.verticalLayout.addWidget(self.pb_load_file)
|
|
213
|
+
|
|
214
|
+
self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
|
215
|
+
|
|
216
|
+
self.verticalLayout.addItem(self.verticalSpacer_3)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
self.horizontalLayout_5.addLayout(self.verticalLayout)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
self.verticalLayout_4.addLayout(self.horizontalLayout_5)
|
|
223
|
+
|
|
224
|
+
self.horizontalLayout_2 = QHBoxLayout()
|
|
225
|
+
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
|
226
|
+
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
|
227
|
+
|
|
228
|
+
self.horizontalLayout_2.addItem(self.horizontalSpacer)
|
|
229
|
+
|
|
230
|
+
self.pbCancel = QPushButton(Dialog)
|
|
231
|
+
self.pbCancel.setObjectName(u"pbCancel")
|
|
232
|
+
|
|
233
|
+
self.horizontalLayout_2.addWidget(self.pbCancel)
|
|
234
|
+
|
|
235
|
+
self.pbOK = QPushButton(Dialog)
|
|
236
|
+
self.pbOK.setObjectName(u"pbOK")
|
|
237
|
+
|
|
238
|
+
self.horizontalLayout_2.addWidget(self.pbOK)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
self.verticalLayout_5.addLayout(self.verticalLayout_4)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
self.retranslateUi(Dialog)
|
|
248
|
+
|
|
249
|
+
self.tabWidgetModifiersSets.setCurrentIndex(-1)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
QMetaObject.connectSlotsByName(Dialog)
|
|
253
|
+
# setupUi
|
|
254
|
+
|
|
255
|
+
def retranslateUi(self, Dialog):
|
|
256
|
+
Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Set modifiers", None))
|
|
257
|
+
self.cb_ask_at_stop.setText(QCoreApplication.translate("Dialog", u"Ask for modifier(s) when behavior stops", None))
|
|
258
|
+
self.lbModifier.setText(QCoreApplication.translate("Dialog", u"Modifier", None))
|
|
259
|
+
self.lbCode.setText(QCoreApplication.translate("Dialog", u"Key code", None))
|
|
260
|
+
self.lbCodeHelp.setText(QCoreApplication.translate("Dialog", u"Key code is case sensitive. Type one character or a function key (F1, F2... F12)", None))
|
|
261
|
+
self.pbAddModifier.setText("")
|
|
262
|
+
self.pbModifyModifier.setText("")
|
|
263
|
+
self.lb_name.setText(QCoreApplication.translate("Dialog", u"Set name", None))
|
|
264
|
+
self.lb_description.setText(QCoreApplication.translate("Dialog", u"Description", None))
|
|
265
|
+
self.lbType.setText(QCoreApplication.translate("Dialog", u"Modifier type", None))
|
|
266
|
+
self.cbType.setItemText(0, QCoreApplication.translate("Dialog", u"Single selection", None))
|
|
267
|
+
self.cbType.setItemText(1, QCoreApplication.translate("Dialog", u"Multiple selection", None))
|
|
268
|
+
self.cbType.setItemText(2, QCoreApplication.translate("Dialog", u"Numeric", None))
|
|
269
|
+
self.cbType.setItemText(3, QCoreApplication.translate("Dialog", u"Value from external data file", None))
|
|
270
|
+
|
|
271
|
+
self.lbValues.setText(QCoreApplication.translate("Dialog", u"Values", None))
|
|
272
|
+
self.pbMoveUp.setText(QCoreApplication.translate("Dialog", u"Move modifier up", None))
|
|
273
|
+
self.pbMoveDown.setText(QCoreApplication.translate("Dialog", u"Move modifier down", None))
|
|
274
|
+
self.pbRemoveModifier.setText(QCoreApplication.translate("Dialog", u"Remove modifier", None))
|
|
275
|
+
self.pb_sort_modifiers.setText(QCoreApplication.translate("Dialog", u"Sort modifiers", None))
|
|
276
|
+
self.pbAddSet.setText(QCoreApplication.translate("Dialog", u"Add set of modifiers", None))
|
|
277
|
+
self.pbRemoveSet.setText(QCoreApplication.translate("Dialog", u"Remove set of modifiers", None))
|
|
278
|
+
self.pbMoveSetLeft.setText(QCoreApplication.translate("Dialog", u"Move set left", None))
|
|
279
|
+
self.pbMoveSetRight.setText(QCoreApplication.translate("Dialog", u"Move set right", None))
|
|
280
|
+
self.pb_add_subjects.setText(QCoreApplication.translate("Dialog", u"Add subjects as modifiers", None))
|
|
281
|
+
self.pb_load_file.setText(QCoreApplication.translate("Dialog", u"Load modifiers from file", None))
|
|
282
|
+
self.pbCancel.setText(QCoreApplication.translate("Dialog", u"Cancel", None))
|
|
283
|
+
self.pbOK.setText(QCoreApplication.translate("Dialog", u"OK", None))
|
|
284
|
+
# retranslateUi
|
|
285
|
+
|
|
@@ -25,9 +25,9 @@ import statistics
|
|
|
25
25
|
import sys
|
|
26
26
|
|
|
27
27
|
import tablib
|
|
28
|
-
from
|
|
29
|
-
from
|
|
30
|
-
from
|
|
28
|
+
from PySide6.QtCore import Qt
|
|
29
|
+
from PySide6.QtGui import QIcon
|
|
30
|
+
from PySide6.QtWidgets import (
|
|
31
31
|
QDialog,
|
|
32
32
|
QFileDialog,
|
|
33
33
|
QHBoxLayout,
|
|
File without changes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BORIS plugin
|
|
3
|
+
|
|
4
|
+
number of occurences of behaviors
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
__version_date__ = "2024-11-14"
|
|
11
|
+
__plugin_name__ = "Number of occurences of behaviors"
|
|
12
|
+
__author__ = "Olivier Friard - University of Torino - Italy"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run(df: pd.DataFrame):
|
|
16
|
+
"""
|
|
17
|
+
Calculate the number of occurrences of behaviors by subject.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
return df.groupby(["Subject", "Behavior"])["Behavior"].count().reset_index(name="number of occurences")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main(df: pd.DataFrame, observations_list: list = [], parameters: dict = {}) -> pd.DataFrame:
|
|
24
|
+
"""
|
|
25
|
+
filter by selected observations.
|
|
26
|
+
filter by selected subjects.
|
|
27
|
+
filter by selected behaviors.
|
|
28
|
+
filter by time interval.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# filter selected observations
|
|
32
|
+
if observations_list:
|
|
33
|
+
df = df[df["Observation id"].isin(observations_list)]
|
|
34
|
+
|
|
35
|
+
if parameters:
|
|
36
|
+
# filter selected subjects
|
|
37
|
+
df = df[df["Subject"].isin(parameters["selected subjects"])]
|
|
38
|
+
|
|
39
|
+
# filter selected behaviors
|
|
40
|
+
df = df[df["Behavior"].isin(parameters["selected behaviors"])]
|
|
41
|
+
|
|
42
|
+
# filter selected time interval
|
|
43
|
+
if parameters["start time"] is not None and parameters["end time"] is not None:
|
|
44
|
+
MIN_TIME = parameters["start time"]
|
|
45
|
+
MAX_TIME = parameters["end time"]
|
|
46
|
+
df_interval = df[
|
|
47
|
+
(
|
|
48
|
+
((df["Start (s)"] >= MIN_TIME) & (df["Start (s)"] <= MAX_TIME))
|
|
49
|
+
| ((df["Stop (s)"] >= MIN_TIME) & (df["Stop (s)"] <= MAX_TIME))
|
|
50
|
+
)
|
|
51
|
+
| ((df["Start (s)"] < MIN_TIME) & (df["Stop (s)"] > MAX_TIME))
|
|
52
|
+
]
|
|
53
|
+
df_interval.loc[df["Start (s)"] < MIN_TIME, "Start (s)"] = MIN_TIME
|
|
54
|
+
df_interval.loc[df["Stop (s)"] > MAX_TIME, "Stop (s)"] = MAX_TIME
|
|
55
|
+
|
|
56
|
+
df_interval.loc[:, "Duration (s)"] = df_interval["Stop (s)"] - df_interval["Start (s)"]
|
|
57
|
+
|
|
58
|
+
df = df_interval
|
|
59
|
+
|
|
60
|
+
return run(df)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BORIS plugin
|
|
3
|
+
|
|
4
|
+
number of occurences of behaviors by independent_variable
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
__version_date__ = "2024-11-14"
|
|
11
|
+
__plugin_name__ = "Number of occurences of behaviors by subject by independent_variable"
|
|
12
|
+
__author__ = "Olivier Friard - University of Torino - Italy"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run(df: pd.DataFrame):
|
|
16
|
+
"""
|
|
17
|
+
Calculate the number of occurrences of behaviors by subject and by independent_variable.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
results = (
|
|
21
|
+
df.groupby(
|
|
22
|
+
[
|
|
23
|
+
"independent variable 'Weather'",
|
|
24
|
+
"Subject",
|
|
25
|
+
"Behavior",
|
|
26
|
+
]
|
|
27
|
+
)["Behavior"]
|
|
28
|
+
.count()
|
|
29
|
+
.reset_index(name="number of occurences")
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return results
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def main(df: pd.DataFrame, observations_list: list = [], parameters: dict = {}) -> pd.DataFrame:
|
|
36
|
+
"""
|
|
37
|
+
filter by selected observations.
|
|
38
|
+
filter by selected subjects.
|
|
39
|
+
filter by selected behaviors.
|
|
40
|
+
filter by time interval.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# filter selected observations
|
|
44
|
+
if observations_list:
|
|
45
|
+
df = df[df["Observation id"].isin(observations_list)]
|
|
46
|
+
|
|
47
|
+
if parameters:
|
|
48
|
+
# filter selected subjects
|
|
49
|
+
df = df[df["Subject"].isin(parameters["selected subjects"])]
|
|
50
|
+
|
|
51
|
+
# filter selected behaviors
|
|
52
|
+
df = df[df["Behavior"].isin(parameters["selected behaviors"])]
|
|
53
|
+
|
|
54
|
+
# filter selected time interval
|
|
55
|
+
if parameters["start time"] is not None and parameters["end time"] is not None:
|
|
56
|
+
MIN_TIME = parameters["start time"]
|
|
57
|
+
MAX_TIME = parameters["end time"]
|
|
58
|
+
df_interval = df[
|
|
59
|
+
(
|
|
60
|
+
((df["Start (s)"] >= MIN_TIME) & (df["Start (s)"] <= MAX_TIME))
|
|
61
|
+
| ((df["Stop (s)"] >= MIN_TIME) & (df["Stop (s)"] <= MAX_TIME))
|
|
62
|
+
)
|
|
63
|
+
| ((df["Start (s)"] < MIN_TIME) & (df["Stop (s)"] > MAX_TIME))
|
|
64
|
+
]
|
|
65
|
+
df_interval.loc[df["Start (s)"] < MIN_TIME, "Start (s)"] = MIN_TIME
|
|
66
|
+
df_interval.loc[df["Stop (s)"] > MAX_TIME, "Stop (s)"] = MAX_TIME
|
|
67
|
+
|
|
68
|
+
df_interval.loc[:, "Duration (s)"] = df_interval["Stop (s)"] - df_interval["Start (s)"]
|
|
69
|
+
|
|
70
|
+
df = df_interval
|
|
71
|
+
|
|
72
|
+
return run(df)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BORIS plugin
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
__version_date__ = "2024-11-14"
|
|
9
|
+
__plugin_name__ = "Time budget"
|
|
10
|
+
__author__ = "Olivier Friard - University of Torino - Italy"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def run(df: pd.DataFrame):
|
|
14
|
+
"""
|
|
15
|
+
Calculate the following values:
|
|
16
|
+
|
|
17
|
+
- Total number of occurences of behavior
|
|
18
|
+
- Total duration of behavior (in seconds)
|
|
19
|
+
- Duration mean of behavior (in seconds)
|
|
20
|
+
- Standard deviation of behavior duration (in seconds)
|
|
21
|
+
- Inter-event intervals mean (in seconds)
|
|
22
|
+
- Inter-event intervals standard deviation (in seconds)
|
|
23
|
+
- % of total duration
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
dfs = [
|
|
27
|
+
df.groupby(["Subject", "Behavior"])["Behavior"].count().reset_index(name="number of occurences"),
|
|
28
|
+
df.groupby(["Subject", "Behavior"])["Duration (s)"].sum().reset_index(name="total duration"),
|
|
29
|
+
df.groupby(["Subject", "Behavior"])["Duration (s)"].mean().astype(float).round(3).reset_index(name="duration mean"),
|
|
30
|
+
df.groupby(["Subject", "Behavior"])["Duration (s)"].std().astype(float).round(3).reset_index(name="duration std dev"),
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# inter events
|
|
34
|
+
df2 = df.sort_values(by=["Observation id", "Subject", "Behavior", "Start (s)"])
|
|
35
|
+
df2["diff"] = df2.groupby(["Observation id", "Subject", "Behavior"])["Start (s)"].shift(periods=-1) - df2["Stop (s)"]
|
|
36
|
+
|
|
37
|
+
dfs.append(df2.groupby(["Subject", "Behavior"])["diff"].mean().astype(float).round(3).reset_index(name="inter-event intervals mean"))
|
|
38
|
+
|
|
39
|
+
dfs.append(df2.groupby(["Subject", "Behavior"])["diff"].std().astype(float).round(3).reset_index(name="inter-event intervals std dev"))
|
|
40
|
+
|
|
41
|
+
# % of time
|
|
42
|
+
dfs.append(
|
|
43
|
+
(100 * df.groupby(["Subject", "Behavior"])["Duration (s)"].sum() / df.groupby(["Subject"])["Duration (s)"].sum())
|
|
44
|
+
.astype(float)
|
|
45
|
+
.round(3)
|
|
46
|
+
.reset_index(name="% of total duration")
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
merged_df = dfs[0]
|
|
50
|
+
for df in dfs[1:]:
|
|
51
|
+
merged_df = pd.merge(merged_df, df, on=["Subject", "Behavior"])
|
|
52
|
+
|
|
53
|
+
return merged_df
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def main(df: pd.DataFrame, observations_list: list = [], parameters: dict = {}) -> pd.DataFrame:
|
|
57
|
+
"""
|
|
58
|
+
filter by selected observations.
|
|
59
|
+
filter by selected subjects.
|
|
60
|
+
filter by selected behaviors.
|
|
61
|
+
filter by time interval.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
# filter selected observations
|
|
65
|
+
if observations_list:
|
|
66
|
+
df = df[df["Observation id"].isin(observations_list)]
|
|
67
|
+
|
|
68
|
+
if parameters:
|
|
69
|
+
# filter selected subjects
|
|
70
|
+
df = df[df["Subject"].isin(parameters["selected subjects"])]
|
|
71
|
+
|
|
72
|
+
# filter selected behaviors
|
|
73
|
+
df = df[df["Behavior"].isin(parameters["selected behaviors"])]
|
|
74
|
+
|
|
75
|
+
# filter selected time interval
|
|
76
|
+
if parameters["start time"] is not None and parameters["end time"] is not None:
|
|
77
|
+
MIN_TIME = parameters["start time"]
|
|
78
|
+
MAX_TIME = parameters["end time"]
|
|
79
|
+
|
|
80
|
+
df_interval = df[
|
|
81
|
+
(
|
|
82
|
+
((df["Start (s)"] >= MIN_TIME) & (df["Start (s)"] <= MAX_TIME))
|
|
83
|
+
| ((df["Stop (s)"] >= MIN_TIME) & (df["Stop (s)"] <= MAX_TIME))
|
|
84
|
+
)
|
|
85
|
+
| ((df["Start (s)"] < MIN_TIME) & (df["Stop (s)"] > MAX_TIME))
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
df_interval.loc[df["Start (s)"] < MIN_TIME, "Start (s)"] = MIN_TIME
|
|
89
|
+
df_interval.loc[df["Stop (s)"] > MAX_TIME, "Stop (s)"] = MAX_TIME
|
|
90
|
+
|
|
91
|
+
df_interval.loc[:, "Duration (s)"] = df_interval["Stop (s)"] - df_interval["Start (s)"]
|
|
92
|
+
|
|
93
|
+
df = df_interval
|
|
94
|
+
|
|
95
|
+
return run(df)
|