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/add_modifier_ui.py
CHANGED
|
@@ -1,181 +1,285 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
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
|
+
################################################################################
|
|
12
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)
|
|
13
22
|
|
|
14
23
|
class Ui_Dialog(object):
|
|
15
24
|
def setupUi(self, Dialog):
|
|
16
|
-
Dialog.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
self.verticalLayout_5
|
|
20
|
-
self.
|
|
21
|
-
self.
|
|
22
|
-
self.
|
|
23
|
-
|
|
24
|
-
self.
|
|
25
|
-
|
|
26
|
-
self.
|
|
27
|
-
self.
|
|
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
|
+
|
|
28
44
|
self.verticalLayout_2.addWidget(self.lbModifier)
|
|
29
|
-
|
|
30
|
-
self.leModifier
|
|
45
|
+
|
|
46
|
+
self.leModifier = QLineEdit(Dialog)
|
|
47
|
+
self.leModifier.setObjectName(u"leModifier")
|
|
48
|
+
|
|
31
49
|
self.verticalLayout_2.addWidget(self.leModifier)
|
|
32
|
-
|
|
33
|
-
self.lbCode
|
|
50
|
+
|
|
51
|
+
self.lbCode = QLabel(Dialog)
|
|
52
|
+
self.lbCode.setObjectName(u"lbCode")
|
|
53
|
+
|
|
34
54
|
self.verticalLayout_2.addWidget(self.lbCode)
|
|
35
|
-
|
|
36
|
-
self.leCode
|
|
55
|
+
|
|
56
|
+
self.leCode = QLineEdit(Dialog)
|
|
57
|
+
self.leCode.setObjectName(u"leCode")
|
|
58
|
+
|
|
37
59
|
self.verticalLayout_2.addWidget(self.leCode)
|
|
38
|
-
|
|
60
|
+
|
|
61
|
+
self.lbCodeHelp = QLabel(Dialog)
|
|
62
|
+
self.lbCodeHelp.setObjectName(u"lbCodeHelp")
|
|
39
63
|
self.lbCodeHelp.setWordWrap(True)
|
|
40
|
-
|
|
64
|
+
|
|
41
65
|
self.verticalLayout_2.addWidget(self.lbCodeHelp)
|
|
42
|
-
|
|
43
|
-
self.
|
|
66
|
+
|
|
67
|
+
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
|
68
|
+
|
|
69
|
+
self.verticalLayout_2.addItem(self.verticalSpacer)
|
|
70
|
+
|
|
71
|
+
|
|
44
72
|
self.horizontalLayout_5.addLayout(self.verticalLayout_2)
|
|
45
|
-
|
|
46
|
-
self.verticalLayout_3
|
|
47
|
-
self.
|
|
48
|
-
self.pbAddModifier
|
|
49
|
-
self.pbAddModifier.setObjectName("pbAddModifier")
|
|
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
|
+
|
|
50
79
|
self.verticalLayout_3.addWidget(self.pbAddModifier)
|
|
51
|
-
|
|
52
|
-
self.pbModifyModifier
|
|
53
|
-
self.pbModifyModifier.setObjectName("pbModifyModifier")
|
|
80
|
+
|
|
81
|
+
self.pbModifyModifier = QPushButton(Dialog)
|
|
82
|
+
self.pbModifyModifier.setObjectName(u"pbModifyModifier")
|
|
83
|
+
|
|
54
84
|
self.verticalLayout_3.addWidget(self.pbModifyModifier)
|
|
55
|
-
|
|
56
|
-
self.
|
|
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
|
+
|
|
57
91
|
self.horizontalLayout_5.addLayout(self.verticalLayout_3)
|
|
58
|
-
|
|
59
|
-
self.verticalLayout
|
|
60
|
-
self.
|
|
61
|
-
self.tabWidgetModifiersSets
|
|
62
|
-
self.tabWidgetModifiersSets.
|
|
63
|
-
self.tabWidgetModifiersSets.
|
|
64
|
-
self.tabWidgetModifiersSets.
|
|
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.TabPosition.North)
|
|
99
|
+
self.tabWidgetModifiersSets.setTabShape(QTabWidget.TabShape.Rounded)
|
|
100
|
+
self.tabWidgetModifiersSets.setElideMode(Qt.TextElideMode.ElideNone)
|
|
65
101
|
self.tabWidgetModifiersSets.setDocumentMode(True)
|
|
66
|
-
|
|
102
|
+
|
|
67
103
|
self.verticalLayout.addWidget(self.tabWidgetModifiersSets)
|
|
68
|
-
|
|
69
|
-
self.lb_name
|
|
104
|
+
|
|
105
|
+
self.lb_name = QLabel(Dialog)
|
|
106
|
+
self.lb_name.setObjectName(u"lb_name")
|
|
107
|
+
|
|
70
108
|
self.verticalLayout.addWidget(self.lb_name)
|
|
71
|
-
|
|
72
|
-
self.le_name
|
|
109
|
+
|
|
110
|
+
self.le_name = QLineEdit(Dialog)
|
|
111
|
+
self.le_name.setObjectName(u"le_name")
|
|
112
|
+
|
|
73
113
|
self.verticalLayout.addWidget(self.le_name)
|
|
74
|
-
|
|
75
|
-
self.lb_description
|
|
114
|
+
|
|
115
|
+
self.lb_description = QLabel(Dialog)
|
|
116
|
+
self.lb_description.setObjectName(u"lb_description")
|
|
117
|
+
|
|
76
118
|
self.verticalLayout.addWidget(self.lb_description)
|
|
77
|
-
|
|
78
|
-
self.le_description
|
|
119
|
+
|
|
120
|
+
self.le_description = QLineEdit(Dialog)
|
|
121
|
+
self.le_description.setObjectName(u"le_description")
|
|
122
|
+
|
|
79
123
|
self.verticalLayout.addWidget(self.le_description)
|
|
80
|
-
|
|
81
|
-
self.lbType
|
|
124
|
+
|
|
125
|
+
self.lbType = QLabel(Dialog)
|
|
126
|
+
self.lbType.setObjectName(u"lbType")
|
|
127
|
+
|
|
82
128
|
self.verticalLayout.addWidget(self.lbType)
|
|
83
|
-
|
|
84
|
-
self.cbType
|
|
129
|
+
|
|
130
|
+
self.cbType = QComboBox(Dialog)
|
|
85
131
|
self.cbType.addItem("")
|
|
86
132
|
self.cbType.addItem("")
|
|
87
133
|
self.cbType.addItem("")
|
|
88
134
|
self.cbType.addItem("")
|
|
135
|
+
self.cbType.setObjectName(u"cbType")
|
|
136
|
+
|
|
89
137
|
self.verticalLayout.addWidget(self.cbType)
|
|
90
|
-
|
|
91
|
-
self.lbValues
|
|
138
|
+
|
|
139
|
+
self.lbValues = QLabel(Dialog)
|
|
140
|
+
self.lbValues.setObjectName(u"lbValues")
|
|
141
|
+
|
|
92
142
|
self.verticalLayout.addWidget(self.lbValues)
|
|
93
|
-
|
|
94
|
-
self.lwModifiers
|
|
143
|
+
|
|
144
|
+
self.lwModifiers = QListWidget(Dialog)
|
|
145
|
+
self.lwModifiers.setObjectName(u"lwModifiers")
|
|
146
|
+
|
|
95
147
|
self.verticalLayout.addWidget(self.lwModifiers)
|
|
96
|
-
|
|
97
|
-
self.horizontalLayout
|
|
98
|
-
self.
|
|
99
|
-
self.pbMoveUp
|
|
148
|
+
|
|
149
|
+
self.horizontalLayout = QHBoxLayout()
|
|
150
|
+
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
|
151
|
+
self.pbMoveUp = QPushButton(Dialog)
|
|
152
|
+
self.pbMoveUp.setObjectName(u"pbMoveUp")
|
|
153
|
+
|
|
100
154
|
self.horizontalLayout.addWidget(self.pbMoveUp)
|
|
101
|
-
|
|
102
|
-
self.pbMoveDown
|
|
155
|
+
|
|
156
|
+
self.pbMoveDown = QPushButton(Dialog)
|
|
157
|
+
self.pbMoveDown.setObjectName(u"pbMoveDown")
|
|
158
|
+
|
|
103
159
|
self.horizontalLayout.addWidget(self.pbMoveDown)
|
|
160
|
+
|
|
161
|
+
self.pb_sort_modifiers = QPushButton(Dialog)
|
|
162
|
+
self.pb_sort_modifiers.setObjectName(u"pb_sort_modifiers")
|
|
163
|
+
|
|
164
|
+
self.horizontalLayout.addWidget(self.pb_sort_modifiers)
|
|
165
|
+
|
|
166
|
+
self.pbRemoveModifier = QPushButton(Dialog)
|
|
167
|
+
self.pbRemoveModifier.setObjectName(u"pbRemoveModifier")
|
|
168
|
+
|
|
169
|
+
self.horizontalLayout.addWidget(self.pbRemoveModifier)
|
|
170
|
+
|
|
171
|
+
|
|
104
172
|
self.verticalLayout.addLayout(self.horizontalLayout)
|
|
105
|
-
|
|
106
|
-
self.
|
|
107
|
-
self.
|
|
108
|
-
self.
|
|
109
|
-
self.
|
|
110
|
-
|
|
111
|
-
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
|
112
|
-
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
|
113
|
-
self.pbAddSet = QtWidgets.QPushButton(Dialog)
|
|
114
|
-
self.pbAddSet.setObjectName("pbAddSet")
|
|
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
|
+
|
|
115
179
|
self.horizontalLayout_3.addWidget(self.pbAddSet)
|
|
116
|
-
|
|
117
|
-
self.
|
|
180
|
+
|
|
181
|
+
self.pbMoveSetLeft = QPushButton(Dialog)
|
|
182
|
+
self.pbMoveSetLeft.setObjectName(u"pbMoveSetLeft")
|
|
183
|
+
|
|
184
|
+
self.horizontalLayout_3.addWidget(self.pbMoveSetLeft)
|
|
185
|
+
|
|
186
|
+
self.pbMoveSetRight = QPushButton(Dialog)
|
|
187
|
+
self.pbMoveSetRight.setObjectName(u"pbMoveSetRight")
|
|
188
|
+
|
|
189
|
+
self.horizontalLayout_3.addWidget(self.pbMoveSetRight)
|
|
190
|
+
|
|
191
|
+
self.pbRemoveSet = QPushButton(Dialog)
|
|
192
|
+
self.pbRemoveSet.setObjectName(u"pbRemoveSet")
|
|
193
|
+
|
|
118
194
|
self.horizontalLayout_3.addWidget(self.pbRemoveSet)
|
|
195
|
+
|
|
196
|
+
|
|
119
197
|
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
|
120
|
-
|
|
121
|
-
self.horizontalLayout_4
|
|
122
|
-
self.
|
|
123
|
-
|
|
124
|
-
self.horizontalLayout_4.addWidget(self.pbMoveSetLeft)
|
|
125
|
-
self.pbMoveSetRight = QtWidgets.QPushButton(Dialog)
|
|
126
|
-
self.pbMoveSetRight.setObjectName("pbMoveSetRight")
|
|
127
|
-
self.horizontalLayout_4.addWidget(self.pbMoveSetRight)
|
|
198
|
+
|
|
199
|
+
self.horizontalLayout_4 = QHBoxLayout()
|
|
200
|
+
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
|
|
201
|
+
|
|
128
202
|
self.verticalLayout.addLayout(self.horizontalLayout_4)
|
|
129
|
-
|
|
130
|
-
self.pb_add_subjects
|
|
203
|
+
|
|
204
|
+
self.pb_add_subjects = QPushButton(Dialog)
|
|
205
|
+
self.pb_add_subjects.setObjectName(u"pb_add_subjects")
|
|
206
|
+
|
|
131
207
|
self.verticalLayout.addWidget(self.pb_add_subjects)
|
|
132
|
-
|
|
133
|
-
self.pb_load_file
|
|
208
|
+
|
|
209
|
+
self.pb_load_file = QPushButton(Dialog)
|
|
210
|
+
self.pb_load_file.setObjectName(u"pb_load_file")
|
|
211
|
+
|
|
134
212
|
self.verticalLayout.addWidget(self.pb_load_file)
|
|
135
|
-
|
|
136
|
-
self.
|
|
213
|
+
|
|
214
|
+
self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
|
215
|
+
|
|
216
|
+
self.verticalLayout.addItem(self.verticalSpacer_3)
|
|
217
|
+
|
|
218
|
+
|
|
137
219
|
self.horizontalLayout_5.addLayout(self.verticalLayout)
|
|
220
|
+
|
|
221
|
+
|
|
138
222
|
self.verticalLayout_4.addLayout(self.horizontalLayout_5)
|
|
139
|
-
|
|
140
|
-
self.horizontalLayout_2
|
|
141
|
-
|
|
142
|
-
self.
|
|
143
|
-
|
|
144
|
-
self.
|
|
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
|
+
|
|
145
233
|
self.horizontalLayout_2.addWidget(self.pbCancel)
|
|
146
|
-
|
|
147
|
-
self.pbOK
|
|
234
|
+
|
|
235
|
+
self.pbOK = QPushButton(Dialog)
|
|
236
|
+
self.pbOK.setObjectName(u"pbOK")
|
|
237
|
+
|
|
148
238
|
self.horizontalLayout_2.addWidget(self.pbOK)
|
|
239
|
+
|
|
240
|
+
|
|
149
241
|
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
|
|
242
|
+
|
|
243
|
+
|
|
150
244
|
self.verticalLayout_5.addLayout(self.verticalLayout_4)
|
|
151
245
|
|
|
246
|
+
|
|
152
247
|
self.retranslateUi(Dialog)
|
|
248
|
+
|
|
153
249
|
self.tabWidgetModifiersSets.setCurrentIndex(-1)
|
|
154
|
-
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
QMetaObject.connectSlotsByName(Dialog)
|
|
253
|
+
# setupUi
|
|
155
254
|
|
|
156
255
|
def retranslateUi(self, Dialog):
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
self.lbModifier.setText(
|
|
160
|
-
self.lbCode.setText(
|
|
161
|
-
self.lbCodeHelp.setText(
|
|
162
|
-
self.
|
|
163
|
-
self.
|
|
164
|
-
self.
|
|
165
|
-
self.
|
|
166
|
-
self.
|
|
167
|
-
self.cbType.setItemText(
|
|
168
|
-
self.cbType.setItemText(
|
|
169
|
-
self.
|
|
170
|
-
self.
|
|
171
|
-
|
|
172
|
-
self.
|
|
173
|
-
self.
|
|
174
|
-
self.
|
|
175
|
-
self.
|
|
176
|
-
self.
|
|
177
|
-
self.
|
|
178
|
-
self.
|
|
179
|
-
self.
|
|
180
|
-
self.
|
|
181
|
-
self.
|
|
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(QCoreApplication.translate("Dialog", u"->", None))
|
|
262
|
+
self.pbModifyModifier.setText(QCoreApplication.translate("Dialog", u"<-", None))
|
|
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.pb_sort_modifiers.setText(QCoreApplication.translate("Dialog", u"Sort modifiers", None))
|
|
275
|
+
self.pbRemoveModifier.setText(QCoreApplication.translate("Dialog", u"Remove modifier", None))
|
|
276
|
+
self.pbAddSet.setText(QCoreApplication.translate("Dialog", u"Add set of modifiers", None))
|
|
277
|
+
self.pbMoveSetLeft.setText(QCoreApplication.translate("Dialog", u"Move set left", None))
|
|
278
|
+
self.pbMoveSetRight.setText(QCoreApplication.translate("Dialog", u"Move set right", None))
|
|
279
|
+
self.pbRemoveSet.setText(QCoreApplication.translate("Dialog", u"Remove set of modifiers", 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
|
+
|
|
@@ -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,16 +19,15 @@ Copyright 2012-2023 Olivier Friard
|
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
from decimal import Decimal as dec
|
|
23
22
|
import pathlib
|
|
24
23
|
import re
|
|
25
24
|
import statistics
|
|
26
25
|
import sys
|
|
27
26
|
|
|
28
27
|
import tablib
|
|
29
|
-
from
|
|
30
|
-
from
|
|
31
|
-
from
|
|
28
|
+
from PySide6.QtCore import Qt
|
|
29
|
+
from PySide6.QtGui import QIcon
|
|
30
|
+
from PySide6.QtWidgets import (
|
|
32
31
|
QDialog,
|
|
33
32
|
QFileDialog,
|
|
34
33
|
QHBoxLayout,
|
|
@@ -156,7 +155,7 @@ class Advanced_event_filtering_dialog(QDialog):
|
|
|
156
155
|
hbox.addItem(QSpacerItem(241, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
|
|
157
156
|
self.pb_save = QPushButton("Save results", clicked=self.save_results)
|
|
158
157
|
hbox.addWidget(self.pb_save)
|
|
159
|
-
self.pb_close = QPushButton(
|
|
158
|
+
self.pb_close = QPushButton(cfg.CLOSE, clicked=self.close)
|
|
160
159
|
hbox.addWidget(self.pb_close)
|
|
161
160
|
vbox.addLayout(hbox)
|
|
162
161
|
|
|
@@ -190,7 +189,6 @@ class Advanced_event_filtering_dialog(QDialog):
|
|
|
190
189
|
add selected logic operaton to lineedit
|
|
191
190
|
"""
|
|
192
191
|
if self.lw3.currentItem():
|
|
193
|
-
|
|
194
192
|
text = ""
|
|
195
193
|
if self.lw3.currentItem().text() == "AND":
|
|
196
194
|
text = " & "
|
|
@@ -208,7 +206,7 @@ class Advanced_event_filtering_dialog(QDialog):
|
|
|
208
206
|
if not self.logic.text():
|
|
209
207
|
return
|
|
210
208
|
if self.logic.text().count('"') % 2:
|
|
211
|
-
QMessageBox.warning(self, cfg.programName,
|
|
209
|
+
QMessageBox.warning(self, cfg.programName, 'Wrong number of double quotes (")')
|
|
212
210
|
return
|
|
213
211
|
|
|
214
212
|
sb_list = re.findall('"([^"]*)"', self.logic.text())
|
|
@@ -237,15 +235,13 @@ class Advanced_event_filtering_dialog(QDialog):
|
|
|
237
235
|
self.tw.clear()
|
|
238
236
|
|
|
239
237
|
if flag_error or self.rb_details.isChecked():
|
|
240
|
-
|
|
241
|
-
self.lb_results.setText(f"Results ({len(self.out)} event{'s'*(len(self.out) > 1)})")
|
|
238
|
+
self.lb_results.setText(f"Results ({len(self.out)} event{'s' * (len(self.out) > 1)})")
|
|
242
239
|
|
|
243
240
|
self.tw.setRowCount(len(self.out))
|
|
244
241
|
self.tw.setColumnCount(len(self.details_header)) # obs_id, comment, start, stop, duration
|
|
245
242
|
self.tw.setHorizontalHeaderLabels(self.details_header)
|
|
246
243
|
|
|
247
244
|
if not flag_error and self.rb_summary.isChecked():
|
|
248
|
-
|
|
249
245
|
summary = {}
|
|
250
246
|
for row in self.out:
|
|
251
247
|
obs_id, _, start, stop, duration = row
|
|
@@ -255,7 +251,6 @@ class Advanced_event_filtering_dialog(QDialog):
|
|
|
255
251
|
|
|
256
252
|
self.out = []
|
|
257
253
|
for obs_id in summary:
|
|
258
|
-
|
|
259
254
|
self.out.append(
|
|
260
255
|
[
|
|
261
256
|
obs_id,
|
|
@@ -266,7 +261,7 @@ class Advanced_event_filtering_dialog(QDialog):
|
|
|
266
261
|
]
|
|
267
262
|
)
|
|
268
263
|
|
|
269
|
-
self.lb_results.setText(f"Results ({len(summary)} observation{'s'*(len(summary) > 1)})")
|
|
264
|
+
self.lb_results.setText(f"Results ({len(summary)} observation{'s' * (len(summary) > 1)})")
|
|
270
265
|
self.tw.setRowCount(len(summary))
|
|
271
266
|
self.tw.setColumnCount(len(self.summary_header)) # obs_id, mean, stdev
|
|
272
267
|
self.tw.setHorizontalHeaderLabels(self.summary_header)
|
|
@@ -303,9 +298,7 @@ class Advanced_event_filtering_dialog(QDialog):
|
|
|
303
298
|
# check if file with new extension already exists
|
|
304
299
|
if pathlib.Path(file_name).is_file():
|
|
305
300
|
if (
|
|
306
|
-
dialog.MessageDialog(
|
|
307
|
-
cfg.programName, f"The file {file_name} already exists.", [cfg.CANCEL, cfg.OVERWRITE]
|
|
308
|
-
)
|
|
301
|
+
dialog.MessageDialog(cfg.programName, f"The file {file_name} already exists.", [cfg.CANCEL, cfg.OVERWRITE])
|
|
309
302
|
== cfg.CANCEL
|
|
310
303
|
):
|
|
311
304
|
return
|
|
@@ -357,22 +350,27 @@ def event_filtering(self):
|
|
|
357
350
|
)
|
|
358
351
|
return
|
|
359
352
|
|
|
360
|
-
max_media_duration_all_obs, _ = observation_operations.media_duration(
|
|
361
|
-
|
|
362
|
-
)
|
|
353
|
+
max_media_duration_all_obs, _ = observation_operations.media_duration(self.pj[cfg.OBSERVATIONS], selected_observations)
|
|
354
|
+
|
|
355
|
+
start_interval, end_interval = observation_operations.time_intervals_range(self.pj[cfg.OBSERVATIONS], selected_observations)
|
|
363
356
|
|
|
364
357
|
parameters = select_subj_behav.choose_obs_subj_behav_category(
|
|
365
358
|
self,
|
|
366
359
|
selected_observations,
|
|
367
360
|
start_coding=start_coding,
|
|
368
361
|
end_coding=end_coding,
|
|
362
|
+
# start_interval=start_interval,
|
|
363
|
+
# end_interval=end_interval,
|
|
364
|
+
start_interval=None,
|
|
365
|
+
end_interval=None,
|
|
369
366
|
maxTime=max_media_duration_all_obs,
|
|
370
|
-
|
|
371
|
-
|
|
367
|
+
show_include_modifiers=False,
|
|
368
|
+
show_exclude_non_coded_behaviors=False,
|
|
372
369
|
by_category=False,
|
|
373
370
|
n_observations=len(selected_observations),
|
|
374
371
|
)
|
|
375
|
-
|
|
372
|
+
|
|
373
|
+
if not parameters:
|
|
376
374
|
return
|
|
377
375
|
|
|
378
376
|
if not parameters[cfg.SELECTED_SUBJECTS] or not parameters[cfg.SELECTED_BEHAVIORS]:
|
|
@@ -389,7 +387,7 @@ def event_filtering(self):
|
|
|
389
387
|
cursor.execute("SELECT MIN(start), MAX(stop) FROM aggregated_events")
|
|
390
388
|
min_time, max_time = cursor.fetchone()
|
|
391
389
|
|
|
392
|
-
if parameters[cfg.TIME_INTERVAL]
|
|
390
|
+
if parameters[cfg.TIME_INTERVAL] in (cfg.TIME_ARBITRARY_INTERVAL, cfg.TIME_OBS_INTERVAL):
|
|
393
391
|
min_time = float(parameters[cfg.START_TIME])
|
|
394
392
|
max_time = float(parameters[cfg.END_TIME])
|
|
395
393
|
|
|
@@ -438,7 +436,7 @@ def event_filtering(self):
|
|
|
438
436
|
for row in cursor.fetchall():
|
|
439
437
|
obs, subj, behav, start, stop = row
|
|
440
438
|
if obs not in events:
|
|
441
|
-
events[obs]
|
|
439
|
+
events[obs] = {}
|
|
442
440
|
|
|
443
441
|
# use function in base at event (state or point)
|
|
444
442
|
interval_func = icc if start == stop else ico
|
|
@@ -452,10 +450,6 @@ def event_filtering(self):
|
|
|
452
450
|
|
|
453
451
|
w = Advanced_event_filtering_dialog(events)
|
|
454
452
|
w.lb_time_interval.setText(
|
|
455
|
-
(
|
|
456
|
-
f"Time interval: "
|
|
457
|
-
f"{util.dynamic_time_format(min_time, cfg.DYNAMIC_TIME_CUTOFF_DEFAULT, self.timeFormat)} - "
|
|
458
|
-
f"{util.dynamic_time_format(max_time, cfg.DYNAMIC_TIME_CUTOFF_DEFAULT, self.timeFormat)}"
|
|
459
|
-
)
|
|
453
|
+
(f"Time interval: {util.smart_time_format(min_time, self.timeFormat)} - {util.smart_time_format(max_time, self.timeFormat)}")
|
|
460
454
|
)
|
|
461
455
|
w.exec_()
|
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BORIS plugin
|
|
3
|
+
|
|
4
|
+
number of occurences of behaviors
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
__version__ = "0.0.1"
|
|
10
|
+
__version_date__ = "2025-04-10"
|
|
11
|
+
__plugin_name__ = "Behavior latencyxxx"
|
|
12
|
+
__author__ = "Olivier Friard - University of Torino - Italy"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import itertools
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def run(df: pd.DataFrame):
|
|
19
|
+
"""
|
|
20
|
+
Latency of a behavior after another.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
df["start_time"] = pd.to_datetime(df["Start (s)"])
|
|
24
|
+
df["end_time"] = pd.to_datetime(df["Stop (s)"])
|
|
25
|
+
|
|
26
|
+
latency_by_subject: dict = {}
|
|
27
|
+
|
|
28
|
+
for subject, group in df.groupby("subject"):
|
|
29
|
+
behaviors = group["behavior"].tolist()
|
|
30
|
+
# combinations = []
|
|
31
|
+
# Utiliser itertools pour créer des combinaisons 2 à 2 des comportements
|
|
32
|
+
for comb in itertools.combinations(behaviors, 2):
|
|
33
|
+
# combinations.append(comb)
|
|
34
|
+
|
|
35
|
+
last_A_end_time = None
|
|
36
|
+
|
|
37
|
+
# Liste pour stocker les latences de chaque sujet
|
|
38
|
+
subject_latency = []
|
|
39
|
+
|
|
40
|
+
for index, row in group.iterrows():
|
|
41
|
+
if row["behavior"] == comb[0]:
|
|
42
|
+
# Si on rencontre un comportement A, on réinitialise le temps de fin du comportement A
|
|
43
|
+
last_A_end_time = row["end_time"]
|
|
44
|
+
subject_latency.append(None) # Pas de latence pour A
|
|
45
|
+
elif row["behavior"] == comb[1] and last_A_end_time is not None:
|
|
46
|
+
# Si on rencontre un comportement B et qu'on a déjà vu un A avant
|
|
47
|
+
latency_time = row["start_time"] - last_A_end_time
|
|
48
|
+
subject_latency.append(latency_time)
|
|
49
|
+
else:
|
|
50
|
+
# Si on rencontre un B mais sans A avant
|
|
51
|
+
subject_latency.append(None)
|
|
52
|
+
|
|
53
|
+
# Ajout des latences calculées au DataFrame
|
|
54
|
+
df.loc[group.index, f"latency {comb[1]} after {comb[0]}"] = subject_latency
|
|
55
|
+
|
|
56
|
+
# Calcul de la latence totale ou moyenne par sujet
|
|
57
|
+
latency_by_subject[(subject, comb)] = df.groupby("subject")["latency"].agg(["sum", "mean"])
|
|
58
|
+
|
|
59
|
+
return str(latency_by_subject)
|