class LoadImage(QtWidgets.QMainWindow, Ui_MainWindow): """Load board images from the menu and the pins icon list.""" def __init__(self): """Set up the user interference from the QT Designer. Initiate the menu bar and clicks on menu options. """ super().__init__() """Set up the user interference from QT Designer.""" self.setupUi(self) self.df_cls = None self.board_type = None self.board_label = None self.first_load = True self.first_resize = True self.resize_timer = None self.list_items = {} self.centralwidget.setDisabled(True) # Creating two menu options: Boards and Export self.file_menu = self.menuBar().addMenu('&File') self.boards_menu = self.menuBar().addMenu('&Boards') # self.export_menu = self.menuBar().addMenu('&Export') self.refresh_menus() self.export_action = self.file_menu.addAction('Save Board Label') self.run_macro_action = self.file_menu.addAction('Run the Macro File') self.exit_action = self.file_menu.addAction('Exit') self.exit_action.triggered.connect(QtWidgets.qApp.quit) # self.export_action = self.export_menu.addAction('Save Board Label') def refresh_menus(self): self.boards_menu.clear() unprocessed_menu = self.boards_menu.addMenu('Unprocessed') processed_menu = self.boards_menu.addMenu('Processed') config = ConfigParser() config.read('socketear.ini') file_path = os.path.normpath(config.get('path', 'dirpath')) # Going through the Board folder to create the appropriate actions for dirpath, dirnames, filenames in os.walk( os.path.join(file_path, 'Processed')): if 'pins' in dirnames and all( fn in filenames for fn in ['classification.csv', 'stitched.png', 'info.txt']): # Add actions for the right path action_cb = processed_menu.addAction( os.path.split(os.path.basename(dirpath))[-1]) action_cb.triggered.connect( functools.partial(self.load_image, dirpath)) for dirpath, dirnames, filenames in os.walk( os.path.join(file_path, 'Unprocessed')): if all(fn.endswith(".tif") for fn in filenames) and not dirnames: board_name = os.path.split(os.path.split(dirpath)[0])[1] save_path = os.path.join(file_path, 'Processed') action_nb = unprocessed_menu.addAction(board_name) action_nb.triggered.connect( functools.partial(self.load_model, dirpath, board_name, save_path)) def remove_board(self): """Remove the layer of matplotlib container and widgetlist. Also, disconnects all the buttons. """ self.mpl_vl.removeWidget(self.canvas) self.canvas.close() # self.mpl_vl.removeWidget(self.toolbar) # self.toolbar.close() self.mpl_figs.clear() self.mpl_figs.currentItemChanged.disconnect() self.nwo_button.disconnect() self.nco_button.disconnect() self.normal_button.disconnect() self.hnp_button.disconnect() self.sb_button.disconnect() self.type1_button.disconnect() self.type2_button.disconnect() self.type3_button.disconnect() self.type4_button.disconnect() self.reject_button.disconnect() # self.no_crack_button.disconnect() self.type_a_button.disconnect() self.type_b_button.disconnect() self.type_c_button.disconnect() self.type_d_button.disconnect() self.type_e_button.disconnect() self.refresh_sjr_button.disconnect() self.refresh_sjq_button.disconnect() self.sjr_image_button.disconnect() self.export_action.disconnect() self.export_action.setDisabled(True) def add_mpl(self): """Add a layer of matplotlib container.""" self.figure = Figure(figsize=(5, 4), dpi=100) self.canvas = FigureCanvas(self.figure) self.mpl_vl.addWidget(self.canvas) self.canvas.draw() # self.toolbar = NavigationToolbar(self.canvas, # self.mpl_window, # coordinates=True) # self.addToolBar(self.toolbar) def button_clicked(self, value): """Change the radio button. Updates the CSV file after a radio button was clicked. """ pin_index = self.mpl_figs.currentItem().data(32) if self.board_type == 'SJR': if isinstance(value, six.string_types): self.df_cls.set_value(pin_index, 'DYE Correction', value) elif isinstance(value, int): self.df_cls.set_value(pin_index, 'SJR Correction', value) elif self.board_type == 'SJQ': self.df_cls.set_value(pin_index, 'SJQ Correction', value) image_path = self.df_cls.loc[pin_index]['Image Path'] csv_path = os.path.split( os.path.split(os.path.normpath(image_path))[0])[0] # Saving the CSV file header = [ 'Row', 'Col', 'StitchedX', 'StitchedY', 'Pin', 'SJQ', 'SJR', 'DYE', 'SJQ Correction', 'SJR Correction', 'DYE Correction', 'Type Change', 'Sorted SJQ', 'Image Path', 'Label Coords', 'DYE Image Path' ] self.df_cls.to_csv(os.path.join(csv_path, 'classification.csv'), columns=header) def nwo_button_clicked(self, enabled): """Activate the nwo button for SJQ.""" if enabled: self.button_clicked(0) def nco_button_clicked(self, enabled): """Activate the nco button for SJQ.""" if enabled: self.button_clicked(1) def normal_button_clicked(self, enabled): """Activate the normal button for SJQ.""" if enabled: self.button_clicked(2) def hnp_button_clicked(self, enabled): """Activate the hnp button for SJQ.""" if enabled: self.button_clicked(3) def sb_button_clicked(self, enabled): """Activate the sb button for SJQ.""" if enabled: self.button_clicked(4) def type1_button_clicked(self, enabled): """Activate the type1 button for SJR.""" if enabled: self.button_clicked(0) def type2_button_clicked(self, enabled): """Activate the type2 button for SJR.""" if enabled: self.button_clicked(1) def type3_button_clicked(self, enabled): """Activate the normal button for SJR.""" if enabled: self.button_clicked(2) def type4_button_clicked(self, enabled): """Activate the type4 button for SJR.""" if enabled: self.button_clicked(3) def reject_button_clicked(self, enabled): """Activate the type4 button for SJR.""" if enabled: self.button_clicked(4) # def no_crack_button_clicked(self, enabled): # """Activate the no crack button for SJR.""" # if enabled: # self.button_clicked('O') def type_a_button_clicked(self, enabled): """Activate the typeA button for SJR.""" if enabled: self.button_clicked('A') def type_b_button_clicked(self, enabled): """Activate the typeB button for SJR.""" if enabled: self.button_clicked('B') def type_c_button_clicked(self, enabled): """Activate the typeC button for SJR.""" if enabled: self.button_clicked('C') def type_d_button_clicked(self, enabled): """Activate the typeD button for SJR.""" if enabled: self.button_clicked('D') def type_e_button_clicked(self, enabled): """Activate the typeE button for SJR.""" if enabled: self.button_clicked('E') def refresh(self, predictions, dye_predictions=None): # start_refresh = datetime.now() self.board_label = self.drawing_tool(shape=1000, pred=predictions, dyepred=dye_predictions) # print('remove scatters!') self.axes1_scatter.remove() self.axes2_scatter.remove() self.axes2_image = self.axes2.imshow(self.board_label) self.canvas.draw() self.background_board = self.canvas.copy_from_bbox(self.axes2.bbox) pin_index = self.mpl_figs.currentItem().data(32) self.load_pin_cls(pin_index) cx_image = self.df_cls.ix[pin_index, 'StitchedX'] cy_image = self.df_cls.ix[pin_index, 'StitchedY'] self.axes1_scatter = self.axes1.scatter(cy_image, cx_image, edgecolor='#ff01d0', marker='s', s=80, linewidth='2', facecolors='none') cx_label = self.df_cls.ix[pin_index, 'Label Coords'][0] * 1000 cy_label = self.df_cls.ix[pin_index, 'Label Coords'][1] * 1000 self.axes2_scatter = self.axes2.scatter(cy_label, cx_label, edgecolor='#ff01d0', marker='s', s=80, linewidth='2', facecolors='none') self.canvas.blit(self.axes1.bbox) self.canvas.blit(self.axes2.bbox) # print('timer canvas.draw: ', datetime.now() - start_refresh) # start_refresh = datetime.now() self.sort_classification() # print('timer sort_classification: ', datetime.now() - start_refresh) # start_refresh = datetime.now() self.pin_dividers() # print('timer pin_dividers: ', datetime.now() - start_refresh) self.mpl_figs.clear() # start_refresh = datetime.now() self.load_pins() # print('timer load_pins: ', datetime.now() - start_refresh) self.mpl_figs.setCurrentItem(self.mpl_figs.item(0)) board_pin_info = self.board_info + "\nPin name: {0}".format( str(self.df_cls.ix[pin_index, 'Pin'])) self.board_display_label.setText(board_pin_info) def refresh_sjq_clicked(self): """Redraw the label board for SJQ model.""" # start_refresh = datetime.now() print('Starting to refresh...') predictions = self.df_cls.set_index('Pin')['SJQ Correction'].to_dict() dye_predictions = None self.refresh(predictions, dye_predictions) # print('start_refresh: ', datetime.now() - start_refresh) def refresh_sjr_clicked(self): """Redraw the label board for SJQ model.""" # start_refresh = datetime.now() print('Starting to refresh...') predictions = self.df_cls.set_index('Pin')['SJR Correction'].to_dict() dye_predictions = self.df_cls.set_index( 'Pin')['DYE Correction'].to_dict() self.refresh(predictions, dye_predictions) # print('start_refresh: ', datetime.now() - start_refresh) def sjr_image_switch(self): """Switch the pin image and dyed pin image for SJR models.""" pin_index = self.mpl_figs.currentItem().data(32) if self.pin_dye_image == self.df_cls.loc[pin_index, 'Image Path']: self.pin_dye_image = self.df_cls.loc[pin_index, 'DYE Image Path'] self.pin_image.setPixmap( QtGui.QPixmap(QtGui.QImage(self.pin_dye_image))) elif self.pin_dye_image == self.df_cls.loc[pin_index, 'DYE Image Path']: self.pin_dye_image = self.df_cls.loc[pin_index, 'Image Path'] self.pin_image.setPixmap( QtGui.QPixmap(QtGui.QImage(self.pin_dye_image))) def on_click(self, event): if not event.inaxes: print('Clicked outside axes bounds but inside plot window') return if event.inaxes == self.axes1: self.df_cls['Image Coords'] = self.df_cls[[ 'StitchedX', 'StitchedY' ]].apply(tuple, axis=1) z = self.df_cls[['StitchedX', 'StitchedY']].values distance = np.linalg.norm( (z - np.array([event.ydata, event.xdata])), axis=1) row_index = np.argmin(distance) current_item = None for index in range(self.mpl_figs.count()): item = self.mpl_figs.item(index) if item.data(32) == row_index: current_item = item if current_item: self.mpl_figs.setCurrentItem(current_item) pin_index = current_item.data(32) self.load_pin_cls(pin_index) else: print('No item found for row {}'.format(row_index)) if event.inaxes == self.axes2: z = np.zeros(shape=(len(self.guide.pins), 2)) for j, pin in enumerate(self.guide.pins): z[j] = 1000 * np.array(self.guide.position(pin)) distance = np.linalg.norm( (z - np.array([event.ydata, event.xdata])), axis=1) k = np.argmin(distance) pin_name = self.guide.pins[k] row = self.df_cls.Pin[self.df_cls.Pin == pin_name].index.tolist()[0] current_item = None for index in range(self.mpl_figs.count()): item = self.mpl_figs.item(index) if item.data(32) == row: current_item = item if current_item: self.mpl_figs.setCurrentItem(current_item) pin_index = current_item.data(32) self.load_pin_cls(pin_index) else: print('No item found for row {}'.format(row)) def current_item_changed(self): """Update the zoom-in pin image and the board image position. Based on the items in the scrollable list(WidgetListItem). """ if self.mpl_figs.currentItem(): pin_index = self.mpl_figs.currentItem().data(32) self.load_pin_cls(pin_index) cx_label = self.df_cls.ix[pin_index, 'Label Coords'][0] * 1000 cy_label = self.df_cls.ix[pin_index, 'Label Coords'][1] * 1000 try: self.axes2_scatter.remove() except: pass self.axes2_scatter = self.axes2.scatter(cy_label, cx_label, edgecolor='#ff01d0', marker='s', s=80, linewidth='2', facecolors='none') cx_image = self.df_cls.ix[pin_index, 'StitchedX'] cy_image = self.df_cls.ix[pin_index, 'StitchedY'] try: self.axes1_scatter.remove() except: pass self.axes1_scatter = self.axes1.scatter(cy_image, cx_image, edgecolor='#ff01d0', marker='s', s=80, linewidth='2', facecolors='none') start_canvas = datetime.now() self.canvas.restore_region(self.background_image) self.canvas.restore_region(self.background_board) self.axes1.draw_artist(self.axes1_scatter) self.axes2.draw_artist(self.axes2_scatter) self.canvas.blit(self.axes1.bbox) self.canvas.blit(self.axes2.bbox) self.canvas.flush_events() # print('canvas: ', datetime.now() - start_canvas) board_pin_info = self.board_info + "\nPin name: {0}".format( str(self.df_cls.ix[pin_index, 'Pin'])) self.board_display_label.setText(board_pin_info) def load_pin_cls(self, pin_index): """Load the zoom-in pin image. And activate the appropriate radio button. """ self.pin_dye_image = self.df_cls.ix[pin_index, 'Image Path'] self.pin_image.setScaledContents(True) self.pin_image.setPixmap( QtGui.QPixmap(QtGui.QImage(self.pin_dye_image))) if self.board_type == 'SJR': classification = self.df_cls.ix[pin_index, 'SJR Correction'] dye_cls = self.df_cls.ix[pin_index, 'DYE Correction'] if classification == 0: self.type1_button.setChecked(True) elif classification == 1: self.type2_button.setChecked(True) elif classification == 2: self.type3_button.setChecked(True) elif classification == 3: self.type4_button.setChecked(True) elif classification == 4: self.reject_button.setChecked(True) # if dye_cls == 'O': # self.no_crack_button.setChecked(True) if dye_cls == 'A': self.type_a_button.setChecked(True) elif dye_cls == 'B': self.type_b_button.setChecked(True) elif dye_cls == 'C': self.type_c_button.setChecked(True) elif dye_cls == 'D': self.type_d_button.setChecked(True) elif dye_cls == 'E': self.type_e_button.setChecked(True) elif self.board_type == 'SJQ': classification = self.df_cls.ix[pin_index, 'SJQ Correction'] if classification == 0: self.nwo_button.setChecked(True) elif classification == 1: self.nco_button.setChecked(True) elif classification == 2: self.normal_button.setChecked(True) elif classification == 3: self.hnp_button.setChecked(True) elif classification == 4: self.sb_button.setChecked(True) def sort_sjq(self, row): if row['SJQ Correction'] == 0: value = 'a' elif row['SJQ Correction'] == 1: value = 'b' elif row['SJQ Correction'] == 2: value = 'e' elif row['SJQ Correction'] == 3: value = 'c' elif row['SJQ Correction'] == 4: value = 'd' else: raise ValueError('Unknown classification') return value def set_buttons(self, column_names): if all(cn in column_names for cn in ['SJR', 'SJQ', 'DYE']): if not(self.df_cls['SJR'].isnull().all()) and \ not(self.df_cls['DYE'].isnull().all()) and \ self.df_cls['SJQ'].isnull().all(): self.board_type = 'SJR' self.nwo_button.setDisabled(True) self.nco_button.setDisabled(True) self.normal_button.setDisabled(True) self.hnp_button.setDisabled(True) self.sb_button.setDisabled(True) self.refresh_sjq_button.setDisabled(True) self.type1_button.setDisabled(False) self.type2_button.setDisabled(False) self.type3_button.setDisabled(False) self.type4_button.setDisabled(False) self.reject_button.setDisabled(False) # self.no_crack_button.setDisabled(False) self.type_a_button.setDisabled(False) self.type_b_button.setDisabled(False) self.type_c_button.setDisabled(False) self.type_d_button.setDisabled(False) self.type_e_button.setDisabled(False) self.refresh_sjr_button.setDisabled(False) self.sjr_image_button.setDisabled(False) elif not(self.df_cls['SJR'].isnull().all()) and \ not(self.df_cls['SJQ'].isnull().all()) and \ self.df_cls['DYE'].isnull().all(): self.board_type = 'SJQ' self.nwo_button.setDisabled(False) self.nco_button.setDisabled(False) self.normal_button.setDisabled(False) self.hnp_button.setDisabled(False) self.sb_button.setDisabled(False) self.refresh_sjq_button.setDisabled(False) self.type1_button.setDisabled(True) self.type2_button.setDisabled(True) self.type3_button.setDisabled(True) self.type4_button.setDisabled(True) self.reject_button.setDisabled(True) # self.no_crack_button.setDisabled(True) self.type_a_button.setDisabled(True) self.type_b_button.setDisabled(True) self.type_c_button.setDisabled(True) self.type_d_button.setDisabled(True) self.type_e_button.setDisabled(True) self.refresh_sjr_button.setDisabled(True) self.sjr_image_button.setDisabled(True) else: raise ValueError('Incomplete CSV file') else: raise ValueError('Unknown board') def sort_classification(self): if self.board_type == 'SJQ': self.df_cls['Sorted SJQ'] = self.df_cls['SJQ Correction'] self.df_cls['Sorted SJQ'] = self.df_cls.apply(self.sort_sjq, axis=1) self.df_cls = self.df_cls.sort_values( by=['Sorted SJQ', 'SJR Correction'], ascending=[True, True]) self.df_cls = self.df_cls.reset_index(drop=True) if self.board_type == 'SJR': self.df_cls = self.df_cls.sort_values( by=['SJR Correction', 'DYE Correction'], ascending=[True, False]) self.df_cls = self.df_cls.reset_index(drop=True) def pin_dividers(self): # Create columns to indicate the divider location for the QListWidgetItem if self.board_type == 'SJQ': self.df_cls['Type Change'] = self.df_cls['SJQ Correction'].shift( -1) != self.df_cls['SJQ Correction'] if self.df_cls.ix[0, 'SJQ Correction'] != self.df_cls.ix[ 1, 'SJQ Correction']: self.df_cls.ix[0, 'Type Change'] = True else: self.df_cls.ix[0, 'Type Change'] = False elif self.board_type == 'SJR': self.df_cls['Type Change'] = self.df_cls['SJR Correction'].shift( -1) != self.df_cls['SJR Correction'] if self.df_cls.ix[0, 'SJR Correction'] != self.df_cls.ix[ 1, 'SJR Correction']: self.df_cls.ix[0, 'Type Change'] = True else: self.df_cls.ix[0, 'Type Change'] = False def load_pins(self, first_load=False): if first_load: self.list_items = {} count_image_cat = 0 # Create a list of the 'Image Path' column image_path_values = self.df_cls['Image Path'].values.tolist() for image_path in self.df_cls['Image Path'].tolist(): if first_load: icon = QtGui.QIcon(image_path) else: icon = self.list_items[image_path] # Adding the pin images to the scrollable list (WidgetListItem) item = QtWidgets.QListWidgetItem() item.setIcon(icon) self.list_items[image_path] = icon index = image_path_values.index(image_path) item.setData(32, index) self.mpl_figs.addItem(item) count_image_cat += 1 if self.df_cls.iloc[index]['Type Change'] == True: mod_of_5 = count_image_cat % 5 if mod_of_5 != 0: amount_of_white = (5 - mod_of_5) + 5 else: amount_of_white = 5 for x in range(0, amount_of_white): item = QtWidgets.QListWidgetItem() # delimiter item.setData(32, -1) item.setFlags( QtCore.Qt.NoItemFlags) # item should not be selectable self.mpl_figs.addItem(item) count_image_cat = 0 def get_pins(self, root): """Load list of pin icons.""" # Reading the CSV file from the appropriate path self.df_cls = pd.read_csv(os.path.join(root, 'classification.csv')) if not ('SJQ Correction' in self.df_cls.columns): self.df_cls['SJQ Correction'] = self.df_cls['SJQ'].copy() if not ('SJR Correction' in self.df_cls.columns): self.df_cls['SJR Correction'] = self.df_cls['SJR'].copy() if not ('DYE Correction' in self.df_cls.columns): self.df_cls['DYE Correction'] = self.df_cls['DYE'].copy() # Adding the Pin column and adding the pin names to it by # combining the Col and Row Columns self.df_cls['Pin'] = self.df_cls[['Row', 'Col']].apply( lambda x: '{}{}{}'.format(x[0], '_', x[1]), axis=1) # Adding a label for the index column self.df_cls.columns.names = ['Index'] column_names = list(self.df_cls) self.set_buttons(column_names) self.sort_classification() df_pin_list = self.df_cls['Pin'].tolist() # Adding the path of the each pin image to the Dataframe # Create a column in the dataframe to store the image paths self.df_cls['Image Path'] = np.nan # Create a column in the dataframe to store the DYE image paths self.df_cls['DYE Image Path'] = np.nan # Matching the pins with the correct image and adding them to # the 'Image Path' column # for every file (image_path) in the pins folder: for f in os.listdir(os.path.join(root, 'pins')): if f.endswith("_1.tif"): image_path = os.path.join(os.getcwd(), os.path.join(root, 'pins'), f) pin_name = os.path.basename(image_path).replace("_1.tif", "") # finding the index of the row where the pin is located in # the dataframe if pin_name in df_pin_list: index = self.df_cls[self.df_cls['Pin'] == pin_name].index[0] # adding the pin's image path to the same row in the dataframe # where the pin is located self.df_cls.loc[index, 'Image Path'] = image_path if self.board_type == 'SJR': if 'dye' in os.listdir(os.path.join(root, '')): for f in os.listdir(os.path.join(root, 'dye')): dye_path = os.path.join(os.getcwd(), os.path.join(root, 'dye'), f) pin_name = os.path.basename(dye_path).replace("_1.tif", "") if pin_name in df_pin_list: index = self.df_cls[self.df_cls['Pin'] == pin_name].index[0] self.df_cls.loc[index, 'DYE Image Path'] = dye_path else: print('Unable to locate the DYE folder. Thus no dye images') self.sjr_image_button.setDisabled(True) self.pin_dividers() self.load_pins(first_load=True) def load_board(self, root): """Load the appropriate board based on the menu clicked.""" self.centralwidget.setDisabled(True) print('Path: ', root) board_name = os.path.basename(root) print('Board name: ', board_name) print('Board type: ', self.board_type) new_font = QtGui.QFont("Arial", 10, QtGui.QFont.Bold) self.board_display_label.setFont(new_font) self.board_info = "Board name: {0}\nBoard type: {1}".format( board_name, self.board_type) self.board_display_label.setText(self.board_info) with open(os.path.join(root, 'info.txt')) as json_file: data = json.load(json_file) print('guide path: ', data['guidePath']) csvpath = data['guidePath'] b2p_ratio = int(data['b2p_ratio']) from guides.generalguide import GeneralGuide self.guide = GeneralGuide(csvpath, b2p_ratio) pin_coords = [] for pin in self.df_cls['Pin'].tolist(): if pin in self.guide.pins: pin_coords.append(tuple(self.guide.position(pin))) self.df_cls['Label Coords'] = pd.Series(pin_coords, index=self.df_cls.index) self.drawing_tool = DrawPredictions(guide=self.guide, mode=self.board_type) cls_corrected_col = "{} Correction".format(self.board_type) # print('cls_corrected_col', cls_corrected_col) predictions = self.df_cls.set_index('Pin')[cls_corrected_col].to_dict() if self.board_type == 'SJR': dye_predictions = self.df_cls.set_index( 'Pin')['DYE Correction'].to_dict() self.board_label = self.drawing_tool(shape=1000, pred=predictions, dyepred=dye_predictions) elif self.board_type == 'SJQ': self.board_label = self.drawing_tool(shape=1000, pred=predictions) else: raise ValueError('Unknown board') self.board_img = mpimg.imread(os.path.join(root, 'stitched.png')) gs = gridspec.GridSpec(1, 2) gs.update(left=0.005, right=0.99, wspace=0.05) self.axes1 = self.figure.add_subplot(gs[0]) self.axes1.get_xaxis().set_visible(False) self.axes1.get_yaxis().set_visible(False) self.axes2 = self.figure.add_subplot(gs[1]) self.axes2.get_xaxis().set_visible(False) self.axes2.get_yaxis().set_visible(False) # print('init scatter') self.axes1_scatter = None self.axes2_scatter = None self.canvas.mpl_connect('resize_event', self.connect_resize) self.export_action.triggered.connect( functools.partial(self.save_board_label, root)) self.export_action.setDisabled(False) self.run_macro_action.triggered.connect( functools.partial(self.run_excel_macro, root)) self.first_load = False self.centralwidget.setDisabled(False) def connect_resize(self, event): print('resize event', event) self.centralwidget.setDisabled(True) self.perform_resize() # try: # print('resize event try', event) # self.resize_timer.cancel() # except: # pass # # self.resize_timer = Timer(1, self.perform_resize) # self.resize_timer.start() def perform_resize(self): # print('perform_resize') self.axes1.imshow(self.board_img) self.axes2.imshow(self.board_label) try: self.axes1_scatter.remove() except: print('Unable to remove axes1_scatter') pass try: self.axes2_scatter.remove() except: print('Unable to remove axes2_scatter') pass self.canvas.draw() self.background_image = self.canvas.copy_from_bbox(self.axes1.bbox) self.background_board = self.canvas.copy_from_bbox(self.axes2.bbox) self.centralwidget.setDisabled(False) def connect_click(self): """Just testing this.""" # connect the click or arrow keys press on the the scrollable # image list to the currentItemChanged self.mpl_figs.currentItemChanged.connect(self.current_item_changed) self.nwo_button.toggled.connect(self.nwo_button_clicked) self.nco_button.toggled.connect(self.nco_button_clicked) self.normal_button.toggled.connect(self.normal_button_clicked) self.hnp_button.toggled.connect(self.hnp_button_clicked) self.sb_button.toggled.connect(self.sb_button_clicked) self.type1_button.toggled.connect(self.type1_button_clicked) self.type2_button.toggled.connect(self.type2_button_clicked) self.type3_button.toggled.connect(self.type3_button_clicked) self.type4_button.toggled.connect(self.type4_button_clicked) self.reject_button.toggled.connect(self.reject_button_clicked) # self.no_crack_button.toggled.connect(self.no_crack_button_clicked) self.type_a_button.toggled.connect(self.type_a_button_clicked) self.type_b_button.toggled.connect(self.type_b_button_clicked) self.type_c_button.toggled.connect(self.type_c_button_clicked) self.type_d_button.toggled.connect(self.type_d_button_clicked) self.type_e_button.toggled.connect(self.type_e_button_clicked) self.refresh_sjq_button.clicked.connect(self.refresh_sjq_clicked) self.refresh_sjr_button.clicked.connect(self.refresh_sjr_clicked) self.sjr_image_button.clicked.connect(self.sjr_image_switch) self.canvas.callbacks.connect('button_press_event', self.on_click) def save_board_label(self, path): import cv2 cv2.imwrite(os.path.join(path, 'board.png'), 255 * self.board_label[:, :, ::-1]) def run_excel_macro(self, path): try: xlApp = win32com.client.Dispatch('Excel.Application') xlsPath = os.path.abspath(os.path.join(path, 'MacroTest.xlsm')) print(xlsPath) macroxl = xlApp.Workbooks.Open(xlsPath) xlApp.Run('MacroTest.xlsm!TEST_1') macroxl.Save() xlApp.Quit() print("Macro ran successfully!") except Exception as e: print("Error found while running the excel macro!") raise def load_image(self, root): """Construct the board image and load it on matplotlib container.""" # Rest the matplotlib container and the buttons print('Starting to load the images...') if not self.first_load: self.remove_board() # Add a matplotlib container self.add_mpl() # load pin images in the zoom-in container and # the scrollable image list self.get_pins(root) self.load_pin_cls(0) self.load_board(root) self.connect_click() def closeEvent(self, event): try: self.resize_timer.cancel() except: pass def load_model(self, root, board_name, save_path): default_settings = { 'sampleID': board_name, 'rawImgPath': root, 'cropSavePath': os.path.join(save_path, "{}", 'pins'), 'savePath': os.path.join(save_path, "{}"), 'additionalCrop': 'None', 'b2p_ratio': '150', 'device': 'gpu0' } dialog = Ui_SettingsWindow(default_settings) dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose) exit_code = dialog.exec_() # print(exit_code) if exit_code: # print(dialog.values) settings_dict = dialog.values userName = settings_dict['userName'] sampleID = settings_dict['sampleID'] analysisType = settings_dict['analysisType'] rawImgPath = settings_dict['rawImgPath'] cropSavePath = settings_dict['cropSavePath'] segDataPath = settings_dict['segDataPath'] savePath = settings_dict['savePath'] guidePath = settings_dict['guidePath'] additionalCrop = settings_dict['additionalCrop'] b2p_ratio = int(settings_dict['b2p_ratio']) device = settings_dict['device'] class TaskThread(QtCore.QThread): def run(self): print("task is running") try: from guides.generalguide import GeneralGuide guide = GeneralGuide(guidePath, b2p_ratio) from model import Model valid_additionalCrop = None if additionalCrop == 'None' else ( int(additionalCrop), int(additionalCrop)) f_model = Model(sampleID, analysisType, guide, valid_additionalCrop, rawImgPath, segDataPath, cropSavePath, savePath, device) from time import time st = time() print('Starting the analysis...') f_model(saveResults=True) sp = time() - st print('Analysis took {} seconds'.format(sp)) except Exception as e: print(e) task_thread = TaskThread() from progress_bar import ConstantProgressBar progress_dialog = ConstantProgressBar(task_thread) exit_code = progress_dialog.exec_() print(exit_code) json.dump(settings_dict, open(os.path.join(savePath, 'info.txt'), 'w'), indent=4) self.refresh_menus() self.load_image(savePath)
class MPLCanvas(QtWidgets.QGroupBox): """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.).""" @enum.unique class WindowTypes(enum.Enum): Rectangular = 0 Hann = 1 Flattop = 2 Tukey_5Percent = 3 windowFunctionMap = { WindowTypes.Rectangular: lambda M: windows.boxcar(M, sym=False), WindowTypes.Hann: lambda M: windows.hann(M, sym=False), WindowTypes.Flattop: lambda M: windows.flattop(M, sym=False), WindowTypes.Tukey_5Percent: lambda M: windows.tukey(M, sym=False, alpha=0.05), } dataIsPower = False dataSet = None prevDataSet = None _prevAxesLabels = None _axesLabels = None _prevDataLabel = None _dataLabel = None _lastPlotTime = 0 _isLiveData = False def __init__(self, parent=None): style_mpl() super().__init__(parent) dpi = QtWidgets.qApp.primaryScreen().logicalDotsPerInch() self.fig = Figure(dpi=dpi) self.fig.patch.set_alpha(0) self.axes = self.fig.add_subplot(2, 1, 1) self.ft_axes = self.fig.add_subplot(2, 1, 2) self.canvas = FigureCanvasQTAgg(self.fig) self.mpl_toolbar = NavigationToolbar2QT(self.canvas, self) self.mpl_toolbar.addSeparator() self.autoscaleAction = self.mpl_toolbar.addAction("Auto-scale") self.autoscaleAction.setCheckable(True) self.autoscaleAction.setChecked(True) self.autoscaleAction.triggered.connect(self._autoscale) self.mpl_toolbar.addWidget( QtWidgets.QLabel("Fourier transform " "window: ")) self.windowComboBox = QtWidgets.QComboBox(self.mpl_toolbar) for e in MPLCanvas.WindowTypes: self.windowComboBox.addItem(e.name, e) self.mpl_toolbar.addWidget(self.windowComboBox) self.windowComboBox.currentIndexChanged.connect(self._replot) vbox = QtWidgets.QVBoxLayout(self) vbox.addWidget(self.mpl_toolbar) vbox.addWidget(self.canvas) vbox.setContentsMargins(0, 0, 0, 0) vbox.setStretch(0, 1) vbox.setStretch(1, 1) self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.updateGeometry() self.fig.tight_layout() self._lines = self.axes.plot([], [], [], [], animated=True) self._lines[0].set_alpha(0.25) self._ftlines = self.ft_axes.plot([], [], [], [], animated=True) self._ftlines[0].set_alpha(0.25) self.axes.legend(['Previous', 'Current']) self.ft_axes.legend(['Previous', 'Current']) self.axes.set_title('Data') self.ft_axes.set_title('Fourier transformed data') self._redraw() # Use a timer with a timeout of 0 to initiate redrawing of the canvas. # This ensures that the eventloop has run once more and prevents # artifacts. self._redrawTimer = QtCore.QTimer(self) self._redrawTimer.setSingleShot(True) self._redrawTimer.setInterval(100) self._redrawTimer.timeout.connect(self._redraw) # will be disconnected in drawDataSet() when live data is detected. self._redraw_id = self.canvas.mpl_connect('draw_event', self._redraw_artists) def _redraw_artists(self, *args): if not self._isLiveData: self.axes.draw_artist(self._lines[0]) self.ft_axes.draw_artist(self._ftlines[0]) self.axes.draw_artist(self._lines[1]) self.ft_axes.draw_artist(self._ftlines[1]) def _redraw(self): self.fig.tight_layout() self.canvas.draw() self.backgrounds = [ self.fig.canvas.copy_from_bbox(ax.bbox) for ax in (self.axes, self.ft_axes) ] self._redraw_artists() def showEvent(self, e): super().showEvent(e) self._redrawTimer.start() def resizeEvent(self, e): super().resizeEvent(e) self._redrawTimer.start() def get_ft_data(self, data): delta = np.mean(np.diff(data.axes[0])) winFn = self.windowFunctionMap[self.windowComboBox.currentData()] refUnit = 1 * data.data.units Y = np.fft.rfft(np.array(data.data / refUnit) * winFn(len(data.data)), axis=0) freqs = np.fft.rfftfreq(len(data.axes[0]), delta) dBdata = 10 * np.log10(np.abs(Y)) if not self.dataIsPower: dBdata *= 2 data_slice = np.array(freqs) < 2.1 return (freqs[data_slice], dBdata[data_slice]) def _dataSetToLines(self, data, line, ftline): if data is None: line.set_data([], []) ftline.set_data([], []) return #data.data -= np.mean(data.data) line.set_data(data.axes[0], data.data) freqs, dBdata = self.get_ft_data(data) ftline.set_data(freqs, dBdata) def _autoscale(self, *, redraw=True): prev_xlim = self.axes.get_xlim() prev_ylim = self.axes.get_ylim() prev_ft_xlim = self.ft_axes.get_xlim() prev_ft_ylim = self.ft_axes.get_ylim() self.axes.relim() self.axes.autoscale() self.ft_axes.relim() self.ft_axes.autoscale() need_redraw = (prev_xlim != self.axes.get_xlim() or prev_ylim != self.axes.get_ylim() or prev_ft_xlim != self.ft_axes.get_xlim() or prev_ft_ylim != self.ft_axes.get_ylim()) if need_redraw and redraw: self._redraw() return need_redraw def _replot(self, redraw_axes=False, redraw_axes_labels=False, redraw_data_label=False): if not self._isLiveData: self._dataSetToLines(self.prevDataSet, self._lines[0], self._ftlines[0]) self._dataSetToLines(self.dataSet, self._lines[1], self._ftlines[1]) if self._axesLabels and redraw_axes_labels: self.axes.set_xlabel('{} [{:C~}]'.format( self._axesLabels[0], self.dataSet.axes[0].units)) self.ft_axes.set_xlabel('1 / {} [1 / {:C~}]'.format( self._axesLabels[0], self.dataSet.axes[0].units)) if self._dataLabel and redraw_data_label: self.axes.set_ylabel('{} [{:C~}]'.format(self._dataLabel, self.dataSet.data.units)) ftUnits = self.dataSet.data.units if not self.dataIsPower: ftUnits = ftUnits**2 self.ft_axes.set_ylabel('Power [dB-({:C~})]'.format(ftUnits)) axis_limits_changed = False if (self.autoscaleAction.isChecked()): axis_limits_changed = self._autoscale(redraw=False) # check whether a full redraw is necessary or if simply redrawing # the data lines is enough if (redraw_axes or redraw_axes_labels or redraw_data_label or axis_limits_changed): self._redraw() else: for bg in self.backgrounds: self.canvas.restore_region(bg) self._redraw_artists() self.canvas.blit(self.axes.bbox) self.canvas.blit(self.ft_axes.bbox) def drawDataSet(self, newDataSet, axes_labels, data_label): plotTime = time.perf_counter() looksLikeLiveData = plotTime - self._lastPlotTime < 1 if looksLikeLiveData != self._isLiveData: if looksLikeLiveData: self.canvas.mpl_disconnect(self._redraw_id) else: self._redraw_id = self.canvas.mpl_connect( 'draw_event', self._redraw_artists) self._isLiveData = looksLikeLiveData # artificially limit the replot rate to 5 Hz if (plotTime - self._lastPlotTime < 0.2): return self._lastPlotTime = plotTime self.prevDataSet = self.dataSet self.dataSet = newDataSet redraw_axes = (self.prevDataSet is None or len(self.prevDataSet.axes) != len(self.dataSet.axes)) if not redraw_axes: for x, y in zip(self.prevDataSet.axes, self.dataSet.axes): if x.units != y.units: redraw_axes = True break redraw_axes_labels = ( self._axesLabels != axes_labels or self.prevDataSet and self.dataSet and self.prevDataSet.axes[0].units != self.dataSet.axes[0].units) redraw_data_label = ( self._dataLabel != data_label or self.prevDataSet and self.dataSet and self.prevDataSet.data.units != self.dataSet.data.units) self._axesLabels = axes_labels self._dataLabel = data_label self._replot(redraw_axes, redraw_axes_labels, redraw_data_label)
class MainWidget(QWidget): def __init__(self): super(MainWidget, self).__init__() self.initUI() def initUI(self): self.resize(1100, 650) self.setWindowTitle("Stok Viewer") vbox = QVBoxLayout() self.setLayout(vbox) dailyBtn = QPushButton("Daily", self) weeklyBtn = QPushButton("Weeky", self) monthlyBtn = QPushButton("Monthly", self) dailyBtn.clicked.connect(lambda: self.plot("day")) weeklyBtn.clicked.connect(lambda: self.plot("week")) monthlyBtn.clicked.connect(lambda: self.plot("month")) timelineBtnBox = QHBoxLayout() timelineBtnBox.addStretch(1) timelineBtnBox.addWidget(dailyBtn) timelineBtnBox.addWidget(weeklyBtn) timelineBtnBox.addWidget(monthlyBtn) # widgets and layouts for plotting self.ybuffer = 5.5 # buffer area for bottom and top(%) self.zoomSpeed = 5 # How much area to zoom for one scroll self.figure = Figure() self.canvas = Canvas(self.figure) self.canvas.mpl_connect("button_press_event", self.onPressEvent) self.canvas.mpl_connect("button_release_event", self.onReleaseEvent) self.canvas.mpl_connect("scroll_event", self.onScrollEvent) self.chartBox = QHBoxLayout() self.chartBox.addWidget(self.canvas) vbox.addLayout(timelineBtnBox) vbox.addLayout(self.chartBox) self.plot("day") self.show() def plot(self, timeline=""): self.figure.clf() self.df = DataFetcher.getStockByTimeline("006400.KS", timeline) self.ax = self.figure.add_subplot() rsiList = getRsi(self.df) self.canvas.draw_idle() custplot(self.ax, self.df) ### 중복되는 기능, delete it later self.lineEndList = [] self.lineStartList = [] for obj in self.ax.get_children(): if type(obj) is type(matplotlib.collections.LineCollection([])): self.lineStartList.append( obj.get_paths()[0].get_extents().get_points()[0][1]) self.lineEndList.append( obj.get_paths()[0].get_extents().get_points()[1][1]) ### self.autoscale() def onPressEvent(self, event): # check if the pressed button was "LEFT" if not event.button == 1: return self.lineEndList = [] self.lineStartList = [] for obj in self.ax.get_children(): if type(obj) is type(matplotlib.collections.LineCollection([])): self.lineStartList.append( obj.get_paths()[0].get_extents().get_points()[0][1]) self.lineEndList.append( obj.get_paths()[0].get_extents().get_points()[1][1]) for obj in self.ax.get_children(): if type(obj) is type(matplotlib.patches.Rectangle): break #print(obj) self.xStart = self.ax.get_xlim()[0] self.xCursor = event.x self.cidDrag = self.canvas.mpl_connect("motion_notify_event", self.onDragEvent) def onDragEvent(self, event): xlim = self.ax.get_xlim() # make drag limits to prevent overflow ### # IMPLMENT PENDING ### movement = (event.x - self.xCursor) / 10 self.xCursor = event.x self.ax.set_xlim(xlim[0] - movement, xlim[1] - movement) self.autoscale() self.canvas.draw_idle() def onReleaseEvent(self, event): self.canvas.mpl_disconnect(self.cidDrag) # method for getting new range of axes and updating them to the df def updateAxes(self): # calculate how much x axis was moved xlim = self.ax.get_xlim() xEnd = -xlim[0] # get new df ogdate = self.df["Date"].iloc[0] newdf = DataFetcher.getStockByDate("006400.KS", ogdate, xEnd) newax = custplot(self.ax, newdf, timeline="day") # update the new df to the ax background = self.canvas.copy_from_bbox(self.ax.bbox) self.ax.draw_artist(newax) self.canvas.blit(self.ax.bbox) def onScrollEvent(self, event): xlim = self.ax.get_xlim() width = xlim[1] - xlim[0] if event.button == "up" or event.button == "down": if event.button == "up": xmin = xlim[0] + (width / 100 * self.zoomSpeed) xmax = xlim[1] - (width / 100 * self.zoomSpeed) else: xmin = xlim[0] - (width / 100 * self.zoomSpeed) xmax = xlim[1] + (width / 100 * self.zoomSpeed) self.ax.set_xlim(xmin, xmax) self.autoscale() self.canvas.draw_idle() else: print("error: unrecognized scroll movement") # method for autoscaling y axis heights according to y limits def autoscale(self): xlim = self.ax.get_xlim() ylim = self.ax.get_ylim() # check if updating lines are out of bound start = int(xlim[0]) if int(xlim[0]) > 0 else 0 end = int(xlim[1]) if int(xlim[1]) < len(self.df["High"]) else ( len(self.df["High"]) - 1) # get the highest and lowest point of y from start to end highest = max(self.lineEndList[start:end + 1]) lowest = min(self.lineStartList[start:end + 1]) height = highest - lowest self.ax.set_ylim(lowest - (height / 100 * self.ybuffer), highest + (height / 100 * self.ybuffer))
class twoDimage(QWidget): def __init__(self, viewer): super(twoDimage, self).__init__() self.data = Spectrum() self.viewer = viewer self.aspect = "auto" #init Image self.fig = Figure(figsize=(5, 3), dpi=150) gs = GridSpec(3, 3, figure=self.fig) self.ax_XDC = self.fig.add_subplot(gs[0, 0:2]) # X Distribution Curve self.ax_Spec = self.fig.add_subplot(gs[1:, 0:2]) # Spectrum self.ax_YDC = self.fig.add_subplot(gs[1:, -1]) # Y Distribution Curve self.lx1 = self.ax_Spec.axhline(self.ax_Spec.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75) # the horiz line 1 self.ly1 = self.ax_Spec.axvline(self.ax_Spec.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75) # the vert line 1 self.lx2 = self.ax_Spec.axhline(self.ax_Spec.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75) # the horiz line 2 self.ly2 = self.ax_Spec.axvline(self.ax_Spec.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75) # the vert line 2 self.vl = self.ax_XDC.axvline(self.ax_XDC.get_xbound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75) self.hl = self.ax_YDC.axhline(self.ax_YDC.get_ybound()[0], visible=False, animated=True, color='k', linestyle='--', linewidth=0.75) # the horiz line self.ax_cmap = self.fig.add_subplot(gs[0, 2]) # color bar self.gradient = np.vstack((np.linspace(0, 1, 256), np.linspace(0, 1, 256))) self.setTickLabelFont(self.ax_Spec, "Comic Sans MS") self.setTickLabelFont(self.ax_XDC, "Comic Sans MS") self.setTickLabelFont(self.ax_YDC, "Comic Sans MS") self.ax_Spec.set_axisbelow(False) self.ax_Spec.tick_params(direction='inout', labelsize=8.5) self.ax_XDC.tick_params(axis='x', labelsize=8.5, labelbottom=False) self.ax_XDC.tick_params(axis='y', which='both', left=False, labelleft=False) self.ax_YDC.tick_params(axis='x', which='both', bottom=False, labelbottom=False) self.ax_YDC.tick_params(axis='y', labelsize=8.5, labelleft=False) self.fig.subplots_adjust(top=0.96, bottom=0.08, left=0.1, right=0.96, wspace=0.15, hspace=0.15) x0, y0, width, height = self.ax_cmap.get_position().bounds nheight = height * 0.2 ny0 = y0 + height * 0.5 * (1 - 0.2) self.ax_cmap.set_position([x0, ny0, width, nheight]) self.ax_cmap.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False) self.ax_cmap.set_title("Color Scale", {'fontsize': 10}, fontname="Comic Sans Ms") self.fig.patch.set_facecolor("None") self.canvas = FigureCanvas(self.fig) self.canvas.setStyleSheet("background-color:transparent;") self.canvas.setFocusPolicy(Qt.ClickFocus) self.XDCLine = Line2D(np.array([0]), np.array([0]), color="blue", linewidth=1, animated=True, solid_joinstyle="round") self.YDCLine = Line2D(np.array([0]), np.array([0]), color="blue", linewidth=1, animated=True, solid_joinstyle="round") self.ax_XDC.add_line(self.XDCLine) self.ax_YDC.add_line(self.YDCLine) self.selector = Selector(self.ax_Spec, self.canvas) self.cid_press = self.canvas.mpl_connect('button_press_event', self.OnPress) self.cid_release = self.canvas.mpl_connect('button_release_event', self.OnRelease) self.cid_keypress = self.canvas.mpl_connect('key_press_event', self.OnKeyPress) #self.cid_scroll = self.canvas.mpl_connect('scroll_event', self.OnExpand) #contextMenu self.contextMenu = QMenu(self) self.CropAction = self.contextMenu.addAction("Crop") self.CropAction.setIcon(QIcon("./image/crop.ico")) self.CropAction.triggered.connect(self.crop) self.RestoreAction = self.contextMenu.addAction("Restore") self.RestoreAction.setIcon(QIcon("./image/restore.ico")) self.RestoreAction.triggered.connect( self.viewer.Win.DataProcessor.tab_single.RestoreData) self.SelectMenu = self.contextMenu.addMenu("Select") self.SelectMenu.setIcon(QIcon("./image/select.ico")) self.SelectX = self.SelectMenu.addAction("X Range") self.SelectX.triggered.connect(self.setSelectionRange) self.SelectY = self.SelectMenu.addAction("Y Range") self.SelectY.triggered.connect(self.setSelectionRange) self.SelectXY = self.SelectMenu.addAction("XY Area") self.SelectXY.triggered.connect(self.setSelectionRange) self.outputMenu = self.contextMenu.addMenu("Output") self.outputMenu.setIcon(QIcon("./image/output.ico")) self.XDC_action = self.outputMenu.addAction("XDC") self.YDC_action = self.outputMenu.addAction("YDC") #init Tool self.toolPanel = QGroupBox("Coordinate System") self.toolPanel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.toolPanel.setCheckable(True) self.toolPanel.setChecked(False) self.toolPanel.setStyle(QStyleFactory.create('Fusion')) self.toolPanel.toggled.connect(self.begincursor) self.X = QDoubleSpinBox() self.X.setFixedWidth(100) self.X.setDecimals(6) self.X.setRange(-1, 1) self.X.setSingleStep(0.01) self.X.setKeyboardTracking(False) self.X.setStyle(QStyleFactory.create('Fusion')) self.X.setValue(-1) self.X.valueChanged.connect(self.setValueFromSpinBox) self.XLabel = QLabel("X:") self.XLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.Y = QDoubleSpinBox() self.Y.setFixedWidth(100) self.Y.setDecimals(6) self.Y.setRange(-1, 1) self.Y.setSingleStep(0.01) self.Y.setKeyboardTracking(False) self.Y.setStyle(QStyleFactory.create('Fusion')) self.Y.setValue(-1) self.Y.valueChanged.connect(self.setValueFromSpinBox) self.YLabel = QLabel("Y:") self.YLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) font = QFont() font.setPointSize(12) font.setBold(True) self.IntLabel = QLabel("Count:") self.IntLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.Int = QLabel("0") self.Int.setFont(font) self.Int.setMinimumWidth(100) self.Int.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.Int.setStyleSheet("QLabel {background-color: white;}") self.Int.setFrameStyle(QFrame.Panel) self.XSlider = QSlider(Qt.Horizontal) self.XSlider.setRange(0, 10000) self.XSlider.setStyle(QStyleFactory.create('Fusion')) self.XSlider.sliderMoved.connect(self.setValueFromSlider) self.XSLabel = QLabel("X:") self.YSlider = QSlider(Qt.Horizontal) self.YSlider.setRange(0, 10000) self.YSlider.setStyle(QStyleFactory.create('Fusion')) self.YSlider.sliderMoved.connect(self.setValueFromSlider) self.YSLabel = QLabel("Y:") self.XSlice = QSpinBox() self.XSlice.setRange(1, 10000) self.XSlice.setSingleStep(2) self.XSlice.setKeyboardTracking(False) self.XSlice.setStyle(QStyleFactory.create('Fusion')) self.XSlice.valueChanged.connect(self.setSlice) self.XSliceLabel = QLabel("Slice:") self.YSlice = QSpinBox() self.YSlice.setRange(1, 10000) self.YSlice.setSingleStep(2) self.YSlice.setKeyboardTracking(False) self.YSlice.setStyle(QStyleFactory.create('Fusion')) self.YSlice.valueChanged.connect(self.setSlice) self.YSliceLabel = QLabel("Slice:") hbox_tool = QHBoxLayout() hbox_tool.addStretch(2) hbox_tool.addWidget(self.XLabel) hbox_tool.addWidget(self.X) hbox_tool.addStretch(1) hbox_tool.addWidget(self.YLabel) hbox_tool.addWidget(self.Y) hbox_tool.addStretch(1) hbox_tool.addWidget(self.IntLabel) hbox_tool.addWidget(self.Int) hbox_tool.addStretch(2) hbox2_tool = QHBoxLayout() hbox2_tool.addWidget(self.XSLabel) hbox2_tool.addWidget(self.XSlider) hbox2_tool.addWidget(self.XSliceLabel) hbox2_tool.addWidget(self.XSlice) hbox3_tool = QHBoxLayout() hbox3_tool.addWidget(self.YSLabel) hbox3_tool.addWidget(self.YSlider) hbox3_tool.addWidget(self.YSliceLabel) hbox3_tool.addWidget(self.YSlice) vbox_tool = QVBoxLayout() vbox_tool.addLayout(hbox_tool) vbox_tool.addLayout(hbox2_tool) vbox_tool.addLayout(hbox3_tool) self.toolPanel.setLayout(vbox_tool) #color scale self.colorPanel = QGroupBox("Color Scale") self.colorPanel.setFixedHeight(105) self.colorPanel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.cmapmenu = CustomComboBox() self.cmapmenu.setFixedWidth(120) self.cmapmenu.setStyle(QStyleFactory.create('Fusion')) self.cmapmenu.setCurrentText("twilight") self.cmapmenu.currentIndexChanged.connect(self.changecmapbyindex) self.Vmin = QDoubleSpinBox() self.Vmin.setFixedWidth(100) self.Vmin.setRange(-1e15, 1e15) self.Vmin.setDecimals(4) self.Vmin.setKeyboardTracking(False) self.Vmin.valueChanged.connect(self.setDynamicRange) self.Vmin.setStyle(QStyleFactory.create('Fusion')) self.VminLabel = QLabel("Min:") self.VminLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.Vmax = QDoubleSpinBox() self.Vmax.setFixedWidth(100) self.Vmax.setRange(-1e15, 1e15) self.Vmax.setDecimals(4) self.Vmax.setKeyboardTracking(False) self.Vmax.valueChanged.connect(self.setDynamicRange) self.Vmax.setStyle(QStyleFactory.create('Fusion')) self.VmaxLabel = QLabel("Max:") self.VmaxLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.resetVrange = QPushButton("Re") self.resetVrange.setFixedWidth(25) self.resetVrange.clicked.connect(self.resetDynamicRange) self.resetVrange.setStyle(QStyleFactory.create('Fusion')) self.revcmap = QCheckBox("R") self.revcmap.stateChanged.connect(self.reversecmap) self.GammaLabel = QLabel("Gamma:") self.GammaLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.Gamma = QDoubleSpinBox() self.Gamma.setFixedWidth(100) self.Gamma.setDecimals(3) self.Gamma.setRange(0.05, 20) self.Gamma.setSingleStep(0.01) self.Gamma.setValue(1) self.Gamma.setKeyboardTracking(False) self.Gamma.valueChanged.connect(self.setGammaFromSpinBox) self.Gamma.setStyle(QStyleFactory.create('Fusion')) self.GSlider = QSlider(Qt.Horizontal) self.GSlider.setRange(1000000 * np.log(0.05), 1000000 * np.log(20)) self.GSlider.setValue(0) self.GSlider.sliderMoved.connect(self.setGammaFromSlider) self.GSlider.setStyle(QStyleFactory.create('Fusion')) hbox1_cmap = QHBoxLayout() hbox1_cmap.addWidget(self.cmapmenu) hbox1_cmap.addStretch(1) hbox1_cmap.addWidget(self.VminLabel) hbox1_cmap.addWidget(self.Vmin) hbox1_cmap.addStretch(1) hbox1_cmap.addWidget(self.VmaxLabel) hbox1_cmap.addWidget(self.Vmax) hbox1_cmap.addStretch(1) hbox1_cmap.addWidget(self.resetVrange) hbox2_cmap = QHBoxLayout() hbox2_cmap.addWidget(self.GammaLabel) hbox2_cmap.addWidget(self.Gamma) hbox2_cmap.addWidget(self.GSlider) hbox2_cmap.addWidget(self.revcmap) vbox_cmap = QVBoxLayout() vbox_cmap.addLayout(hbox1_cmap) vbox_cmap.addLayout(hbox2_cmap) self.colorPanel.setLayout(vbox_cmap) self.colorPanel.setEnabled(False) #Layout box = QVBoxLayout() box.addWidget(self.toolPanel) box.addWidget(self.canvas) box.addWidget(self.colorPanel) self.setLayout(box) def loaddata(self, data): self.canvas.draw() self.selector.set_visible(False) self.data = data self.GetWhiteBackground() self.X.setRange(data.xmin, data.xmax) self.X.setSingleStep(data.xstep) self.Y.setRange(data.ymin, data.ymax) self.Y.setSingleStep(data.ystep) newX = 0 if data.xmin * data.xmax < 0: newX = 0 else: newX = (data.xmin + data.xmax) / 2 if round(newX, 6) == self.X.value(): self.X.valueChanged.emit(newX) else: self.X.setValue(newX) newY = 0 if data.ymin * data.ymax < 0: newY = 0 else: newY = (data.ymin + data.ymax) / 2 if round(newY, 6) == self.Y.value(): self.Y.valueChanged.emit(newY) else: self.Y.setValue(newY) if data.data[~np.isnan(data.data)].max() > 0: self.Vmax.setValue(data.data[~np.isnan(data.data)].max()) self.Vmin.setValue(data.data[~np.isnan(data.data)].min()) else: self.Vmin.setValue(data.data[~np.isnan(data.data)].min()) self.Vmax.setValue(data.data[~np.isnan(data.data)].max()) self.XSlice.setRange(1, self.data.dimension[0]) self.YSlice.setRange(1, self.data.dimension[1]) self.plotimage(data, self.getcurrentcmap(), self.Vmin.value(), self.Vmax.value(), False) self.updatecolorscale(self.getcurrentcmap(), False) self.updateAxesPosition(True) self.colorPanel.setEnabled(True) def setValueFromSlider(self, value): if self.sender() == self.XSlider: self.X.setValue(value * (self.X.maximum() - self.X.minimum()) / 10000 + self.X.minimum()) elif self.sender() == self.YSlider: self.Y.setValue(value * (self.Y.maximum() - self.Y.minimum()) / 10000 + self.Y.minimum()) def setValueFromSpinBox(self, value): if self.sender() == self.X: self.XSlider.setValue( (value - self.X.minimum()) / (self.X.maximum() - self.X.minimum()) * 10000) half_wid_num = (self.XSlice.value() - 1) / 2 self.ly1.set_xdata(value - self.data.xstep * half_wid_num) self.ly2.set_xdata(value + self.data.xstep * half_wid_num) self.vl.set_xdata(value) self.YDC = self.get_YDC(value) self.resetYDC() self.plotYDC(True, True) self.plotXDC(True, True) elif self.sender() == self.Y: self.YSlider.setValue( (value - self.Y.minimum()) / (self.Y.maximum() - self.Y.minimum()) * 10000) half_wid_num = (self.YSlice.value() - 1) / 2 self.lx1.set_ydata(value - self.data.ystep * half_wid_num) self.lx2.set_ydata(value + self.data.ystep * half_wid_num) self.hl.set_ydata(value) self.XDC = self.get_XDC(value) self.resetXDC() self.plotXDC(True, True) self.plotYDC(True, True) self.plotArtist() self.setIntensity() def setIntensity(self): intensity = self.get_intensity(self.X.value(), self.Y.value()) if np.isnan(intensity): self.Int.setText("NaN") elif np.abs(intensity) >= 0.01: self.Int.setText("%.2f" % intensity) else: self.Int.setText("%.2e" % intensity) def setSlice(self, value): if self.sender() == self.XSlice: if value % 2 == 0: self.XSlice.setValue(value - 1) else: if value == 1: self.ly2.set_visible(False) else: self.ly2.set_visible(True) half_wid_num = (self.XSlice.value() - 1) / 2 self.ly1.set_xdata(self.X.value() - self.data.xstep * half_wid_num) self.ly2.set_xdata(self.X.value() + self.data.xstep * half_wid_num) self.plotArtist() self.YDC = self.get_YDC(self.X.value()) self.resetYDC() self.plotYDC(True, True) if self.sender() == self.YSlice: if value % 2 == 0: self.YSlice.setValue(value - 1) else: if value == 1: self.lx2.set_visible(False) else: self.lx2.set_visible(True) half_wid_num = (self.YSlice.value() - 1) / 2 self.lx1.set_ydata(self.Y.value() - self.data.ystep * half_wid_num) self.lx2.set_ydata(self.Y.value() + self.data.ystep * half_wid_num) self.plotArtist() self.XDC = self.get_XDC(self.Y.value()) self.resetXDC() self.plotXDC(True, True) self.setIntensity() def setDynamicRange(self, value): if self.sender() == self.Vmin: if value <= self.Vmax.value(): self.plotimage(self.data, self.getcurrentcmap(), value, self.Vmax.value(), True) else: self.plotimage(self.data, self.getcurrentcmap(), self.Vmax.value(), self.Vmax.value(), True) elif self.sender() == self.Vmax: if value >= self.Vmin.value(): self.plotimage(self.data, self.getcurrentcmap(), self.Vmin.value(), value, True) else: self.plotimage(self.data, self.getcurrentcmap(), self.Vmin.value(), self.Vmin.value(), True) def resetDynamicRange(self): self.Vmin.setValue(self.data.data[~np.isnan(self.data.data)].min()) self.Vmax.setValue(self.data.data[~np.isnan(self.data.data)].max()) def setTickLabelFont(self, ax, font): for tick in ax.get_xticklabels(): tick.set_fontname(font) for tick in ax.get_yticklabels(): tick.set_fontname(font) def scale2pnt(self, value, scale): return (np.abs(scale - value)).argmin() def get_intensity(self, xvalue, yvalue): xidx = self.scale2pnt(xvalue, self.data.xscale) yidx = self.scale2pnt(yvalue, self.data.yscale) half_wid_xnum = int((self.XSlice.value() - 1) / 2) half_wid_ynum = int((self.YSlice.value() - 1) / 2) if xidx < half_wid_xnum: xminidx = 0 else: xminidx = xidx - half_wid_xnum xmaxidx = xidx + half_wid_xnum + 1 if yidx < half_wid_ynum: yminidx = 0 else: yminidx = yidx - half_wid_ynum ymaxidx = yidx + half_wid_ynum + 1 return self.data.data[xminidx:xmaxidx, yminidx:ymaxidx].sum() def get_XDC(self, yvalue): yidx = self.scale2pnt(yvalue, self.data.yscale) half_wid_num = int((self.YSlice.value() - 1) / 2) if yidx < half_wid_num: yminidx = 0 else: yminidx = yidx - half_wid_num ymaxidx = yidx + half_wid_num + 1 array = self.data.data[:, yminidx:ymaxidx] return np.sum(array, axis=1) def get_YDC(self, xvalue): xidx = self.scale2pnt(xvalue, self.data.xscale) half_wid_num = int((self.XSlice.value() - 1) / 2) if xidx < half_wid_num: xminidx = 0 else: xminidx = xidx - half_wid_num xmaxidx = xidx + half_wid_num + 1 array = self.data.data[xminidx:xmaxidx, :] return np.sum(array, axis=0) def getcurrentcmap(self): cmap_str = self.cmapmenu.currentText() if self.revcmap.checkState() == Qt.Checked: cmap_str += "_r" raw_cmap = cm.get_cmap(cmap_str, 256) linearIndex = np.linspace(0, 1, 256) nonlinearIndex = np.power(linearIndex, self.Gamma.value()) new_cmap = ListedColormap(raw_cmap(nonlinearIndex)) return new_cmap def setGammaFromSpinBox(self, value): self.updatecolorscale(self.getcurrentcmap(), True) self.plotimage(self.data, self.getcurrentcmap(), self.Vmin.value(), self.Vmax.value(), True) self.GSlider.setValue(1000000 * np.log(value)) def setGammaFromSlider(self, value): self.Gamma.setValue(np.exp(value / 1000000)) def reversecmap(self, state): self.updatecolorscale(self.getcurrentcmap(), True) self.plotimage(self.data, self.getcurrentcmap(), self.Vmin.value(), self.Vmax.value(), True) def changecmapbyindex(self, index): self.updatecolorscale(self.getcurrentcmap(), True) self.plotimage(self.data, self.getcurrentcmap(), self.Vmin.value(), self.Vmax.value(), True) def updatecolorscale(self, cmap, removeflag): if removeflag: for img in self.ax_cmap.get_images(): img.remove() self.cmapimage = self.ax_cmap.imshow(self.gradient, cmap=cmap, origin="lower", aspect="auto") self.ax_cmap.redraw_in_frame() self.canvas.blit(self.ax_cmap.bbox) def begincursor(self, on): if on: self.lx1.set_visible(True) self.ly1.set_visible(True) if self.YSlice.value() > 1: self.lx2.set_visible(True) if self.XSlice.value() > 1: self.ly2.set_visible(True) self.vl.set_visible(True) self.hl.set_visible(True) self.plotArtist() self.plotXDC(True, True) self.plotYDC(True, True) self.cid_mouse = self.canvas.mpl_connect('motion_notify_event', self.navigate) self.cid_key = self.canvas.mpl_connect('key_press_event', self.navigate) else: self.lx1.set_visible(False) self.ly1.set_visible(False) self.lx2.set_visible(False) self.ly2.set_visible(False) self.vl.set_visible(False) self.hl.set_visible(False) self.plotXDC(True, False) self.plotYDC(True, False) self.plotArtist() self.canvas.mpl_disconnect(self.cid_mouse) self.canvas.mpl_disconnect(self.cid_key) def navigate(self, event): if event.inaxes == self.ax_Spec and event.key == "control": self.X.setValue(event.xdata) self.Y.setValue(event.ydata) def OnPress(self, event): if event.inaxes == self.ax_Spec and event.button == 1: if not self.selector.visible: #draw selector from nothing self.selector.moving_state = "draw" self.selector.origin = (event.xdata, event.ydata) self.cid_drawRS = self.canvas.mpl_connect( 'motion_notify_event', self.OnDrawRS) else: dist = self.selector.nearestCorner(event.x, event.y) if dist < 10: self.selector.moving_state = "moveHandle" self.selector.origin = (event.xdata, event.ydata) self.cid_moveHandle = self.canvas.mpl_connect( 'motion_notify_event', self.OnMoveHandle) else: if self.selector.isinRegion( event.xdata, event.ydata): #move the selector self.selector.moving_state = "move" self.selector.origin = (event.xdata, event.ydata) self.cid_moveRS = self.canvas.mpl_connect( 'motion_notify_event', self.OnMoveRS) else: #clear the selector self.selector.set_visible(False) self.plotArtist() def OnDrawRS(self, event): if event.inaxes == self.ax_Spec and event.button == 1: if event.xdata != self.selector.origin[ 0] and event.ydata != self.selector.origin[1]: self.selector.set_visible(True) self.selector.resize(self.selector.origin[0], self.selector.origin[1], event.xdata, event.ydata) self.plotArtist() def OnMoveRS(self, event): if event.inaxes == self.ax_Spec and event.button == 1: xmin, ymin, xmax, ymax = self.selector.region self.selector.resize(xmin + event.xdata - self.selector.origin[0], ymin + event.ydata - self.selector.origin[1], xmax + event.xdata - self.selector.origin[0], ymax + event.ydata - self.selector.origin[1]) self.plotArtist() self.selector.origin = (event.xdata, event.ydata) def OnMoveHandle(self, event): if event.inaxes == self.ax_Spec and event.button == 1: xmin, ymin, xmax, ymax = self.selector.region if self.selector.active_handle == 0: self.selector.resize( xmin + event.xdata - self.selector.origin[0], ymin + event.ydata - self.selector.origin[1], xmax, ymax) elif self.selector.active_handle == 1: self.selector.resize( xmin, ymin + event.ydata - self.selector.origin[1], xmax, ymax) elif self.selector.active_handle == 2: self.selector.resize( xmin, ymin + event.ydata - self.selector.origin[1], xmax + event.xdata - self.selector.origin[0], ymax) elif self.selector.active_handle == 3: self.selector.resize( xmin, ymin, xmax + event.xdata - self.selector.origin[0], ymax) elif self.selector.active_handle == 4: self.selector.resize( xmin, ymin, xmax + event.xdata - self.selector.origin[0], ymax + event.ydata - self.selector.origin[1]) elif self.selector.active_handle == 5: self.selector.resize( xmin, ymin, xmax, ymax + event.ydata - self.selector.origin[1]) elif self.selector.active_handle == 6: self.selector.resize( xmin + event.xdata - self.selector.origin[0], ymin, xmax, ymax + event.ydata - self.selector.origin[1]) elif self.selector.active_handle == 7: self.selector.resize( xmin + event.xdata - self.selector.origin[0], ymin, xmax, ymax) self.plotArtist() self.selector.origin = (event.xdata, event.ydata) def OnRelease(self, event): if event.inaxes == self.ax_Spec: if event.button == 1: if self.selector.moving_state == "draw": self.canvas.mpl_disconnect(self.cid_drawRS) elif self.selector.moving_state == "move": self.canvas.mpl_disconnect(self.cid_moveRS) elif self.selector.moving_state == "moveHandle": self.canvas.mpl_disconnect(self.cid_moveHandle) if event.button == 3: if self.selector.visible and self.selector.isinRegion( event.xdata, event.ydata): self.CropAction.setEnabled(True) self.SelectMenu.setEnabled(True) else: self.CropAction.setEnabled(False) self.SelectMenu.setEnabled(False) self.showContextMenu() else: if event.button == 3: self.CropAction.setEnabled(False) self.SelectMenu.setEnabled(False) self.showContextMenu() def showContextMenu(self): self.contextMenu.move(QCursor.pos()) self.contextMenu.show() def crop(self): x0, y0, x1, y1 = self.selector.region self.viewer.Win.DataProcessor.tab_single.setSelectXYRange( x0, x1, y0, y1, True) self.selector.set_visible(False) self.plotArtist() self.viewer.Win.DataProcessor.tab_single.crop2D.clicked.emit() def setSelectionRange(self): x0, y0, x1, y1 = self.selector.region if self.sender() == self.SelectX: self.viewer.Win.DataProcessor.tab_single.setSelectXRange(x0, x1) elif self.sender() == self.SelectY: self.viewer.Win.DataProcessor.tab_single.setSelectYRange(y0, y1) elif self.sender() == self.SelectXY: self.viewer.Win.DataProcessor.tab_single.setSelectXYRange( x0, x1, y0, y1, True) self.selector.set_visible(False) self.plotArtist() def outputData(self): if self.sender() == self.XDC_action: pass elif self.sender() == self.YDC_action: pass def OnKeyPress(self, event): if event.key == 'ctrl+a': if self.toolPanel.isChecked(): self.toolPanel.setChecked(False) else: self.toolPanel.setChecked(True) def GetWhiteBackground(self): self.ax_XDC.redraw_in_frame() self.canvas.blit(self.ax_XDC.get_window_extent()) self.ax_YDC.redraw_in_frame() self.canvas.blit(self.ax_YDC.get_window_extent()) self.background_XDC = self.canvas.copy_from_bbox( self.ax_XDC.get_window_extent()) self.background_YDC = self.canvas.copy_from_bbox( self.ax_YDC.get_window_extent()) self.background_Spec = self.canvas.copy_from_bbox( self.ax_Spec.get_window_extent()) def plotArtist(self): self.canvas.restore_region(self.background_Spec) for line in self.ax_Spec.get_lines(): self.ax_Spec.draw_artist(line) for artist in self.selector.artist: self.ax_Spec.draw_artist(artist) self.canvas.blit(self.ax_Spec.get_window_extent()) def plotimage(self, data, cmap, vmin, vmax, useblit): for img in self.ax_Spec.get_images(): img.remove() self.twoDspec = self.ax_Spec.imshow( data.data.T, cmap=cmap, vmin=vmin, vmax=vmax, origin="lower", extent=(data.xmin - 0.5 * data.xstep, data.xmax + 0.5 * data.xstep, data.ymin - 0.5 * data.ystep, data.ymax + 0.5 * data.ystep), aspect=self.aspect, interpolation='none') self.setTickLabelFont(self.ax_Spec, "Comic Sans MS") visible_flag = self.selector.visible self.selector.set_visible(False) if useblit: self.refreshimage() else: pass self.background_Spec = self.canvas.copy_from_bbox( self.ax_Spec.get_window_extent() ) #this line makes sure that the background will be updated when user change color map self.selector.set_visible(visible_flag) self.plotArtist() def refreshimage(self): self.ax_Spec.redraw_in_frame() self.canvas.blit(self.ax_Spec.get_window_extent()) def plotXDC(self, useblit, usecursor): if useblit: self.canvas.restore_region(self.background_XDC) self.ax_XDC.draw_artist(self.XDCLine) if usecursor: self.ax_XDC.draw_artist(self.vl) self.canvas.blit(self.ax_XDC.get_window_extent()) else: self.canvas.draw() def plotYDC(self, useblit, usecursor): if useblit: self.canvas.restore_region(self.background_YDC) self.ax_YDC.draw_artist(self.YDCLine) if usecursor: self.ax_YDC.draw_artist(self.hl) self.canvas.blit(self.ax_YDC.get_window_extent()) else: self.canvas.draw() def resetXDC(self): mask = np.isnan(self.XDC) self.XDCLine.set_data(self.data.xscale[~mask], self.XDC[~mask]) if len(self.XDC[~mask]) > 1: minvalue = min(self.XDC[~mask]) maxvalue = max(self.XDC[~mask]) if minvalue == maxvalue: minvalue = minvalue - 0.5 maxvalue = maxvalue + 0.5 else: minvalue = 0 maxvalue = 1 self.ax_XDC.set_ybound(lower=minvalue - 0.01 * (maxvalue - minvalue), upper=maxvalue + 0.01 * (maxvalue - minvalue)) self.ax_XDC.set_xbound(lower=self.data.xmin - self.data.xstep * 0.5, upper=self.data.xmax + self.data.xstep * 0.5) def resetYDC(self): mask = np.isnan(self.YDC) self.YDCLine.set_data(self.YDC[~mask], self.data.yscale[~mask]) if len(self.YDC[~mask]) > 1: minvalue = min(self.YDC[~mask]) maxvalue = max(self.YDC[~mask]) if minvalue == maxvalue: minvalue = minvalue - 0.5 maxvalue = maxvalue + 0.5 else: minvalue = 0 maxvalue = 1 self.ax_YDC.set_xbound(lower=minvalue - 0.01 * (maxvalue - minvalue), upper=maxvalue + 0.01 * (maxvalue - minvalue)) self.ax_YDC.set_ybound(lower=self.data.ymin - self.data.ystep * 0.5, upper=self.data.ymax + self.data.ystep * 0.5) def changeAspect(self, state): if state: self.aspect = "equal" else: self.aspect = "auto" self.ax_Spec.set_aspect(self.aspect) self.updateAxesPosition(True) def updateAxesPosition(self, useDraw): x_Spec, y_Spec, w_Spec, h_Spec = self.ax_Spec.get_position().bounds x_XDC, y_XDC, w_XDC, h_XDC = self.ax_XDC.get_position().bounds x_YDC, y_YDC, w_YDC, h_YDC = self.ax_YDC.get_position().bounds self.ax_XDC.set_position([x_Spec, y_XDC, w_Spec, h_XDC]) self.ax_YDC.set_position([x_YDC, y_Spec, w_YDC, h_Spec]) visible_flag = self.selector.visible self.selector.set_visible(False) if useDraw: self.canvas.draw() self.GetWhiteBackground() self.selector.set_visible(visible_flag) self.plotArtist() self.plotXDC(True, True) self.plotYDC(True, True) def resizeEvent_wrapper(self): self.updateAxesPosition(False)