Skip to content

Commit

Permalink
update napari examples (#357)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 committed Jan 20, 2022
1 parent 0ac4809 commit 7727732
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 51 deletions.
42 changes: 42 additions & 0 deletions examples/napari_combine_qt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
Napari provides a few conveniences with magicgui, and one of the
most commonly used is the layer combo box that gets created when
a parameter is annotated as napari.layers.Layer.
The layer box will stay in sync with the viewer model, adding and
removing layers as needed.
This example shows how to use just that widget in the context
of a larger custom QWidget.
"""
import napari
from qtpy.QtWidgets import QVBoxLayout, QWidget

from magicgui.widgets import create_widget


class CustomWidget(QWidget):
def __init__(self) -> None:
super().__init__()
self.setLayout(QVBoxLayout())
# change annotation to napari.layers.Image (e.g) to restrict to just Images
self._layer_combo = create_widget(annotation=napari.layers.Layer)
# magicgui widgets hold the Qt widget at `widget.native`
self.layout().addWidget(self._layer_combo.native)


viewer = napari.Viewer()
viewer.add_points()
viewer.add_points()

my_widget = CustomWidget()
viewer.window.add_dock_widget(my_widget)

# when my_widget is a magicgui.Widget, it will detect that it has been added
# to a viewer, and automatically update the choices. Otherwise, you need to
# trigger this yourself:
my_widget._layer_combo.reset_choices()
viewer.layers.events.inserted.connect(my_widget._layer_combo.reset_choices)
viewer.layers.events.removed.connect(my_widget._layer_combo.reset_choices)

napari.run()
41 changes: 19 additions & 22 deletions examples/napari_image_arithmetic.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Basic example of using magicgui to create an Image Arithmetic GUI in napari."""
from enum import Enum

import napari
import numpy
from napari import Viewer, gui_qt
from napari.layers import Image
from napari.types import ImageData

Expand All @@ -23,28 +23,25 @@ class Operation(Enum):
divide = numpy.divide


with gui_qt():
# create a viewer and add a couple image layers
viewer = Viewer()
viewer.add_image(numpy.random.rand(20, 20), name="Layer 1")
viewer.add_image(numpy.random.rand(20, 20), name="Layer 2")
# create a viewer and add a couple image layers
viewer = napari.Viewer()
viewer.add_image(numpy.random.rand(20, 20), name="Layer 1")
viewer.add_image(numpy.random.rand(20, 20), name="Layer 2")

# use the magic decorator! This takes a function, and generates a widget instance
# using the function signature. Note that we aren't returning a napari Image layer,
# but instead a numpy array which we want napari to interperate as Image data.
@magicgui(call_button="execute")
def image_arithmetic(
layerA: Image, operation: Operation, layerB: Image
) -> ImageData:
"""Add, subtracts, multiplies, or divides to image layers with equal shape."""
return operation.value(layerA.data, layerB.data)

# add our new magicgui widget to the viewer
viewer.window.add_dock_widget(image_arithmetic)
# for details on why the `-> ImageData` return annotation works:
# https://napari.org/guides/stable/magicgui.html#return-annotations
@magicgui(call_button="execute", layout="horizontal")
def image_arithmetic(layerA: Image, operation: Operation, layerB: Image) -> ImageData:
"""Add, subtracts, multiplies, or divides to image layers with equal shape."""
return operation.value(layerA.data, layerB.data)

# keep the dropdown menus in the gui in sync with the layer model
viewer.layers.events.inserted.connect(image_arithmetic.reset_choices)
viewer.layers.events.removed.connect(image_arithmetic.reset_choices)

# note: the function may still be called directly as usual!
# new_image = image_arithmetic(img_a, Operation.add, img_b)
# add our new magicgui widget to the viewer
viewer.window.add_dock_widget(image_arithmetic, area="bottom")


# note: the function may still be called directly as usual!
# new_image = image_arithmetic(img_a, Operation.add, img_b)

napari.run()
57 changes: 28 additions & 29 deletions examples/napari_param_sweep.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,31 @@

from magicgui import magicgui

with napari.gui_qt():
# create a viewer and add some images
viewer = napari.Viewer()
viewer.add_image(skimage.data.astronaut().mean(-1), name="astronaut")
viewer.add_image(skimage.data.grass().astype("float"), name="grass")

# turn the gaussian blur function into a magicgui
# - `auto_call` tells magicgui to call the function whenever a parameter changes
# - we use `widget_type` to override the default "float" widget on sigma
# - we provide some Qt-specific parameters
# - we contstrain the possible choices for `mode`
# Note that we aren't returning a napari Image layer, but instead a numpy array
# which we want napari to interperate as Image data.
@magicgui(
auto_call=True,
sigma={"widget_type": "FloatSlider", "max": 6},
mode={"choices": ["reflect", "constant", "nearest", "mirror", "wrap"]},
)
def gaussian_blur(layer: Image, sigma: float = 1.0, mode="nearest") -> ImageData:
"""Apply a gaussian blur to ``layer``."""
if layer:
return skimage.filters.gaussian(layer.data, sigma=sigma, mode=mode)

# Add it to the napari viewer
# NOTE: using `.native` will not be necessary after
# https://github.com/napari/napari/pull/1994
viewer.window.add_dock_widget(gaussian_blur.native)
# update the layer dropdown menu when the layer list changes
viewer.layers.events.changed.connect(gaussian_blur.reset_choices)
# create a viewer and add some images
viewer = napari.Viewer()
viewer.add_image(skimage.data.astronaut().mean(-1), name="astronaut")
viewer.add_image(skimage.data.grass().astype("float"), name="grass")


# turn the gaussian blur function into a magicgui
# for details on why the `-> ImageData` return annotation works:
# https://napari.org/guides/stable/magicgui.html#return-annotations
@magicgui(
# tells magicgui to call the function whenever a parameter changes
auto_call=True,
# `widget_type` to override the default (spinbox) "float" widget
sigma={"widget_type": "FloatSlider", "max": 6},
# contstrain the possible choices for `mode`
mode={"choices": ["reflect", "constant", "nearest", "mirror", "wrap"]},
layout="horizontal",
)
def gaussian_blur(layer: Image, sigma: float = 1.0, mode="nearest") -> ImageData:
"""Apply a gaussian blur to ``layer``."""
if layer:
return skimage.filters.gaussian(layer.data, sigma=sigma, mode=mode)


# Add it to the napari viewer
viewer.window.add_dock_widget(gaussian_blur, area="bottom")

napari.run()

0 comments on commit 7727732

Please sign in to comment.