def __init__(self): super(MainWindow, self).__init__() mw = MatplotlibWidget() subplot = mw.getFigure().add_subplot(111) mw.draw() # print(dir(mw)) # layout=QHBoxLayout() # mylabel=QLabel('Hi') # layout.addWidget(mylabel) # layout.addWidget(mw) # self.setLayout(layout) layout = QFormLayout() self.btn = QPushButton("Choose from list") self.btn.clicked.connect(self.getItem) self.le = QLineEdit() layout.addRow(self.btn, self.le) self.btn1 = QPushButton("get name") self.btn1.clicked.connect(self.gettext) self.le1 = QLineEdit() layout.addRow(self.btn1, self.le1) self.btn2 = QPushButton("Enter an integer") self.btn2.clicked.connect(self.getint) self.le2 = QLineEdit() layout.addRow(self.btn2, self.le2) self.setLayout(layout) self.setWindowTitle("Input Dialog demo") layout.addRow(mw)
def _create_expected_answered_ease_heatmap(self): chosen_ease = ['1', '2', '3', '4'] expected_ease = ['1', '2', '3'] answers = [[t.expected_ease, t.chosen_ease] for t in RevisionAnswer.select(RevisionAnswer.expected_ease, RevisionAnswer.chosen_ease)] df = pandas.DataFrame(answers, columns=['expected_ease', 'chosen_ease']).groupby([ 'expected_ease', 'chosen_ease' ]).size().unstack(fill_value=0) mat = df.to_numpy() print(mat) mw = MatplotlibWidget() fig = mw.getFigure() ax = fig.add_subplot() im = ax.imshow(df) ax.set_xticks(numpy.arange(len(chosen_ease))) ax.set_yticks(numpy.arange(len(expected_ease))) ax.set_xticklabels(chosen_ease) ax.set_yticklabels(expected_ease) ax.set_xlabel("Chosen ease") ax.set_ylabel("Expected ease") pyplot.setp(ax.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor") for i in range(len(chosen_ease)): for j in range(len(expected_ease)): text = ax.text(i, j, mat[j, i], ha="center", va="center", color="w") fig.tight_layout() mw.draw() self.layout.addWidget(mw)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setGeometry(100, 100, 600, 900) self.centralWidget = QWidget() # GrphicsWidget() layout = QHBoxLayout(self.centralWidget) self.scrollArea = QScrollArea(self) # gwidget=GrphicsWidget() self.mw = MatplotlibWidget(size=(3.0, 40.0), dpi=100) lplot = self.mw.getFigure().add_subplot(121) # print(dir(self.mw.getFigure())) # self.mw.getFigure().set_axes([0.85, 0.1, 0.075, 0.8]) self.ax = self.mw.getFigure().gca() self.ax.set_position([0.1, 0.05, 0.8, 0.94]) self.ax.invert_yaxis() # l, b, w, h = self.ax.get_position().bounds # print(l, b, w, h) self.mw.draw() # self.plotlayout.addWidget(self.mw) self.scrollArea.setWidget(self.mw) layout.addWidget(self.scrollArea) self.setCentralWidget(self.centralWidget) self.wellLoad() self.logtree = LasTree(['GR', 'NPHI']) self.logtree.buildTreeWidget() self.logtree.tree.itemSelectionChanged.connect(self.logPlot) self.createDockWindows() # self.logFileList.itemSelectionChanged.connect(self.lasLoad) # if not self.las_just_selected: # self.logList.itemSelectionChanged.connect(self.logPlot) self.setWindowTitle("Loggy") # self.newLetter() def wellLoad(self): self.wellFolder = r'E:\Data\W1\LAS\\' self.files = np.array(os.listdir(self.wellFolder)[:]) files_w_path = [self.wellFolder + f for f in self.files] # print(files_w_path) # self.logFileList.addItems(self.files) # folder=r'D:\Ameyem Office\Projects\Cairn\W1\LAS\\' cols = [] # las=[] # log.df().sort_values([log.keys()[dindx]]) # log.keys() self.files = np.array(os.listdir(self.wellFolder)[:]) self.lastree = LasTree(self.files) self.lastree.buildTreeWidget() self.lastree.tree.itemSelectionChanged.connect(self.lasLoad) self.lasLoadThread = LasLoadThread(files=files_w_path) # def lasBackgroundLoad(): def lasLoad(self): las_name = self.lastree.tree.selectedItems()[0].text( 0) #self.logFileList.selectedItems()[0].text() if las_name in ['TVD', 'MD', 'LWD', 'WireLine']: return findex = np.where(self.files == las_name)[0][0] # print(findex) Loaded = False while (not Loaded): if (findex < len(self.lasLoadThread.Lases)): self.las = self.lasLoadThread.Lases[findex] Loaded = True else: self.logtree.clear() # self.logtree.addItems(['Loading....']) time.sleep(1) if len(self.logtree.selectedItems()) > 0: item = self.logtree.selectedItems()[0] # print(dir(item)) item.setSelected = False # self.logList.clear() # self.logList.addItems(self.las.keys() ) if not (len(self.las.keys()) < 1): self.logtree = LasTree(self.las.keys()) self.logtree.buildTreeWidget() # self.logtree.tree.itemSelectionChanged.connect(self.logPlot) dcol = self.las.keys()[find_depth_indx(self.las)] self.depth_col = str_array2floats(self.las[dcol]) # else: # self.las_just_selected = True def logPlot(self): # print(self.mw.getFigure().) # pass # if not self.las_just_selected: if len(self.logtree.selectedItems()) > 0: keycol = self.logtree.selectedItems()[0].text(0) try: self.log_col = str_array2floats(self.las[keycol]) self.ax = LogPlot.basicPlot(self.ax, self.depth_col, self.log_col, lcolor='#800000') except: print('Unable to convert log to floats') # else: # self.las_just_selected=False # fig.subplots_adjust(top=0.75,wspace=0.1) # ax.invert_yaxis() # ax.plot([1,2,3],[2,1,4],'*') self.mw.draw() # self.subplot1 = self.mw.getFigure().add_subplot(121) def createDockWindows(self): dock = QDockWidget("Log Files", self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) # self.logFileList = self.lastree.tree #QListWidget(dock) # self.customerList.addItems(('Hello','How are you')) dock.setWidget(self.lastree.tree) # self.addDockWidget(Qt.LeftDockWidgetArea, dock) # self.viewMenu.addAction(dock.toggleViewAction()) dock = QDockWidget("Logs", self) # self.logList = QListWidget(dock) # self.logList.addItems(('Good morning','Hope you are doing well')) dock.setWidget(self.logtree.tree) # self.logList = QListWidget(dock) # self.logList.addItems(('Good morning','Hope you are doing well')) # dock.setWidget(self.logList) self.addDockWidget(Qt.LeftDockWidgetArea, dock)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.createActions() self.createMenus() self.setGeometry(100, 100, 600, 900) self.centralWidget = QWidget() # GrphicsWidget() layout = QHBoxLayout(self.centralWidget) self.scrollArea = QScrollArea(self) self.mw = MatplotlibWidget(size=(3.0, 40.0), dpi=100) lplot = self.mw.getFigure().add_subplot(121) self.ax = self.mw.getFigure().gca() l, b, w, h = self.ax.get_position().bounds # print(l, b, w, h) # self.ax.invert_yaxis() self.ax.set_position([0.125, 0.05, 0.5, 0.94]) # l, b, w, h = self.ax.get_position().bounds # print(l, b, w, h) self.mw.draw() # self.plotlayout.addWidget(self.mw) self.scrollArea.setWidget(self.mw) layout.addWidget(self.scrollArea) self.setCentralWidget(self.centralWidget) self.lastree = LasTree() self.logtree = LasTree() self.wellLoad() self.logtree.set_files(['GR', 'BS']) self.logtree.buildTreeWidget() self.logtree.tree.itemSelectionChanged.connect(self.logPlot) self.createDockWindows() # self.logFileList.itemSelectionChanged.connect(self.lasLoad) # if not self.las_just_selected: # self.logList.itemSelectionChanged.connect(self.logPlot) self.setWindowTitle("Loggy") # self.newLetter() def wellLoad(self): self.wellFolder = well_folder self.files = [] for f in np.array(os.listdir(self.wellFolder)[:]): if f[-4:].lower() in ['.las', 'dlis']: self.files.append(f) self.files = np.array(self.files) files_w_path = [self.wellFolder + f for f in self.files] cols = [] # self.files=np.array(os.listdir(self.wellFolder)[:]) self.lastree.set_files(self.files) self.lastree.buildTreeWidget() self.lasfiletree = self.lastree.treeview_dict.copy() self.lastree.tree.itemSelectionChanged.connect(self.lasLoad) self.lasLoadThread = LasLoadThread(files=files_w_path) # def lasBackgroundLoad(): def lasLoad(self): las_name = self.lastree.tree.selectedItems()[0].text( 0) #self.logFileList.selectedItems()[0].text() if las_name in ['TVD', 'MD', 'LWD', 'WireLine']: return findex = np.where(self.files == las_name)[0][0] # print(findex) Loaded = False while (not Loaded): if (findex < len(self.lasLoadThread.Lases)): self.las = self.lasLoadThread.Lases[findex] Loaded = True self.logtree.tree.clear() # print('hi') else: # print('hello') # self.logtree.addItems(['Loading....']) time.sleep(1) if len(self.logtree.tree.selectedItems()) > 0: item = self.logtree.tree.selectedItems()[0] # print(dir(item)) item.setSelected = False if not (len(self.las.keys()) < 1): # self.logtree = LasTree(self.las.keys()) self.logtree.set_files(self.las.keys()) self.logtree.buildTreeWidget() dcol = self.las.keys()[find_depth_indx(self.las)] self.depth_col = str_array2floats(self.las[dcol]) # else: # self.las_just_selected = True def logPlot(self): # print(self.mw.getFigure().) # pass # if not self.las_just_selected: if len(self.logtree.tree.selectedItems()) > 0: keycol = self.logtree.tree.selectedItems()[0].text(0) try: self.log_col = str_array2floats(self.las[keycol]) self.ax = LogPlot.basicPlot(self.ax, self.depth_col, self.log_col, lcolor='#800000') self.ax.set_ylim(500, 3000) self.ax.invert_yaxis() except: print('Unable to convert log to floats') self.mw.draw() def set_category(self): # qt_app = QApplication(sys.argv) # mnomonicsfile=mnomonicsfile # print(self.logtree.treeview_dict) # set_category_app = Categorize(self.logtree.treeview_dict,mnomonicsfile) print('*************************************************') print(self.logtree.treeview_dict) category_window = Categorize(self) category_window.set_params(self.logtree, mnomonicsfile) category_window.show() # self.logtree.tree.clear() # self.logtree.buildTreeWidget() # set_category_app.run() # self.logtree.buildTreeWidget() def createDockWindows(self): dock = QDockWidget("Log Files", self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) dock.setWidget(self.lastree.tree) # self.addDockWidget(Qt.LeftDockWidgetArea, dock) self.set_category_button = QPushButton('Set Category', self) self.slect_files_button = QPushButton( 'Select files for further process', self) # self.layout.addWidget(self.logtree.tree) dock = QDockWidget("Set", self) btn_w = QWidget() self.btn_layout = QVBoxLayout() btn_w.setLayout(self.btn_layout) dock.setWidget(btn_w) self.btn_layout.addWidget(self.set_category_button) self.btn_layout.addWidget(self.slect_files_button) self.addDockWidget(Qt.LeftDockWidgetArea, dock) dock = QDockWidget("Logs", self) dock.setWidget(self.logtree.tree) self.addDockWidget(Qt.LeftDockWidgetArea, dock) self.set_category_button.clicked.connect(self.set_category) self.slect_files_button.clicked.connect(self.retain4FurtherAnalysis) def createActions(self): self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close) self.openFileAct = QAction("&Open", self, shortcut="Ctrl+O", triggered=self.file_open) self.aboutAct = QAction("&About", self, triggered=self.about) def retain4FurtherAnalysis(self): # print(self.lastree.treeview_dict) print(self.lasfiletree) lasfilemodtree = {} lc = LogCategorize(mnomonicsfile) self.files_4_further_analysis = [] self.allfiles = {'fname': [], 'drange': [], 'curve_names': []} if len(self.lasLoadThread.Lases) == len(self.files): print('Loaded all files...') for las, lf in zip(self.lasLoadThread.Lases, self.files): lc.set_las(las) lc.lasCategorize() # print(lc.treeview_dict) # print(lc.get_catePresent()) # print( lc.get_lasdepthrange()) # print( lc.get_curverange('CAL')) lcates = lc.get_catePresent() # if len(lcates)>3: self.allfiles['fname'].append(lf) self.allfiles['drange'].append(lc.get_lasdepthrange()) self.allfiles['curve_names'].append(lc.get_catePresent()) # print(self.allfiles) topdepts = np.array( [np.float(d[0]) for d in self.allfiles['drange']]) ncurves = np.array([len(d) for d in self.allfiles['curve_names']]) self.allfiles['topdepts'] = topdepts self.allfiles['ncurves'] = ncurves self.allfiles['fname'] = np.array(self.allfiles['fname']) print(np.column_stack((topdepts, ncurves))) for k in self.lasfiletree: lasfilemodtree[k] = {} for l in self.lasfiletree[k]: lasfilemodtree[k][l] = {} if (len(self.lasfiletree[k][l]) > 0): branch_files = np.array(self.lasfiletree[k][l]) print('*****************************************') print(branch_files) branch_files = self.sort_per_depthNcurves(branch_files) print(branch_files) for m in branch_files: indx = np.where(self.allfiles['fname'] == m)[0][0] print(m, self.allfiles['fname'], indx) lasfilemodtree[k][l][m] = [ '{} - {}'.format( *self.allfiles['drange'][indx]), str(len(self.allfiles['curve_names'][indx])), ','.join(self.allfiles['curve_names'][indx]) ] else: print('Not loaded all files...') print(lasfilemodtree) self.retain_tree = Pytree(self) self.retain_tree.set_tree(lasfilemodtree) self.retain_tree.select_btn.clicked.connect(self.return_selected_items) self.retain_tree.buildTree() self.retain_tree.show() # sys.exit(app.exec_()) def return_selected_items(self): iterator = QTreeWidgetItemIterator(self.retain_tree.tree) value = iterator.value() self.retain_files = [] self.retain_files_ranges = [] while value: if value.checkState(0) == Qt.Checked: # print('yes') print(value.text(0)) self.retain_files.append(value.text(0)) self.retain_files_ranges.append(value.text(1)) # if hasattr(value, 'saveValue'): # value.saveValue() iterator += 1 value = iterator.value() # print(self.retain_files) # print(self.retain_files_ranges) self.retain_tree.close() self.show_lateralCorrections() def show_lateralCorrections(self): self.lateralCorr_buttons = [] for i, rf in enumerate(zip(self.retain_files, self.retain_files_ranges)): lcw = QWidget() self.harlayout = QHBoxLayout() self.lateralCorr_buttons.append( QPushButton('Do Lateral Depth Match-' + str(i), self)) self.harlayout.addWidget(QLabel(rf[1])) self.harlayout.addWidget(self.lateralCorr_buttons[-1]) print(rf[0]) self.lateralCorr_buttons[-1].clicked.connect( lambda state, x=rf[0]: self.doLateralCorr(x)) lcw.setLayout(self.harlayout) self.btn_layout.addWidget(lcw) def doLateralCorr(self, lfilename): self.selected_lases = [] findex = np.where(self.files == lfilename)[0][0] print(lfilename, findex) self.selected_lases.append(self.lasLoadThread.Lases[findex]) lateralWin = LateralCorr(self) lateralWin.buildLogTree(self.selected_lases) lateralWin.logCorrelations() lateralWin.show() def sort_per_depthNcurves(self, branch_files): indxs = [] for m in branch_files: indxs.append(np.where(self.allfiles['fname'] == m)[0][0]) ncurves = self.allfiles['ncurves'][indxs] sort_dpt_indx = np.argsort(self.allfiles['topdepts'][indxs]) ncurves_rule = ncurves[sort_dpt_indx] > 2 branch_files = branch_files[sort_dpt_indx] # sort_dpt_indx=sort_dpt_indx[::-1] return np.append(branch_files[ncurves_rule], branch_files[~ncurves_rule]) def createMenus(self): self.fileMenu = QMenu("&File", self) # self.fileMenu.addAction(self.openAct) # self.fileMenu.addAction(self.printAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.openFileAct) self.fileMenu.addAction(self.exitAct) self.helpMenu = QMenu("&Help", self) self.helpMenu.addAction(self.aboutAct) # self.helpMenu.addAction(self.aboutQtAct) self.menuBar().addMenu(self.fileMenu) # self.menuBar().addMenu(self.viewMenu) # self.menuBar().addMenu(self.digitizeMenu) self.menuBar().addMenu(self.helpMenu) self.file_toolbar = QToolBar("File") self.file_toolbar.setIconSize(QSize(24, 24)) self.addToolBar(self.file_toolbar) def about(self): QMessageBox.about( self, "About Log splicer", "<p>The <b>Image Viewer</b> example shows how to combine " "(QScrollArea.widgetResizable), can be used to implement " "zooming and scaling features.</p>" "<p>In addition the example shows how to use QPainter to " "print an image.</p>") def file_open(self): print('Not yet set')
class VerticalCorr(QMainWindow): def __init__(self, parent=None): super(VerticalCorr, self).__init__(parent) from loggy_settings import well_folder, lwdVSwirelineFile, mnomonicsfile # projectFolder=r'D:\Ameyem Office\Projects\Cairn\W1\\' self.log_bundle = np.load(well_folder + '..\proc_logs_bundle.npy') self.flt_logs = {} for logname in self.log_bundle[0]['keys']: print(logname) self.flt_logs[logname] = [[] for i in range(len(self.log_bundle))] print('Starting main window...') self.centralWidget = QWidget() self.setCentralWidget(self.centralWidget) self.setWindowTitle('Vertical Correlations') self.setGeometry(100, 100, 900, 400) layout = QVBoxLayout(self.centralWidget) self.logscrollArea = QScrollArea(self) layout.addWidget(self.logscrollArea) fw = QWidget() # fw.setMaximumWidth(120) # self.formLayout=QFormLayout() self.formLayout = QHBoxLayout() fw.setLayout(self.formLayout) layout.addWidget(fw) self.filtscrollArea = QScrollArea(self) layout.addWidget(self.filtscrollArea) self.getFormLayerFilled() self.setCentralWidget(self.centralWidget) self.createDockWindows() self.run_mass_filter() def getFormLayerFilled(self): self.learray = [] # self.formLayout.addRow(QLabel(' ')) # self.formLayout.addRow(QLabel('Calculated delays')) # self.formLayout.addRow(QLabel(' ')) # for i,l in enumerate(self.delays.keys()): # self.learray.append( QLineEdit('%.2f'%self.delays[l])) # # self.formLayout.addRow(QLabel(l),self.learray[-1]) self.n_patches2retain_le = QLineEdit('1') self.n_hist_segments_le = QLineEdit('100') self.histFilter_btn = QPushButton("Remove Spikes") self.histForm = QFormLayout() self.histForm.addRow(QLabel('Retainpatches: '), self.n_patches2retain_le) self.histForm.addRow(QLabel('HistSegments: '), self.n_hist_segments_le) hfw = QWidget() hfw.setMaximumWidth(200) hfw.setLayout(self.histForm) # hfw.setMinimumWidth(120) self.formLayout.addWidget(hfw) self.formLayout.addWidget(self.histFilter_btn) self.histFilter_btn.clicked.connect(self.histFilter) # self.formLayout.addRow(QLabel(' ')) # self.recal_btn = QPushButton("Recalculate") # self.formLayout.addRow(self.recal_btn) # self.recal_btn.clicked.connect(self.recalculateDelay) # self.formLayout.addRow(QLabel(' ')) # self.save_btn = QPushButton("Save Curves") # self.formLayout.addRow(self.save_btn) # self.save_btn.clicked.connect(self.saveCorrCurves) # def applyDelayChange(self): # for le,key in zip(self.learray,self.delays.keys()): # self.delays[key]=np.float(le.text()) # print(le.text()) # self.log_correlations_plot() # def recalculateDelay(self): # self.logCorrelations() # def saveCorrCurves(self): # print('Saving logs...') # proc_logs={} # for logname in self.delays.keys(): # if self.delays[logname] !=0: # shift_depth=self.depth_col+self.delays[logname] # shift_depth.shape=len(shift_depth),1 # # np.save('now.npy',(shift_depth,self.las[logname])) # # print(shift_depth,self.las[logname]) # XY=np.append(shift_depth,self.las[logname].reshape(len(shift_depth),1),axis=1) # XY.shape=len(shift_depth),2 # # print(XY) # flexlog=FlexLog(XY) # resamLog=flexlog.resampleY(self.depth_col) # else: # resamLog=self.las[logname] # key=self.interestedKeynames[self.interestedLognames==logname][0] # proc_logs[key]=resamLog # proc_logs['GR']=self.las[self.grlogname] # proc_logs['DEPTH']=self.depth_col # proc_logs['vlues_size']=np.size(self.las.values()) # proc_logs['keys']=self.interestedKeynames # # proc_logs['test']='yes' # bundle_file=self.wellFolder+'../proc_logs_bundle.npy' # repeated=False # if os.path.isfile(bundle_file): # logbundle=np.load(bundle_file) # for i,lb in enumerate(logbundle): # if lb['vlues_size']==proc_logs['vlues_size']: # repeated=True # print('It is repeated so updated but not created...') # logbundle[i]=proc_logs # else: # logbundle=[] # if not repeated: # logbundle=np.append(logbundle,proc_logs) # np.save(bundle_file,logbundle) # print('Processed logs saved.. you can move on to next set...') # time.sleep(2) # self.close() def histFilter(self): depthcol_name = 'DEPTH' self.filtw = MatplotlibWidget(size=(22.0, 4), dpi=100) self.filtscrollArea.setWidget(self.filtw) ax = self.filtw.getFigure().add_subplot(1, 1, 1) hist_bins = np.int(self.n_hist_segments_le.text()) n_big_patches = np.int(self.n_patches2retain_le.text()) self.flt_logs[self.logname] = [] for i, lb in enumerate(self.log_bundle): self.flt_logs[self.logname][i] = hist_filter( lb[self.logname].copy(), n_big_patches=n_big_patches, hist_bins=hist_bins) ax.plot(lb[depthcol_name], self.flt_logs[self.logname][i]) # print(flt_arrs) def run_mass_filter(self): hist_bins = np.int(self.n_hist_segments_le.text()) n_big_patches = np.int(self.n_patches2retain_le.text()) for i, lb in enumerate(self.log_bundle): for logname in lb['keys']: self.flt_logs[logname][i] = hist_filter( lb[logname].copy(), n_big_patches=n_big_patches, hist_bins=hist_bins) def logPlotPanel(self): print('Initiating plot widget...') self.logname = self.lastree.tree.selectedItems()[0].text(0) depthcol_name = 'DEPTH' # firstlog logdata = [] depthdata = [] self.mw = MatplotlibWidget(size=(22.0, 4), dpi=100) self.logscrollArea.setWidget(self.mw) self.ax = self.mw.getFigure().add_subplot(1, 1, 1) self.filtw = MatplotlibWidget(size=(22.0, 4), dpi=100) self.filtscrollArea.setWidget(self.filtw) ax2 = self.filtw.getFigure().add_subplot(1, 1, 1) for i, lb in enumerate(self.log_bundle): # print(lb[self.logname],lb[depthcol_name]) self.ax.plot(lb[depthcol_name], lb[self.logname]) ax2.plot(lb[depthcol_name], self.flt_logs[self.logname][i]) # logdata=np.append([logdata],[lb[logname]],axis=0 ) # depthdata=np.append([depthdata],[lb[depthcol_name] ],axis=0 ) # print(logdata) # self.depth_col=self.las[dcol] # dt=self.depth_col[1]-self.depth_col[0] # print('Spacing = ',dt) # gammacol=self.las[self.grlogname] # gammacol[np.isnan(gammacol)]=0 # self.norm_gamma=mean_norm(gammacol)#[0:800] # l, b, w, h = self.ax.get_position().bounds # self.ax.set_position([0.27,b+0.1,0.7,h]) # self.lag_corrs={} # self.delays={} # self.normlogs={} # print('Calculating correlations...') # for logname in self.interestedLognames: # if logname != self.grlogname: # self.log_col=self.las[logname] # self.log_col[np.isnan(self.log_col)]=0 # norm_blog=mean_norm(self.log_col)#[0:800] # self.normlogs[logname]=norm_blog # dist2look=100 # delay_estimation,lag_corr= get_delay(self.norm_gamma,norm_blog,dt,corrtype='abs',dist2look=dist2look) # self.delays[logname]=-delay_estimation # lagcor_range=np.arange(round(len(lag_corr[0])/2)-4*dist2look,round(len(lag_corr[0])/2)+4*dist2look) # self.lag_corrs[logname]=(lag_corr[0][lagcor_range],lag_corr[1][lagcor_range]) # self.log_correlations_plot() # self.getFormLayerFilled() def log_correlations_plot(self): self.mw = MatplotlibWidget(size=(22.0, len(self.interestedLognames) * 1.6), dpi=100) self.logscrollArea.setWidget(self.mw) print('Plotting...') self.ax = [] for i, logname in enumerate(self.normlogs.keys()): self.ax.append(self.mw.getFigure().add_subplot( len(self.normlogs), 1, i + 1)) l, b, w, h = self.ax[-1].get_position().bounds self.ax[-1].set_position([0.27, b + 0.1, 0.7, h]) # self.log_col=self.las[logname] # self.log_col[np.isnan(self.log_col)]=0 # norm_blog=mean_norm(self.log_col)#[0:800] depthb_shift = self.depth_col + self.delays[logname] self.ax[-1].plot(self.depth_col, self.normlogs[logname], 'b') self.ax[-1].plot(self.depth_col, self.norm_gamma, 'r') self.ax[-1].plot(depthb_shift, self.normlogs[logname], 'magenta') self.ax[-1].text(self.depth_col[0] - 50, 0.02, logname) lenax = len(self.ax) for i, logname in enumerate(self.lag_corrs.keys()): self.ax.append(self.mw.getFigure().add_subplot( len(self.normlogs), 2, lenax + i + 1)) l, b, w, h = self.ax[i].get_position().bounds self.ax[-1].set_position([0.03, b, 0.21, h]) self.ax[-1].plot(self.lag_corrs[logname][0], self.lag_corrs[logname][1], 'b') self.ax[-1].text(self.delays[logname], min(self.lag_corrs[logname][1]), 'Delay = %.2f' % self.delays[logname]) line = self.ax[-1].axvline(x=self.delays[logname], ymin=-1, ymax=+1, linewidth=1.5, color='c') self.ax[-1].text(self.lag_corrs[logname][0][0], 0.4, logname) self.mw.draw() print('Complete...') def buildLogTree(self): self.lastree = LasTree() self.lastree.tree.headerItem().setText(0, "Categories") for lb in self.log_bundle: # logkeys=np.append(['GR'],lb['keys']) # print(logkeys) self.lastree.set_files(lb['keys'], make_tree_dict=False) mind, maxd = min(lb['DEPTH']), max(lb['DEPTH']) self.lastree.tree = treeWidgetFrmArray( self.lastree.tree, '({0:4.1f} to {1:4.1f})'.format(mind, maxd), lb['keys']) self.lastree.tree.itemSelectionChanged.connect(self.logPlotPanel) self.dock.setWidget(self.lastree.tree) print(dir(self.lastree.tree)) print(help(self.lastree.tree.itemAt)) print(self.lastree.tree.itemAt(1, 0).text(0)) def createDockWindows(self): self.dock = QDockWidget("Log Files", self) self.dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) # dock.setWidget(self.lastree.tree) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock)
class mainWindow(QtGui.QMainWindow): """ main Window, parent to GL Viewport and UI """ def __init__(self, load=None, loadsnapshot=None, options={}, **kwargs): super(mainWindow, self).__init__() self._setupUI() if load is not None: self.loaddata_gadget(load) if loadsnapshot is not None: self.loadsnapshot_gadget(loadsnapshot, basic=options.basic) def _setupUI(self): area = DockArea() self.setCentralWidget(area) self.resize(1000,800) self.setWindowTitle('Gadget Visualization') self._setupMenu() ## Create docks, place them into the window one at a time. ## Note that size arguments are only a suggestion; docks will still have to ## fill the entire dock area and obey the limits of their internal widgets. self.dock1 = Dock("Main Window", size=(800, 800)) self.dock2 = Dock("Console", size=(800,200)) self.dock3 = Dock("View", size=(200,800)) self.dock4 = Dock("Options", size=(200,800)) self.dock1.hideTitleBar() self.dock2.hideTitleBar() # dock3.hideTitleBar() area.addDock(self.dock1, 'left') area.addDock(self.dock3, 'right', self.dock1) area.addDock(self.dock4, 'top', self.dock3) area.addDock(self.dock2, 'bottom', self.dock1) area.moveDock(self.dock3, 'above', self.dock4) ## Add widgets into each dock # self.sn = None self.filePath = '.' self.sn = snapshot() self.vis = sphvis() ## add GL Viewport self.ViewWidget = myGLViewWidget() self.ViewWidget.addItem(self.vis) self.dock1.addWidget(self.ViewWidget) ## setup embedded IPython terminal self._setupIpythonWidget() ## setup control widget self._setupControls() def _setupIpythonWidget(self): namespace={'pg': pg, 'np': np, 'vis': self.vis, 'sn': self.sn, 'vw': self.ViewWidget, 'main': self } #w2 = pg.console.ConsoleWidget(namespace=namespace) self.ipythonWidget = QIPythonWidget() self.ipythonWidget.pushVariables(namespace) self.dock2.addWidget(self.ipythonWidget) self.ipythonWidget.execute("%pylab", True, False) welcomeText = "\nPySPHViewer v%s\n" % (VERSION) \ + "The data of the currently visible Snapshot can be accessed with the 'sn' object\n" \ + "import numpy as np, pyqtgraph as pg\n" \ + "\n" self.ipythonWidget.printText(welcomeText) def _setupControls(self): w3 = pg.LayoutWidget() self.dock3.addWidget(w3) label = QtGui.QLabel("") w3.addWidget(label) w3.nextRow() ##buttons buttons = [('Reset', self.ViewWidget.reset, 'r', -1), ('Save Rotation', self.saveCurrentView, None, -1), ('X-Z', self.ViewWidget.rotateXZ, 'c', None), ('X-Y', self.ViewWidget.rotateXY, 'v', None), ('Y-Z', self.ViewWidget.rotateYZ, 'b', 1), ] for text, action, shortcut, cs in buttons: btn = QtGui.QPushButton(text) btn.setMinimumWidth(15) if cs: w3.addWidget(btn, colspan=cs) w3.nextRow() else: w3.addWidget(btn) if shortcut: btn.setShortcut(shortcut) btn.clicked.connect(action) w4 = pg.LayoutWidget() self.dock3.addWidget(w4) ## Checkboxes to select particle types to be displayed for t in range(self.vis.ntypes): cb = QtGui.QCheckBox(self.vis.typenames[t]) cb.toggle() cb.stateChanged.connect(partial(self.vis.changeDrawTypes, ptype=t)) w4.addWidget(cb) w4.nextRow() sliders = [ ("Pointsize", np.sqrt(self.vis.mastersize)*25, self.vis.sizeChange, (0,100)), ("Alpha", self.vis.lum * 100, self.vis.alphaChange, (0,100)), ("Step", self.vis.step, self.vis.stepChange, (1,100)), ] for text, val, slot, srange in sliders: label = QtGui.QLabel("%16s" % text) w4.addWidget(label) sl = QtGui.QSlider(QtCore.Qt.Horizontal) sl.setRange(*srange) sl.setValue(val) w4.addWidget(sl) w4.nextRow() sl.valueChanged.connect(slot) label = QtGui.QLabel("") w4.addWidget(label) def initpopup(self): self.popupPlot = popupPlot() vbox = QtGui.QVBoxLayout() self.popupPlot.setLayout(vbox) self.popupPlot.show() self.mw = MatplotlibWidget() vbox.addWidget(self.mw) self.subplot = self.mw.getFigure().add_subplot(111) self.subplot.plot(np.arange(10)) self.mw.draw() def _setupMenu(self): openFile = QtGui.QAction('&Open File', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Open new Gadget File') openFile.triggered.connect(self.openGadget) popupAction = QtGui.QAction('&PlotPopup', self) popupAction.setStatusTip('Exit application') popupAction.triggered.connect(self.initpopup) exitAction = QtGui.QAction('&Exit', self) exitAction.setShortcut('Esc') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(QtGui.qApp.quit) self.statusBar() menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(openFile) fileMenu.addAction(exitAction) self.toolbar = self.addToolBar('Exit') self.toolbar.addAction(openFile) self.toolbar.addAction(popupAction) self.toolbar.addAction(exitAction) def fileSelect(self): fname = QtGui.QFileDialog.getOpenFileName(self, 'Open file', self.filePath) if fname: self.filePath = QtCore.QFileInfo(fname).path() return fname def openGadget(self): fname = self.fileSelect() if fname: self.loadsnapshot_gadget(fname) def saveCurrentView(self): fname = self.fileSelect() with (open(fname, 'w')) as f: self.ViewWidget.currentView().transpose().astype(np.float64).tofile(f) def loadsnapshot_gadget(self, fname, **kwargs): self.sn.readgadget(fname, **kwargs) self.loaddata_gadget(self.sn) def loaddata_gadget(self, *args): self.vis.loaddata_gadget(*args) self.statusBar().showMessage('Snapshot loaded')
class LateralCorr(QMainWindow): def __init__(self,parent=None): super(LateralCorr, self).__init__(parent) # self.wellFolder=well_folder print('Starting main window...') self.centralWidget = QWidget() self.setCentralWidget(self.centralWidget) self.setWindowTitle('Lateral Correlations') self.setGeometry(100,100, 900,400) layout = QHBoxLayout(self.centralWidget) self.formLayout=QFormLayout() fw=QWidget() fw.setMaximumWidth(120) # fw.setMinimumHeight(400) fw.setLayout(self.formLayout) self.logscrollArea = QScrollArea(self) # self.corrscrollArea = QScrollArea(self) # layout.addWidget(self.corrscrollArea) layout.addWidget(fw) layout.addWidget(self.logscrollArea) self.setCentralWidget(self.centralWidget) # self.create_plotWindow() self.createDockWindows() def getFormLayerFilled(self): self.learray=[] self.formLayout.addRow(QLabel(' ')) self.formLayout.addRow(QLabel('Calculated delays')) self.formLayout.addRow(QLabel(' ')) for i,l in enumerate(self.delays.keys()): self.learray.append( QLineEdit('%.2f'%self.delays[l])) # self.formLayout.addRow(QLabel(l),self.learray[-1]) self.delaysubmit_btn = QPushButton("Apply") self.formLayout.addRow(self.delaysubmit_btn) self.delaysubmit_btn.clicked.connect(self.applyDelayChange) self.formLayout.addRow(QLabel(' ')) self.recal_btn = QPushButton("Recalculate") self.formLayout.addRow(self.recal_btn) self.recal_btn.clicked.connect(self.recalculateDelay) self.formLayout.addRow(QLabel(' ')) self.save_btn = QPushButton("Save Curves") self.formLayout.addRow(self.save_btn) self.save_btn.clicked.connect(self.saveCorrCurves) def applyDelayChange(self): for le,key in zip(self.learray,self.delays.keys()): self.delays[key]=np.float(le.text()) print(le.text()) self.log_correlations_plot() def recalculateDelay(self): self.logCorrelations() def saveCorrCurves(self): print('Saving logs...') proc_logs={} for logname in self.delays.keys(): if self.delays[logname] !=0: shift_depth=self.depth_col+self.delays[logname] shift_depth.shape=len(shift_depth),1 # np.save('now.npy',(shift_depth,self.las[logname])) # print(shift_depth,self.las[logname]) XY=np.append(shift_depth,self.las[logname].reshape(len(shift_depth),1),axis=1) XY.shape=len(shift_depth),2 # print(XY) flexlog=FlexLog(XY) resamLog=flexlog.resampleY(self.depth_col) else: resamLog=self.las[logname] key=self.interestedKeynames[self.interestedLognames==logname][0] proc_logs[key]=resamLog proc_logs['GR']=self.las[self.grlogname] proc_logs['DEPTH']=self.depth_col proc_logs['vlues_size']=np.size(self.las.values()) proc_logs['keys']=self.interestedKeynames # proc_logs['test']='yes' bundle_file=proc_logs_bundle_file repeated=False if os.path.isfile(bundle_file): logbundle=np.load(bundle_file) print('______________________^^^^__________________________') print(len(logbundle)) for i,lb in enumerate(logbundle): if lb['vlues_size']==proc_logs['vlues_size']: repeated=True print('________________________________________________') print('It is repeated so updated but not created...') logbundle[i]=proc_logs break # else: # print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^') # print('It is not repeated so created...') else: logbundle=[] if not repeated: if (len(logbundle)>0): if proc_logs['DEPTH'][0]>logbundle[-1]['DEPTH'][0]: logbundle=np.append(logbundle,proc_logs) else: logbundle=np.append(proc_logs,logbundle) else: logbundle=np.append(proc_logs,logbundle) np.save(bundle_file,logbundle) print('Processed logs saved.. you can move on to next set...') time.sleep(2) self.close() def logCorrelations(self): print('Initiating plot widget...') self.interestedLognames=np.array([self.treeview_dict['Log'][key][0] for key in self.treeview_dict['Log']]) # self.interestedLognames=np.array(self.interestedLognames) # print('self.interestedLognames : ',self.interestedLognames) self.interestedKeynames=np.array([k for k in self.treeview_dict['Log'].keys()]) self.grlogname=self.treeview_dict['Log']['GR'][0] dcol=self.las.keys()[find_depth_indx(self.las)] self.depth_col=self.las[dcol] dt=self.depth_col[1]-self.depth_col[0] print('Spacing = ',dt) gammacol=self.las[self.grlogname] gammacol[np.isnan(gammacol)]=0 self.norm_gamma=mean_norm(gammacol)#[0:800] self.lag_corrs={} self.delays={} self.normlogs={} print('Calculating correlations...') for logname in self.interestedLognames: if logname != self.grlogname: self.log_col=self.las[logname] self.log_col[np.isnan(self.log_col)]=0 norm_blog=mean_norm(self.log_col)#[0:800] self.normlogs[logname]=norm_blog dist2look=100 delay_estimation,lag_corr= get_delay(self.norm_gamma,norm_blog,dt,corrtype='abs',dist2look=dist2look) self.delays[logname]=-delay_estimation lagcor_range=np.arange(round(len(lag_corr[0])/2)-4*dist2look,round(len(lag_corr[0])/2)+4*dist2look) self.lag_corrs[logname]=(lag_corr[0][lagcor_range],lag_corr[1][lagcor_range]) self.log_correlations_plot() self.getFormLayerFilled() def log_correlations_plot(self): self.mw = MatplotlibWidget(size=(22.0, len(self.interestedLognames)*1.6), dpi=100) self.logscrollArea.setWidget(self.mw) print('Plotting...') self.ax=[] for i,logname in enumerate(self.normlogs.keys()): self.ax.append(self.mw.getFigure().add_subplot(len(self.normlogs),1,i+1) ) l, b, w, h = self.ax[-1].get_position().bounds self.ax[-1].set_position([0.27,b+0.1,0.7,h]) # self.log_col=self.las[logname] # self.log_col[np.isnan(self.log_col)]=0 # norm_blog=mean_norm(self.log_col)#[0:800] depthb_shift=self.depth_col+self.delays[logname] self.ax[-1].plot(self.depth_col,self.normlogs[logname],'b') self.ax[-1].plot(self.depth_col,self.norm_gamma,'r') self.ax[-1].plot(depthb_shift,self.normlogs[logname],'magenta') self.ax[-1].text(self.depth_col[0]-50,0.02,logname) lenax=len(self.ax) for i,logname in enumerate(self.lag_corrs.keys()): self.ax.append(self.mw.getFigure().add_subplot(len(self.normlogs),2,lenax+i+1) ) l, b, w, h = self.ax[i].get_position().bounds self.ax[-1].set_position([0.03,b,0.21,h]) self.ax[-1].plot(self.lag_corrs[logname][0],self.lag_corrs[logname][1],'b') self.ax[-1].text(self.delays[logname],min(self.lag_corrs[logname][1]),'Delay = %.2f'%self.delays[logname]) line = self.ax[-1].axvline(x=self.delays[logname], ymin=-1, ymax = +1, linewidth=1.5, color='c') self.ax[-1].text(self.lag_corrs[logname][0][0],0.4,logname) self.mw.draw() print('Complete...') def buildLogTree(self,lases): w = LasTree() # self.lasLoadThread = LasLoadThread(files=files_w_path) self.lases=lases if (len(self.lases)>0): if (len(self.lases[0].keys())>0): self.las=self.lases[0] w.set_files(self.las.keys()) del w.treeview_dict['Log']['NA'] self.treeview_dict=w.treeview_dict w.buildTreeWidget() self.dock.setWidget(w.tree) def createDockWindows(self): self.dock = QDockWidget("Log Files", self) self.dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) # dock.setWidget(self.lastree.tree) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock)
class AitoffDock(Dock): """ Aitoff plot for displaying locations. """ def __init__(self, *args, **kwargs): log.info('') super().__init__(*args, **kwargs) self.points = None self._axis_aitoff_text_labels = [] self.mw = MatplotlibWidget() self.mw.toolbar.hide() self.subplot = self.mw.getFigure().add_subplot(111, projection="aitoff") self.subplot.grid('on') # # Add some dummy points # self.mw.draw() self.subplot_background = self.subplot.get_figure( ).canvas.copy_from_bbox(self.subplot.bbox) self.addWidget(self.mw) def clear_points(self): # # Delete the points # log.info('') if self.points is not None: self.points.remove() self.points = None self.mw.draw() # # Delete the text labels # for t in self._axis_aitoff_text_labels: t.remove() self._axis_aitoff_text_labels = [] def add_points(self, points, color='b'): log.info('') self.clear_points() converted_points = [self.convert_ra_dec(*radec) for radec in points] # # Display the points on the Aitoff projection # xs = np.array([x[0] for x in converted_points]) ys = np.array([x[1] for x in converted_points]) self.points = self.subplot.scatter(xs, ys, c='b') # # Now label the numbers on the plot to correspond to the # similar images. # converted_points = np.array(converted_points) d = distance_matrix(converted_points, converted_points) rows = set(range(converted_points.shape[0])) groups = {} while len(rows) > 0: row = rows.pop() close = np.nonzero(d[row] < 0.01)[0] rows = rows - set(list(close)) groups[row] = close for k, v in groups.items(): tt = self.subplot.text(converted_points[k][0] + 0.05, converted_points[k][1] + 0.05, ','.join([str(x + 1) for x in v])) self._axis_aitoff_text_labels.append(tt) self.subplot.draw_artist(tt) self.mw.draw() def convert_ra_dec(self, ra, dec): log.info('') if ra is not None and dec is not None: coords = SkyCoord(ra=ra, dec=dec, unit='degree') ra = coords.ra.wrap_at(180 * u.deg).radian dec = coords.dec.radian else: ra, dec = None, None return ra, dec
class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) self.loadIcons() self.setupUserInterface() self.setupSignals() self.__version__ = __version__ # Initialise variables self.imageFiles = {} self.timeData = None self.plotWin = None self.imageWin = None self.BMDchange = None self.roiNames = None def loadIcons(self): """ Load icons """ self.icons = dict([ ('BMDanalyseIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","logo.png"))), ('imageAddIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","file_add.png"))), ('imageRemIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","file_delete2.png"))), ('imageDownIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","arrow-up-2.png"))), ('imageUpIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","arrow-down-2.png"))), ('imagePrevIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","arrow-left.png"))), ('imageNextIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","arrow-right.png"))), ('roiAddIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","green-add3.png"))), ('roiRectIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","rectangularIcon.png"))), ('roiPolyIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","polygonIcon.png"))), ('roiRemIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","red_delete.png"))), ('roiSaveIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","filesave.png"))), ('roiCopyIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","file_copy.png"))), ('roiLoadIcon', QtGui.QIcon(os.path.join(absDirPath,"icons","opened-folder.png")))]) def setupUserInterface(self): """ Initialise the User Interface """ # Left frame leftFrame = QtGui.QFrame() leftFrameLayout = QtGui.QHBoxLayout() leftFrame.setLayout(leftFrameLayout) leftFrame.setLineWidth(0) leftFrame.setFrameStyle(QtGui.QFrame.Panel) leftFrameLayout.setContentsMargins(0,0,5,0) # Left frame contents self.viewMain = GraphicsLayoutWidget() # A GraphicsLayout within a GraphicsView leftFrameLayout.addWidget(self.viewMain) self.viewMain.setMinimumSize(200,200) self.vb = MultiRoiViewBox(lockAspect=True,enableMenu=True) self.viewMain.addItem(self.vb) self.vb.disableAutoRange() # Right frame self.sidePanel = SidePanel(self) # UI window (containing left and right frames) UIwindow = QtGui.QWidget(self) UIwindowLayout = QtGui.QHBoxLayout() UIwindowSplitter = QtGui.QSplitter(QtCore.Qt.Horizontal) UIwindowLayout.addWidget(UIwindowSplitter) UIwindow.setLayout(UIwindowLayout) self.setCentralWidget(UIwindow) UIwindowSplitter.addWidget(leftFrame) UIwindowSplitter.addWidget(self.sidePanel) # Application window self.setWindowTitle('BMDanalyse') self.setWindowIcon(self.icons['BMDanalyseIcon']) self.setMinimumSize(600,500) self.resize(self.minimumSize()) # Window menus self.createMenus() self.createActions() def createMenus(self): # Menus menubar = self.menuBar() self.fileMenu = menubar.addMenu('&File') self.roiMenu = menubar.addMenu('&ROIs') self.submenu = self.roiMenu.addMenu(self.icons['roiAddIcon'],"Add ROI") self.analyseMenu = menubar.addMenu('&Analyse') self.aboutMenu = menubar.addMenu('A&bout') def createActions(self): # Actions for File menu self.loadImageAct = QtGui.QAction(self.icons['imageAddIcon'], "&Load image(s)", self, shortcut="Ctrl+L") self.removeImageAct = QtGui.QAction(self.icons['imageRemIcon'], "&Remove current image", self, shortcut="Ctrl+X") self.exitAct = QtGui.QAction("&Quit", self, shortcut="Ctrl+Q",statusTip="Exit the application") fileMenuActions = [self.loadImageAct,self.removeImageAct,self.exitAct] fileMenuActFuncs = [self.loadImages,self.removeImage,self.close] for i in xrange(len(fileMenuActions)): action = fileMenuActions[i] function = fileMenuActFuncs[i] action.triggered[()].connect(function) self.fileMenu.addAction(self.loadImageAct) self.fileMenu.addAction(self.removeImageAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) # Actions for ROI menu # Submenu to add ROIs #self.addROIRectAct = QActionCustom("Rectangular",self.submenu) #self.addROIPolyAct = QActionCustom("Polygon",self.submenu) self.addROIRectAct = QtGui.QAction("Rectangular",self.submenu) self.addROIPolyAct = QtGui.QAction("Polygon",self.submenu) #self.addROIRectAct.clickEvent.connect(self.vb.addROI) #self.addROIPolyAct.clickEvent.connect(self.vb.addPolyRoiRequest) self.addROIRectAct.triggered[()].connect(self.vb.addROI) self.addROIPolyAct.triggered[()].connect(self.vb.addPolyRoiRequest) self.submenu.addAction(self.addROIRectAct) self.submenu.addAction(self.addROIPolyAct) self.addROIRectAct.setIcon(self.icons['roiRectIcon']) self.addROIPolyAct.setIcon(self.icons['roiPolyIcon']) self.addROIRectAct.setShortcut("Ctrl+Shift+R") self.addROIPolyAct.setShortcut("Ctrl+Shift+P") self.loadRoiAct = QtGui.QAction(self.icons['roiLoadIcon'], "L&oad ROI", self, shortcut="Ctrl+O") self.copyRoiAct = QtGui.QAction(self.icons['roiCopyIcon'], "&Copy ROI", self, shortcut="Ctrl+C") self.saveRoiAct = QtGui.QAction(self.icons['roiSaveIcon'], "&Save ROI", self, shortcut="Ctrl+S") self.remRoiAct = QtGui.QAction(self.icons['roiRemIcon'] , "&Remove ROI", self, shortcut="Ctrl+D") roiMenuActions = [self.loadRoiAct,self.copyRoiAct,self.saveRoiAct,self.remRoiAct] roiMenuActFuncs = [self.vb.loadROI,self.vb.copyROI,self.vb.saveROI,self.vb.removeROI] for i in xrange(len(roiMenuActions)): action = roiMenuActions[i] function = roiMenuActFuncs[i] action.triggered[()].connect(function) self.roiMenu.addAction(action) # Actions for Analyse menu self.roiAnalysisAct = QtGui.QAction("&ROI analysis", self.viewMain, shortcut="Ctrl+R",triggered=self.getBMD) self.imgAnalysisAct = QtGui.QAction("&Image analysis", self.viewMain, shortcut="Ctrl+I",triggered=self.imageAnalysis) self.analyseMenu.addAction(self.roiAnalysisAct) self.analyseMenu.addAction(self.imgAnalysisAct) # Actions for self.aboutAct = QtGui.QAction("&About", self.viewMain, shortcut='F1', triggered=self.onAbout) self.aboutMenu.addAction(self.aboutAct) def setupSignals(self): """ Setup signals """ self.sidePanel.imageFileList.itemSelectionChanged.connect(self.getImageToDisplay) self.sidePanel.buttImageAdd.clicked.connect(self.loadImages) self.sidePanel.buttImageRem.clicked.connect(self.removeImage) self.sidePanel.buttImageUp.clicked.connect(self.sidePanel.moveImageUp) self.sidePanel.buttImageDown.clicked.connect(self.sidePanel.moveImageDown) self.sidePanel.roiMenu.button1.clicked[()].connect(self.vb.addROI) self.sidePanel.roiMenu.button2.clicked[()].connect(self.vb.addPolyRoiRequest) self.sidePanel.buttRoiCopy.clicked[()].connect(self.vb.copyROI) self.sidePanel.buttRoiRem.clicked.connect(self.vb.removeROI) self.sidePanel.buttRoiLoad.clicked.connect(self.vb.loadROI) self.sidePanel.buttRoiSave.clicked.connect(self.vb.saveROI) #self.vb.sigROIchanged.connect(self.updateROItools) def onAbout(self): """ About BMDanalyse message""" author ='Michael Hogg' date ='2012 - 2013' version = self.__version__ QtGui.QMessageBox.about(self, 'About BMDanalyse', """ <b>BMDanalyse</b> <p>A simple program for the analysis of a time series of Bone Mineral Density (BMD) images.</p> <p>Used to evaluate the bone gain / loss in a number of regions of interest (ROIs) over time, typically due to bone remodelling as a result of stress shielding around an orthopaedic implant.</p> <p><table border="0" width="150"> <tr> <td>Author:</td> <td>%s</td> </tr> <tr> <td>Version:</td> <td>%s</td> </tr> <tr> <td>Date:</td> <td>%s</td> </tr> </table></p> """ % (author,version,date)) def updateROItools(self,roi=None): """ Update ROI info box in side panel """ if roi==None: self.sidePanel.updateRoiInfoBox() else: roiState = roi.getState() posx,posy = roiState['pos'] sizex,sizey = roiState['size'] angle = roiState['angle'] name = roi.name pos = '(%.3f, %.3f)' % (posx,posy) size = '(%.3f, %.3f)' % (sizex,sizey) angle = '%.3f' % angle self.sidePanel.updateRoiInfoBox(name,pos,size,angle) def loadImages(self): """ Load an image to be analysed """ newImages = {} fileNames = QtGui.QFileDialog.getOpenFileNames(self, self.tr("Load images"),QtCore.QDir.currentPath()) # Fix for PySide. PySide doesn't support QStringList types. PyQt4 getOpenFileNames returns a QStringList, whereas PySide # returns a type (the first entry being the list of filenames). if isinstance(fileNames,types.TupleType): fileNames = fileNames[0] if hasattr(QtCore,'QStringList') and isinstance(fileNames, QtCore.QStringList): fileNames = [str(i) for i in fileNames] if len(fileNames)>0: for fileName in fileNames: if fileName!='': imgarr = np.array(Image.open(str(fileName))) imgarr = imgarr.swapaxes(0,1) if imgarr.ndim==2: imgarr = imgarr[:,::-1] elif imgarr.ndim==3: imgarr = imgarr[:,::-1,:] newImages[fileName] = imgarr # Add filenames to list widget. Only add new filenames. If filename exists aready, then # it will not be added, but data will be updated for fileName in sorted(newImages.keys()): if not self.imageFiles.has_key(fileName): self.sidePanel.addImageToList(fileName) self.imageFiles[fileName] = newImages[fileName] # Show image in Main window self.vb.enableAutoRange() if self.sidePanel.imageFileList.currentRow()==-1: self.sidePanel.imageFileList.setCurrentRow(0) self.showImage(str(self.sidePanel.imageFileList.currentItem().text())) self.vb.disableAutoRange() def removeImage(self): """ Remove image from sidePanel imageFileList """ # Return if there is no image to remove if self.vb.img==None: return # Get current image in sidePanel imageFileList and remove from list currentRow = self.sidePanel.imageFileList.currentRow() image = self.sidePanel.imageFileList.takeItem(currentRow) imageName = str(image.text()) # Delete key and value from dictionary if imageName!='': del self.imageFiles[imageName] #self.imageFiles.pop(imageName,None) # Get image item in imageFileList to replace deleted image if self.sidePanel.imageFileList.count()==0: self.vb.enableAutoRange() self.vb.removeItem(self.vb.img) self.vb.showImage(None) #self.vb.img = None self.vb.disableAutoRange() else: currentRow = self.sidePanel.imageFileList.currentRow() imageName = str(self.sidePanel.imageFileList.item(currentRow).text()) self.showImage(imageName) def showImage(self,imageFilename): """ Shows image in main view """ self.arr = self.imageFiles[imageFilename] self.vb.showImage(self.arr) def getImageToDisplay(self): """ Get current item in file list and display in main view""" try: imageFilename = str(self.sidePanel.imageFileList.currentItem().text()) except: pass else: self.showImage(imageFilename) def getBMD(self): """ Get change in BMD over time (e.g. for each image) for all ROIs. Revised function that converts the list of images into a 3D array and then uses the relative position of the ROIs to the current image, self.vb.img, to get the average BMD value e.g. it doesn't use setImage to change the image in the view. This requires that all images are the same size and in the same position. """ # Return if there is no image or rois in view if self.vb.img==None or len(self.vb.rois)==0: return # Collect all images into a 3D array imageFilenames = self.sidePanel.getListOfImages() images = [self.imageFiles[str(name.text())] for name in imageFilenames] imageData = np.dstack(images) numImages = len(images) # Get BMD across image stack for each ROI numROIs = len(self.vb.rois) BMD = np.zeros((numImages,numROIs),dtype=float) self.roiNames = [] for i in xrange(numROIs): roi = self.vb.rois[i] self.roiNames.append(roi.name) arrRegion = roi.getArrayRegion(imageData,self.vb.img, axes=(0,1)) avgROIvalue = arrRegion.mean(axis=0).mean(axis=0) BMD[:,i] = avgROIvalue # Calculate the BMD change (percentage of original) tol = 1.0e-06 for i in xrange(numROIs): if abs(BMD[0,i])<tol: BMD[:,i] = 100. else: BMD[:,i] = BMD[:,i] / BMD[0,i] * 100. self.BMDchange = BMD-100. if self.timeData==None or self.timeData.size!=numImages: self.timeData = np.arange(numImages,dtype=float) # Plot results self.showResults() def imageAnalysis(self): # Generate images of BMD change if self.vb.img==None: return self.showImageWin() def sliderValueChanged(self,value): self.imageWin.sliderLabel.setText('BMD change: >= %d %s' % (value,'%')) self.setLookupTable(value) self.imageWin.vb.img2.setLookupTable(self.lut) def setLookupTable(self,val): lut = [] for i in range(256): if i > 127+val: lut.append(matplotlib.cm.jet(255)) elif i < 127-val: lut.append(matplotlib.cm.jet(0)) else: lut.append((0.0,0.0,0.0,0.0)) lut = np.array(lut)*255 self.lut = np.array(lut,dtype=np.ubyte) def createImageWin(self): self.buttMinimumSize = QtCore.QSize(70,36) self.iconSize = QtCore.QSize(24,24) if self.imageWin==None: self.imageWin = QtGui.QDialog(self, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint | \ QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowMaximizeButtonHint) self.imageWin.setWindowTitle('BMDanalyse') self.imageWin.setWindowIcon(self.icons['BMDanalyseIcon']) self.imageWin.setMinimumSize(250,500) self.imageWin.resize(self.imageWin.minimumSize()) # Create viewBox self.imageWin.glw = GraphicsLayoutWidget() # A GraphicsLayout within a GraphicsView self.imageWin.vb = ImageAnalysisViewBox(lockAspect=True,enableMenu=True) self.imageWin.vb.disableAutoRange() self.imageWin.glw.addItem(self.imageWin.vb) arr = self.imageFiles.values()[0] self.imageWin.vb.img1 = pg.ImageItem(arr,autoRange=False,autoLevels=False) self.imageWin.vb.addItem(self.imageWin.vb.img1) self.imageWin.vb.img2 = pg.ImageItem(None,autoRange=False,autoLevels=False) self.imageWin.vb.addItem(self.imageWin.vb.img2) self.imageWin.vb.autoRange() lut = [ [ int(255*val) for val in matplotlib.cm.gray(i)[:3] ] for i in xrange(256) ] lut = np.array(lut,dtype=np.ubyte) self.imageWin.vb.img1.setLookupTable(lut) # Label to show index of current image label self.imageCurrCont = QtGui.QFrame() self.imageCurrCont.setLineWidth(2) self.imageCurrCont.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised) self.imageCurrCont.setMinimumWidth(70) self.imageWin.currLabel = QtGui.QLabel("") self.imageWin.currLabel.setAlignment(QtCore.Qt.AlignHCenter) imageCurrContLayout = QtGui.QHBoxLayout() imageCurrContLayout.addWidget(self.imageWin.currLabel) self.imageCurrCont.setLayout(imageCurrContLayout) # Create buttons to select images self.imageWin.buttCont = QtGui.QWidget() self.imageWin.buttPrev = QtGui.QPushButton(self.icons['imagePrevIcon'],"") self.imageWin.buttNext = QtGui.QPushButton(self.icons['imageNextIcon'],"") self.buttLayout = QtGui.QHBoxLayout() self.buttLayout.addStretch(1) self.buttLayout.addWidget(self.imageWin.buttPrev) self.buttLayout.addWidget(self.imageCurrCont) self.buttLayout.addWidget(self.imageWin.buttNext) self.buttLayout.addStretch(1) self.imageWin.buttCont.setLayout(self.buttLayout) self.imageWin.buttPrev.setMinimumSize(self.buttMinimumSize) self.imageWin.buttNext.setMinimumSize(self.buttMinimumSize) self.imageWin.buttPrev.setIconSize(self.iconSize) self.imageWin.buttNext.setIconSize(self.iconSize) self.buttLayout.setContentsMargins(0,5,0,5) self.imageWin.buttPrev.clicked.connect(self.prevImage) self.imageWin.buttNext.clicked.connect(self.nextImage) # Create slider self.imageWin.sliderCon = QtGui.QWidget() self.imageWin.slider = QtGui.QSlider(self) self.imageWin.slider.setOrientation(QtCore.Qt.Horizontal) self.imageWin.slider.setMinimum(1) self.imageWin.slider.setMaximum(100) self.imageWin.slider.setMinimumWidth(100) self.imageWin.slider.valueChanged.connect(self.sliderValueChanged) self.imageWin.sliderLabel = QtGui.QLabel('1') self.imageWin.sliderLabel.setMinimumWidth(120) self.sliderLayout = QtGui.QHBoxLayout() self.sliderLayout.addStretch(1) self.sliderLayout.addWidget(self.imageWin.sliderLabel) self.sliderLayout.addWidget(self.imageWin.slider) self.sliderLayout.addStretch(1) self.imageWin.sliderCon.setLayout(self.sliderLayout) self.sliderLayout.setContentsMargins(0,0,0,5) # Format image window self.imageWinLayout = QtGui.QVBoxLayout() self.imageWinLayout.addWidget(self.imageWin.glw) self.imageWinLayout.addWidget(self.imageWin.buttCont) self.imageWinLayout.addWidget(self.imageWin.sliderCon) self.imageWin.setLayout(self.imageWinLayout) self.imageWin.imagesRGB = None # Show self.imageWin.show() self.imageWin.slider.setValue(10) self.sliderValueChanged(10) self.imageWinIndex = 0 def prevImage(self): #numImages = len(self.imageFiles) minIndex = 0 currIndex = self.imageWinIndex prevIndex = currIndex - 1 self.imageWinIndex = max(prevIndex,minIndex) self.updateImageWin() def nextImage(self): numImages = len(self.imageFiles) maxIndex = numImages - 1 currIndex = self.imageWinIndex nextIndex = currIndex + 1 self.imageWinIndex = min(nextIndex,maxIndex) self.updateImageWin() def updateImageWin(self): imageFilenames = self.sidePanel.getListOfImages() imageName = imageFilenames[self.imageWinIndex] self.imageWin.vb.img1.setImage(self.imageFiles[str(imageName.text())],autoLevels=False) self.imageWin.vb.img2.setImage(self.imageWin.imagesRGB[self.imageWinIndex],autoLevels=False) self.imageWin.currLabel.setText("%i / %i" % (self.imageWinIndex+1,len(imageFilenames))) def showImageWin(self): self.createImageWin() #if self.imageWin.imagesRGB == None: self.imagesBMDpercentChange() self.imagesBMDpercentChange() self.updateImageWin() def imagesBMDpercentChange(self): # Get image arrays and convert to an array of floats imageFilenames = self.sidePanel.getListOfImages() images = [ self.imageFiles[str(name.text())] for name in imageFilenames ] imagesConv = [] for img in images: image = img.copy() image[np.where(image==0)] = 1 image = image.astype(np.float) imagesConv.append(image) # Calculate percentage change and set with limits -100% to +100% imagesPercCh = [] imageInitial = imagesConv[0] for image in imagesConv: imagePercCh = (image-imageInitial)/imageInitial*100. imagePercCh[np.where(imagePercCh> 100.)] = 100. imagePercCh[np.where(imagePercCh<-100.)] = -100. imagesPercCh.append(imagePercCh) numImages = len(imagesPercCh) self.imageWin.imagesRGB = [] for i in xrange(numImages): image = imagesPercCh[i] sx,sy = image.shape #imageCh = np.zeros((sx,sy),dtype=np.float) imageRGB = image*(255/200.)+(255/2.) self.imageWin.imagesRGB.append(imageRGB) def BMDtoCSVfile(self): """ Write BMD change to csv file """ fileName = QtGui.QFileDialog.getSaveFileName(None,self.tr("Export to CSV"),QtCore.QDir.currentPath(),self.tr("CSV (*.csv)")) # Fix for PyQt/PySide compatibility. PyQt returns a QString, whereas PySide returns a tuple (first entry is filename as string) if isinstance(fileName,types.TupleType): fileName = fileName[0] if hasattr(QtCore,'QString') and isinstance(fileName, QtCore.QString): fileName = str(fileName) if not fileName=='': #if not fileName.isEmpty(): textFile = open(fileName,'w') numFrames, numROIs = self.BMDchange.shape roiNames = self.roiNames header = "%10s," % 'Time' header += ((numROIs-1)*'%10s,'+'%10s\n') % tuple(roiNames) textFile.write(header) for i in xrange(numFrames): textFile.write('%10.1f,' % self.timeData[i]) for j in xrange(numROIs): if j<numROIs-1: fmt = '%10.3f,' else: fmt = '%10.3f\n' textFile.write(fmt % self.BMDchange[i,j]) textFile.close() def showResults(self,): """ Plots BMD change using matplotlib """ # Create plot window if self.plotWin==None: self.plotWin = QtGui.QDialog(self, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint | \ QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowMaximizeButtonHint) self.plotWin.setWindowTitle('BMDanalyse') self.plotWin.setWindowIcon(self.icons['BMDanalyseIcon']) self.plotWin.setMinimumSize(600,500) self.plotWin.resize(self.minimumSize()) # Create Matplotlib widget self.mplw = MatplotlibWidget(size=(5,6)) self.fig = self.mplw.getFigure() self.editDataButton = QtGui.QPushButton('Edit plot') self.exportCSVButton = QtGui.QPushButton('Export data') self.mplw.toolbar.addWidget(self.editDataButton) self.mplw.toolbar.addWidget(self.exportCSVButton) self.editDataButton.clicked.connect(self.showEditBox) self.exportCSVButton.clicked.connect(self.BMDtoCSVfile) # Format plot window self.plotWinLayout = QtGui.QVBoxLayout() self.plotWinLayout.addWidget(self.mplw) self.plotWin.setLayout(self.plotWinLayout) self.createFigure() self.plotWin.show() self.mplw.draw() def createFigure(self): """ Creates plot of results """ self.ax1 = self.fig.add_subplot(111) self.ax1.clear() self.fig.subplots_adjust(bottom=0.15,top=0.85,left=0.15,right=0.925) numFrames, numROIs = self.BMDchange.shape t = self.timeData # Plot data for i in xrange(numROIs): roiname = self.roiNames[i] self.ax1.plot(t,self.BMDchange[:,i],'-o',label=roiname,linewidth=2.0) kwargs = dict(y=1.05) # Or kwargs = {'y':1.05} self.ax1.set_title('Change in Bone Mineral Density over time',fontsize=14,fontweight='roman',**kwargs) self.ax1.set_xlabel('Time',fontsize=10) self.ax1.set_ylabel('Change in BMD (%)',fontsize=10) self.ax1.legend(loc=0) matplotlib.pyplot.setp(self.ax1.get_xmajorticklabels(), fontsize=10) matplotlib.pyplot.setp(self.ax1.get_ymajorticklabels(), fontsize=10) matplotlib.pyplot.setp(self.ax1.get_legend().get_texts(),fontsize=10) self.ax1.grid() def fillEditBox(self): rows,cols = self.BMDchange.shape for i in xrange(rows): itmValue = '%.2f' % self.timeData[i] itm = QtGui.QTableWidgetItem(itmValue) self.tableResults.setItem(i,0,itm) for j in xrange(cols): itmValue = '%.2f' % self.BMDchange[i,j] itm = QtGui.QTableWidgetItem(itmValue) self.tableResults.setItem(i,j+1,itm) def showEditBox(self): self.plotWin.editBox = QtGui.QDialog(self.plotWin, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) self.plotWin.editBox.setWindowIcon(self.icons['BMDanalyseIcon']) self.plotWin.editBox.setWindowTitle('BMDanalyse') self.plotWin.editBox.setModal(True) # Add table layout = QtGui.QVBoxLayout() layout.setContentsMargins(10,10,10,10) layout.setSpacing(20) rows,cols = self.BMDchange.shape self.tableResults = MyTableWidget(rows,cols+1,self.plotWin.editBox) self.tableResults.verticalHeader().setVisible(True) # Set headers self.tableResults.setHorizontalHeaderItem(0,QtGui.QTableWidgetItem('Time')) for i in xrange(cols): header = QtGui.QTableWidgetItem(self.roiNames[i]) self.tableResults.setHorizontalHeaderItem(i+1,header) # Add values to table self.fillEditBox() # Set layout layout.addWidget(self.tableResults) self.buttonsFrame = QtGui.QFrame() self.buttonsLayout = QtGui.QHBoxLayout() self.buttonReset = QtGui.QPushButton('Reset') self.buttonSave = QtGui.QPushButton('Save') self.buttonClose = QtGui.QPushButton('Cancel') self.buttonReset.setFixedWidth(50) self.buttonSave.setFixedWidth(50) self.buttonClose.setFixedWidth(50) self.buttonClose.clicked.connect(self.plotWin.editBox.close) self.buttonSave.clicked.connect(self.updateTableValues) self.buttonReset.clicked.connect(self.fillEditBox) self.buttonsLayout.addStretch(1) self.buttonsLayout.addWidget(self.buttonReset) self.buttonsLayout.addWidget(self.buttonSave) self.buttonsLayout.addWidget(self.buttonClose) self.buttonsLayout.setContentsMargins(0,0,0,0) self.buttonsFrame.setLayout(self.buttonsLayout) layout.addWidget(self.buttonsFrame) self.plotWin.editBox.setLayout(layout) self.plotWin.editBox.setMaximumSize(layout.sizeHint()) self.plotWin.editBox.show() def updateTableValues(self): # Create temporary arrays timeData = self.timeData.copy() BMDchange = self.BMDchange.copy() # Put the values from the tables into the temporary arrays rows = self.tableResults.rowCount() cols = self.tableResults.columnCount() for r in xrange(rows): for c in xrange(cols): item = self.tableResults.item(r,c) itemValue = float(item.text()) if c==0: timeData[r] = itemValue else: BMDchange[r,c-1] = itemValue # Check that time values are in increasing order. If so, then update arrays if any(np.diff(timeData)<=0): self.errorMessage = QtGui.QMessageBox() self.errorMessage.setWindowIcon(self.icons['BMDanalyseIcon']) self.errorMessage.setWindowTitle('BMDanalyse') self.errorMessage.setText('Input error: Time values should be in order of increasing value') self.errorMessage.setIcon(QtGui.QMessageBox.Warning) self.errorMessage.open() else: self.timeData = timeData self.BMDchange = BMDchange self.createFigure() self.mplw.draw() self.plotWin.editBox.close()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setGeometry(100, 100, 600, 900) self.centralWidget = QWidget() # GrphicsWidget() layout = QHBoxLayout(self.centralWidget) self.scrollArea = QScrollArea(self) # gwidget=GrphicsWidget() self.mw = MatplotlibWidget(size=(3.0, 40.0), dpi=100) lplot = self.mw.getFigure().add_subplot(121) # print(dir(self.mw.getFigure())) # self.mw.getFigure().set_axes([0.85, 0.1, 0.075, 0.8]) self.ax = self.mw.getFigure().gca() self.ax.set_position([0.1, 0.05, 0.8, 0.94]) self.ax.invert_yaxis() # l, b, w, h = self.ax.get_position().bounds # print(l, b, w, h) self.mw.draw() # self.plotlayout.addWidget(self.mw) self.scrollArea.setWidget(self.mw) layout.addWidget(self.scrollArea) self.setCentralWidget(self.centralWidget) self.lastree = LasTree() self.logtree = LasTree() self.wellLoad() self.logtree.set_files(['GR', 'BS']) self.logtree.buildTreeWidget() self.logtree.tree.itemSelectionChanged.connect(self.logPlot) self.createDockWindows() # self.logFileList.itemSelectionChanged.connect(self.lasLoad) # if not self.las_just_selected: # self.logList.itemSelectionChanged.connect(self.logPlot) self.setWindowTitle("Loggy") # self.newLetter() def wellLoad(self): self.wellFolder = r'D:\Ameyem Office\Projects\Cairn\W1\LAS\\' self.files = np.array(os.listdir(self.wellFolder)[:]) files_w_path = [self.wellFolder + f for f in self.files] cols = [] self.files = np.array(os.listdir(self.wellFolder)[:]) self.lastree.set_files(self.files) self.lastree.buildTreeWidget() self.lastree.tree.itemSelectionChanged.connect(self.lasLoad) self.lasLoadThread = LasLoadThread(files=files_w_path) # def lasBackgroundLoad(): def lasLoad(self): las_name = self.lastree.tree.selectedItems()[0].text( 0) #self.logFileList.selectedItems()[0].text() if las_name in ['TVD', 'MD', 'LWD', 'WireLine']: return findex = np.where(self.files == las_name)[0][0] # print(findex) Loaded = False while (not Loaded): if (findex < len(self.lasLoadThread.Lases)): self.las = self.lasLoadThread.Lases[findex] Loaded = True self.logtree.tree.clear() # print('hi') else: # print('hello') # self.logtree.addItems(['Loading....']) time.sleep(1) if len(self.logtree.tree.selectedItems()) > 0: item = self.logtree.tree.selectedItems()[0] # print(dir(item)) item.setSelected = False if not (len(self.las.keys()) < 1): # self.logtree = LasTree(self.las.keys()) self.logtree.set_files(self.las.keys()) self.logtree.buildTreeWidget() dcol = self.las.keys()[find_depth_indx(self.las)] self.depth_col = str_array2floats(self.las[dcol]) # else: # self.las_just_selected = True def logPlot(self): # print(self.mw.getFigure().) # pass # if not self.las_just_selected: if len(self.logtree.tree.selectedItems()) > 0: keycol = self.logtree.tree.selectedItems()[0].text(0) try: self.log_col = str_array2floats(self.las[keycol]) self.ax = LogPlot.basicPlot(self.ax, self.depth_col, self.log_col, lcolor='#800000') except: print('Unable to convert log to floats') self.mw.draw() def set_category(self): # qt_app = QApplication(sys.argv) mnomonicsfile = self.wellFolder + '../../mnemonics.txt' # print(self.logtree.treeview_dict) # set_category_app = Categorize(self.logtree.treeview_dict,mnomonicsfile) print('*************************************************') print(self.logtree.treeview_dict) category_window = Categorize(self) category_window.set_params(self.logtree, mnomonicsfile) category_window.show() # self.logtree.tree.clear() # self.logtree.buildTreeWidget() # set_category_app.run() # self.logtree.buildTreeWidget() def createDockWindows(self): dock = QDockWidget("Log Files", self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) dock.setWidget(self.lastree.tree) # self.addDockWidget(Qt.LeftDockWidgetArea, dock) self.set_category_button = QPushButton('Set Category', self) # self.layout.addWidget(self.logtree.tree) dock = QDockWidget("Set", self) dock.setWidget(self.set_category_button) self.addDockWidget(Qt.LeftDockWidgetArea, dock) dock = QDockWidget("Logs", self) dock.setWidget(self.logtree.tree) self.addDockWidget(Qt.LeftDockWidgetArea, dock) self.set_category_button.clicked.connect(self.set_category)
class SplatalogueAssignmentWindow(QDialog): FACE_COLOR = "#626262" EXPERIMENT_EDGE_COLOR = 'black' def __init__(self, experiment, chemical, selection_widget): super(SplatalogueAssignmentWindow, self).__init__() self.setWindowIcon(QIcon(QPixmap(images.LOGO_ICON))) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowTitle("Splatalogue Assignment Window") self.resize(1500, 750) ''' Data ''' self.experiment = experiment self.chemical = chemical ''' Widgets ''' self.info_widget = SplatalogueInfoWidget(chemical) self.table_widget = QTableWidget() self.matplot_widget = MatplotlibWidget() self.selection_widget = selection_widget '''Colors''' self.color___experiment_edge = SplatalogueAssignmentWindow.EXPERIMENT_EDGE_COLOR self.color___face_color = SplatalogueAssignmentWindow.FACE_COLOR self.__setup__() def validate(self): # Validate all lines for now for line in self.chemical.lines: line.validated = True match = self.chemical.validate_chemical(self.experiment) self.selection_widget.add_row(match) self.close() self.setResult(1) def __setup__(self): self.setStyleSheet( "background-color: rgb(48, 48, 48);\ngridline-color: rgb(195, 195, 195);\ncolor: rgb(255, 255, 255);\n") self.matplot_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__setup_layout() self.__populate_graph() self.__populate_table() def __setup_layout(self): outer_layout = QVBoxLayout() ''' Inner Grid Layout ''' layout = QGridLayout() left_layout = QVBoxLayout() left_layout.addWidget(self.info_widget) left_layout.addWidget(self.table_widget) layout.addLayout(left_layout, 0, 0) layout.addWidget(self.matplot_widget, 0, 1) ''' Bottom Frame ''' bottom_frame = QFrame() frame_layout = QHBoxLayout() # --- Widgets --- # validate_btn = QPushButton(QIcon(images.VALIDATE_ICON), "Validate") cancel_btn = QPushButton("Cancel") # -- Settings -- # bottom_frame.setFrameShadow(QFrame.Raised) bottom_frame.setFrameShape(QFrame.StyledPanel) # -- Add Widgets -- # frame_layout.addSpacerItem(QSpacerItem(20, 40, QSizePolicy.Expanding, QSizePolicy.Minimum)) frame_layout.addWidget(validate_btn) frame_layout.addWidget(cancel_btn) bottom_frame.setLayout(frame_layout) # -- Button Connections -- # validate_btn.clicked.connect(self.validate) cancel_btn.clicked.connect(self.close) ''' Add ''' outer_layout.addLayout(layout) outer_layout.addWidget(bottom_frame) self.setLayout(outer_layout) def __populate_graph(self): """ :return: """ figure = self.matplot_widget.getFigure() figure.set_facecolor(self.color___face_color) ''' Experiment Subplot ''' frequencies, intensities = self.experiment.get_experiment_frequencies_intensities_list() max_freq = max(frequencies) min_freq = min(frequencies) self.subplot_1 = figure.add_subplot(311, axisbg='white', title='Experiment: ' + self.experiment.name + ' Peaks') self.subplot_1.bar(frequencies, intensities, width=0.02, edgecolor=self.color___experiment_edge) ''' Matches Subplot ''' self.subplot_2 = figure.add_subplot(312, axisbg='white', sharex=self.subplot_1) for l in self.chemical.lines: # if l.intensity <= 0: self.subplot_2.bar(l.frequency, 1, width=0.02, edgecolor='blue') # else: # self.subplot_2.bar(l.frequency, l.intensity, width=0.02, edgecolor='blue') ''' Chemical Subplot ''' self.subplot_3 = figure.add_subplot(313, axisbg='white', sharex=self.subplot_1) lines = self.chemical.get_all_lines(min_freq, max_freq) for l in lines: if l.intensity is None: # or l.intensity <= 1: self.subplot_3.bar(l.frequency, 1, width=0.02, edgecolor='black') else: self.subplot_3.bar(l.frequency, l.intensity, width=0.02, edgecolor='blue') ''' Adjustments ''' # self.matplot_widget.getFigure().subplots_adjust(top=0.95, # bottom = 0.07, # left = 0.05, # right = 0.97, # hspace=0.35,) self.matplot_widget.draw() def __populate_table(self): """ :return: """ row_count = self.chemical.N column_count = 5 # Format Table self.table_widget.setRowCount(row_count) self.table_widget.setColumnCount(column_count) self.table_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding) self.table_widget.setSortingEnabled(True) # Set Header Label self.table_widget.setHorizontalHeaderLabels(["EXP-Frequency", "Frequency", "Intensity", \ "Units", "Linelist", ]) for i in range(0, row_count): # Get Row Data # exp_freq = self.chemical.matched_lines[i] exp_freq = get_frequency(conn, self.chemical.matched_lines[i]) frequency = self.chemical.lines[i].frequency intensity = self.chemical.lines[i].intensity line_list = self.chemical.lines[i].line_list units = self.chemical.lines[i].units # Convert Data to QTableWidgetItem exp_freq_item = QTableWidgetItem(str(exp_freq)) frequency_item = QTableWidgetItem(str(frequency)) intensity_item = QTableWidgetItem(str(intensity)) line_list_item = QTableWidgetItem(str(line_list)) units_item = QTableWidgetItem(str(units)) self.table_widget.setItem(i, 0, exp_freq_item) self.table_widget.setItem(i, 1, frequency_item) self.table_widget.setItem(i, 2, intensity_item) self.table_widget.setItem(i, 3, units_item) self.table_widget.setItem(i, 4, line_list_item) # --- Set Size Policy --- # self.table_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding) self.table_widget.setMaximumWidth(600) self.table_widget.setFixedWidth(500) self.table_widget.resizeColumnsToContents() self.table_widget.resizeRowsToContents() # -- Additional Options -- # self.table_widget.setEditTriggers(QTableWidget.NoEditTriggers) # disallow in-table editing
class VESViewer(QMainWindow): curve = [] Image = [] listitem = [] imfolder = r"D:\Ameyem Office\Geoservices\Digitizer\\" zoom_fact = 1 fileName = '' pick_type = 'digitize' depth_pix_lims = [] prop_pix_lims = [] init_thicks = [1, 10, 15, 175] init_res = [20, 4, 60, 200, 2000] proj_path = r'D:/Ameyem Office/Projects/Electric surveys/Easwar files/Mahoba/mohaba.resp/' def __init__(self): super(VESViewer, self).__init__() self.createActions() self.createMenus() win = QWidget() self.setCentralWidget(win) self.plotlayout = QHBoxLayout(self) self.init_m = np.append(self.init_res, self.init_thicks) self.datapath = self.proj_path + 'VESData/' # creates plot # self.plot = pg.PlotWidget() self.mw = MatplotlibWidget() self.subplot1 = self.mw.getFigure().add_subplot(121) self.subplot2 = self.mw.getFigure().add_subplot(122) self.mw.draw() self.plotlayout.addWidget(self.mw) # mltoolbar=self.mw.get_ToolBar() layout = BorderLayout() layout.add(self.plotlayout, BorderLayout.Center) self.list_w = QListWidget() # self.listitem.append(QListWidgetItem('Welcome to ResLayer!!!')) self.list_w.setFrameStyle(QFrame.Box | QFrame.Raised) layout.add(QWidgetItem(self.list_w), BorderLayout.West) win.setLayout(layout) # self.list_w.addItem(self.listitem[0]) # self.list_w.itemClicked.connect(self.OnSingleClick) self.list_w.itemSelectionChanged.connect(self.OnSingleClick) self.setWindowTitle("Border Layout") mypen = pg.mkPen('y', width=1) # self.curve = self.plot.plot(x=[], y=[], pen=mypen) # self.plot.addItem(self.curve) files = os.listdir(self.datapath) for f in files: self.listitem.append(QListWidgetItem(f[:-4])) self.list_w.addItem(self.listitem[-1]) self.vdf = pd.read_csv(self.datapath + files[0], header=None) self.plotVES() def onMouseMoved(self, point): # print(point) p = self.plot.plotItem.vb.mapSceneToView(point) self.statusBar().showMessage("{}-{}".format(p.x(), p.y())) def about(self): QMessageBox.about( self, "About Image Viewer", "<p>The <b>Image Viewer</b> example shows how to combine " "(QScrollArea.widgetResizable), can be used to implement " "zooming and scaling features.</p>" "<p>In addition the example shows how to use QPainter to " "print an image.</p>") def dialog_critical(self, s): dlg = QMessageBox(self) dlg.setText(s) dlg.setIcon(QMessageBox.Critical) dlg.show() def file_open(self): # path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "CSV documents (*.dat);All files (*.*)") path = r'D:/Ameyem Office/Projects/Electric surveys/Easwar files/Mahoba/VES_data/112.dat' try: self.vdf = pd.read_csv(path, header=None) except Exception as e: self.dialog_critical(str(e)) else: self.path = path self.plotVES(self.vdf) def createActions(self): self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close) self.openFileAct = QAction("&Open", self, shortcut="Ctrl+O", triggered=self.file_open) self.aboutAct = QAction("&About", self, triggered=self.about) self.do_inversion_action = QAction(QIcon( os.path.join('ves_imgs', 'invert-tool.png')), "&Invert", self, shortcut="Ctrl+I", triggered=self.doVESinv) self.do_inversion_action.setStatusTip("Run inversion") # self.do_inversion_action.triggered.connect(self.doVESinv) # openFileAct = QAction(QIcon(os.path.join('images', 'blue-folder-open-document.png')), "Open file...", self) # open_file_action.setStatusTip("Open file") # open_file_action.triggered.connect(self.file_open) # file_menu.addAction(open_file_action) # file_toolbar.addAction(open_file_action) def createMenus(self): self.fileMenu = QMenu("&File", self) # self.fileMenu.addAction(self.openAct) # self.fileMenu.addAction(self.printAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.openFileAct) self.fileMenu.addAction(self.exitAct) self.helpMenu = QMenu("&Help", self) self.helpMenu.addAction(self.aboutAct) # self.helpMenu.addAction(self.aboutQtAct) self.menuBar().addMenu(self.fileMenu) # self.menuBar().addMenu(self.viewMenu) # self.menuBar().addMenu(self.digitizeMenu) self.menuBar().addMenu(self.helpMenu) self.file_toolbar = QToolBar("File") self.file_toolbar.setIconSize(QSize(24, 24)) self.addToolBar(self.file_toolbar) self.fileMenu.addAction(self.do_inversion_action) self.file_toolbar.addAction(self.do_inversion_action) def OnSingleClick(self): print('\nItems selected...', end=' ') # self.curve=self.plot.plot(x=[0.9 ,300], y=[1, 10000], size=1, pen=pg.mkPen(None),clear=True) # self.plot2.plot(x=[0.9 ,300], y=[1, 10000], size=1, pen=pg.mkPen(None),clear=True) for item in self.list_w.selectedItems(): vespoint_name = item.text() print(vespoint_name, end=' ') self.vdf = pd.read_csv(self.datapath + vespoint_name + '.dat', header=None) # # self.plot.close() # # self.plot = pg.PlotWidget() self.plotVES() # self.plotLocationPanel(locations4panel) def plotVES(self): # self.curve= self.subplot1.cla() self.subplot1.loglog(self.vdf[0], self.vdf[1], '*', basex=10) # self.subplot1.grid(True) self.subplot1.grid(b=True, which='major', color='grey', linestyle='-') self.subplot1.grid(b=True, which='minor') self.subplot1.set_title('Apparent resisitivity log ') self.subplot1.set_xlabel('Distance (m)') self.subplot1.set_ylabel('Apparent Resistivity (ohm-m)') self.subplot1.set_xlim(1, 1000) self.subplot1.set_ylim(1, 10000) self.subplot2.cla() # self.subplot2.loglog(self.vdf[0],self.vdf[1],'*', basex=10) # self.subplot1.grid(True) lr = int(1 + len(self.init_m) / 2) lt = int(len(self.init_m) / 2) r = np.append(self.init_m[:lr], np.nan) t = np.append(np.append(0.01, self.init_m[-lt:]), 1000) self.subplot2.grid(b=True, which='major', color='grey', linestyle='-') self.subplot2.grid(b=True, which='minor') self.subplot2.set_title('Layer model') self.subplot2.set_xlabel('Resistivity (ohm-m)') self.subplot2.set_ylabel('Depth (m)') # self.subplot2.invert_yaxis() self.subplot2.set_xlim(1, 6000) self.subplot2.set_ylim(0.1, 500) self.subplot2.step(r, np.cumsum(t), 'k', dashes=[5, 5, 5, 5], linewidth=2) self.subplot2.set_xscale('log') self.subplot2.set_yscale('log') self.subplot2.invert_yaxis() self.mw.draw() def VESInvplot(self, x, roa, roaf, m, mf): lr = int(1 + len(mf) / 2) lt = int(len(mf) / 2) rf = np.append(mf[:lr], np.nan) tf = np.append(np.append(0.01, mf[-lt:]), 1000) self.subplot1.loglog(x, roaf, '-r', basex=10) self.subplot2.step(rf, np.cumsum(tf), 'r') self.mw.draw() def doVESinv(self): method = 'ghosh' x = self.vdf[0].values roa = self.vdf[1].values # ri= [100, 30, 20., 4.]; # ti =[9, 61 ,50]; m = np.append(self.init_res, self.init_thicks) mf, roaf = VES1dInv(m, x, roa, method=method, maxiteration=100) # VESplot(self.mw,x,roa,roaf,m,mf) self.VESInvplot(x, roa, roaf, m, mf)
class PlotWidget(QWidget): """ This class inherited from pyqtgraphs Plotwidget and MatplotlibWidget and adds additional compononets like: 1) Cross-hair to view X, Y coordinates 2) Changing plot-styles interactively """ def __init__(self,parent=None,matplotlib=False): QWidget.__init__(self,parent) self.matplotlib=matplotlib self.mplPlotData={} self.mplErrorData={} self.xLabelFontSize=10 self.yLabelFontSize=10 self.titleFontSize=12 self.xLabel='x' self.yLabel='y' self.title='Plot' self.createPlotWidget() self.data={} self.dataErrPos={} self.dataErrNeg={} self.dataErr={} self.err={} self.data_num=0 self.yerr={} self.fit={} def createPlotWidget(self): """ Creates the plotWidget """ self.vbLayout=QVBoxLayout(self) self.plotLayout=pg.LayoutWidget() self.vbLayout.addWidget(self.plotLayout) row=0 col=0 lineWidthLabel=QLabel('Line width') self.lineWidthLineEdit=QLineEdit('2') self.lineWidthLineEdit.returnPressed.connect(self.updatePlot) pointSizeLabel=QLabel('Point size') self.pointSizeLineEdit=QLineEdit('5') self.pointSizeLineEdit.returnPressed.connect(self.updatePlot) self.bgCheckBox=QCheckBox('White BG') self.bgCheckBox.stateChanged.connect(self.bgCheckBoxChanged) self.errorbarCheckBox=QCheckBox('Errorbar') self.errorbarCheckBox.stateChanged.connect(self.errorbarChanged) self.plotLayout.addWidget(lineWidthLabel,row=row,col=col) col+=1 self.plotLayout.addWidget(self.lineWidthLineEdit,row=row,col=col) col+=1 self.plotLayout.addWidget(pointSizeLabel,row=row,col=col) col+=1 self.plotLayout.addWidget(self.pointSizeLineEdit,row=row,col=col) col+=1 self.plotLayout.addWidget(self.bgCheckBox,row=row,col=col) col+=1 self.plotLayout.addWidget(self.errorbarCheckBox,row=row,col=col) col=0 row+=1 if self.matplotlib: self.plotWidget=MatplotlibWidget() self.subplot=self.plotWidget.getFigure().add_subplot(111) self.plotWidget.fig.set_tight_layout(True) self.plotWidget.draw() else: self.plotWidget=pg.PlotWidget() self.plotWidget.getPlotItem().vb.scene().sigMouseMoved.connect(self.mouseMoved) self.legendItem=pg.LegendItem(offset=(0.0,1.0)) self.legendItem.setParentItem(self.plotWidget.getPlotItem()) self.plotLayout.addWidget(self.plotWidget,row=row,col=col,colspan=6) row+=1 col=0 self.crosshairLabel=QLabel(u'X={: .5f} , y={: .5f}'.format(0.0,0.0)) self.xLogCheckBox=QCheckBox('LogX') self.xLogCheckBox.setTristate(False) self.xLogCheckBox.stateChanged.connect(self.updatePlot) self.yLogCheckBox=QCheckBox('LogY') self.yLogCheckBox.setTristate(False) self.yLogCheckBox.stateChanged.connect(self.updatePlot) if not self.matplotlib: self.plotLayout.addWidget(self.crosshairLabel,row=row,col=col,colspan=4) self.plotLayout.addWidget(self.xLogCheckBox,row=row,col=4) self.plotLayout.addWidget(self.yLogCheckBox,row=row,col=5) def bgCheckBoxChanged(self): if self.bgCheckBox.isChecked(): self.plotWidget.setBackground('w') self.plotWidget.getAxis('left').setPen('k') self.plotWidget.getAxis('left').setTextPen('k') self.plotWidget.getAxis('bottom').setPen('k') self.plotWidget.getAxis('bottom').setTextPen('k') else: self.plotWidget.setBackground('k') self.plotWidget.getAxis('left').setPen('w') self.plotWidget.getAxis('left').setTextPen('w') self.plotWidget.getAxis('bottom').setPen('w') self.plotWidget.getAxis('bottom').setTextPen('w') def mouseMoved(self,pos): try: pointer=self.plotWidget.getPlotItem().vb.mapSceneToView(pos) x,y=pointer.x(),pointer.y() if self.plotWidget.getPlotItem().ctrl.logXCheck.isChecked(): x=10**x if self.plotWidget.getPlotItem().ctrl.logYCheck.isChecked(): y=10**y self.crosshairLabel.setText('X={: 10.5f}, Y={: 10.5e}'.format(x,y)) # if x>1e-3 and y>1e-3: # self.crosshairLabel.setText(u'X={: .5f} , Y={: .5f}'.format(x,y)) # if x<1e-3 and y>1e-3: # self.crosshairLabel.setText(u'X={: .3e} , Y={: .5f}'.format(x,y)) # if x>1e-3 and y<1e-3: # self.crosshairLabel.setText(u'X={: .5f} , Y={: .3e}'.format(x,y)) # if x<1e-3 and y<1e-3: # self.crosshairLabel.setText(u'X={: .3e} , Y={: .3e}'.format(x,y)) except: pass #self.crosshairLabel.setText(u'X=%+0.5f, Y=%+0.5e'%(x,y)) def add_data(self,x,y,yerr=None,name=None,fit=False,color=None): """ Adds data into the plot where: x=Array of x-values y=Array of y-values yerr=Array of yerr-values. If None yerr will be set to sqrt(y) name=any string to be used for the key to put the data fit= True if the data corresponds to a fit """ if not (isinstance(yerr,list) or isinstance(yerr,np.ndarray)): yerr=np.ones_like(y) x=np.array(x) y=np.array(y) if len(x)==len(y) and len(y)==len(yerr): if name is None: dname=str(self.data_num) else: dname=name if np.all(yerr==1): self.yerr[dname]=False else: self.yerr[dname]=True self.fit[dname]=fit if dname in self.data.keys(): if color is None: color=self.data[dname].opts['symbolPen'].color() pen=pg.mkPen(color=color,width=float(self.lineWidthLineEdit.text())) symbol='o' if self.fit[dname]: symbol=None self.data[dname].setData(x,y,pen=pen,symbol=symbol,symbolSize=float(self.pointSizeLineEdit.text()),symbolPen=pg.mkPen(color=color),symbolBrush=pg.mkBrush(color=color)) #self.data[dname].setPen(pg.mkPen(color=pg.intColor(np.random.choice(range(0,210),1)[0]),width=int(self.lineWidthLineEdit.text()))) #if self.errorbarCheckBox.isChecked(): # self.dataErrPos[dname].setData(x,np.where(y+yerr/2.0>0,y+yerr/2.0,y)) # self.dataErrNeg[dname].setData(x,np.where(y-yerr/2.0>0,y-yerr/2.0,y)) self.err[dname]= yerr self.dataErr[dname].setData(x=x, y=y, top=self.err[dname], bottom=self.err[dname], pen='w')# beam=min(np.abs(x))*0.01*float(self.pointSizeLineEdit.text()),pen='w') #self.dataErr[dname].setCurves(self.dataErrPos[dname],self.dataErrNeg[dname]) else: if color is None: color=pg.intColor(np.random.choice(range(0,210),1)[0]) #color=self.data[dname].opts['pen'].color() pen=pg.mkPen(color=color,width=float(self.lineWidthLineEdit.text())) symbol='o' if self.fit[dname]: symbol=None self.data[dname]=pg.PlotDataItem(x,y,pen=pen,symbol=symbol,symbolSize=float(self.pointSizeLineEdit.text()),symbolPen=pg.mkPen(color=color),symbolBrush=pg.mkBrush(color=color)) self.dataErr[dname] = pg.ErrorBarItem() self.err[dname]=yerr self.dataErr[dname].setData(x=x,y=y,top=self.err[dname],bottom=self.err[dname], pen='w')# beam=min(np.abs(x))*0.01*float(self.pointSizeLineEdit.text()),pen='w') self.data[dname].curve.setClickable(True,width=10) self.data[dname].sigClicked.connect(self.colorChanged) #if self.errorbarCheckBox.isChecked(): # self.dataErrPos[dname]=pg.PlotDataItem(x,np.where(y+yerr/2.0>0,y+yerr/2.0,y)) # self.dataErrNeg[dname]=pg.PlotDataItem(x,np.where(y-yerr/2.0>0,y-yerr/2.0,y)) #self.dataErr[dname]=pg.FillBetweenItem(curve1=self.dataErrPos[dname],curve2=self.dataErrNeg[dname],brush=pg.mkBrush(color=pg.hsvColor(1.0,sat=0.0,alpha=0.2))) self.data_num+=1 #if len(x)>1: self.Plot([dname]) return True else: QMessageBox.warning(self,'Data error','The dimensions of x, y or yerr are not matching',QMessageBox.Ok) return False def colorChanged(self,item): """ Color of the item changed """ color=item.opts['symbolPen'].color() newcolor=QColorDialog.getColor(initial=color) if newcolor.isValid(): #if self.lineWidthLineEdit.text()!='0': item.setPen(pg.mkPen(color=newcolor,width=int(self.lineWidthLineEdit.text()))) if self.pointSizeLineEdit.text()!='0': item.setSymbolBrush(pg.mkBrush(color=newcolor)) item.setSymbolPen(pg.mkPen(color=newcolor)) def errorbarChanged(self): """ Updates the plot checking the Errorbar is checked or not """ try: self.Plot(self.selDataNames) except: pass def Plot(self,datanames): """ Plots all the data in the memory with errorbars where: datanames is the list of datanames """ self.selDataNames=datanames if self.matplotlib: #Plotting with matplotlib names=list(self.mplPlotData.keys()) for name in names: if name not in self.selDataNames: self.mplPlotData[name].remove() del self.mplPlotData[name] try: self.mplErrorData[name].remove() del self.mplErrorData[name] except: pass self.xLabel=self.subplot.get_xlabel() self.yLabel=self.subplot.get_ylabel() self.title=self.subplot.get_title() #self.subplot.axes.cla() for dname in self.selDataNames: if self.fit[dname]: plot_type = '-' else: plot_type = '.-' if self.errorbarCheckBox.checkState()==Qt.Checked: try: self.mplPlotData[dname].set_xdata(self.data[dname].xData) self.mplPlotData[dname].set_ydata(self.data[dname].yData) self.mplPlotData[dname].set_markersize(int(self.pointSizeLineEdit.text())) self.mplPlotData[dname].set_linewidth(int(self.lineWidthLineEdit.text())) self.mplErrorData[dname].set_segments(np.array([[x,yt],[x,yb]]) for x,yt,yb in zip(self.data[dname].xData,self.dataErrPos[dname].yData,self.dataErrNeg[dname].yData)) self.mplErrorData[dname].set_linewidth(2) except: ln,err,bar =self.subplot.errorbar(self.data[dname].xData,self.data[dname].yData,xerr=None,yerr=self.dataErr[dname].opts['top']*2,fmt=plot_type,markersize=int(self.pointSizeLineEdit.text()),linewidth=int(self.lineWidthLineEdit.text()),label=dname) self.mplPlotData[dname]=ln self.mplErrorData[dname],=bar else: try: self.mplPlotData[dname].set_xdata(self.data[dname].xData) self.mplPlotData[dname].set_ydata(self.data[dname].yData) self.mplPlotData[dname].set_markersize(int(self.pointSizeLineEdit.text())) self.mplPlotData[dname].set_linewidth(int(self.lineWidthLineEdit.text())) except: self.mplPlotData[dname], =self.subplot.plot(self.data[dname].xData,self.data[dname].yData,plot_type,markersize=int(self.pointSizeLineEdit.text()),linewidth=int(self.lineWidthLineEdit.text()),label=dname) if self.xLogCheckBox.checkState()==Qt.Checked: self.subplot.set_xscale('log') else: self.subplot.set_xscale('linear') if self.yLogCheckBox.checkState()==Qt.Checked: self.subplot.set_yscale('log') else: self.subplot.set_yscale('linear') self.subplot.set_xlabel(self.xLabel,fontsize=self.xLabelFontSize) self.subplot.set_ylabel(self.yLabel,fontsize=self.yLabelFontSize) self.subplot.set_title(self.title,fontsize=self.titleFontSize) # try: # self.leg.draggable() # except: self.leg=self.subplot.legend() self.leg.set_draggable(True) self.plotWidget.fig.set_tight_layout(True) self.plotWidget.draw() else: self.plotWidget.plotItem.setLogMode(x=False,y=False) self.plotWidget.clear() for names in self.data.keys(): self.legendItem.removeItem(names) xlog_res=True ylog_res=True for dname in self.selDataNames: if np.all(self.data[dname].yData==0) and self.yLogCheckBox.checkState()==Qt.Checked: #This step is necessary for checking the zero values QMessageBox.warning(self,'Zero error','All the yData are zeros. So Cannot plot Logarithm of yData for %s'%dname,QMessageBox.Ok) ylog_res=ylog_res and False if not ylog_res: self.yLogCheckBox.stateChanged.disconnect(self.updatePlot) self.yLogCheckBox.setCheckState(Qt.Unchecked) self.yLogCheckBox.stateChanged.connect(self.updatePlot) if np.all(self.data[dname].xData==0) and self.xLogCheckBox.checkState()==Qt.Checked: QMessageBox.warning(self,'Zero error','All the xData are zeros. So Cannot plot Logarithm of xData for %s'%dname,QMessageBox.Ok) xlog_res=xlog_res and False if not xlog_res: self.xLogCheckBox.stateChanged.disconnect(self.updatePlot) self.xLogCheckBox.setCheckState(Qt.Unchecked) self.xLogCheckBox.stateChanged.connect(self.updatePlot) self.plotWidget.addItem(self.data[dname]) if self.errorbarCheckBox.isChecked() and self.yerr[dname]: x=self.data[dname].xData y=self.data[dname].yData top=copy.copy(self.err[dname]) bottom= copy.copy(self.err[dname]) if self.xLogCheckBox.checkState() == Qt.Checked: x=np.log10(x) if self.yLogCheckBox.checkState() == Qt.Checked: top=np.log10(1+top/y) bottom=np.log10(y/(y-bottom)) y = np.log10(y) self.dataErr[dname].setData(x=x,y=y,top=top,bottom=bottom,pen='w')#beam=min(np.abs(x))*0.01*float(self.pointSizeLineEdit.text()),pen='w') self.plotWidget.addItem(self.dataErr[dname]) # self.plotWidget.addItem(self.dataErrPos[dname]) # self.plotWidget.addItem(self.dataErrNeg[dname]) #self.plotWidget.addItem(self.dataErr[dname]) #self.dataErr[dname].setCurves(self.dataErrPos[dname],self.dataErrNeg[dname]) self.legendItem.addItem(self.data[dname],dname) if self.xLogCheckBox.checkState()==Qt.Checked: self.plotWidget.plotItem.setLogMode(x=True) else: self.plotWidget.plotItem.setLogMode(x=False) if self.yLogCheckBox.checkState()==Qt.Checked: self.plotWidget.plotItem.setLogMode(y=True) else: self.plotWidget.plotItem.setLogMode(y=False) def remove_data(self,datanames): for dname in datanames: if self.matplotlib: self.mplPlotData[dname].remove() del self.mplPlotData[dname] if self.errorbarCheckBox.isChecked() and self.yerr[dname]: self.mplErrorData[dname].remove() del self.mplErrorData[dname] else: self.plotWidget.removeItem(self.data[dname]) self.legendItem.removeItem(dname) if self.errorbarCheckBox.isChecked() and self.yerr[dname]: self.plotWidget.removeItem(self.dataErr[dname]) # self.plotWidget.removeItem(self.dataErrPos[dname]) # self.plotWidget.removeItem(self.dataErrNeg[dname]) del self.data[dname] del self.dataErr[dname] # del self.dataErrPos[dname] # del self.dataErrNeg[dname] def updatePlot(self): try: for dname in self.selDataNames: if self.lineWidthLineEdit.text()=='0' and not self.fit[dname]: self.data[dname].opts['pen']=None self.data[dname].updateItems() else: #try: self.data[dname].setPen(self.data[dname].opts['symbolPen']) #setting the same color as the symbol color=self.data[dname].opts['pen'].color() self.data[dname].setPen(pg.mkPen(color=color,width=float(self.lineWidthLineEdit.text()))) #except: # self.data[dname].setPen(pg.mkPen(color='b',width=float(self.lineWidthLineEdit.text()))) self.data[dname].opts['symbol']='o' if self.fit[dname]: self.data[dname].setSymbolSize(0) else: self.data[dname].setSymbolSize(float(self.pointSizeLineEdit.text())) self.Plot(self.selDataNames) except: QMessageBox.warning(self,'Data Error','No data to plot',QMessageBox.Ok) def setXLabel(self,label,fontsize=4): """ sets the X-label of the plot """ self.xLabel=label self.xLabelFontSize=fontsize if self.matplotlib: self.subplot.set_xlabel(label,fontsize=fontsize) self.plotWidget.draw() else: self.plotWidget.getPlotItem().setLabel('bottom','<font size='+str(fontsize)+'>'+label+'</font>') def setYLabel(self,label,fontsize=4): """ sets the y-label of the plot """ self.yLabel=label self.yLabelFontSize=fontsize if self.matplotlib: self.subplot.set_ylabel(label,fontsize=fontsize) self.plotWidget.draw() else: self.plotWidget.getPlotItem().setLabel('left','<font size='+str(fontsize)+'>'+label+'</font>') def setTitle(self,title,fontsize=6): """ Sets the y-label of the plot """ self.title=title self.titleFontSize=fontsize if self.matplotlib: self.subplot.set_title(title,fontsize=fontsize) self.plotWidget.draw() else: self.plotWidget.getPlotItem().setTitle(title='<font size='+str(fontsize)+'>'+title+'</font>') def addROI(self,values=(0,1),orientation='horizontal',movable=True, minmax_widget=None, min_widget=None, max_widget=None): if orientation=='vertical': self.roi=pg.LinearRegionItem(values=values,orientation=pg.LinearRegionItem.Vertical,movable=movable) else: self.roi = pg.LinearRegionItem(values=values, orientation=pg.LinearRegionItem.Horizontal,movable=movable) self.plotWidget.addItem(self.roi) return self.roi
class mainApp(qt.QMainWindow): def __init__(self, parent=None): super(mainApp, self).__init__(parent) self.setMinimumWidth(1040 / 2) self.setMinimumHeight(1392 / 2) self.layout = qt.QGridLayout() self.widget = qt.QWidget() self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) args = parser.parse_args() self.currentDirectory = os.path.abspath(args.directory) self.selectedDir = None self.table = qt.QListWidget() self.table.setMinimumWidth(200) self.table.setMaximumWidth(250) self.textedit = qt.QTextEdit() self.textedit.setMaximumHeight(150) self.textedit.setMinimumWidth(200) self.textedit.setMaximumWidth(250) self.update_directory_list() self.mw = MatplotlibWidget() self.mw.setMinimumWidth(1400) self.layout.addWidget(self.table, 0, 0, 1, 1) self.layout.addWidget(self.textedit, 1, 0, 1, 1) self.layout.addWidget(self.mw, 0, 1, 2, 3) # self.timer = qt.QTimer() # self.timer.timeout.connect(self.update_directory_list) # self.timer.start(10000) self.table.itemClicked.connect(self.analyse_image) self.table.itemDoubleClicked.connect(self.change_directory) # sys.stdout = OutLog( self.textedit, sys.stdout) # sys.stderr = OutLog( self.textedit, sys.stderr, qt.QColor(255,0,0) ) def analyse_image(self, item): dir = self.currentDirectory + '/' + str(item.text()) self.selectedDir = str(item.text()) if not dir == '.' and not dir == '..': self.mw.getFigure().clear() # ''' initialise an instance of the stripPlot Widget ''' analyse_image(self.mw, dir) self.mw.draw() def update_directory_list(self): index = None self.table.clear() start = time.time() # print (os.listdir(self.currentDirectory)) dirs = [ os.path.abspath(self.currentDirectory + '/' + a) for a in os.listdir(self.currentDirectory) if os.path.isdir(self.currentDirectory + '/' + a) ] print('read dirs in ', time.time() - start) if os.path.isfile(self.currentDirectory + '/best_solutions_running.csv'): solutions = [] with open(self.currentDirectory + '/best_solutions_running.csv', 'rt') as csvfile: spamreader = csv.reader(csvfile, csv.QUOTE_NONE, delimiter=',') for row in spamreader: solutions.append([float(a) for a in row]) # solutions = np.array(sorted([s for s in solutions if s[-3] < 12 and s[-4] < 2], key=lambda a: a[-1])) solutions = np.array(sorted(solutions, key=lambda a: a[-1])) # print (solutions) iterdirs = [ self.currentDirectory + '/iteration_' + str(int(a[-2])) for a in solutions if os.path.isdir(self.currentDirectory + '/iteration_' + str(int(a[-2]))) ] basedirs = [a for a in dirs if 'basefiles_' in a] vbcdirs = [a for a in dirs if 'vbc_' in a] setdirs = [a for a in dirs if 'set' in a] dirs = iterdirs # + setdirs + vbcdirs + basedirs # print 'sorted dirs in ', time.time() - start else: dirs.sort(key=os.path.getmtime, reverse=True) self.table.addItem('.') self.table.addItem('..') for i, d in enumerate(dirs[:100]): d = d.replace(self.currentDirectory + '/', '').replace(self.currentDirectory + '\\', '') item = self.table.addItem(d) if d == self.selectedDir: # print 'found dir = ', d, self.selectedDir index = i + 2 if self.selectedDir is not None and index is not None: # try: self.table.itemClicked.disconnect(self.analyse_image) self.table.setCurrentRow(index) self.table.itemClicked.connect(self.analyse_image) # except: # self.table.setCurrentRow(index) def change_directory(self, item): dir = str(item.text()) print('changing directory! = ', os.path.abspath(self.currentDirectory + '/' + dir + '/')) self.currentDirectory = os.path.abspath(self.currentDirectory + '/' + dir + '/') self.update_directory_list()
class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) self.loadIcons() self.setupUserInterface() self.setupSignals() self.__version__ = __version__ # Initialise variables self.imageFiles = {} self.timeData = None self.plotWin = None self.imageWin = None self.BMDchange = None self.roiNames = None def loadIcons(self): """ Load icons """ self.icons = dict([ ('BMDanalyseIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "logo.png"))), ('imageAddIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "file_add.png"))), ('imageRemIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "file_delete2.png"))), ('imageDownIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "arrow-up-2.png"))), ('imageUpIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "arrow-down-2.png"))), ('imagePrevIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "arrow-left.png"))), ('imageNextIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "arrow-right.png"))), ('roiAddIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "green-add3.png"))), ('roiRectIcon', QtGui.QIcon( os.path.join(absDirPath, "icons", "rectangularIcon.png"))), ('roiPolyIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "polygonIcon.png"))), ('roiRemIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "red_delete.png"))), ('roiSaveIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "filesave.png"))), ('roiCopyIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "file_copy.png"))), ('roiLoadIcon', QtGui.QIcon(os.path.join(absDirPath, "icons", "opened-folder.png"))) ]) def setupUserInterface(self): """ Initialise the User Interface """ # Left frame leftFrame = QtGui.QFrame() leftFrameLayout = QtGui.QHBoxLayout() leftFrame.setLayout(leftFrameLayout) leftFrame.setLineWidth(0) leftFrame.setFrameStyle(QtGui.QFrame.Panel) leftFrameLayout.setContentsMargins(0, 0, 5, 0) # Left frame contents self.viewMain = GraphicsLayoutWidget( ) # A GraphicsLayout within a GraphicsView leftFrameLayout.addWidget(self.viewMain) self.viewMain.setMinimumSize(200, 200) self.vb = MultiRoiViewBox(lockAspect=True, enableMenu=True) self.viewMain.addItem(self.vb) self.vb.disableAutoRange() # Right frame self.sidePanel = SidePanel(self) # UI window (containing left and right frames) UIwindow = QtGui.QWidget(self) UIwindowLayout = QtGui.QHBoxLayout() UIwindowSplitter = QtGui.QSplitter(QtCore.Qt.Horizontal) UIwindowLayout.addWidget(UIwindowSplitter) UIwindow.setLayout(UIwindowLayout) self.setCentralWidget(UIwindow) UIwindowSplitter.addWidget(leftFrame) UIwindowSplitter.addWidget(self.sidePanel) # Application window self.setWindowTitle('BMDanalyse') self.setWindowIcon(self.icons['BMDanalyseIcon']) self.setMinimumSize(600, 500) self.resize(self.minimumSize()) # Window menus self.createMenus() self.createActions() def createMenus(self): # Menus menubar = self.menuBar() self.fileMenu = menubar.addMenu('&File') self.roiMenu = menubar.addMenu('&ROIs') self.submenu = self.roiMenu.addMenu(self.icons['roiAddIcon'], "Add ROI") self.analyseMenu = menubar.addMenu('&Analyse') self.aboutMenu = menubar.addMenu('A&bout') def createActions(self): # Actions for File menu self.loadImageAct = QtGui.QAction(self.icons['imageAddIcon'], "&Load image(s)", self, shortcut="Ctrl+L") self.removeImageAct = QtGui.QAction(self.icons['imageRemIcon'], "&Remove current image", self, shortcut="Ctrl+X") self.exitAct = QtGui.QAction("&Quit", self, shortcut="Ctrl+Q", statusTip="Exit the application") fileMenuActions = [ self.loadImageAct, self.removeImageAct, self.exitAct ] fileMenuActFuncs = [self.loadImages, self.removeImage, self.close] for i in xrange(len(fileMenuActions)): action = fileMenuActions[i] function = fileMenuActFuncs[i] action.triggered[()].connect(function) self.fileMenu.addAction(self.loadImageAct) self.fileMenu.addAction(self.removeImageAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) # Actions for ROI menu # Submenu to add ROIs #self.addROIRectAct = QActionCustom("Rectangular",self.submenu) #self.addROIPolyAct = QActionCustom("Polygon",self.submenu) self.addROIRectAct = QtGui.QAction("Rectangular", self.submenu) self.addROIPolyAct = QtGui.QAction("Polygon", self.submenu) #self.addROIRectAct.clickEvent.connect(self.vb.addROI) #self.addROIPolyAct.clickEvent.connect(self.vb.addPolyRoiRequest) self.addROIRectAct.triggered[()].connect(self.vb.addROI) self.addROIPolyAct.triggered[()].connect(self.vb.addPolyRoiRequest) self.submenu.addAction(self.addROIRectAct) self.submenu.addAction(self.addROIPolyAct) self.addROIRectAct.setIcon(self.icons['roiRectIcon']) self.addROIPolyAct.setIcon(self.icons['roiPolyIcon']) self.addROIRectAct.setShortcut("Ctrl+Shift+R") self.addROIPolyAct.setShortcut("Ctrl+Shift+P") self.loadRoiAct = QtGui.QAction(self.icons['roiLoadIcon'], "L&oad ROI", self, shortcut="Ctrl+O") self.copyRoiAct = QtGui.QAction(self.icons['roiCopyIcon'], "&Copy ROI", self, shortcut="Ctrl+C") self.saveRoiAct = QtGui.QAction(self.icons['roiSaveIcon'], "&Save ROI", self, shortcut="Ctrl+S") self.remRoiAct = QtGui.QAction(self.icons['roiRemIcon'], "&Remove ROI", self, shortcut="Ctrl+D") roiMenuActions = [ self.loadRoiAct, self.copyRoiAct, self.saveRoiAct, self.remRoiAct ] roiMenuActFuncs = [ self.vb.loadROI, self.vb.copyROI, self.vb.saveROI, self.vb.removeROI ] for i in xrange(len(roiMenuActions)): action = roiMenuActions[i] function = roiMenuActFuncs[i] action.triggered[()].connect(function) self.roiMenu.addAction(action) # Actions for Analyse menu self.roiAnalysisAct = QtGui.QAction("&ROI analysis", self.viewMain, shortcut="Ctrl+R", triggered=self.getBMD) self.imgAnalysisAct = QtGui.QAction("&Image analysis", self.viewMain, shortcut="Ctrl+I", triggered=self.imageAnalysis) self.analyseMenu.addAction(self.roiAnalysisAct) self.analyseMenu.addAction(self.imgAnalysisAct) # Actions for self.aboutAct = QtGui.QAction("&About", self.viewMain, shortcut='F1', triggered=self.onAbout) self.aboutMenu.addAction(self.aboutAct) def setupSignals(self): """ Setup signals """ self.sidePanel.imageFileList.itemSelectionChanged.connect( self.getImageToDisplay) self.sidePanel.buttImageAdd.clicked.connect(self.loadImages) self.sidePanel.buttImageRem.clicked.connect(self.removeImage) self.sidePanel.buttImageUp.clicked.connect(self.sidePanel.moveImageUp) self.sidePanel.buttImageDown.clicked.connect( self.sidePanel.moveImageDown) self.sidePanel.roiMenu.button1.clicked[()].connect(self.vb.addROI) self.sidePanel.roiMenu.button2.clicked[()].connect( self.vb.addPolyRoiRequest) self.sidePanel.buttRoiCopy.clicked[()].connect(self.vb.copyROI) self.sidePanel.buttRoiRem.clicked.connect(self.vb.removeROI) self.sidePanel.buttRoiLoad.clicked.connect(self.vb.loadROI) self.sidePanel.buttRoiSave.clicked.connect(self.vb.saveROI) #self.vb.sigROIchanged.connect(self.updateROItools) def onAbout(self): """ About BMDanalyse message""" author = 'Michael Hogg' date = '2012 - 2013' version = self.__version__ QtGui.QMessageBox.about( self, 'About BMDanalyse', """ <b>BMDanalyse</b> <p>A simple program for the analysis of a time series of Bone Mineral Density (BMD) images.</p> <p>Used to evaluate the bone gain / loss in a number of regions of interest (ROIs) over time, typically due to bone remodelling as a result of stress shielding around an orthopaedic implant.</p> <p><table border="0" width="150"> <tr> <td>Author:</td> <td>%s</td> </tr> <tr> <td>Version:</td> <td>%s</td> </tr> <tr> <td>Date:</td> <td>%s</td> </tr> </table></p> """ % (author, version, date)) def updateROItools(self, roi=None): """ Update ROI info box in side panel """ if roi == None: self.sidePanel.updateRoiInfoBox() else: roiState = roi.getState() posx, posy = roiState['pos'] sizex, sizey = roiState['size'] angle = roiState['angle'] name = roi.name pos = '(%.3f, %.3f)' % (posx, posy) size = '(%.3f, %.3f)' % (sizex, sizey) angle = '%.3f' % angle self.sidePanel.updateRoiInfoBox(name, pos, size, angle) def loadImages(self): """ Load an image to be analysed """ newImages = {} fileNames = QtGui.QFileDialog.getOpenFileNames( self, self.tr("Load images"), QtCore.QDir.currentPath()) # Fix for PySide. PySide doesn't support QStringList types. PyQt4 getOpenFileNames returns a QStringList, whereas PySide # returns a type (the first entry being the list of filenames). if isinstance(fileNames, types.TupleType): fileNames = fileNames[0] if hasattr(QtCore, 'QStringList') and isinstance( fileNames, QtCore.QStringList): fileNames = [str(i) for i in fileNames] if len(fileNames) > 0: for fileName in fileNames: if fileName != '': imgarr = np.array(Image.open(str(fileName))) imgarr = imgarr.swapaxes(0, 1) if imgarr.ndim == 2: imgarr = imgarr[:, ::-1] elif imgarr.ndim == 3: imgarr = imgarr[:, ::-1, :] newImages[fileName] = imgarr # Add filenames to list widget. Only add new filenames. If filename exists aready, then # it will not be added, but data will be updated for fileName in sorted(newImages.keys()): if not self.imageFiles.has_key(fileName): self.sidePanel.addImageToList(fileName) self.imageFiles[fileName] = newImages[fileName] # Show image in Main window self.vb.enableAutoRange() if self.sidePanel.imageFileList.currentRow() == -1: self.sidePanel.imageFileList.setCurrentRow(0) self.showImage( str(self.sidePanel.imageFileList.currentItem().text())) self.vb.disableAutoRange() def removeImage(self): """ Remove image from sidePanel imageFileList """ # Return if there is no image to remove if self.vb.img == None: return # Get current image in sidePanel imageFileList and remove from list currentRow = self.sidePanel.imageFileList.currentRow() image = self.sidePanel.imageFileList.takeItem(currentRow) imageName = str(image.text()) # Delete key and value from dictionary if imageName != '': del self.imageFiles[imageName] #self.imageFiles.pop(imageName,None) # Get image item in imageFileList to replace deleted image if self.sidePanel.imageFileList.count() == 0: self.vb.enableAutoRange() self.vb.removeItem(self.vb.img) self.vb.showImage(None) #self.vb.img = None self.vb.disableAutoRange() else: currentRow = self.sidePanel.imageFileList.currentRow() imageName = str( self.sidePanel.imageFileList.item(currentRow).text()) self.showImage(imageName) def showImage(self, imageFilename): """ Shows image in main view """ self.arr = self.imageFiles[imageFilename] self.vb.showImage(self.arr) def getImageToDisplay(self): """ Get current item in file list and display in main view""" try: imageFilename = str( self.sidePanel.imageFileList.currentItem().text()) except: pass else: self.showImage(imageFilename) def getBMD(self): """ Get change in BMD over time (e.g. for each image) for all ROIs. Revised function that converts the list of images into a 3D array and then uses the relative position of the ROIs to the current image, self.vb.img, to get the average BMD value e.g. it doesn't use setImage to change the image in the view. This requires that all images are the same size and in the same position. """ # Return if there is no image or rois in view if self.vb.img == None or len(self.vb.rois) == 0: return # Collect all images into a 3D array imageFilenames = self.sidePanel.getListOfImages() images = [self.imageFiles[str(name.text())] for name in imageFilenames] imageData = np.dstack(images) numImages = len(images) # Get BMD across image stack for each ROI numROIs = len(self.vb.rois) BMD = np.zeros((numImages, numROIs), dtype=float) self.roiNames = [] for i in xrange(numROIs): roi = self.vb.rois[i] self.roiNames.append(roi.name) arrRegion = roi.getArrayRegion(imageData, self.vb.img, axes=(0, 1)) avgROIvalue = arrRegion.mean(axis=0).mean(axis=0) BMD[:, i] = avgROIvalue # Calculate the BMD change (percentage of original) tol = 1.0e-06 for i in xrange(numROIs): if abs(BMD[0, i]) < tol: BMD[:, i] = 100. else: BMD[:, i] = BMD[:, i] / BMD[0, i] * 100. self.BMDchange = BMD - 100. if self.timeData == None or self.timeData.size != numImages: self.timeData = np.arange(numImages, dtype=float) # Plot results self.showResults() def imageAnalysis(self): # Generate images of BMD change if self.vb.img == None: return self.showImageWin() def sliderValueChanged(self, value): self.imageWin.sliderLabel.setText('BMD change: >= %d %s' % (value, '%')) self.setLookupTable(value) self.imageWin.vb.img2.setLookupTable(self.lut) def setLookupTable(self, val): lut = [] for i in range(256): if i > 127 + val: lut.append(matplotlib.cm.jet(255)) elif i < 127 - val: lut.append(matplotlib.cm.jet(0)) else: lut.append((0.0, 0.0, 0.0, 0.0)) lut = np.array(lut) * 255 self.lut = np.array(lut, dtype=np.ubyte) def createImageWin(self): self.buttMinimumSize = QtCore.QSize(70, 36) self.iconSize = QtCore.QSize(24, 24) if self.imageWin == None: self.imageWin = QtGui.QDialog(self, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint | \ QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowMaximizeButtonHint) self.imageWin.setWindowTitle('BMDanalyse') self.imageWin.setWindowIcon(self.icons['BMDanalyseIcon']) self.imageWin.setMinimumSize(250, 500) self.imageWin.resize(self.imageWin.minimumSize()) # Create viewBox self.imageWin.glw = GraphicsLayoutWidget( ) # A GraphicsLayout within a GraphicsView self.imageWin.vb = ImageAnalysisViewBox(lockAspect=True, enableMenu=True) self.imageWin.vb.disableAutoRange() self.imageWin.glw.addItem(self.imageWin.vb) arr = self.imageFiles.values()[0] self.imageWin.vb.img1 = pg.ImageItem(arr, autoRange=False, autoLevels=False) self.imageWin.vb.addItem(self.imageWin.vb.img1) self.imageWin.vb.img2 = pg.ImageItem(None, autoRange=False, autoLevels=False) self.imageWin.vb.addItem(self.imageWin.vb.img2) self.imageWin.vb.autoRange() lut = [[int(255 * val) for val in matplotlib.cm.gray(i)[:3]] for i in xrange(256)] lut = np.array(lut, dtype=np.ubyte) self.imageWin.vb.img1.setLookupTable(lut) # Label to show index of current image label self.imageCurrCont = QtGui.QFrame() self.imageCurrCont.setLineWidth(2) self.imageCurrCont.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised) self.imageCurrCont.setMinimumWidth(70) self.imageWin.currLabel = QtGui.QLabel("") self.imageWin.currLabel.setAlignment(QtCore.Qt.AlignHCenter) imageCurrContLayout = QtGui.QHBoxLayout() imageCurrContLayout.addWidget(self.imageWin.currLabel) self.imageCurrCont.setLayout(imageCurrContLayout) # Create buttons to select images self.imageWin.buttCont = QtGui.QWidget() self.imageWin.buttPrev = QtGui.QPushButton( self.icons['imagePrevIcon'], "") self.imageWin.buttNext = QtGui.QPushButton( self.icons['imageNextIcon'], "") self.buttLayout = QtGui.QHBoxLayout() self.buttLayout.addStretch(1) self.buttLayout.addWidget(self.imageWin.buttPrev) self.buttLayout.addWidget(self.imageCurrCont) self.buttLayout.addWidget(self.imageWin.buttNext) self.buttLayout.addStretch(1) self.imageWin.buttCont.setLayout(self.buttLayout) self.imageWin.buttPrev.setMinimumSize(self.buttMinimumSize) self.imageWin.buttNext.setMinimumSize(self.buttMinimumSize) self.imageWin.buttPrev.setIconSize(self.iconSize) self.imageWin.buttNext.setIconSize(self.iconSize) self.buttLayout.setContentsMargins(0, 5, 0, 5) self.imageWin.buttPrev.clicked.connect(self.prevImage) self.imageWin.buttNext.clicked.connect(self.nextImage) # Create slider self.imageWin.sliderCon = QtGui.QWidget() self.imageWin.slider = QtGui.QSlider(self) self.imageWin.slider.setOrientation(QtCore.Qt.Horizontal) self.imageWin.slider.setMinimum(1) self.imageWin.slider.setMaximum(100) self.imageWin.slider.setMinimumWidth(100) self.imageWin.slider.valueChanged.connect(self.sliderValueChanged) self.imageWin.sliderLabel = QtGui.QLabel('1') self.imageWin.sliderLabel.setMinimumWidth(120) self.sliderLayout = QtGui.QHBoxLayout() self.sliderLayout.addStretch(1) self.sliderLayout.addWidget(self.imageWin.sliderLabel) self.sliderLayout.addWidget(self.imageWin.slider) self.sliderLayout.addStretch(1) self.imageWin.sliderCon.setLayout(self.sliderLayout) self.sliderLayout.setContentsMargins(0, 0, 0, 5) # Format image window self.imageWinLayout = QtGui.QVBoxLayout() self.imageWinLayout.addWidget(self.imageWin.glw) self.imageWinLayout.addWidget(self.imageWin.buttCont) self.imageWinLayout.addWidget(self.imageWin.sliderCon) self.imageWin.setLayout(self.imageWinLayout) self.imageWin.imagesRGB = None # Show self.imageWin.show() self.imageWin.slider.setValue(10) self.sliderValueChanged(10) self.imageWinIndex = 0 def prevImage(self): #numImages = len(self.imageFiles) minIndex = 0 currIndex = self.imageWinIndex prevIndex = currIndex - 1 self.imageWinIndex = max(prevIndex, minIndex) self.updateImageWin() def nextImage(self): numImages = len(self.imageFiles) maxIndex = numImages - 1 currIndex = self.imageWinIndex nextIndex = currIndex + 1 self.imageWinIndex = min(nextIndex, maxIndex) self.updateImageWin() def updateImageWin(self): imageFilenames = self.sidePanel.getListOfImages() imageName = imageFilenames[self.imageWinIndex] self.imageWin.vb.img1.setImage(self.imageFiles[str(imageName.text())], autoLevels=False) self.imageWin.vb.img2.setImage( self.imageWin.imagesRGB[self.imageWinIndex], autoLevels=False) self.imageWin.currLabel.setText( "%i / %i" % (self.imageWinIndex + 1, len(imageFilenames))) def showImageWin(self): self.createImageWin() #if self.imageWin.imagesRGB == None: self.imagesBMDpercentChange() self.imagesBMDpercentChange() self.updateImageWin() def imagesBMDpercentChange(self): # Get image arrays and convert to an array of floats imageFilenames = self.sidePanel.getListOfImages() images = [self.imageFiles[str(name.text())] for name in imageFilenames] imagesConv = [] for img in images: image = img.copy() image[np.where(image == 0)] = 1 image = image.astype(np.float) imagesConv.append(image) # Calculate percentage change and set with limits -100% to +100% imagesPercCh = [] imageInitial = imagesConv[0] for image in imagesConv: imagePercCh = (image - imageInitial) / imageInitial * 100. imagePercCh[np.where(imagePercCh > 100.)] = 100. imagePercCh[np.where(imagePercCh < -100.)] = -100. imagesPercCh.append(imagePercCh) numImages = len(imagesPercCh) self.imageWin.imagesRGB = [] for i in xrange(numImages): image = imagesPercCh[i] sx, sy = image.shape #imageCh = np.zeros((sx,sy),dtype=np.float) imageRGB = image * (255 / 200.) + (255 / 2.) self.imageWin.imagesRGB.append(imageRGB) def BMDtoCSVfile(self): """ Write BMD change to csv file """ fileName = QtGui.QFileDialog.getSaveFileName(None, self.tr("Export to CSV"), QtCore.QDir.currentPath(), self.tr("CSV (*.csv)")) # Fix for PyQt/PySide compatibility. PyQt returns a QString, whereas PySide returns a tuple (first entry is filename as string) if isinstance(fileName, types.TupleType): fileName = fileName[0] if hasattr(QtCore, 'QString') and isinstance(fileName, QtCore.QString): fileName = str(fileName) if not fileName == '': #if not fileName.isEmpty(): textFile = open(fileName, 'w') numFrames, numROIs = self.BMDchange.shape roiNames = self.roiNames header = "%10s," % 'Time' header += ((numROIs - 1) * '%10s,' + '%10s\n') % tuple(roiNames) textFile.write(header) for i in xrange(numFrames): textFile.write('%10.1f,' % self.timeData[i]) for j in xrange(numROIs): if j < numROIs - 1: fmt = '%10.3f,' else: fmt = '%10.3f\n' textFile.write(fmt % self.BMDchange[i, j]) textFile.close() def showResults(self, ): """ Plots BMD change using matplotlib """ # Create plot window if self.plotWin == None: self.plotWin = QtGui.QDialog(self, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint | \ QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowMaximizeButtonHint) self.plotWin.setWindowTitle('BMDanalyse') self.plotWin.setWindowIcon(self.icons['BMDanalyseIcon']) self.plotWin.setMinimumSize(600, 500) self.plotWin.resize(self.minimumSize()) # Create Matplotlib widget self.mplw = MatplotlibWidget(size=(5, 6)) self.fig = self.mplw.getFigure() self.editDataButton = QtGui.QPushButton('Edit plot') self.exportCSVButton = QtGui.QPushButton('Export data') self.mplw.toolbar.addWidget(self.editDataButton) self.mplw.toolbar.addWidget(self.exportCSVButton) self.editDataButton.clicked.connect(self.showEditBox) self.exportCSVButton.clicked.connect(self.BMDtoCSVfile) # Format plot window self.plotWinLayout = QtGui.QVBoxLayout() self.plotWinLayout.addWidget(self.mplw) self.plotWin.setLayout(self.plotWinLayout) self.createFigure() self.plotWin.show() self.mplw.draw() def createFigure(self): """ Creates plot of results """ self.ax1 = self.fig.add_subplot(111) self.ax1.clear() self.fig.subplots_adjust(bottom=0.15, top=0.85, left=0.15, right=0.925) numFrames, numROIs = self.BMDchange.shape t = self.timeData # Plot data for i in xrange(numROIs): roiname = self.roiNames[i] self.ax1.plot(t, self.BMDchange[:, i], '-o', label=roiname, linewidth=2.0) kwargs = dict(y=1.05) # Or kwargs = {'y':1.05} self.ax1.set_title('Change in Bone Mineral Density over time', fontsize=14, fontweight='roman', **kwargs) self.ax1.set_xlabel('Time', fontsize=10) self.ax1.set_ylabel('Change in BMD (%)', fontsize=10) self.ax1.legend(loc=0) matplotlib.pyplot.setp(self.ax1.get_xmajorticklabels(), fontsize=10) matplotlib.pyplot.setp(self.ax1.get_ymajorticklabels(), fontsize=10) matplotlib.pyplot.setp(self.ax1.get_legend().get_texts(), fontsize=10) self.ax1.grid() def fillEditBox(self): rows, cols = self.BMDchange.shape for i in xrange(rows): itmValue = '%.2f' % self.timeData[i] itm = QtGui.QTableWidgetItem(itmValue) self.tableResults.setItem(i, 0, itm) for j in xrange(cols): itmValue = '%.2f' % self.BMDchange[i, j] itm = QtGui.QTableWidgetItem(itmValue) self.tableResults.setItem(i, j + 1, itm) def showEditBox(self): self.plotWin.editBox = QtGui.QDialog( self.plotWin, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) self.plotWin.editBox.setWindowIcon(self.icons['BMDanalyseIcon']) self.plotWin.editBox.setWindowTitle('BMDanalyse') self.plotWin.editBox.setModal(True) # Add table layout = QtGui.QVBoxLayout() layout.setContentsMargins(10, 10, 10, 10) layout.setSpacing(20) rows, cols = self.BMDchange.shape self.tableResults = MyTableWidget(rows, cols + 1, self.plotWin.editBox) self.tableResults.verticalHeader().setVisible(True) # Set headers self.tableResults.setHorizontalHeaderItem( 0, QtGui.QTableWidgetItem('Time')) for i in xrange(cols): header = QtGui.QTableWidgetItem(self.roiNames[i]) self.tableResults.setHorizontalHeaderItem(i + 1, header) # Add values to table self.fillEditBox() # Set layout layout.addWidget(self.tableResults) self.buttonsFrame = QtGui.QFrame() self.buttonsLayout = QtGui.QHBoxLayout() self.buttonReset = QtGui.QPushButton('Reset') self.buttonSave = QtGui.QPushButton('Save') self.buttonClose = QtGui.QPushButton('Cancel') self.buttonReset.setFixedWidth(50) self.buttonSave.setFixedWidth(50) self.buttonClose.setFixedWidth(50) self.buttonClose.clicked.connect(self.plotWin.editBox.close) self.buttonSave.clicked.connect(self.updateTableValues) self.buttonReset.clicked.connect(self.fillEditBox) self.buttonsLayout.addStretch(1) self.buttonsLayout.addWidget(self.buttonReset) self.buttonsLayout.addWidget(self.buttonSave) self.buttonsLayout.addWidget(self.buttonClose) self.buttonsLayout.setContentsMargins(0, 0, 0, 0) self.buttonsFrame.setLayout(self.buttonsLayout) layout.addWidget(self.buttonsFrame) self.plotWin.editBox.setLayout(layout) self.plotWin.editBox.setMaximumSize(layout.sizeHint()) self.plotWin.editBox.show() def updateTableValues(self): # Create temporary arrays timeData = self.timeData.copy() BMDchange = self.BMDchange.copy() # Put the values from the tables into the temporary arrays rows = self.tableResults.rowCount() cols = self.tableResults.columnCount() for r in xrange(rows): for c in xrange(cols): item = self.tableResults.item(r, c) itemValue = float(item.text()) if c == 0: timeData[r] = itemValue else: BMDchange[r, c - 1] = itemValue # Check that time values are in increasing order. If so, then update arrays if any(np.diff(timeData) <= 0): self.errorMessage = QtGui.QMessageBox() self.errorMessage.setWindowIcon(self.icons['BMDanalyseIcon']) self.errorMessage.setWindowTitle('BMDanalyse') self.errorMessage.setText( 'Input error: Time values should be in order of increasing value' ) self.errorMessage.setIcon(QtGui.QMessageBox.Warning) self.errorMessage.open() else: self.timeData = timeData self.BMDchange = BMDchange self.createFigure() self.mplw.draw() self.plotWin.editBox.close()
class Ui_MainWindow(object): def setupUi(self, MainWindow): self.axs = {} MainWindow.setObjectName(_fromUtf8("MainWindow")) MainWindow.resize(1024, 768) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(_fromUtf8("./resources/icons/logo48.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) MainWindow.setWindowIcon(icon) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.splitter1 = QtGui.QSplitter(QtCore.Qt.Horizontal) #self.splitter1.setOpaqueResize(False) self.splitter1.setChildrenCollapsible(False) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) self.progressBar = QtGui.QProgressBar(self.centralwidget) self.progressBar.setProperty("value", 24) self.progressBar.setObjectName(_fromUtf8("progressBar")) self.progressBar.hide() self.progressBar_batch = QtGui.QProgressBar(self.centralwidget) self.progressBar_batch.setProperty("value", 24) self.progressBar_batch.setObjectName(_fromUtf8("progressBar_batch")) #self.progressBar_batch.hide() #self.verticalLayout.addWidget(self.progressBar) MainWindow.setCentralWidget(self.centralwidget) # Menu bar self.menubar = QtGui.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 574, 36)) self.menubar.setObjectName(_fromUtf8("menubar")) self.menuFile = QtGui.QMenu(self.menubar) self.menuFile.setObjectName(_fromUtf8("menuFile")) self.menuExport = QtGui.QMenu(self.menuFile) self.menuExport.setObjectName(_fromUtf8("menuExport")) self.menuView = QtGui.QMenu(self.menubar) self.menuView.setObjectName(_fromUtf8("menuView")) MainWindow.setMenuBar(self.menubar) # Status bar self.statusbar = QtGui.QStatusBar(MainWindow) self.statusbar.setObjectName(_fromUtf8("statusbar")) MainWindow.setStatusBar(self.statusbar) self.statusbar.addPermanentWidget(self.progressBar) self.statusbar.addPermanentWidget(self.progressBar_batch) # Tool bar self.toolBar = QtGui.QToolBar(MainWindow) self.toolBar.setObjectName(_fromUtf8("toolBar")) self.toolBar.setIconSize(QtCore.QSize(64, 64)) #self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) MainWindow.addToolBar(QtCore.Qt.LeftToolBarArea, self.toolBar) # Dockable filelist # http://www.tutorialspoint.com/pyqt/pyqt_qdockwidget.htm # Is it necessary to use dockWidgetContent and layout? self.dockWidget_file_list = QtGui.QDockWidget("Annotations", MainWindow) self.dockWidget_file_list.setObjectName(_fromUtf8("dockWidget_file_list")) MainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockWidget_file_list) self.tableWidget_file_list = QtGui.QTableWidget(0, 2) self.tableWidget_file_list.setHorizontalHeaderLabels(['File','Fraction(%)']) self.tableWidget_file_list.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableWidget_file_list.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.tableWidget_file_list.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.dockWidget_file_list.setWidget(self.tableWidget_file_list) header = self.tableWidget_file_list.horizontalHeader() header.setStretchLastSection(True) #header.setResizeMode(QtGui.QHeaderView.Stretch) # Dockable hist self.splitter_lcd = QtGui.QSplitter(QtCore.Qt.Vertical) #self.splitter1.setOpaqueResize(False) self.splitter_lcd.setChildrenCollapsible(False) self.mw_hist = MatplotlibWidget() self.axs['hist_viewer'] = self.mw_hist.getFigure().add_subplot(111) self.splitter_lcd.addWidget(self.mw_hist) self.lcdNumber = QtGui.QLCDNumber(self.centralwidget) self.lcdNumber.setProperty("value", 12.34) self.lcdNumber.setObjectName(_fromUtf8("lcdNumber")) #self.lcdNumber.setSegmentStyle(QtGui.QLCDNumber.Flat) self.splitter_lcd.addWidget(self.lcdNumber) self.lcdNumber.setMinimumHeight(40) # self.splitter_lcd.setStretchFactor(0, 7); # self.splitter_lcd.setStretchFactor(1, 1); # self.splitter_lcd.setSizes([100,1]) #http://stackoverflow.com/questions/14478574/changing-the-digit-color-of-qlcd-number palette = self.lcdNumber.palette() # foreground color palette.setColor(palette.WindowText, QtCore.Qt.red) # background color palette.setColor(palette.Background, QtGui.QColor(255, 0, 0)) # # "light" border # palette.setColor(palette.Light, QtGui.QColor(255, 0, 0)) # # "dark" border # palette.setColor(palette.Dark, QtGui.QColor(0, 255, 0)) # set the palette self.lcdNumber.setPalette(palette) self.dockWidget_hist = QtGui.QDockWidget("Distribution", MainWindow) self.dockWidget_hist.setObjectName(_fromUtf8("dockWidget_hist")) self.dockWidget_hist.setWidget(self.splitter_lcd) MainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dockWidget_hist) # Dockable responses self.dockWidget_responses = QtGui.QDockWidget("Responses", MainWindow) self.dockWidget_responses.setObjectName(_fromUtf8("dockWidget_responses")) MainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dockWidget_responses) self.mw_response = MatplotlibWidget() self.axs['response_viewer'] = self.mw_response.getFigure().add_subplot(221) self.axs['segment_viewer'] = self.mw_response.getFigure().add_subplot(222) self.axs['raw_response_viewer'] = self.mw_response.getFigure().add_subplot(223) self.axs['exemplar_viewer'] = self.mw_response.getFigure().add_subplot(224) self.dockWidget_responses.setWidget(self.mw_response) #self.splitter1.addWidget(self.splitter_lcd) # Actions self.actionOpen = QtGui.QAction(MainWindow) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap(_fromUtf8("./resources/icons/add_image.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionOpen.setIcon(icon1) self.actionOpen.setObjectName(_fromUtf8("actionOpen")) self.actionOpen_folder = QtGui.QAction(MainWindow) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(_fromUtf8("./resources/icons/add_folder.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionOpen_folder.setIcon(icon2) self.actionOpen_folder.setObjectName(_fromUtf8("actionOpen_folder")) self.actionExportAsCSV = QtGui.QAction(MainWindow) self.actionOpen_folder.setObjectName(_fromUtf8("actionExportAsCSV")) self.actionDetect = QtGui.QAction(MainWindow) icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap(_fromUtf8("./resources/icons/detection.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionDetect.setIcon(icon3) self.actionDetect.setObjectName(_fromUtf8("actionDetect")) self.actionEstimate = QtGui.QAction(MainWindow) icon4 = QtGui.QIcon() icon4.addPixmap(QtGui.QPixmap(_fromUtf8("./resources/icons/recognition.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionEstimate.setIcon(icon4) self.actionEstimate.setObjectName(_fromUtf8("actionEstimate")) self.actionRunOne = QtGui.QAction(MainWindow) icon5 = QtGui.QIcon() icon5.addPixmap(QtGui.QPixmap(_fromUtf8("./resources/icons/run_one.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionRunOne.setIcon(icon5) self.actionRunOne.setObjectName(_fromUtf8("actionRunOne")) self.actionRunAll = QtGui.QAction(MainWindow) icon6 = QtGui.QIcon() icon6.addPixmap(QtGui.QPixmap(_fromUtf8("./resources/icons/run_all.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionRunAll.setIcon(icon6) self.actionRunAll.setObjectName(_fromUtf8("actionRunAll")) # Add actions to menu and toolbar self.menuFile.addAction(self.actionOpen) self.menuFile.addAction(self.actionOpen_folder) self.menuFile.addAction(self.menuExport.menuAction()) self.menuExport.addAction(self.actionExportAsCSV) self.menuFile.addAction(self.actionDetect) self.menubar.addAction(self.menuFile.menuAction()) self.toolBar.addAction(self.actionOpen) self.toolBar.addAction(self.actionOpen_folder) self.toolBar.addSeparator() self.toolBar.addAction(self.actionDetect) self.toolBar.addAction(self.actionEstimate) self.toolBar.addAction(self.actionRunOne) self.toolBar.addAction(self.actionRunAll) self.actionOpen.triggered.connect(self.load_image) self.actionOpen_folder.triggered.connect(self.load_dir) self.actionExportAsCSV.triggered.connect(self.export_as_csv) self.actionDetect.triggered.connect(self.detect_blackboard_at_present) self.actionEstimate.triggered.connect(self.estimate_coverage_at_present) self.actionRunOne.triggered.connect(self.run_one_at_present) self.actionRunAll.triggered.connect(self.run_all) self.tableWidget_file_list.currentItemChanged.connect(self.file_list_selChanged) ########################################## # Matplotlib Image Viewer self.mw_image = MatplotlibWidget() self.axs['image_viewer'] = self.mw_image.getFigure().add_subplot(111) self.axs['image_viewer'].set_frame_on(False) #self.splitter_lcd.addWidget(self.lcdNumber) #self.toolBar.addWidget(self.lcdNumber) self.splitter1.addWidget(self.mw_image) #self.splitter1.addWidget(self.splitter_lcd) self.splitter1.setStretchFactor(0, 10); #self.splitter1.setStretchFactor(1, 3); self.verticalLayout.addWidget(self.splitter1) subplot = self.mw_image.getFigure().add_subplot(111) x = np.array(range(100)) y = np.array(range(100)) subplot.plot(x,y) self.mw_image.draw() self.retranslateUi(MainWindow) #QtCore.QObject.connect(self.horizontalSlider, QtCore.SIGNAL(_fromUtf8("valueChanged(int)")), self.progressBar.setValue) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.window = MainWindow self.veg_data = veg_data() self.veg_data.img_orig = None self.veg_data.bbox = [] def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "MO-VE: Missouri Vegetation Measurement Tool", None)) #self.label.setText(_translate("MainWindow", "Output:", None)) self.menuFile.setTitle(_translate("MainWindow", "File", None)) self.menuExport.setTitle(_translate("MainWindow", "Export", None)) self.menuView.setTitle(_translate("MainWindow", "View", None)) self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar", None)) self.actionOpen.setText(_translate("MainWindow", "Load an image", None)) self.actionOpen_folder.setText(_translate("MainWindow", "Load a folder", None)) self.actionExportAsCSV.setText(_translate("MainWindow", "Export as CSV", None)) self.actionDetect.setText(_translate("MainWindow", "Detect blackboard", None)) self.actionEstimate.setText(_translate("MainWindow", "Estimate coverage rate", None)) self.actionRunOne.setText(_translate("MainWindow", "Run on current image", None)) self.actionRunAll.setText(_translate("MainWindow", "Run on all images", None)) def load_image(self): fileName = QtGui.QFileDialog.getOpenFileName(None, 'OpenFile') fileName = unicode(fileName) if fileName == '' or self.load_image_by_name(fileName): return if not self.load_image_by_name(fileName): return dir_name, picture_name = os.path.split(fileName) self.veg_data.dir = dir_name self.veg_data.picture_list = [picture_name] self.veg_data.fraction_list = ['-'] self.tableWidget_file_list.clearContents() self.tableWidget_file_list.setRowCount(1) self.tableWidget_file_list.setItem(0,0, QtGui.QTableWidgetItem(picture_name)) self.tableWidget_file_list.setItem(0,1, QtGui.QTableWidgetItem("-")) def load_image_by_name(self, fileName): if fileName == '': return print fileName t0 = time.time() img = cv2.imread(fileName) t1 = time.time() print 'cv2.imread', t1 - t0 if img is None: msg = QtGui.QMessageBox() msg.setIcon(QtGui.QMessageBox.Warning) msg.setText("Unable to open " + fileName + '.') msg.setInformativeText("Unrecognized image format.") msg.setWindowTitle("MessageBox demo") #msg.setDetailedText("The details are as follows:") msg.setStandardButtons(QtGui.QMessageBox.Ok) retval = msg.exec_() return False else: b,g,r = cv2.split(img) img2 = cv2.merge([r,g,b]) t0 = time.time() self.axs['image_viewer'].cla() self.axs['image_viewer'].imshow(img2) #self.axs['image_viewer'].set_title(os.path.basename(fileName)) self.mw_image.draw() t1 = time.time() print 'plt.imshow', t1 - t0 #plt.show() self.veg_data.img_orig = img self.veg_data.bbox = [] return True def load_dir(self): supported_formats = ['.jpg', '.jpeg', '.png'] dir_name = unicode(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) if dir_name == '': return file_list = os.listdir(dir_name) picture_list = [f for f in file_list if os.path.splitext(f)[1].lower() in supported_formats] if not picture_list: return self.tableWidget_file_list.clearContents() self.tableWidget_file_list.setRowCount(len(picture_list)) for i, p in enumerate(picture_list): self.tableWidget_file_list.setItem(i,0, QtGui.QTableWidgetItem(p)) self.tableWidget_file_list.setItem(i,1, QtGui.QTableWidgetItem("-")) self.veg_data.dir = dir_name self.veg_data.picture_list = picture_list self.veg_data.fraction_list = ['-'] * len(picture_list) #http://stackoverflow.com/questions/14803315/connecting-qtableview-selectionchanged-signal-produces-segfault-with-pyqt def file_list_selChanged(self, item0, item1): if item0 is None: return if item1 is not None and item0.row() == item1.row(): return print 'Selection changed.', item0.row(), unicode(item0.text()) self.load_image_by_name(os.path.join(self.veg_data.dir, self.veg_data.picture_list[item0.row()])) self.veg_data.current_item_idx = item0.row() # Read cache file_name = self.veg_data.picture_list[self.veg_data.current_item_idx] file_name = os.path.basename(file_name) file_name = os.path.splitext(file_name)[0] segments = cv2.imread(os.path.join(self.veg_data.cache_dir, file_name + '_segments.tiff')) hist = None fraction = 0.0 if segments is not None: segments = np.bool_(segments) #print 'segments.shape == ', segments.shape hist = np.float32(segments[:,:,0]).mean(1) self.veg_data.fraction = float(hist.mean()) #print os.path.join(self.veg_data.cache_dir, file_name + '_segments.tiff') # print segments.shape self.update_segment_viewer(segments) self.update_hist_viewer(hist) # print self.veg_data.fraction # print type(self.veg_data.fraction), type(self.veg_data.fraction * 1.0) self.lcdNumber.display(self.veg_data.fraction * 100.0) def export_as_csv(self): #### non-native way: # dialog = QtGui.QFileDialog() # dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden) # dialog.setDefaultSuffix('json') # dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave) # dialog.setNameFilters(['JSON (*.json)']) # if dialog.exec_() == QtGui.QDialog.Accepted: # print(dialog.selectedFiles()) # else: # print('Cancelled') #### fileName = QtGui.QFileDialog.getSaveFileName(None, 'Export as CSV', './untitled.csv', 'Comma-Separated Values files (*.csv)') fileName = unicode(fileName) if fileName: # if os.path.splitext(fileName)[1] != '.csv': # fileName += '.csv' with open(fileName, 'wb') as csvfile: csv_writer = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) for file_name, cov_rate in zip(self.veg_data.picture_list, self.veg_data.fraction_list): csv_writer.writerow([file_name, cov_rate]) print fileName def detect_blackboard(self, img): height = img.shape[0] width = img.shape[1] # Get the bounding box of blackboard img_HSV = cv2.cvtColor(img, cv2.cv.CV_BGR2HSV) x0, y0, x1, y1 = detectBlackboard(img_HSV) x0 *= width x1 *= width y0 *= height y1 = (x1-x0) * 1.5 + y0 print x0, y0, x1, y1 bbox = [x0, y0, x1, y1] return bbox def detect_blackboard_at_present(self): img = self.veg_data.img_orig if img is None: return self.veg_data.bbox = self.detect_blackboard(img) # Visulization self.draw_bbox(self.veg_data.bbox) def estimate_coverage_at_present(self): img = self.veg_data.img_orig if img is None: return bbox = self.veg_data.bbox #print 'bbox', bbox if not bbox: return fraction, segments, hist, response, raw_response = \ self.estimate_coverage(img, bbox, fast_mode=self.veg_data.fast_mode) # update list self.veg_data.fraction_list[self.veg_data.current_item_idx] = fraction self.veg_data.fraction = fraction self.tableWidget_file_list.item(self.veg_data.current_item_idx, 1).setText(str(fraction * 100)) # save cache file_name = self.veg_data.picture_list[self.veg_data.current_item_idx] file_name = os.path.basename(file_name) file_name = os.path.splitext(file_name)[0] cv2.imwrite(os.path.join(self.veg_data.cache_dir, file_name + '_segments.tiff'), np.uint8(segments)) cv2.imwrite(os.path.join(self.veg_data.cache_dir, file_name + '_segments.pbm'), np.uint8(segments)) # Visulization self.lcdNumber.display(float(fraction) * 100.0) self.progressBar.setValue(90) QtGui.QApplication.processEvents() self.update_segment_viewer(segments) self.update_response_viewer(response) self.update_raw_response_viewer(raw_response) self.update_hist_viewer(hist) self.update_exemplar_viewer(raw_response > THRES_RAW) self.progressBar.setValue(100) QtGui.QApplication.processEvents() self.progressBar.hide() # Reactivate the file list tablewidget self.tableWidget_file_list.setEnabled(True) def estimate_coverage(self, img, bbox, fast_mode=False): self.progressBar.show() self.progressBar.setValue(10) QtGui.QApplication.processEvents() x0 = bbox[0] y0 = bbox[1] x1 = bbox[2] y1 = bbox[3] img_bboard = img[int(y0):int(y1), int(x0):int(x1), :] response, raw_response, exemplar_colors = \ classify(img_bboard, THRES_RAW, fast_mode=fast_mode) self.progressBar.setValue(65) QtGui.QApplication.processEvents() fraction = 0.0 if response is not None: segments = (response > THRES_KMS) fraction = np.mean(segments) hist = np.float32(segments).mean(1) else: hist = None return fraction, segments, hist, response, raw_response # Make blackboard red # r1 = r[int(y0):int(y1), int(x0):int(x1)] # r1 = np.uint8(np.multiply(r1, coverage) # + np.multiply(r1, ~coverage) * 0.4 + ~coverage * (255*0.6)) # r[int(y0):int(y1), int(x0):int(x1)] = r1 # img2 = cv2.merge([r,g,b]) def run_all(self): if len(self.veg_data.picture_list) > 0: self.progressBar_batch.setMaximum(len(self.veg_data.picture_list)) # # Disable items first to prevent user's interacting # # http://stackoverflow.com/questions/21001144/disable-user-to-click-over-qtablewidget # for i, p in enumerate(self.veg_data.picture_list): # item = self.tableWidget_file_list.item(i,0) # item.setFlags(item.flags() & ~QtCore.Qt.ItemIsEnabled) # item = self.tableWidget_file_list.item(i,1) # item.setFlags(item.flags() & ~QtCore.Qt.ItemIsEnabled) self.tableWidget_file_list.setEnabled(False) for i in range(len(self.veg_data.picture_list)): self.tableWidget_file_list.selectRow(i) # This line need to be reimplemented, # Different image shouldn't be selected though GUI self.run_one(fast_mode=True) self.progressBar_batch.setValue(i+1) QtGui.QApplication.processEvents() self.tableWidget_file_list.setEnabled(True) # # Resume user's interacting # for i, p in enumerate(self.veg_data.picture_list): # item = self.tableWidget_file_list.item(i,0) # item.setFlags(item.flags() | QtCore.Qt.ItemIsEnabled) # item = self.tableWidget_file_list.item(i,1) # item.setFlags(item.flags() | QtCore.Qt.ItemIsEnabled) def run_one_at_present(self): self.tableWidget_file_list.setEnabled(False) self.detect_blackboard_at_present() self.estimate_coverage_at_present() self.tableWidget_file_list.setEnabled(True) def run_one(self,fast_mode=True): # Disactive the file list tablewidget self.tableWidget_file_list.setEnabled(False) img = self.veg_data.img_orig bbox = self.detect_blackboard(img) # Visulization self.draw_bbox(bbox) fraction, segments, hist, response, raw_response = \ self.estimate_coverage(img, bbox, fast_mode=fast_mode) # update list self.veg_data.fraction_list[self.veg_data.current_item_idx] = fraction self.veg_data.fraction = fraction self.tableWidget_file_list.item(self.veg_data.current_item_idx, 1).setText(str(fraction * 100)) # Visulization self.lcdNumber.display(float(fraction) * 100.0) self.progressBar.setValue(90) QtGui.QApplication.processEvents() self.update_segment_viewer(segments) self.update_response_viewer(response) self.update_raw_response_viewer(raw_response) self.update_hist_viewer(hist) self.update_exemplar_viewer(raw_response > THRES_RAW) self.progressBar.setValue(100) QtGui.QApplication.processEvents() self.progressBar.hide() # Reactivate the file list tablewidget self.tableWidget_file_list.setEnabled(True) def draw_bbox(self, bbox): x0 = bbox[0] y0 = bbox[1] x1 = bbox[2] y1 = bbox[3] self.axs['image_viewer'].add_patch( plt.Rectangle((x0, y0), (x1 - x0), (y1 - y0), fill=False, edgecolor='red', linewidth=2.0) ) self.axs['image_viewer'].text(x0, y0 - 30, "blackboard", bbox=dict(facecolor='red', alpha=0.5), fontsize=12, color='white') self.mw_image.draw() def update_segment_viewer(self, segments): self.axs['segment_viewer'].cla() if segments is None: self.mw_response.draw() return self.axs['segment_viewer'].imshow(segments, cmap='gray', interpolation='nearest') self.axs['segment_viewer'].set_title('Predicted vegetation') self.mw_response.draw() def update_raw_response_viewer(self, raw_response): self.axs['raw_response_viewer'].cla() if raw_response is None: self.mw_response.draw() return self.axs['raw_response_viewer'].imshow(-raw_response, interpolation='nearest') self.axs['raw_response_viewer'].set_title('LBP+SVM response map') self.mw_response.draw() def update_exemplar_viewer(self, exemplar): self.axs['exemplar_viewer'].cla() if exemplar is None: self.mw_response.draw() return self.axs['exemplar_viewer'].imshow(exemplar, cmap='gray', interpolation='nearest') self.axs['exemplar_viewer'].set_title('BBoard exemplar regions') self.mw_response.draw() def update_response_viewer(self, response): self.axs['response_viewer'].cla() if response is None: self.mw_response.draw() return self.axs['response_viewer'].imshow(np.log(response)) self.axs['response_viewer'].set_title('KMeans loss map') self.mw_response.draw() def update_hist_viewer(self, hist): self.axs['hist_viewer'].cla() # print "hist is None:", hist is None # print hist.shape if hist is None or hist.shape[0] == 0: self.axs['hist_viewer'].text(0.1, 0, "Unknown", fontsize=15, weight='bold', color='red') self.mw_hist.draw() return # print hist.shape heights = range(hist.shape[0]) heights.reverse() self.axs['hist_viewer'].fill_betweenx(heights, hist, x2=0.0, color='#76b900', linewidth=1.0) self.axs['hist_viewer'].set_xlim([0.0, 1.0]) self.axs['hist_viewer'].set_ylim([0.0, hist.shape[0]]) self.axs['hist_viewer'].set_xlabel('coverage rate') self.axs['hist_viewer'].set_ylabel('height (/px)') self.axs['hist_viewer'].set_title('Coverage rate vs. Height ') self.axs['hist_viewer'].set_axis_bgcolor('#444444') self.axs['hist_viewer'].grid(True, color='white') self.axs['hist_viewer'].text(0.1, 0, "overall\ncoverage:\n{0:.1f}%".format(np.mean(hist) * 100), fontsize=15, weight='bold', color='white') #self.mw_hist.getFigure().tight_layout() # Failed when too narrow self.mw_hist.getFigure().subplots_adjust(left=0.4, right=0.9) self.mw_hist.getFigure().subplots_adjust(left=0.4, right=0.9) self.mw_hist.draw()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.createActions() self.createMenus() self.setGeometry(100, 100, 600, 900) self.centralWidget = QWidget() # GrphicsWidget() layout = QHBoxLayout(self.centralWidget) self.scrollArea = QScrollArea(self) self.mw = MatplotlibWidget(size=(3.0, 40.0), dpi=100) lplot = self.mw.getFigure().add_subplot(121) self.ax = self.mw.getFigure().gca() l, b, w, h = self.ax.get_position().bounds # print(l, b, w, h) # self.ax.invert_yaxis() self.ax.set_position([0.125, 0.05, 0.5, 0.94]) # l, b, w, h = self.ax.get_position().bounds # print(l, b, w, h) self.mw.draw() # self.plotlayout.addWidget(self.mw) self.scrollArea.setWidget(self.mw) layout.addWidget(self.scrollArea) self.setCentralWidget(self.centralWidget) self.lastree = LasTree() self.logtree = LasTree() self.wellLoad() self.logtree.set_files(['GR', 'BS']) self.logtree.buildTreeWidget() self.logtree.tree.itemSelectionChanged.connect(self.logPlot) self.createDockWindows() # self.logFileList.itemSelectionChanged.connect(self.lasLoad) # if not self.las_just_selected: # self.logList.itemSelectionChanged.connect(self.logPlot) self.setWindowTitle("Loggy") # self.newLetter() def wellLoad(self): self.wellFolder = well_folder self.files = [] for f in np.array(os.listdir(self.wellFolder)[:]): if f[-4:].lower() in ['.las', 'dlis']: self.files.append(f) self.files = np.array(self.files) files_w_path = [self.wellFolder + f for f in self.files] cols = [] # self.files=np.array(os.listdir(self.wellFolder)[:]) self.lastree.set_files(self.files) self.lastree.buildTreeWidget() self.lastree.tree.itemSelectionChanged.connect(self.lasLoad) self.lasLoadThread = LasLoadThread(files=files_w_path) # def lasBackgroundLoad(): def lasLoad(self): las_name = self.lastree.tree.selectedItems()[0].text( 0) #self.logFileList.selectedItems()[0].text() if las_name in ['TVD', 'MD', 'LWD', 'WireLine']: return findex = np.where(self.files == las_name)[0][0] # print(findex) Loaded = False while (not Loaded): if (findex < len(self.lasLoadThread.Lases)): self.las = self.lasLoadThread.Lases[findex] Loaded = True self.logtree.tree.clear() # print('hi') else: # print('hello') # self.logtree.addItems(['Loading....']) time.sleep(1) if len(self.logtree.tree.selectedItems()) > 0: item = self.logtree.tree.selectedItems()[0] # print(dir(item)) item.setSelected = False if not (len(self.las.keys()) < 1): # self.logtree = LasTree(self.las.keys()) self.logtree.set_files(self.las.keys()) self.logtree.buildTreeWidget() dcol = self.las.keys()[find_depth_indx(self.las)] self.depth_col = str_array2floats(self.las[dcol]) # else: # self.las_just_selected = True def logPlot(self): # print(self.mw.getFigure().) # pass # if not self.las_just_selected: if len(self.logtree.tree.selectedItems()) > 0: keycol = self.logtree.tree.selectedItems()[0].text(0) try: self.log_col = str_array2floats(self.las[keycol]) self.ax = LogPlot.basicPlot(self.ax, self.depth_col, self.log_col, lcolor='#800000') self.ax.set_ylim(500, 3000) self.ax.invert_yaxis() except: print('Unable to convert log to floats') self.mw.draw() def set_category(self): # qt_app = QApplication(sys.argv) # mnomonicsfile=mnomonicsfile # print(self.logtree.treeview_dict) # set_category_app = Categorize(self.logtree.treeview_dict,mnomonicsfile) print('*************************************************') print(self.logtree.treeview_dict) category_window = Categorize(self) category_window.set_params(self.logtree, mnomonicsfile) category_window.show() # self.logtree.tree.clear() # self.logtree.buildTreeWidget() # set_category_app.run() # self.logtree.buildTreeWidget() def createDockWindows(self): dock = QDockWidget("Log Files", self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) dock.setWidget(self.lastree.tree) # self.addDockWidget(Qt.LeftDockWidgetArea, dock) self.set_category_button = QPushButton('Set Category', self) # self.layout.addWidget(self.logtree.tree) dock = QDockWidget("Set", self) dock.setWidget(self.set_category_button) self.addDockWidget(Qt.LeftDockWidgetArea, dock) dock = QDockWidget("Logs", self) dock.setWidget(self.logtree.tree) self.addDockWidget(Qt.LeftDockWidgetArea, dock) self.set_category_button.clicked.connect(self.set_category) def createActions(self): self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close) self.openFileAct = QAction("&Open", self, shortcut="Ctrl+O", triggered=self.file_open) self.aboutAct = QAction("&About", self, triggered=self.about) def createMenus(self): self.fileMenu = QMenu("&File", self) # self.fileMenu.addAction(self.openAct) # self.fileMenu.addAction(self.printAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.openFileAct) self.fileMenu.addAction(self.exitAct) self.helpMenu = QMenu("&Help", self) self.helpMenu.addAction(self.aboutAct) # self.helpMenu.addAction(self.aboutQtAct) self.menuBar().addMenu(self.fileMenu) # self.menuBar().addMenu(self.viewMenu) # self.menuBar().addMenu(self.digitizeMenu) self.menuBar().addMenu(self.helpMenu) self.file_toolbar = QToolBar("File") self.file_toolbar.setIconSize(QSize(24, 24)) self.addToolBar(self.file_toolbar) def about(self): QMessageBox.about( self, "About Log splicer", "<p>The <b>Image Viewer</b> example shows how to combine " "(QScrollArea.widgetResizable), can be used to implement " "zooming and scaling features.</p>" "<p>In addition the example shows how to use QPainter to " "print an image.</p>") def file_open(self): print('Not yet set')