diff --git a/src/cell_gater/_reader.py b/src/cell_gater/_reader.py deleted file mode 100644 index 97e57cf..0000000 --- a/src/cell_gater/_reader.py +++ /dev/null @@ -1,73 +0,0 @@ -""" -This module is an example of a barebones numpy reader plugin for napari. - -It implements the Reader specification, but your plugin may choose to -implement multiple readers or even other plugin contributions. see: -https://napari.org/stable/plugins/guides.html?#readers -""" - -import numpy as np - - -def napari_get_reader(path): - """A basic implementation of a Reader contribution. - - Parameters - ---------- - path : str or list of str - Path to file, or list of paths. - - Returns - ------- - function or None - If the path is a recognized format, return a function that accepts the - same path or list of paths, and returns a list of layer data tuples. - """ - if isinstance(path, list): - # reader plugins may be handed single path, or a list of paths. - # if it is a list, it is assumed to be an image stack... - # so we are only going to look at the first file. - path = path[0] - - # if we know we cannot read the file, we immediately return None. - if not path.endswith(".npy"): - return None - - # otherwise we return the *function* that can read ``path``. - return reader_function - - -def reader_function(path): - """Take a path or list of paths and return a list of LayerData tuples. - - Readers are expected to return data as a list of tuples, where each tuple - is (data, [add_kwargs, [layer_type]]), "add_kwargs" and "layer_type" are - both optional. - - Parameters - ---------- - path : str or list of str - Path to file, or list of paths. - - Returns - ------- - layer_data : list of tuples - A list of LayerData tuples where each tuple in the list contains - (data, metadata, layer_type), where data is a numpy array, metadata is - a dict of keyword arguments for the corresponding viewer.add_* method - in napari, and layer_type is a lower-case string naming the type of - layer. Both "meta", and "layer_type" are optional. napari will - default to layer_type=="image" if not provided - """ - # handle both a string and a list of strings - paths = [path] if isinstance(path, str) else path - # load all files into array - arrays = [np.load(_path) for _path in paths] - # stack arrays into single array - data = np.squeeze(np.stack(arrays)) - - # optional kwargs for the corresponding viewer.add_* method - add_kwargs = {} - - layer_type = "image" # optional, default is "image" - return [(data, add_kwargs, layer_type)] diff --git a/src/cell_gater/_sample_data.py b/src/cell_gater/_sample_data.py deleted file mode 100644 index 203451f..0000000 --- a/src/cell_gater/_sample_data.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -This module is an example of a barebones sample data provider for napari. - -It implements the "sample data" specification. -see: https://napari.org/stable/plugins/guides.html?#sample-data - -Replace code below according to your needs. -""" - -from __future__ import annotations - -import numpy - - -def make_sample_data(): - """Generates an image""" - # Return list of tuples - # [(data1, add_image_kwargs1), (data2, add_image_kwargs2)] - # Check the documentation for more information about the - # add_image_kwargs - # https://napari.org/stable/api/napari.Viewer.html#napari.Viewer.add_image - return [(numpy.random.rand(512, 512), {})] diff --git a/src/cell_gater/_widget.py b/src/cell_gater/_widget.py deleted file mode 100644 index b4f9058..0000000 --- a/src/cell_gater/_widget.py +++ /dev/null @@ -1,129 +0,0 @@ -""" -This module contains four napari widgets declared in -different ways: - -- a pure Python function flagged with `autogenerate: true` - in the plugin manifest. Type annotations are used by - magicgui to generate widgets for each parameter. Best - suited for simple processing tasks - usually taking - in and/or returning a layer. -- a `magic_factory` decorated function. The `magic_factory` - decorator allows us to customize aspects of the resulting - GUI, including the widgets associated with each parameter. - Best used when you have a very simple processing task, - but want some control over the autogenerated widgets. If you - find yourself needing to define lots of nested functions to achieve - your functionality, maybe look at the `Container` widget! -- a `magicgui.widgets.Container` subclass. This provides lots - of flexibility and customization options while still supporting - `magicgui` widgets and convenience methods for creating widgets - from type annotations. If you want to customize your widgets and - connect callbacks, this is the best widget option for you. -- a `QWidget` subclass. This provides maximal flexibility but requires - full specification of widget layouts, callbacks, events, etc. - -References: -- Widget specification: https://napari.org/stable/plugins/guides.html?#widgets -- magicgui docs: https://pyapp-kit.github.io/magicgui/ - -Replace code below according to your needs. -""" - -from typing import TYPE_CHECKING - -from magicgui import magic_factory -from magicgui.widgets import CheckBox, Container, create_widget -from qtpy.QtWidgets import QHBoxLayout, QPushButton, QWidget -from skimage.util import img_as_float - -if TYPE_CHECKING: - import napari - - -# Uses the `autogenerate: true` flag in the plugin manifest -# to indicate it should be wrapped as a magicgui to autogenerate -# a widget. -def threshold_autogenerate_widget( - img: "napari.types.ImageData", - threshold: "float", -) -> "napari.types.LabelsData": - return img_as_float(img) > threshold - - -# the magic_factory decorator lets us customize aspects of our widget -# we specify a widget type for the threshold parameter -# and use auto_call=True so the function is called whenever -# the value of a parameter changes -@magic_factory( - threshold={"widget_type": "FloatSlider", "max": 1}, auto_call=True -) -def threshold_magic_widget( - img_layer: "napari.layers.Image", threshold: "float" -) -> "napari.types.LabelsData": - return img_as_float(img_layer.data) > threshold - - -# if we want even more control over our widget, we can use -# magicgui `Container` -class ImageThreshold(Container): - def __init__(self, viewer: "napari.viewer.Viewer"): - super().__init__() - self._viewer = viewer - # use create_widget to generate widgets from type annotations - self._image_layer_combo = create_widget( - label="Image", annotation="napari.layers.Image" - ) - self._threshold_slider = create_widget( - label="Threshold", annotation=float, widget_type="FloatSlider" - ) - self._threshold_slider.min = 0 - self._threshold_slider.max = 1 - # use magicgui widgets directly - self._invert_checkbox = CheckBox(text="Keep pixels below threshold") - - # connect your own callbacks - self._threshold_slider.changed.connect(self._threshold_im) - self._invert_checkbox.changed.connect(self._threshold_im) - - # append into/extend the container with your widgets - self.extend( - [ - self._image_layer_combo, - self._threshold_slider, - self._invert_checkbox, - ] - ) - - def _threshold_im(self): - image_layer = self._image_layer_combo.value - if image_layer is None: - return - - image = img_as_float(image_layer.data) - name = image_layer.name + "_thresholded" - threshold = self._threshold_slider.value - if self._invert_checkbox.value: - thresholded = image < threshold - else: - thresholded = image > threshold - if name in self._viewer.layers: - self._viewer.layers[name].data = thresholded - else: - self._viewer.add_labels(thresholded, name=name) - - -class ExampleQWidget(QWidget): - # your QWidget.__init__ can optionally request the napari viewer instance - # use a type annotation of 'napari.viewer.Viewer' for any parameter - def __init__(self, viewer: "napari.viewer.Viewer"): - super().__init__() - self.viewer = viewer - - btn = QPushButton("Click me!") - btn.clicked.connect(self._on_click) - - self.setLayout(QHBoxLayout()) - self.layout().addWidget(btn) - - def _on_click(self): - print("napari has", len(self.viewer.layers), "layers") diff --git a/src/cell_gater/widgets/scatter_widget.py b/src/cell_gater/widgets/scatter_widget.py new file mode 100644 index 0000000..e69de29