Skip to content

Commit

Permalink
Communicate napari layer deletions appropriately to the plugin (#49)
Browse files Browse the repository at this point in the history
* layer_deletion

* Update brainglobe_registration/registration_widget.py

Co-authored-by: Igor Tatarnikov <61896994+IgorTatarnikov@users.noreply.github.com>

* layer_deletion_edits

* Made pytest happy

* Update brainglobe_registration/registration_widget.py

Co-authored-by: Igor Tatarnikov <61896994+IgorTatarnikov@users.noreply.github.com>

* Update brainglobe_registration/registration_widget.py

Co-authored-by: Igor Tatarnikov <61896994+IgorTatarnikov@users.noreply.github.com>

* Update brainglobe_registration/registration_widget.py

Co-authored-by: Igor Tatarnikov <61896994+IgorTatarnikov@users.noreply.github.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* updated_layer

* fixed manual vs automatic deletion

* fixed manual vs automatic deletion

* Refactored some old code to avoid duplication

* add comments

---------

Co-authored-by: Igor Tatarnikov <61896994+IgorTatarnikov@users.noreply.github.com>
Co-authored-by: IgorTatarnikov <igor.tatarnikov@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Aug 13, 2024
1 parent f690dea commit 17435b1
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 20 deletions.
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 @@ def __init__(self, napari_viewer: Viewer):
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 @@ def __init__(self, napari_viewer: Viewer):
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 @@ def __init__(self, napari_viewer: Viewer):

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()
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 @@ def _on_sample_dropdown_index_changed(self, index):
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_adjust_moving_image_reset_button_click(self):
def _on_run_button_click(self):
from brainglobe_registration.elastix.register import run_registration

if self._atlas_data_layer is None:
display_info(
widget=self,
title="Warning",
message="Please select an atlas before clicking 'Run'.",
)
return

if self._moving_image == self._atlas_data_layer:
display_info(
widget=self,
title="Warning",
message="Your moving image cannot be an atlas.",
)
return

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()

0 comments on commit 17435b1

Please sign in to comment.