Source code for impy.viewer.widgets.dialog

from __future__ import annotations
import datetime
from qtpy.QtWidgets import (QDialog, QPushButton, QLabel, QGridLayout, QCheckBox, QLineEdit, 
                            QComboBox, QVBoxLayout, QHBoxLayout, QSpinBox, QWidget)
import napari
import numpy as np
from functools import wraps

from ..utils import add_labeledarray, copy_layer, front_image, add_labels, layer_to_impy_object
from ..._const import SetConst
from ...utils.slicer import axis_targeted_slicing
from ...utils.axesop import find_first_appeared

[docs]def close_anyway(func): @wraps(func) def wrapped_func(self:QDialog, *args, **kwargs): from napari.utils.notifications import Notification, notification_manager try: out = func(self, *args, **kwargs) except Exception as e: notification_manager.dispatch(Notification.from_exception(e)) out = None finally: self.close() return out return wrapped_func
[docs]class RegionPropsDialog(QDialog): history = "mean_intensity" def __init__(self, viewer:"napari.Viewer"): self.viewer = viewer super().__init__(viewer.window._qt_window) self.resize(180, 120) self.setLayout(QGridLayout()) self._add_widgets()
[docs] @close_anyway def run(self, *args): selected = list(self.viewer.layers.selection) if not any(isinstance(layer, napari.layers.Image) for layer in selected): selected = [front_image(self.viewer)] properties = ("label",) + tuple(self.line.text().split(",")) for layer in selected: if not isinstance(layer, napari.layers.Image): continue if not hasattr(layer.data, "labels"): raise ValueError(f"Image of layer {layer.name} does not have labels.") lbl = layer.data.labels with SetConst("SHOW_PROGRESS", False): out = layer.data.regionprops(properties=properties) out["label"] = out["label"].astype(lbl.dtype) order = np.argsort(out["label"].value) prop = {k: np.concatenate([[np.nan], out[k].value[order]]) for k in properties} # find Labels layer for l in self.viewer.layers: if l.metadata.get("destination_image", None) is layer.data: l.properties = prop break else: l = add_labels(self.viewer, lbl, translate=layer.translate)[0] l.properties = prop from .table import TableWidget import pandas as pd df = pd.DataFrame(l.properties) df = df.drop(df.index[0]) # The first row is background table = TableWidget(self.viewer, df, name=f"Properties of {layer.name}") self.viewer.window.add_dock_widget(table, area="right", name=table.name) self.__class__.history = self.line.text() return None
def _add_widgets(self): self.line = QLineEdit(self) self.line.setText(self.__class__.history) self.layout().addWidget(self.line) self.run_button= QPushButton("Run", self) self.run_button.clicked.connect(self.run) self.layout().addWidget(self.run_button) return None
[docs]class DuplicateDialog(QDialog): """ This dialog is opened when an image layer is duplicated. """ def __init__(self, viewer:"napari.Viewer", layer): self.viewer = viewer self.layer = layer super().__init__(viewer.window._qt_window) self.resize(180, 120) self.setLayout(QGridLayout()) self._add_widgets()
[docs] @close_anyway def run(self, *args): line = self.line.text() if line.strip() == "" and not self.check.isChecked(): new_layer = copy_layer(self.layer) elif line.strip(): new_layer = self.duplicate_sliced_layer(self.layer) else: new_layer = self.duplicate_current_step(self.layer) self.viewer.add_layer(new_layer) return None
[docs] def duplicate_current_step(self, layer): sl = self.viewer.dims.current_step[:-2] data, kwargs, *_ = layer.as_layer_data_tuple() if isinstance(layer, (napari.layers.Image, napari.layers.Labels)): data = data[sl] else: raise TypeError("Cannot duplicate DataFrame with current step.") # linear interpolation is valid only in 3D mode. if kwargs["interpolation"] == "linear": kwargs = kwargs.copy() kwargs["interpolation"] = "nearest" kwargs["scale"] = kwargs["scale"][-2:] kwargs["translate"] = kwargs["translate"][-2:] kwargs["rotate"] = np.array(kwargs["rotate"])[-2:, -2:] kwargs["shear"] = None copy = layer.__class__(data, **kwargs) return copy
[docs] def duplicate_sliced_layer(self, layer): key = self.line.text().strip("'").strip('"') sl = axis_targeted_slicing(layer.data, layer.data.axes, key) data, kwargs, *_ = layer.as_layer_data_tuple() try: data = data[key] except Exception: raise ValueError(f"Cannot duplicate layer with string {key}") # linear interpolation is valid only in 3D mode. if kwargs["interpolation"] == "linear": kwargs = kwargs.copy() kwargs["interpolation"] = "nearest" kwargs["scale"] = [a for i, a in enumerate(kwargs["scale"]) if not isinstance(sl[i], int)] kwargs["translate"] = [a for i, a in enumerate(kwargs["translate"]) if not isinstance(sl[i], int)] kwargs["rotate"] = None kwargs["shear"] = None copy = layer.__class__(data, **kwargs) return copy
def _add_widgets(self): label = QLabel(self) label.setText('Enter such as "t=1;z=5:8" if needed.') self.layout().addWidget(label) self.line = QLineEdit(self) self.layout().addWidget(self.line) self.check = QCheckBox(self) self.check.setText("or duplicate current 2D slice.") self.layout().addWidget(self.check) self.run_button= QPushButton("Run", self) self.run_button.clicked.connect(self.run) self.layout().addWidget(self.run_button) return None
[docs]class ProjectionDialog(QDialog): def __init__(self, viewer:"napari.Viewer", layer): self.viewer = viewer self.layer = layer self.data = layer_to_impy_object(viewer, layer) super().__init__(viewer.window._qt_window) self.resize(180, 120) self.setLayout(QHBoxLayout()) self._add_widgets() def _add_widgets(self): ...
[docs]class ImageProjectionDialog(ProjectionDialog): """ This dialog is opened when an image layer is projected. """
[docs] @close_anyway def run(self, *args): img = self.data out = img.proj(axis=self.axis.currentText(), method=self.method.currentText()) translate = [t for a, t in zip(img.axes, self.layer.translate) if a in out.axes] add_labeledarray(self.viewer, out, translate=translate, name=f"[Proj]{self.layer.name}") return None
def _add_widgets(self): self.method = QComboBox(self) self.method.setToolTip("Projection method") self.method.addItems(["mean", "max", "median", "min", "std"]) self.method.setCurrentText("mean") self.layout().addWidget(self.method) axes = str(self.data.axes) self.axis = QComboBox(self) self.axis.setToolTip("Projection axis") self.axis.addItems(list(axes[:-2])) self.axis.setCurrentText(find_first_appeared("ztpi<c", axes, "yx")) self.layout().addWidget(self.axis) self.run_button= QPushButton("Run", self) self.run_button.clicked.connect(self.run) self.layout().addWidget(self.run_button)
[docs]class LabelProjectionDialog(ProjectionDialog): """ This dialog is opened when an image layer is projected. """
[docs] @close_anyway def run(self, *args): lbl = self.data out = lbl.proj(axis=self.axis.currentText()) translate = [t for a, t in zip(lbl.axes, self.layer.translate) if a in out.axes] add_labels(self.viewer, out, translate=translate, name=f"[Proj]{self.layer.name}") return None
def _add_widgets(self): axes = str(self.data.axes) self.axis = QComboBox(self) self.axis.setToolTip("Projection axis") self.axis.addItems(list(axes[:-2])) self.axis.setCurrentText(find_first_appeared("ztpi<c", axes, "yx")) self.layout().addWidget(self.axis) self.run_button= QPushButton("Run", self) self.run_button.clicked.connect(self.run) self.layout().addWidget(self.run_button)
[docs]class TimeStamper(QDialog): def __init__(self, viewer:"napari.Viewer", layer): self.viewer = viewer self.layer = layer super().__init__(viewer.window._qt_window) self.resize(180, 120) self.setLayout(QVBoxLayout()) self._add_widgets()
[docs] @close_anyway def run(self, *args): i = np.arange(self.layer.data.shape.t) factor = {"hr": 3600, "min": 60, "sec": 1, "msec":0.001}[self.unit.currentText()] sec = i * self.dt.value() * factor time_stamp = [str(datetime.timedelta(seconds=float(s))) for s in sec] taxis = self.layer.data.axisof("t") arr_basic = np.zeros((4, self.viewer.dims.ndim)) arr_basic[1, -2] = 1 arr_basic[2, -2] = 1 arr_basic[2, -1] = 1 arr_basic[3, -1] = 1 def _rectangle(t): arr = arr_basic.copy() arr[:, taxis] = t return arr shapes = [_rectangle(t) for t in i] text_params = {"text": "{time}", "color": "white", "anchor": "upper_left", "size": 10} self.viewer.add_shapes(shapes, text=text_params, properties={"time": time_stamp}, face_color=[0,0,0,0], edge_color=[0,0,0,0], name="Time Stamp") return None
def _add_widgets(self): wid = QWidget(self) wid.setLayout(QHBoxLayout()) self.dt = QSpinBox(wid) self.dt.setToolTip("Time per frame") self.dt.setValue(10) wid.layout().addWidget(self.dt) self.unit = QComboBox(wid) self.unit.setToolTip("Time unit") self.unit.addItems(["hr", "min", "sec", "msec"]) self.unit.setCurrentText("sec") wid.layout().addWidget(self.unit) self.layout().addWidget(wid) self.run_button= QPushButton("OK", self) self.run_button.clicked.connect(self.run) self.layout().addWidget(self.run_button)