Types & Widgets

The central feature of magicgui is conversion from an argument type declared in a function signature, to an appropriate widget type for the given backend. This page describes the logic used.

type inference

magicgui determines the type of an argument as follows:

  1. If a type hint is provided, it is used (regardless of the type of the default value, if provided).

  2. If no type hint is provided, the type of the default value is used, if one is provided.

  3. If a bare argument is defined without a type annotation or default value, it is assumed to be a string.

# arg is assumed to be a float
def function(arg: float = 1):
    ...

# arg is assumed to be a float
def function(arg = 1.0):
    ...

# arg is assumed to be a str
def function(arg):
    ...

type-to-widget conversion

Using a set of type_matcher()s and other logic defined in the magicgui.type_map module, magicgui will select an appropriate Widget subclass to display the any given type or type annotation. To see the default type of widget magicgui will for a given value, use the get_widget_class() function:

import datetime
from enum import Enum
from pathlib import Path
from magicgui.type_map import get_widget_class

Animal = Enum('Animal', 'ANT BEE CAT DOG')
values = [
    True, 1, 3.43, 'text', Path.home(),
    datetime.datetime.now(), datetime.time(12, 30),
    datetime.date(2000, 2, 18),
    Animal.ANT, range(10), slice(1,20), lambda x: x
]
for v in values:
    cls, options = get_widget_class(v)
    print(f"The widget for {type(v)} is {cls.__name__!r}")
The widget for <class 'bool'> is 'CheckBox'
The widget for <class 'int'> is 'SpinBox'
The widget for <class 'float'> is 'FloatSpinBox'
The widget for <class 'str'> is 'LineEdit'
The widget for <class 'pathlib.PosixPath'> is 'FileEdit'
The widget for <class 'datetime.datetime'> is 'DateTimeEdit'
The widget for <class 'datetime.time'> is 'TimeEdit'
The widget for <class 'datetime.date'> is 'DateEdit'
The widget for <enum 'Animal'> is 'ComboBox'
The widget for <class 'range'> is 'RangeEdit'
The widget for <class 'slice'> is 'SliceEdit'
The widget for <class 'function'> is 'FunctionGui'

register_type

To provide custom behavior for a specific object type, you may use the magicgui.type_map.register_type() function to:

  1. register a special widget_type

  2. register a special set of choices used when magicgui encounters that type

  3. control what happens when magicgui encounters a function with a return annotation of your custom type.

Hint

This is how napari registers itself to handle napari-specific types in magicgui functions, as shown in the examples

to get a drop-down list:

  • use an Enum as either the default value or type hint for an argument

from magicgui import magicgui
from enum import Enum

class RefractiveIndex(Enum):
    Oil = 1.515
    Water = 1.33
    Air = 1.0

@magicgui
def function_a(ri = RefractiveIndex.Water):
    ...

function_a.show()
../_images/types_widgets_3_0.png
@magicgui(ri={"choices": ["Oil", "Water", "Air"]})
def function_b(ri="Water"):
    ...

function_b.show()
../_images/types_widgets_5_0.png

Note

In the first example using an Enum, the value of the attribute will be an enum instance. In the second example using a choices list, the value will be a simple string:

>>> print(repr(function_a.ri.value))
<RefractiveIndex.Water: 1.33>
>>> print(repr(function_b.ri.value))
'Water'

If you’d like to have a drop-down menu with strings labels, but don’t want to use an Enum, you can use a list of 2-tuples:

@magicgui(ri={"choices": [("Oil", 1.515), ("Water", 1.33), ("Air", 1.0)]})
def function_c(ri=1.33):
    ...
>>> print(repr(function_c.ri.value))
1.33