Skip to content

Commit

Permalink
visually group existing widgets using groupboxes
Browse files Browse the repository at this point in the history
  • Loading branch information
niksirbi committed Jan 11, 2024
1 parent 521b1dc commit 83546a7
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 36 deletions.
23 changes: 23 additions & 0 deletions brainglobe_template_builder/napari/_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,32 @@ def __init__(self, napari_viewer: Viewer, parent=None):
collapsible=True,
widget_title="Create mask",
)
self._expand_mask_widget()

self.add_widget(
FindMidline(napari_viewer, parent=self),
collapsible=True,
widget_title="Find midline",
)
self._connect_midline_widget_toggle()

def get_widgets(self):
"""Get all widgets in the container."""
return [
self.layout().itemAt(i).widget()
for i in range(self.layout().count())
]

def _expand_mask_widget(self):
"""Expand the mask widget."""
mask_widget = self.get_widgets()[0]
mask_widget.expand()

def _connect_midline_widget_toggle(self):
"""Connect the toggle of the midline widget to the refresh of its
dropdowns.
"""
midline_widget = self.get_widgets()[1]
midline_widget.toggled.connect(
midline_widget.content().refresh_dropdowns
)
29 changes: 20 additions & 9 deletions brainglobe_template_builder/napari/mask_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from qtpy.QtWidgets import (
QComboBox,
QFormLayout,
QGroupBox,
QPushButton,
QSpinBox,
QWidget,
Expand All @@ -20,23 +21,33 @@ def __init__(self, napari_viewer: Viewer, parent=None):
self.viewer = napari_viewer
self.setLayout(QFormLayout())

self.gauss_sigma = QSpinBox(parent=self)
self._create_mask_group()

def _create_mask_group(self):
"""Create the group of widgets concerned with creating a mask."""
self.mask_groupbox = QGroupBox("Create mask to exclude background")
self.mask_groupbox.setLayout(QFormLayout())
self.layout().addRow(self.mask_groupbox)

self.gauss_sigma = QSpinBox(parent=self.mask_groupbox)
self.gauss_sigma.setRange(0, 20)
self.gauss_sigma.setValue(3)
self.layout().addRow("gauss sigma:", self.gauss_sigma)
self.mask_groupbox.layout().addRow("gaussian sigma:", self.gauss_sigma)

self.threshold_method = QComboBox(parent=self)
self.threshold_method = QComboBox(parent=self.mask_groupbox)
self.threshold_method.addItems(["triangle", "otsu", "isodata"])
self.layout().addRow("threshold method:", self.threshold_method)
self.mask_groupbox.layout().addRow(
"threshold method:", self.threshold_method
)

self.closing_size = QSpinBox(parent=self)
self.closing_size = QSpinBox(parent=self.mask_groupbox)
self.closing_size.setRange(0, 20)
self.closing_size.setValue(5)
self.layout().addRow("closing size:", self.closing_size)
self.mask_groupbox.layout().addRow("closing size:", self.closing_size)

self.generate_mask_button = QPushButton("Create mask", parent=self)
self.layout().addRow(self.generate_mask_button)
self.generate_mask_button.clicked.connect(self._on_button_click)
self.create_mask_button = QPushButton("Create mask", parent=self)
self.mask_groupbox.layout().addRow(self.create_mask_button)
self.create_mask_button.clicked.connect(self._on_button_click)

def _on_button_click(self):
"""Create a mask from the selected image layer, using the parameters
Expand Down
93 changes: 66 additions & 27 deletions brainglobe_template_builder/napari/midline_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from qtpy.QtWidgets import (
QComboBox,
QFormLayout,
QGroupBox,
QPushButton,
QWidget,
)
Expand All @@ -21,44 +22,76 @@ def __init__(self, napari_viewer: Viewer, parent=None):
super().__init__(parent=parent)
self.viewer = napari_viewer
self.setLayout(QFormLayout())
self._create_estimate_group()
self._create_align_group()

def _create_estimate_group(self):
"""Create the group of widgets concerned with estimating midline
points."""
self.estimate_groupbox = QGroupBox("Estimate points along midline")
self.estimate_groupbox.setLayout(QFormLayout())
self.layout().addRow(self.estimate_groupbox)

# Add dropdown to select labels layer (mask)
self.select_mask_dropdown = QComboBox(parent=self.estimate_groupbox)
self.select_mask_dropdown.addItems(self._get_layers_by_type(Labels))
self.select_mask_dropdown.currentTextChanged.connect(
self._on_dropdown_selection_change
)
self.estimate_groupbox.layout().addRow(
"mask:", self.select_mask_dropdown
)

# Initialise button to estimate midline points
self.estimate_points_button = QPushButton(
"Estimate midline points", parent=self
"Estimate points", parent=self.estimate_groupbox
)
self.layout().addRow(self.estimate_points_button)
self.estimate_points_button.setEnabled(False)
self.estimate_points_button.clicked.connect(
self._on_estimate_button_click
)
self.estimate_groupbox.layout().addRow(self.estimate_points_button)

def _create_align_group(self):
"""Create the group of widgets concerned with aligning the image to
the midline."""

self.align_groupbox = QGroupBox("Align image to midline")
self.align_groupbox.setLayout(QFormLayout())
self.layout().addRow(self.align_groupbox)

# Add dropdown to select image layer
self.select_image_dropdown = QComboBox(parent=self)
self.select_image_dropdown = QComboBox(parent=self.align_groupbox)
self.select_image_dropdown.addItems(self._get_layers_by_type(Image))
self.select_image_dropdown.currentTextChanged.connect(
self._on_dropdown_selection_change
)
self.layout().addRow("image:", self.select_image_dropdown)
self.align_groupbox.layout().addRow(
"image:", self.select_image_dropdown
)

# Add dropdown to select points layer
self.select_points_dropdown = QComboBox(parent=self)
self.select_points_dropdown = QComboBox(parent=self.align_groupbox)
self.select_points_dropdown.addItems(self._get_layers_by_type(Points))
self.select_points_dropdown.currentTextChanged.connect(
self._on_dropdown_selection_change
)
self.layout().addRow("points:", self.select_points_dropdown)
self.align_groupbox.layout().addRow(
"points:", self.select_points_dropdown
)

# Add dropdown to select axis
self.select_axis_dropdown = QComboBox(parent=self)
self.select_axis_dropdown = QComboBox(parent=self.align_groupbox)
self.select_axis_dropdown.addItems(["x", "y", "z"])
self.layout().addRow("axis:", self.select_axis_dropdown)
self.align_groupbox.layout().addRow("axis:", self.select_axis_dropdown)

# Add button to align image to midline
self.align_image_button = QPushButton(
"Align image to midline", parent=self
"Align image", parent=self.align_groupbox
)
self.layout().addRow(self.align_image_button)
self.align_image_button.clicked.connect(self._on_align_button_click)
self.align_image_button.setEnabled(False)
self.align_image_button.clicked.connect(self._on_align_button_click)
self.align_groupbox.layout().addRow(self.align_image_button)

# 9 colors taken from ColorBrewer2.org Set3 palette
self.point_colors = [
Expand All @@ -81,28 +114,25 @@ def _get_layers_by_type(self, layer_type: Layer) -> list:
if isinstance(layer, layer_type)
]

def _refresh_layer_dropdowns(self):
def refresh_dropdowns(self):
"""Refresh the dropdowns to reflect the current layers."""
for layer_type, dropdown in zip(
[Image, Points],
[self.select_image_dropdown, self.select_points_dropdown],
[Labels, Image, Points],
[
self.select_mask_dropdown,
self.select_image_dropdown,
self.select_points_dropdown,
],
):
dropdown.clear()
dropdown.addItems(self._get_layers_by_type(layer_type))

def _on_estimate_button_click(self):
"""Estimate midline points and add them to the viewer."""
if len(self.viewer.layers.selection) != 1:
show_info("Please select exactly one Labels layer")
return None

mask = list(self.viewer.layers.selection)[0]

if not isinstance(mask, Labels):
show_info("The selected layer is not a Labels layer")
return None

# Estimate 9 midline points
# Estimate 9 midline points based on the selected mask
mask_name = self.select_mask_dropdown.currentText()
mask = self.viewer.layers[mask_name]
points = get_midline_points(mask.data)
# Point layer attributes
point_attrs = {
Expand All @@ -119,7 +149,11 @@ def _on_estimate_button_click(self):

mask.visible = False
self.viewer.add_points(points, **point_attrs)
self._refresh_layer_dropdowns()
self.refresh_dropdowns()
show_info(
"Please move the estimated points so that they sit exactly "
"on the mid-sagittal plane."
)

def _on_align_button_click(self):
"""Align image and add the transformed image to the viewer."""
Expand All @@ -138,8 +172,13 @@ def _on_align_button_click(self):
self.viewer.add_image(aligned_image, name="aligned image")

def _on_dropdown_selection_change(self):
"""Enable align button if both image and points dropdowns
have a selection."""
# Enable estimate button if mask dropdown has a value
if self.select_mask_dropdown.currentText() == "":
self.estimate_points_button.setEnabled(False)
else:
self.estimate_points_button.setEnabled(True)

# Enable align button if both image and points dropdowns have a value
if (
self.select_image_dropdown.currentText() == ""
or self.select_points_dropdown.currentText() == ""
Expand Down

0 comments on commit 83546a7

Please sign in to comment.