diff --git a/sleap/gui/app.py b/sleap/gui/app.py index 784ce885e..de79a7d85 100644 --- a/sleap/gui/app.py +++ b/sleap/gui/app.py @@ -156,6 +156,7 @@ def __init__( self.state["edge style"] = prefs["edge style"] self.state["fit"] = False self.state["color predicted"] = prefs["color predicted"] + self.state["trail_shade"] = prefs["trail shade"] self.state["marker size"] = prefs["marker size"] self.state["propagate track labels"] = prefs["propagate track labels"] self.state["node label size"] = prefs["node label size"] @@ -218,6 +219,7 @@ def closeEvent(self, event): prefs["edge style"] = self.state["edge style"] prefs["propagate track labels"] = self.state["propagate track labels"] prefs["color predicted"] = self.state["color predicted"] + prefs["trail shade"] = self.state["trail_shade"] prefs["share usage data"] = self.state["share usage data"] # Save preferences. @@ -632,12 +634,19 @@ def prev_vid(): key="node label size", ) + viewMenu.addSeparator() add_submenu_choices( menu=viewMenu, title="Trail Length", - options=(0, 10, 50, 100, 250), + options=TrackTrailOverlay.get_length_options(), key="trail_length", ) + add_submenu_choices( + menu=viewMenu, + title="Trail Shade", + options=tuple(TrackTrailOverlay.get_shade_options().keys()), + key="trail_shade", + ) viewMenu.addSeparator() add_menu_item( @@ -1177,7 +1186,11 @@ def goto_suggestion(*args): def _load_overlays(self): """Load all standard video overlays.""" self.overlays["track_labels"] = TrackListOverlay(self.labels, self.player) - self.overlays["trails"] = TrackTrailOverlay(self.labels, self.player) + self.overlays["trails"] = TrackTrailOverlay( + labels=self.labels, + player=self.player, + trail_shade=self.state["trail_shade"], + ) self.overlays["instance"] = InstanceOverlay( self.labels, self.player, self.state ) @@ -1196,6 +1209,7 @@ def overlay_state_connect(overlay, state_key, overlay_attribute=None): ) overlay_state_connect(self.overlays["trails"], "trail_length") + overlay_state_connect(self.overlays["trails"], "trail_shade") overlay_state_connect(self.color_manager, "palette") overlay_state_connect(self.color_manager, "distinctly_color") diff --git a/sleap/gui/overlays/tracks.py b/sleap/gui/overlays/tracks.py index 382523f40..9382bab55 100644 --- a/sleap/gui/overlays/tracks.py +++ b/sleap/gui/overlays/tracks.py @@ -1,6 +1,5 @@ -""" -Track trail and track list overlays. -""" +"""Track trail and track list overlays.""" + from sleap.gui.overlays.base import BaseOverlay from sleap.instance import Track from sleap.io.dataset import Labels @@ -10,7 +9,7 @@ import attr -from typing import Iterable, List, Optional +from typing import Iterable, List, Optional, Dict from qtpy import QtCore, QtGui @@ -27,6 +26,8 @@ class TrackTrailOverlay(BaseOverlay): labels: The :class:`Labels` dataset from which to get overlay data. player: The video player in which to show overlay. trail_length: The maximum number of frames to include in trail. + trail_shade: A literal "Dark", "Normal", or "Bright" which determines the shade + of the trail color. Usage: After class is instantiated, call :meth:`add_to_scene(frame_idx)` @@ -34,9 +35,27 @@ class TrackTrailOverlay(BaseOverlay): """ trail_length: int = 0 + trail_shade: str = attr.ib( + default="Normal", validator=attr.validators.in_(["Dark", "Normal", "Light"]) + ) show: bool = True max_node_count: Optional[int] = None + def __attrs_post_init__(self): + """Initialize the shade options attribute after initalizing the instance.""" + + self.shade_options = self.get_shade_options() + + @classmethod + def get_length_options(cls): + return (0, 10, 50, 100, 250) + + @classmethod + def get_shade_options(cls): + """Return a dictionary with values to multiply each RGB value by.""" + + return {"Dark": 0.6, "Normal": 1.0, "Light": 1.25} + def get_track_trails(self, frame_selection: Iterable["LabeledFrame"]): """Get data needed to draw track trail. @@ -85,9 +104,7 @@ def get_track_trails(self, frame_selection: Iterable["LabeledFrame"]): return all_track_trails def get_frame_selection(self, video: Video, frame_idx: int): - """ - Return `LabeledFrame` objects to include in trail for specified frame. - """ + """Return `LabeledFrame` objects to include in trail for specified frame.""" frame_selection = self.labels.find(video, range(0, frame_idx + 1)) frame_selection.sort(key=lambda x: x.frame_idx) @@ -97,8 +114,7 @@ def get_frame_selection(self, video: Video, frame_idx: int): def get_tracks_in_frame( self, video: Video, frame_idx: int, include_trails: bool = False ) -> List[Track]: - """ - Returns list of tracks that have instance in specified frame. + """Returns list of tracks that have instance in specified frame. Args: video: Video for which we want tracks. @@ -108,6 +124,7 @@ def get_tracks_in_frame( within trail_length). Returns: List of tracks. + """ if include_trails: @@ -125,7 +142,9 @@ def add_to_scene(self, video: Video, frame_idx: int): Args: video: current video frame_idx: index of the frame to which the trail is attached + """ + if not self.show or self.trail_length == 0: return @@ -134,8 +153,11 @@ def add_to_scene(self, video: Video, frame_idx: int): all_track_trails = self.get_track_trails(frame_selection) for track, trails in all_track_trails.items(): - - color = QtGui.QColor(*self.player.color_manager.get_track_color(track)) + trail_color = tuple( + min(c * self.shade_options[self.trail_shade], 255) + for c in self.player.color_manager.get_track_color(track) + ) + color = QtGui.QColor(*trail_color) pen = QtGui.QPen() pen.setCosmetic(True) pen.setColor(color) @@ -183,9 +205,7 @@ def map_to_qt_path(point_list): @attr.s(auto_attribs=True) class TrackListOverlay(BaseOverlay): - """ - Class to show track number and names in overlay. - """ + """Class to show track number and names in overlay.""" text_box: Optional[QtTextWithBackground] = None diff --git a/sleap/prefs.py b/sleap/prefs.py index 9aced5855..3d5a2113e 100644 --- a/sleap/prefs.py +++ b/sleap/prefs.py @@ -19,6 +19,7 @@ class Preferences(object): "palette": "standard", "bold lines": False, "trail length": 0, + "trail shade": "Normal", "trail width": 4.0, "trail node count": 1, "marker size": 4,