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

Communicate napari layer deletions appropriately to the plugin #49

Merged
merged 15 commits into from
Aug 13, 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
102 changes: 83 additions & 19 deletions brainglobe_registration/registration_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
from brainglobe_atlasapi import BrainGlobeAtlas
from brainglobe_atlasapi.list_atlases import get_downloaded_atlases
from brainglobe_utils.qtpy.collapsible_widget import CollapsibleWidgetContainer
from brainglobe_utils.qtpy.dialog import display_info
from brainglobe_utils.qtpy.logo import header_widget
from dask_image.ndinterp import affine_transform as dask_affine_transform
from napari.qt.threading import thread_worker
from napari.utils.events import Event
from napari.utils.notifications import show_error
from napari.viewer import Viewer
from pytransform3d.rotations import active_matrix_from_angle
Expand Down Expand Up @@ -60,6 +62,8 @@
self._atlas_annotations_layer: Optional[napari.layers.Labels] = None
self._moving_image: Optional[napari.layers.Image] = None
self._moving_image_data_backup: Optional[npt.NDArray] = None
self._automatic_deletion_flag = False
# Flag to differentiate between manual and automatic atlas deletion

self.transform_params: dict[str, dict] = {
"rigid": {},
Expand Down Expand Up @@ -136,6 +140,8 @@
self._on_default_file_selection_change
)

# Use decorator to connect to layer deletion event
self._connect_events()
self.filter_checkbox = QCheckBox("Filter Images")
self.filter_checkbox.setChecked(False)

Expand Down Expand Up @@ -183,33 +189,69 @@

check_atlas_installed(self)

def _connect_events(self):
@self._viewer.layers.events.removed.connect
def _on_layer_deleted(event: Event):
if not self._automatic_deletion_flag:
self._handle_layer_deletion(event)

def _handle_layer_deletion(self, event: Event):
deleted_layer = event.value

# Check if the deleted layer is the moving image
if self._moving_image == deleted_layer:
self._moving_image = None
self._moving_image_data_backup = None
self._update_dropdowns()

# Check if deleted layer is the atlas reference / atlas annotations
if (
self._atlas_data_layer == deleted_layer
or self._atlas_annotations_layer == deleted_layer
):
# Reset the atlas selection combobox
self.get_atlas_widget.reset_atlas_combobox()

def _delete_atlas_layers(self):
# Delete atlas reference layer if it exists
if self._atlas_data_layer in self._viewer.layers:
self._viewer.layers.remove(self._atlas_data_layer)

# Delete atlas annotations layer if it exists
if self._atlas_annotations_layer in self._viewer.layers:
self._viewer.layers.remove(self._atlas_annotations_layer)

# Clear atlas attributes
self._atlas = None
self._atlas_data_layer = None
self._atlas_annotations_layer = None
self.run_button.setEnabled(False)
self._viewer.grid.enabled = False

def _update_dropdowns(self):
# Extract the names of the remaining layers
layer_names = get_image_layer_names(self._viewer)
# Update the dropdowns in SelectImagesView
self.get_atlas_widget.update_sample_image_names(layer_names)

def _on_atlas_dropdown_index_changed(self, index):
# Hacky way of having an empty first dropdown
if index == 0:
if self._atlas:
current_atlas_layer_index = find_layer_index(
self._viewer, self._atlas.atlas_name
)

self._viewer.layers.pop(current_atlas_layer_index)
self._atlas = None
self._atlas_data_layer = None
self._atlas_annotations_layer = None
self.run_button.setEnabled(False)
self._viewer.grid.enabled = False

self._delete_atlas_layers()
saarah815 marked this conversation as resolved.
Show resolved Hide resolved
return

atlas_name = self._available_atlases[index]

if self._atlas:
current_atlas_layer_index = find_layer_index(
self._viewer, self._atlas.atlas_name
)
# Set flag to True when atlas is changed, not manually deleted
# Ensures atlas index does not reset to 0
self._automatic_deletion_flag = True
try:
self._delete_atlas_layers()
finally:
self._automatic_deletion_flag = False

self._viewer.layers.pop(current_atlas_layer_index)
else:
self.run_button.setEnabled(True)
self.run_button.setEnabled(True)

self._atlas = BrainGlobeAtlas(atlas_name)
dask_reference = da.from_array(
Expand Down Expand Up @@ -252,13 +294,19 @@
viewer_index = find_layer_index(
self._viewer, self._sample_images[index]
)
if viewer_index == -1:
self._moving_image = None
self._moving_image_data_backup = None

return

self._moving_image = self._viewer.layers[viewer_index]
self._moving_image_data_backup = self._moving_image.data.copy()

def _on_adjust_moving_image(self, x: int, y: int, rotate: float):
if not self._moving_image:
show_error(
"No moving image selected. "
"No moving image selected."
"Please select a moving image before adjusting"
)
return
Expand All @@ -276,6 +324,22 @@
def _on_run_button_click(self):
from brainglobe_registration.elastix.register import run_registration

if self._atlas_data_layer is None:
display_info(

Check warning on line 328 in brainglobe_registration/registration_widget.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_registration/registration_widget.py#L327-L328

Added lines #L327 - L328 were not covered by tests
widget=self,
title="Warning",
message="Please select an atlas before clicking 'Run'.",
)
return

Check warning on line 333 in brainglobe_registration/registration_widget.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_registration/registration_widget.py#L333

Added line #L333 was not covered by tests

if self._moving_image == self._atlas_data_layer:
display_info(

Check warning on line 336 in brainglobe_registration/registration_widget.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_registration/registration_widget.py#L335-L336

Added lines #L335 - L336 were not covered by tests
widget=self,
title="Warning",
message="Your moving image cannot be an atlas.",
)
return

Check warning on line 341 in brainglobe_registration/registration_widget.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_registration/registration_widget.py#L341

Added line #L341 was not covered by tests

current_atlas_slice = self._viewer.dims.current_step[0]

if self.filter_checkbox.isChecked():
Expand Down
7 changes: 6 additions & 1 deletion brainglobe_registration/widgets/select_images_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def __init__(

def update_sample_image_names(self, sample_image_names: List[str]):
self.available_sample_dropdown.clear()
self.available_sample_dropdown.addItems(sample_image_names)
if len(sample_image_names) != 0:
self.available_sample_dropdown.addItems(sample_image_names)

def _on_atlas_index_change(self):
"""
Expand All @@ -122,5 +123,9 @@ def _on_moving_image_index_change(self):
self.available_sample_dropdown.currentIndex()
)

def reset_atlas_combobox(self):
if self.available_atlas_dropdown is not None:
self.available_atlas_dropdown.setCurrentIndex(0)

def _on_sample_popup_about_to_show(self):
self.sample_image_popup_about_to_show.emit()
Loading