def __init__(self, parent, viewer_reference): QtWidgets.QDockWidget.__init__(self, parent) self.setFloating(True) self.setWindowTitle('Caiman detrend ΔF/F') self.vi = ViewerUtils(viewer_reference) opts = \ { 'quantileMin': { 'minmax': (0, 100) }, 'frames_window': { 'minmax': (0, 1000), 'step': 10 } } self.function = Function(detrend_df_f, opts, parent=self) self.function.sig_set_clicked.connect(self.set_data) self.setWidget(self.function.widget)
class NusetWidget(QtWidgets.QWidget): sig_zlevel_changed = QtCore.pyqtSignal(int) def __init__(self, parent, viewer_ref): QtWidgets.QWidget.__init__(self, parent) self.vlayout = QtWidgets.QVBoxLayout(self) self.splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal) self.vlayout.addWidget(self.splitter) self.left_layout = QtWidgets.QVBoxLayout(self) self.left_widget = QtWidgets.QWidget(self.splitter) self.left_widget.setLayout(self.left_layout) hlayout_custom_img = QtWidgets.QHBoxLayout(self.left_widget) self.lineedit_custom_img_path = QtWidgets.QLineEdit(self.left_widget) self.lineedit_custom_img_path.setPlaceholderText( "Path to custom image or stack") self.lineedit_custom_img_path.setToolTip( "Use a different image or stack for segmentation, such as an image or stack of nuclei." ) self.button_use_custom = QtWidgets.QPushButton(self.left_widget) self.button_use_custom.setMaximumWidth(50) self.button_use_custom.setText("Set") hlayout_custom_img.addWidget(self.lineedit_custom_img_path) hlayout_custom_img.addWidget(self.button_use_custom) self.left_layout.addLayout(hlayout_custom_img) hlayout_projection_radios = QtWidgets.QHBoxLayout(self.left_widget) self.radio_std = QtWidgets.QRadioButton(self.left_widget) self.radio_std.setText("Std. Deviation") self.radio_max = QtWidgets.QRadioButton(self.left_widget) self.radio_max.setText("Max") self.radio_mean = QtWidgets.QRadioButton(self.left_widget) self.radio_mean.setText("Mean") self.projection_option: str = '' for w in [self.radio_std, self.radio_max, self.radio_mean]: hlayout_projection_radios.addWidget(w) w.clicked.connect(self.update_projection) label_projections = QtWidgets.QLabel(self.left_widget) label_projections.setText("Choose Input Projection") label_projections.setStyleSheet("font-weight: bold") self.left_layout.addWidget(label_projections) self.left_layout.addLayout(hlayout_projection_radios) # projection image self.glw_raw = GraphicsLayoutWidget(self.left_widget) self.imgitem_raw = ImageItem() self.viewbox_raw = self.glw_raw.addViewBox() self.viewbox_raw.setAspectLocked(True) self.viewbox_raw.addItem(self.imgitem_raw) self.left_layout.addWidget(self.glw_raw) hlayout_preprocess = QtWidgets.QHBoxLayout(self.left_widget) arg_opts_preprocess = \ { 'img': {'ignore': True}, 'sigmoid_cutoff': { 'step': 10, 'minmax': (0, 9999.9) }, 'sigmoid_gain': { 'step': 0.01 }, 'equalize_lower': { 'step': 0.01, 'minmax': (-1.0, 1.0) }, 'equalize_upper': { 'step': 0.01, 'minmax': (-1.0, 1.0) } } self.preprocess_controls = \ Function( get_preprocess, arg_opts=arg_opts_preprocess, parent=self.left_widget ) self.preprocess_controls.button_set.hide() self.preprocess_controls.sig_changed.connect(self.update_preprocess) self.preprocess_controls.set_title("Pre-process Settings") hlayout_preprocess.addWidget(self.preprocess_controls.widget) self.zslider = QtWidgets.QSlider(parent=self.left_widget, orientation=QtCore.Qt.Vertical) self.zslider.setInvertedAppearance(True) self.zslider.setSingleStep(1) self.zslider.valueChanged.connect(self.update_zlevel) label_zslider = QtWidgets.QLabel(self.left_widget) label_zslider.setText("z-level") self.spinbox_zlevel = QtWidgets.QSpinBox(self.left_widget) self.spinbox_zlevel.setSingleStep(1) self.spinbox_zlevel.valueChanged.connect(self.zslider.setValue) self.zslider.valueChanged.connect(self.spinbox_zlevel.setValue) hlayout_preprocess.addWidget(label_zslider) hlayout_preprocess.addWidget(self.zslider) hlayout_preprocess.addWidget(self.spinbox_zlevel) self.left_layout.addLayout(hlayout_preprocess) # preprocess image item self.glw_preprocess = GraphicsLayoutWidget(self.left_widget) self.imgitem_preprocess = ImageItem() self.viewbox_preprocess = self.glw_preprocess.addViewBox() self.viewbox_preprocess.setAspectLocked(True) self.viewbox_preprocess.addItem(self.imgitem_preprocess) self.left_layout.addWidget(self.glw_preprocess) self.splitter.addWidget(self.left_widget) # segmentation stuff self.nuset_model = Nuset() self.right_layout = QtWidgets.QVBoxLayout(self) self.right_widget = QtWidgets.QWidget(self.splitter) self.right_widget.setLayout(self.right_layout) hlayout_nuset = QtWidgets.QHBoxLayout(self.right_widget) arg_opts_nuset = \ { 'image': {'ignore': True}, 'min_score': { 'minmax': (0.0, 1.0), 'step': 0.05 }, 'nms_threshold': { 'minmax': (0.0, 1.0), 'step': 0.05 }, 'rescale_ratio': { 'minmax': (0.1, 10.0), 'step': 0.25, 'val': 1.25 # not working if set to 1.0 with pyqtgraph ImageItem for some reason } } self.nuset_controls = \ Function( self.nuset_model.predict, arg_opts=arg_opts_nuset, parent=self.right_widget ) # self.nuset_controls.button_set.hide() self.nuset_controls.sig_set_clicked.connect(self.update_segmentation) self.nuset_controls.set_title("NuSeT Parameters") hlayout_nuset.addWidget(self.nuset_controls.widget) arg_opts_postprocess = \ { 'img': {'ignore': True}, 'abs_obj_threshold': { 'minmax': (-1, 100), 'step': 2, }, 'rel_obj_threshold': { 'minmax': (0, 100), 'step': 2 }, 'obj_connectivity': { 'minmax': (0, 10), 'step': 1 }, 'abs_hol_threshold': { 'minmax': (-1, 100), 'step': 2, }, 'rel_hol_threshold': { 'minmax': (0, 100), 'step': 2 }, 'hol_connectivity': { 'minmax': (0, 100), 'step': 1 } } self.postprocess_controls = \ Function( get_postprocess, arg_opts=arg_opts_postprocess, parent=self.right_widget ) self.postprocess_controls.button_set.hide() self.postprocess_controls.sig_changed.connect(self.update_postprocess) self.postprocess_controls.set_title("Post-process Parameters") hlayout_nuset.addWidget(self.postprocess_controls.widget) self.right_layout.addLayout(hlayout_nuset) self.checkbox_segment_current_plane = QtWidgets.QCheckBox( self.nuset_controls.widget) self.checkbox_segment_current_plane.setText( "Only segment current plane") self.checkbox_segment_current_plane.setToolTip( "Performs segmentation for only the current plane, " "useful for trying out parameters.") self.checkbox_segment_current_plane.setChecked(True) self.nuset_controls.vlayout.addWidget( self.checkbox_segment_current_plane) self.glw_segmented = GraphicsLayoutWidget(self.right_widget) self.imgitem_segmented = ImageItem() self.imgitem_segmented_underlay = ImageItem() self.viewbox_segmented = self.glw_segmented.addViewBox() self.viewbox_segmented.setAspectLocked(True) self.viewbox_segmented.addItem(self.imgitem_segmented) self.viewbox_segmented.addItem(self.imgitem_segmented_underlay) # colormaps for the mask overlay plot cm_cyan = cm.get_cmap(cmap_cyan) cm_cyan._init() lut_cyan = (cm_cyan._lut * 255).view(np.ndarray)[128:-5] self.imgitem_segmented_underlay.setLookupTable(lut_cyan) # colormaps for the mask overlay plot cm_magenta = cm.get_cmap(cmap_magenta) cm_magenta._init() lut_magenta = (cm_magenta._lut * 255).view( np.ndarray)[:-5] # so it displays as a mask self.imgitem_segmented.setLookupTable(lut_magenta) # allow transparency # self.imgitem_segmented.setCompositionMode(QtGui.QPainter.CompositionMode_Overlay) self.imgitem_segmented_underlay.setCompositionMode( QtGui.QPainter.CompositionMode_SourceOver) self.imgitem_segmented.setZValue(2) self.imgitem_segmented.setOpacity(0.5) self.imgitem_segmented_underlay.setZValue(1) self.imgitem_segmented_underlay.setOpacity(0.3) self.slider_underlay_opacity = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider_underlay_opacity.setMinimum(0) self.slider_underlay_opacity.setMaximum(100) self.slider_underlay_opacity.setValue(30) self.slider_underlay_opacity.valueChanged.connect( lambda v: self.imgitem_segmented_underlay.setOpacity(v / 100)) label_underlay_opacity = QtWidgets.QLabel(self.nuset_controls.widget) label_underlay_opacity.setText("Underlay opacity") self.nuset_controls.vlayout.addWidget(label_underlay_opacity) self.nuset_controls.vlayout.addWidget(self.slider_underlay_opacity) self.slider_mask_opacity = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider_mask_opacity.setMinimum(0) self.slider_mask_opacity.setMaximum(100) self.slider_mask_opacity.setValue(50) self.slider_mask_opacity.valueChanged.connect( lambda v: self.imgitem_segmented.setOpacity(v / 100)) label_segmented_opacity = QtWidgets.QLabel(self.nuset_controls.widget) label_segmented_opacity.setText("Segmentation opacity") self.nuset_controls.vlayout.addWidget(label_segmented_opacity) self.nuset_controls.vlayout.addWidget(self.slider_mask_opacity) self.combo_blend_mode = QtWidgets.QComboBox(self.nuset_controls.widget) self.combo_blend_mode.addItems( ['SourceOver', 'Overlay', 'Plus', 'Multiply']) self.combo_blend_mode.setCurrentIndex(0) self.combo_blend_mode.currentTextChanged.connect( lambda opt: self.imgitem_segmented.setCompositionMode( getattr(QtGui.QPainter, f'CompositionMode_{opt}'))) label_blend_mode = QtWidgets.QLabel(self.nuset_controls.widget) label_blend_mode.setText('Blend mode:') self.nuset_controls.vlayout.addWidget(label_blend_mode) self.nuset_controls.vlayout.addWidget(self.combo_blend_mode) self.right_layout.addWidget(self.glw_segmented) self.splitter.addWidget(self.right_widget) self.export_widget = ExportWidget(self) self.imgs_projected: List[np.ndarray] = [] self.imgs_preprocessed: List[np.ndarray] = [] self.imgs_segmented: List[np.ndarray] = [] self.imgs_postprocessed: List[np.ndarray] = [] self.input_img: np.ndarray = np.empty(0) self.zlevel = 0 self.z_max: int = 0 self.process_pool = Pool(cpu_count()) self.error_label = QtWidgets.QLabel(self) self.error_label.setMaximumHeight(20) self.error_label.setStyleSheet("font-weight: bold; color: red") self.vlayout.addWidget(self.error_label) self.projection_option = '' self.params_final = None if viewer_ref is None: logger.info("Assuming testing mode") else: self.vi = ViewerUtils(viewer_ref) self.vi.viewer.sig_workEnv_changed.connect(self.set_input) self.set_input(self.vi.viewer.workEnv) @use_open_file_dialog('Open image file', None, ['*.tiff', '*.tif']) @present_exceptions('Error', 'Error loading custom input image') def set_custom_input(self, path, *args): self.clear_widget() img = tifffile.imread(path) self._set_input_image(img.T) def set_input(self, workEnv: ViewerWorkEnv): self.clear_widget() try: img = workEnv.imgdata._seq except: return self._set_input_image(img) def _set_input_image(self, img: np.ndarray): self.input_img = img if self.input_img.ndim == 4: self.z_max = self.input_img.shape[3] - 1 else: self.z_max = 0 self.zslider.valueChanged.disconnect(self.update_zlevel) self.zslider.setValue(0) self.zslider.setMaximum(self.z_max) self.spinbox_zlevel.setMaximum(self.z_max) self.zslider.valueChanged.connect(self.update_zlevel) def update_zlevel(self, z: int): self.zlevel = z self.sig_zlevel_changed.emit(z) for imgitem, imglist in zip([ self.imgitem_raw, self.imgitem_preprocess, self.imgitem_segmented_underlay, self.imgitem_segmented ], [ self.imgs_projected, self.imgs_preprocessed, self.imgs_preprocessed, self.imgs_postprocessed ]): if imglist: # set if the list is not empty if imglist[z].size > 0: imgitem.setImage(imglist[z]) def update_projection(self): if not self.input_img.size > 0: self.error_label.setText("No input image") return if self.radio_std.isChecked(): opt = 'std' elif self.radio_max.isChecked(): opt = 'max' elif self.radio_mean.isChecked(): opt = 'mean' if self.projection_option == opt: return self.projection_option = opt func = getattr(np, f'nan{opt}') logger.info("Updating Projection(s)") if self.input_img.ndim == 4: self.imgs_projected = [ func(self.input_img[:, :, :, z], axis=2) for z in tqdm(range(self.z_max + 1)) ] else: self.imgs_projected = [func(self.input_img, axis=2)] self.imgitem_raw.setImage(self.imgs_projected[self.zlevel]) self.error_label.clear() def update_preprocess(self, params): if not self.imgs_projected: self.error_label.setText("Projection Image is Empty") return logger.info("Preprocessing Image(s)") # self.image_preprocesses = [ # get_preprocess(p, **params) for p in tqdm(self.image_projections) # ] kwargs = [{'img': img, **params} for img in self.imgs_projected] self.imgs_preprocessed = self.process_pool.map(wrap_preprocess, kwargs) self.imgitem_preprocess.setImage(self.imgs_preprocessed[self.zlevel]) self.imgitem_segmented_underlay.setImage( self.imgs_preprocessed[self.zlevel]) self.error_label.clear() def update_segmentation(self, params): if not self.imgs_preprocessed: self.error_label.setText("Preprocess Image is Empty") return logger.info("Segmenting Image(s)") if not self.checkbox_segment_current_plane.isChecked(): self.imgs_segmented = [ self.nuset_model.predict(img, **params) for img in tqdm(self.imgs_preprocessed) ] else: self.imgs_segmented = [np.empty(0) for i in range(self.z_max + 1)] self.imgs_segmented[self.zlevel] = self.nuset_model.predict( self.imgs_preprocessed[self.zlevel], **params) # postprocess funciton will just return the segmented img if do_postprocess is False self.update_postprocess(self.postprocess_controls.get_data()) self.params_final = \ { 'method': 'NuSeT', 'projection_option': self.projection_option, **self.preprocess_controls.get_data(), **self.nuset_controls.get_data(), **self.postprocess_controls.get_data(), } self.error_label.clear() def update_postprocess(self, params): if not self.imgs_segmented: self.error_label.setText("Segmented Image is Empty") return logger.info("Postprocessing Image(s)") self.imgs_postprocessed = [ get_postprocess(img, **params) for img in tqdm(self.imgs_segmented) ] self.imgitem_segmented.setImage(self.imgs_postprocessed[self.zlevel]) self.error_label.clear() def clear_widget(self): self.imgs_projected.clear() self.imgs_preprocessed.clear() self.imgs_segmented.clear() self.imgs_postprocessed.clear() self.imgitem_raw.clear() self.imgitem_preprocess.clear() self.imgitem_segmented.clear() self.imgitem_segmented_underlay.clear() self.radio_std.setChecked(False) self.radio_max.setChecked(False) self.radio_mean.setChecked(False) self.projection_option = ''
def __init__(self, parent, viewer_ref): QtWidgets.QWidget.__init__(self, parent) self.vlayout = QtWidgets.QVBoxLayout(self) self.splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal) self.vlayout.addWidget(self.splitter) self.left_layout = QtWidgets.QVBoxLayout(self) self.left_widget = QtWidgets.QWidget(self.splitter) self.left_widget.setLayout(self.left_layout) hlayout_custom_img = QtWidgets.QHBoxLayout(self.left_widget) self.lineedit_custom_img_path = QtWidgets.QLineEdit(self.left_widget) self.lineedit_custom_img_path.setPlaceholderText( "Path to custom image or stack") self.lineedit_custom_img_path.setToolTip( "Use a different image or stack for segmentation, such as an image or stack of nuclei." ) self.button_use_custom = QtWidgets.QPushButton(self.left_widget) self.button_use_custom.setMaximumWidth(50) self.button_use_custom.setText("Set") hlayout_custom_img.addWidget(self.lineedit_custom_img_path) hlayout_custom_img.addWidget(self.button_use_custom) self.left_layout.addLayout(hlayout_custom_img) hlayout_projection_radios = QtWidgets.QHBoxLayout(self.left_widget) self.radio_std = QtWidgets.QRadioButton(self.left_widget) self.radio_std.setText("Std. Deviation") self.radio_max = QtWidgets.QRadioButton(self.left_widget) self.radio_max.setText("Max") self.radio_mean = QtWidgets.QRadioButton(self.left_widget) self.radio_mean.setText("Mean") self.projection_option: str = '' for w in [self.radio_std, self.radio_max, self.radio_mean]: hlayout_projection_radios.addWidget(w) w.clicked.connect(self.update_projection) label_projections = QtWidgets.QLabel(self.left_widget) label_projections.setText("Choose Input Projection") label_projections.setStyleSheet("font-weight: bold") self.left_layout.addWidget(label_projections) self.left_layout.addLayout(hlayout_projection_radios) # projection image self.glw_raw = GraphicsLayoutWidget(self.left_widget) self.imgitem_raw = ImageItem() self.viewbox_raw = self.glw_raw.addViewBox() self.viewbox_raw.setAspectLocked(True) self.viewbox_raw.addItem(self.imgitem_raw) self.left_layout.addWidget(self.glw_raw) hlayout_preprocess = QtWidgets.QHBoxLayout(self.left_widget) arg_opts_preprocess = \ { 'img': {'ignore': True}, 'sigmoid_cutoff': { 'step': 10, 'minmax': (0, 9999.9) }, 'sigmoid_gain': { 'step': 0.01 }, 'equalize_lower': { 'step': 0.01, 'minmax': (-1.0, 1.0) }, 'equalize_upper': { 'step': 0.01, 'minmax': (-1.0, 1.0) } } self.preprocess_controls = \ Function( get_preprocess, arg_opts=arg_opts_preprocess, parent=self.left_widget ) self.preprocess_controls.button_set.hide() self.preprocess_controls.sig_changed.connect(self.update_preprocess) self.preprocess_controls.set_title("Pre-process Settings") hlayout_preprocess.addWidget(self.preprocess_controls.widget) self.zslider = QtWidgets.QSlider(parent=self.left_widget, orientation=QtCore.Qt.Vertical) self.zslider.setInvertedAppearance(True) self.zslider.setSingleStep(1) self.zslider.valueChanged.connect(self.update_zlevel) label_zslider = QtWidgets.QLabel(self.left_widget) label_zslider.setText("z-level") self.spinbox_zlevel = QtWidgets.QSpinBox(self.left_widget) self.spinbox_zlevel.setSingleStep(1) self.spinbox_zlevel.valueChanged.connect(self.zslider.setValue) self.zslider.valueChanged.connect(self.spinbox_zlevel.setValue) hlayout_preprocess.addWidget(label_zslider) hlayout_preprocess.addWidget(self.zslider) hlayout_preprocess.addWidget(self.spinbox_zlevel) self.left_layout.addLayout(hlayout_preprocess) # preprocess image item self.glw_preprocess = GraphicsLayoutWidget(self.left_widget) self.imgitem_preprocess = ImageItem() self.viewbox_preprocess = self.glw_preprocess.addViewBox() self.viewbox_preprocess.setAspectLocked(True) self.viewbox_preprocess.addItem(self.imgitem_preprocess) self.left_layout.addWidget(self.glw_preprocess) self.splitter.addWidget(self.left_widget) # segmentation stuff self.nuset_model = Nuset() self.right_layout = QtWidgets.QVBoxLayout(self) self.right_widget = QtWidgets.QWidget(self.splitter) self.right_widget.setLayout(self.right_layout) hlayout_nuset = QtWidgets.QHBoxLayout(self.right_widget) arg_opts_nuset = \ { 'image': {'ignore': True}, 'min_score': { 'minmax': (0.0, 1.0), 'step': 0.05 }, 'nms_threshold': { 'minmax': (0.0, 1.0), 'step': 0.05 }, 'rescale_ratio': { 'minmax': (0.1, 10.0), 'step': 0.25, 'val': 1.25 # not working if set to 1.0 with pyqtgraph ImageItem for some reason } } self.nuset_controls = \ Function( self.nuset_model.predict, arg_opts=arg_opts_nuset, parent=self.right_widget ) # self.nuset_controls.button_set.hide() self.nuset_controls.sig_set_clicked.connect(self.update_segmentation) self.nuset_controls.set_title("NuSeT Parameters") hlayout_nuset.addWidget(self.nuset_controls.widget) arg_opts_postprocess = \ { 'img': {'ignore': True}, 'abs_obj_threshold': { 'minmax': (-1, 100), 'step': 2, }, 'rel_obj_threshold': { 'minmax': (0, 100), 'step': 2 }, 'obj_connectivity': { 'minmax': (0, 10), 'step': 1 }, 'abs_hol_threshold': { 'minmax': (-1, 100), 'step': 2, }, 'rel_hol_threshold': { 'minmax': (0, 100), 'step': 2 }, 'hol_connectivity': { 'minmax': (0, 100), 'step': 1 } } self.postprocess_controls = \ Function( get_postprocess, arg_opts=arg_opts_postprocess, parent=self.right_widget ) self.postprocess_controls.button_set.hide() self.postprocess_controls.sig_changed.connect(self.update_postprocess) self.postprocess_controls.set_title("Post-process Parameters") hlayout_nuset.addWidget(self.postprocess_controls.widget) self.right_layout.addLayout(hlayout_nuset) self.checkbox_segment_current_plane = QtWidgets.QCheckBox( self.nuset_controls.widget) self.checkbox_segment_current_plane.setText( "Only segment current plane") self.checkbox_segment_current_plane.setToolTip( "Performs segmentation for only the current plane, " "useful for trying out parameters.") self.checkbox_segment_current_plane.setChecked(True) self.nuset_controls.vlayout.addWidget( self.checkbox_segment_current_plane) self.glw_segmented = GraphicsLayoutWidget(self.right_widget) self.imgitem_segmented = ImageItem() self.imgitem_segmented_underlay = ImageItem() self.viewbox_segmented = self.glw_segmented.addViewBox() self.viewbox_segmented.setAspectLocked(True) self.viewbox_segmented.addItem(self.imgitem_segmented) self.viewbox_segmented.addItem(self.imgitem_segmented_underlay) # colormaps for the mask overlay plot cm_cyan = cm.get_cmap(cmap_cyan) cm_cyan._init() lut_cyan = (cm_cyan._lut * 255).view(np.ndarray)[128:-5] self.imgitem_segmented_underlay.setLookupTable(lut_cyan) # colormaps for the mask overlay plot cm_magenta = cm.get_cmap(cmap_magenta) cm_magenta._init() lut_magenta = (cm_magenta._lut * 255).view( np.ndarray)[:-5] # so it displays as a mask self.imgitem_segmented.setLookupTable(lut_magenta) # allow transparency # self.imgitem_segmented.setCompositionMode(QtGui.QPainter.CompositionMode_Overlay) self.imgitem_segmented_underlay.setCompositionMode( QtGui.QPainter.CompositionMode_SourceOver) self.imgitem_segmented.setZValue(2) self.imgitem_segmented.setOpacity(0.5) self.imgitem_segmented_underlay.setZValue(1) self.imgitem_segmented_underlay.setOpacity(0.3) self.slider_underlay_opacity = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider_underlay_opacity.setMinimum(0) self.slider_underlay_opacity.setMaximum(100) self.slider_underlay_opacity.setValue(30) self.slider_underlay_opacity.valueChanged.connect( lambda v: self.imgitem_segmented_underlay.setOpacity(v / 100)) label_underlay_opacity = QtWidgets.QLabel(self.nuset_controls.widget) label_underlay_opacity.setText("Underlay opacity") self.nuset_controls.vlayout.addWidget(label_underlay_opacity) self.nuset_controls.vlayout.addWidget(self.slider_underlay_opacity) self.slider_mask_opacity = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.slider_mask_opacity.setMinimum(0) self.slider_mask_opacity.setMaximum(100) self.slider_mask_opacity.setValue(50) self.slider_mask_opacity.valueChanged.connect( lambda v: self.imgitem_segmented.setOpacity(v / 100)) label_segmented_opacity = QtWidgets.QLabel(self.nuset_controls.widget) label_segmented_opacity.setText("Segmentation opacity") self.nuset_controls.vlayout.addWidget(label_segmented_opacity) self.nuset_controls.vlayout.addWidget(self.slider_mask_opacity) self.combo_blend_mode = QtWidgets.QComboBox(self.nuset_controls.widget) self.combo_blend_mode.addItems( ['SourceOver', 'Overlay', 'Plus', 'Multiply']) self.combo_blend_mode.setCurrentIndex(0) self.combo_blend_mode.currentTextChanged.connect( lambda opt: self.imgitem_segmented.setCompositionMode( getattr(QtGui.QPainter, f'CompositionMode_{opt}'))) label_blend_mode = QtWidgets.QLabel(self.nuset_controls.widget) label_blend_mode.setText('Blend mode:') self.nuset_controls.vlayout.addWidget(label_blend_mode) self.nuset_controls.vlayout.addWidget(self.combo_blend_mode) self.right_layout.addWidget(self.glw_segmented) self.splitter.addWidget(self.right_widget) self.export_widget = ExportWidget(self) self.imgs_projected: List[np.ndarray] = [] self.imgs_preprocessed: List[np.ndarray] = [] self.imgs_segmented: List[np.ndarray] = [] self.imgs_postprocessed: List[np.ndarray] = [] self.input_img: np.ndarray = np.empty(0) self.zlevel = 0 self.z_max: int = 0 self.process_pool = Pool(cpu_count()) self.error_label = QtWidgets.QLabel(self) self.error_label.setMaximumHeight(20) self.error_label.setStyleSheet("font-weight: bold; color: red") self.vlayout.addWidget(self.error_label) self.projection_option = '' self.params_final = None if viewer_ref is None: logger.info("Assuming testing mode") else: self.vi = ViewerUtils(viewer_ref) self.vi.viewer.sig_workEnv_changed.connect(self.set_input) self.set_input(self.vi.viewer.workEnv)
from pyqtgraph.console import ConsoleWidget def f(a: int = 1, b: float = 3.14, c: str = 'yay', d: bool = True): pass if __name__ == '__main__': app = QtWidgets.QApplication([]) opts = \ { 'b': { 'use_slider': True, 'minmax': (0, 100), 'step': 1, 'suffix': '%', 'typ': int, 'tooltip': 'yay tooltips' } } func = Function(f, arg_opts=opts) func.widget.show() console = ConsoleWidget(parent=func.widget, namespace={'this': func}) func.vlayout.addWidget(console) app.exec()