boris-behav-obs 8.25.4__py2.py3-none-any.whl → 8.26.1__py2.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/add_modifier.py CHANGED
@@ -36,7 +36,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
36
36
  tabMem = -1
37
37
  itemPositionMem = -1
38
38
 
39
- def __init__(self, modifiers_str, subjects=[], parent=None):
39
+ def __init__(self, modifiers_str: str, subjects: list = [], ask_at_stop_enabled: bool = False, parent=None):
40
40
  super().__init__()
41
41
  self.setupUi(self)
42
42
 
@@ -44,10 +44,12 @@ class addModifierDialog(QDialog, Ui_Dialog):
44
44
  if not self.subjects:
45
45
  self.pb_add_subjects.setEnabled(False)
46
46
 
47
+ self.ask_at_stop_enabled = ask_at_stop_enabled
48
+
47
49
  self.pbAddModifier.clicked.connect(self.addModifier)
48
50
  self.pbAddModifier.setIcon(QIcon(":/frame_forward"))
49
- self.pbAddSet.clicked.connect(self.addSet)
50
- self.pbRemoveSet.clicked.connect(self.removeSet)
51
+ self.pbAddSet.clicked.connect(self.add_set_of_modifiers)
52
+ self.pbRemoveSet.clicked.connect(self.remove_set_of_modifiers)
51
53
  self.pbModifyModifier.clicked.connect(self.modifyModifier)
52
54
  self.pbModifyModifier.setIcon(QIcon(":/frame_backward"))
53
55
 
@@ -60,22 +62,27 @@ class addModifierDialog(QDialog, Ui_Dialog):
60
62
  self.pb_add_subjects.clicked.connect(self.add_subjects)
61
63
  self.pb_load_file.clicked.connect(self.add_modifiers_from_file)
62
64
 
63
- self.pbOK.clicked.connect(lambda: self.pb_pushed("ok"))
64
- self.pbCancel.clicked.connect(lambda: self.pb_pushed("cancel"))
65
+ self.pbOK.clicked.connect(lambda: self.pb_pushed(cfg.OK))
66
+ self.pbCancel.clicked.connect(lambda: self.pb_pushed(cfg.CANCEL))
65
67
 
66
68
  self.le_name.textChanged.connect(self.set_name_changed)
67
69
  self.le_description.textChanged.connect(self.set_description_changed)
68
70
 
69
71
  self.cbType.currentIndexChanged.connect(self.type_changed)
70
72
 
71
- dummy_dict = json.loads(modifiers_str) if modifiers_str else {}
72
- modif_values = []
73
+ # self.cb_ask_at_stop.clicked.connect(self.ask_at_stop_changed)
74
+
75
+ dummy_dict: dict = json.loads(modifiers_str) if modifiers_str else {}
76
+ modif_values: list = []
73
77
  for idx in sorted_keys(dummy_dict):
74
78
  modif_values.append(dummy_dict[idx])
75
79
 
76
- self.modifiers_sets_dict = {}
80
+ self.modifiers_sets_dict: dict = {}
77
81
  for modif in modif_values:
78
82
  self.modifiers_sets_dict[str(len(self.modifiers_sets_dict))] = dict(modif)
83
+ if self.ask_at_stop_enabled:
84
+ if dict(modif).get("ask at stop", False):
85
+ self.cb_ask_at_stop.setChecked(True)
79
86
 
80
87
  self.tabWidgetModifiersSets.currentChanged.connect(self.tabWidgetModifiersSets_changed)
81
88
 
@@ -102,6 +109,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
102
109
  self.pb_add_subjects,
103
110
  self.pb_load_file,
104
111
  self.pb_sort_modifiers,
112
+ self.cb_ask_at_stop,
105
113
  ):
106
114
  w.setVisible(False)
107
115
  for w in (self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier):
@@ -120,14 +128,14 @@ class addModifierDialog(QDialog, Ui_Dialog):
120
128
  "If you close the window it will be lost.<br>"
121
129
  "Do you want to change modifiers set"
122
130
  ),
123
- ["Close", cfg.CANCEL],
131
+ [cfg.CLOSE, cfg.CANCEL],
124
132
  )
125
133
  == cfg.CANCEL
126
134
  ):
127
135
  return
128
- if button == "ok":
136
+ if button == cfg.OK:
129
137
  self.accept()
130
- if button == "cancel":
138
+ if button == cfg.CANCEL:
131
139
  self.reject()
132
140
 
133
141
  def add_subjects(self):
@@ -247,6 +255,12 @@ class addModifierDialog(QDialog, Ui_Dialog):
247
255
  else:
248
256
  self.lb_name.setText("Set name")
249
257
 
258
+ # def ask_at_stop_changed(self):
259
+ # """
260
+ # value changed
261
+ # """
262
+ # self.modifiers_sets_dict[str(self.tabWidgetModifiersSets.currentIndex())]["ask at stop"] = self.cb_ask_at_stop.isChecked()
263
+
250
264
  def moveSetLeft(self):
251
265
  """
252
266
  move selected modifiers set left
@@ -304,7 +318,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
304
318
  self.lwModifiers.item(x).text() for x in range(self.lwModifiers.count())
305
319
  ]
306
320
 
307
- def addSet(self):
321
+ def add_set_of_modifiers(self):
308
322
  """
309
323
  Add a set of modifiers
310
324
  """
@@ -315,6 +329,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
315
329
  "name": "",
316
330
  "description": "",
317
331
  "type": cfg.SINGLE_SELECTION,
332
+ "ask at stop": False,
318
333
  "values": [],
319
334
  }
320
335
  self.tabWidgetModifiersSets.addTab(QWidget(), f"Set #{len(self.modifiers_sets_dict)}")
@@ -342,6 +357,8 @@ class addModifierDialog(QDialog, Ui_Dialog):
342
357
  self.pb_sort_modifiers,
343
358
  ):
344
359
  w.setVisible(True)
360
+ self.cb_ask_at_stop.setVisible(self.ask_at_stop_enabled)
361
+
345
362
  for w in (self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier):
346
363
  w.setEnabled(True)
347
364
  return
@@ -351,6 +368,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
351
368
  "name": "",
352
369
  "description": "",
353
370
  "type": cfg.SINGLE_SELECTION,
371
+ "ask at stop": False,
354
372
  "values": [],
355
373
  }
356
374
  self.tabWidgetModifiersSets.addTab(QWidget(), f"Set #{len(self.modifiers_sets_dict)}")
@@ -364,7 +382,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
364
382
  "It is not possible to add a modifiers' set while the current modifiers' set is empty.",
365
383
  )
366
384
 
367
- def removeSet(self):
385
+ def remove_set_of_modifiers(self):
368
386
  """
369
387
  remove set of modifiers
370
388
  """
@@ -403,14 +421,15 @@ class addModifierDialog(QDialog, Ui_Dialog):
403
421
  self.pbRemoveSet,
404
422
  self.pbMoveSetLeft,
405
423
  self.pbMoveSetRight,
424
+ self.cb_ask_at_stop,
406
425
  ):
407
426
  w.setVisible(False)
408
- for w in [self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier]:
427
+ for w in (self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier):
409
428
  w.setEnabled(False)
410
429
 
411
430
  if not len(self.modifiers_sets_dict):
412
431
  # set invisible and unavailable buttons and others elements
413
- for w in [
432
+ for w in (
414
433
  self.lb_name,
415
434
  self.le_name,
416
435
  self.lbType,
@@ -428,7 +447,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
428
447
  self.pb_add_subjects,
429
448
  self.pb_load_file,
430
449
  self.pb_sort_modifiers,
431
- ]:
450
+ ):
432
451
  w.setVisible(False)
433
452
  for w in [self.leModifier, self.leCode, self.pbAddModifier, self.pbModifyModifier]:
434
453
  w.setEnabled(False)
@@ -500,6 +519,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
500
519
  "name": "",
501
520
  "description": "",
502
521
  "type": cfg.SINGLE_SELECTION,
522
+ "ask at stop": False,
503
523
  "values": [],
504
524
  }
505
525
 
@@ -530,6 +550,7 @@ class addModifierDialog(QDialog, Ui_Dialog):
530
550
  "name": "",
531
551
  "description": "",
532
552
  "type": cfg.SINGLE_SELECTION,
553
+ "ask at stop": False,
533
554
  "values": [],
534
555
  }
535
556
 
@@ -582,6 +603,8 @@ class addModifierDialog(QDialog, Ui_Dialog):
582
603
  self.lwModifiers.clear()
583
604
  self.leCode.clear()
584
605
  self.leModifier.clear()
606
+ # if self.ask_at_stop_enabled:
607
+ # self.cb_ask_at_stop.setChecked(False)
585
608
 
586
609
  self.tabMem = tabIndex
587
610
 
@@ -589,14 +612,21 @@ class addModifierDialog(QDialog, Ui_Dialog):
589
612
  self.le_name.setText(self.modifiers_sets_dict[str(tabIndex)]["name"])
590
613
  self.le_description.setText(self.modifiers_sets_dict[str(tabIndex)].get("description", ""))
591
614
  self.cbType.setCurrentIndex(self.modifiers_sets_dict[str(tabIndex)]["type"])
615
+ # if self.ask_at_stop_enabled:
616
+ # self.cb_ask_at_stop.setChecked(self.modifiers_sets_dict[str(tabIndex)].get("ask at stop", False))
617
+
592
618
  self.lwModifiers.addItems(self.modifiers_sets_dict[str(tabIndex)]["values"])
593
619
 
594
- def getModifiers(self) -> str:
620
+ def get_modifiers(self) -> str:
595
621
  """
596
622
  returns modifiers as string
597
623
  """
598
- keys_to_delete = []
624
+ keys_to_delete: list = []
599
625
  for idx in self.modifiers_sets_dict:
626
+ # add ask_at_stop value (boolean) to each set of modifiers
627
+ if self.ask_at_stop_enabled:
628
+ self.modifiers_sets_dict[idx]["ask at stop"] = self.cb_ask_at_stop.isChecked()
629
+ # delete modifiers without values for selection
600
630
  if (
601
631
  self.modifiers_sets_dict[idx]["type"] in (cfg.SINGLE_SELECTION, cfg.MULTI_SELECTION)
602
632
  and not self.modifiers_sets_dict[idx]["values"]
boris/add_modifier_ui.py CHANGED
@@ -1,8 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- # Form implementation generated from reading ui file 'add_modifier.ui'
3
+ # Form implementation generated from reading ui file 'boris/add_modifier.ui'
4
4
  #
5
- # Created by: PyQt5 UI code generator 5.15.7
5
+ # Created by: PyQt5 UI code generator 5.15.6
6
6
  #
7
7
  # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8
8
  # run again. Do not edit this file unless you know what you are doing.
@@ -14,9 +14,12 @@ from PyQt5 import QtCore, QtGui, QtWidgets
14
14
  class Ui_Dialog(object):
15
15
  def setupUi(self, Dialog):
16
16
  Dialog.setObjectName("Dialog")
17
- Dialog.resize(638, 636)
17
+ Dialog.resize(1088, 654)
18
18
  self.verticalLayout_5 = QtWidgets.QVBoxLayout(Dialog)
19
19
  self.verticalLayout_5.setObjectName("verticalLayout_5")
20
+ self.cb_ask_at_stop = QtWidgets.QCheckBox(Dialog)
21
+ self.cb_ask_at_stop.setObjectName("cb_ask_at_stop")
22
+ self.verticalLayout_5.addWidget(self.cb_ask_at_stop)
20
23
  self.verticalLayout_4 = QtWidgets.QVBoxLayout()
21
24
  self.verticalLayout_4.setObjectName("verticalLayout_4")
22
25
  self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
@@ -101,10 +104,10 @@ class Ui_Dialog(object):
101
104
  self.pbMoveDown = QtWidgets.QPushButton(Dialog)
102
105
  self.pbMoveDown.setObjectName("pbMoveDown")
103
106
  self.horizontalLayout.addWidget(self.pbMoveDown)
104
- self.verticalLayout.addLayout(self.horizontalLayout)
105
107
  self.pbRemoveModifier = QtWidgets.QPushButton(Dialog)
106
108
  self.pbRemoveModifier.setObjectName("pbRemoveModifier")
107
- self.verticalLayout.addWidget(self.pbRemoveModifier)
109
+ self.horizontalLayout.addWidget(self.pbRemoveModifier)
110
+ self.verticalLayout.addLayout(self.horizontalLayout)
108
111
  self.pb_sort_modifiers = QtWidgets.QPushButton(Dialog)
109
112
  self.pb_sort_modifiers.setObjectName("pb_sort_modifiers")
110
113
  self.verticalLayout.addWidget(self.pb_sort_modifiers)
@@ -156,6 +159,7 @@ class Ui_Dialog(object):
156
159
  def retranslateUi(self, Dialog):
157
160
  _translate = QtCore.QCoreApplication.translate
158
161
  Dialog.setWindowTitle(_translate("Dialog", "Set modifiers"))
162
+ self.cb_ask_at_stop.setText(_translate("Dialog", "Ask for modifier(s) when behavior stops"))
159
163
  self.lbModifier.setText(_translate("Dialog", "Modifier"))
160
164
  self.lbCode.setText(_translate("Dialog", "Key code"))
161
165
  self.lbCodeHelp.setText(_translate("Dialog", "Key code is case sensitive. Type one character or a function key (F1, F2... F12)"))
@@ -155,7 +155,7 @@ class Advanced_event_filtering_dialog(QDialog):
155
155
  hbox.addItem(QSpacerItem(241, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
156
156
  self.pb_save = QPushButton("Save results", clicked=self.save_results)
157
157
  hbox.addWidget(self.pb_save)
158
- self.pb_close = QPushButton("Close", clicked=self.close)
158
+ self.pb_close = QPushButton(cfg.CLOSE, clicked=self.close)
159
159
  hbox.addWidget(self.pb_close)
160
160
  vbox.addLayout(hbox)
161
161
 
@@ -429,7 +429,7 @@ def event_filtering(self):
429
429
  for row in cursor.fetchall():
430
430
  obs, subj, behav, start, stop = row
431
431
  if obs not in events:
432
- events[obs]: dict = {}
432
+ events[obs] = {}
433
433
 
434
434
  # use function in base at event (state or point)
435
435
  interval_func = icc if start == stop else ico
@@ -138,7 +138,7 @@ class BehaviorsMapCreatorWindow(QMainWindow):
138
138
  self.addToProject.triggered.connect(self.add_to_project)
139
139
 
140
140
  self.exitAction = QAction(QIcon(), "&Close", self)
141
- self.exitAction.setStatusTip("Close")
141
+ self.exitAction.setStatusTip(cfg.CLOSE)
142
142
  self.exitAction.triggered.connect(self.close)
143
143
 
144
144
  menubar = self.menuBar()
@@ -102,7 +102,7 @@ class BehaviorsCodingMapWindowClass(QWidget):
102
102
  self.leareaCode = QLineEdit(self)
103
103
  hBoxLayout1.addWidget(self.leareaCode)
104
104
 
105
- self.btClose = QPushButton("Close")
105
+ self.btClose = QPushButton(cfg.CLOSE)
106
106
  self.btClose.clicked.connect(self.close)
107
107
  hBoxLayout1.addWidget(self.btClose)
108
108
 
boris/config.py CHANGED
@@ -82,6 +82,7 @@ EVENTS = "events"
82
82
  TIME_OFFSET = "time offset"
83
83
 
84
84
  CODING_MAP = "coding_map"
85
+ CODING_MAP_sp = "coding map" # space between words (no underscore)
85
86
  BEHAVIORS_CODING_MAP = "behaviors_coding_map"
86
87
  SUBJECTS = "subjects_conf"
87
88
  ETHOGRAM = "behaviors_conf"
@@ -139,6 +140,7 @@ YES = "Yes"
139
140
  NO = "No"
140
141
  CANCEL = "Cancel"
141
142
  APPEND = "Append"
143
+ CLOSE = "Close"
142
144
  REPLACE = "Replace"
143
145
  REMOVE = "Remove"
144
146
  SAVE = "Save"
@@ -210,17 +212,6 @@ TIME_LAPSE = "time_lapse_delay"
210
212
 
211
213
 
212
214
  # fields for event configuration
213
- """
214
- fields = {
215
- "type": 0,
216
- "key": 1,
217
- "code": 2,
218
- "description": 3,
219
- "modifiers": 4,
220
- "excluded": 5,
221
- "coding map": 6,
222
- }
223
- """
224
215
 
225
216
  ETHOGRAM_TABLE_COLUMNS: dict = {
226
217
  0: "key",
@@ -245,18 +236,6 @@ behavioursFields: dict = {
245
236
  "excluded": 7,
246
237
  "coding map": 8,
247
238
  }
248
- """
249
- ETHOGRAM_FIELDS = [
250
- "type",
251
- "key",
252
- "code",
253
- "description",
254
- "category",
255
- "modifiers",
256
- "excluded",
257
- "coding map",
258
- ]
259
- """
260
239
  ETHOGRAM_EDITABLE_FIELDS: tuple = ("key", "code", "description")
261
240
 
262
241
  PROJECT_BEHAVIORS_KEY_FIELD_IDX = 1
@@ -471,6 +450,9 @@ WAVEFORM_PLOT = "waveform"
471
450
  SPECTROGRAM_PLOT = "spectrogram"
472
451
  EVENTS_PLOT = "plot_events"
473
452
 
453
+ PLAYING = "playing"
454
+ PAUSED = "paused"
455
+ STOPPED = "stopped"
474
456
 
475
457
  POINT_EVENT_ST_DURATION = 0.5
476
458
 
@@ -481,6 +463,8 @@ SLIDER_MAXIMUM = 1000
481
463
 
482
464
  FRAME_DEFAULT_CACHE_SIZE = 1
483
465
 
466
+ EXCLUDED = "excluded"
467
+
484
468
  # modifiers
485
469
  MODIFIERS = "modifiers"
486
470
  SINGLE_SELECTION = 0
boris/config_file.py CHANGED
@@ -316,8 +316,6 @@ def save(self, lastCheckForNewVersion=0):
316
316
 
317
317
  settings = QSettings(str(file_path), QSettings.IniFormat)
318
318
 
319
- print(f"{self.config_param=}")
320
-
321
319
  settings.setValue("config", self.config_param)
322
320
 
323
321
  settings.setValue("geometry", self.saveGeometry())
boris/core.py CHANGED
@@ -20,7 +20,6 @@ This file is part of BORIS.
20
20
 
21
21
  """
22
22
 
23
-
24
23
  import os
25
24
  import sys
26
25
 
@@ -1365,13 +1364,14 @@ class MainWindow(QMainWindow, Ui_MainWindow):
1365
1364
 
1366
1365
  try:
1367
1366
  versionURL = "https://www.boris.unito.it/static/ver4.dat"
1368
- lastVersion = urllib.request.urlopen(versionURL).read().strip().decode("utf-8")
1369
- if util.versiontuple(lastVersion) > util.versiontuple(__version__):
1367
+ last_version = urllib.request.urlopen(versionURL).read().strip().decode("utf-8")
1368
+ if util.versiontuple(last_version) > util.versiontuple(__version__):
1370
1369
  msg = (
1371
- f"A new version is available: v. <b>{lastVersion}</b><br>"
1370
+ f"A new version is available: v. <b>{last_version}</b><br>"
1372
1371
  'Go to <a href="https://www.boris.unito.it">'
1373
1372
  "https://www.boris.unito.it</a> to install it."
1374
1373
  )
1374
+ # https://github.com/olivierfriard/BORIS/archive/refs/tags/v{last_version}.zip
1375
1375
  else:
1376
1376
  msg = f"The version you are using is the last one: <b>{__version__}</b>"
1377
1377
  newsURL = "https://www.boris.unito.it/static/news.dat"
@@ -3611,6 +3611,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
3611
3611
  if dialog.MessageDialog(cfg.programName, "Delete the current events?", (cfg.YES, cfg.NO)) == cfg.YES:
3612
3612
  self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS] = []
3613
3613
  self.project_changed()
3614
+ self.load_tw_events(self.observationId)
3614
3615
 
3615
3616
  self.pb_live_obs.setText("Stop live observation")
3616
3617
 
@@ -4651,9 +4652,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
4651
4652
 
4652
4653
  event = dict(self.pj[cfg.ETHOGRAM][behavior_idx])
4653
4654
  # check if coding map for modifiers
4654
- if "coding map" in self.pj[cfg.ETHOGRAM][behavior_idx] and self.pj[cfg.ETHOGRAM][behavior_idx]["coding map"]:
4655
+ if util.has_coding_map(self.pj[cfg.ETHOGRAM], behavior_idx):
4655
4656
  # pause if media and media playing
4656
- if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE] in [cfg.MEDIA]:
4657
+ if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE] == cfg.MEDIA:
4657
4658
  if self.playerType == cfg.MEDIA:
4658
4659
  if self.is_playing():
4659
4660
  flag_player_playing = True
boris/dialog.py CHANGED
@@ -1027,8 +1027,8 @@ class FindInEvents(QWidget):
1027
1027
  hbox2 = QHBoxLayout()
1028
1028
  self.pbOK = QPushButton("Find")
1029
1029
  self.pbOK.clicked.connect(lambda: self.click("FIND"))
1030
- self.pbCancel = QPushButton("Close")
1031
- self.pbCancel.clicked.connect(lambda: self.click("CLOSE"))
1030
+ self.pbCancel = QPushButton(cfg.CLOSE)
1031
+ self.pbCancel.clicked.connect(lambda: self.click(cfg.CLOSE))
1032
1032
  hbox2.addWidget(self.pbCancel)
1033
1033
  hbox2.addWidget(self.pbOK)
1034
1034
  hbox.addLayout(hbox2)
@@ -182,7 +182,7 @@ class wgMeasurement(QDialog):
182
182
 
183
183
  self.pb_save = QPushButton("Save results", clicked=self.pb_save_clicked)
184
184
  hbox3.addWidget(self.pb_save)
185
- self.pb_close = QPushButton("Close", clicked=self.pbClose_clicked)
185
+ self.pb_close = QPushButton(cfg.CLOSE, clicked=self.pbClose_clicked)
186
186
  hbox3.addWidget(self.pb_close)
187
187
  vbox.addLayout(hbox3)
188
188
 
@@ -111,7 +111,7 @@ class wgMeasurement(QWidget):
111
111
  self.pbSave = QPushButton("Save results", clicked=self.pbSave_clicked)
112
112
  hbox3.addWidget(self.pbSave)
113
113
 
114
- self.pbClose = QPushButton("Close", clicked=self.pbClose_clicked)
114
+ self.pbClose = QPushButton(cfg.CLOSE, clicked=self.pbClose_clicked)
115
115
  hbox3.addWidget(self.pbClose)
116
116
 
117
117
  vbox.addLayout(hbox3)
boris/observation.py CHANGED
@@ -706,7 +706,7 @@ class Observation(QDialog, Ui_Form):
706
706
  w = dialog.View_data()
707
707
  w.setWindowTitle("View data")
708
708
  w.lb.setText(f"View first and last rows of <b>{pl.Path(data_file_path).name}</b> file")
709
- w.pbOK.setText("Close")
709
+ w.pbOK.setText(cfg.CLOSE)
710
710
  w.label.setText("Index of columns to plot")
711
711
  w.le.setEnabled(False)
712
712
  w.le.setText(columns_to_plot)
boris/otx_parser.py CHANGED
@@ -31,7 +31,7 @@ import zipfile
31
31
  import pathlib as pl
32
32
  from xml.dom import minidom
33
33
  import logging
34
- from typing import Optional, Tuple
34
+ from typing import Tuple
35
35
 
36
36
  try:
37
37
  from . import config as cfg
boris/preferences.py CHANGED
@@ -204,8 +204,6 @@ def preferences(self):
204
204
  preferencesWindow.sb_toolbar_icon_size.setValue(self.config_param.get(cfg.TOOLBAR_ICON_SIZE, cfg.DEFAULT_TOOLBAR_ICON_SIZE_VALUE))
205
205
  preferencesWindow.cb_darkmode.setChecked(self.config_param.get(cfg.DARK_MODE, cfg.DARK_MODE_DEFAULT_VALUE))
206
206
 
207
- self.config_param[cfg.DARK_MODE] = preferencesWindow.cb_darkmode.isChecked()
208
-
209
207
  gui_utilities.restore_geometry(preferencesWindow, "preferences", (700, 500))
210
208
 
211
209
  if preferencesWindow.exec_():
boris/project.py CHANGED
@@ -760,7 +760,7 @@ class projectDialog(QDialog, Ui_dlgProject):
760
760
  # check if double click on 'coding map' column
761
761
  if column == cfg.behavioursFields["coding map"]:
762
762
  if "with coding map" in self.twBehaviors.item(row, cfg.behavioursFields[cfg.TYPE]).text():
763
- self.behaviorTypeChanged(row)
763
+ self.behavior_type_changed(row)
764
764
  else:
765
765
  QMessageBox.information(self, cfg.programName, "Change the behavior type on first column to select a coding map")
766
766
 
@@ -790,10 +790,15 @@ class projectDialog(QDialog, Ui_dlgProject):
790
790
  subjectName = self.twSubjects.item(subject_row, 1).text().strip() if self.twSubjects.item(subject_row, 1) else ""
791
791
  subjects_list.append((subjectName, key))
792
792
 
793
- addModifierWindow = add_modifier.addModifierDialog(self.twBehaviors.item(row, column).text(), subjects=subjects_list)
793
+ addModifierWindow = add_modifier.addModifierDialog(
794
+ self.twBehaviors.item(row, column).text(),
795
+ subjects=subjects_list,
796
+ ask_at_stop_enabled=self.twBehaviors.item(row, cfg.behavioursFields["type"]).text() == cfg.STATE_EVENT,
797
+ )
794
798
  addModifierWindow.setWindowTitle(f'Set modifiers for "{self.twBehaviors.item(row, 2).text()}" behavior')
799
+
795
800
  if addModifierWindow.exec_():
796
- self.twBehaviors.item(row, column).setText(addModifierWindow.getModifiers())
801
+ self.twBehaviors.item(row, column).setText(addModifierWindow.get_modifiers())
797
802
 
798
803
  def behavior_type_doubleclicked(self, row):
799
804
  """
@@ -810,7 +815,7 @@ class projectDialog(QDialog, Ui_dlgProject):
810
815
  if ok and new_type:
811
816
  self.twBehaviors.item(row, cfg.behavioursFields["type"]).setText(new_type)
812
817
 
813
- self.behaviorTypeChanged(row)
818
+ self.behavior_type_changed(row)
814
819
 
815
820
  def color_doubleclicked(self, row: int) -> None:
816
821
  """
@@ -1325,16 +1330,16 @@ class projectDialog(QDialog, Ui_dlgProject):
1325
1330
  self.twBehaviors.setItem(self.twBehaviors.rowCount() - 1, cfg.behavioursFields[field_type], item)
1326
1331
  self.twBehaviors.scrollToBottom()
1327
1332
 
1328
- def behaviorTypeChanged(self, row):
1333
+ def behavior_type_changed(self, row: int) -> None:
1329
1334
  """
1330
1335
  event type combobox changed
1331
1336
  """
1332
1337
 
1333
- if "with coding map" in self.twBehaviors.item(row, cfg.behavioursFields[cfg.TYPE]).text():
1338
+ if cfg.CODING_MAP_sp in self.twBehaviors.item(row, cfg.behavioursFields[cfg.TYPE]).text():
1334
1339
  # let user select a coding maop
1335
1340
  fn = QFileDialog().getOpenFileName(
1336
1341
  self,
1337
- "Select a coding map for " f"{self.twBehaviors.item(row, cfg.behavioursFields['code']).text()} behavior",
1342
+ "Select a modifier coding map for " f"{self.twBehaviors.item(row, cfg.behavioursFields['code']).text()} behavior",
1338
1343
  "",
1339
1344
  "BORIS map files (*.boris_map);;All files (*)",
1340
1345
  )
@@ -1344,12 +1349,12 @@ class projectDialog(QDialog, Ui_dlgProject):
1344
1349
  try:
1345
1350
  new_map = json.loads(open(fileName, "r").read())
1346
1351
  except Exception:
1347
- QMessageBox.critical(self, cfg.programName, "Error reding the file")
1352
+ QMessageBox.critical(self, cfg.programName, "Error reding the coding map")
1348
1353
  return
1349
1354
  self.pj[cfg.CODING_MAP][new_map["name"]] = new_map
1350
1355
 
1351
1356
  # add modifiers from coding map areas
1352
- modifstr = str(
1357
+ modifstr = json.dumps(
1353
1358
  {
1354
1359
  "0": {
1355
1360
  "name": new_map["name"],
@@ -1581,7 +1586,7 @@ class projectDialog(QDialog, Ui_dlgProject):
1581
1586
  def check_ethogram(self) -> dict:
1582
1587
  """
1583
1588
  check ethogram for various parameter
1584
- returns ethogram dict or {cfg.CANCEL: True"} in case of error
1589
+ returns ethogram dict or {cfg.CANCEL: True} in case of error
1585
1590
 
1586
1591
  """
1587
1592
  # store behaviors
@@ -1602,7 +1607,11 @@ class projectDialog(QDialog, Ui_dlgProject):
1602
1607
 
1603
1608
  if self.twBehaviors.item(r, cfg.behavioursFields["modifiers"]).text():
1604
1609
  try:
1605
- modifiers_dict = eval(self.twBehaviors.item(r, cfg.behavioursFields["modifiers"]).text())
1610
+ modifiers_dict = (
1611
+ json.loads(self.twBehaviors.item(r, cfg.behavioursFields["modifiers"]).text())
1612
+ if self.twBehaviors.item(r, cfg.behavioursFields["modifiers"]).text()
1613
+ else {}
1614
+ )
1606
1615
  for k in modifiers_dict:
1607
1616
  for value in modifiers_dict[k]["values"]:
1608
1617
  modif_code = value.split(" (")[0]
@@ -1672,7 +1681,7 @@ class projectDialog(QDialog, Ui_dlgProject):
1672
1681
  if field == "modifiers" and row["modifiers"]:
1673
1682
  if remove_leading_trailing_spaces_in_modifiers == cfg.YES:
1674
1683
  try:
1675
- modifiers_dict = eval(row["modifiers"])
1684
+ modifiers_dict = json.loads(row["modifiers"]) if row["modifiers"] else {}
1676
1685
  for k in modifiers_dict:
1677
1686
  for idx, value in enumerate(modifiers_dict[k]["values"]):
1678
1687
  modif_code = value.split(" (")[0]
@@ -1688,7 +1697,13 @@ class projectDialog(QDialog, Ui_dlgProject):
1688
1697
  QMessageBox.critical(self, cfg.programName, "Error removing leading/trailing spaces in modifiers")
1689
1698
 
1690
1699
  else:
1691
- row["modifiers"] = eval(row["modifiers"])
1700
+ """
1701
+ if row["modifiers"]:
1702
+ row["modifiers"] = eval(row["modifiers"])
1703
+ else:
1704
+ row["modifiers"] = {}
1705
+ """
1706
+ row["modifiers"] = json.loads(row["modifiers"]) if row["modifiers"] else {}
1692
1707
  else:
1693
1708
  row[field] = ""
1694
1709
 
@@ -1714,7 +1729,7 @@ class projectDialog(QDialog, Ui_dlgProject):
1714
1729
  return {cfg.CANCEL: True}
1715
1730
 
1716
1731
  # check if behavior belong to category that is not in categories list
1717
- behavior_category = []
1732
+ behavior_category: list = []
1718
1733
  for idx in checked_ethogram:
1719
1734
  if cfg.BEHAVIOR_CATEGORY in checked_ethogram[idx]:
1720
1735
  if checked_ethogram[idx][cfg.BEHAVIOR_CATEGORY]: