def __init__(self, main_widget, tab, settings_tab=True): super(ROIImageViewModule, self).__init__(main_widget, histogram=False) self.tab = tab self.resetting_view = False # Way to prevent infinite loops of reset_view self.current_foreground_intensity = 30 self.click_event = False self.outlines = True self.trial_selector_input = OptionInput( "Time Block:", "", lambda x, y: self.set_background("", self.current_background_name), val_list=self.data_handler.trials_loaded, tool_tip="Select Time block to display", display_tool_tip=False, default_index=0, show_name=True) self.set_background("", "Max Image", update_image=False) self.image_item.mouseClickEvent = lambda x: self.roi_view_click(x) self.image_item.mouseDragEvent = lambda x: self.roi_view_drag(x) shape = main_widget.data_handler.shape self.select_image_flat = np.zeros([shape[0] * shape[1], 3]) self.box_selector_enabled = False self.box_selector_cords = [(0, 0), (0, 0)] self.current_background_name = "Max Image" if settings_tab: self.layout.removeWidget(self.image_view) self.layout.addWidget(self.createTabLayout())
def createSettings(self): self.display_settings_layout = QVBoxLayout() display_settings = QWidget() display_settings.setLayout(self.display_settings_layout) image_chooser = OptionInput("ROI Display type:", "", on_change_function=self.set_image, default_index=0, tool_tip="Choose background to display", val_list=["Outlines", "Blob", "Neuropil"]) self.display_settings_layout.addWidget(image_chooser) self.background_chooser = OptionInput( "Background:", "", on_change_function=self.set_background, default_index=2, tool_tip="Choose background to display", val_list=[ "Blank Image", "Mean Image", "Max Image", # "Temporal Correlation Image", "Eigen Norm Image" ]) self.display_settings_layout.addWidget(self.background_chooser) self.display_settings_layout.addWidget(self.trial_selector_input) background_slider_layout = QHBoxLayout() label_0 = QLabel("0") label_0.setStyleSheet("QWidget {border: 0px solid #32414B;}") background_slider_layout.addWidget(label_0) # initializes a slider to control how much to blend background image in when # blob is view is enabled self.background_slider = QSlider(Qt.Horizontal) self.background_slider.setStyleSheet( "QWidget {border: 0px solid #32414B;}") self.background_slider.setMinimum(0) self.background_slider.setMaximum(100) self.background_slider.setSingleStep(1) self.background_slider.valueChanged.connect( self.intensitySliderChanged) try: self.background_slider.setValue(self.current_foreground_intensity) except AttributeError: pass background_slider_layout.addWidget(self.background_slider) label_10 = QLabel("10") label_10.setStyleSheet("QWidget {border: 0px solid #32414B;}") background_slider_layout.addWidget(label_10) label_overlay = QLabel("Change background intensity:") label_overlay.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.display_settings_layout.addWidget(label_overlay) self.display_settings_layout.addLayout(background_slider_layout) return display_settings
def set_image_display(self, data): self.trial_selector_input.setParent(None) self.trial_selector_input = OptionInput("", "", lambda x, y: 3, val_list=["All"], tool_tip="Select Timeblock to display", display_tool_tip=False, default_index=0, show_name=False) self._image_buttons_layout.addWidget(self.trial_selector_input) self.main_widget.preprocess_image_view.setImage( data.copy())
def set_image_display_list(self, trial_names, data_list, name, button=None): """ Sets the preprocessing image display to use an option input and set data list Parameters ---------- trial_names : List[str] the names of each trial data_list : List[np.ndarray] Corresponding data for each trial Returns ------- Nothing """ def set_image(x, trial_name): try: self.main_widget.preprocess_image_view.setImage( data_list[trial_names.index(trial_name)][:]) except TypeError: self.updateTab() if hasattr(self, "trial_selector_input"): self.trial_selector_input.setParent(None) if hasattr(self, "trial_selector_input"): current = self.trial_selector_input.input_box.currentIndex() else: current = 0 # if button != None: # button.setStyleSheet("QPushButton {border 1px solid #148CD2; }") self.trial_selector_input = OptionInput("", "", set_image, val_list=trial_names, tool_tip="Select time block to display", display_tool_tip=False, default_index=0, show_name=False) self.trial_selector_input.input_box.setCurrentIndex(current) self._image_buttons_layout.addWidget(self.trial_selector_input) set_image("", trial_names[current]) if len(data_list[0].shape) == 3: cur_size = [str(data_list[0].shape[1]), str(data_list[0].shape[2])] else: cur_size = [str(data_list[0].shape[0]), str(data_list[0].shape[1])] if hasattr(self.data_handler, "total_size"): total_size = ( str(self.data_handler.total_size[0]), str(self.data_handler.total_size[1])) else: total_size = [0, 0] self.image_view.image_label.setText( name + ", Original Size: (%s, %s), Cropped Size: (%s, %s)" % ( total_size[1], total_size[0], cur_size[1], cur_size[0])) self.main_widget.console.updateText("Setting current background to: %s" % name)
class PreprocessingTab(Tab): """Class controlling the Preprocessing tab, inherits from Tab Attributes ---------- main_widget : MainWidget A reference to the main widget data_handler : DataHandler A reference to the main DataHandler of MainWidget """ def __init__(self, main_widget): self.main_widget = main_widget self.image_view = self.main_widget.preprocess_image_view # This part initializes the button to process the data process_button = QPushButton() process_button.setText("Apply Settings") process_button_layout = QVBoxLayout() process_button_widget = QWidget() process_button_widget.setLayout(process_button_layout) process_button_layout.addWidget(process_button) process_button_layout.setContentsMargins(0, 0, 0, 0) thread = PreprocessThread(main_widget, process_button, self) main_widget.thread_list.append(thread) # Appends the thread to the main # widget thread list process_button.clicked.connect(lambda: thread.runThread()) # Section that creates all the buttons to change which image is displayed image_buttons = QWidget() self._image_buttons_layout = QHBoxLayout() self._image_buttons_layout.setContentsMargins(2, 0, 2, 0) image_buttons.setLayout(self._image_buttons_layout) self.max_image_button = QPushButton() self.max_image_button.setText("Max Image") self.max_image_button.clicked.connect( lambda: self.set_image_display_list(self.data_handler.trials_loaded, self.data_handler.max_images, "Max Image", self.max_image_button)) stack_button = QPushButton() stack_button.setText("Filtered Stack") stack_button.clicked.connect( lambda: self.set_image_display_list(self.data_handler.trials_loaded, self.data_handler.dataset_trials_filtered_loaded, "Filtered Stack", stack_button)) self.pca_stack_button = QPushButton() self.pca_stack_button.setText("PCA Stack") self.pca_stack_button.clicked.connect( lambda: self.set_image_display_list(self.data_handler.trials_loaded, self.data_handler.pca_decomp, "PCA Stack", self.pca_stack_button)) self.mean_image_button = QPushButton() self.mean_image_button.setText("Mean Image") self.mean_image_button.clicked.connect( lambda: self.set_image_display_list(self.data_handler.trials_loaded, self.data_handler.mean_images, "Mean Image", self.mean_image_button)) self.temporal_correlation_image_button = QPushButton() self.temporal_correlation_image_button.setText("Temporal Correlation Image") self.temporal_correlation_image_button.clicked.connect( lambda: self.set_image_display_list(self.data_handler.trials_loaded, self.data_handler.temporal_correlation_images, "Temporal Correlation Image", self.temporal_correlation_image_button)) self._image_buttons_layout.addWidget(stack_button) self._image_buttons_layout.addWidget(self.max_image_button) self._image_buttons_layout.addWidget(self.mean_image_button) # self._image_buttons_layout.addWidget(self.temporal_correlation_image_button) self._image_buttons_layout.addWidget(self.pca_stack_button) main_widget.preprocess_image_view.setContentsMargins(0, 0, 0, 0) # main_widget.preprocess_image_view.setMargin(0) preprocessing_settings_widget = preprocessing_settings(main_widget) preprocessing_settings_widget.setContentsMargins(0, 0, 0, 0) # preprocessing_settings_widget.setMaximumWidth(400) # preprocessing_settings_widget.setMinimumWidth(int(400*((self.logicalDpiX() / 96.0-1)/2+1))) # main_widget.preprocess_image_view.setMinimumWidth(500) # Update image view self.updateTab() main_widget.preprocess_image_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Initialize the tab with the necessary columns super().__init__("Preprocessing", column_1=[preprocessing_settings_widget ], column_2=[main_widget.preprocess_image_view ], horiz_moveable=True) # process_button_widget.setMaximumWidth(400*((self.logicalDpiX() / 96.0-1)/2+1) self.layout.setContentsMargins(0, 0, 0, 0) self.column_1_layout.addWidget(process_button_widget, alignment=QtCore.Qt.AlignBottom) self.column_1_layout.setContentsMargins(0, 0, 0, 0) self.column_2_layout.addWidget(image_buttons, alignment=QtCore.Qt.AlignBottom) self.column_2_layout.setContentsMargins(0, 0, 0, 0) @property def data_handler(self): return self.main_widget.data_handler def set_image_display_list(self, trial_names, data_list, name, button=None): """ Sets the preprocessing image display to use an option input and set data list Parameters ---------- trial_names : List[str] the names of each trial data_list : List[np.ndarray] Corresponding data for each trial Returns ------- Nothing """ def set_image(x, trial_name): try: self.main_widget.preprocess_image_view.setImage( data_list[trial_names.index(trial_name)][:]) except TypeError: self.updateTab() if hasattr(self, "trial_selector_input"): self.trial_selector_input.setParent(None) if hasattr(self, "trial_selector_input"): current = self.trial_selector_input.input_box.currentIndex() else: current = 0 # if button != None: # button.setStyleSheet("QPushButton {border 1px solid #148CD2; }") self.trial_selector_input = OptionInput("", "", set_image, val_list=trial_names, tool_tip="Select time block to display", display_tool_tip=False, default_index=0, show_name=False) self.trial_selector_input.input_box.setCurrentIndex(current) self._image_buttons_layout.addWidget(self.trial_selector_input) set_image("", trial_names[current]) if len(data_list[0].shape) == 3: cur_size = [str(data_list[0].shape[1]), str(data_list[0].shape[2])] else: cur_size = [str(data_list[0].shape[0]), str(data_list[0].shape[1])] if hasattr(self.data_handler, "total_size"): total_size = ( str(self.data_handler.total_size[0]), str(self.data_handler.total_size[1])) else: total_size = [0, 0] self.image_view.image_label.setText( name + ", Original Size: (%s, %s), Cropped Size: (%s, %s)" % ( total_size[1], total_size[0], cur_size[1], cur_size[0])) self.main_widget.console.updateText("Setting current background to: %s" % name) def set_image_display(self, data): self.trial_selector_input.setParent(None) self.trial_selector_input = OptionInput("", "", lambda x, y: 3, val_list=["All"], tool_tip="Select Timeblock to display", display_tool_tip=False, default_index=0, show_name=False) self._image_buttons_layout.addWidget(self.trial_selector_input) self.main_widget.preprocess_image_view.setImage( data.copy()) def updateTab(self): if (self.main_widget.checkThreadRunning()): self.pca_stack_button.setEnabled(self.data_handler.filter_params["pca"]) self.set_image_display_list(self.data_handler.trials_loaded, self.data_handler.max_images, "Max Image")
def __init__(self, main_widget): self.main_widget = main_widget self.image_view = ROIPaintImageViewModule(main_widget, self, False) self.image_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.roi_unconnected = QErrorMessage(self.main_widget.main_window) # This part creates the top left settings/roi list view in two tabs self.tab_selector_roi = QTabWidget() # self.tab_selector_roi.setStyleSheet("QTabWidget {font-size: 20px;}") # ROI modification Tab roi_modification_tab = QWidget() roi_modification_tab.setStyleSheet("margin:0px; padding: 0px;") roi_modification_tab_layout = QVBoxLayout() roi_modification_tab_layout.setContentsMargins(1, 1, 1, 1) roi_modification_tab_layout_top = QVBoxLayout() roi_modification_tab_layout_top.setContentsMargins(0, 0, 0, 0) roi_modification_tab_layout.addLayout(roi_modification_tab_layout_top) display_settings = self.image_view.createSettings() display_settings.setStyleSheet("QWidget {border: 2px solid #32414B;}") roi_modification_tab_layout.addWidget(display_settings) roi_modification_tab.setLayout(roi_modification_tab_layout) self.roi_list_module = ROIListModule(main_widget.data_handler, self, select_multiple=False, display_time=False) roi_modification_tab_layout.addWidget(self.roi_list_module) roi_modification_button_top_layout = QHBoxLayout() roi_modification_button_top_layout.setContentsMargins(2, 2, 2, 2) roi_modification_button_top_widget = QWidget() roi_modification_button_top_widget.setStyleSheet( "QWidget {border: 0px solid #32414B;}") roi_modification_button_top_widget.setLayout( roi_modification_button_top_layout) # roi_modification_tab_layout.addLayout(roi_modification_button_top_layout) add_new_roi = QPushButton(text="Create ROI from\nMask (D)") add_new_roi.clicked.connect(lambda x: self.add_new_roi()) add_new_roi.setToolTip( "Use this button to create a new ROI from mask. \n" "ROI is added to bottiom of ROI list") add_to_roi = QPushButton(text="Add Mask to \nSelected ROI (A)") add_to_roi.clicked.connect(lambda x: self.modify_roi( self.roi_list_module.current_selected_roi, "add")) add_to_roi.setToolTip("Use this button to add the current mask to" " the selected ROI. \n" "Select an roi in the ROI list below") sub_to_roi = QPushButton(text="Subtract Mask from\nSelected ROI (S)") sub_to_roi.clicked.connect(lambda x: self.modify_roi( self.roi_list_module.current_selected_roi, "subtract")) sub_to_roi.setToolTip( "Use this button to subtract the current mask from" " the selected ROI. \n" "Select an roi in the ROI list below") delete_roi = QPushButton(text="Delete Selected\nROI (F)") delete_roi.setToolTip("Use this button to delete the selected ROI. \n" "Select an roi in the ROI list below") delete_roi.clicked.connect(lambda x: self.delete_roi( self.roi_list_module.current_selected_roi)) roi_modification_button_top_layout.addWidget(add_new_roi) roi_modification_button_top_layout.addWidget(add_to_roi) roi_modification_button_top_layout.addWidget(sub_to_roi) roi_modification_button_top_layout.addWidget(delete_roi) add_to_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") sub_to_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") add_new_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") delete_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") # Paint Selection button group painter_button_group = QButtonGroup() self.off_button = QRadioButton(text="Off (Q)") self.off_button.setChecked(True) self.off_button.setToolTip("Turns off the mask brush") self.on_button = QRadioButton(text="Add to Mask (W)") self.on_button.setToolTip( "Turns on the selector brush, draw on the image by right clicking") self.sub_button = QRadioButton(text="Subtract from Mask (E)") self.sub_button.setToolTip( "Turns the selector brush to subtract mode. Removing currently selected pixels" ) self.magic_wand = QRadioButton(text="Magic Wand (R)") self.magic_wand.setToolTip( "Turns the Mask brush to magic wand mode. Click on where you believe \n" "there should be an ROI, and it will attempt to create one for you.\n Note just click one at a time. " ) self.off_button.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.on_button.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.sub_button.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.magic_wand.setStyleSheet("QWidget {border: 0px solid #32414B;}") painter_button_group.addButton(self.off_button) painter_button_group.addButton(self.on_button) painter_button_group.addButton(self.sub_button) painter_button_group.addButton(self.magic_wand) self.off_button.clicked.connect( lambda x: self.image_view.setSelectorBrushType("off")) self.on_button.clicked.connect( lambda x: self.image_view.setSelectorBrushType("add")) self.sub_button.clicked.connect( lambda x: self.image_view.setSelectorBrushType("subtract")) self.magic_wand.clicked.connect( lambda x: self.image_view.setSelectorBrushType("magic")) painter_widget = QWidget() painter_layout = QVBoxLayout() painter_widget.setLayout(painter_layout) label = QLabel(text="Mask Brush (green): ") label.setStyleSheet("QWidget {border: 0px solid #32414B;}") painter_layout_sub_1 = QHBoxLayout() painter_layout_sub_1.addWidget(label) painter_layout_sub_1.addWidget(self.off_button) painter_layout_sub_2 = QHBoxLayout() painter_layout_sub_2.addWidget(self.on_button) painter_layout_sub_2.addWidget(self.magic_wand) painter_layout_sub_3 = QHBoxLayout() painter_layout_sub_3.addWidget(self.sub_button) painter_layout.addLayout(painter_layout_sub_1) painter_layout.addLayout(painter_layout_sub_2) painter_layout.addLayout(painter_layout_sub_3) self._brush_size_options = OptionInput( "Brush Size:", "", lambda x, y: self.image_view.setBrushSize(y), 1, "Sets the brush size", ["1", "3", "5", "7", "9", "11", "15", "21", "27", "35"]) self._brush_size_options.setStyleSheet( "QWidget {border: 0px solid #32414B;}") painter_layout_sub_3.addWidget(self._brush_size_options) clear_from_selection = QPushButton(text="Clear Mask (T)") clear_from_selection.setStyleSheet( "QWidget {border: 0px solid #32414B;}") clear_from_selection.clicked.connect( lambda x: self.image_view.clearPixelSelection()) painter_layout.addWidget(clear_from_selection) roi_modification_button_top_widget.setStyleSheet( "QWidget {border: 2px solid #32414B; font-size: %dpx}" % (self.main_widget.scale * 20)) painter_widget.setStyleSheet("QWidget {border: 2px solid #32414B;}") roi_modification_tab_layout_top.addWidget(painter_widget) roi_modification_tab_layout_top.addWidget( roi_modification_button_top_widget) recalc_time_traces_button = QPushButton(text="Recalculate Time Traces") recalc_time_traces_button.clicked.connect( lambda: self.update_time_traces()) roi_modification_tab_layout.addWidget(recalc_time_traces_button) # ROI Settings Tab process_button = QPushButton() process_button.setText("Apply Settings") self.thread = ROIExtractionThread(main_widget, process_button, self.roi_list_module, self) self.main_widget.thread_list.append(self.thread) self.time_trace_thread = TimeTraceCalculateThread( main_widget, process_button, self.roi_list_module) self.main_widget.thread_list.append(self.time_trace_thread) process_button.clicked.connect(lambda: self.thread.runThread()) self.roi_settings = QWidget() self.roi_settings_layout = QVBoxLayout() self.roi_settings_layout.setContentsMargins(2, 2, 2, 2) self.roi_settings.setLayout(self.roi_settings_layout) settings = roi_extraction_settings(main_widget) self.roi_settings_layout.addWidget(settings) self.roi_settings_layout.addWidget(process_button) # adding the tabs to the window self.tab_selector_roi.addTab(self.roi_settings, "ROI Creation") self.tab_selector_roi.addTab(roi_modification_tab, "ROI Modification") # self.tab_selector_roi.setMaximumWidth(435) # self.tab_selector_roi.setMinimumWidth(435) # Eigen vector viewer if dev mode is enabled if self.main_widget.dev: self.eigen_view = QWidget() self.eigen_view_layout = QVBoxLayout() self.eigen_view_box_input = IntInput("Box Number", "", None, 0, "", 0, 100, 1, False) self.eigen_view_number_input = IntInput("Vector Number", "", None, 0, "", 0, 100, 1, False) self.eigen_view_trial_input = IntInput("Trial Number", "", None, 0, "", 0, 100, 1, False) view_eigen_vector_button = QPushButton("View Eigen Vector") view_eigen_vector_button.clicked.connect( lambda x: self.view_eigen_vector()) self.eigen_view_layout.addWidget(self.eigen_view_box_input) self.eigen_view_layout.addWidget(self.eigen_view_number_input) self.eigen_view_layout.addWidget(self.eigen_view_trial_input) self.eigen_view_layout.addWidget(view_eigen_vector_button) self.eigen_view.setLayout(self.eigen_view_layout) self.tab_selector_roi.addTab(self.eigen_view, "View Eigen Vectors") # If ROIs are loaded, add them to display # Tab selector for the time trace window tab_selector_time_trace = QTabWidget() # tab_selector_time_trace.setStyleSheet("QTabWidget {font-size: 20px;}") tab_selector_time_trace.setMaximumHeight(220) # plot of time traces self.time_plot = pg.PlotWidget() self.time_plot.getPlotItem().getViewBox().setMouseEnabled(True, False) self.time_plot.showGrid(x=True, y=True, alpha=0.3) tab_selector_time_trace.addTab(self.time_plot, "Time Trace Plot") # Setting window for time traces time_trace_settings = QWidget() time_trace_settings_layout = QVBoxLayout() time_trace_settings_layout.setContentsMargins(0, 0, 0, 0) time_trace_settings.setLayout(time_trace_settings_layout) self.time_trace_type = OptionInput( "Time Trace Type", "", lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="Select way to calculate time trace," " \ncheck github for more details", val_list=list( self.data_handler.time_trace_possibilities_functions.keys())) time_trace_settings_layout.addWidget(self.time_trace_type, stretch=1) # A list widget to select what trials to calculate/display time traces for self._time_trace_trial_select_list = TrialListWidget(False) self._time_trace_trial_select_list.setMinimumHeight(115) self._time_trace_trial_select_list.set_items_from_list( self.data_handler.trials_all, self.data_handler.trials_loaded_time_trace_indices) if not len(self.data_handler.trials_loaded) == 1 and not \ self.data_handler.dataset_params["single_file_mode"] and not \ self.data_handler.dataset_params["trial_split"]: time_trace_settings_layout.addWidget( self._time_trace_trial_select_list, stretch=5) time_trace_update_button = QPushButton("Update Time Traces") time_trace_settings_layout.addWidget(time_trace_update_button) time_trace_update_button.clicked.connect( lambda x: self.update_time_traces()) tab_selector_time_trace.addTab(time_trace_settings, "Time Trace Settings") self.updateTab() super().__init__("ROI Extraction", column_1=[self.tab_selector_roi], column_2=[self.image_view, tab_selector_time_trace], column_2_display=True, horiz_moveable=True) self._brush_size_options.setMinimumHeight( int(30 * ((self.logicalDpiX() / 96.0 - 1) / 2 + 1)))
class ROIExtractionTab(Tab): """Class controlling the ROI Extraction tab, inherits from Tab Attributes ---------- main_widget : MainWidget A reference to the main widget data_handler : DataHandler A reference to the main DataHandler of MainWidget time_plot : pg.PlotWidget the plot for the time traces roi_list_module : ROIListModule The module the controlls the list of ROIs thread : ROIExtractionThread The thread that runs the roi extraction process """ def __init__(self, main_widget): self.main_widget = main_widget self.image_view = ROIPaintImageViewModule(main_widget, self, False) self.image_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.roi_unconnected = QErrorMessage(self.main_widget.main_window) # This part creates the top left settings/roi list view in two tabs self.tab_selector_roi = QTabWidget() # self.tab_selector_roi.setStyleSheet("QTabWidget {font-size: 20px;}") # ROI modification Tab roi_modification_tab = QWidget() roi_modification_tab.setStyleSheet("margin:0px; padding: 0px;") roi_modification_tab_layout = QVBoxLayout() roi_modification_tab_layout.setContentsMargins(1, 1, 1, 1) roi_modification_tab_layout_top = QVBoxLayout() roi_modification_tab_layout_top.setContentsMargins(0, 0, 0, 0) roi_modification_tab_layout.addLayout(roi_modification_tab_layout_top) display_settings = self.image_view.createSettings() display_settings.setStyleSheet("QWidget {border: 2px solid #32414B;}") roi_modification_tab_layout.addWidget(display_settings) roi_modification_tab.setLayout(roi_modification_tab_layout) self.roi_list_module = ROIListModule(main_widget.data_handler, self, select_multiple=False, display_time=False) roi_modification_tab_layout.addWidget(self.roi_list_module) roi_modification_button_top_layout = QHBoxLayout() roi_modification_button_top_layout.setContentsMargins(2, 2, 2, 2) roi_modification_button_top_widget = QWidget() roi_modification_button_top_widget.setStyleSheet( "QWidget {border: 0px solid #32414B;}") roi_modification_button_top_widget.setLayout( roi_modification_button_top_layout) # roi_modification_tab_layout.addLayout(roi_modification_button_top_layout) add_new_roi = QPushButton(text="Create ROI from\nMask (D)") add_new_roi.clicked.connect(lambda x: self.add_new_roi()) add_new_roi.setToolTip( "Use this button to create a new ROI from mask. \n" "ROI is added to bottiom of ROI list") add_to_roi = QPushButton(text="Add Mask to \nSelected ROI (A)") add_to_roi.clicked.connect(lambda x: self.modify_roi( self.roi_list_module.current_selected_roi, "add")) add_to_roi.setToolTip("Use this button to add the current mask to" " the selected ROI. \n" "Select an roi in the ROI list below") sub_to_roi = QPushButton(text="Subtract Mask from\nSelected ROI (S)") sub_to_roi.clicked.connect(lambda x: self.modify_roi( self.roi_list_module.current_selected_roi, "subtract")) sub_to_roi.setToolTip( "Use this button to subtract the current mask from" " the selected ROI. \n" "Select an roi in the ROI list below") delete_roi = QPushButton(text="Delete Selected\nROI (F)") delete_roi.setToolTip("Use this button to delete the selected ROI. \n" "Select an roi in the ROI list below") delete_roi.clicked.connect(lambda x: self.delete_roi( self.roi_list_module.current_selected_roi)) roi_modification_button_top_layout.addWidget(add_new_roi) roi_modification_button_top_layout.addWidget(add_to_roi) roi_modification_button_top_layout.addWidget(sub_to_roi) roi_modification_button_top_layout.addWidget(delete_roi) add_to_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") sub_to_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") add_new_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") delete_roi.setStyleSheet("QWidget {border: 0px solid #32414B;}") # Paint Selection button group painter_button_group = QButtonGroup() self.off_button = QRadioButton(text="Off (Q)") self.off_button.setChecked(True) self.off_button.setToolTip("Turns off the mask brush") self.on_button = QRadioButton(text="Add to Mask (W)") self.on_button.setToolTip( "Turns on the selector brush, draw on the image by right clicking") self.sub_button = QRadioButton(text="Subtract from Mask (E)") self.sub_button.setToolTip( "Turns the selector brush to subtract mode. Removing currently selected pixels" ) self.magic_wand = QRadioButton(text="Magic Wand (R)") self.magic_wand.setToolTip( "Turns the Mask brush to magic wand mode. Click on where you believe \n" "there should be an ROI, and it will attempt to create one for you.\n Note just click one at a time. " ) self.off_button.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.on_button.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.sub_button.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.magic_wand.setStyleSheet("QWidget {border: 0px solid #32414B;}") painter_button_group.addButton(self.off_button) painter_button_group.addButton(self.on_button) painter_button_group.addButton(self.sub_button) painter_button_group.addButton(self.magic_wand) self.off_button.clicked.connect( lambda x: self.image_view.setSelectorBrushType("off")) self.on_button.clicked.connect( lambda x: self.image_view.setSelectorBrushType("add")) self.sub_button.clicked.connect( lambda x: self.image_view.setSelectorBrushType("subtract")) self.magic_wand.clicked.connect( lambda x: self.image_view.setSelectorBrushType("magic")) painter_widget = QWidget() painter_layout = QVBoxLayout() painter_widget.setLayout(painter_layout) label = QLabel(text="Mask Brush (green): ") label.setStyleSheet("QWidget {border: 0px solid #32414B;}") painter_layout_sub_1 = QHBoxLayout() painter_layout_sub_1.addWidget(label) painter_layout_sub_1.addWidget(self.off_button) painter_layout_sub_2 = QHBoxLayout() painter_layout_sub_2.addWidget(self.on_button) painter_layout_sub_2.addWidget(self.magic_wand) painter_layout_sub_3 = QHBoxLayout() painter_layout_sub_3.addWidget(self.sub_button) painter_layout.addLayout(painter_layout_sub_1) painter_layout.addLayout(painter_layout_sub_2) painter_layout.addLayout(painter_layout_sub_3) self._brush_size_options = OptionInput( "Brush Size:", "", lambda x, y: self.image_view.setBrushSize(y), 1, "Sets the brush size", ["1", "3", "5", "7", "9", "11", "15", "21", "27", "35"]) self._brush_size_options.setStyleSheet( "QWidget {border: 0px solid #32414B;}") painter_layout_sub_3.addWidget(self._brush_size_options) clear_from_selection = QPushButton(text="Clear Mask (T)") clear_from_selection.setStyleSheet( "QWidget {border: 0px solid #32414B;}") clear_from_selection.clicked.connect( lambda x: self.image_view.clearPixelSelection()) painter_layout.addWidget(clear_from_selection) roi_modification_button_top_widget.setStyleSheet( "QWidget {border: 2px solid #32414B; font-size: %dpx}" % (self.main_widget.scale * 20)) painter_widget.setStyleSheet("QWidget {border: 2px solid #32414B;}") roi_modification_tab_layout_top.addWidget(painter_widget) roi_modification_tab_layout_top.addWidget( roi_modification_button_top_widget) recalc_time_traces_button = QPushButton(text="Recalculate Time Traces") recalc_time_traces_button.clicked.connect( lambda: self.update_time_traces()) roi_modification_tab_layout.addWidget(recalc_time_traces_button) # ROI Settings Tab process_button = QPushButton() process_button.setText("Apply Settings") self.thread = ROIExtractionThread(main_widget, process_button, self.roi_list_module, self) self.main_widget.thread_list.append(self.thread) self.time_trace_thread = TimeTraceCalculateThread( main_widget, process_button, self.roi_list_module) self.main_widget.thread_list.append(self.time_trace_thread) process_button.clicked.connect(lambda: self.thread.runThread()) self.roi_settings = QWidget() self.roi_settings_layout = QVBoxLayout() self.roi_settings_layout.setContentsMargins(2, 2, 2, 2) self.roi_settings.setLayout(self.roi_settings_layout) settings = roi_extraction_settings(main_widget) self.roi_settings_layout.addWidget(settings) self.roi_settings_layout.addWidget(process_button) # adding the tabs to the window self.tab_selector_roi.addTab(self.roi_settings, "ROI Creation") self.tab_selector_roi.addTab(roi_modification_tab, "ROI Modification") # self.tab_selector_roi.setMaximumWidth(435) # self.tab_selector_roi.setMinimumWidth(435) # Eigen vector viewer if dev mode is enabled if self.main_widget.dev: self.eigen_view = QWidget() self.eigen_view_layout = QVBoxLayout() self.eigen_view_box_input = IntInput("Box Number", "", None, 0, "", 0, 100, 1, False) self.eigen_view_number_input = IntInput("Vector Number", "", None, 0, "", 0, 100, 1, False) self.eigen_view_trial_input = IntInput("Trial Number", "", None, 0, "", 0, 100, 1, False) view_eigen_vector_button = QPushButton("View Eigen Vector") view_eigen_vector_button.clicked.connect( lambda x: self.view_eigen_vector()) self.eigen_view_layout.addWidget(self.eigen_view_box_input) self.eigen_view_layout.addWidget(self.eigen_view_number_input) self.eigen_view_layout.addWidget(self.eigen_view_trial_input) self.eigen_view_layout.addWidget(view_eigen_vector_button) self.eigen_view.setLayout(self.eigen_view_layout) self.tab_selector_roi.addTab(self.eigen_view, "View Eigen Vectors") # If ROIs are loaded, add them to display # Tab selector for the time trace window tab_selector_time_trace = QTabWidget() # tab_selector_time_trace.setStyleSheet("QTabWidget {font-size: 20px;}") tab_selector_time_trace.setMaximumHeight(220) # plot of time traces self.time_plot = pg.PlotWidget() self.time_plot.getPlotItem().getViewBox().setMouseEnabled(True, False) self.time_plot.showGrid(x=True, y=True, alpha=0.3) tab_selector_time_trace.addTab(self.time_plot, "Time Trace Plot") # Setting window for time traces time_trace_settings = QWidget() time_trace_settings_layout = QVBoxLayout() time_trace_settings_layout.setContentsMargins(0, 0, 0, 0) time_trace_settings.setLayout(time_trace_settings_layout) self.time_trace_type = OptionInput( "Time Trace Type", "", lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="Select way to calculate time trace," " \ncheck github for more details", val_list=list( self.data_handler.time_trace_possibilities_functions.keys())) time_trace_settings_layout.addWidget(self.time_trace_type, stretch=1) # A list widget to select what trials to calculate/display time traces for self._time_trace_trial_select_list = TrialListWidget(False) self._time_trace_trial_select_list.setMinimumHeight(115) self._time_trace_trial_select_list.set_items_from_list( self.data_handler.trials_all, self.data_handler.trials_loaded_time_trace_indices) if not len(self.data_handler.trials_loaded) == 1 and not \ self.data_handler.dataset_params["single_file_mode"] and not \ self.data_handler.dataset_params["trial_split"]: time_trace_settings_layout.addWidget( self._time_trace_trial_select_list, stretch=5) time_trace_update_button = QPushButton("Update Time Traces") time_trace_settings_layout.addWidget(time_trace_update_button) time_trace_update_button.clicked.connect( lambda x: self.update_time_traces()) tab_selector_time_trace.addTab(time_trace_settings, "Time Trace Settings") self.updateTab() super().__init__("ROI Extraction", column_1=[self.tab_selector_roi], column_2=[self.image_view, tab_selector_time_trace], column_2_display=True, horiz_moveable=True) self._brush_size_options.setMinimumHeight( int(30 * ((self.logicalDpiX() / 96.0 - 1) / 2 + 1))) def keyPressEvent(self, event): super(ROIExtractionTab, self).keyPressEvent(event) if self.tab_selector_roi.currentIndex() == 1: if event.key() == 81: # Q self.off_button.setChecked(True) self.image_view.setSelectorBrushType("off") if event.key() == 87: # W if self.on_button.isChecked(): self.off_button.setChecked(True) self.image_view.setSelectorBrushType("off") else: self.on_button.setChecked(True) self.image_view.setSelectorBrushType("add") if event.key() == 69: # E if self.sub_button.isChecked(): self.off_button.setChecked(True) self.image_view.setSelectorBrushType("off") else: self.sub_button.setChecked(True) self.image_view.setSelectorBrushType("subtract") if event.key() == 82: # R if self.magic_wand.isChecked(): self.off_button.setChecked(True) self.image_view.setSelectorBrushType("off") else: self.magic_wand.setChecked(True) self.image_view.setSelectorBrushType("magic") if event.key() == 84: # T self.image_view.clearPixelSelection() if event.key() == 65: # A self.modify_roi(self.roi_list_module.current_selected_roi, "add") if event.key() == 83: #S self.modify_roi(self.roi_list_module.current_selected_roi, "subtract") if event.key() == 68: # D self.add_new_roi() if event.key() == 70 or 16777219 == event.key(): # F or delete self.delete_roi(self.roi_list_module.current_selected_roi) @property def data_handler(self): return self.main_widget.data_handler def add_new_roi(self): """ Adds a new roi using selection(self.image_view.current_selected_pixels_list) """ self.main_widget.console.updateText("Creating new ROI") if (self.main_widget.checkThreadRunning()): if len(self.image_view.current_selected_pixels_list) == 0: print("Please select some pixels") self.main_widget.console.updateText( "Please select some pixels") return temp_roi = np.array(self.image_view.current_selected_pixels_list) num = number_connected_components( self.data_handler.shape[0] * self.data_handler.shape[1], [0] + self.data_handler.shape, temp_roi) holes_filled = fill_holes_func([temp_roi], self.data_handler.shape[0] * self.data_handler.shape[1], [0] + self.data_handler.shape) if len(holes_filled[0]) != len(temp_roi): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setStyleSheet(qdarkstyle.load_stylesheet()) msg.setText("Would you like to fill in your selection?") # msg.setInformativeText("This is additional information") # msg.setWindowTitle("MessageBox demo") # msg.setDetailedText("The details are as follows:") msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) retval = msg.exec_() if retval == 16384: temp_roi = holes_filled[0] else: return False if num == 2: pass else: msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setStyleSheet(qdarkstyle.load_stylesheet()) msg.setText( "The pixels you selected are not connected, Are you sure you want to create a new ROI with them?" ) # msg.setInformativeText("This is additional information") # msg.setWindowTitle("MessageBox demo") # msg.setDetailedText("The details are as follows:") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) retval = msg.exec_() if retval == 1024: pass else: return False self.data_handler.rois.append(temp_roi) self.data_handler.gen_roi_display_variables() # self.data_handler.time_traces.append([]) # for _ in range(len(self.data_handler.trials_all)): # self.data_handler.time_traces[-1].append(False) self.data_handler.roi_time_trace_need_update.append(True) # self.data_handler.time_traces.append([np.zeros(50)]) self.image_view.clearPixelSelection() self.update_roi(False) self.roi_list_module.set_list_items(self.data_handler.rois) self.deselectRoiTime() self.roi_list_module.set_current_select(len( self.data_handler.rois)) self.main_widget.tabs[2].updateTab() self.off_button.setChecked(True) self.image_view.setSelectorBrushType("off") def delete_roi(self, roi_num): """ Deletes an roi Parameters ---------- roi_num roi to delete starts at 1 Returns ------- """ if (self.main_widget.checkThreadRunning()): if roi_num is None or roi_num < 1: self.main_widget.console.updateText("Invalid ROI Selected") print("Invalid ROI Selected") return roi_num = roi_num - 1 try: self.main_widget.console.updateText("Deleting ROI #%s" % str(roi_num + 1)) self.data_handler.rois.pop(roi_num) self.data_handler.gen_roi_display_variables() for x in self.data_handler.time_traces.keys(): self.data_handler.time_traces[x].pop(roi_num) self.data_handler.roi_time_trace_need_update.pop(roi_num) self.update_roi(False) self.roi_list_module.set_list_items(self.data_handler.rois) self.deselectRoiTime() self.main_widget.tabs[2].updateTab() except IndexError: self.main_widget.console.updateText("Invalid ROI Selected") print("Invalid ROI Selected") def modify_roi(self, roi_num, add_subtract="add", override=False): """ Add/subtracts the currently selected pixels from an ROI Parameters ---------- roi_num roi to modify starting at 1 add_subtract either add or subtract depending on operation wanted Returns ------- Nothing """ if (self.main_widget.checkThreadRunning()): if roi_num is None or roi_num < 1: print("Please select an roi") self.main_widget.console.updateText("Please Select an ROI") return False roi_num = roi_num - 1 if len(self.image_view.current_selected_pixels_list) == 0: print("Please select some pixels") self.main_widget.console.updateText( "Please select some pixels") return False if add_subtract == "add": print("Adding Selection to ROI #" + str(roi_num + 1)) temp_roi = combine_rois( self.data_handler.rois[roi_num], self.image_view.current_selected_pixels_list) num = number_connected_components( self.data_handler.shape[0] * self.data_handler.shape[1], [0] + self.data_handler.shape, temp_roi) if num == 2 or override: self.data_handler.rois[roi_num] = temp_roi self.data_handler.gen_roi_display_variables() self.data_handler.roi_time_trace_need_update[ roi_num] = True else: msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setStyleSheet(qdarkstyle.load_stylesheet()) msg.setText( "The pixels you selected are not connect to ROI #%s, Are you sure you want to add them?" % str(roi_num + 1)) # msg.setInformativeText("This is additional information") # msg.setWindowTitle("MessageBox demo") # msg.setDetailedText("The details are as follows:") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) retval = msg.exec_() if retval == 1024: self.data_handler.rois[roi_num] = temp_roi self.data_handler.gen_roi_display_variables() self.data_handler.roi_time_trace_need_update[ roi_num] = True else: return False if add_subtract == "subtract": print("Subtracting Selection from ROI #" + str(roi_num + 1)) self.data_handler.rois[roi_num] = [ x for x in self.data_handler.rois[roi_num] if x not in self.image_view.current_selected_pixels_list ] self.data_handler.gen_roi_display_variables() self.data_handler.roi_time_trace_need_update[roi_num] = True self.deselectRoiTime() self.roi_list_module.set_current_select(roi_num + 1) self.image_view.clearPixelSelection() self.image_view.setSelectorBrushType("off") self.update_roi(new=False) self.main_widget.tabs[2].updateTab() if add_subtract == "subtract": self.main_widget.console.updateText( "Subtracting Selection from ROI #" + str(roi_num + 1)) if add_subtract == "add": self.main_widget.console.updateText( "Adding Selection to ROI #" + str(roi_num + 1)) self.off_button.setChecked(True) self.main_widget.console.updateText( "Some time traces are out of date, please recalculate", warning=True) return True def update_roi(self, new=True): """Resets the roi image display""" if (self.main_widget.checkThreadRunning()): self.image_view.reset_view(new=new) def selectRoiTime(self, num): if (self.main_widget.checkThreadRunning()): try: color_roi = self.main_widget.data_handler.color_list[ (num - 1) % len(self.main_widget.data_handler.color_list)] if (self.roi_list_module.roi_time_check_list[num - 1]): if self.data_handler.roi_time_trace_need_update[num - 1]: self.main_widget.console.updateText( "Some time traces are out of date, please recalculate", warning=True) pen = pg.mkPen(color=color_roi, width=3) time_trace = self.main_widget.data_handler.get_time_trace( num, trace_type=self.time_trace_type.current_state()) if type(time_trace) == bool: return self.time_plot.plot(time_trace, pen=pen) self.time_plot.enableAutoRange(axis=0) except AttributeError: pass def deselectRoiTime(self): if (self.main_widget.checkThreadRunning()): try: self.time_plot.clear() self.time_plot.enableAutoRange(axis=0) for num2, x in zip( range(1, len(self.roi_list_module.roi_time_check_list)), self.roi_list_module.roi_time_check_list): if x: if self.data_handler.roi_time_trace_need_update[num2 - 1]: self.main_widget.console.updateText( "Some time traces are out of date, please recalculate", warning=True) color_roi = self.main_widget.data_handler.color_list[ (num2 - 1) % len(self.main_widget.data_handler.color_list)] pen = pg.mkPen(color=color_roi, width=3) self.time_plot.plot( self.main_widget.data_handler.get_time_trace( num2, trace_type=self.time_trace_type.current_state( )), pen=pen) except AttributeError: print("No ROIs have been generated yet") def update_time_traces(self): def end_func(): if self.data_handler.real_trials: self.data_handler.update_selected_trials( self._time_trace_trial_select_list.selectedTrials()) self.deselectRoiTime() self.main_widget.tabs[2].updateTab() if self.main_widget.checkThreadRunning(): if any(self.data_handler.roi_time_trace_need_update): # self.data_handler.calculate_time_traces() self.time_trace_thread.runThread(end_func) else: self.main_widget.console.updateText("No update necessary") def view_eigen_vector(self): vector_num = self.eigen_view_number_input.current_state() trial_num = self.eigen_view_trial_input.current_state() box_num = self.eigen_view_box_input.current_state() try: vector = self.data_handler.get_eigen_vector(box_num, trial_num=trial_num, vector_num=vector_num) self.image_view.image_item.image = vector self.image_view.image_item.updateImage(autoLevels=True) except FileNotFoundError: print("Invalid location") def updateTab(self): if (self.main_widget.checkThreadRunning()): self._time_trace_trial_select_list.set_items_from_list( self.data_handler.trials_all, self.data_handler.trials_loaded_time_trace_indices) if self.data_handler.rois_loaded: self.roi_list_module.set_list_items( self.main_widget.data_handler.rois) self.image_view.reset_view()
class ROIImageViewModule(ImageViewModule): # QApplication.mouseButtons() == Qt.LeftButton def __init__(self, main_widget, tab, settings_tab=True): super(ROIImageViewModule, self).__init__(main_widget, histogram=False) self.tab = tab self.resetting_view = False # Way to prevent infinite loops of reset_view self.current_foreground_intensity = 30 self.click_event = False self.outlines = True self.trial_selector_input = OptionInput( "Time Block:", "", lambda x, y: self.set_background("", self.current_background_name), val_list=self.data_handler.trials_loaded, tool_tip="Select Time block to display", display_tool_tip=False, default_index=0, show_name=True) self.set_background("", "Max Image", update_image=False) self.image_item.mouseClickEvent = lambda x: self.roi_view_click(x) self.image_item.mouseDragEvent = lambda x: self.roi_view_drag(x) shape = main_widget.data_handler.shape self.select_image_flat = np.zeros([shape[0] * shape[1], 3]) self.box_selector_enabled = False self.box_selector_cords = [(0, 0), (0, 0)] self.current_background_name = "Max Image" if settings_tab: self.layout.removeWidget(self.image_view) self.layout.addWidget(self.createTabLayout()) def createSettings(self): self.display_settings_layout = QVBoxLayout() display_settings = QWidget() display_settings.setLayout(self.display_settings_layout) image_chooser = OptionInput("ROI Display type:", "", on_change_function=self.set_image, default_index=0, tool_tip="Choose background to display", val_list=["Outlines", "Blob", "Neuropil"]) self.display_settings_layout.addWidget(image_chooser) self.background_chooser = OptionInput( "Background:", "", on_change_function=self.set_background, default_index=2, tool_tip="Choose background to display", val_list=[ "Blank Image", "Mean Image", "Max Image", # "Temporal Correlation Image", "Eigen Norm Image" ]) self.display_settings_layout.addWidget(self.background_chooser) self.display_settings_layout.addWidget(self.trial_selector_input) background_slider_layout = QHBoxLayout() label_0 = QLabel("0") label_0.setStyleSheet("QWidget {border: 0px solid #32414B;}") background_slider_layout.addWidget(label_0) # initializes a slider to control how much to blend background image in when # blob is view is enabled self.background_slider = QSlider(Qt.Horizontal) self.background_slider.setStyleSheet( "QWidget {border: 0px solid #32414B;}") self.background_slider.setMinimum(0) self.background_slider.setMaximum(100) self.background_slider.setSingleStep(1) self.background_slider.valueChanged.connect( self.intensitySliderChanged) try: self.background_slider.setValue(self.current_foreground_intensity) except AttributeError: pass background_slider_layout.addWidget(self.background_slider) label_10 = QLabel("10") label_10.setStyleSheet("QWidget {border: 0px solid #32414B;}") background_slider_layout.addWidget(label_10) label_overlay = QLabel("Change background intensity:") label_overlay.setStyleSheet("QWidget {border: 0px solid #32414B;}") self.display_settings_layout.addWidget(label_overlay) self.display_settings_layout.addLayout(background_slider_layout) return display_settings def createTabLayout(self): # ROI view tab section roi_view_tabs = QTabWidget() roi_view_tabs.setStyleSheet("QTabWidget {font-size: 20px;}") # Display settings tab display_settings = self.createSettings() # ROI image view part self.setStyleSheet("margin:0px; border:0px solid rgb(50, 65, " "75); padding: 0px;") roi_view_widget = QWidget() roi_view_widget_layout = QVBoxLayout() roi_view_widget_layout.setContentsMargins(0, 0, 0, 0) roi_view_widget_layout.addWidget(self.image_view) roi_view_widget.setLayout(roi_view_widget_layout) roi_view_tabs.addTab(roi_view_widget, "ROI Display") roi_view_tabs.addTab(display_settings, "Display Settings") return roi_view_tabs def settingsLayout(self): return self.display_settings_layout def intensitySliderChanged(self): self.current_foreground_intensity = ( float(self.background_slider.value()) / 10) self.updateImageDisplay() def set_background(self, name, func_name, update_image=True, reset_override=False): if (not self.resetting_view or reset_override): self.main_widget.console.updateText( "Setting current background to: %s" % func_name) # Background refers to the image behind the rois shape = self.main_widget.data_handler.shape if func_name == "Mean Image": self.current_background = \ self.main_widget.data_handler.mean_images[ self.data_handler.trials_loaded.index( self.trial_selector_input.current_state())][:].reshape( [-1, 1]) self.current_background_name = "Mean Image" elif func_name == "Max Image": self.current_background = self.main_widget.data_handler.max_images[ self.data_handler.trials_loaded.index( self.trial_selector_input.current_state())][:].reshape( [-1, 1]) self.current_background_name = "Max Image" elif func_name == "Blank Image": self.current_background = np.zeros([shape[0] * shape[1], 1]) self.current_background_name = "Blank Image" # if func_name == "Temporal Correlation Image": # self.current_background = self.data_handler.temporal_correlation_image.reshape( # [-1, 1]) elif func_name == "Eigen Norm Image": try: self.current_background = self.data_handler.eigen_norm_image.reshape( [-1, 1]) self.current_background_name = "Eigen Norm Image" except AttributeError: print("Eigen vectors aren't currently generated or valid") self.current_background = self.main_widget.data_handler.max_images[ self.data_handler.trials_loaded.index( self.trial_selector_input.current_state( ))][:].reshape([-1, 1]) if update_image: self.updateImageDisplay() self.main_widget.console.updateText( "Can't display Eigen Norm image, Eigen vectors aren't currently generated or valid" ) self.current_background_name = "Max Image" return else: self.current_background_name = "Max Image" try: self.trial_selector_input.set_default_val() self.current_background = self.main_widget.data_handler.max_images[ self.data_handler.trials_loaded.index( self.trial_selector_input.current_state( ))][:].reshape([-1, 1]) except AttributeError: pass try: if self.current_background_name != self.background_chooser.current_state( ): # pass self.background_chooser.set_val( self.current_background_name) except AttributeError: pass if update_image: self.updateImageDisplay() def set_image(self, name, func_name, update_image=True): if (self.main_widget.checkThreadRunning() and self.data_handler.rois_loaded): # Background refers to the image behind the rois shape = self.main_widget.data_handler.edge_roi_image_flat.shape if func_name == "Outlines": self.outlines = True self.roi_image_flat = np.hstack([ self.data_handler.edge_roi_image_flat, np.zeros(shape), np.zeros(shape) ]) if func_name == "Blob": self.outlines = False self.roi_image_flat = self.main_widget.data_handler.pixel_with_rois_color_flat if func_name == "Neuropil": self.outlines = False self.roi_image_flat = self.main_widget.data_handler.neuropil_image_display if update_image: self.updateImageDisplay() def updateImageDisplay(self, new=False): try: # new is to determine whether the zoom should be saved # TODO add in update with image paint layer shape = self.main_widget.data_handler.shape # range_list = self.main_widget.roi_image_view.image_view.view.viewRange() background_max = np.percentile(self.current_background, 98) background_min = np.percentile(self.current_background, 2) background_image_scaled = ( self.current_foreground_intensity / 7 * (self.current_background - background_min) * 255 / ((background_max - background_min) if (background_max - background_min) != 0 else 1)) background_image_scaled_3_channel = np.hstack([ background_image_scaled, background_image_scaled, background_image_scaled ]) if new and not hasattr(self.main_widget.data_handler, "edge_roi_image_flat"): self.image_item.image = background_image_scaled_3_channel.reshape( (shape[0], shape[1], 3)) self.image_item.updateImage(autoLevels=False) self.image_item.setLevels((0, 255)) elif new: # if self.add_image: combined = self.roi_image_flat * .45 + background_image_scaled_3_channel * .45 + self.select_image_flat * .45 # else: # combined = background_image_scaled + self.select_image_flat # mask = np.any(self.roi_image_flat != [0, 0, 0], axis=1) # combined[mask] = self.roi_image_flat[mask] combined_reshaped = combined.reshape((shape[0], shape[1], 3)) self.image_item.setLevels((0, 255)) self.tab.image_view.setImage(combined_reshaped) else: self.image_item.image = background_image_scaled_3_channel.reshape( (shape[0], shape[1], 3)) * .45 self.image_item.updateImage(autoLevels=False) self.image_item.setLevels((0, 255)) # if self.add_image: combined = (self.roi_image_flat * .45 + self.select_image_flat * .45).reshape( (shape[0], shape[1], 3)) self.image_item.image += combined self.image_item.updateImage(autoLevels=False) # self.main_widget.roi_image_view.image_view.view.setRange(xRange=range_list[0], # yRange=range_list[1]) # range_list = self.main_widget.roi_image_view.image_view.view.viewRange() # print(range_list) pass except AttributeError as e: logger1.error(e) except ValueError as e: if "shape" in e.args[0]: self.reset_view() def selectRoi(self, num): try: color_select = (245, 249, 22) if self.outlines else (255, 255, 255) color_roi = self.main_widget.data_handler.color_list[ (num - 1) % len(self.main_widget.data_handler.color_list)] self.select_image_flat[self.main_widget.data_handler.rois[ num - 1]] = color_select self.updateImageDisplay() except AttributeError: pass except IndexError: self.main_widget.console.updateText( "Please regenerate ROIs before trying this operation") print("Please regenerate ROIs before trying this operation") except ValueError as e: if "shape" in e.args[0]: self.main_widget.console.updateText("Error please try again") print("Error please try again") self.reset_view() def deselectRoi(self, num): try: color = self.main_widget.data_handler.color_list[(num - 1) % len( self.main_widget.data_handler.color_list)] shape_flat = self.data_handler.edge_roi_image_flat.shape self.select_image_flat[self.main_widget.data_handler.rois[num - 1]] = (0, 0, 0) self.updateImageDisplay() except ValueError as e: if "shape" in e.args[0]: self.main_widget.console.updateText("Error please try again") print("Error please try again") self.reset_view() def zoomRoi(self, num): """ Zooms in to a certain roi Parameters ---------- num : int roi num starts at 1 Returns ------- Nothing """ num = num - 1 max_cord = self.main_widget.data_handler.roi_max_cord_list[num] + 15 min_cord = self.main_widget.data_handler.roi_min_cord_list[num] - 15 self.image_view.getView().setYRange(min_cord[1], max_cord[1]) self.image_view.getView().setXRange(min_cord[0], max_cord[0]) def roi_view_click(self, event): if event.button() == QtCore.Qt.RightButton: if self.image_item.raiseContextMenu(event): event.accept() if hasattr( self.main_widget.data_handler, "pixel_with_rois_flat" ) and self.main_widget.data_handler.pixel_with_rois_flat is not None: pos = event.pos() y = int(pos.x()) x = int(pos.y()) self.click_event = True pixel_with_rois_flat = self.main_widget.data_handler.pixel_with_rois_flat shape = self.main_widget.data_handler.shape roi_num = int(pixel_with_rois_flat[shape[1] * x + y]) # TODO change to int if roi_num != 0: event.accept() self.tab.roi_list_module.set_current_select(roi_num) def roi_view_drag(self, event): prev = True pos = event.pos() y = int(pos.x()) # Because of column order thing in image_view x = int(pos.y()) modifiers = QApplication.keyboardModifiers() if modifiers == QtCore.Qt.ShiftModifier and not self.box_selector_enabled: self.box_selector_enabled = True self.box_selector_cords = [(x, y), (x, y)] prev = False if self.box_selector_enabled: event.accept() if prev: try: if (self.box_selector_cords[0][0] < self.box_selector_cords[1][0]): self.image_item.image[ self.box_selector_cords[0][0]:self. box_selector_cords[1][0], self.box_selector_cords[0][1]] -= [255, 255, 255] self.image_item.image[ self.box_selector_cords[0][0]:self. box_selector_cords[1][0], self.box_selector_cords[1][1]] -= [255, 255, 255] else: self.image_item.image[ self.box_selector_cords[1][0]:self. box_selector_cords[0][0], self.box_selector_cords[0][1]] -= [255, 255, 255] self.image_item.image[ self.box_selector_cords[1][0]:self. box_selector_cords[0][0], self.box_selector_cords[1][1]] -= [255, 255, 255] if self.box_selector_cords[0][1] < self.box_selector_cords[ 1][1]: self.image_item.image[self.box_selector_cords[0][0], self.box_selector_cords[0][1]:self.box_selector_cords[1][1]] -= \ [255, 255, 255] self.image_item.image[self.box_selector_cords[1][0], self.box_selector_cords[0][1]:self.box_selector_cords[1][1]] -= \ [255, 255, 255] else: self.image_item.image[self.box_selector_cords[0][0], self.box_selector_cords[1][1]:self.box_selector_cords[0][1]] -= \ [255, 255, 255] self.image_item.image[self.box_selector_cords[1][0], self.box_selector_cords[1][1]:self.box_selector_cords[0][1]] -= \ [255, 255, 255] except IndexError: pass if QApplication.mouseButtons() != Qt.LeftButton: self.box_selector_enabled = False shape = self.main_widget.data_handler.shape rois_image = np.reshape( self.main_widget.data_handler.pixel_with_rois_flat, shape) if (self.box_selector_cords[0][0] < self.box_selector_cords[1][0]): rois_image = rois_image[self.box_selector_cords[0][0]:self. box_selector_cords[1][0]] else: rois_image = rois_image[self.box_selector_cords[1][0]:self. box_selector_cords[0][0]] if self.box_selector_cords[0][1] < self.box_selector_cords[1][ 1]: rois_image = rois_image[:, self.box_selector_cords[0][1]:self. box_selector_cords[1][1]] else: rois_image = rois_image[:, self.box_selector_cords[1][1]:self. box_selector_cords[0][1]] rois_selected = np.unique(rois_image)[1:] self.tab.update_time = False for x in rois_selected: self.tab.roi_list_module.roi_item_list[ int(x) - 1].check_box.setChecked(True) self.tab.update_time = True self.tab.deselectRoiTime() self.box_selector_cords = [(0, 0), (0, 0)] else: self.box_selector_cords[1] = (x, y) try: if (self.box_selector_cords[0][0] < self.box_selector_cords[1][0]): self.image_item.image[ self.box_selector_cords[0][0]:self. box_selector_cords[1][0], self.box_selector_cords[0][1]] += [255, 255, 255] self.image_item.image[ self.box_selector_cords[0][0]:self. box_selector_cords[1][0], self.box_selector_cords[1][1]] += [255, 255, 255] else: self.image_item.image[ self.box_selector_cords[1][0]:self. box_selector_cords[0][0], self.box_selector_cords[0][1]] += [255, 255, 255] self.image_item.image[ self.box_selector_cords[1][0]:self. box_selector_cords[0][0], self.box_selector_cords[1][1]] += [255, 255, 255] if self.box_selector_cords[0][1] < self.box_selector_cords[ 1][1]: self.image_item.image[self.box_selector_cords[0][0], self.box_selector_cords[0][1]:self.box_selector_cords[1][1]] += \ [255, 255, 255] self.image_item.image[self.box_selector_cords[1][0], self.box_selector_cords[0][1]:self.box_selector_cords[1][1]] += \ [255, 255, 255] else: self.image_item.image[self.box_selector_cords[0][0], self.box_selector_cords[1][1]:self.box_selector_cords[0][1]] += \ [255, 255, 255] self.image_item.image[self.box_selector_cords[1][0], self.box_selector_cords[1][1]:self.box_selector_cords[0][1]] += \ [255, 255, 255] except IndexError: pass self.image_item.updateImage() def reset_view(self, updateDisplay=True): if not any([x.isRunning() for x in self.main_widget.thread_list ]) and not self.resetting_view: self.resetting_view = True if hasattr( self.main_widget.data_handler, "edge_roi_image_flat" ) and self.main_widget.data_handler.edge_roi_image_flat is not None: shape = self.main_widget.data_handler.edge_roi_image_flat.shape self.data_handler.save_rois(self.data_handler.rois) self.select_image_flat = np.zeros([shape[0] * shape[1], 3]) if self.outlines: self.roi_image_flat = np.hstack([ self.data_handler.edge_roi_image_flat, np.zeros(shape), np.zeros(shape) ]) else: self.roi_image_flat = self.main_widget.data_handler.pixel_with_rois_color_flat if len(self.trial_selector_input.val_list) != len( self.data_handler.trials_loaded) or any([ x != y for x, y in zip(self.trial_selector_input.val_list, self.data_handler.trials_loaded) ]): self.trial_selector_input.set_new_options( self.data_handler.trials_loaded) self.trial_selector_input.set_default_val() self.set_background("", self.current_background_name, update_image=False, reset_override=True) if (updateDisplay): self.updateImageDisplay(new=True) self.resetting_view = False def setImage(self, data): # if self.already_loaded == False: # print("changed image") # self.already_loaded = True # self.layout.removeWidget(self.no_image_message) # self.no_image_message.deleteLater() # # self.layout.setAlignment(Qt.AlignLeft) # self.image_view = ImageView() # # self.layout.addWidget(self.image_view) # bottom_5 = np.percentile(data, 5) # top_5 = np.percentile(data, 95) # top_10 = np.percentile(data, 90) # bottom_2 = np.percentile(data, 2) # top_2 = np.percentile(data, 98) # data[data>top_10] = top_10 self.image_view.setImage(data, levelMode='mono', autoRange=True, autoLevels=True, autoHistogramRange=True)
def __init__(self, main_widget): self.main_widget = main_widget self.cur_plot_type = "neuron" self.image_view = ROIImageViewModule(self.main_widget, self, settings_tab=False) self.roi_list_module = ROIListModule(main_widget.data_handler, self, select_multiple=True, display_time=False) self.thread = ROIExtractionThread(main_widget, QPushButton(), self.roi_list_module, self) self.main_widget.thread_list.append(self.thread) self.update_time = True settings_tabs = QTabWidget() plot_settings_widget = QWidget() plot_settings_layout = QVBoxLayout() plot_settings_widget.setLayout(plot_settings_layout) settings_tabs.addTab(plot_settings_widget, "Settings") self.plot_type_input = OptionInput( display_name="Plot Type", program_name="", on_change_function=lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="", display_tool_tip=False, val_list=["Color Mesh", "Line"]) plot_settings_layout.addWidget(self.plot_type_input) self.plot_by_input = OptionInput( display_name="Plot By", program_name="", on_change_function=lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="", display_tool_tip=False, val_list=["Neuron", "Trial"]) plot_settings_layout.addWidget(self.plot_by_input) self.time_trace_type = OptionInput( "Time Trace Type", "", lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="Select way to calculate time trace", val_list=list( self.data_handler.time_trace_possibilities_functions.keys())) plot_settings_layout.addWidget(self.time_trace_type) time_trace_settings = QWidget() time_trace_settings_layout = QVBoxLayout() if not len(self.data_handler.trials_loaded) == 1 and not \ self.data_handler.dataset_params["single_file_mode"] and not \ self.data_handler.dataset_params["trial_split"]: settings_tabs.addTab(time_trace_settings, "Trial Selector") else: plot_settings_layout.addWidget(time_trace_settings) time_trace_settings.hide() settings_tabs.addTab(self.image_view.createSettings(), "Display Settings") time_trace_settings_layout.setContentsMargins(0, 0, 0, 0) time_trace_settings.setLayout(time_trace_settings_layout) self._time_trace_trial_select_list = TrialListWidget(False) self._time_trace_trial_select_list.setMinimumHeight(115) self._time_trace_trial_select_list.set_items_from_list( self.data_handler.trials_all, self.data_handler.trials_loaded_time_trace_indices) time_trace_settings_layout.addWidget( self._time_trace_trial_select_list, stretch=5) time_trace_update_button = QPushButton("Update Time Traces") time_trace_settings_layout.addWidget(time_trace_update_button) time_trace_update_button.clicked.connect( lambda x: self.update_time_traces()) self.plot_widget = GraphDisplayWidget(self.main_widget) self.deselect_all_button = QPushButton("Deselect All") self.deselect_all_button.clicked.connect( lambda x: self.selectAll(False)) self.select_all_button = QPushButton("Select All") self.select_all_button.clicked.connect(lambda x: self.selectAll(True)) button_layout = QHBoxLayout() button_layout.addWidget(self.select_all_button) button_layout.addWidget(self.deselect_all_button) export_overlapping_rois = QPushButton(text="Export Overlapping ROIs") export_overlapping_rois.hide() export_overlapping_rois.clicked.connect( lambda: self.export_overlap_rois()) if self.main_widget.dev: export_overlapping_rois.show() # bottom_half.addWidget(self.plot_widget, stretch=2) if self.main_widget.data_handler.rois_loaded: self.updateTab() # self.plot_widget.set_list_items([self.data_handler.get_time_trace(x) for x in range(20)], [x for x in range(20)], None) super().__init__("Analysis", column_1=[ self.roi_list_module, button_layout, export_overlapping_rois, settings_tabs ], column_2=[self.image_view, self.plot_widget], column_2_display=True, column2_moveable=True)
class AnalysisTab(Tab): def __init__(self, main_widget): self.main_widget = main_widget self.cur_plot_type = "neuron" self.image_view = ROIImageViewModule(self.main_widget, self, settings_tab=False) self.roi_list_module = ROIListModule(main_widget.data_handler, self, select_multiple=True, display_time=False) self.thread = ROIExtractionThread(main_widget, QPushButton(), self.roi_list_module, self) self.main_widget.thread_list.append(self.thread) self.update_time = True settings_tabs = QTabWidget() plot_settings_widget = QWidget() plot_settings_layout = QVBoxLayout() plot_settings_widget.setLayout(plot_settings_layout) settings_tabs.addTab(plot_settings_widget, "Settings") self.plot_type_input = OptionInput( display_name="Plot Type", program_name="", on_change_function=lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="", display_tool_tip=False, val_list=["Color Mesh", "Line"]) plot_settings_layout.addWidget(self.plot_type_input) self.plot_by_input = OptionInput( display_name="Plot By", program_name="", on_change_function=lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="", display_tool_tip=False, val_list=["Neuron", "Trial"]) plot_settings_layout.addWidget(self.plot_by_input) self.time_trace_type = OptionInput( "Time Trace Type", "", lambda x, y: self.deselectRoiTime(), default_index=0, tool_tip="Select way to calculate time trace", val_list=list( self.data_handler.time_trace_possibilities_functions.keys())) plot_settings_layout.addWidget(self.time_trace_type) time_trace_settings = QWidget() time_trace_settings_layout = QVBoxLayout() if not len(self.data_handler.trials_loaded) == 1 and not \ self.data_handler.dataset_params["single_file_mode"] and not \ self.data_handler.dataset_params["trial_split"]: settings_tabs.addTab(time_trace_settings, "Trial Selector") else: plot_settings_layout.addWidget(time_trace_settings) time_trace_settings.hide() settings_tabs.addTab(self.image_view.createSettings(), "Display Settings") time_trace_settings_layout.setContentsMargins(0, 0, 0, 0) time_trace_settings.setLayout(time_trace_settings_layout) self._time_trace_trial_select_list = TrialListWidget(False) self._time_trace_trial_select_list.setMinimumHeight(115) self._time_trace_trial_select_list.set_items_from_list( self.data_handler.trials_all, self.data_handler.trials_loaded_time_trace_indices) time_trace_settings_layout.addWidget( self._time_trace_trial_select_list, stretch=5) time_trace_update_button = QPushButton("Update Time Traces") time_trace_settings_layout.addWidget(time_trace_update_button) time_trace_update_button.clicked.connect( lambda x: self.update_time_traces()) self.plot_widget = GraphDisplayWidget(self.main_widget) self.deselect_all_button = QPushButton("Deselect All") self.deselect_all_button.clicked.connect( lambda x: self.selectAll(False)) self.select_all_button = QPushButton("Select All") self.select_all_button.clicked.connect(lambda x: self.selectAll(True)) button_layout = QHBoxLayout() button_layout.addWidget(self.select_all_button) button_layout.addWidget(self.deselect_all_button) export_overlapping_rois = QPushButton(text="Export Overlapping ROIs") export_overlapping_rois.hide() export_overlapping_rois.clicked.connect( lambda: self.export_overlap_rois()) if self.main_widget.dev: export_overlapping_rois.show() # bottom_half.addWidget(self.plot_widget, stretch=2) if self.main_widget.data_handler.rois_loaded: self.updateTab() # self.plot_widget.set_list_items([self.data_handler.get_time_trace(x) for x in range(20)], [x for x in range(20)], None) super().__init__("Analysis", column_1=[ self.roi_list_module, button_layout, export_overlapping_rois, settings_tabs ], column_2=[self.image_view, self.plot_widget], column_2_display=True, column2_moveable=True) def selectAll(self, select): self.update_time = False for x in self.roi_list_module.roi_item_list: x.check_box.setChecked(select) self.update_time = True self.deselectRoiTime() def selectRoiTime(self, num): self.deselectRoiTime() def deselectRoiTime(self): if (self.main_widget.checkThreadRunning()): if any(self.data_handler.roi_time_trace_need_update): self.main_widget.console.updateText( "Some time traces are out of date, please recalculate", warning=True) if self.update_time: if self.plot_by_input.current_state() == "Neuron": if self.cur_plot_type != "neuron": self.cur_plot_type = "neuron" self.roi_list_module.select_multiple = True try: data_list = [] roi_names = [] for num2, x in zip( range( 1, len(self.roi_list_module. roi_time_check_list) + 1), self.roi_list_module.roi_time_check_list): if x: data_list.append( self.main_widget.data_handler. get_time_trace( num2, trace_type=self.time_trace_type. current_state())) roi_names.append(num2) self.plot_widget.set_list_items( data_list, roi_names, [], p_color=self.plot_type_input.current_state() == "Color Mesh", type="neuron") except AttributeError as e: print("No ROIs have been generated yet") else: if self.cur_plot_type != "trial": self.roi_list_module.select_multiple = False self.cur_plot_type = "trial" self.selectAll(False) try: print(self.roi_list_module.current_selected_roi) if self.roi_list_module.current_selected_roi is not None: roi = self.roi_list_module.current_selected_roi data_list = [] roi_names = [roi] for x in self.data_handler.trials_loaded_time_trace_indices: data_list.append( self.main_widget.data_handler. get_time_trace(roi, x)) self.plot_widget.set_list_items( data_list, roi_names, self.data_handler. trials_loaded_time_trace_indices, p_color=self.plot_type_input.current_state() == "Color Mesh", type="trial") else: self.plot_widget.set_list_items( [], [], [], p_color=self.plot_type_input.current_state() == "Color Mesh", type="trial") except AttributeError: print("No ROIs have been generated yet") @property def data_handler(self): return self.main_widget.data_handler def update_time_traces(self): if (self.main_widget.checkThreadRunning()): self.data_handler.calculate_time_traces() self.data_handler.update_selected_trials( self._time_trace_trial_select_list.selectedTrials()) self.deselectRoiTime() def updateTab(self): if (self.main_widget.checkThreadRunning()): self._time_trace_trial_select_list.set_items_from_list( self.data_handler.trials_all, self.data_handler.trials_loaded_time_trace_indices) if self.data_handler.rois_loaded: self.roi_list_module.set_list_items( self.main_widget.data_handler.rois) self.selectAll(False) self.image_view.reset_view() try: # self.update_time = False for x in self.roi_list_module.roi_item_list[:1]: x.check_box.setChecked(True) # self.deselectRoiTime() # self.update_time = True except: pass else: self.image_view.reset_view() def export_overlap_rois(self): roi_nums = [] for num, x in zip( range(1, len(self.roi_list_module.roi_time_check_list) + 1), self.roi_list_module.roi_time_check_list): if x: roi_nums.append(num) if len(roi_nums) == 2: self.data_handler.export_overlapping_rois(roi_nums[0], roi_nums[1]) print("export success")