Skip to content

Commit e2ca392

Browse files
authored
Merge pull request #199 from KumarLabJax/add-identity-to-stacked-timeline-rows
add the identity as a label to each section of the stacked timeline
2 parents cbe2915 + 0fb1c9e commit e2ca392

File tree

4 files changed

+39
-27
lines changed

4 files changed

+39
-27
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "jabs-behavior-classifier"
3-
version = "0.34.2"
3+
version = "0.34.3"
44
license = "Proprietary"
55
repository = "https://github.com/KumarLabJax/JABS-behavior-classifier"
66
description = ""

src/jabs/project/session_tracker.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,5 +332,9 @@ def resume_session(self):
332332
def _flush_session(self):
333333
"""Flush the current session data to the session file."""
334334
if self._session_file and self._session:
335-
with open(self._session_file, "w") as f:
336-
json.dump(self._session, f, indent=4)
335+
try:
336+
with open(self._session_file, "w") as f:
337+
json.dump(self._session, f, indent=4)
338+
except NameError:
339+
# Python is shutting down, and open is no longer available
340+
pass

src/jabs/ui/central_widget.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,7 @@ def load_video(self, path: Path) -> None:
290290
# open poses and any labels that might exist for this video
291291
self._pose_est = self._project.load_pose_est(path)
292292
self._labels = self._project.video_manager.load_video_labels(path)
293-
self._stacked_timeline.num_identities = self._pose_est.num_identities
294-
self._stacked_timeline.num_frames = self._pose_est.num_frames
293+
self._stacked_timeline.pose = self._pose_est
295294

296295
# if no saved labels exist, initialize a new VideoLabels object
297296
if self._labels is None:

src/jabs/ui/stacked_timeline_widget/stacked_timeline_widget.py

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import numpy as np
44
from PySide6.QtCore import Slot
5-
from PySide6.QtWidgets import QApplication, QFrame, QSizePolicy, QVBoxLayout, QWidget
5+
from PySide6.QtWidgets import QApplication, QFrame, QLabel, QSizePolicy, QVBoxLayout, QWidget
66

77
from jabs.behavior_search import (
88
BehaviorSearchQuery,
@@ -11,6 +11,7 @@
1111
SearchHit,
1212
TimelineAnnotationSearchQuery,
1313
)
14+
from jabs.pose_estimation import PoseEstimation
1415
from jabs.project import TrackLabels
1516

1617
from .frame_labels_widget import FrameLabelsWidget
@@ -63,6 +64,7 @@ def __init__(self, *args, **kwargs) -> None:
6364
self._prediction_overview_widgets = []
6465
self._identity_frames = []
6566
self._frame_labels = FrameLabelsWidget(self)
67+
self._pose: PoseEstimation | None = None
6668

6769
self._layout = QVBoxLayout(self)
6870
self._layout.setContentsMargins(0, 0, 0, 0)
@@ -87,18 +89,6 @@ def _prediction_overview_widget_factory(self, parent) -> PredictionOverviewWidge
8789
widget.framerate = self.framerate
8890
return widget
8991

90-
@property
91-
def num_identities(self) -> int:
92-
"""Get the number of identities."""
93-
return self._num_identities
94-
95-
@num_identities.setter
96-
def num_identities(self, value: int) -> None:
97-
"""Set the number of identities and reset the layout."""
98-
if value != self._num_identities:
99-
self._num_identities = value
100-
self._reset_layout()
101-
10292
@property
10393
def view_mode(self) -> ViewMode:
10494
"""Get the current view mode."""
@@ -123,6 +113,23 @@ def identity_mode(self, value: IdentityMode) -> None:
123113
self._identity_mode = value
124114
self._update_widget_visibility()
125115

116+
@property
117+
def pose(self) -> PoseEstimation | None:
118+
"""Get the PoseEstimation object used by the label overview widgets."""
119+
return self._pose
120+
121+
@pose.setter
122+
def pose(self, pose_est: PoseEstimation) -> None:
123+
"""Set the PoseEstimation object used by the label overview widgets.
124+
125+
Args:
126+
pose_est: PoseEstimation object to set.
127+
"""
128+
self._pose = pose_est
129+
self._num_identities = pose_est.num_identities
130+
self._num_frames = pose_est.num_frames
131+
self._reset_layout()
132+
126133
def _reset_layout(self) -> None:
127134
"""Recreate the layout and child widgets for all identities.
128135
@@ -143,7 +150,12 @@ def _reset_layout(self) -> None:
143150
self._identity_frames = []
144151

145152
# Create new frames and widgets
146-
for _ in range(self._num_identities):
153+
for identity_index in range(self._num_identities):
154+
if self._pose and self._pose.external_identities is not None:
155+
identity_display_name = self._pose.external_identities[identity_index]
156+
else:
157+
identity_display_name = identity_index
158+
147159
frame = QFrame(self)
148160
frame.setFrameShape(QFrame.Shape.NoFrame)
149161
frame.setStyleSheet("QFrame {border: none; padding: 2px;}")
@@ -156,6 +168,7 @@ def _reset_layout(self) -> None:
156168
label_widget.setVisible(False)
157169
prediction_widget.setVisible(False)
158170

171+
vbox.addWidget(QLabel(f"{identity_display_name}:"))
159172
vbox.addWidget(label_widget)
160173
vbox.addWidget(prediction_widget)
161174

@@ -189,10 +202,12 @@ def _set_active_frame_border(self, active_index: int | None = None) -> None:
189202
for i, frame in enumerate(self._identity_frames):
190203
if i == active_index:
191204
frame.setStyleSheet(
192-
f"QFrame {{border: 2px solid {accent_color}; border-radius: 8px;}}"
205+
f"QFrame > QWidget {{border: none;}} QFrame {{border: 2px solid {accent_color}; border-radius: 8px; padding: 2px;}}"
193206
)
194207
else:
195-
frame.setStyleSheet("QFrame {border: none; padding: 2px;}")
208+
frame.setStyleSheet(
209+
"QFrame > QWidget {border: none;} QFrame {border: 2px solid transparent; border-radius: 8px; padding: 2px;}"
210+
)
196211

197212
@staticmethod
198213
def _get_accent_color() -> str:
@@ -205,12 +220,6 @@ def num_frames(self) -> int:
205220
"""Get the number of frames."""
206221
return self._num_frames
207222

208-
@num_frames.setter
209-
def num_frames(self, value: int) -> None:
210-
"""Set the number of frames."""
211-
self._num_frames = value
212-
self._frame_labels.set_num_frames(value)
213-
214223
@property
215224
def framerate(self) -> int:
216225
"""Get the framerate."""

0 commit comments

Comments
 (0)