Skip to content
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
2 changes: 1 addition & 1 deletion docs/extend/01_gui.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ This workshop has **four blocks**:
|-------|-------|
| **1** | Welcome and GUI Walkthrough — get oriented in the napari viewer |
| **2** | Python, Data, and Metadata — control napari from Python, set physical scales, work with xarray and Zarr |
| **3** | Custom Widgets and Interactions — build interactive GUIs with magicgui, keybindings, and mouse callbacks |
| **3** | Custom Widgets and Interactions — build interactive GUIs with magicgui, layer events, and mouse callbacks |
| **4** | From Script to Plugin — package your custom tools as pip-installable napari plugins |

With everything from microscopes to telescopes to satellites, scientists
Expand Down
73 changes: 5 additions & 68 deletions docs/extend/03_widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ kernelspec:
name: python3
---

**Goal:** Add interactive GUI widgets, custom keybindings, layer event
callbacks, and mouse drag interactions to napari — turning analysis functions
into interactive tools.
**Goal:** Add interactive GUI widgets, layer event callbacks, and mouse
drag interactions to napari — turning analysis functions into interactive
tools.

# Setup

Expand Down Expand Up @@ -314,70 +314,8 @@ ndevio returned a `list` of `LayerDataTuple`s. Can you modify `detect_spots()`
to also return the high-pass filtered image as an image layer?
Hint: Only the return statement needs to change!
```
(extend-block3-keybindings)=
# 3. Custom keybindings

Keybindings let you trigger actions with keyboard shortcuts. napari makes
this remarkably easy with the `bind_key` decorator.

Let's bind `Shift-D` to report how many spots were detected in the current
Points layer. We'll attach it to the Points layer type so it only fires
when a Points layer is active:

```{code-cell} ipython3
from napari.layers import Points
from napari.utils.notifications import show_info

@Points.bind_key("Shift-D")
def report_spot_count(points_layer: Points):
"""Print the number of detected spots in the active Points layer."""
count = len(points_layer.data)
show_info(f"Detected {count} spots")
```

Now select the Points layer created by `detect_spots` and press `Shift-D`.
You should see a notification pop up in the viewer!

```{code-cell} ipython3
:tags: [remove-cell]

# Simulate for the notebook
report_spot_count(viewer.layers['points'])
```

```{tip}
We used `show_info()` instead of `print()` — this displays a notification
right in the napari viewer, which is much more visible than looking for
output in a notebook or terminal. Check out
[`napari.utils.notifications`](https://napari.org/dev/api/napari.utils.notifications.html)
for `show_warning()` and `show_error()` too.
```

```{important}
At the moment, `bind_key` shortcuts cannot overwrite napari's built-in
shortcuts. If a built-in shortcut uses the same key combination, the
built-in one wins — silently. Check **File > Preferences > Shortcuts**
to see which keys are already taken.
```

Keybindings can also be attached to the viewer (fires regardless of which
layer is active):

```{code-cell} ipython3
@viewer.bind_key('Shift-R')
def run_detector(viewer):
"""Re-run spot detection with current settings."""
detect_spots(viewer.layers['spots'].data)
```

```{code-cell} ipython3
:tags: [remove-cell]

viewer.close()
```

(extend-block3-events)=
# 4. Layer events
# 3. Layer events

napari layers emit **events** when their properties change — data, colormap,
opacity, even individual point positions. You can connect custom functions
Expand Down Expand Up @@ -457,7 +395,7 @@ viewer.layers['checkerboard'].data = image
```

(extend-block3-mouse)=
# 5. Mouse callbacks
# 4. Mouse callbacks

Layer events fire when a change *completes*. But what if you want to react
while the user is dragging? That's where **mouse callbacks** come in.
Expand Down Expand Up @@ -535,7 +473,6 @@ In this block you learned to:
| Technique | What it does | How to attach |
|-----------|-------------|---------------|
| **magicgui** | Auto-generate GUI widgets from functions | `@magicgui` + `viewer.window.add_dock_widget()` |
| **Custom keybindings** | Trigger actions with keyboard shortcuts | `@Points.bind_key('Shift-D')` / `@viewer.bind_key('key')` |
| **Layer events** | React to property changes | `layer.events.data.connect(callback)` |
| **Mouse callbacks** | React to mouse drag in real time | `layer.mouse_drag_callbacks.append(callback)` |

Expand Down
2 changes: 1 addition & 1 deletion docs/extend/schedule-360.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ to help but not leading each step.
| 1:55 | **Break** | — | — |
| 2:05 | Write and test analysis functions | [Analysis functions](03_widgets.md#extend-block3-functions) | follow along |
| 2:15 | Build interactive controls with magicgui | [magicgui](03_widgets.md#extend-block3-magicgui) | follow along |
| 2:35 | Keybindings and layer events | [Keybindings](03_widgets.md#extend-block3-keybindings), [Layer events](03_widgets.md#extend-block3-events) | follow along |
| 2:35 | Layer events | [Layer events](03_widgets.md#extend-block3-events) | follow along |
| 2:50 | Mouse callbacks | [Mouse callbacks](03_widgets.md#extend-block3-mouse) | follow along |
| 3:00 | **Break** | — | — |
| 3:05 | Plugin model and contribution types | [Plugin workshop material](04_plugin.md) | show |
Expand Down
4 changes: 2 additions & 2 deletions docs/extend/schedule-90.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ to help but not leading each step.
| 0:25 | Your data and its meaning (scale, units, axis labels) | [Block 2 §4-5](#extend-block2-scale) | follow along |
| 0:40 | **Break** | — | — |
| 0:45 | From function to control panel (magicgui) | [Block 3 §1-2](#extend-block3-functions) | follow along |
| 1:05 | Demo - interactions, keybindings, and plugins | [Block 3 §3-5](#extend-block3-keybindings) and [Block 4](#extend-block4) | demo |
| 1:05 | Demo - interactions and plugins | [Block 3 §3-4](#extend-block3-events) and [Block 4](#extend-block4) | demo |
| 1:20 | Survey and wrap-up | — | show |
| 1:25 | Buffer | — | — |

Expand All @@ -49,4 +49,4 @@ to help but not leading each step.
[Introduction to napari: with the App](#intro-overview) (no code).
- Want the whole thing rather than the 90-minute path?
[Half-day schedule](#extend-schedule-360) continues from where this session
stops, including Zarr, custom keybindings, and plugin packaging.
stops, including Zarr, layer and mouse interactions, and plugin packaging.
Loading