예제 #1
0
def test_container_widget():
    """Test basic container functionality."""
    container = widgets.Container(labels=False)
    labela = widgets.Label(value="hi", name="labela")
    labelb = widgets.Label(value="hi", name="labelb")
    container.append(labela)
    container.extend([labelb])
    # different ways to index
    assert container[0] == labela
    assert container["labelb"] == labelb
    assert container[:1] == [labela]
    assert container[-1] == labelb

    with pytest.raises(NotImplementedError):
        container[0] = "something"

    assert container.layout == "vertical"
    with pytest.raises(NotImplementedError):
        container.layout = "horizontal"

    assert all(x in dir(container) for x in ["labela", "labelb"])

    assert container.margins
    container.margins = (8, 8, 8, 8)
    assert container.margins == (8, 8, 8, 8)

    del container[1:]
    del container[-1]
    assert not container
예제 #2
0
def test_containers_show_nested_containers():
    """make sure showing a container shows a nested FunctionGui."""
    @magicgui
    def func(x: int, y: str):
        pass

    assert not func.visible
    c2 = widgets.Container(widgets=[func])
    assert not c2.visible
    c2.show()
    assert c2.visible and func.visible
예제 #3
0
def test_delete_widget():
    """We can delete widgets from containers."""
    a = widgets.Label(name="a")
    container = widgets.Container(widgets=[a])
    # we can delete widgets
    del container.a
    with pytest.raises(AttributeError):
        getattr(container, "a")

    # they disappear from the layout
    with pytest.raises(ValueError):
        container.index(a)
예제 #4
0
def test_container_removal():
    c = widgets.Container()
    s = widgets.Slider(label="label")
    assert len(c) == 0
    assert c.native.layout().count() == 0

    c.append(s)
    assert len(c) == 1
    assert c.native.layout().count() == 1

    c.pop()
    assert len(c) == 0
    assert c.native.layout().count() == 0
예제 #5
0
def test_visible_in_container():
    """Test that visibility depends on containers."""
    w1 = widgets.Label(value="hi", name="w1")
    w2 = widgets.Label(value="hi", name="w2")
    w3 = widgets.Label(value="hi", name="w2", visible=False)
    container = widgets.Container(widgets=[w2, w3])
    assert not w1.visible
    assert not w2.visible
    assert not w3.visible
    assert not container.visible
    container.show()
    assert container.visible
    assert w2.visible
    assert not w3.visible
    w1.show()
    assert w1.visible
예제 #6
0
def test_container_label_widths():
    """Test basic container functionality."""
    container = widgets.Container(layout="vertical")
    labela = widgets.Label(value="hi", name="labela")
    labelb = widgets.Label(value="hi", name="I have a very long label")

    def _label_width():
        measure = use_app().get_obj("get_text_width")
        return max(
            measure(w.label) for w in container
            if not isinstance(w, widgets._bases.ButtonWidget))

    container.append(labela)
    before = _label_width()
    container.append(labelb)
    assert _label_width() > before
예제 #7
0
def test_labeled_widget_container():
    """Test that _LabeledWidgets follow their children."""
    from magicgui.widgets._concrete import _LabeledWidget

    w1 = widgets.Label(value="hi", name="w1")
    w2 = widgets.Label(value="hi", name="w2")
    container = widgets.Container(widgets=[w1, w2], layout="vertical")
    assert w1._labeled_widget
    lw = w1._labeled_widget()
    assert isinstance(lw, _LabeledWidget)
    assert not lw.visible
    container.show()
    assert w1.visible
    assert lw.visible
    w1.hide()
    assert not w1.visible
    assert not lw.visible
    w1.label = "another label"
    assert lw._label_widget.value == "another label"
예제 #8
0
def test_container_indexing_with_native_mucking():
    """Mostly make sure that the inner model isn't messed up.

    keeping indexes with a manipulated native model *may* be something to do in future.
    """
    l1 = widgets.Label(name="l1")
    l2 = widgets.Label(name="l2")
    l3 = widgets.Label(name="l3")
    c = widgets.Container(widgets=[l1, l2, l3])
    assert c[-1] == l3
    # so far they should be in sync
    native = c.native.layout()
    assert native.count() == len(c)
    # much with native layout
    native.addStretch()
    # haven't changed the magicgui container
    assert len(c) == 3
    assert c[-1] == l3
    # though it has changed the native model
    assert native.count() == 4
예제 #9
0
def test_reset_choice_recursion():
    """Test that reset_choices recursion works for multiple types of widgets."""
    x = 0

    def get_choices(widget):
        nonlocal x
        x += 1
        return list(range(x))

    @magicgui(c={"choices": get_choices})
    def f(c):
        pass

    assert f.c.choices == (0, )

    container = widgets.Container(widgets=[f])
    container.reset_choices()
    assert f.c.choices == (0, 1)
    container.reset_choices()
    assert f.c.choices == (0, 1, 2)
예제 #10
0
def test_basic_widget_attributes():
    """Basic test coverage for getting/setting attributes."""
    widget = widgets.create_widget(value=1, name="my_name")
    container = widgets.Container(labels=False)
    assert widget.enabled
    widget.enabled = False
    assert not widget.enabled

    assert not widget.visible
    widget.show()
    assert widget.visible

    assert widget.parent is None
    container.append(widget)
    assert widget.parent is container.native
    widget.parent = None
    assert widget.parent is None
    assert widget.label == "my name"
    widget.label = "A different label"
    assert widget.label == "A different label"
    assert widget.width < 100
    widget.width = 150
    assert widget.width == 150

    assert widget.param_kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
    widget.param_kind = inspect.Parameter.KEYWORD_ONLY
    widget.param_kind = "positional_only"
    assert widget.param_kind == inspect.Parameter.POSITIONAL_ONLY
    with pytest.raises(KeyError):
        widget.param_kind = "not a proper param type"
    with pytest.raises(TypeError):
        widget.param_kind = 1

    assert repr(widget) == "SpinBox(value=1, annotation=None, name='my_name')"
    assert widget.options == {
        "max": 1000,
        "min": 0,
        "step": 1,
        "enabled": False,
        "visible": False,
    }
예제 #11
0

# alternatively, you can the `widget.called` signal to connect a callback function
# where the result of the function being called is at `event.value`
def _on_func_a(event):
    func_b.input.value = event.value


func_a.called.connect(_on_func_a)


@magicgui(
    auto_call=True,
    input={"visible": False, "max": 100000},
    result_widget=True,
    labels=False,
)
def func_c(input: int, format: str = "({} + {}) * {} is {}") -> str:
    print("calling func_c\n")
    return format.format(func_a.x.value, func_a.y.value, func_b.mult.value, input)


container = widgets.Container(
    widgets=[func_a, func_b, func_c], layout="vertical", labels=False
)
container.native.setMinimumWidth(500)
func_a()
container.show(run=True)

# notice which functions get called when you change each widget.
예제 #12
0

@magicgui(ri={"choices": ["Oil", "Water", "Air"]}, auto_call=True)
def as_list(ri="Water"):
    print("refractive index is", Medium[ri].value)


@magicgui(auto_call=True)
def as_enum(ri: Medium = Medium.Water):
    print("refractive index is", ri.value)


@magicgui(ri={"choices": [("Oil", 1.515), ("Water", 1.33), ("Air", 1.0)]},
          auto_call=True)
def as_2tuple(ri=1.33):
    print("refractive index is", ri)


def get_choices(gui):
    return [("Oil", 1.515), ("Water", 1.33), ("Air", 1.0)]


@magicgui(ri={"choices": get_choices}, auto_call=True)
def as_function(ri: float):
    print("refractive index is", ri)


container = widgets.Container(
    widgets=[as_list, as_enum, as_2tuple, as_function], layout="vertical")
container.show(run=True)
    def create_selector_widget(self, label_layer):
        # TODO: Generalize this. Instead of 0, 1, 2, 3, 4: Arbitrary class numbers. Ability to add classes & name them?
        choices = ['Deselect', 'Class 1', 'Class 2', 'Class 3', 'Class 4']
        selector = widgets.RadioButtons(choices=choices,
                                        label='Selection Class:',
                                        value='Class 1')
        save_button = widgets.PushButton(value=True, text='Save Classifier')
        run_button = widgets.PushButton(value=True, text='Run Classifier')
        container = widgets.Container(
            widgets=[selector, save_button, run_button])
        # TODO: Add text field & button to save classifier output to disk for a given site

        @label_layer.mouse_drag_callbacks.append
        def toggle_label(obj, event):
            # TODO: Add a warning when user clicks while the wrong layer is selected?
            self.selection_layer.visible = True
            # Need to scale position that event.position returns by the label_layer scale.
            # If scale is (1, 1, 1), nothing changes
            # If scale is anything else, this makes the click still match the correct label
            scaled_position = tuple(
                pos / scale
                for pos, scale in zip(event.position, label_layer.scale))
            label = label_layer.get_value(scaled_position)
            #label = label_layer.get_value(event.position)
            if selector.value is None:
                napari_warn(
                    'No class is selected. Select a class in the classifier widget.'
                )
            # Check if background or foreground was clicked. If background was clicked, do nothing (background can't be assigned a class)
            elif label == 0:
                pass
            else:
                # Check if the label exists in the current dataframe. Otherwise, do nothing
                if (self.DataFrame, label) in self.clf.train_data.index:
                    # Assign name of class
                    #self.clf.train_data.loc[(DataFrame, label)] = selector.value
                    # Assign a numeric value to make it easier (colormap currently only supports this mode)
                    self.clf.train_data.loc[(self.DataFrame,
                                             label)] = choices.index(
                                                 selector.value)
                    self.update_label_colormap(self.selection_layer, label,
                                               choices.index(selector.value))
                else:
                    napari_warn('The data that was provided to the classifier '\
                                  'does not contain an object with index {}. '\
                                  'Thus, this object cannot be included in the ' \
                                  'classifier'.format(label))

        @selector.changed.connect
        def change_choice(choice):
            self.selection_layer.visible = True
            self.viewer.layers.selection.clear()
            self.viewer.layers.selection.add(self.label_layer)

        @label_layer.bind_key('s')
        @save_button.changed.connect
        def save_classifier(event):
            show_info('Saving classifier')
            self.clf.save()

        @label_layer.bind_key('t')
        @run_button.changed.connect
        def run_classifier(event):
            # TODO: Add Run mode? Fuzzy, Cross-validated, train/test split
            show_info('Running classifier')
            self.clf.train()
            self.create_label_colormap(self.prediction_layer,
                                       self.clf.predict_data, 'predict')
            self.clf.save()
            self.selection_layer.visible = False
            self.prediction_layer.visible = True
            # TODO: Report classifier performance to the user? => Get the print into the napari notification engine

        @label_layer.bind_key('o')
        def toggle_selection(layer):
            current = self.selection_layer.visible
            self.selection_layer.visible = not current

        @label_layer.bind_key('p')
        def toggle_selection(layer):
            current = self.prediction_layer.visible
            self.prediction_layer.visible = not current

        @label_layer.bind_key('v')
        def toggle_selection(event):
            # Toggling off the label layer would be inconvenient (can't click on it anymore)
            # => just toggle the opacity to 0
            opacity = label_layer.opacity
            if opacity > 0:
                label_layer.opacity = 0.0
            else:
                label_layer.opacity = 0.8

        @label_layer.bind_key('0')
        def set_class_0(event):
            selector.value = choices[0]
            change_choice(event)

        @label_layer.bind_key('1')
        def set_class_1(event):
            selector.value = choices[1]
            change_choice(event)

        @label_layer.bind_key('2')
        def set_class_2(event):
            selector.value = choices[2]
            change_choice(event)

        @label_layer.bind_key('3')
        def set_class_3(event):
            selector.value = choices[3]
            change_choice(event)

        @label_layer.bind_key('4')
        def set_class_4(event):
            selector.value = choices[4]
            change_choice(event)

        return container