Event handling in Napari

Hey napari friends,

I’m attempting to listen to events in napari. Specifically, I’m looking for a way to react to a specifc layer being removed. I would like to do something with the layer before or after it disappears.

Related basic question: Is there a full list of events one can connect to and some explanation for each? The intro here is great. I’d like to learn more :slight_smile:

If found

  • events in viewer.layers:

    • status
    • active_layer
    • layers_change
  • events in individual layers

    • refresh
    • set_data
    • select
    • deselect
    • data
    • name
    • loaded
  • Side note, in this thread a viewer.layers.events.added is mentioned, but in the code, I can only find viewer.layers.events.inserted.

My use case is the following: I would like to associate a dock-widget with each layer I create. If I activate a layer, the dock widget is shown. Dock widgets associated with other layers are removed. Therefore I need to listen to a “removed” event that is thrown on the removed layer. I can only find a removed event on all layers but then, the layer is gone and I can’t access it anymore. Thus, I cannot remove its dock widget.

Any hint is appreciated!

Cheers,
Robert

5 Likes

The LayerList (i.e. viewer.layers) has events removed and removing that might do what you need. viewer.layers is a LayerList which is a sublcass of EventedList which has a decent docstring on all of the events and what they do.

Here’s a rough sketch that might work for you (untested)

DOCK_WIDGETS = {} # keep a map of layer keys -> dock_widget values

def _on_removing(event):
    print(event.index)  # the index about to be removed

def _on_removed(event):
    print(event.index)  # the index that was removed
    # NOTE: event.value on the removed event IS the layer...
    # so while it's not still in the layerlist, it isn't entirely gone
    layer = event.value  # the object that was removed
    viewer.window.remove_dock_widget(DOCK_WIDGETS.pop(layer))

viewer.layers.events.removing.connect(_on_removing)
viewer.layers.events.removed.connect(_on_removed)

Sadly, there’s no global list in the dev docs just yet, so one still has to kinda look through the source. The event architecture is in heavy flux after
#1475, (and see #1490 for progress tracking). I whole-heartedly agree that a full list like this would be super useful, and not that hard to pull together. Ideally would be autogenerated… I started working on an autogenerated event connection graph here… it has a pretty good list of events (and could be used for docs too), though it might need updating.

yeah, viewer.layers has undergone some changes since Dec last year :slight_smile: sorry (specifically, we’re trying to bring its syntax and terminology inline with a plain python list)

4 Likes

Hey @talley,

great, it works like a charm. Thanks for the quick response. Just for completeness, a fully executable example:

import napari
from skimage.io import imread
image = imread('https://samples.fiji.sc/blobs.png')

with napari.gui_qt():
    viewer = napari.Viewer()
    viewer.add_image(image)
    viewer.add_image(image)
    viewer.add_image(image)
    viewer.add_image(image)

    def _on_removed(event):
        layer = event.value
        print("removed: " + layer.name)

    viewer.layers.events.removed.connect(_on_removed)

Thanks :raised_hands:

7 Likes