예제 #1
0
def make_checkboxes(pt):
    c = Container(labels=False)
    dt = [
        ("cameras", DeviceType.CameraDevice),
        ("shutters", DeviceType.ShutterDevice),
        ("stages", DeviceType.StageDevice),
        ("wheels, turrets, etc.", DeviceType.StateDevice),
        ("other devices", OTHER_DEVICES),
    ]
    for label, dtype in dt:

        @magicgui(auto_call=True, dt={"bind": dtype}, vis={"label": label})
        def toggle(vis: bool = True, dt=None):
            pt.set_dtype_visibility(dt, visible=vis)

        toggle.name = label[:2]
        c.append(toggle)

    @magicgui(auto_call=True, show={"label": "Show read-only"})
    def show_ro(show: bool = True):
        pt.show_read_only = show

    c.append(show_ro)

    return c
예제 #2
0
    def to_container(self, **kwargs) -> Container:
        """Return a ``magicgui.widgets.Container`` for this MagicSignature."""
        from magicgui.widgets import Container

        return Container(
            widgets=list(self.widgets(kwargs.get("app")).values()),
            **kwargs,
        )
    def create_gui_nms_slider(self, shape_layer):
        from magicgui.widgets import FloatSlider, Container, Label
        from torchvision.ops import nms
        slider = FloatSlider(min=0.0, max=1.0, step=0.01, name='NMS')
        slider_label = Label(name='IoU_threshold')

        container = Container(widgets=[slider, slider_label])

        def change_boxes(event, shape_layer=shape_layer):
            # remove all shapes from layer
            self.select_all_shapes(shape_layer)
            shape_layer.remove_selected()

            # create mask and new information
            boxes = torch.tensor([
                make_bbox_napari(box, reverse=True)
                for box in shape_layer.metadata['boxes']
            ])
            scores = torch.tensor(shape_layer.metadata['scores'])

            if boxes.size()[0] > 0:
                mask = nms(boxes, scores, slider.value)  # torch.tensor
                mask = (np.array(mask), )

                new_boxes = np.asarray(shape_layer.metadata['boxes'])[mask]
                new_labels = shape_layer.metadata['labels'][mask]
                new_scores = shape_layer.metadata['scores'][mask]

                # set the current properties as workaround
                shape_layer.current_properties['labels'] = new_labels
                shape_layer.current_properties['scores'] = new_scores

                # add shapes to layer
                if new_boxes.size > 0:
                    shape_layer.add(list(new_boxes))

                # set the properties
                shape_layer.properties['labels'] = new_labels
                shape_layer.properties['scores'] = new_scores

                # set temporary information
                shape_layer.metadata['boxes_nms'] = list(new_boxes)
                shape_layer.metadata['labels_nms'] = new_labels
                shape_layer.metadata['scores_nms'] = new_scores

            # change label
            slider_label.value = str(slider.value)

        slider.changed.connect(change_boxes)

        # invoke nms
        container.NMS.value = 1.0

        # event triggered when the name of the shape layer changes
        self.shape_layer.events.name.connect(change_boxes)

        return container
예제 #4
0
 def __init__(self, mmcore=None, parent=None):
     super().__init__(parent)
     self.pt = PropTable(mmcore)
     self.le = LineEdit(label="Filter:")
     self.le.native.setPlaceholderText("Filter...")
     self.le.changed.connect(self._on_le_change)
     right = Container(widgets=[self.le, self.pt], labels=False)
     self.cb = make_checkboxes(self.pt)
     self.cb.native.layout().addStretch()
     self.cb.native.layout().setSpacing(0)
     self.pt.show()
     self.cb.show()
     self._container = Container(
         layout="horizontal", widgets=[self.cb, right], labels=False
     )
     self._container.margins = 0, 0, 0, 0
     self.setLayout(QHBoxLayout())
     self.setContentsMargins(0, 0, 0, 0)
     self.layout().addWidget(self._container.native)
예제 #5
0
def create_label_menu(shapes_layer, label_feature, labels):
    """Create a label menu widget that can be added to the napari viewer dock

    Parameters
    ----------
    shapes_layer : napari.layers.Shapes
        a napari shapes layer
    label_feature : str
        the name of the shapes feature to use the displayed text
    labels : List[str]
        list of the possible text labels values.

    Returns
    -------
    label_widget : magicgui.widgets.Container
        the container widget with the label combobox
    """
    # Create the label selection menu
    label_menu = ComboBox(label='text label', choices=labels)
    label_widget = Container(widgets=[label_menu])

    def update_label_menu():
        """This is a callback function that updates the label menu when
        the default features of the Shapes layer change
        """
        new_label = str(shapes_layer.feature_defaults[label_feature][0])
        if new_label != label_menu.value:
            label_menu.value = new_label

    shapes_layer.events.feature_defaults.connect(update_label_menu)

    def set_selected_features_to_default():
        """This is a callback that updates the feature values of the currently
        selected shapes. This is a side-effect of the deprecated current_properties
        setter, but does not occur when modifying feature_defaults."""
        indices = list(shapes_layer.selected_data)
        default_value = shapes_layer.feature_defaults[label_feature][0]
        shapes_layer.features[label_feature][indices] = default_value
        shapes_layer.events.features()

    shapes_layer.events.feature_defaults.connect(
        set_selected_features_to_default)
    shapes_layer.events.features.connect(shapes_layer.refresh_text)

    def label_changed(value: str):
        """This is a callback that update the default features on the Shapes layer
        when the label menu selection changes
        """
        shapes_layer.feature_defaults[label_feature] = value
        shapes_layer.events.feature_defaults()

    label_menu.changed.connect(label_changed)

    return label_widget
 def __init__(self, mmcore=None, parent=None):
     super().__init__(parent)
     self.setLayout(QVBoxLayout())
     self.setContentsMargins(0, 0, 0, 0)
     self._container = Container(
         widgets=[
             get_editor_widget(prop, mmcore)
             for prop in iter_dev_props(mmcore)
             if LIGHT_LIST.search(prop.name) and prop.has_range
         ],
         labels=True,
     )
     self.layout().addWidget(self._container.native)
    def create_gui_score_slider(self, shape_layer):
        from magicgui.widgets import FloatSlider, Container, Label

        slider = FloatSlider(min=0.0,
                             max=1.0,
                             step=0.05,
                             name='Score',
                             value=0.0)
        slider_label = Label(name='Score_threshold', value=0.0)

        container = Container(widgets=[slider, slider_label])

        def change_boxes(event, shape_layer=shape_layer):
            # remove all shapes from layer
            self.select_all_shapes(shape_layer)
            shape_layer.remove_selected()

            # create mask and new information
            mask = np.where(shape_layer.metadata['scores'] > slider.value)
            new_boxes = np.asarray(shape_layer.metadata['boxes'])[mask]
            new_labels = shape_layer.metadata['labels'][mask]
            new_scores = shape_layer.metadata['scores'][mask]

            # set the current properties as workaround
            shape_layer.current_properties['labels'] = new_labels
            shape_layer.current_properties['scores'] = new_scores

            # add shapes to layer
            if new_boxes.size > 0:
                shape_layer.add(list(new_boxes))

            # set the properties
            shape_layer.properties['labels'] = new_labels
            shape_layer.properties['scores'] = new_scores

            # change label
            slider_label.value = str(slider.value)

        slider.changed.connect(change_boxes)

        # invoke scoring
        container.Score.value = 0.0

        # event triggered when the name of the shape layer changes
        self.shape_layer.events.name.connect(change_boxes)

        return container
예제 #8
0
def create_label_menu(shapes_layer, label_property, labels):
    """Create a label menu widget that can be added to the napari viewer dock

    Parameters
    ----------
    shapes_layer : napari.layers.Shapes
        a napari shapes layer
    label_property : str
        the name of the shapes property to use the displayed text
    labels : List[str]
        list of the possible text labels values.

    Returns
    -------
    label_widget : magicgui.widgets.Container
        the container widget with the label combobox
    """
    # Create the label selection menu
    label_menu = ComboBox(label='text label', choices=labels)
    label_widget = Container(widgets=[label_menu])

    def update_label_menu(event):
        """This is a callback function that updates the label menu when
        the current properties of the Shapes layer change
        """
        new_label = str(shapes_layer.current_properties[label_property][0])
        if new_label != label_menu.value:
            label_menu.value = new_label

    shapes_layer.events.current_properties.connect(update_label_menu)

    def label_changed(event):
        """This is a callback that update the current properties on the Shapes layer
        when the label menu selection changes
        """
        selected_label = event.value
        current_properties = shapes_layer.current_properties
        current_properties[label_property] = np.asarray([selected_label])
        shapes_layer.current_properties = current_properties

    label_menu.changed.connect(label_changed)

    return label_widget
    def create_gui_text_properties(self, shape_layer):
        TextColor = Combobox(
            choices=shape_layer._colors, name="text color", value="white"
        )
        TextSize = Slider(min=1, max=50, name="text size", value=1)

        container = Container(widgets=[TextColor, TextSize])

        def change_text_color(event):
            # This changes the text color
            shape_layer.text.color = str(TextColor.value)

        def change_text_size(event):
            # This changes the text size
            shape_layer.text.size = int(TextSize.value)

        TextColor.changed.connect(change_text_color)
        TextSize.changed.connect(change_text_size)

        return container
예제 #10
0
def create_label_menu(points_layer, labels):
    """Create a label menu widget that can be added to the napari viewer dock

    Parameters:
    -----------
    points_layer : napari.layers.Points
        a napari points layer
    labels : List[str]
        list of the labels for each keypoint to be annotated (e.g., the body parts to be labeled).

    Returns:
    --------
    label_menu : QComboBox
        the label menu qt widget
    """
    # Create the label selection menu
    label_menu = ComboBox(label='feature_label', choices=labels)
    label_widget = Container(widgets=[label_menu])

    def update_label_menu(event):
        """Update the label menu when the point selection changes"""
        new_label = str(points_layer.current_properties['label'][0])
        if new_label != label_menu.value:
            label_menu.value = new_label

    points_layer.events.current_properties.connect(update_label_menu)

    def label_changed(event):
        """Update the Points layer when the label menu selection changes"""
        selected_label = event.value
        current_properties = points_layer.current_properties
        current_properties['label'] = np.asarray([selected_label])
        points_layer.current_properties = current_properties

    label_menu.changed.connect(label_changed)

    return label_widget
예제 #11
0
"""Demonstrates decorating a method.

Once the class is instantiated, `instance.method_name` will return a FunctionGui
in which the instance will always be provided as the first argument (i.e. "self") when
the FunctionGui or method is called.
"""
from magicgui import event_loop, magicgui
from magicgui.widgets import Container


class MyObject:
    def __init__(self, name):
        self.name = name
        self.counter = 0.0

    @magicgui(auto_call=True)
    def method(self, sigma: float = 0):
        print(
            f"instance: {self.name}, counter: {self.counter}, sigma: {sigma}")
        self.counter = self.counter + sigma
        return self.name


with event_loop():
    a = MyObject("a")
    b = MyObject("b")
    container = Container(widgets=[a.method, b.method])
    container.show()
    assert a.method() == "a"
    assert b.method() == "b"
예제 #12
0
    def track_explorer(R, keep_only=False):
        """
        Track explorer app. Written using magicgui (Thanks @tlambert03!)

        Allows one to easily browse through tracks, plot the data and see the corresponding movies. Can also be used for curation and quality control.

        Parameters:
        keep_only : [False] Bool - If true, only tracks that are in PosLbl.track_to_use will be loaded in a given position. This can be used to filter unwanted tracks before examining for quality with the explorer.
        """
        from typing import List
        import matplotlib
        import matplotlib.pyplot as plt
        import numpy as np
        from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
        from magicgui import magicgui
        from magicgui.widgets import Checkbox, PushButton, Container
        from oyLabImaging.Processing.imvisutils import get_or_create_viewer
        from scipy import stats
        from napari import run
        from natsort import natsorted

        cmaps = ['cyan', 'magenta', 'yellow', 'red', 'green', 'blue']
        viewer = get_or_create_viewer()

        matplotlib.use('Agg')
        mpl_fig = plt.figure()
        ax = mpl_fig.add_subplot(111)

        fc = FigureCanvasQTAgg(mpl_fig)

        #attr_list = ['area', 'convex_area','centroid','perimeter','eccentricity','solidity','inertia_tensor_eigvals', 'orientation'] #todo: derive list from F regioprops

        position = list(natsorted(R.PosLbls.keys()))[0]
        PosLbl0 = R.PosLbls[position]

        attr_list = [
            f for f in list(PosLbl0.framelabels[0].regionprops)
            if not f.startswith(('mean', 'median', 'max', 'min', '90th',
                                 'slice'))
        ]
        attr_cmap = plt.cm.get_cmap('tab20b', len(attr_list)).colors

        @magicgui(
            auto_call=True,
            position={
                "choices": natsorted([str(a) for a in R.PosLbls.keys()])
            },
            track_id={
                "choices":
                range(R.PosLbls[sorted([str(a) for a in R.PosLbls.keys()
                                        ])[0]].get_track(0).numtracks)
            },
            channels={
                "widget_type": "Select",
                "choices": list(R.channels)
            },
            features={
                "widget_type": "Select",
                "choices": attr_list
            },
        )
        def widget(position: List[str], track_id: int, channels: List[str],
                   features: List[str]):
            # preserving these parameters for things that the graphing function
            # needs... so that anytime this is called we have to graph.
            ...
            # do your graphing here
            PosLbl = R.PosLbls[position]
            t0 = PosLbl.get_track(track_id)
            ax.cla()
            ax.set_xlabel('Timepoint')
            ax.set_ylabel('kAU')
            ch_choices = widget.channels.choices
            for ch in channels:
                ax.plot(t0.T,
                        stats.zscore(t0.mean(ch)),
                        color=cmaps[ch_choices.index(ch)])

            f_choices = widget.features.choices
            for ch in features:
                feat_to_plot = eval("t0.prop('" + ch + "')")
                if np.ndim(feat_to_plot) == 1:
                    ax.plot(t0.T,
                            stats.zscore(feat_to_plot, nan_policy='omit'),
                            '--',
                            color=attr_cmap[f_choices.index(ch)],
                            alpha=0.33)
                else:
                    mini_cmap = plt.cm.get_cmap('jet',
                                                np.shape(feat_to_plot)[1])
                    for dim in np.arange(np.shape(feat_to_plot)[1]):
                        ax.plot(t0.T,
                                stats.zscore(feat_to_plot[:, dim],
                                             nan_policy='omit'),
                                '--',
                                color=mini_cmap(dim),
                                alpha=0.33)
                        #ax.plot(t0.T, feat_to_plot[:,dim],'--', color=mini_cmap(dim), alpha=0.25)

            ax.legend(channels + features)
            fc.draw()

        @widget.position.changed.connect
        def _on_position_changed():
            PosLbl = R.PosLbls[widget.position.value]
            try:
                PosLbl.track_to_use
            except:
                PosLbl.track_to_use = []
            viewer.layers.clear()
            #update track_id choices - bug in choices:
            if keep_only:
                J = PosLbl.track_to_use
            else:
                J = range(PosLbl.get_track(0).numtracks)
            widget.track_id.choices = []
            widget.track_id.choices = J
            #update keep_btn value
            #keep_btn.value= widget.track_id.value in PosLbl.track_to_use

        @widget.track_id.changed.connect
        def _on_track_changed(new_track: int):
            PosLbl = R.PosLbls[widget.position.value]
            viewer.layers.clear()
            keep_btn.value = widget.track_id.value in PosLbl.track_to_use
            #print("you cahnged to ", new_track)

        movie_btn = PushButton(text="Movie")
        widget.insert(1, movie_btn)

        @movie_btn.clicked.connect
        def _on_movie_clicked():
            PosLbl = R.PosLbls[widget.position.value]
            channels = widget.channels.get_value()
            track_id = widget.track_id.get_value()
            t0 = PosLbl.get_track(track_id)
            viewer.layers.clear()
            ch_choices = widget.channels.choices
            t0.show_movie(
                Channel=channels,
                cmaps=[cmaps[ch_choices.index(ch)] for ch in channels])

        btn = PushButton(text="NEXT")
        widget.insert(-1, btn)

        @btn.clicked.connect
        def _on_next_clicked():
            choices = widget.track_id.choices
            current_index = choices.index(widget.track_id.value)
            widget.track_id.value = choices[(current_index + 1) %
                                            (len(choices))]

        PosLbl = R.PosLbls[widget.position.value]
        try:
            PosLbl.track_to_use
        except:
            PosLbl.track_to_use = []

        keep_btn = Checkbox(text="Keep")
        keep_btn.value = widget.track_id.value in PosLbl.track_to_use
        widget.append(keep_btn)

        @keep_btn.clicked.connect
        def _on_keep_btn_clicked(value: bool):
            #print("keep is now", value)
            PosLbl = R.PosLbls[widget.position.value]
            if value == True:
                if widget.track_id.value not in PosLbl.track_to_use:
                    PosLbl.track_to_use.append(widget.track_id.value)
            if value == False:
                if widget.track_id.value in PosLbl.track_to_use:
                    PosLbl.track_to_use.remove(widget.track_id.value)
            R.PosLbls[widget.position.value] = PosLbl

        # widget.native
        # ... points to the underlying backend widget

        container = Container(layout='horizontal')

        # magicgui container expect magicgui objects
        # but we can access and modify the underlying QLayout
        # https://doc.qt.io/qt-5/qlayout.html#addWidget

        layout = container.native.layout()

        layout.addWidget(fc)
        layout.addWidget(widget.native)  # adding native, because we're in Qt

        #container.show(run=True)
        # OR

        viewer.window.add_dock_widget(container)
        #run()
        matplotlib.use('Qt5Agg')