def __init__(self, parent, batch_manager): super().__init__(parent) self.task_count = 0 self.calculation_manager = batch_manager self.whole_progress = QProgressBar(self) self.whole_progress.setMinimum(0) self.whole_progress.setMaximum(1) self.whole_progress.setFormat("%v of %m") self.whole_progress.setTextVisible(True) self.part_progress = QProgressBar(self) self.part_progress.setMinimum(0) self.part_progress.setMaximum(1) self.part_progress.setFormat("%v of %m") self.whole_label = QLabel("All batch progress:", self) self.part_label = QLabel("Single batch progress:", self) self.cancel_remove_btn = QPushButton("Remove task") self.cancel_remove_btn.setDisabled(True) self.logs = ExceptionList(self) self.logs.setToolTip("Logs") self.task_view = QListView() self.task_que = QStandardItemModel(self) self.task_view.setModel(self.task_que) self.process_num_timer = QTimer() self.process_num_timer.setInterval(1000) self.process_num_timer.setSingleShot(True) self.process_num_timer.timeout.connect(self.change_number_of_workers) self.number_of_process = QSpinBox(self) self.number_of_process.setRange(1, multiprocessing.cpu_count()) self.number_of_process.setValue(1) self.number_of_process.setToolTip( "Number of process used in batch calculation") self.number_of_process.valueChanged.connect( self.process_num_timer_start) self.progress_item_dict = {} layout = QGridLayout() layout.addWidget(self.whole_label, 0, 0, Qt.AlignRight) layout.addWidget(self.whole_progress, 0, 1, 1, 2) layout.addWidget(self.part_label, 1, 0, Qt.AlignRight) layout.addWidget(self.part_progress, 1, 1, 1, 2) lab = QLabel("Number of process:") lab.setToolTip("Number of process used in batch calculation") layout.addWidget(lab, 2, 0) layout.addWidget(self.number_of_process, 2, 1) layout.addWidget(self.logs, 3, 0, 2, 3) layout.addWidget(self.task_view, 0, 4, 4, 1) layout.addWidget(self.cancel_remove_btn, 4, 4, 1, 1) layout.setColumnMinimumWidth(2, 10) layout.setColumnStretch(2, 1) self.setLayout(layout) self.preview_timer = QTimer() self.preview_timer.setInterval(1000) self.preview_timer.timeout.connect(self.update_info) self.task_view.selectionModel().currentChanged.connect( self.task_selection_change) self.cancel_remove_btn.clicked.connect(self.task_cancel_remove)
def add_brainrender_panel(self, layout): self.initialise_brainrender() self.brainrender_panel = QGroupBox("brainrender") brainrender_layout = QGridLayout() add_button( "View in Brainrender", brainrender_layout, self.to_brainrender, 4, 1, ) self.region_alpha = add_float_box( brainrender_layout, self.region_alpha_default, 0, 1, "Segmented region alpha", 0.1, 0, ) self.structure_alpha = add_float_box( brainrender_layout, self.structure_alpha_default, 0, 1, "Atlas region alpha", 0.1, 1, ) self.shading = add_combobox( brainrender_layout, "Segmented region shading", self.vtkplotter_shading_types, 2, ) self.region_to_render = add_combobox( brainrender_layout, "Region to render", self.available_meshes, 3, ) brainrender_layout.setColumnMinimumWidth(1, 150) self.brainrender_panel.setLayout(brainrender_layout) layout.addWidget(self.brainrender_panel, 6, 0, 1, 2) layout.setAlignment(QtCore.Qt.AlignTop) layout.setSpacing(4) self.brainrender_panel.setVisible(False)
def __init__(self, parent, batch_manager): QWidget.__init__(self, parent) self.calculation_manager = batch_manager self.whole_progress = QProgressBar(self) self.whole_progress.setMinimum(0) self.whole_progress.setMaximum(1) self.whole_progress.setFormat("%v of %m") self.whole_progress.setTextVisible(True) self.part_progress = QProgressBar(self) self.part_progress.setMinimum(0) self.part_progress.setMaximum(1) self.part_progress.setFormat("%v of %m") self.whole_label = QLabel("All batch progress:", self) self.part_label = QLabel("Single batch progress:", self) self.logs = ExceptionList(self) self.logs.setToolTip("Logs") self.task_que = QListWidget() self.process_num_timer = QTimer() self.process_num_timer.setInterval(1000) self.process_num_timer.setSingleShot(True) self.process_num_timer.timeout.connect(self.change_number_of_workers) self.number_of_process = QSpinBox(self) self.number_of_process.setRange(1, multiprocessing.cpu_count()) self.number_of_process.setValue(1) self.number_of_process.setToolTip( "Number of process used in batch calculation") self.number_of_process.valueChanged.connect( self.process_num_timer_start) layout = QGridLayout() layout.addWidget(self.whole_label, 0, 0, Qt.AlignRight) layout.addWidget(self.whole_progress, 0, 1, 1, 2) layout.addWidget(self.part_label, 1, 0, Qt.AlignRight) layout.addWidget(self.part_progress, 1, 1, 1, 2) lab = QLabel("Number of process:") lab.setToolTip("Number of process used in batch calculation") layout.addWidget(lab, 2, 0) layout.addWidget(self.number_of_process, 2, 1) layout.addWidget(self.logs, 3, 0, 1, 3) layout.addWidget(self.task_que, 0, 4, 0, 1) layout.setColumnMinimumWidth(2, 10) layout.setColumnStretch(2, 1) self.setLayout(layout) self.preview_timer = QTimer() self.preview_timer.setInterval(1000) self.preview_timer.timeout.connect(self.update_info)
def __init__(self, subject_settings): super(SubjectWidget, self).__init__() self.subject_enums = DBWrapper().return_enums('subject') subject_layout = QGridLayout(self) subject_layout.setColumnMinimumWidth(2, 60) subject_layout.addWidget(QLabel("Id: "), 0, 0, 1, 1) self.id_combo = QComboBox() self.id_combo.setEditable(True) self.id_combo.addItem('') self.id_combo.addItems(DBWrapper().list_all_subjects()) self.id_combo.currentIndexChanged.connect(self.load_subject) self.id_combo.lineEdit().editingFinished.connect(self.check_subject) subject_layout.addWidget(self.id_combo, 0, 1, 1, 4) subject_layout.addWidget(QLabel("Name: "), 1, 0, 1, 1) self.name_edit = QLineEdit() self.name_edit.setMaxLength(135) subject_layout.addWidget(self.name_edit, 1, 1, 1, 4) subject_layout.addWidget(QLabel("Sex: "), 2, 0, 1, 1) self.sex_combo = QComboBox() self.sex_combo.addItems(self.subject_enums['sex'] if 'sex' in self.subject_enums.keys() else []) self.sex_combo.setCurrentIndex(0) subject_layout.addWidget(self.sex_combo, 2, 1, 1, 1) subject_layout.addWidget((QLabel("Date of birth: ")), 3, 0, 1, 1) self.dob_calendar = QCalendarWidget() subject_layout.addWidget(self.dob_calendar, 3, 1, 1, 3) subject_layout.addWidget(QLabel("NSP file comment: "), 4, 0, 1, 1) self.file_comment = QTextEdit("") self.file_comment.setMaximumHeight(150) subject_layout.addWidget(self.file_comment, 4, 1, 1, 4) # Subject Settings self.subject_settings = subject_settings if not self.subject_settings: self.update_settings_from_db(-1) self.update_subject()
def add_region_panel(self, layout): self.region_panel = QGroupBox("Region analysis") region_layout = QGridLayout() add_button( "Add region", region_layout, self.add_new_region, 2, 0, ) add_button( "Analyse regions", region_layout, self.run_region_analysis, 2, 1, ) self.calculate_volumes_checkbox = add_checkbox( region_layout, self.calculate_volumes_default, "Calculate volumes", 0, ) self.summarise_volumes_checkbox = add_checkbox( region_layout, self.summarise_volumes_default, "Summarise volumes", 1, ) region_layout.setColumnMinimumWidth(1, 150) self.region_panel.setLayout(region_layout) layout.addWidget(self.region_panel, 5, 0, 1, 2) layout.setAlignment(QtCore.Qt.AlignTop) layout.setSpacing(4) self.region_panel.setVisible(False)
def add_region_panel(self, row): self.region_panel = QGroupBox("Region analysis") region_layout = QGridLayout() add_button( "Add region", region_layout, self.add_region, 2, 0, ) add_button( "Analyse regions", region_layout, self.run_region_analysis, 2, 1, ) self.calculate_volumes_checkbox = add_checkbox( region_layout, self.calculate_volumes_default, "Calculate volumes", 0, ) self.summarise_volumes_checkbox = add_checkbox( region_layout, self.summarise_volumes_default, "Summarise volumes", 1, ) region_layout.setColumnMinimumWidth(1, COLUMN_WIDTH) self.region_panel.setLayout(region_layout) self.parent.layout.addWidget(self.region_panel, row, 0, 1, 2) self.region_panel.setVisible(False)
def add_track_panel(self, row): self.track_panel = QGroupBox("Track tracing") track_layout = QGridLayout() add_button( "Add surface points", track_layout, self.add_surface_points, 5, 1, ) add_button( "Add track", track_layout, self.add_track, 6, 0, ) add_button( "Trace tracks", track_layout, self.run_track_analysis, 6, 1, ) self.summarise_track_checkbox = add_checkbox( track_layout, self.summarise_track_default, "Summarise", 0, ) self.fit_degree = add_int_box( track_layout, self.fit_degree_default, 1, 5, "Fit degree", 1, ) self.spline_smoothing = add_float_box( track_layout, self.spline_smoothing_default, 0, 1, "Spline smoothing", 0.1, 2, ) self.spline_points = add_int_box( track_layout, self.spline_points_default, 1, 10000, "Spline points", 3, ) track_layout.setColumnMinimumWidth(1, COLUMN_WIDTH) self.track_panel.setLayout(track_layout) self.parent.layout.addWidget(self.track_panel, row, 0, 1, 2) self.track_panel.setVisible(False)
class SegmentationWidget(QWidget): def __init__( self, viewer, boundaries_string=BOUNDARIES_STRING, ): super(SegmentationWidget, self).__init__() # general variables self.viewer = viewer # Disable / overwrite napari viewer functions # that either do not make sense or should be avoided by the user disable_napari_btns(self.viewer) disable_napari_key_bindings() # overwrite_napari_roll(self.viewer) # Main layers self.base_layer = [] # Contains registered brain / reference brain self.atlas_layer = [] # Contains annotations / region information # Track variables self.track_layers = [] # Region variables self.label_layers = [] # Atlas variables self.current_atlas_name = "" self.atlas = None self.boundaries_string = boundaries_string self.directory = "" # Set up segmentation methods self.region_seg = RegionSeg(self) self.track_seg = TrackSeg(self) # Generate main layout self.setup_main_layout() if DISPLAY_REGION_INFO: @self.viewer.mouse_move_callbacks.append def display_region_info(v, event): """ Show brain region info on mouse over in status bar on the right """ assert self.viewer == v if len(v.layers) and self.atlas_layer and self.atlas: _, _, _, region_info = structure_from_viewer( self.viewer.status, self.atlas_layer, self.atlas) self.viewer.help = region_info def setup_main_layout(self): """ Construct main layout of widget """ self.layout = QGridLayout() self.layout.setContentsMargins(10, 10, 10, 10) self.layout.setAlignment(QtCore.Qt.AlignTop) self.layout.setSpacing(4) # 3 Steps: # - Loading panel # - Segmentation methods panel # -> Individual segmentation methods (which are invisible at first) # - Saving panel self.add_loading_panel(1) self.add_segmentation_methods_panel(1) self.track_seg.add_track_panel(2) # Track segmentation subpanel self.region_seg.add_region_panel(3) # Region segmentation subpanel self.add_saving_panel(4) # Take care of status label self.status_label = QLabel() self.status_label.setText("Ready") self.layout.addWidget(self.status_label, 5, 0) self.setLayout(self.layout) # PANELS ############################################################### def add_segmentation_methods_panel(self, row, column=1): """ Segmentation methods chooser panel: Toggle visibility of segmentation methods """ self.toggle_methods_panel = QGroupBox("Segmentation") self.toggle_methods_layout = QGridLayout() self.toggle_methods_layout.setContentsMargins(10, 10, 10, 10) self.toggle_methods_layout.setSpacing(5) self.toggle_methods_layout.setAlignment(QtCore.Qt.AlignBottom) self.show_trackseg_button = add_button( "Track tracing", self.toggle_methods_layout, self.track_seg.toggle_track_panel, 0, 1, minimum_width=COLUMN_WIDTH, alignment=SEGM_METHODS_PANEL_ALIGN, ) self.show_trackseg_button.setEnabled(False) self.show_regionseg_button = add_button( "Region segmentation", self.toggle_methods_layout, self.region_seg.toggle_region_panel, 1, 1, minimum_width=COLUMN_WIDTH, alignment=SEGM_METHODS_PANEL_ALIGN, ) self.show_regionseg_button.setEnabled(False) self.toggle_methods_layout.setColumnMinimumWidth(1, COLUMN_WIDTH) self.toggle_methods_panel.setLayout(self.toggle_methods_layout) self.toggle_methods_panel.setVisible(True) self.layout.addWidget(self.toggle_methods_panel, row, column, 1, 1) def add_loading_panel(self, row, column=0): """ Loading panel: - Load project (sample space) - Load project (atlas space) - Atlas chooser """ self.load_data_panel = QGroupBox("Load data") self.load_data_layout = QGridLayout() self.load_data_layout.setSpacing(15) self.load_data_layout.setContentsMargins(10, 10, 10, 10) self.load_data_layout.setAlignment(QtCore.Qt.AlignBottom) self.load_button = add_button( "Load project (sample space)", self.load_data_layout, self.load_brainreg_directory_sample, 0, 0, minimum_width=COLUMN_WIDTH, alignment=LOADING_PANEL_ALIGN, ) self.load_button_standard = add_button( "Load project (atlas space)", self.load_data_layout, self.load_brainreg_directory_standard, 1, 0, minimum_width=COLUMN_WIDTH, alignment=LOADING_PANEL_ALIGN, ) self.add_atlas_menu(self.load_data_layout) self.load_data_layout.setColumnMinimumWidth(0, COLUMN_WIDTH) self.load_data_panel.setLayout(self.load_data_layout) self.load_data_panel.setVisible(True) self.layout.addWidget(self.load_data_panel, row, column, 1, 1) def add_saving_panel(self, row): """ Saving/Export panel """ self.save_data_panel = QGroupBox() self.save_data_layout = QGridLayout() self.export_button = add_button( "To brainrender", self.save_data_layout, self.export_to_brainrender, 0, 0, visibility=False, ) self.save_button = add_button("Save", self.save_data_layout, self.save, 0, 1, visibility=False) self.save_data_layout.setColumnMinimumWidth(1, COLUMN_WIDTH) self.save_data_panel.setLayout(self.save_data_layout) self.layout.addWidget(self.save_data_panel, row, 0, 1, 2) self.save_data_panel.setVisible(False) # ATLAS INTERACTION #################################################### def add_atlas_menu(self, layout): list_of_atlasses = ["Load atlas"] available_atlases = get_available_atlases() for atlas in available_atlases.keys(): atlas_desc = f"{atlas} v{available_atlases[atlas]}" list_of_atlasses.append(atlas_desc) atlas_menu, _ = add_combobox( layout, None, list_of_atlasses, 2, 0, label_stack=True, callback=self.initialise_atlas, width=COLUMN_WIDTH, ) self.atlas_menu = atlas_menu def initialise_atlas(self): atlas_string = self.atlas_menu.currentText() atlas_name = atlas_string.split(" ")[0].strip() if atlas_name != self.current_atlas_name: status = self.remove_layers() if not status: # Something prevented deletion self.reset_atlas_menu() return else: print(f"{atlas_string} already selected for segmentation.") self.reset_atlas_menu() return # Get / set output directory self.set_output_directory() if not self.directory: self.reset_atlas_menu() return self.current_atlas_name = atlas_name # Instantiate atlas layers self.load_atlas() self.directory = self.directory / atlas_name self.paths = Paths(self.directory, atlas_space=True) self.status_label.setText("Ready") # Set window title self.viewer.title = f"Atlas: {self.current_atlas_name}" self.initialise_segmentation_interface() # Check / load previous regions and tracks self.region_seg.check_saved_region() self.track_seg.check_saved_track() self.reset_atlas_menu() def set_output_directory(self): self.status_label.setText("Loading...") options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.directory = QFileDialog.getExistingDirectory( self, "Select output directory", options=options, ) if self.directory != "": self.directory = Path(self.directory) def load_atlas(self): atlas = BrainGlobeAtlas(self.current_atlas_name) self.atlas = atlas self.base_layer = self.viewer.add_image( self.atlas.reference, name="Reference", ) self.atlas_layer = self.viewer.add_labels( self.atlas.annotation, name=self.atlas.atlas_name, blending="additive", opacity=0.3, visible=False, ) self.standard_space = True def reset_atlas_menu(self): # Reset menu for atlas - show initial description self.atlas_menu.blockSignals(True) self.atlas_menu.setCurrentIndex(0) self.atlas_menu.blockSignals(False) # BRAINREG INTERACTION ################################################# def load_brainreg_directory_sample(self): self.get_brainreg_directory(standard_space=False) def load_brainreg_directory_standard(self): self.get_brainreg_directory(standard_space=True) def get_brainreg_directory(self, standard_space): """ Shows file dialog to choose output directory and sets global directory info """ if standard_space: self.plugin = "brainreg_standard" self.standard_space = True else: self.plugin = "brainreg" self.standard_space = False self.status_label.setText("Loading...") options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog brainreg_directory = QFileDialog.getExistingDirectory( self, "Select brainreg directory", options=options, ) if not brainreg_directory: return if self.directory != brainreg_directory: status = self.remove_layers() if not status: return # Something prevented deletion self.directory = Path(brainreg_directory) else: print(f"{str(brainreg_directory)} already loaded.") return # Otherwise, proceed loading brainreg dir self.load_brainreg_directory() def load_brainreg_directory(self): """ Opens brainreg folder in napari. Calls initialise_loaded_data to set up layers / info. Then checks for previously loaded data. """ try: self.viewer.open(str(self.directory), plugin=self.plugin) self.paths = Paths( self.directory, standard_space=self.standard_space, ) self.initialise_loaded_data() except ValueError: print(f"The directory ({self.directory}) does not appear to be " f"a brainreg directory, please try again.") return # Check / load previous regions and tracks self.region_seg.check_saved_region() self.track_seg.check_saved_track() def initialise_loaded_data(self): """ Set up brainreg layers in napari / fill with new data and info """ try: self.viewer.layers.remove(self.boundaries_string) except KeyError: pass self.base_layer = self.viewer.layers["Registered image"] self.metadata = self.base_layer.metadata self.atlas = self.metadata["atlas_class"] self.atlas_layer = self.viewer.layers[self.metadata["atlas"]] self.initialise_segmentation_interface() # Set window title self.viewer.title = ( f"Brainreg: {self.metadata['atlas']} ({self.plugin})") self.status_label.setText("Ready") # MORE LAYOUT COMPONENTS ########################################### def initialise_segmentation_interface(self): self.reset_variables() self.initialise_image_view() self.save_data_panel.setVisible(True) self.save_button.setVisible(True) self.export_button.setVisible(self.standard_space) self.show_regionseg_button.setEnabled(True) self.show_trackseg_button.setEnabled(True) self.status_label.setText("Ready") def initialise_image_view(self): self.set_z_position() def set_z_position(self): midpoint = int(round(len(self.base_layer.data) / 2)) self.viewer.dims.set_point(0, midpoint) def reset_variables(self): """ Reset atlas scale dependent variables - point_size (Track segmentation) - spline_size (Track segmentation) - brush_size (Region segmentation) """ self.mean_voxel_size = int( np.sum(self.atlas.resolution) / len(self.atlas.resolution)) self.track_seg.point_size = (self.track_seg.point_size_default / self.mean_voxel_size) self.track_seg.spline_size = (self.track_seg.spline_size_default / self.mean_voxel_size) self.region_seg.brush_size = (self.region_seg.brush_size_default / self.mean_voxel_size) return def display_delete_warning(self): """ Display a warning in a pop up that informs about deletion of all annotation layers """ message_reply = QMessageBox.question( self, "About to remove layers", "All layers are about to be deleted. Proceed?", QMessageBox.Yes | QMessageBox.Cancel, ) if message_reply == QMessageBox.Yes: return True else: return False def remove_layers(self): """ TODO: This needs work. Runs into an error currently when switching from a annotated project to another one """ if len(self.viewer.layers) != 0: # Check with user if that is really what is wanted if self.track_layers or self.label_layers: choice = self.display_delete_warning() if not choice: print('Preventing deletion because user chose "Cancel"') return False # Remove old layers for layer in list(self.viewer.layers): try: self.viewer.layers.remove(layer) except IndexError: # no idea why this happens pass # There seems to be a napari bug trying to access previously used slider # values. Trying to circument for now self.viewer.window.qt_viewer.dims._last_used = None self.track_layers = [] self.label_layers = [] return True def save(self): if self.label_layers or self.track_layers: print("Saving") worker = save_all( self.paths.regions_directory, self.paths.tracks_directory, self.label_layers, self.track_layers, track_file_extension=TRACK_FILE_EXT, ) worker.start() def export_to_brainrender(self): print("Exporting") max_axis_2 = self.base_layer.shape[2] worker = export_all( self.paths.regions_directory, self.paths.tracks_directory, self.label_layers, self.track_seg.splines, self.track_seg.spline_names, self.atlas.resolution[0], max_axis_2, ) worker.start()
def __init__(self, parent, text): QWidget.__init__(self, parent) self.text_editor = QTextEdit(self) self.text_editor.setText(text) self.text_editor.setReadOnly(True) # Type frame type_layout = QHBoxLayout() type_label = QLabel(_("Import as")) type_layout.addWidget(type_label) data_btn = QRadioButton(_("data")) data_btn.setChecked(True) self._as_data= True type_layout.addWidget(data_btn) code_btn = QRadioButton(_("code")) self._as_code = False type_layout.addWidget(code_btn) txt_btn = QRadioButton(_("text")) type_layout.addWidget(txt_btn) h_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) type_layout.addItem(h_spacer) type_frame = QFrame() type_frame.setLayout(type_layout) # Opts frame grid_layout = QGridLayout() grid_layout.setSpacing(0) col_label = QLabel(_("Column separator:")) grid_layout.addWidget(col_label, 0, 0) col_w = QWidget() col_btn_layout = QHBoxLayout() self.tab_btn = QRadioButton(_("Tab")) self.tab_btn.setChecked(False) col_btn_layout.addWidget(self.tab_btn) other_btn_col = QRadioButton(_("other")) other_btn_col.setChecked(True) col_btn_layout.addWidget(other_btn_col) col_w.setLayout(col_btn_layout) grid_layout.addWidget(col_w, 0, 1) self.line_edt = QLineEdit(",") self.line_edt.setMaximumWidth(30) self.line_edt.setEnabled(True) other_btn_col.toggled.connect(self.line_edt.setEnabled) grid_layout.addWidget(self.line_edt, 0, 2) row_label = QLabel(_("Row separator:")) grid_layout.addWidget(row_label, 1, 0) row_w = QWidget() row_btn_layout = QHBoxLayout() self.eol_btn = QRadioButton(_("EOL")) self.eol_btn.setChecked(True) row_btn_layout.addWidget(self.eol_btn) other_btn_row = QRadioButton(_("other")) row_btn_layout.addWidget(other_btn_row) row_w.setLayout(row_btn_layout) grid_layout.addWidget(row_w, 1, 1) self.line_edt_row = QLineEdit(";") self.line_edt_row.setMaximumWidth(30) self.line_edt_row.setEnabled(False) other_btn_row.toggled.connect(self.line_edt_row.setEnabled) grid_layout.addWidget(self.line_edt_row, 1, 2) grid_layout.setRowMinimumHeight(2, 15) other_group = QGroupBox(_("Additional options")) other_layout = QGridLayout() other_group.setLayout(other_layout) skiprows_label = QLabel(_("Skip rows:")) other_layout.addWidget(skiprows_label, 0, 0) self.skiprows_edt = QLineEdit('0') self.skiprows_edt.setMaximumWidth(30) intvalid = QIntValidator(0, len(to_text_string(text).splitlines()), self.skiprows_edt) self.skiprows_edt.setValidator(intvalid) other_layout.addWidget(self.skiprows_edt, 0, 1) other_layout.setColumnMinimumWidth(2, 5) comments_label = QLabel(_("Comments:")) other_layout.addWidget(comments_label, 0, 3) self.comments_edt = QLineEdit('#') self.comments_edt.setMaximumWidth(30) other_layout.addWidget(self.comments_edt, 0, 4) self.trnsp_box = QCheckBox(_("Transpose")) #self.trnsp_box.setEnabled(False) other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0) grid_layout.addWidget(other_group, 3, 0, 2, 0) opts_frame = QFrame() opts_frame.setLayout(grid_layout) data_btn.toggled.connect(opts_frame.setEnabled) data_btn.toggled.connect(self.set_as_data) code_btn.toggled.connect(self.set_as_code) # self.connect(txt_btn, SIGNAL("toggled(bool)"), # self, SLOT("is_text(bool)")) # Final layout layout = QVBoxLayout() layout.addWidget(type_frame) layout.addWidget(self.text_editor) layout.addWidget(opts_frame) self.setLayout(layout)
class QtLayerControls(QFrame): """Superclass for all the other LayerControl classes. This class is never directly instantiated anywhere. Parameters ---------- layer : napari.layers.Layer An instance of a napari layer. Attributes ---------- blendComboBox : qtpy.QtWidgets.QComboBox Drowpdown widget to select blending mode of layer. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Layer An instance of a napari layer. opacitySlider : qtpy.QtWidgets.QSlider Slider controlling opacity of the layer. """ def __init__(self, layer): super().__init__() self.layer = layer self.layer.events.blending.connect(self._on_blending_change) self.layer.events.opacity.connect(self._on_opacity_change) self.setObjectName('layer') self.setMouseTracking(True) self.grid_layout = QGridLayout(self) self.grid_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setSpacing(2) self.grid_layout.setColumnMinimumWidth(0, 86) self.grid_layout.setColumnStretch(1, 1) self.setLayout(self.grid_layout) sld = QDoubleSlider(Qt.Horizontal, parent=self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(1) sld.setSingleStep(0.01) sld.valueChanged.connect(self.changeOpacity) self.opacitySlider = sld self._on_opacity_change() blend_comboBox = QComboBox(self) for index, (data, text) in enumerate(BLENDING_TRANSLATIONS.items()): data = data.value blend_comboBox.addItem(text, data) if data == self.layer.blending: blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect(self.changeBlending) self.blendComboBox = blend_comboBox def changeOpacity(self, value): """Change opacity value on the layer model. Parameters ---------- value : float Opacity value for shapes. Input range 0 - 100 (transparent to fully opaque). """ with self.layer.events.blocker(self._on_opacity_change): self.layer.opacity = value def changeBlending(self, text): """Change blending mode on the layer model. Parameters ---------- text : str Name of blending mode, eg: 'translucent', 'additive', 'opaque'. """ self.layer.blending = self.blendComboBox.currentData() def _on_opacity_change(self): """Receive layer model opacity change event and update opacity slider.""" with self.layer.events.opacity.blocker(): self.opacitySlider.setValue(self.layer.opacity) def _on_blending_change(self): """Receive layer model blending mode change event and update slider.""" with self.layer.events.blending.blocker(): self.blendComboBox.setCurrentIndex( self.blendComboBox.findData(self.layer.blending)) def deleteLater(self): disconnect_events(self.layer.events, self) super().deleteLater() def close(self): """Disconnect events when widget is closing.""" disconnect_events(self.layer.events, self) for child in self.children(): close_method = getattr(child, 'close', None) if close_method is not None: close_method() return super().close()
def __init__(self, *args, **kwargs): super(Arboretum, self).__init__(*args, **kwargs) layout = QVBoxLayout() # add some buttons self.load_button = QPushButton('Load...', self) self.config_button = QPushButton('Configure...', self) self.localize_button = QPushButton('Localize', self) self.track_button = QPushButton('Track', self) self.save_button = QPushButton('Save...', self) # checkboxes self.optimize_checkbox = QCheckBox() self.optimize_checkbox.setChecked(True) # self.use_states_checkbox = QCheckBox() # self.use_states_checkbox.setChecked(True) # combo boxes self.tracking_mode_combobox = QComboBox() for mode in BayesianUpdates: self.tracking_mode_combobox.addItem(mode.name.lower()) default_mode = BayesianUpdates.EXACT self.tracking_mode_combobox.setCurrentIndex(default_mode.value) # # sliders self.search_radius_slider = QSlider(Qt.Horizontal) self.search_radius_slider.setFocusPolicy(Qt.NoFocus) self.search_radius_slider.setMinimum(1) self.search_radius_slider.setMaximum(300) self.search_radius_slider.setSingleStep(1) # self.search_radius_slider.setEnabled(False) # dynamic labels self.config_filename_label = QLabel() self.localizations_label = QLabel() self.tracks_label = QLabel() self.status_label = QLabel() self.search_radius_label = QLabel() self.search_radius_label.setAlignment(Qt.AlignRight) # load/save buttons io_panel = QWidget() io_layout = QHBoxLayout() io_layout.addWidget(self.load_button) io_layout.addWidget(self.save_button) io_panel.setLayout(io_layout) io_panel.setMaximumWidth(GUI_MAXIMUM_WIDTH) layout.addWidget(io_panel) # tracking panel tracking_panel = QGroupBox('tracking') tracking_layout = QGridLayout() tracking_layout.addWidget(QLabel('method: '), 0, 0) tracking_layout.addWidget(self.tracking_mode_combobox, 0, 1) tracking_layout.addWidget(self.search_radius_label, 1, 0) tracking_layout.addWidget(self.search_radius_slider, 1, 1) tracking_layout.addWidget(QLabel('optimize: '), 2, 0) tracking_layout.addWidget(self.optimize_checkbox, 2, 1) tracking_layout.addWidget(self.config_button, 3, 0) tracking_layout.addWidget(self.config_filename_label, 3, 1) tracking_layout.addWidget(self.localize_button, 4, 0) tracking_layout.addWidget(self.localizations_label, 4, 1) tracking_layout.addWidget(self.track_button, 5, 0) tracking_layout.addWidget(self.tracks_label, 5, 1) tracking_layout.setColumnMinimumWidth(1, 150) tracking_layout.setSpacing(4) tracking_panel.setMaximumWidth(GUI_MAXIMUM_WIDTH) tracking_panel.setLayout(tracking_layout) layout.addWidget(tracking_panel) # status panel status_panel = QGroupBox('status') status_layout = QHBoxLayout() status_layout.addWidget(self.status_label) status_panel.setMaximumWidth(GUI_MAXIMUM_WIDTH) status_panel.setLayout(status_layout) layout.addWidget(status_panel) # set the layout layout.setAlignment(Qt.AlignTop) layout.setSpacing(4) self.setLayout(layout) self.setMaximumHeight(GUI_MAXIMUM_HEIGHT) self.setMaximumWidth(GUI_MAXIMUM_WIDTH) # callbacks self.load_button.clicked.connect(self.load_data) self.save_button.clicked.connect(self.export_data) self.config_button.clicked.connect(self.load_config) self.tracking_mode_combobox.currentTextChanged.connect( self._on_mode_change) self.search_radius_slider.valueChanged.connect(self._on_radius_change) self._tracker_state = None self._segmentation = None self._localizations = None self._tracks = None self._btrack_cfg = None self._active_layer = None # TODO(arl): this is the working filename for the dataset self.filename = None self._search_radius = None self._on_mode_change() self.search_radius_slider.setValue(100)
class QtLayer(QFrame): def __init__(self, layer): super().__init__() self.layer = layer layer.events.select.connect(self._on_select) layer.events.deselect.connect(self._on_deselect) layer.events.name.connect(self._on_layer_name_change) layer.events.blending.connect(self._on_blending_change) layer.events.opacity.connect(self._on_opacity_change) layer.events.visible.connect(self._on_visible_change) self.setObjectName('layer') self.grid_layout = QGridLayout() cb = QCheckBox(self) cb.setObjectName('visibility') cb.setToolTip('Layer visibility') cb.setChecked(self.layer.visible) cb.setProperty('mode', 'visibility') cb.stateChanged.connect(lambda state=cb: self.changeVisible(state)) self.visibleCheckBox = cb self.grid_layout.addWidget(cb, 0, 0) textbox = QLineEdit(self) textbox.setText(layer.name) textbox.home(False) textbox.setToolTip('Layer name') textbox.setFixedWidth(122) textbox.setAcceptDrops(False) textbox.setEnabled(True) textbox.editingFinished.connect(self.changeText) self.nameTextBox = textbox self.grid_layout.addWidget(textbox, 0, 1) self.grid_layout.addWidget(QLabel('opacity:'), 1, 0) sld = QSlider(Qt.Horizontal, self) sld.setFocusPolicy(Qt.NoFocus) sld.setFixedWidth(110) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.setValue(self.layer.opacity * 100) sld.valueChanged[int].connect( lambda value=sld: self.changeOpacity(value)) self.opacitySilder = sld self.grid_layout.addWidget(sld, 1, 1) blend_comboBox = QComboBox() for blend in self.layer._blending_modes: blend_comboBox.addItem(blend) index = blend_comboBox.findText(self.layer.blending, Qt.MatchFixedString) blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect( lambda text=blend_comboBox: self.changeBlending(text)) self.blendComboBox = blend_comboBox self.grid_layout.addWidget(QLabel('blending:'), 2, 0) self.grid_layout.addWidget(blend_comboBox, 2, 1) self.setLayout(self.grid_layout) msg = 'Click to select\nDrag to rearrange\nDouble click to expand' self.setToolTip(msg) self.setExpanded(False) self.setFixedWidth(250) self.grid_layout.setColumnMinimumWidth(0, 100) self.grid_layout.setColumnMinimumWidth(1, 100) self.layer.selected = True def _on_select(self, event): self.setProperty('selected', True) self.nameTextBox.setEnabled(True) self.style().unpolish(self) self.style().polish(self) def _on_deselect(self, event): self.setProperty('selected', False) self.nameTextBox.setEnabled(False) self.style().unpolish(self) self.style().polish(self) def changeOpacity(self, value): with self.layer.events.blocker(self._on_opacity_change): self.layer.opacity = value / 100 def changeVisible(self, state): if state == Qt.Checked: self.layer.visible = True else: self.layer.visible = False def changeText(self): self.layer.name = self.nameTextBox.text() def changeBlending(self, text): self.layer.blending = text def mouseReleaseEvent(self, event): modifiers = event.modifiers() if modifiers == Qt.ShiftModifier: index = self.layer.viewer.layers.index(self.layer) lastSelected = None for i in range(len(self.layer.viewer.layers)): if self.layer.viewer.layers[i].selected: lastSelected = i r = [index, lastSelected] r.sort() for i in range(r[0], r[1] + 1): self.layer.viewer.layers[i].selected = True elif modifiers == Qt.ControlModifier: self.layer.selected = not self.layer.selected else: self.layer.viewer.layers.unselect_all(ignore=self.layer) self.layer.selected = True def mousePressEvent(self, event): self.dragStartPosition = event.pos() def mouseMoveEvent(self, event): distance = (event.pos() - self.dragStartPosition).manhattanLength() if distance < QApplication.startDragDistance(): return mimeData = QMimeData() if not self.layer.selected: name = self.layer.name else: name = '' for layer in self.layer.viewer.layers: if layer.selected: name = layer.name + '; ' + name name = name[:-2] mimeData.setText(name) drag = QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(event.pos() - self.rect().topLeft()) dropAction = drag.exec_(Qt.MoveAction | Qt.CopyAction) if dropAction == Qt.CopyAction: if not self.layer.selected: index = self.layer.viewer.layers.index(self.layer) self.layer.viewer.layers.pop(index) else: self.layer.viewer.layers.remove_selected() def setExpanded(self, bool): if bool: self.expanded = True rows = self.grid_layout.rowCount() self.setFixedHeight(55 * (rows - 1)) else: self.expanded = False self.setFixedHeight(55) rows = self.grid_layout.rowCount() for i in range(1, rows): for j in range(2): if self.expanded: self.grid_layout.itemAtPosition(i, j).widget().show() else: self.grid_layout.itemAtPosition(i, j).widget().hide() def mouseDoubleClickEvent(self, event): self.setExpanded(not self.expanded) def _on_layer_name_change(self, event): with self.layer.events.name.blocker(): self.nameTextBox.setText(self.layer.name) self.nameTextBox.home(False) def _on_opacity_change(self, event): with self.layer.events.opacity.blocker(): self.opacitySilder.setValue(self.layer.opacity * 100) def _on_blending_change(self, event): with self.layer.events.blending.blocker(): index = self.blendComboBox.findText(self.layer.blending, Qt.MatchFixedString) self.blendComboBox.setCurrentIndex(index) def _on_visible_change(self, event): with self.layer.events.visible.blocker(): self.visibleCheckBox.setChecked(self.layer.visible)
def get_manual_correction_widget(self, parent): """.""" man_wid = QWidget(parent) man_wid.setObjectName('grp') gdl = QGridLayout(man_wid) gdl.setSpacing(9) calc = PyDMPushButton( man_wid, '', pressValue=1, init_channel=self.devpref.substitute(propty='CalcDelta-Cmd')) calc.setIcon(qta.icon('mdi.calculator-variant')) calc.setToolTip('Calculate Kicks') calc.setObjectName('button') calc.setStyleSheet('#button {\ min-height: 45px; min-width: 45px;\ max-height: 45px; max-width: 45px;\ icon-size: 40px;}') rules = ( '[{"name": "EnblRule", "property": "Enable", ' + '"expression": "not ch[0]", "channels": [{"channel": "' + self.devpref.substitute(propty='LoopState-Sts') + '", "trigger": true}]}]') calc.rules = rules if self.acc == 'BO': gdl.addWidget(calc, 1, 1) gdl.setColumnStretch(0, 2) gdl.setColumnStretch(2, 2) gdl.setRowStretch(0, 2) gdl.setRowStretch(2, 2) return man_wid exp = 'ch[0] in (1, 2, 3)' ch = '' if self.isring: exp = 'ch[1] in (1, 2, 3) and not ch[0]' ch = '{"channel": "' + self.devpref.substitute( propty='LoopState-Sts') + '", "trigger": true},' rules = ( '[{"name": "EnblRule", "property": "Enable", ' + '"expression": "'+exp+'", "channels": ['+ch + '{"channel": "'+self.devpref.substitute(propty='SOFBMode-Sts') + '", "trigger": true}]}]') lst = [ ('All', self._csorb.ApplyDelta.All), ('CH', self._csorb.ApplyDelta.CH), ('CV', self._csorb.ApplyDelta.CV)] if self.acc in {'SI', 'BO'}: lst.append(('RF', self._csorb.ApplyDelta.RF)) btns = dict() for itm, val in lst: btn = PyDMPushButton( man_wid, ' '+itm, pressValue=val, init_channel=self.devpref.substitute(propty='ApplyDelta-Cmd')) btn.rules = rules btn.setIcon(qta.icon('fa5s.hammer')) btn.setToolTip('Apply ' + itm) btn.setObjectName('button') btn.setStyleSheet('#button {\ min-height: 25px; min-width: 45px;\ max-height: 25px;\ icon-size: 20px;}') if self.acc == 'BO': btn.setVisible(False) btns[itm] = btn gdl.addWidget(calc, 0, 0, 2, 1) gdl.addWidget(btns['CH'], 0, 1) gdl.addWidget(btns['CV'], 0, 2) if self.acc in {'SI', 'BO'}: gdl.addWidget(btns['RF'], 0, 3) gdl.addWidget(btns['All'], 1, 1, 1, 3) else: gdl.addWidget(btns['All'], 1, 1, 1, 2) gdl.setColumnMinimumWidth(0, 60) grpbx = QWidget(man_wid) grpbx.setObjectName('gbx') if self.acc in {'SI', 'BO'}: planes = ('CH', 'CV', 'RF') gdl.addWidget(grpbx, 2, 0, 1, 4) else: planes = ('CH', 'CV') gdl.addWidget(grpbx, 2, 0, 1, 3) fbl = QFormLayout(grpbx) for pln in planes: lbl = QLabel(pln+' [%] ', grpbx) lbl.setObjectName('lbl') lbl.setStyleSheet('#lbl{min-height:1em;}') wid = self.create_pair(grpbx, 'ManCorrGain'+pln) wid.setObjectName('wid') wid.setStyleSheet('#wid{min-height:1.2em;}') if self.acc == 'BO': lbl.setVisible(False) wid.setVisible(False) fbl.addRow(lbl, wid) vlay = QVBoxLayout() vlay.addStretch() gdl.addLayout(vlay, 3, 0) return man_wid
def add_track_panel(self, layout): self.track_panel = QGroupBox("Track tracing") track_layout = QGridLayout() add_button( "Add track", track_layout, self.add_track, 5, 0, ) add_button( "Trace tracks", track_layout, self.run_track_analysis, 5, 1, ) self.summarise_track_checkbox = add_checkbox( track_layout, self.summarise_track_default, "Summarise", 0, ) self.add_surface_point_checkbox = add_checkbox( track_layout, self.add_surface_point_default, "Add surface point", 1, ) self.fit_degree = add_int_box( track_layout, self.fit_degree_default, 1, 5, "Fit degree", 2, ) self.spline_smoothing = add_float_box( track_layout, self.spline_smoothing_default, 0, 1, "Spline smoothing", 0.1, 3, ) self.spline_points = add_int_box( track_layout, self.spline_points_default, 1, 10000, "Spline points", 4, ) track_layout.setColumnMinimumWidth(1, 150) self.track_panel.setLayout(track_layout) layout.addWidget(self.track_panel, 3, 0, 1, 2) layout.setAlignment(QtCore.Qt.AlignTop) layout.setSpacing(4) self.track_panel.setVisible(False)
class QtLayerProperties(QFrame): def __init__(self, layer): super().__init__() self.layer = layer layer.events.select.connect(lambda v: self.setSelected(True)) layer.events.deselect.connect(lambda v: self.setSelected(False)) layer.events.name.connect(self._on_layer_name_change) layer.events.blending.connect(self._on_blending_change) layer.events.opacity.connect(self._on_opacity_change) layer.events.visible.connect(self._on_visible_change) layer.events.thumbnail.connect(self._on_thumbnail_change) self.setObjectName('layer') self.vbox_layout = QVBoxLayout() self.top = QFrame() self.top_layout = QHBoxLayout() self.grid = QFrame() self.grid_layout = QGridLayout() self.vbox_layout.addWidget(self.top) self.vbox_layout.addWidget(self.grid) self.vbox_layout.setSpacing(0) self.top.setFixedHeight(38) self.top_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setContentsMargins(0, 0, 0, 0) self.top_layout.setAlignment(Qt.AlignCenter) self.top.setLayout(self.top_layout) self.grid.setLayout(self.grid_layout) self.setLayout(self.vbox_layout) self.name_column = 0 self.property_column = 1 cb = QCheckBox(self) cb.setObjectName('visibility') cb.setToolTip('Layer visibility') cb.setChecked(self.layer.visible) cb.setProperty('mode', 'visibility') cb.stateChanged.connect(lambda state=cb: self.changeVisible(state)) self.visibleCheckBox = cb self.top_layout.addWidget(cb) tb = QLabel(self) tb.setObjectName('thumbmnail') tb.setToolTip('Layer thumbmnail') self.thumbnail_label = tb self._on_thumbnail_change(None) self.top_layout.addWidget(tb) textbox = QLineEdit(self) textbox.setText(layer.name) textbox.home(False) textbox.setToolTip('Layer name') textbox.setAcceptDrops(False) textbox.setEnabled(True) textbox.editingFinished.connect(self.changeText) self.nameTextBox = textbox self.top_layout.addWidget(textbox) pb = QPushButton(self) pb.setToolTip('Expand properties') pb.clicked.connect(self.changeExpanded) pb.setObjectName('expand') self.expand_button = pb self.top_layout.addWidget(pb) row = self.grid_layout.rowCount() sld = QSlider(Qt.Horizontal, self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.setValue(self.layer.opacity * 100) sld.valueChanged[int].connect( lambda value=sld: self.changeOpacity(value)) self.opacitySilder = sld row = self.grid_layout.rowCount() self.grid_layout.addWidget(QLabel('opacity:'), row, self.name_column) self.grid_layout.addWidget(sld, row, self.property_column) row = self.grid_layout.rowCount() blend_comboBox = QComboBox() for blend in Blending: blend_comboBox.addItem(str(blend)) index = blend_comboBox.findText(self.layer.blending, Qt.MatchFixedString) blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect( lambda text=blend_comboBox: self.changeBlending(text)) self.blendComboBox = blend_comboBox self.grid_layout.addWidget(QLabel('blending:'), row, self.name_column) self.grid_layout.addWidget(blend_comboBox, row, self.property_column) msg = 'Click to select\nDrag to rearrange\nDouble click to expand' self.setToolTip(msg) self.setExpanded(False) self.setFixedWidth(250) self.grid_layout.setColumnMinimumWidth(0, 100) self.grid_layout.setColumnMinimumWidth(1, 100) self.setSelected(self.layer.selected) def setSelected(self, state): self.setProperty('selected', state) self.nameTextBox.setEnabled(state) self.style().unpolish(self) self.style().polish(self) def changeOpacity(self, value): with self.layer.events.blocker(self._on_opacity_change): self.layer.opacity = value / 100 def changeVisible(self, state): if state == Qt.Checked: self.layer.visible = True else: self.layer.visible = False def changeText(self): self.layer.name = self.nameTextBox.text() def changeBlending(self, text): self.layer.blending = text def mouseReleaseEvent(self, event): event.ignore() def mousePressEvent(self, event): event.ignore() def mouseMoveEvent(self, event): event.ignore() def mouseDoubleClickEvent(self, event): self.setExpanded(not self.expanded) def changeExpanded(self): self.setExpanded(not self.expanded) def setExpanded(self, bool): if bool: self.expanded = True self.expand_button.setProperty('expanded', True) rows = self.grid_layout.rowCount() self.setFixedHeight(38 + 30 * rows) self.grid.show() else: self.expanded = False self.expand_button.setProperty('expanded', False) self.setFixedHeight(60) self.grid.hide() self.expand_button.style().unpolish(self.expand_button) self.expand_button.style().polish(self.expand_button) def _on_layer_name_change(self, event): with self.layer.events.name.blocker(): self.nameTextBox.setText(self.layer.name) self.nameTextBox.home(False) def _on_opacity_change(self, event): with self.layer.events.opacity.blocker(): self.opacitySilder.setValue(self.layer.opacity * 100) def _on_blending_change(self, event): with self.layer.events.blending.blocker(): index = self.blendComboBox.findText(self.layer.blending, Qt.MatchFixedString) self.blendComboBox.setCurrentIndex(index) def _on_visible_change(self, event): with self.layer.events.visible.blocker(): self.visibleCheckBox.setChecked(self.layer.visible) def _on_thumbnail_change(self, event): thumbnail = self.layer.thumbnail # Note that QImage expects the image width followed by height image = QImage( thumbnail, thumbnail.shape[1], thumbnail.shape[0], QImage.Format_RGBA8888, ) self.thumbnail_label.setPixmap(QPixmap.fromImage(image))
class QtLayerControls(QFrame): """Superclass for all the other LayerControl classes. This class is never directly instantiated anywhere. Parameters ---------- layer : napari.layers.Layer An instance of a napari layer. Attributes ---------- blendComboBox : qtpy.QtWidgets.QComboBox Drowpdown widget to select blending mode of layer. grid_layout : qtpy.QtWidgets.QGridLayout Layout of Qt widget controls for the layer. layer : napari.layers.Layer An instance of a napari layer. opacitySlider : qtpy.QtWidgets.QSlider Slider controlling opacity of the layer. """ def __init__(self, layer): super().__init__() self.layer = layer self.layer.events.blending.connect(self._on_blending_change) self.layer.events.opacity.connect(self._on_opacity_change) self.setAttribute(Qt.WA_DeleteOnClose) self.setObjectName('layer') self.setMouseTracking(True) self.grid_layout = QGridLayout(self) self.grid_layout.setContentsMargins(0, 0, 0, 0) self.grid_layout.setSpacing(2) self.grid_layout.setColumnMinimumWidth(0, 86) self.grid_layout.setColumnStretch(1, 1) self.setLayout(self.grid_layout) sld = QSlider(Qt.Horizontal, parent=self) sld.setFocusPolicy(Qt.NoFocus) sld.setMinimum(0) sld.setMaximum(100) sld.setSingleStep(1) sld.valueChanged.connect(self.changeOpacity) self.opacitySlider = sld self._on_opacity_change() blend_comboBox = QComboBox(self) blend_comboBox.addItems(Blending.keys()) index = blend_comboBox.findText( self.layer.blending, Qt.MatchFixedString ) blend_comboBox.setCurrentIndex(index) blend_comboBox.activated[str].connect(self.changeBlending) self.blendComboBox = blend_comboBox def changeOpacity(self, value): """Change opacity value on the layer model. Parameters ---------- value : float Opacity value for shapes. Input range 0 - 100 (transparent to fully opaque). """ with self.layer.events.blocker(self._on_opacity_change): self.layer.opacity = value / 100 def changeBlending(self, text): """Change blending mode on the layer model. Parameters ---------- text : str Name of blending mode, eg: 'translucent', 'additive', 'opaque'. """ self.layer.blending = text def _on_opacity_change(self, event=None): """Receive layer model opacity change event and update opacity slider. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method, by default None. """ with self.layer.events.opacity.blocker(): self.opacitySlider.setValue(int(self.layer.opacity * 100)) def _on_blending_change(self, event=None): """Receive layer model blending mode change event and update slider. Parameters ---------- event : napari.utils.event.Event, optional The napari event that triggered this method, by default None. """ with self.layer.events.blending.blocker(): index = self.blendComboBox.findText( self.layer.blending, Qt.MatchFixedString ) self.blendComboBox.setCurrentIndex(index) def close(self): """Disconnect events when widget is closing.""" disconnect_events(self.layer.events, self) for child in self.children(): close_method = getattr(child, 'close', None) if close_method is not None: close_method() super().close()
def __init__(self, parent, text): QWidget.__init__(self, parent) self.text_editor = QTextEdit(self) self.text_editor.setText(text) self.text_editor.setReadOnly(True) # Type frame type_layout = QHBoxLayout() type_label = QLabel(_("Import as")) type_layout.addWidget(type_label) data_btn = QRadioButton(_("data")) data_btn.setChecked(True) self._as_data = True type_layout.addWidget(data_btn) code_btn = QRadioButton(_("code")) self._as_code = False type_layout.addWidget(code_btn) txt_btn = QRadioButton(_("text")) type_layout.addWidget(txt_btn) h_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) type_layout.addItem(h_spacer) type_frame = QFrame() type_frame.setLayout(type_layout) # Opts frame grid_layout = QGridLayout() grid_layout.setSpacing(0) col_label = QLabel(_("Column separator:")) grid_layout.addWidget(col_label, 0, 0) col_w = QWidget() col_btn_layout = QHBoxLayout() self.tab_btn = QRadioButton(_("Tab")) self.tab_btn.setChecked(False) col_btn_layout.addWidget(self.tab_btn) self.ws_btn = QRadioButton(_("Whitespace")) self.ws_btn.setChecked(False) col_btn_layout.addWidget(self.ws_btn) other_btn_col = QRadioButton(_("other")) other_btn_col.setChecked(True) col_btn_layout.addWidget(other_btn_col) col_w.setLayout(col_btn_layout) grid_layout.addWidget(col_w, 0, 1) self.line_edt = QLineEdit(",") self.line_edt.setMaximumWidth(30) self.line_edt.setEnabled(True) other_btn_col.toggled.connect(self.line_edt.setEnabled) grid_layout.addWidget(self.line_edt, 0, 2) row_label = QLabel(_("Row separator:")) grid_layout.addWidget(row_label, 1, 0) row_w = QWidget() row_btn_layout = QHBoxLayout() self.eol_btn = QRadioButton(_("EOL")) self.eol_btn.setChecked(True) row_btn_layout.addWidget(self.eol_btn) other_btn_row = QRadioButton(_("other")) row_btn_layout.addWidget(other_btn_row) row_w.setLayout(row_btn_layout) grid_layout.addWidget(row_w, 1, 1) self.line_edt_row = QLineEdit(";") self.line_edt_row.setMaximumWidth(30) self.line_edt_row.setEnabled(False) other_btn_row.toggled.connect(self.line_edt_row.setEnabled) grid_layout.addWidget(self.line_edt_row, 1, 2) grid_layout.setRowMinimumHeight(2, 15) other_group = QGroupBox(_("Additional options")) other_layout = QGridLayout() other_group.setLayout(other_layout) skiprows_label = QLabel(_("Skip rows:")) other_layout.addWidget(skiprows_label, 0, 0) self.skiprows_edt = QLineEdit('0') self.skiprows_edt.setMaximumWidth(30) intvalid = QIntValidator(0, len(to_text_string(text).splitlines()), self.skiprows_edt) self.skiprows_edt.setValidator(intvalid) other_layout.addWidget(self.skiprows_edt, 0, 1) other_layout.setColumnMinimumWidth(2, 5) comments_label = QLabel(_("Comments:")) other_layout.addWidget(comments_label, 0, 3) self.comments_edt = QLineEdit('#') self.comments_edt.setMaximumWidth(30) other_layout.addWidget(self.comments_edt, 0, 4) self.trnsp_box = QCheckBox(_("Transpose")) #self.trnsp_box.setEnabled(False) other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0) grid_layout.addWidget(other_group, 3, 0, 2, 0) opts_frame = QFrame() opts_frame.setLayout(grid_layout) data_btn.toggled.connect(opts_frame.setEnabled) data_btn.toggled.connect(self.set_as_data) code_btn.toggled.connect(self.set_as_code) # self.connect(txt_btn, SIGNAL("toggled(bool)"), # self, SLOT("is_text(bool)")) # Final layout layout = QVBoxLayout() layout.addWidget(type_frame) layout.addWidget(self.text_editor) layout.addWidget(opts_frame) self.setLayout(layout)
class CurationWidget(QWidget): def __init__( self, viewer, ): super(CurationWidget, self).__init__() self.viewer = viewer self.background_layer = [] self.background_path = "" self.signal_layer = [] self.signal_path = "" self.directory = "" self.output_directory = None self.setup_main_layout() def setup_main_layout(self): """ Construct main layout of widget """ self.layout = QGridLayout() self.layout.setContentsMargins(10, 10, 10, 10) self.layout.setAlignment(QtCore.Qt.AlignTop) self.layout.setSpacing(4) self.add_loading_panel(1) self.status_label = QLabel() self.status_label.setText("Ready") self.layout.addWidget(self.status_label, 5, 0) self.setLayout(self.layout) def add_loading_panel(self, row, column=0): """ Loading panel: - Load project (sample space) - Load project (atlas space) - Atlas chooser """ self.load_data_panel = QGroupBox("Load data") self.load_data_layout = QGridLayout() self.load_data_layout.setSpacing(15) self.load_data_layout.setContentsMargins(10, 10, 10, 10) self.load_data_layout.setAlignment(QtCore.Qt.AlignBottom) # self.load_cellfinder_dir_button = add_button( # "Load cellfinder project", # self.load_data_layout, # self.get_cellfinder_directory, # 0, # 0, # minimum_width=COLUMN_WIDTH, # ) # self.load_background_button = add_button( # "Load background", # self.load_data_layout, # self.get_background, # 1, # 0, # minimum_width=COLUMN_WIDTH, # ) self.load_signal_button = add_button( "Load signal", self.load_data_layout, self.get_signal, 2, 0, minimum_width=COLUMN_WIDTH, ) self.add_cells_button = add_button( "Add cell count", self.load_data_layout, self.add_cell_count, 3, 0, minimum_width=COLUMN_WIDTH, ) self.add_cells_button = add_button( "Load cell count", self.load_data_layout, self.load_cells, 4, 0, minimum_width=COLUMN_WIDTH, ) self.save_cells_button = add_button( "Save cells", self.load_data_layout, self.save_cell_count, 5, 0, minimum_width=COLUMN_WIDTH, ) self.analyse_cells_button = add_button( "Analyse cells", self.load_data_layout, self.analyse_cells, 6, 0, minimum_width=COLUMN_WIDTH, ) self.load_data_layout.setColumnMinimumWidth(0, COLUMN_WIDTH) self.load_data_panel.setLayout(self.load_data_layout) self.load_data_panel.setVisible(True) self.layout.addWidget(self.load_data_panel, row, column, 1, 1) def get_cellfinder_directory(self): self.status_label.setText("Loading...") options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog cellfinder_directory = QFileDialog.getExistingDirectory( self, "Select cellfinder directory", options=options, ) if not cellfinder_directory: return if self.directory != cellfinder_directory: self.directory = Path(cellfinder_directory) else: print(f"{str(cellfinder_directory)} already loaded.") return # Otherwise, proceed loading brainreg dir self.load_cellfinder_directory() self.status_label.setText("Ready...") def load_cellfinder_directory(self): try: self.viewer.open(str(self.directory), plugin="cellfinder") except ValueError: print(f"The directory ({self.directory}) does not appear to be " f"a cellfinder directory, please try again.") return def get_background(self): self.background_layer, self.background_path = self.get_data( name="background", visible=False) def get_signal(self): self.signal_layer, self.signal_path = self.get_data(name="signal") self.status_label.setText("Ready") def get_data(self, name="", visible=True): self.status_label.setText("Loading...") options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog directory = QFileDialog.getExistingDirectory( self, f"Select {name} channel", options=options, ) if not directory: return if self.directory != directory: self.directory = Path(directory) else: print(f"{str(directory)} already loaded.") return return self.load_data(name=name, visible=visible), directory def load_data(self, name="", visible=True): try: img_paths = get_sorted_file_paths(self.directory, file_extension=".tif") images = magic_imread(img_paths, use_dask=True, stack=True) return self.viewer.add_image(images) # return self.viewer.open( # str(self.directory), name=name, visible=visible # ) except ValueError: print(f"The directory ({self.directory}) cannot be " f"loaded, please try again.") return def add_cell_count(self): self.cell_layer = self.viewer.add_points( np.empty((0, 3)), symbol="ring", n_dimensional=True, size=10, opacity=0.6, face_color="lightgoldenrodyellow", name="cells", ) def load_cells(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog filename = QFileDialog.getOpenFileName( self, "Select cell file...", filter="cellfinder xml files (*.xml)", options=options, ) cells, _ = get_cell_arrays(filename[0]) self.cell_layer = self.viewer.add_points( cells, symbol="ring", n_dimensional=True, size=10, opacity=0.6, face_color="lightgoldenrodyellow", name="cells", ) def save_cell_count(self): self.status_label.setText("Saving cells") print("Saving cells") self.get_output_directory() filename = self.output_directory / "cells.xml" cells_to_save = [] for idx, point in enumerate(self.cell_layer.data): cell = Cell([point[2], point[1], point[0]], Cell.CELL) cells_to_save.append(cell) save_cells(cells_to_save, str(filename)) self.status_label.setText("Ready") print("Done!") def get_output_directory(self): if self.output_directory is None: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.output_directory = QFileDialog.getExistingDirectory( self, "Select output directory", options=options, ) self.output_directory = Path(self.output_directory) def analyse_cells(self): self.status_label.setText("Analysing cells") print("Analysing cells") self.get_output_directory() self.get_brainreg_directory() analyse_cell_positions( self.cell_layer.data, self.brainreg_directory, self.signal_path, self.output_directory, ) self.status_label.setText("Ready") def get_brainreg_directory(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog self.brainreg_directory = QFileDialog.getExistingDirectory( self, "Select brainreg directory", options=options, )