Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement button to flip the tree view axes #114

Merged
merged 3 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/motile_plugin/data_views/views/tree_view/flip_axes_widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from psygnal import Signal
from qtpy.QtWidgets import QGroupBox, QPushButton, QVBoxLayout, QWidget


class FlipTreeWidget(QWidget):
"""Widget to flip the axis of the tree view"""

flip_tree = Signal()

def __init__(self):
super().__init__()

flip_layout = QVBoxLayout()
display_box = QGroupBox("Plot axes [F]")
flip_button = QPushButton("Flip")
flip_button.clicked.connect(self.flip)
flip_layout.addWidget(flip_button)
display_box.setLayout(flip_layout)

layout = QVBoxLayout()
layout.addWidget(display_box)
self.setLayout(layout)
display_box.setMaximumWidth(90)
display_box.setMaximumHeight(82)

def flip(self):
"""Send a signal to flip the axes of the plot"""

self.flip_tree.emit()
86 changes: 61 additions & 25 deletions src/motile_plugin/data_views/views/tree_view/tree_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from motile_plugin.data_views.views_coordinator.tracks_viewer import TracksViewer

from .flip_axes_widget import FlipTreeWidget
from .navigation_widget import NavigationWidget
from .tree_view_feature_widget import TreeViewFeatureWidget
from .tree_view_mode_widget import TreeViewModeWidget
Expand Down Expand Up @@ -124,6 +125,7 @@ def update(
feature: str,
selected_nodes: list[Any],
reset_view: bool | None = False,
allow_flip: bool | None = True,
):
"""Update the entire view, including the data, view direction, and
selected nodes
Expand All @@ -136,11 +138,15 @@ def update(
"""
self.set_data(track_df, feature)
self._update_viewed_data(view_direction) # this can be expensive
self.set_view(view_direction, feature, reset_view)
self.set_view(view_direction, feature, reset_view, allow_flip)
self.set_selection(selected_nodes, feature)

def set_view(
self, view_direction: str, feature: str, reset_view: bool | None = False
self,
view_direction: str,
feature: str,
reset_view: bool | None = False,
allow_flip: bool | None = True,
):
"""Set the view direction, saving the new value as an attribute and
changing the axes labels. Shortcuts if the view direction is already
Expand All @@ -153,31 +159,34 @@ def set_view(
"""

if view_direction == self.view_direction and feature == self.feature:
if view_direction == "horizontal" or reset_view:
if reset_view:
self.autoRange()
return
if view_direction == "vertical":
self.setLabel("left", text="Time Point")
self.getAxis("left").setStyle(showValues=True)
if feature == "tree":
self.getAxis("bottom").setStyle(showValues=False)
self.setLabel("bottom", text="")
else: # should this actually ever happen?
self.getAxis("bottom").setStyle(showValues=True)
self.setLabel("bottom", text="Object size in calibrated units")
self.autoRange()
self.invertY(True) # to show tracks from top to bottom
elif view_direction == "horizontal":
self.setLabel("bottom", text="Time Point")
self.getAxis("bottom").setStyle(showValues=True)

axis_titles = {
"time": "Time Point",
"area": "Object size in calibrated units",
"tree": "",
}
if allow_flip:
if view_direction == "vertical":
time_axis = "left" # time is on y axis
feature_axis = "bottom"
self.invertY(True) # to show tracks from top to bottom
else:
time_axis = "bottom" # time is on y axis
feature_axis = "left"
self.invertY(False)
self.setLabel(time_axis, text=axis_titles["time"])
self.getAxis(time_axis).setStyle(showValues=True)

self.setLabel(feature_axis, text=axis_titles[feature])
if feature == "tree":
self.setLabel("left", text="")
self.getAxis("left").setStyle(showValues=False)
self.getAxis(feature).setStyle(showValues=False)
else:
self.setLabel("left", text="Object size in calibrated units")
self.getAxis("left").setStyle(showValues=True)
self.autoRange()
self.invertY(False)
self.getAxis(feature_axis).setStyle(showValues=True)
self.autoRange() # not sure if this is necessary or not

if (
self.view_direction != view_direction
or self.feature != feature
Expand Down Expand Up @@ -439,18 +448,23 @@ def __init__(self, viewer: napari.Viewer):
self.feature,
)

# Add widget to flip the axes
self.flip_widget = FlipTreeWidget()
self.flip_widget.flip_tree.connect(self._flip_axes)

# Construct a toolbar and set main layout
panel_layout = QHBoxLayout()
panel_layout.addWidget(self.mode_widget)
panel_layout.addWidget(self.feature_widget)
panel_layout.addWidget(self.navigation_widget)
panel_layout.addWidget(self.flip_widget)
panel_layout.setSpacing(0)
panel_layout.setContentsMargins(0, 0, 0, 0)

panel = QWidget()
panel.setLayout(panel_layout)
panel.setMaximumWidth(820)
panel.setMaximumHeight(78)
panel.setMaximumWidth(930)
panel.setMaximumHeight(82)

# Make a collapsible for TreeView widgets
collapsable_widget = QCollapsible("Show/Hide Tree View Controls")
Expand All @@ -476,6 +490,7 @@ def keyPressEvent(self, event: QKeyEvent) -> None:
Qt.Key_R: self.redo,
Qt.Key_Q: self.toggle_display_mode,
Qt.Key_W: self.toggle_feature_mode,
Qt.Key_F: self._flip_axes,
Qt.Key_X: lambda: self.set_mouse_enabled(x=True, y=False),
Qt.Key_Y: lambda: self.set_mouse_enabled(x=False, y=True),
}
Expand Down Expand Up @@ -525,6 +540,22 @@ def toggle_feature_mode(self):
"""Toggle feature mode."""
self.feature_widget._toggle_feature_mode()

def _flip_axes(self):
"""Flip the axes of the plot"""

if self.view_direction == "horizontal":
self.view_direction = "vertical"
else:
self.view_direction = "horizontal"

self.navigation_widget.view_direction = self.view_direction
self.tree_widget._update_viewed_data(self.view_direction)
self.tree_widget.set_view(
view_direction=self.view_direction,
feature=self.tree_widget.feature,
reset_view=False,
)

def set_mouse_enabled(self, x: bool, y: bool):
"""Enable or disable mouse zoom scrolling in X or Y direction."""
self.tree_widget.setMouseEnabled(x=x, y=y)
Expand Down Expand Up @@ -593,6 +624,9 @@ def _update_track_data(self, reset_view: bool | None = None) -> None:
self.view_direction = "vertical"
self.feature = "tree"
self.feature_widget.show_tree_radio.setChecked(True)
allow_flip = True
else:
allow_flip = False

# also update the navigation widget
self.navigation_widget.track_df = self.track_df
Expand All @@ -607,6 +641,7 @@ def _update_track_data(self, reset_view: bool | None = None) -> None:
self.feature,
self.selected_nodes,
reset_view=reset_view,
allow_flip=allow_flip,
)

else:
Expand All @@ -616,6 +651,7 @@ def _update_track_data(self, reset_view: bool | None = None) -> None:
self.feature,
self.selected_nodes,
reset_view=reset_view,
allow_flip=allow_flip,
)

def _set_mode(self, mode: str) -> None:
Expand Down
Loading