boris-behav-obs 9.3.3__py2.py3-none-any.whl → 9.3.5__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/config.py +2 -0
- boris/core.py +21 -103
- boris/core_qrc.py +6580 -6784
- boris/dialog.py +78 -9
- boris/edit_event.py +47 -27
- boris/edit_event_ui.py +69 -36
- boris/event_operations.py +52 -47
- boris/observation.py +1 -2
- boris/observation_operations.py +34 -12
- boris/project.py +11 -9
- boris/project_functions.py +39 -15
- boris/select_observations.py +7 -1
- boris/state_events.py +1 -1
- boris/utilities.py +1 -1
- boris/version.py +2 -2
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.5.dist-info}/METADATA +2 -2
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.5.dist-info}/RECORD +21 -21
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.5.dist-info}/WHEEL +1 -1
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.5.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.5.dist-info}/licenses/LICENSE.TXT +0 -0
- {boris_behav_obs-9.3.3.dist-info → boris_behav_obs-9.3.5.dist-info}/top_level.txt +0 -0
boris/config.py
CHANGED
|
@@ -37,6 +37,7 @@ SECONDS_PER_DAY: int = 86_400
|
|
|
37
37
|
HOUR_CUTOFF: int = 7 * 24
|
|
38
38
|
DATE_CUTOFF: int = HOUR_CUTOFF * 60 * 60 # 1 week
|
|
39
39
|
|
|
40
|
+
# cutoff for displaying time in HH:MM:SS.zzz format
|
|
40
41
|
SMART_TIME_CUTOFF_DEFAULT: int = 300
|
|
41
42
|
|
|
42
43
|
# minimal project version for handling observations from images
|
|
@@ -218,6 +219,7 @@ OVERLAY = "video overlay"
|
|
|
218
219
|
|
|
219
220
|
|
|
220
221
|
USE_EXIF_DATE = "use_exif_date"
|
|
222
|
+
SUBSTRACT_FIRST_EXIF_DATE = "substract_first_exif_date"
|
|
221
223
|
TIME_LAPSE = "time_lapse_delay"
|
|
222
224
|
|
|
223
225
|
|
boris/core.py
CHANGED
|
@@ -308,9 +308,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
308
308
|
play_rate_step: float = 0.1
|
|
309
309
|
currentSubject: str = "" # contains the current subject of observation
|
|
310
310
|
|
|
311
|
-
#
|
|
312
|
-
memx = -1
|
|
313
|
-
memy = -1
|
|
311
|
+
# geometric measurements
|
|
314
312
|
mem_player = -1
|
|
315
313
|
|
|
316
314
|
# path for ffmpeg/ffmpeg.exe program
|
|
@@ -339,6 +337,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
339
337
|
|
|
340
338
|
mem_hash_obs: int = 0
|
|
341
339
|
|
|
340
|
+
# variables for list of observations
|
|
341
|
+
data: list = []
|
|
342
|
+
not_paired: list = []
|
|
343
|
+
|
|
342
344
|
'''
|
|
343
345
|
def add_button_menu(self, data, menu_obj):
|
|
344
346
|
"""
|
|
@@ -1342,21 +1344,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1342
1344
|
self.pj[cfg.BEHAVIORS_CODING_MAP][idx] = dict(behav_coding_map)
|
|
1343
1345
|
return
|
|
1344
1346
|
|
|
1345
|
-
"""
|
|
1346
|
-
QMessageBox.critical(
|
|
1347
|
-
None,
|
|
1348
|
-
cfg.programName,
|
|
1349
|
-
(
|
|
1350
|
-
"The current project already contains a behaviors coding map "
|
|
1351
|
-
f"with the same name (<b>{behav_coding_map['name']}</b>)"
|
|
1352
|
-
),
|
|
1353
|
-
QMessageBox.Ok | QMessageBox.Default,
|
|
1354
|
-
QMessageBox.NoButton,
|
|
1355
|
-
)
|
|
1356
|
-
|
|
1357
|
-
return
|
|
1358
|
-
"""
|
|
1359
|
-
|
|
1360
1347
|
self.pj[cfg.BEHAVIORS_CODING_MAP].append(behav_coding_map)
|
|
1361
1348
|
QMessageBox.information(
|
|
1362
1349
|
self,
|
|
@@ -1526,7 +1513,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1526
1513
|
jt.setWindowTitle("Jump to specific time")
|
|
1527
1514
|
jt.label.setText("Set the time")
|
|
1528
1515
|
|
|
1529
|
-
if jt.
|
|
1516
|
+
if jt.exec():
|
|
1530
1517
|
new_time = jt.time_widget.get_time()
|
|
1531
1518
|
if new_time < 0:
|
|
1532
1519
|
return
|
|
@@ -1704,7 +1691,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1704
1691
|
QMessageBox.critical(
|
|
1705
1692
|
None,
|
|
1706
1693
|
cfg.programName,
|
|
1707
|
-
("The picture directory
|
|
1694
|
+
("The picture directory has changed since the creation of observation."),
|
|
1708
1695
|
QMessageBox.Ok | QMessageBox.Default,
|
|
1709
1696
|
QMessageBox.NoButton,
|
|
1710
1697
|
)
|
|
@@ -1718,15 +1705,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1718
1705
|
# extract EXIF tag
|
|
1719
1706
|
if self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.USE_EXIF_DATE, False):
|
|
1720
1707
|
date_time_original = util.extract_exif_DateTimeOriginal(self.images_list[self.image_idx])
|
|
1708
|
+
|
|
1721
1709
|
if date_time_original != -1:
|
|
1722
1710
|
msg += f"<br>EXIF Date/Time Original: <b>{datetime.datetime.fromtimestamp(date_time_original):%Y-%m-%d %H:%M:%S}</b>"
|
|
1723
|
-
else:
|
|
1724
|
-
msg += "<br>EXIF Date/Time Original: <b>NA</b>"
|
|
1725
1711
|
|
|
1726
|
-
|
|
1727
|
-
|
|
1712
|
+
if self.image_idx == 0:
|
|
1713
|
+
self.image_time_ref = date_time_original
|
|
1728
1714
|
|
|
1729
|
-
if date_time_original != -1:
|
|
1730
1715
|
if self.image_time_ref is not None:
|
|
1731
1716
|
seconds_from_1st = date_time_original - self.image_time_ref
|
|
1732
1717
|
|
|
@@ -1736,6 +1721,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1736
1721
|
seconds_from_1st_formated = seconds_from_1st
|
|
1737
1722
|
|
|
1738
1723
|
else:
|
|
1724
|
+
msg += "<br>EXIF Date/Time Original: <b>NA</b>"
|
|
1739
1725
|
seconds_from_1st_formated = cfg.NA
|
|
1740
1726
|
|
|
1741
1727
|
msg += f"<br>Time from 1st image: <b>{seconds_from_1st_formated}</b>"
|
|
@@ -2311,11 +2297,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2311
2297
|
self.tv_events.setModel(model)
|
|
2312
2298
|
|
|
2313
2299
|
# column width
|
|
2314
|
-
|
|
2315
|
-
self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
|
|
2316
|
-
|
|
2317
|
-
# self.table.setSortingEnabled(True)
|
|
2318
|
-
# self.table.sortByColumn(0, Qt.AscendingOrder)
|
|
2300
|
+
self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
|
|
2319
2301
|
|
|
2320
2302
|
def load_tw_events(self, obs_id) -> None:
|
|
2321
2303
|
"""
|
|
@@ -2343,76 +2325,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2343
2325
|
|
|
2344
2326
|
return
|
|
2345
2327
|
|
|
2346
|
-
"""
|
|
2347
|
-
DISABLED tableview component is used
|
|
2348
|
-
|
|
2349
|
-
logging.debug(f"begin load events from obs in tablewidget: {obs_id}")
|
|
2350
|
-
|
|
2351
|
-
t1 = time.time()
|
|
2352
|
-
|
|
2353
|
-
self.twEvents.clear()
|
|
2354
|
-
|
|
2355
|
-
self.twEvents.setColumnCount(len(cfg.TW_EVENTS_FIELDS[self.playerType]))
|
|
2356
|
-
self.twEvents.setHorizontalHeaderLabels([s.capitalize() for s in cfg.TW_EVENTS_FIELDS[self.playerType]])
|
|
2357
|
-
|
|
2358
|
-
for idx, field in enumerate(cfg.TW_EVENTS_FIELDS[self.playerType]):
|
|
2359
|
-
if field not in self.config_param.get(f"{self.playerType} tw fields", cfg.TW_EVENTS_FIELDS[self.playerType]):
|
|
2360
|
-
self.twEvents.horizontalHeader().hideSection(idx)
|
|
2361
|
-
else:
|
|
2362
|
-
self.twEvents.horizontalHeader().showSection(idx)
|
|
2363
|
-
|
|
2364
|
-
self.twEvents.setRowCount(len(self.pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]))
|
|
2365
|
-
if self.filtered_behaviors or self.filtered_subjects:
|
|
2366
|
-
self.twEvents.setRowCount(0)
|
|
2367
|
-
row = 0
|
|
2368
|
-
|
|
2369
|
-
for event_idx, event in enumerate(self.pj[cfg.OBSERVATIONS][obs_id][cfg.EVENTS]):
|
|
2370
|
-
if self.filtered_behaviors and event[cfg.PJ_OBS_FIELDS[self.playerType][cfg.BEHAVIOR_CODE]] not in self.filtered_behaviors:
|
|
2371
|
-
continue
|
|
2372
|
-
|
|
2373
|
-
if self.filtered_subjects and event[cfg.PJ_OBS_FIELDS[self.playerType][cfg.SUBJECT]] not in self.filtered_subjects:
|
|
2374
|
-
continue
|
|
2375
|
-
|
|
2376
|
-
if self.filtered_behaviors or self.filtered_subjects:
|
|
2377
|
-
self.twEvents.insertRow(self.twEvents.rowCount())
|
|
2378
|
-
|
|
2379
|
-
for field_type in cfg.TW_EVENTS_FIELDS[self.playerType]:
|
|
2380
|
-
if field_type in cfg.PJ_EVENTS_FIELDS[self.playerType]:
|
|
2381
|
-
field = event_operations.read_event_field(event, self.playerType, field_type)
|
|
2382
|
-
|
|
2383
|
-
if field_type == cfg.TIME:
|
|
2384
|
-
item = QTableWidgetItem(str(util.convertTime(self.timeFormat, field)))
|
|
2385
|
-
|
|
2386
|
-
# add index of project events
|
|
2387
|
-
item.setData(Qt.UserRole, event_idx)
|
|
2388
|
-
self.twEvents.setItem(row, cfg.TW_OBS_FIELD[self.playerType][field_type], item)
|
|
2389
|
-
continue
|
|
2390
|
-
|
|
2391
|
-
if field_type in (cfg.IMAGE_INDEX, cfg.FRAME_INDEX):
|
|
2392
|
-
field = str(field)
|
|
2393
|
-
|
|
2394
|
-
self.twEvents.setItem(
|
|
2395
|
-
row,
|
|
2396
|
-
cfg.TW_OBS_FIELD[self.playerType][field_type],
|
|
2397
|
-
QTableWidgetItem(field),
|
|
2398
|
-
)
|
|
2399
|
-
|
|
2400
|
-
else:
|
|
2401
|
-
self.twEvents.setItem(
|
|
2402
|
-
row,
|
|
2403
|
-
cfg.TW_OBS_FIELD[self.playerType][field_type],
|
|
2404
|
-
QTableWidgetItem(""),
|
|
2405
|
-
)
|
|
2406
|
-
|
|
2407
|
-
row += 1
|
|
2408
|
-
|
|
2409
|
-
self.update_events_start_stop()
|
|
2410
|
-
|
|
2411
|
-
print("load twevent:", time.time() - t1)
|
|
2412
|
-
|
|
2413
|
-
logging.debug("end load events from obs")
|
|
2414
|
-
"""
|
|
2415
|
-
|
|
2416
2328
|
def close_tool_windows(self):
|
|
2417
2329
|
"""
|
|
2418
2330
|
close tool windows:
|
|
@@ -3493,7 +3405,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3493
3405
|
return
|
|
3494
3406
|
|
|
3495
3407
|
logging.debug(
|
|
3496
|
-
f"{self.config_param[cfg.CHECK_PROJECT_INTEGRITY] if cfg.CHECK_PROJECT_INTEGRITY in self.config_param else
|
|
3408
|
+
f"{self.config_param[cfg.CHECK_PROJECT_INTEGRITY] if cfg.CHECK_PROJECT_INTEGRITY in self.config_param else 'Check project integrity config NOT FOUND'=}"
|
|
3497
3409
|
)
|
|
3498
3410
|
|
|
3499
3411
|
if self.config_param.get(cfg.CHECK_PROJECT_INTEGRITY, True):
|
|
@@ -4707,7 +4619,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4707
4619
|
self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.USE_EXIF_DATE, False)
|
|
4708
4620
|
and util.extract_exif_DateTimeOriginal(self.images_list[self.image_idx]) != -1
|
|
4709
4621
|
):
|
|
4710
|
-
time_ = util.extract_exif_DateTimeOriginal(self.images_list[self.image_idx])
|
|
4622
|
+
time_ = util.extract_exif_DateTimeOriginal(self.images_list[self.image_idx])
|
|
4623
|
+
# check if first value must be substracted
|
|
4624
|
+
if self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.SUBSTRACT_FIRST_EXIF_DATE, True):
|
|
4625
|
+
time_ -= self.image_time_ref
|
|
4711
4626
|
|
|
4712
4627
|
elif self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.TIME_LAPSE, 0):
|
|
4713
4628
|
time_ = (self.image_idx + 1) * self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.TIME_LAPSE, 0)
|
|
@@ -4765,7 +4680,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4765
4680
|
self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.USE_EXIF_DATE, False)
|
|
4766
4681
|
and util.extract_exif_DateTimeOriginal(self.images_list[self.image_idx]) != -1
|
|
4767
4682
|
):
|
|
4768
|
-
time_ = util.extract_exif_DateTimeOriginal(self.images_list[self.image_idx])
|
|
4683
|
+
time_ = util.extract_exif_DateTimeOriginal(self.images_list[self.image_idx])
|
|
4684
|
+
# check if first value must be substracte
|
|
4685
|
+
if self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.SUBSTRACT_FIRST_EXIF_DATE, True):
|
|
4686
|
+
time_ -= self.image_time_ref
|
|
4769
4687
|
|
|
4770
4688
|
elif self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.TIME_LAPSE, 0):
|
|
4771
4689
|
time_ = (self.image_idx + 1) * self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.TIME_LAPSE, 0)
|