boris-behav-obs 9.3.3__py2.py3-none-any.whl → 9.3.4__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/core_qrc.py +6580 -6784
- boris/dialog.py +73 -4
- boris/event_operations.py +14 -2
- boris/observation_operations.py +18 -9
- boris/project.py +11 -9
- boris/project_functions.py +38 -14
- boris/utilities.py +1 -1
- boris/version.py +2 -2
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.4.dist-info}/METADATA +2 -2
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.4.dist-info}/RECORD +14 -14
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.4.dist-info}/WHEEL +0 -0
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.4.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.4.dist-info}/licenses/LICENSE.TXT +0 -0
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.4.dist-info}/top_level.txt +0 -0
boris/dialog.py
CHANGED
|
@@ -184,7 +184,7 @@ class Info_widget(QWidget):
|
|
|
184
184
|
|
|
185
185
|
class get_time_widget(QWidget):
|
|
186
186
|
"""
|
|
187
|
-
widget for selecting a time in various formats:
|
|
187
|
+
widget for selecting a time in various formats: seconds, HH:MM:SS:ZZZ or YYYY-mm-DD HH:MM:SS:ZZZ
|
|
188
188
|
"""
|
|
189
189
|
|
|
190
190
|
def __init__(self, time_value=dec(0), parent=None):
|
|
@@ -408,7 +408,7 @@ class get_time_widget(QWidget):
|
|
|
408
408
|
if self.pb_sign.text() == "-":
|
|
409
409
|
time_sec = -time_sec
|
|
410
410
|
|
|
411
|
-
return dec(time_sec) if time_sec is not None else None
|
|
411
|
+
return dec(time_sec).quantize(dec("0.001")) if time_sec is not None else None
|
|
412
412
|
|
|
413
413
|
def set_time(self, new_time: dec) -> None:
|
|
414
414
|
"""
|
|
@@ -440,6 +440,11 @@ class get_time_widget(QWidget):
|
|
|
440
440
|
|
|
441
441
|
|
|
442
442
|
class Ask_time(QDialog):
|
|
443
|
+
"""
|
|
444
|
+
Qdialog class for asking time to user
|
|
445
|
+
User can select a time format between seconds, HHMMSS.zzz or YYY-mm-DD HH:MM:SS.zzz
|
|
446
|
+
"""
|
|
447
|
+
|
|
443
448
|
def __init__(self, time_value=0):
|
|
444
449
|
super().__init__()
|
|
445
450
|
self.setWindowTitle("")
|
|
@@ -453,10 +458,10 @@ class Ask_time(QDialog):
|
|
|
453
458
|
|
|
454
459
|
hbox.addWidget(self.time_widget)
|
|
455
460
|
|
|
456
|
-
self.pbOK = QPushButton(
|
|
461
|
+
self.pbOK = QPushButton(cfg.OK, clicked=self.pb_ok_clicked)
|
|
457
462
|
self.pbOK.setDefault(True)
|
|
458
463
|
|
|
459
|
-
self.pbCancel = QPushButton(
|
|
464
|
+
self.pbCancel = QPushButton(cfg.CANCEL)
|
|
460
465
|
self.pbCancel.clicked.connect(self.reject)
|
|
461
466
|
|
|
462
467
|
self.hbox2 = QHBoxLayout(self)
|
|
@@ -975,6 +980,70 @@ class Results_dialog(QDialog):
|
|
|
975
980
|
self.done(cfg.SAVE_DATASET)
|
|
976
981
|
|
|
977
982
|
|
|
983
|
+
class Results_dialog_exit_code(QDialog):
|
|
984
|
+
"""
|
|
985
|
+
widget for visualizing text output
|
|
986
|
+
"""
|
|
987
|
+
|
|
988
|
+
def __init__(self):
|
|
989
|
+
super().__init__()
|
|
990
|
+
|
|
991
|
+
self.dataset = False
|
|
992
|
+
|
|
993
|
+
self.setWindowTitle("")
|
|
994
|
+
|
|
995
|
+
hbox = QVBoxLayout()
|
|
996
|
+
|
|
997
|
+
self.lb = QLabel("")
|
|
998
|
+
hbox.addWidget(self.lb)
|
|
999
|
+
|
|
1000
|
+
self.ptText = QPlainTextEdit()
|
|
1001
|
+
self.ptText.setReadOnly(True)
|
|
1002
|
+
hbox.addWidget(self.ptText)
|
|
1003
|
+
|
|
1004
|
+
hbox2 = QHBoxLayout()
|
|
1005
|
+
hbox2.addItem(QSpacerItem(241, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
|
|
1006
|
+
|
|
1007
|
+
self.pbSave = QPushButton("Save results", clicked=self.save_results)
|
|
1008
|
+
hbox2.addWidget(self.pbSave)
|
|
1009
|
+
|
|
1010
|
+
self.pb1 = QPushButton("1", clicked=lambda: self.done_(1))
|
|
1011
|
+
hbox2.addWidget(self.pb1)
|
|
1012
|
+
|
|
1013
|
+
self.pb2 = QPushButton("2", clicked=lambda: self.done_(2))
|
|
1014
|
+
hbox2.addWidget(self.pb2)
|
|
1015
|
+
|
|
1016
|
+
self.pb3 = QPushButton("3", clicked=lambda: self.done_(3))
|
|
1017
|
+
hbox2.addWidget(self.pb3)
|
|
1018
|
+
|
|
1019
|
+
hbox.addLayout(hbox2)
|
|
1020
|
+
self.setLayout(hbox)
|
|
1021
|
+
|
|
1022
|
+
self.resize(800, 640)
|
|
1023
|
+
|
|
1024
|
+
def done_(self, status):
|
|
1025
|
+
self.done(status)
|
|
1026
|
+
|
|
1027
|
+
def save_results(self):
|
|
1028
|
+
"""
|
|
1029
|
+
save content of self.ptText
|
|
1030
|
+
"""
|
|
1031
|
+
|
|
1032
|
+
if not self.dataset:
|
|
1033
|
+
file_name, _ = QFileDialog().getSaveFileName(self, "Save results", "", "Text files (*.txt *.tsv);;All files (*)")
|
|
1034
|
+
|
|
1035
|
+
if not file_name:
|
|
1036
|
+
return
|
|
1037
|
+
try:
|
|
1038
|
+
with open(file_name, "w") as f:
|
|
1039
|
+
f.write(self.ptText.toPlainText())
|
|
1040
|
+
except Exception:
|
|
1041
|
+
QMessageBox.critical(self, cfg.programName, f"The file {file_name} can not be saved")
|
|
1042
|
+
|
|
1043
|
+
else:
|
|
1044
|
+
self.done(cfg.SAVE_DATASET)
|
|
1045
|
+
|
|
1046
|
+
|
|
978
1047
|
class View_data(QDialog):
|
|
979
1048
|
"""
|
|
980
1049
|
widget for visualizing rows of data file
|
boris/event_operations.py
CHANGED
|
@@ -576,6 +576,8 @@ def edit_event(self):
|
|
|
576
576
|
|
|
577
577
|
pj_event_idx = self.tv_idx2events_idx[tvevents_row]
|
|
578
578
|
|
|
579
|
+
print(f"{self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS]=}")
|
|
580
|
+
|
|
579
581
|
time_value = self.pj[cfg.OBSERVATIONS][self.observationId][cfg.EVENTS][pj_event_idx][
|
|
580
582
|
cfg.PJ_OBS_FIELDS[self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE]][cfg.TIME]
|
|
581
583
|
]
|
|
@@ -601,9 +603,12 @@ def edit_event(self):
|
|
|
601
603
|
)
|
|
602
604
|
edit_window.setWindowTitle("Edit event")
|
|
603
605
|
|
|
606
|
+
print(f"{time_value=}")
|
|
607
|
+
|
|
604
608
|
# time
|
|
605
609
|
if time_value.is_nan():
|
|
606
610
|
edit_window.cb_set_time_na.setChecked(True)
|
|
611
|
+
|
|
607
612
|
if self.playerType in (cfg.VIEWER_MEDIA, cfg.VIEWER_LIVE, cfg.VIEWER_IMAGES):
|
|
608
613
|
edit_window.pb_set_to_current_time.setVisible(False)
|
|
609
614
|
|
|
@@ -673,12 +678,15 @@ def edit_event(self):
|
|
|
673
678
|
|
|
674
679
|
flag_ok = False # for looping until event is OK or Cancel pressed
|
|
675
680
|
while True:
|
|
676
|
-
if edit_window.
|
|
681
|
+
if edit_window.exec(): # button OK
|
|
677
682
|
self.project_changed()
|
|
678
683
|
|
|
679
684
|
# MEDIA / LIVE
|
|
680
685
|
if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
|
|
681
686
|
new_time = edit_window.time_widget.get_time()
|
|
687
|
+
|
|
688
|
+
print(f"{new_time=}")
|
|
689
|
+
|
|
682
690
|
if new_time is None:
|
|
683
691
|
QMessageBox.warning(
|
|
684
692
|
self,
|
|
@@ -747,7 +755,11 @@ def edit_event(self):
|
|
|
747
755
|
for key in self.pj[cfg.ETHOGRAM]:
|
|
748
756
|
if self.pj[cfg.ETHOGRAM][key][cfg.BEHAVIOR_CODE] == edit_window.cobCode.currentText():
|
|
749
757
|
event = self.full_event(key)
|
|
750
|
-
if
|
|
758
|
+
if (
|
|
759
|
+
edit_window.time_value == cfg.NA
|
|
760
|
+
or (isinstance(edit_window.time_value, dec) and edit_window.time_value.is_nan())
|
|
761
|
+
or (edit_window.cb_set_time_na.isChecked())
|
|
762
|
+
):
|
|
751
763
|
event[cfg.TIME] = dec("NaN")
|
|
752
764
|
else:
|
|
753
765
|
event[cfg.TIME] = edit_window.time_widget.get_time()
|
boris/observation_operations.py
CHANGED
|
@@ -1100,7 +1100,7 @@ def close_observation(self):
|
|
|
1100
1100
|
|
|
1101
1101
|
logging.info(f"Close observation (player type: {self.playerType})")
|
|
1102
1102
|
|
|
1103
|
-
# check observation events
|
|
1103
|
+
# check observation state events
|
|
1104
1104
|
|
|
1105
1105
|
flag_ok, msg = project_functions.check_state_events_obs(
|
|
1106
1106
|
self.observationId,
|
|
@@ -1111,16 +1111,22 @@ def close_observation(self):
|
|
|
1111
1111
|
|
|
1112
1112
|
if not flag_ok:
|
|
1113
1113
|
out = f"The current observation has state event(s) that are not PAIRED:<br><br>{msg}"
|
|
1114
|
-
results = dialog.
|
|
1114
|
+
results = dialog.Results_dialog_exit_code()
|
|
1115
1115
|
results.setWindowTitle(f"{cfg.programName} - Check selected observations")
|
|
1116
1116
|
results.ptText.setReadOnly(True)
|
|
1117
1117
|
results.ptText.appendHtml(out)
|
|
1118
|
-
results.pbSave.setVisible(False)
|
|
1119
|
-
results.pbCancel.setText("Close observation")
|
|
1120
|
-
results.pbCancel.setVisible(True)
|
|
1121
|
-
results.pbOK.setText("Fix unpaired state events")
|
|
1122
1118
|
|
|
1123
|
-
|
|
1119
|
+
results.pb1.setText("Close observation")
|
|
1120
|
+
results.pb2.setText("Return to observation")
|
|
1121
|
+
if self.playerType == cfg.IMAGES:
|
|
1122
|
+
results.pb3.setVisible(False)
|
|
1123
|
+
else:
|
|
1124
|
+
results.pb3.setText("Fix unpaired state events")
|
|
1125
|
+
|
|
1126
|
+
r = results.exec()
|
|
1127
|
+
if r == 2: # Return to observation
|
|
1128
|
+
return
|
|
1129
|
+
if r == 3: # Fix unpaired state events
|
|
1124
1130
|
state_events.fix_unpaired_events(self, silent_mode=True)
|
|
1125
1131
|
|
|
1126
1132
|
self.saved_state = self.saveState()
|
|
@@ -2407,8 +2413,11 @@ def event2media_file_name(observation: dict, timestamp: dec) -> Optional[str]:
|
|
|
2407
2413
|
|
|
2408
2414
|
cumul_media_durations: list = [dec(0)]
|
|
2409
2415
|
for media_file in observation[cfg.FILE][cfg.PLAYER1]:
|
|
2410
|
-
|
|
2411
|
-
|
|
2416
|
+
try:
|
|
2417
|
+
media_duration = dec(str(observation[cfg.MEDIA_INFO][cfg.LENGTH][media_file]))
|
|
2418
|
+
cumul_media_durations.append(round(cumul_media_durations[-1] + media_duration, 3))
|
|
2419
|
+
except KeyError:
|
|
2420
|
+
return None
|
|
2412
2421
|
|
|
2413
2422
|
cumul_media_durations.remove(dec(0))
|
|
2414
2423
|
|
boris/project.py
CHANGED
|
@@ -150,12 +150,14 @@ class BehavioralCategories(QDialog):
|
|
|
150
150
|
sorted([pj[cfg.ETHOGRAM][idx].get(cfg.BEHAVIOR_CATEGORY, "") for idx in pj.get(cfg.ETHOGRAM, {})])
|
|
151
151
|
)
|
|
152
152
|
|
|
153
|
-
if behavioral_categories_in_ethogram.difference(set(behavioral_categories))
|
|
153
|
+
if behavioral_categories_in_ethogram.difference(set(behavioral_categories)) and behavioral_categories_in_ethogram.difference(
|
|
154
|
+
set(behavioral_categories)
|
|
155
|
+
) != {""}:
|
|
154
156
|
if (
|
|
155
157
|
dialog.MessageDialog(
|
|
156
158
|
cfg.programName,
|
|
157
159
|
(
|
|
158
|
-
"
|
|
160
|
+
"There are behavioral categories that are present in ethogram but not defined.<br>"
|
|
159
161
|
f"{behavioral_categories_in_ethogram.difference(set(behavioral_categories))}<br>"
|
|
160
162
|
"<br>"
|
|
161
163
|
"Do you want to add them in the behavioral categories list?"
|
|
@@ -210,7 +212,6 @@ class BehavioralCategories(QDialog):
|
|
|
210
212
|
color = col_diag.currentColor()
|
|
211
213
|
if color.name() == "#000000": # black -> delete color
|
|
212
214
|
self.lw.item(row, 1).setText("")
|
|
213
|
-
# self.lw.item(row, 1).setBackground(QColor(230, 230, 230))
|
|
214
215
|
self.lw.item(row, 1).setBackground(self.not_editable_column_color())
|
|
215
216
|
elif color.isValid():
|
|
216
217
|
self.lw.item(row, 1).setText(color.name())
|
|
@@ -820,18 +821,18 @@ class projectDialog(QDialog, Ui_dlgProject):
|
|
|
820
821
|
column (int): column double-clicked
|
|
821
822
|
"""
|
|
822
823
|
|
|
823
|
-
#
|
|
824
|
+
# excluded column
|
|
824
825
|
if column == cfg.behavioursFields[cfg.EXCLUDED]:
|
|
825
826
|
self.exclusion_matrix()
|
|
826
827
|
|
|
827
|
-
#
|
|
828
|
+
# coding map
|
|
828
829
|
if column == cfg.behavioursFields[cfg.CODING_MAP_sp]:
|
|
829
830
|
if "with coding map" in self.twBehaviors.item(row, cfg.behavioursFields[cfg.TYPE]).text():
|
|
830
831
|
self.behavior_type_changed(row)
|
|
831
832
|
else:
|
|
832
833
|
QMessageBox.information(self, cfg.programName, "Change the behavior type on first column to select a coding map")
|
|
833
834
|
|
|
834
|
-
#
|
|
835
|
+
# behavior type
|
|
835
836
|
if column == cfg.behavioursFields["type"]:
|
|
836
837
|
self.behavior_type_doubleclicked(row)
|
|
837
838
|
|
|
@@ -843,7 +844,7 @@ class projectDialog(QDialog, Ui_dlgProject):
|
|
|
843
844
|
if column == cfg.behavioursFields[cfg.BEHAVIOR_CATEGORY]:
|
|
844
845
|
self.category_doubleclicked(row)
|
|
845
846
|
|
|
846
|
-
#
|
|
847
|
+
# modifiers
|
|
847
848
|
if column == cfg.behavioursFields[cfg.MODIFIERS]:
|
|
848
849
|
# check if behavior has coding map
|
|
849
850
|
if (
|
|
@@ -897,16 +898,17 @@ class projectDialog(QDialog, Ui_dlgProject):
|
|
|
897
898
|
if self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).text():
|
|
898
899
|
current_color = QColor(self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).text())
|
|
899
900
|
if current_color.isValid():
|
|
901
|
+
print(f"{current_color=}")
|
|
900
902
|
col_diag.setCurrentColor(current_color)
|
|
901
903
|
|
|
902
|
-
if col_diag.
|
|
904
|
+
if col_diag.exec():
|
|
903
905
|
color = col_diag.currentColor()
|
|
904
906
|
if color.name() == "#000000": # black -> delete color
|
|
905
907
|
self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setText("")
|
|
906
908
|
self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setBackground(self.not_editable_column_color())
|
|
907
909
|
elif color.isValid():
|
|
910
|
+
self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setBackground(QColor(color.name()))
|
|
908
911
|
self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setText(color.name())
|
|
909
|
-
self.twBehaviors.item(row, cfg.behavioursFields[cfg.COLOR]).setBackground(color)
|
|
910
912
|
|
|
911
913
|
def category_doubleclicked(self, row):
|
|
912
914
|
"""
|
boris/project_functions.py
CHANGED
|
@@ -356,7 +356,7 @@ def check_state_events(pj: dict, observations_list: list) -> Tuple[bool, tuple]:
|
|
|
356
356
|
use check_state_events_obs function
|
|
357
357
|
"""
|
|
358
358
|
|
|
359
|
-
logging.info("Check state events")
|
|
359
|
+
logging.info("Check state events function")
|
|
360
360
|
|
|
361
361
|
out = ""
|
|
362
362
|
not_paired_obs_list = []
|
|
@@ -404,7 +404,7 @@ def check_project_integrity(
|
|
|
404
404
|
* check if media file are available (optional)
|
|
405
405
|
* check if media length available
|
|
406
406
|
* check independent variables
|
|
407
|
-
* check if coded subjects are
|
|
407
|
+
* check if coded subjects are defined
|
|
408
408
|
|
|
409
409
|
Args:
|
|
410
410
|
pj (dict): BORIS project
|
|
@@ -474,6 +474,7 @@ def check_project_integrity(
|
|
|
474
474
|
if not timestamp.is_nan() and not (-2147483647 <= timestamp <= 2147483647):
|
|
475
475
|
out_events += f"Observation: <b>{obs_id}</b><br>The timestamp {timestamp} is not between -2147483647 and 2147483647.<br>"
|
|
476
476
|
|
|
477
|
+
"""
|
|
477
478
|
# check if media length available
|
|
478
479
|
if pj[cfg.OBSERVATIONS][obs_id][cfg.TYPE] == cfg.MEDIA:
|
|
479
480
|
for nplayer in cfg.ALL_PLAYERS:
|
|
@@ -484,6 +485,7 @@ def check_project_integrity(
|
|
|
484
485
|
except KeyError:
|
|
485
486
|
out += "<br><br>" if out else ""
|
|
486
487
|
out += f"Observation: <b>{obs_id}</b><br>Length not available for media file <b>{media_file}</b>"
|
|
488
|
+
"""
|
|
487
489
|
|
|
488
490
|
out += "<br><br>" if out else ""
|
|
489
491
|
out += out_events
|
|
@@ -530,25 +532,46 @@ def check_project_integrity(
|
|
|
530
532
|
]
|
|
531
533
|
)
|
|
532
534
|
|
|
533
|
-
|
|
535
|
+
tmp_out: str = ""
|
|
534
536
|
for obs_id in pj[cfg.OBSERVATIONS]:
|
|
535
537
|
if cfg.INDEPENDENT_VARIABLES not in pj[cfg.OBSERVATIONS][obs_id]:
|
|
536
538
|
continue
|
|
537
539
|
for var_label in pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES]:
|
|
538
540
|
if var_label in defined_set_var_label:
|
|
539
541
|
if pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][var_label] not in defined_set_var_label[var_label].split(","):
|
|
540
|
-
|
|
542
|
+
tmp_out += (
|
|
541
543
|
f"{obs_id}: the <b>{pj[cfg.OBSERVATIONS][obs_id][cfg.INDEPENDENT_VARIABLES][var_label]}</b> value "
|
|
542
544
|
f" is not allowed for {var_label} (choose between {defined_set_var_label[var_label]})<br>"
|
|
543
545
|
)
|
|
546
|
+
if tmp_out:
|
|
547
|
+
out += "<br><br>" if out else ""
|
|
548
|
+
out += tmp_out
|
|
544
549
|
|
|
545
550
|
# check if coded subjects are defined in the subjects list
|
|
551
|
+
tmp_out: str = ""
|
|
546
552
|
subjects_list: list = [pj[cfg.SUBJECTS][x]["name"] for x in pj[cfg.SUBJECTS]]
|
|
547
553
|
coded_subjects = set(util.flatten_list([[y[1] for y in pj[cfg.OBSERVATIONS][x].get(cfg.EVENTS, [])] for x in pj[cfg.OBSERVATIONS]]))
|
|
548
554
|
|
|
549
555
|
for subject in coded_subjects:
|
|
550
556
|
if subject and subject not in subjects_list:
|
|
551
|
-
|
|
557
|
+
tmp_out += f"The coded subject <b>{subject}</b> is not defined in the subjects list.<br>You can use the <b>Explore project</b> to fix it.<br><br>"
|
|
558
|
+
if tmp_out:
|
|
559
|
+
out += "<br><br>" if out else ""
|
|
560
|
+
out += tmp_out
|
|
561
|
+
|
|
562
|
+
# check if media file have info in media_info section of project
|
|
563
|
+
tmp_out: str = ""
|
|
564
|
+
for obs_id in pj[cfg.OBSERVATIONS]:
|
|
565
|
+
for player in pj[cfg.OBSERVATIONS][obs_id][cfg.FILE]:
|
|
566
|
+
for media_file in pj[cfg.OBSERVATIONS][obs_id][cfg.FILE][player]:
|
|
567
|
+
for info in (cfg.LENGTH, cfg.FPS, cfg.HAS_AUDIO, cfg.HAS_VIDEO):
|
|
568
|
+
if media_file not in pj[cfg.OBSERVATIONS][obs_id][cfg.MEDIA_INFO][info]:
|
|
569
|
+
tmp_out += f"Observation <b>{obs_id}</b>:<br>"
|
|
570
|
+
tmp_out += f"The media file {media_file} has no <b>{info}</b> info.<br>"
|
|
571
|
+
if tmp_out:
|
|
572
|
+
tmp_out += "<br>You should repick the media file to fix this issue."
|
|
573
|
+
out += "<br><br>" if out else ""
|
|
574
|
+
out += tmp_out
|
|
552
575
|
|
|
553
576
|
return out
|
|
554
577
|
|
|
@@ -1168,13 +1191,8 @@ def observed_interval(observation: dict) -> Tuple[dec, dec]:
|
|
|
1168
1191
|
"""
|
|
1169
1192
|
if not observation[cfg.EVENTS]:
|
|
1170
1193
|
return (dec("0.0"), dec("0.0"))
|
|
1171
|
-
if observation[cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
|
|
1172
|
-
"""
|
|
1173
|
-
print("=" * 120)
|
|
1174
|
-
print(observation[cfg.EVENTS])
|
|
1175
|
-
print("=" * 120)
|
|
1176
|
-
"""
|
|
1177
1194
|
|
|
1195
|
+
if observation[cfg.TYPE] in (cfg.MEDIA, cfg.LIVE):
|
|
1178
1196
|
event_timestamp = [event[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.TIME]] for event in observation[cfg.EVENTS]]
|
|
1179
1197
|
|
|
1180
1198
|
return (
|
|
@@ -1183,8 +1201,12 @@ def observed_interval(observation: dict) -> Tuple[dec, dec]:
|
|
|
1183
1201
|
)
|
|
1184
1202
|
if observation[cfg.TYPE] == cfg.IMAGES:
|
|
1185
1203
|
events = [x[cfg.PJ_OBS_FIELDS[observation[cfg.TYPE]][cfg.IMAGE_INDEX]] for x in observation[cfg.EVENTS]]
|
|
1186
|
-
|
|
1187
|
-
|
|
1204
|
+
# test if indexes contain NA
|
|
1205
|
+
try:
|
|
1206
|
+
dec(min(events))
|
|
1207
|
+
return (dec(min(events)), dec(max(events)))
|
|
1208
|
+
except Exception:
|
|
1209
|
+
return (dec("NaN"), dec("NaN"))
|
|
1188
1210
|
|
|
1189
1211
|
|
|
1190
1212
|
def events_start_stop(ethogram: dict, events: list, obs_type: str) -> List[tuple]:
|
|
@@ -1273,7 +1295,7 @@ def open_project_json(project_file_name: str) -> tuple:
|
|
|
1273
1295
|
str: message
|
|
1274
1296
|
"""
|
|
1275
1297
|
|
|
1276
|
-
logging.debug(f"
|
|
1298
|
+
logging.debug(f"open_project_json function: {project_file_name}")
|
|
1277
1299
|
|
|
1278
1300
|
projectChanged: bool = False
|
|
1279
1301
|
msg: str = ""
|
|
@@ -1612,6 +1634,8 @@ def fix_unpaired_state_events2(ethogram: dict, events: list, fix_at_time: dec) -
|
|
|
1612
1634
|
list: list of events with state events fixed
|
|
1613
1635
|
"""
|
|
1614
1636
|
|
|
1637
|
+
logging.debug("fix_unpaired_state_events2 function")
|
|
1638
|
+
|
|
1615
1639
|
closing_events_to_add: list = []
|
|
1616
1640
|
subjects: list = [event[cfg.EVENT_SUBJECT_FIELD_IDX] for event in events]
|
|
1617
1641
|
ethogram_behaviors: dict = {ethogram[idx][cfg.BEHAVIOR_CODE] for idx in ethogram}
|
boris/utilities.py
CHANGED
|
@@ -129,7 +129,7 @@ def extract_video_creation_date(file_path: str) -> int | None:
|
|
|
129
129
|
return None
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
def extract_date_time_from_file_name(file_path: str) -> int:
|
|
132
|
+
def extract_date_time_from_file_name(file_path: str) -> int | None:
|
|
133
133
|
"""
|
|
134
134
|
extract YYYY-MM-DD_HHMMSS or YYYY-MM-DD_HH:MM:SS from file name
|
|
135
135
|
"""
|
boris/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: boris-behav-obs
|
|
3
|
-
Version: 9.3.
|
|
3
|
+
Version: 9.3.4
|
|
4
4
|
Summary: BORIS - Behavioral Observation Research Interactive Software
|
|
5
5
|
Author-email: Olivier Friard <olivier.friard@unito.it>
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -24,7 +24,7 @@ Requires-Dist: matplotlib>=3.3.3
|
|
|
24
24
|
Requires-Dist: pandas>=2.2.2
|
|
25
25
|
Requires-Dist: tablib[cli,html,ods,pandas,xls,xlsx]>=3
|
|
26
26
|
Requires-Dist: pyreadr
|
|
27
|
-
Requires-Dist: pyside6==6.
|
|
27
|
+
Requires-Dist: pyside6==6.9
|
|
28
28
|
Requires-Dist: hachoir>=3.3.0
|
|
29
29
|
Provides-Extra: dev
|
|
30
30
|
Requires-Dist: ruff; extra == "dev"
|
|
@@ -17,15 +17,15 @@ boris/converters.py,sha256=c1Jps-URoglY5ILQHz-pCCf6-4DFUHZLtqr_ofsrFg0,11722
|
|
|
17
17
|
boris/converters_ui.py,sha256=uu7LOBV_fKv2DBdOqsqPwjGsjgONr5ODBoscAA-EP48,9900
|
|
18
18
|
boris/cooccurence.py,sha256=tVERC-V8MWjWHlGEfDuu08iS94qjt4do-38jwI62QaY,10367
|
|
19
19
|
boris/core.py,sha256=EK19Xn0Z_sxu9TaqeRimMzzpn9ThZdTqUtlJJXz6pVY,233512
|
|
20
|
-
boris/core_qrc.py,sha256=
|
|
20
|
+
boris/core_qrc.py,sha256=J0kom27nrmi4-TCDLJZCZbtUAitiXQ4WEDfErawuxt8,639879
|
|
21
21
|
boris/core_ui.py,sha256=SeC26uveDCjrCBLsRPuQ6FaapKfON_HIRcQStEDLhl4,76384
|
|
22
22
|
boris/db_functions.py,sha256=Uw9wWH_Pe-qNzpV1k21YG_jKsoOmfY_iiK_7ARZHGDc,13352
|
|
23
23
|
boris/dev.py,sha256=9pUElbjl9g17rFUJXX5aVSu55_iIKIuDxNdrB0DI_d0,3671
|
|
24
|
-
boris/dialog.py,sha256=
|
|
24
|
+
boris/dialog.py,sha256=AxqXiTNiNOM5Ec9hGQ54aSeG-0jN_rycQdxJvhM7XWg,34956
|
|
25
25
|
boris/duration_widget.py,sha256=GjZgCAMGOcsNjoPiRImEVe6yMkH2vuNoh44ulpd5nlg,6924
|
|
26
26
|
boris/edit_event.py,sha256=2hpxn9DYuJW1CK02hF4iU0--J_0C_KTiN9gGZ1frJBc,7678
|
|
27
27
|
boris/edit_event_ui.py,sha256=vhglQrhkF9tt0HVlkXnkG7symW0eOFA7nhbk6l_qn3k,7772
|
|
28
|
-
boris/event_operations.py,sha256=
|
|
28
|
+
boris/event_operations.py,sha256=JNSK9zTbVaPSP2H4hGUtbygyBlFX4hmJXjOqKYRxKoc,38670
|
|
29
29
|
boris/events_cursor.py,sha256=VPY_ygD0fxE5lp25mcd2l00XQXurCR6hprffF4tKRbU,2078
|
|
30
30
|
boris/events_snapshots.py,sha256=PjWzQvUGQtIcEc_7FDsRphf7fAhhTccQgYc2eQSA65g,27621
|
|
31
31
|
boris/exclusion_matrix.py,sha256=ff88xD6aqc8bpIuj9ZCz9ju_HeqqgibQwoaJrIOJ6RI,5272
|
|
@@ -47,7 +47,7 @@ boris/mpv-1.0.3.py,sha256=EXRtzQqFjOn4wMC6482Ilq3fNQ9N1GRP1VxwLzdeaBY,88077
|
|
|
47
47
|
boris/mpv.py,sha256=EfzIHjPbgewG4w3smEtqEUPZoVwYmMQkL4Q8ZyW-a58,76410
|
|
48
48
|
boris/mpv2.py,sha256=IUI4t4r9GYX7G5OXTjd3RhMMOkDdfal_15buBgksLsk,92152
|
|
49
49
|
boris/observation.py,sha256=d-7q-RkMHuLDV87nF4yahvDFPYhlXp6GmE80vckn5zU,57073
|
|
50
|
-
boris/observation_operations.py,sha256=
|
|
50
|
+
boris/observation_operations.py,sha256=5OLdnnzdlazhevJzalDMtXSxo9dRZOLN_5jVE54ZnKE,106039
|
|
51
51
|
boris/observation_ui.py,sha256=DAnU94QBNvkLuHT6AxTwqSk_D_n6VUhSl8PexZv_dUk,33309
|
|
52
52
|
boris/observations_list.py,sha256=NqwECGHtHYmKhSe-qCfqPmJ24SSfzlXvIXS2i3op_zE,10591
|
|
53
53
|
boris/otx_parser.py,sha256=70QvilzFHXbjAHR88YH0aEXJ3xxheLS5fZGgHFHGpNE,16367
|
|
@@ -62,8 +62,8 @@ boris/plot_waveform_rt.py,sha256=05JN_6HCq674ROore_6PNw93GQNZJQDlDxp2ODAFkkA,747
|
|
|
62
62
|
boris/plugins.py,sha256=CCS1I44OMkGZqcfLGKNPGfEQXPgngocy5YhWveXQPKM,10029
|
|
63
63
|
boris/preferences.py,sha256=qPfd9Tyg7u30kXwVqMOgkdy2RXri9bItRa5U2-ZVQmg,16847
|
|
64
64
|
boris/preferences_ui.py,sha256=D2bFLb3E0m6IwSeqKoItRDiqvPmJGoeXLHF2K02n1Zo,26293
|
|
65
|
-
boris/project.py,sha256=
|
|
66
|
-
boris/project_functions.py,sha256=
|
|
65
|
+
boris/project.py,sha256=nyXfCDY_rLP3jC1QGv-280jUKgbABqESjOm7I19rJ1U,86432
|
|
66
|
+
boris/project_functions.py,sha256=eP-YEjoFvZXEPuzNPBeXsRDYurt0wHP6B09a8k8SlDc,80792
|
|
67
67
|
boris/project_import_export.py,sha256=oBG1CSXfKISsb3TLNT-8BH8kZPAzxIYSNemlLVH1Lh8,38560
|
|
68
68
|
boris/project_ui.py,sha256=yB-ewhHt8S8DTTRIk-dNK2tPMNU24lNji9fDW_Xazu8,38805
|
|
69
69
|
boris/qrc_boris.py,sha256=aH-qUirYY1CGxmTK1SFCPvuZfazIHX4DdUKF1gxZeYM,675008
|
|
@@ -77,8 +77,8 @@ boris/synthetic_time_budget.py,sha256=3Eb9onMLmgqCLd50CuxV9L8RV2ESzfaMWvPK_bXUMM
|
|
|
77
77
|
boris/time_budget_functions.py,sha256=y5He8crz0xsTxVfz0jATwFFQVnPAIrNHja_0sF6NtRE,52551
|
|
78
78
|
boris/time_budget_widget.py,sha256=z-tyITBtIz-KH1H2OdMB5a8x9QQLK7Wu96-zkC6NVDA,43213
|
|
79
79
|
boris/transitions.py,sha256=_aZJfJWv3EBrtmQ7qsdTCayQo6uWU7BXqtQQgflEhr4,12250
|
|
80
|
-
boris/utilities.py,sha256=
|
|
81
|
-
boris/version.py,sha256=
|
|
80
|
+
boris/utilities.py,sha256=4b3BjO96eR54sPXIYkHwxkUnROGgY5f5vhWKIy8THUo,52646
|
|
81
|
+
boris/version.py,sha256=st-9YZePMhFx60fiF0uKR_IhGjVv4ik2D_Td5O2XQr0,787
|
|
82
82
|
boris/video_equalizer.py,sha256=FartoGghFK-T53zklP70rPKYqTuzL8qdvfGlsOF2wwc,5854
|
|
83
83
|
boris/video_equalizer_ui.py,sha256=1CG3s79eM4JAbaCx3i1ILZXLceb41_gGXlOLNfpBgnw,10142
|
|
84
84
|
boris/video_operations.py,sha256=mh3iR__Sm2KnV44L_sW2pOo3AgLwlM7wiTnnqQiAVs4,9381
|
|
@@ -96,9 +96,9 @@ boris/portion/dict.py,sha256=SyHxc7PfDw2ufNLFQycwJtzmRfL48rDp4UrM2KN7IWc,11282
|
|
|
96
96
|
boris/portion/func.py,sha256=3TkQtFKLfsqntwd27HSGHceFhnXHmT-EbNMqktElC5Q,2174
|
|
97
97
|
boris/portion/interval.py,sha256=bAdUiJjGeUAPgsBAImwNeviiwfQq5odfhFZccAWzOTA,20299
|
|
98
98
|
boris/portion/io.py,sha256=ppNeRpiLNrocF1yzGeuEUIhYMf2LfsR-cji3d0nmvUs,6371
|
|
99
|
-
boris_behav_obs-9.3.
|
|
100
|
-
boris_behav_obs-9.3.
|
|
101
|
-
boris_behav_obs-9.3.
|
|
102
|
-
boris_behav_obs-9.3.
|
|
103
|
-
boris_behav_obs-9.3.
|
|
104
|
-
boris_behav_obs-9.3.
|
|
99
|
+
boris_behav_obs-9.3.4.dist-info/licenses/LICENSE.TXT,sha256=WJ7YI-moTFb-uVrFjnzzhGJrnL9P2iqQe8NuED3hutI,35141
|
|
100
|
+
boris_behav_obs-9.3.4.dist-info/METADATA,sha256=G03KB1bA9U-pdA0egf0dsvhkvRG2O3jQZudOyEdjfyA,4514
|
|
101
|
+
boris_behav_obs-9.3.4.dist-info/WHEEL,sha256=oSJJyWjO7Z2XSScFQUpXG1HL-N0sFMqqeKVVbZTPkWc,109
|
|
102
|
+
boris_behav_obs-9.3.4.dist-info/entry_points.txt,sha256=k__8XvFi4vaA4QFvQehCZjYkKmZH34HSAJI2iYCWrMs,52
|
|
103
|
+
boris_behav_obs-9.3.4.dist-info/top_level.txt,sha256=fJSgm62S7WesiwTorGbOO4nNN0yzgZ3klgfGi3Px4qI,6
|
|
104
|
+
boris_behav_obs-9.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|