# napari image arithmetic widget¶

napari is a fast, interactive, multi-dimensional image viewer for python. It uses Qt for the GUI, so it’s easy to extend napari with small, composable widgets created with `magicgui`

. Here we’re going to build this simple image arithmetic widget with a few additional lines of code.

For napari-specific magicgui documentation, see the napari docs

## outline¶

**This example demonstrates how to:**

⬇️ Create a `magicgui`

widget that can be used in another program (napari)

⬇️ Use an `Enum`

to create a dropdown menu

⬇️ Connect some event listeners to create interactivity.

## code¶

*Code follows, with explanation below… You can also get this example at github.*

```
1from enum import Enum
2
3import numpy
4import napari
5from napari.types import ImageData
6
7from magicgui import magicgui
8
9class Operation(Enum):
10 """A set of valid arithmetic operations for image_arithmetic.
11
12 To create nice dropdown menus with magicgui, it's best
13 (but not required) to use Enums. Here we make an Enum
14 class for all of the image math operations we want to
15 allow.
16 """
17 add = numpy.add
18 subtract = numpy.subtract
19 multiply = numpy.multiply
20 divide = numpy.divide
21
22
23# here's the magicgui! We also use the additional
24# `call_button` option
25@magicgui(call_button="execute")
26def image_arithmetic(
27 layerA: ImageData, operation: Operation, layerB: ImageData
28) -> ImageData:
29 """Add, subtracts, multiplies, or divides to image layers."""
30 return operation.value(layerA, layerB)
31
32# create a viewer and add a couple image layers
33viewer = napari.Viewer()
34viewer.add_image(numpy.random.rand(20, 20), name="Layer 1")
35viewer.add_image(numpy.random.rand(20, 20), name="Layer 2")
36
37# add our new magicgui widget to the viewer
38viewer.window.add_dock_widget(image_arithmetic)
39
40# keep the dropdown menus in the gui in sync with the layer model
41viewer.layers.events.inserted.connect(image_arithmetic.reset_choices)
42viewer.layers.events.removed.connect(image_arithmetic.reset_choices)
43
44napari.run()
```

## walkthrough¶

We’re going to go a little out of order so that the other code makes more sense. Let’s start with the actual function we’d like to write to do some image arithmetic.

### the function¶

Our function takes two `numpy`

arrays (in this case, from Image layers), and some mathematical operation (we’ll restrict the options using an `Enum`

). When called, our function calls the selected operation on the data.

```
def image_arithmetic(array1, operation, array2):
return operation.value(array1, array2)
```

#### type annotations¶

`magicgui`

works particularly well with type annotations, and allows third-party libraries to register widgets and behavior for handling their custom types (using `magicgui.type_map.register_type()`

). `napari`

provides support for `magicgui`

by registering a dropdown menu whenever a function parameter is annotated as one of the basic napari `Layer`

types, or, in this case, `ImageData`

indicates we just the `data`

attribute of the layer. Furthermore, it recognizes when a function has a `Layer`

or `LayerData`

return type annotation, and will add the result to the viewer. So we gain a *lot* by annotating the above function with the appropriate `napari`

types.

```
from napari.types import ImageData
def image_arithmetic(
layerA: ImageData, operation: Operation, layerB: ImageData
) -> ImageData:
return operation.value(layerA, layerB)
```

### the magic part¶

Finally, we decorate the function with `@magicgui`

and tell it we’d like to have a `call_button`

that we can click to execute the function.

```
@magicgui(call_button="execute")
def image_arithmetic(layerA: ImageData, operation: Operation, layerB: ImageData):
return operation.value(layerA, layerB)
```

That’s it! The `image_arithmetic`

function is now a `FunctionGui`

that can be shown, or incorporated into other GUIs (such as the napari GUI shown in this example)

Note

While type hints aren’t always required in `magicgui`

, they are recommended (see type inference )… and they *are* required for certain things, like the `Operation(Enum)`

used here for the dropdown and the `napari.types.ImageData`

annotations that `napari`

has registered with `magicgui`

.

### create dropdowns with Enums¶

We’d like the user to be able to select the operation (`add`

, `subtract`

, `multiply`

, `divide`

) using a dropdown menu. `Enum`

s offer a convenient way to restrict values to a strict set of options, while providing `name: value`

pairs for each of the options. Here, the value for each choice is the actual function we would like to have called when that option is selected.

```
class Operation(enum.Enum):
add = numpy.add
subtract = numpy.subtract
multiply = numpy.multiply
divide = numpy.divide
```

### add it to napari¶

When we decorated the `image_arithmetic`

function above, it became a `FunctionGui`

. Napari recognizes this type, so we can simply add it to the napari viewer as follows:

```
viewer.window.add_dock_widget(image_arithmetic)
```

Caution

This api has changed slightly with version 0.2.0 of magicgui. See the migration guide if you are migrating from a previous version.

### connect event listeners for interactivity¶

What fun is a GUI without some interactivity? Let’s make stuff happen.

We connect the `image_arithmetic.reset_choices`

function to the `viewer.layers.events.inserted/removed`

event from `napari`

, to make sure that the dropdown menus stay in sync if a layer gets added or removed from the napari window:

```
viewer.layers.events.inserted.connect(image_arithmetic.reset_choices)
viewer.layers.events.removed.connect(image_arithmetic.reset_choices)
```

Tip

An additional offering from `magicgui`

here is that the decorated function also acquires a new attribute “`called`

” that can be connected to callback functions of your choice. Then, whenever the gui widget *or the original function* are called, the result will be passed to your callback function:

```
@image_arithmetic.called.connect
def print_mean(value):
"""Callback function that accepts an event"""
# the value attribute has the result of calling the function
print(np.mean(value))
```

```
>>> image_arithmetic()
1.0060037881040373
```