def load_totals_data(self, initial_balances, expenditures_by_type, current_balances): if expenditures_by_type is not None and expenditures_by_type != []: total_spending = 0 for row in expenditures_by_type: total_spending += row[1] spending_text = TableWidget.format_as_currency(total_spending) self.totals_table.set_value(spending_text, 0, 1) else: self.totals_table.set_value("-", 0, 1) if initial_balances is not None and initial_balances != []: total_initial_balance = 0 for balance in initial_balances: total_initial_balance += balance[2] initial_text = TableWidget.format_as_currency( total_initial_balance) self.totals_table.set_value(initial_text, 0, 0) else: self.totals_table.set_value("-", 0, 0) if current_balances is not None and current_balances != []: total_current_balance = 0 for balance in current_balances: total_current_balance += balance[2] current_text = TableWidget.format_as_currency( total_current_balance) self.totals_table.set_value(current_text, 0, 2) else: self.totals_table.set_value("-", 0, 2)
def _restore_windows_ui(self, windows): for window in windows: widget = TableWidget(self.db, window.title, window.sql_select, self.edit_update_ui) sub_window = self.mdiArea.addSubWindow(widget) sub_window.setGeometry(window.x, window.y, window.width, window.height) widget.splitter.setSizes(window.sizes) widget.show()
def setup_balance_table(self): # invert_axis is True because the data will be added in cols self.balance_table = TableWidget(self, 2, self.field_count, table_name=self.table_widget_name, invert_axis=True, column_widths=default_field_col_widths, head_font=self.head_font, entry_font=self.entry_font, header_widths=default_header_widths) self.balance_table.add_listener(self) self.balance_table.set_header_values(['Source', 'Amount']) self.balance_table.grid(row=1, columnspan=2)
def load_spending_by_category(self): self.category_table = TableWidget(self, 2, self.field_count, head_font=default_table_head_font, entry_font=default_entry_font, entry_justify_list=["right", "left"], head_justify_list=["right", "left"]) self.category_table.hide_config_buttons() self.category_table.set_header_values(['Category', 'Amount']) self.category_table.grid(row=0, column=2)
def load_total_amounts(self): self.totals_table = TableWidget( self, 3, 1, entry_font=default_entry_font, entry_justify=["left"], head_justify_list=["right", "right", "right"], invert_axis=True) self.totals_table.hide_config_buttons() self.totals_table.set_header_values( ["Initial Total", "Expenditure Total", "Current Total"]) self.totals_table.grid(row=0, column=0)
def setup_expenditure_table(self): # adds the expenditure table self.expenditure_table = TableWidget( self, 3, self.field_count + 1, table_name="expenditures", invert_axis=False, column_widths=default_field_col_widths, head_font=self.head_font, entry_font=self.entry_font) self.expenditure_table.hide_config_buttons() self.expenditure_table.add_listener(self) self.expenditure_table.set_header_values(['Amount', 'Name', 'Type']) self.expenditure_table.grid(row=1, columnspan=2)
def set_balances(self, balance_matrix: [[]]): # sets the values in the balances table given the balance matrix table = [] for row_index in range(len(balance_matrix)): values = [balance_matrix[row_index][1], TableWidget.format_as_currency(balance_matrix[row_index][2])] table.append(values) self.balance_table.load_table_data(table) self.expenditures_set = True
def maybe_show_item(self, item, _=None): if item.parent() is None: return # Ignore top-level items kind = item.parent().text(0).lower()[:-1] name = item.text(0) sub_window = self.findSubWindow(name) if sub_window is None: if kind in {'table', 'view'}: sql = self.db.select_make(kind, name) widget = TableWidget(self.db, f'{name} ({kind})', sql, self.edit_update_ui) sub_window = self.mdiArea.addSubWindow(widget) widget.show() else: # TODO create a new QueryWidget or TriggerEditWidget etc. print('maybe_show_item', kind, name) # TODO if sub_window is not None: self.mdiArea.setActiveSubWindow(sub_window)
def send_edit_to_database(self, table_name: str, row_index: int, values): # passes the row values to the listener to the DatabaseModel to be processed and stored in the database value_dict = { 'amount': TableWidget.unformat_from_currency(values[0]), 'name': values[1], 'type': values[2] } self.table_edit_listener.send_edit_to_database(table_name, row_index, value_dict)
def set_expenditures(self, expenditure_matrix: [[]]): # passes the label values to the table to be inserted into the labels self.expenditures_set = True table = [] for row_index in range(len(expenditure_matrix)): values = [ TableWidget.format_as_currency( expenditure_matrix[row_index][1]), expenditure_matrix[row_index][2], expenditure_matrix[row_index][3] ] table.append(values) self.expenditure_table.load_table_data(table)
def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.resize(1624, 660) controlWidget = ControlWidget() monitorWidget = TableWidget() splitter = QSplitter() splitter.addWidget(controlWidget) splitter.addWidget(monitorWidget) splitter.setStretchFactor(0, 6) splitter.setStretchFactor(1, 10) self.setCentralWidget(splitter)
def load_expenditure_data(self, expenditures_by_type: [[]]): if expenditures_by_type is not None and expenditures_by_type != []: labels = [] values = [] table = [] for row_index in range(len(expenditures_by_type)): labels.append(expenditures_by_type[row_index][0]) values.append(expenditures_by_type[row_index][1]) table.append([ expenditures_by_type[row_index][0], TableWidget.format_as_currency( expenditures_by_type[row_index][1]) ]) self.category_table.load_table_data(table) self.pie_chart.construct_pie_chart( labels, values, text_col=self.pie_chart.label_text_col) else: self.category_table.clear_labels() self.pie_chart.construct_empty_chart()
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 = TableWidget(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()
class SonicViewer(QtGui.QWidget): ''' Has 3 plots stored in dict plots={'P':,'Sx':,'Sy':} has 3 modifuing parameter trees to operate data: Shift - shift the data along x axis Amplify ''' mode = 'Contours' autoShift = {'P':True,'Sx':True,'Sy':True} # flag to match 0 and transmission time arrivalsPicked = False updateQTable = True # don't need skipPlottingFAmpFlag = False skipPlottingFPhaseFlag = False def __init__(self,parent=None): self.parent = parent QtGui.QWidget.__init__(self,None,QtCore.Qt.WindowStaysOnTopHint) self.setupGUI() self.fWidget = TriplePlotWidget() self.phWidget = TriplePlotWidget() self.bWidget = BindingWidget(parents=[parent,self]) self.isWidget = InterpretationSettingsWidget() self.data = {'P':{},'Sx':{},'Sy':{}} self.currentShifts = {'P':0,'Sx':0,'Sy':0} self.connectPlotButtons() self.gEdit = GradientEditorWidget() self.gw = self.gEdit.sgw self.fgw = self.gEdit.fgw self.pgw = self.gEdit.pgw # sel self.gw.restoreState(Gradients['hot']) self.fgw.restoreState(Gradients['hot']) self.pgw.restoreState(Gradients['hot']) self.allParameters = [] self.yAxis = 'Track #' self.y = {} self.aTimes = {} # Connect everything self.showArrivalsButton.triggered.connect(self.parent.plotSonicData) self.pickArrivalsButton.triggered.connect(self.pickAllArrivals) self.invertYButton.triggered.connect(self.parent.plotSonicData) self.autoScaleButton.triggered.connect(self.autoScalePlots) self.editGradientsButton.triggered.connect(self.gEdit.show) self.gEdit.okButton.pressed.connect(self.parent.plotSonicData) self.showTableButton.triggered.connect(self.showTable) self.showForrierMagnitudeButton.triggered.connect(self.showFourrier) self.showForrierPhasesButton.triggered.connect(self.showPhases) # self.showArrivalsButton.triggered.connect(self.plot) self.waveFormButton.triggered.connect(lambda: self.setMode('WaveForms')) self.contourButton.triggered.connect(lambda: self.setMode('Contours')) self.moduliButton.triggered.connect(self.isWidget.show) self.isWidget.okButton.pressed.connect(self.runBindingWidget) self.filteringButton.triggered.connect(self.parent.plotSonicData) self.fWidget.sigRegionChanged.connect(self.plotFilteredData) # self.moduliButton.triggered.connect(self.bWidget.run) for wave in WaveTypes: self.params[wave].param('Arrival times').param('Mpoint').sigValueChanged.connect(self.recomputeArrivals) self.params[wave].param('Arrival times').param('BTA').sigValueChanged.connect(self.recomputeArrivals) self.params[wave].param('Arrival times').param('ATA').sigValueChanged.connect(self.recomputeArrivals) self.params[wave].param('Arrival times').param('DTA').sigValueChanged.connect(self.recomputeArrivals) self.plots[wave].vb.sigAltClick.connect(self.handPick) def handPick(self,sender,pos): if not self.handPickArrivalsButton.isChecked(): return else: # first find sender for wave in self.getActivePlots(): if self.plots[wave].vb == sender: break # now wave is the type sent the signal # find closest sonic track to the y position closest = abs(self.y[wave] - pos.y()).argmin() self.aTimes[wave][closest] = pos.x() self.parent.plotSonicData() def plotFilteredData(self): self.skipPlottingFAmpFlag = True self.parent.plotSonicData() def runBindingWidget(self): testconf = self.isWidget.testconf capsconf = self.isWidget.capsconf if testconf == None: return 0 dens = self.isWidget.dens length = self.isWidget.length atime = self.isWidget.atime self.bWidget.setConfig(testconf,capsconf,dens,length,atime) self.bWidget.run() def setData(self,data): ''' data is a dictionary with keys: P,Sx,Sy ''' for wave in WaveTypes: self.data[wave] = data[wave] self.createTable() self.getFourrierTransforms() self.arrivalsPicked = False def hasData(self): ''' check if the viewer has data to work with ''' for wave in WaveTypes: if len(self.data[wave])>0: return True return False def createTable(self): ''' store all data in one 3D np-array 1st dimension - time or amplitude 2nd dimension - number of file 3rd dimension - datapoints ''' if not self.hasData(): return 0 # if no data pass print 'Building sonic matrix' self.table = {} for wave in WaveTypes: self.table[wave] = get_table(self.data[wave]) self.y[wave] = np.arange(self.table[wave].shape[1]) def showFourrier(self): self.fWidget.show() self.fWidget.activateWindow() self.parent.plotSonicData() def showPhases(self): self.phWidget.show() self.phWidget.activateWindow() self.parent.plotSonicData() def getFourrierTransforms(self): if not self.hasData(): return 0 # if no data pass print 'Building Fourrier matrix' self.fft = {} # power self.fftamp = {} # power self.fftph = {} # phase for wave in WaveTypes: x = self.table[wave][0,:,:] y = self.table[wave][1,:,:] N = y.shape[1] h = x[0,1] - x[0,0] # yf = np.fft.fft(y).real[:,:N/2] ft = np.fft.fft(y) fft = ft[:,:N/2] fft = np.fft.fft(y)[:,:N/2] yf = np.absolute(fft) yp = np.arctan2(fft.imag,fft.real) xf0 = np.fft.fftfreq(N,h) xf = xf0[:N/2] xf = np.tile(xf,y.shape[0]) xf0 = np.tile(xf0,y.shape[0]) xf = xf.reshape(yf.shape[0],yf.shape[1]) xf0 = xf0.reshape(ft.shape[0],ft.shape[1]) self.fft[wave] = np.array((xf0,ft)) self.fftamp[wave] = np.array((xf,yf)) self.fftph[wave] = np.array((xf,yp)) def connectPlotButtons(self): for wave in WaveTypes: self.params[wave].param('Show').sigValueChanged.connect(self.changeLayout) def changeLayout(self): print 'changing layout' for wave in WaveTypes: try: self.sublayout.removeItem(self.plots[wave]) self.fWidget.sublayout.removeItem(self.fWidget.plots[wave]) except: pass for wave in self.getActivePlots(): if wave: self.sublayout.addItem(self.plots[wave]) self.fWidget.sublayout.addItem(self.fWidget.plots[wave]) self.sublayout.nextRow() self.fWidget.sublayout.nextRow() def autoScalePlots(self): if self.autoScaleButton.isChecked(): for wave in self.getActivePlots(): self.plots[wave].enableAutoRange() self.fWidget.plots[wave].enableAutoRange() self.phWidget.plots[wave].enableAutoRange() else: for wave in self.getActivePlots(): self.plots[wave].disableAutoRange() self.fWidget.plots[wave].disableAutoRange() self.phWidget.plots[wave].disableAutoRange() def getActivePlots(self): activePlots = [] for wave in WaveTypes: val = self.params[wave].param('Show').value() if val: activePlots.append(wave) return activePlots def pickAllArrivals(self) : pBar = QtGui.QProgressDialog(None,QtCore.Qt.WindowStaysOnTopHint) pBar.setWindowTitle("Picking first arrivals") pBar.setAutoClose(True) pBar.show() pBar.activateWindow() progress = 0 pBar.setValue(progress) for wave in WaveTypes: self.pickArrivals(wave) progress += 33 pBar.setValue(progress) pBar.setValue(100) self.arrivalsPicked = True self.showArrivalsButton.setDisabled(False) self.moduliButton.setDisabled(False) self.handPickArrivalsButton.setDisabled(False) self.showArrivalsButton.trigger() def getInverseFFT(self): ifft = {} interval = self.fWidget.interval() for wave in WaveTypes: x = self.table[wave][0,:,:] xf = self.fft[wave][0,:,:] yf = copy(self.fft[wave][1,:,:]) yf[abs(xf)<min(interval)] = 0 yf[abs(xf)>max(interval)] = 0 ift = np.fft.ifft(yf) ifft[wave] = np.array((x,ift.real)) return ifft def plot(self,indices=None,yarray=None,yindices=None, amplify=None,yAxisName='Track #'): ''' indices - number of sonic tracks to plot yarray - y values yindices - indices of yarray to plot ''' # print 1 for wave in self.getActivePlots(): plot = self.plots[wave] fplot = self.fWidget.plots[wave] phplot = self.phWidget.plots[wave] plot.clear(); if self.skipPlottingFAmpFlag: pass else: fplot.clear() fplot.getAxis('left').setLabel(yAxisName,**LabelStyle) fplot.getAxis('bottom').setLabel(fXAxisName,**LabelStyle) if self.autoScaleButton.isChecked(): fplot.enableAutoRange(enable=True) else: fplot.disableAutoRange() if self.skipPlottingFPhaseFlag: pass else: phplot.clear() phplot.getAxis('left').setLabel(yAxisName,**LabelStyle) phplot.getAxis('bottom').setLabel(fXAxisName,**LabelStyle) if self.autoScaleButton.isChecked(): phplot.enableAutoRange(enable=True) else: phplot.disableAutoRange() plot.getAxis('left').setLabel(yAxisName,**LabelStyle) plot.getAxis('bottom').setLabel(xAxisName,**LabelStyle) if self.autoScaleButton.isChecked(): plot.enableAutoRange(enable=True) else: plot.disableAutoRange() # Plot data in main sonic viewer if self.filteringButton.isChecked(): self.fWidget.show() # self.fWidget.activateWindow() ifft = self.getInverseFFT() if self.mode == 'WaveForms': self.plotDataWaveForms(ifft,self, indices,amplify,yAxisName) elif self.mode == 'Contours': self.plotDataContours(ifft, self, self.fgw, indices,yarray,yindices, amplify,yAxisName) else: if self.mode == 'WaveForms': self.plotWaveForms(indices,amplify,yAxisName) elif self.mode == 'Contours': self.plotContours(indices,yarray,yindices, amplify,yAxisName) # Plot fourrier transform amplitude data if not self.skipPlottingFAmpFlag: if self.fWidget.isVisible(): if self.filteringButton.isChecked(): self.fWidget.addRegions() if self.mode == 'WaveForms': self.plotDataWaveForms(self.fftamp,self.fWidget, indices,amplify,yAxisName) elif self.mode == 'Contours': self.plotDataContours(self.fftamp, self.fWidget, self.fgw, indices,yarray,yindices, amplify,yAxisName) # Plot fourrier transform phase data if not self.skipPlottingFPhaseFlag: if self.phWidget.isVisible(): if self.mode == 'WaveForms': self.plotDataWaveForms(self.fftph,self.pWidget, indices,amplify,yAxisName) elif self.mode == 'Contours': self.plotDataContours(self.fftph, self.phWidget, self.gw, indices,yarray,yindices, amplify,yAxisName) # Plot arrival times if self.showArrivalsButton.isChecked(): self.plotArrivals(indices,yarray,yindices, amplify,yAxisName) # print 6 self.skipPlottingFAmpFlag = False self.skipPlottingFPhaseFlag = False def plotWaveForms(self,indices=None, amplify=None,yAxisName=''): self.graphicPaths = {} if (amplify is None): amp=np.average(np.abs(np.diff(self.y['P']))) for wave in self.getActivePlots(): plot = self.plots[wave] if self.invertYButton.isChecked(): plot.invertY(True) else: plot.invertY(False) if indices: sind = indices[wave] else: sind = np.arange(self.table[wave].shape[1]) Nlines = len(self.y[wave]) y = amp*self.table[wave][1,sind,:] + self.y[wave].reshape(Nlines,1) # self.params[wave].param('Amplify').setValue(amp) if indices: self.graphicPaths[wave] = MultiLine(self.table[wave][0,sind,:],y) else: self.graphicPaths[wave] = MultiLine(self.table[wave][0,:,:],y) try: plot.addItem(self.graphicPaths[wave]) except: pass def plotDataWaveForms(self, data,widget,indices=None, amplify=None,yAxisName=''): paths = {} amp=np.average(np.abs(np.diff(self.y['P'])))/data['P'].max() for wave in self.getActivePlots(): plot = widget.plots[wave] if self.invertYButton.isChecked(): plot.invertY(True) else: plot.invertY(False) if indices: sind = indices[wave] else: sind = np.arange(data[wave].shape[1]) Nlines = len(self.y[wave]) y = amp*data[wave][1,sind,:] + self.y[wave].reshape(Nlines,1) if indices: paths[wave] = MultiLine(data[wave][0,sind,:],y) else: paths[wave] = MultiLine(data[wave][0,:,:],y) try: plot.addItem(paths[wave]) except: pass def plotDataContours(self,data,widget,gw, indices=None,yarray=None,yindices=None, amplify=None,yAxisName=''): images = {} k = 0 for wave in self.getActivePlots(): plot = widget.plots[wave] if self.invertYButton.isChecked(): plot.invertY(True) else: plot.invertY(False) images[wave] = pg.ImageItem() if indices: z = data[wave][1,indices[wave],:].T else: z = data[wave][1,:,:].T if k == 0: lut = gw.getLookupTable(z.shape[0], alpha=None) images[wave].setImage(z) plot.addItem(images[wave]) x = data[wave][0,0,:] shiftX0 = x[0] scaleX = (x[-1] - x[0])/x.shape[0] y = self.y[wave] ymax = y.max() ymin = y.min() shiftY0 = ymin scaleY = float(ymax - ymin)/y.shape[0] images[wave].translate(shiftX0,shiftY0) images[wave].scale(scaleX,scaleY) # set Colors images[wave].setLookupTable(lut, update=True) k += 1 def plotContours(self,indices=None,yarray=None,yindices=None, amplify=None,yAxisName=''): self.images = {} k = 0 for wave in self.getActivePlots(): plot = self.plots[wave] if self.invertYButton.isChecked(): plot.invertY(True) else: plot.invertY(False) self.images[wave] = pg.ImageItem() if indices: z = self.table[wave][1,indices[wave],:].T else: z = self.table[wave][1,:,:].T if k == 0: lut = self.gw.getLookupTable(z.shape[0], alpha=None) self.images[wave].setImage(z) plot.addItem(self.images[wave]) # scale and shift image x = self.table[wave][0,0,:] shiftX0 = x[0] scaleX = (x[-1] - x[0])/x.shape[0] y = self.y[wave] ymax = y.max() ymin = y.min() shiftY0 = ymin scaleY = float(ymax - ymin)/y.shape[0] self.images[wave].translate(shiftX0,shiftY0) self.images[wave].scale(scaleX,scaleY) # set Colors self.images[wave].setLookupTable(lut, update=True) k += 1 def plotArrivals(self,indices=None,yarray=None,yindices=None, amplify=None,yAxisName='Track #'): try: self.QTable.cellChanged.disconnect(self.editArrivals) except: pass tableLabels = get_list(yAxisName,WaveTypes) self.QTable.setHorizontalHeaderLabels(tableLabels) for wave in self.getActivePlots(): k = WaveTypes.index(wave) if yarray is None: x = self.aTimes[wave] y = np.arange(self.aTimes[wave].shape[0]) else: ind = yindices[wave] sind = indices[wave] y = yarray[ind] x = self.aTimes[wave][sind] if self.updateQTable: self.QTable.setColumn(y,k) self.QTable.setColumn(x,k+3) else: self.QTable.close() # otherwise it stalls plt = self.plots[wave] pen = pg.mkPen(color=(72,209,204), width=2) plt.plot(x,y,pen=pen) self.updateQTable = True self.QTable.cellChanged.connect(self.editArrivals) def setYAxisParameters(self,parameters): # we use setLimits because of weird implementation # in pyqtgraph self.allParameters = parameters self.yAxisMenu.clear() self.yAxisButtons = {} self.yAxisButtons['Track #'] = QtGui.QAction('Track #',self,checkable=True) self.yAxisButtons['Track #'].setActionGroup(self.yAxisGroup) self.yAxisMenu.addAction(self.yAxisButtons['Track #']) for p in parameters: if self.mode == 'Contours' and p!='Time': continue self.yAxisButtons[p] = QtGui.QAction(p,self,checkable=True) self.yAxisButtons[p].setActionGroup(self.yAxisGroup) self.yAxisMenu.addAction(self.yAxisButtons[p]) pass try: print 'Setting y axis to: Time' self.yAxisButtons['Time'].setChecked(True) self.yAxis = 'Time' except: print 'setting was not successful' def setMode(self,mode): ''' takes string arguments: WaveForms and Contours ''' self.mode = mode if mode == 'WaveForms': print 'Setting mode to Wave Forms' # self.modeMenu.setDefaultAction(self.waveFormButton) elif mode == 'Contours': print 'Setting mode to Contours' # self.modeMenu.setDefaultAction(self.contourButton) self.setYAxisParameters(self.allParameters) def setupGUI(self): self.setWindowTitle("Sonic Viewer") pg.setConfigOption('background', (255,255,255)) pg.setConfigOption('foreground',(0,0,0)) self.layout = QtGui.QVBoxLayout() self.layout.setContentsMargins(0,0,0,0) self.layout.setSpacing(0) self.setLayout(self.layout) ## setting up the menu bar self.menuBar = QtGui.QMenuBar() self.layout.setMenuBar(self.menuBar) self.viewMenu = self.menuBar.addMenu('View') self.modeMenu = self.menuBar.addMenu('Mode') self.transformMenu = self.menuBar.addMenu('Transform') self.intMenu = self.menuBar.addMenu('Interpretation') # VIEW MENU self.autoScaleButton = QtGui.QAction('Auto scale',self,checkable=True) self.autoScaleButton.setChecked(True) self.showArrivalsButton = QtGui.QAction('Arrivals',self,checkable=True) self.showArrivalsButton.setDisabled(True) self.showTableButton = QtGui.QAction('Table',self) self.yAxisMenu = self.viewMenu.addMenu('y axis') self.editGradientsButton = QtGui.QAction('Edit Gradients',self) self.invertYButton = QtGui.QAction('Invert y axis',self,checkable=True) self.viewMenu.addAction(self.autoScaleButton) self.viewMenu.addAction(self.showArrivalsButton) self.viewMenu.addAction(self.showTableButton) self.viewMenu.addAction(self.editGradientsButton) self.viewMenu.addAction(self.invertYButton) # MODE MENU self.modeGroup = QtGui.QActionGroup(self) self.waveFormButton = QtGui.QAction('Wave Forms',self,checkable=True) self.contourButton = QtGui.QAction('Contours',self,checkable=True) self.waveFormButton.setActionGroup(self.modeGroup) self.contourButton.setActionGroup(self.modeGroup) self.contourButton.setChecked(True) self.modeMenu.addAction(self.waveFormButton) self.modeMenu.addAction(self.contourButton) # INTERPRETATION MENU self.pickArrivalsButton = QtGui.QAction('Pick arrivals',self) self.handPickArrivalsButton = QtGui.QAction('Hand pick',self,checkable=True) self.moduliButton = QtGui.QAction('Elastic moduli',self) self.moduliButton.setDisabled(True) self.handPickArrivalsButton.setDisabled(True) self.intMenu.addAction(self.pickArrivalsButton) self.intMenu.addAction(self.handPickArrivalsButton) self.intMenu.addAction(self.moduliButton) # TRANSFORM MENU self.showForrierMagnitudeButton = QtGui.QAction('Fourrier magnitude',self) self.showForrierPhasesButton = QtGui.QAction('Fourrier phases',self) self.filteringButton = QtGui.QAction('Frequency filtering',self,checkable=True) self.transformMenu.addAction(self.showForrierMagnitudeButton) self.transformMenu.addAction(self.showForrierPhasesButton) self.transformMenu.addAction(self.filteringButton) # dict to store actions for y Axis self.yAxisButtons = {} self.yAxisGroup = QtGui.QActionGroup(self) self.yAxisButtons['Track #'] = QtGui.QAction('Track #',self,checkable=True) self.yAxisButtons['Track #'].setActionGroup(self.yAxisGroup) self.yAxisMenu.addAction(self.yAxisButtons['Track #']) self.yAxisButtons['Track #'].setChecked(True) # for wave in WaveTypes: # split main widget into plotting area and parameters area self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.layout.addWidget(self.splitter) # split parameter area into 3 for each wave self.treeSplitter = QtGui.QSplitter() self.treeSplitter.setOrientation(QtCore.Qt.Vertical) self.splitter.addWidget(self.treeSplitter) # create parameter trees self.trees={} for wave in WaveTypes: self.trees[wave] = ParameterTree(showHeader=False) self.treeSplitter.addWidget(self.trees[wave]) # create layout for the plotting area self.sublayout = pg.GraphicsLayoutWidget() self.splitter.addWidget(self.sublayout) self.params = {} self.plots = {} for wave in WaveTypes: # create parameter instances self.params[wave] = Parameter.create(name=wave + ' wave', type='group',children=Parameters) self.trees[wave].setParameters(self.params[wave],showTop=True) # fill plotting area with 3 plots # self.plots[wave] = self.sublayout.addPlot() self.plots[wave] = self.sublayout.addPlot(viewBox=ViewBox()) setup_plot(self.plots[wave]) self.sublayout.nextRow() self.params['Sx'].param('Arrival times').param('BTA').setValue(36) self.params['Sx'].param('Arrival times').param('ATA').setValue(5) self.params['Sx'].param('Arrival times').param('DTA').setValue(20) self.params['Sy'].param('Arrival times').param('BTA').setValue(100) self.params['Sy'].param('Arrival times').param('ATA').setValue(5) self.params['Sy'].param('Arrival times').param('DTA').setValue(30) # create table widget to show arrival times self.QTable = TableWidget(['Number P','Number Sx','Number Sy','P','Sx','Sy']) # self.splitter.addWidget(self.QTable) self.QTable.setColumnCount(6) self.QTable.hide() self.splitter.setSizes([int(self.width()*0.30), int(self.width()*0.35), int(self.width()*0.35) ]) self.splitter.setStretchFactor(0, 0) self.splitter.setStretchFactor(1, 1) self.splitter.setStretchFactor(2, 0) def pickArrivals(self,wave): print 'Computing arrival times for %s wave'%(wave) win = [0,0,0] mpoint = self.params[wave].param('Arrival times').param('Mpoint').value() win[0] = self.params[wave].param('Arrival times').param('BTA').value() win[1] = self.params[wave].param('Arrival times').param('ATA').value() win[2] = self.params[wave].param('Arrival times').param('DTA').value() x = self.table[wave][0,:,:] y = self.table[wave][1,:,:] h = x[0,1] - x[0,0] r = multi_window(y,win) rx = np.arange(r.shape[1])*h + x[0,win[0]] mind = abs(rx-mpoint).argmin() #index of middle point sInd = r[:,:mind].argmax(axis=1) # sender indices sTimes = rx[sInd] # sender times rInd = r[:,mind:].argmax(axis=1) # receiver indices rTimes = rx[mind+rInd] self.aTimes[wave] = rTimes - sTimes # shift initial data so if self.autoShift[wave]: shift = np.mean(sTimes) self.table[wave][0,:,:] -= shift self.autoShift[wave] = False def editArrivals(self): data = self.QTable.getValues() indices = self.parent.trsIndices if self.yAxis == 'Track #': for wave in WaveTypes: indices[wave] = np.arange(len(self.parent.sTimes[wave])) pass self.aTimes['P'][indices['P']] = data[:,3] self.aTimes['Sx'][indices['Sx']] = data[:,4] self.aTimes['Sy'][indices['Sy']] = data[:,5] self.updateQTable = False self.parent.plotSonicData() def recomputeArrivals(self): parent = self.sender().parent().parent().name() wave = parent.split()[0] self.pickArrivals(wave) self.parent.plotSonicData() def showTable(self): # show = self.showTableButton.isChecked() self.QTable.show() self.QTable.activateWindow() def closeEvent(self,event): QtGui.QWidget.closeEvent(self,event) self.fWidget.close() self.phWidget.close() self.QTable.close() self.bWidget.close()
class ExpenditureWidget(tkinter.Frame, TableEditListener): # is a widget that displays the expenditures in the database def __init__(self, parent, **optional_arguments): # initializes the frame and sub frames tkinter.Frame.__init__(self, parent) self.colors = None self.expenditures_set = False self.table_edit_listener: TableEditListener = None self.field_count = default_field_count # setup the default parameters then process the optional arguments self.title_font = default_title_font self.head_font = default_table_head_font self.entry_font = default_entry_font self.title_text = default_title_text self.process_optional_arguments(optional_arguments) # setup the title label self.head_label = None self.setup_title_label() # setup the edit button self.edit_button = None self.done_button = None self.setup_edit_button() # setup the expenditure table self.expenditure_table = None self.setup_expenditure_table() def add_listener(self, listener: TableEditListener): self.table_edit_listener = listener def process_optional_arguments(self, optional_arguments): # processes the optional arguments passed to the constructor if 'title_font' in optional_arguments: self.title_font = optional_arguments['title_font'] if 'head_font' in optional_arguments: self.head_font = optional_arguments['head_font'] if 'entry_font' in optional_arguments: self.entry_font = optional_arguments['entry_font'] if 'name' in optional_arguments: self.title_text = optional_arguments['name'] def setup_title_label(self): # adds a title label above the table self.head_label = tkinter.Label(self) self.head_label.config(text=self.title_text, font=self.title_font) self.head_label.grid(row=0, column=0, sticky="E") def setup_expenditure_table(self): # adds the expenditure table self.expenditure_table = TableWidget( self, 3, self.field_count + 1, table_name="expenditures", invert_axis=False, column_widths=default_field_col_widths, head_font=self.head_font, entry_font=self.entry_font) self.expenditure_table.hide_config_buttons() self.expenditure_table.add_listener(self) self.expenditure_table.set_header_values(['Amount', 'Name', 'Type']) self.expenditure_table.grid(row=1, columnspan=2) def setup_edit_button(self): self.edit_button = tkinter.Button(self, text="Edit", command=lambda: self.edit_pressed()) self.done_button = tkinter.Button(self, text="Done", command=lambda: self.done_pressed()) self.edit_button.grid(row=0, column=1, sticky="W") def edit_pressed(self): if self.expenditures_set: self.expenditure_table.show_config_buttons() self.edit_button.grid_forget() self.done_button.grid(row=0, column=1, sticky="W") def done_pressed(self): self.expenditure_table.hide_config_buttons() self.done_button.grid_forget() self.edit_button.grid(row=0, column=1, sticky="W") def set_expenditures(self, expenditure_matrix: [[]]): # passes the label values to the table to be inserted into the labels self.expenditures_set = True table = [] for row_index in range(len(expenditure_matrix)): values = [ TableWidget.format_as_currency( expenditure_matrix[row_index][1]), expenditure_matrix[row_index][2], expenditure_matrix[row_index][3] ] table.append(values) self.expenditure_table.load_table_data(table) def send_edit_to_database(self, table_name: str, row_index: int, values): # passes the row values to the listener to the DatabaseModel to be processed and stored in the database value_dict = { 'amount': TableWidget.unformat_from_currency(values[0]), 'name': values[1], 'type': values[2] } self.table_edit_listener.send_edit_to_database(table_name, row_index, value_dict) def set_colors(self, color_dict: {str: str}): self.colors = color_dict self.update_colors() def update_colors(self): if self.colors is not None: self.config(bg=self.colors['bg_col']) self.head_label.config(bg=self.colors['bg_col'], fg=self.colors['text_col']) self.expenditure_table.set_colors(self.colors) self.edit_button.config( fg=self.colors['button_col']['button_text_col'], highlightbackground=self.colors['button_col']['button_bg_col'], activeforeground=self.colors['button_col'] ['button_pressed_text'], activebackground=self.colors['button_col'] ['button_pressed_bg']) self.done_button.config( fg=self.colors['button_col']['button_text_col'], highlightbackground=self.colors['button_col']['button_bg_col'], activeforeground=self.colors['button_col'] ['button_pressed_text'], activebackground=self.colors['button_col'] ['button_pressed_bg'])
def on_finished(self): fileName = self.lineEdit.text() for i in range(1, self.tableWidget.columnCount()): self.headTitle.append(self.tableWidget.item(0, i).text()) id = self.currentId() if id == 4 and fileName != "": position = self.father.tab.currentIndex() root = self.father.tree.topLevelItem(position - 1) self.startrow = int(self.le1.text()) selectedList = self.father.tree.selectedItems() for i in range(0, len(selectedList)): selectedList[i].setSelected(0) # tree_record title = 'File Data' s = 0 while title in self.father.tree_record[root.text(0)]: s += 1 title = 'File Data' + str(s) self.father.tree_record[root.text(0)][title] = {'type': 'FileData'} child = QTreeWidgetItem(root) child.setText(0, title) root.setExpanded(1) child.setSelected(1) data = [] suffixList = fileName.split('.') suffix = suffixList[-1] if suffix != 'xls' and suffix != 'xlsx': filename = open(fileName) line1s = filename.readlines() for line in line1s[self.startrow - 1:]: if line.rstrip() == '': continue temp = line.rstrip().split(',') data.append(temp) if suffix == 'xls' or suffix == 'xlsx': data = xlrd.open_workbook(fileName) table = data.sheets()[0] for i in range(self.startrow - 1, table.nrows): datatemp = [] for j in range(0, table.ncols): datatemp.append(str(table.cell(i, j).value)) data.append(datatemp) self.tableWidget = TableWidget(self.father, data, self.headTitle, 0, 0) sub = QMdiSubWindow() sub.setWindowIcon(QIcon(".\\image\\logo.png")) sub.setWidget(self.tableWidget) sub.setWindowTitle(title) sub.resize(750, 750) self.father.tab.widget(position).addSubWindow(sub) sub.show() self.father.tab.widget(position).setActiveSubWindow(sub)
class Wizard(QWizard): def __init__(self, parent): super(Wizard, self).__init__(parent) self.setWindowTitle("File-Choosing Wizard") self.setWindowIcon(QIcon(".\\image\\logo.png")) self.setGeometry(600, 250, 350, 350) self.father = parent self.linenumber = 0 firstPage = QWizardPage() firstPage.setSubTitle("welcome") firstPage.setPixmap(QWizard.WatermarkPixmap, QPixmap(".\\image\\image.jpg")) label = QLabel() label.setText( "This wizard will guide you to select\n and preview the documents. \n \nTips: If you need inversion function, \nplease change the column names to Vxx, Vxy,\n Vxz, Vyy, Vyz, Vzz on the last page. \n If you are ready, please click Next." ) label.setAlignment(Qt.AlignCenter) layout1 = QVBoxLayout() layout1.addWidget(label) firstPage.setLayout(layout1) secondPage = QWizardPage() secondPage.setSubTitle("Choose File") self.lineEdit = QLineEdit() self.button = QPushButton("Choose File", secondPage) layout = QHBoxLayout() layout.addWidget(self.lineEdit) layout.addWidget(self.button) layout3 = QVBoxLayout() layout3.addStretch(5) layout3.addLayout(layout) layout3.addStretch(5) layout3.setAlignment(layout, Qt.AlignCenter) secondPage.setLayout(layout3) thirdPage = QWizardPage() thirdPage.setSubTitle("preview & choose") #self.tw = QTableWidget() self.te = QTextEdit() self.text1 = QLabel("Data Start Line:") self.le1 = QLineEdit() layout21 = QHBoxLayout() layout21.addStretch(1) layout21.addWidget(self.text1, 1) layout21.addWidget(self.le1, 1) layout21.addStretch(1) layout2 = QVBoxLayout() layout2.addWidget(self.te, 3) layout2.addLayout(layout21, 1) thirdPage.setLayout(layout2) forthPage = QWizardPage() forthPage.setSubTitle("Fill in the Coordinate Name") tip = QLabel(self) tip.setText("Double-click the header(s) to name the column(s)!") tip.setAlignment(Qt.AlignCenter) self.tableWidget = QTableWidget() layout4 = QVBoxLayout() layout4.addWidget(tip, 1) layout4.addWidget(self.tableWidget, 9) forthPage.setLayout(layout4) self.startrow = 0 self.headTitle = ["ZERO"] self.uplimit = 0 self.setWizardStyle(QWizard.ModernStyle) self.setPage(1, firstPage) self.setPage(2, secondPage) self.setPage(3, thirdPage) self.setPage(4, forthPage) self.setStartId(1) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.button.clicked.connect(self.chooseFile) self.currentIdChanged.connect(self.on_currentIdChanged) self.finished.connect(self.on_finished) def isFloot(self, s): try: s = float(s) except TypeError: return False except ValueError: return False else: return True def chooseFile(self): name = QFileDialog.getOpenFileName(self, 'Open File', './', '*.txt *.xls') self.lineEdit.setText(str(name[0])) def validateCurrentPage(self): fileName = self.lineEdit.text() id = self.currentId() if id == 2: if fileName == "": QMessageBox.information(self, "Attention", "Please Choose File") return 0 with open(fileName, 'r') as fw: lines = fw.readlines() h = len(lines) for i in range(0, h): line = lines[i].rstrip().split(',') if self.isFloot(line[0]) == 1: self.le1.setText(str(i + 1)) break if id == 3: if self.le1.text() == "": QMessageBox.information(self, "Attention", "Please Fill in Data Start Line") return 0 else: try: temp = int(self.le1.text()) except ValueError: QMessageBox.information(self, "Attention", "Data Start Line isn't a integer") return 0 if temp < 1 or temp > self.uplimit: return 0 if id == 4: headTemp = [] for i in range(1, self.tableWidget.columnCount()): headTemp.append(self.tableWidget.item(0, i).text()) flagX = 0 flagY = 0 for i in range(0, len(headTemp)): if headTemp[i] == 'X' or headTemp[i] == 'x': flagX = 1 if headTemp[i] == 'Y' or headTemp[i] == 'y': flagY = 1 if flagX == 0 or flagY == 0: QMessageBox.information(self, "Attention", "No X, Y Axes Selected.") return 0 return 1 def on_currentIdChanged(self): fileName = self.lineEdit.text() id = self.currentId() suffixList = fileName.split('.') suffix = suffixList[-1] if id == 3 and fileName != "": if suffix != 'xls' and suffix != 'xlsx': filename = open(fileName) line1s = filename.readlines() self.uplimit = len(line1s) aa = "" count = 1 for line in line1s: aa = aa + str(count) + " " + line + "\n" count += 1 td = QTextDocument(aa) self.te.setDocument(td) if suffix == 'xls' or suffix == 'xlsx': data = xlrd.open_workbook(fileName) table = data.sheets()[0] self.uplimit = table.nrows aa = "" for i in range(0, table.nrows): aa = aa + str(i + 1) + " " for j in range(0, table.ncols): aa = aa + str(table.cell(i, j).value) + "\t" aa = aa + "\n" td = QTextDocument(aa) self.te.setDocument(td) if id == 4 and self.le1.text() != "": fileName = self.lineEdit.text() data = [] if suffix != 'xls' and suffix != 'xlsx': filename = open(fileName) line1s = filename.readlines() for line in line1s[int(self.le1.text()) - 1:]: if line.rstrip() == '': continue temp = line.rstrip().split(',') for i in range(0, len(temp)): if temp[i] == "": QMessageBox.information( self, "Attention", "File Exceptions.Back to the Previous Page.") self.back() self.back() return data.append(temp) if suffix == 'xls' or suffix == 'xlsx': file = xlrd.open_workbook(fileName) table = file.sheets()[0] for i in range(int(self.le1.text()) - 1, table.nrows): datatemp = [] for j in range(0, table.ncols): if str(table.cell(i, j).value) == "": QMessageBox.information( self, "Attention", "File Exceptions. Back to the Previous Page.") self.back() self.back() return datatemp.append(str(table.cell(i, j).value)) data.append(datatemp) tempcount = len(data[0]) for i in range(1, len(data)): if tempcount != len(data[i]): QMessageBox.information( self, "Attention", "File Exceptions. Back to the Previous Page.") self.back() self.back() return self.tableWidget.setColumnCount(len(data[0]) + 1) self.tableWidget.setRowCount(len(data) + 1) self.tableWidget.horizontalHeader().setVisible(0) self.tableWidget.verticalHeader().setVisible(0) self.linenumber = len(data[0]) + 1 temp_header = [] flag = 0 with open(fileName, 'r') as f: for i in range(0, int(self.le1.text()) - 1): t = f.readline().rstrip('\n') temp_header = t.rstrip().split(',') if len(temp_header) == len(data[0]): flag = 1 for i in range(1, len(data[0]) + 1): self.tableWidget.setItem( 0, i, QTableWidgetItem(temp_header[i - 1])) if flag == 0: header = ['Vxx', 'Vxy', 'Vxz', 'Vyy', 'Vyz', 'Vzz', 'x', 'y'] if (len(data[0]) + 1 > 8): for i in range(0, len(data[0]) - 7): header.append('V' + str(i)) for i in range(1, len(data[0]) + 1): self.tableWidget.setItem(0, i, QTableWidgetItem(header[i - 1])) self.tableWidget.setItem(0, len(data[0]) - 1, QTableWidgetItem('x')) self.tableWidget.setItem(0, len(data[0]), QTableWidgetItem('y')) for i in range(1, len(data) + 1): self.tableWidget.setItem(i, 0, QTableWidgetItem(str(i))) for j in range(1, len(data[0]) + 1): self.tableWidget.setItem( i, j, QTableWidgetItem(data[i - 1][j - 1])) def on_finished(self): fileName = self.lineEdit.text() for i in range(1, self.tableWidget.columnCount()): self.headTitle.append(self.tableWidget.item(0, i).text()) id = self.currentId() if id == 4 and fileName != "": position = self.father.tab.currentIndex() root = self.father.tree.topLevelItem(position - 1) self.startrow = int(self.le1.text()) selectedList = self.father.tree.selectedItems() for i in range(0, len(selectedList)): selectedList[i].setSelected(0) # tree_record title = 'File Data' s = 0 while title in self.father.tree_record[root.text(0)]: s += 1 title = 'File Data' + str(s) self.father.tree_record[root.text(0)][title] = {'type': 'FileData'} child = QTreeWidgetItem(root) child.setText(0, title) root.setExpanded(1) child.setSelected(1) data = [] suffixList = fileName.split('.') suffix = suffixList[-1] if suffix != 'xls' and suffix != 'xlsx': filename = open(fileName) line1s = filename.readlines() for line in line1s[self.startrow - 1:]: if line.rstrip() == '': continue temp = line.rstrip().split(',') data.append(temp) if suffix == 'xls' or suffix == 'xlsx': data = xlrd.open_workbook(fileName) table = data.sheets()[0] for i in range(self.startrow - 1, table.nrows): datatemp = [] for j in range(0, table.ncols): datatemp.append(str(table.cell(i, j).value)) data.append(datatemp) self.tableWidget = TableWidget(self.father, data, self.headTitle, 0, 0) sub = QMdiSubWindow() sub.setWindowIcon(QIcon(".\\image\\logo.png")) sub.setWidget(self.tableWidget) sub.setWindowTitle(title) sub.resize(750, 750) self.father.tab.widget(position).addSubWindow(sub) sub.show() self.father.tab.widget(position).setActiveSubWindow(sub)
def __init__(self, parent): super(Wizard, self).__init__(parent) self.setWindowTitle("File-Choosing Wizard") self.setWindowIcon(QIcon(".\\image\\logo.png")) self.setGeometry(600, 250, 350, 350) self.father = parent self.linenumber = 0 firstPage = QWizardPage() firstPage.setSubTitle("welcome") firstPage.setPixmap(QWizard.WatermarkPixmap, QPixmap(".\\image\\image.jpg")) label = QLabel() label.setText( "This wizard will guide you to select\n and preview the documents. \n \nTips: If you need inversion function, \nplease change the column names to Vxx, Vxy,\n Vxz, Vyy, Vyz, Vzz on the last page. \n If you are ready, please click Next." ) label.setAlignment(Qt.AlignCenter) layout1 = QVBoxLayout() layout1.addWidget(label) firstPage.setLayout(layout1) secondPage = QWizardPage() secondPage.setSubTitle("Choose File") self.lineEdit = QLineEdit() self.button = QPushButton("Choose File", secondPage) layout = QHBoxLayout() layout.addWidget(self.lineEdit) layout.addWidget(self.button) layout3 = QVBoxLayout() layout3.addStretch(5) layout3.addLayout(layout) layout3.addStretch(5) layout3.setAlignment(layout, Qt.AlignCenter) secondPage.setLayout(layout3) thirdPage = QWizardPage() thirdPage.setSubTitle("preview & choose") #self.tw = QTableWidget() self.te = QTextEdit() self.text1 = QLabel("Data Start Line:") self.le1 = QLineEdit() layout21 = QHBoxLayout() layout21.addStretch(1) layout21.addWidget(self.text1, 1) layout21.addWidget(self.le1, 1) layout21.addStretch(1) layout2 = QVBoxLayout() layout2.addWidget(self.te, 3) layout2.addLayout(layout21, 1) thirdPage.setLayout(layout2) forthPage = QWizardPage() forthPage.setSubTitle("Fill in the Coordinate Name") tip = QLabel(self) tip.setText("Double-click the header(s) to name the column(s)!") tip.setAlignment(Qt.AlignCenter) self.tableWidget = QTableWidget() layout4 = QVBoxLayout() layout4.addWidget(tip, 1) layout4.addWidget(self.tableWidget, 9) forthPage.setLayout(layout4) self.startrow = 0 self.headTitle = ["ZERO"] self.uplimit = 0 self.setWizardStyle(QWizard.ModernStyle) self.setPage(1, firstPage) self.setPage(2, secondPage) self.setPage(3, thirdPage) self.setPage(4, forthPage) self.setStartId(1) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.button.clicked.connect(self.chooseFile) self.currentIdChanged.connect(self.on_currentIdChanged) self.finished.connect(self.on_finished)
class BalanceWidget(tkinter.Frame): # is a widget that tells the user the balance and the sum def __init__(self, parent, **optional_arguments): # initialized the frame and sub frames tkinter.Frame.__init__(self, parent) self.colors = None self.table_edit_listener: TableEditListener = None self.field_count = default_field_count self.expenditures_set = False # set up and process the optional arguments self.title_font = default_title_font self.head_font = default_table_head_font self.entry_font = default_entry_font self.title_text = default_title_text self.table_widget_name = None self.process_optional_arguments(optional_arguments) # sets up the title label self.head_label: tkinter.Label = None self.setup_title_label() # set up the edit button self.edit_button = None self.done_button = None self.setup_edit_button() # sets up the balance table self.balance_table: TableWidget = None self.setup_balance_table() self.balance_table.hide_config_buttons() def add_listener(self, listener): self.table_edit_listener = listener def process_optional_arguments(self, optional_arguments): # processes optional arguments passed to the Balance Widget # store the label fonts if 'title_font' in optional_arguments: self.title_font = optional_arguments['title_font'] if 'head_font' in optional_arguments: self.head_font = optional_arguments['head_font'] if 'entry_font' in optional_arguments: self.entry_font = optional_arguments['entry_font'] # stores the name if 'name' in optional_arguments: self.title_text = optional_arguments['name'] if self.title_text == "Initial Balance": self.table_widget_name = "initialBalances" elif self.title_text == "Current Balance": self.table_widget_name = "currentBalances" def setup_title_label(self): # adds a title label above the table self.head_label = tkinter.Label(self) self.head_label.config(text=self.title_text, font=self.title_font) self.head_label.grid(row=0, column=0, sticky="E") def setup_edit_button(self): self.edit_button = tkinter.Button(self, text="Edit", command=lambda: self.edit_pressed()) self.done_button = tkinter.Button(self, text="Done", command=lambda: self.done_pressed()) self.edit_button.grid(row=0, column=1, sticky="W") def edit_pressed(self): if self.expenditures_set: self.balance_table.show_config_buttons() self.edit_button.grid_forget() self.done_button.grid(row=0, column=1, sticky="W") def done_pressed(self): self.balance_table.hide_config_buttons() self.done_button.grid_forget() self.edit_button.grid(row=0, column=1, sticky="W") def send_edit_to_database(self, table_name: str, row_index: int, values): # passes the row values to the listener to the DatabaseModel to be processed and stored in the database value_dict = {'amount': TableWidget.unformat_from_currency(values[1]), 'source': values[0]} self.table_edit_listener.send_edit_to_database(table_name, row_index, value_dict) def setup_balance_table(self): # invert_axis is True because the data will be added in cols self.balance_table = TableWidget(self, 2, self.field_count, table_name=self.table_widget_name, invert_axis=True, column_widths=default_field_col_widths, head_font=self.head_font, entry_font=self.entry_font, header_widths=default_header_widths) self.balance_table.add_listener(self) self.balance_table.set_header_values(['Source', 'Amount']) self.balance_table.grid(row=1, columnspan=2) def set_balances(self, balance_matrix: [[]]): # sets the values in the balances table given the balance matrix table = [] for row_index in range(len(balance_matrix)): values = [balance_matrix[row_index][1], TableWidget.format_as_currency(balance_matrix[row_index][2])] table.append(values) self.balance_table.load_table_data(table) self.expenditures_set = True def set_colors(self, color_dict: {str: str}): self.colors = color_dict self.update_colors() def update_colors(self): if self.colors is not None: self.config(bg=self.colors['bg_col']) self.head_label.config(bg=self.colors['bg_col'], fg=self.colors['text_col']) self.balance_table.set_colors(self.colors) self.edit_button.config(fg=self.colors['button_col']['button_text_col'], highlightbackground=self.colors['button_col']['button_bg_col'], activeforeground=self.colors['button_col']['button_pressed_text'], activebackground=self.colors['button_col']['button_pressed_bg']) self.done_button.config(fg=self.colors['button_col']['button_text_col'], highlightbackground=self.colors['button_col']['button_bg_col'], activeforeground=self.colors['button_col']['button_pressed_text'], activebackground=self.colors['button_col']['button_pressed_bg'])
class DataVisualizer(tkinter.LabelFrame): def __init__(self, parent, **optional_arguments): tkinter.LabelFrame.__init__(self, parent, text=optional_arguments['text']) self.colors = None # setup default parameters and then process optional arguments self.field_count = default_field_count self.process_optional_arguments(optional_arguments) # setup the table showing initial balance, current balance, and expenditure totals self.totals_table: TableWidget = None self.load_total_amounts() # sets up a separator between the two tables separator = Separator(self) separator.grid(row=0, column=1, sticky="NS") # setup the table showing spending by category self.category_table: TableWidget = None self.load_spending_by_category() # setup the pie chart self.pie_chart = PieChart(self) self.pie_chart.grid(row=1, columnspan=3) self.load_table_data(None, None, None) def process_optional_arguments(self, optional_arguments): if 'field_count' in optional_arguments.keys(): self.field_count = optional_arguments['field_count'] def load_spending_by_category(self): self.category_table = TableWidget(self, 2, self.field_count, head_font=default_table_head_font, entry_font=default_entry_font, entry_justify_list=["right", "left"], head_justify_list=["right", "left"]) self.category_table.hide_config_buttons() self.category_table.set_header_values(['Category', 'Amount']) self.category_table.grid(row=0, column=2) def load_total_amounts(self): self.totals_table = TableWidget( self, 3, 1, entry_font=default_entry_font, entry_justify=["left"], head_justify_list=["right", "right", "right"], invert_axis=True) self.totals_table.hide_config_buttons() self.totals_table.set_header_values( ["Initial Total", "Expenditure Total", "Current Total"]) self.totals_table.grid(row=0, column=0) def load_table_data(self, expenditures_by_type: [[]], initial_balances, current_balances): self.load_expenditure_data(expenditures_by_type) self.load_totals_data(initial_balances, expenditures_by_type, current_balances) self.update_colors() def load_expenditure_data(self, expenditures_by_type: [[]]): if expenditures_by_type is not None and expenditures_by_type != []: labels = [] values = [] table = [] for row_index in range(len(expenditures_by_type)): labels.append(expenditures_by_type[row_index][0]) values.append(expenditures_by_type[row_index][1]) table.append([ expenditures_by_type[row_index][0], TableWidget.format_as_currency( expenditures_by_type[row_index][1]) ]) self.category_table.load_table_data(table) self.pie_chart.construct_pie_chart( labels, values, text_col=self.pie_chart.label_text_col) else: self.category_table.clear_labels() self.pie_chart.construct_empty_chart() def load_totals_data(self, initial_balances, expenditures_by_type, current_balances): if expenditures_by_type is not None and expenditures_by_type != []: total_spending = 0 for row in expenditures_by_type: total_spending += row[1] spending_text = TableWidget.format_as_currency(total_spending) self.totals_table.set_value(spending_text, 0, 1) else: self.totals_table.set_value("-", 0, 1) if initial_balances is not None and initial_balances != []: total_initial_balance = 0 for balance in initial_balances: total_initial_balance += balance[2] initial_text = TableWidget.format_as_currency( total_initial_balance) self.totals_table.set_value(initial_text, 0, 0) else: self.totals_table.set_value("-", 0, 0) if current_balances is not None and current_balances != []: total_current_balance = 0 for balance in current_balances: total_current_balance += balance[2] current_text = TableWidget.format_as_currency( total_current_balance) self.totals_table.set_value(current_text, 0, 2) else: self.totals_table.set_value("-", 0, 2) def set_colors(self, color_dict: {str: str}): self.colors = color_dict self.update_colors() def update_colors(self): if self.colors is not None: self.config(bg=self.colors['bg_col'], fg=self.colors['text_col']) self.pie_chart.set_colors(self.colors['pie_chart_colors']) self.category_table.set_colors( self.colors['category_table_colors']) self.totals_table.set_colors(self.colors['totals_table_colors'])
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.imageMenu = menubar.addMenu('&Images') self.roiMenu = menubar.addMenu('&ROIs') self.submenu = self.roiMenu.addMenu(self.icons['roiAddIcon'],"Add ROI") self.analyseMenu = menubar.addMenu('&Analysis') self.aboutMenu = menubar.addMenu('A&bout') def createActions(self): # Actions for File menu self.exitAct = QtGui.QAction("&Quit", self, shortcut="Ctrl+Q",statusTip="Exit the application") self.exitAct.triggered[()].connect(self.close) self.fileMenu.addAction(self.exitAct) # Actions for Images 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") imageMenuActions = [self.loadImageAct,self.removeImageAct] imageMenuActFuncs = [self.loadImages,self.removeImage] for i in xrange(len(imageMenuActions)): action = imageMenuActions[i] function = imageMenuActFuncs[i] action.triggered[()].connect(function) self.imageMenu.addAction(self.loadImageAct) self.imageMenu.addAction(self.removeImageAct) # Actions for ROI menu self.addROIRectAct = QtGui.QAction("Rectangular",self.submenu) self.addROIPolyAct = QtGui.QAction("Polygon",self.submenu) 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.sidePanel.buttRoiAnalysis.clicked.connect(self.getBMD) self.sidePanel.buttImgAnalysis.clicked.connect(self.imageAnalysis) def onAbout(self): """ About BMDanalyse message""" author ='Michael Hogg' date ='2016' 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 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!='': img = Image.open(str(fileName)) imgarr = np.array(img.convert('L')) # Convert to 8-bit imgarr = imgarr.swapaxes(0,1) 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 is 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] # 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.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 is 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) # Doesn't work correctly if images are not all the same shape 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 is 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 is 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) self.imageWin.vb.img2.setLevels([0,255]) 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 = ImageItem(arr,autoRange=False,autoLevels=False) self.imageWin.vb.addItem(self.imageWin.vb.img1) self.imageWin.vb.img2 = 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): 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() 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 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=='': 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 = TableWidget(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()
def on_finished(self): self.xlow = float(self.xle1.text()) self.xhigh = float(self.xle2.text()) self.dx = float(self.xle3.text()) self.ylow = float(self.yle1.text()) self.yhigh = float(self.yle2.text()) self.dy = float(self.yle3.text()) if len(self.data) == 0: return xlow = float(self.xle1.text()) xhigh = float(self.xle2.text()) xdistance = float(self.xle3.text()) ylow = float(self.yle1.text()) yhigh = float(self.yle2.text()) ydistance = float(self.yle3.text()) model_Number = int(self.lineEdit.text()) Observation_height = float(self.le3.text()) mw = ModelWidget(self) mwTitle = self.le1.text() mwColorBarTitle = self.le2.text() if mwTitle == "": mwTitle = "Forwarding Model" mw.mpl.setTitle(mwTitle) densityData = [] c = [] b = [] a = [] flag = 0 zmax = 0 for i in range(0, len(self.data)): if self.data[i][0] == "Cube": density = float(self.data[i][4]) densityData.append(density) self.densityMax = max(densityData) self.densityMin = min(densityData) if self.densityMax == self.densityMin: self.densityMax += 1 mw.mpl.setRange(self.densityMin, self.densityMax) for i in range(0, len(self.data)): if self.data[i][0] == "Cube": flag = 1 xlim = self.data[i][1].split(',') if len(xlim) == 1: xlim = self.data[i][1].split(',') ylim = self.data[i][2].split(',') if len(ylim) == 1: ylim = self.data[i][2].split(',') zlim = self.data[i][3].split(',') if len(zlim) == 1: zlim = self.data[i][3].split(',') density = float(self.data[i][4]) tem = [] tem.append(float(zlim[0])) tem.append(float(zlim[1])) c.append(tem) tem1 = [] tem1.append(float(ylim[0])) tem1.append(float(ylim[1])) b.append(tem1) tem2 = [] tem2.append(float(xlim[0])) tem2.append(float(xlim[1])) a.append(tem2) if zmax < float(zlim[1]): k = int(float(zlim[1]) / 1000) yu = float(zlim[1]) - k * 1000 if yu > 0: zmax = (k + 1) * 1000 else: zmax = k * 1000 mw.mpl.paintCube(xlim, ylim, zlim, density, xlow - xdistance / 2, xhigh + xdistance / 2, ylow - ydistance / 2, yhigh + ydistance / 2, zmax, 1, 1) self.zmax = zmax if mwColorBarTitle == "": mwColorBarTitle = "density(g/cm^3)" mw.mpl.setColorbar(mwColorBarTitle) frontView = QAction("X-Z Profile", self) sideView = QAction("Y-Z Profile", self) downView = QAction("X-Y Profile", self) mw.mpl.menu.addAction(frontView) mw.mpl.menu.addAction(sideView) mw.mpl.menu.addAction(downView) x = [] y = [] nx = int((xhigh - xlow) / xdistance) + 1 ny = int((yhigh - ylow) / ydistance) + 1 point_count = nx * ny for i in range(0, nx): x.append(xlow + i * xdistance) for i in range(0, ny): y.append(ylow + i * ydistance) mx = [0 for x in range(0, 2 * model_Number)] my = [0 for x in range(0, 2 * model_Number)] mz = [0 for x in range(0, 2 * model_Number)] for i in range(0, len(self.data)): if self.data[i][0] == "Cube": flag = 1 xlim = self.data[i][1].split(',') if len(xlim) == 1: xlim = self.data[i][1].split(',') ylim = self.data[i][2].split(',') if len(ylim) == 1: ylim = self.data[i][2].split(',') zlim = self.data[i][3].split(',') if len(zlim) == 1: zlim = self.data[i][3].split(',') mx[i] = float(xlim[0]) mx[i + model_Number] = float(xlim[1]) my[i] = float(ylim[0]) my[i + model_Number] = float(ylim[1]) mz[i] = float(zlim[0]) mz[i + model_Number] = float(zlim[1]) NX = c_int(nx) NY = c_int(ny) POINT_COUNT = c_int(point_count) MODEL_NUMBER = c_int(model_Number) XLOW = c_double(xlow) XDISTANCE = c_double(xdistance) XHIGH = c_double(xhigh) YLOW = c_double(ylow) YDISTANCE = c_double(ydistance) YHIGH = c_double(yhigh) OBSERVATION_HEIGHT = c_double(Observation_height) X = POINTER(c_double)((c_double * len(x))(*x)) Y = POINTER(c_double)((c_double * len(y))(*y)) MX = POINTER(c_double)((c_double * len(mx))(*mx)) MY = POINTER(c_double)((c_double * len(my))(*my)) MZ = POINTER(c_double)((c_double * len(mz))(*mz)) DENSITYDATA = POINTER(c_double)( (c_double * len(densityData))(*densityData)) ll = cdll.LoadLibrary Objdll = ll("./Forwarding_DLL.dll") func = Objdll.Forwarding func.argtypes = (c_int, c_int,c_int,c_int, c_double,c_double,c_double,c_double,c_double, c_double, c_double, \ POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double)) func.restype = POINTER(c_double) data_result = [] data_result = Objdll.Forwarding(NX, NY, POINT_COUNT, MODEL_NUMBER, XLOW, XDISTANCE, XHIGH, YLOW, YDISTANCE,\ YHIGH, OBSERVATION_HEIGHT, X, Y, MX, MY, MZ, DENSITYDATA) F_Data = [] for i in range(0, len(y)): for j in range(0, len(x)): temp = [] for k in range(0, 7): temp.append( float(data_result[k * point_count + j + i * len(x)])) temp.append(x[j]) temp.append(y[i]) F_Data.append(temp) headTitle = ['0', 'V', 'X', 'Y'] if flag == 1: headTitle = [ '0', 'Vxx', 'Vxy', 'Vxz', 'Vyy', 'Vyz', 'Vzz', 'Vz', 'X', 'Y' ] tableWidget = TableWidget(self.father, F_Data, headTitle, 0, 0) tableWidget.forwardingInformation = tableWidget.forwardingInformation + "X-Range:" + str( xlow) + "m-" + str(xhigh) + "m dx" + str(xdistance) + "m\n" tableWidget.forwardingInformation = tableWidget.forwardingInformation + "Y-Range:" + str( ylow) + "m-" + str(yhigh) + "m dy" + str(ydistance) + "m\n" tableWidget.forwardingInformation = tableWidget.forwardingInformation + "Observation height:" + str( Observation_height) + "m\n" tableWidget.forwardingInformation = tableWidget.forwardingInformation + self.information position = self.father.tab.currentIndex() root = self.father.tree.topLevelItem(position - 1) s = root.text(0) title = 'Data' num = 0 while title in self.father.tree_record[s]: num += 1 title = 'Data' + str(num) frontView.triggered.connect(lambda: self.dialog(1, title)) sideView.triggered.connect(lambda: self.dialog(2, title)) downView.triggered.connect(lambda: self.dialog(3, title)) sub = QMdiSubWindow() sub.setWindowIcon(QIcon(".\\image\\logo.png")) sub.setWidget(tableWidget) sub.setWindowTitle(title) sub.resize(750, 750) self.father.tab.widget(position).addSubWindow(sub) self.father.tab.widget(position).setActiveSubWindow(sub) sub.show() selectedList = self.father.tree.selectedItems() for i in range(0, len(selectedList)): selectedList[i].setSelected(0) self.father.tree_record[s][title] = {} self.father.tree_record[s][title]={'Number_of_Model':str(self.lineEdit.text()), \ 'Model_Title':str(mwTitle), 'ColorBar_Title':str(mwColorBarTitle),'Observation_height':str(self.le3.text()), \ 'xlow':str(self.xle1.text()), 'xhigh':str(self.xle2.text()), 'xdistance':str(self.xle3.text()), \ 'ylow':str(self.yle1.text()), 'yhigh':str(self.yle2.text()), 'ydistance':str(self.xle3.text()), \ 'ForwardingModel':mw, 'ForwardingModelFlag':0, 'type':'ForwardingData', 'densityMax':self.densityMax, \ 'densityMin':self.densityMin} for i in range(0, int(self.lineEdit.text())): name_temp = 'Number_' + str(i + 1) self.father.tree_record[s][title][name_temp] = {} for j in range(0, len(self.data[i])): self.father.tree_record[s][title][name_temp][str(j)] = str( self.data[i][j]) child1 = QTreeWidgetItem(root) child1.setText(0, title) child1.setSelected(1) root.setExpanded(1) return
def setupGUI(self): self.setWindowTitle("Sonic Viewer") pg.setConfigOption('background', (255,255,255)) pg.setConfigOption('foreground',(0,0,0)) self.layout = QtGui.QVBoxLayout() self.layout.setContentsMargins(0,0,0,0) self.layout.setSpacing(0) self.setLayout(self.layout) ## setting up the menu bar self.menuBar = QtGui.QMenuBar() self.layout.setMenuBar(self.menuBar) self.viewMenu = self.menuBar.addMenu('View') self.modeMenu = self.menuBar.addMenu('Mode') self.transformMenu = self.menuBar.addMenu('Transform') self.intMenu = self.menuBar.addMenu('Interpretation') # VIEW MENU self.autoScaleButton = QtGui.QAction('Auto scale',self,checkable=True) self.autoScaleButton.setChecked(True) self.showArrivalsButton = QtGui.QAction('Arrivals',self,checkable=True) self.showArrivalsButton.setDisabled(True) self.showTableButton = QtGui.QAction('Table',self) self.yAxisMenu = self.viewMenu.addMenu('y axis') self.editGradientsButton = QtGui.QAction('Edit Gradients',self) self.invertYButton = QtGui.QAction('Invert y axis',self,checkable=True) self.viewMenu.addAction(self.autoScaleButton) self.viewMenu.addAction(self.showArrivalsButton) self.viewMenu.addAction(self.showTableButton) self.viewMenu.addAction(self.editGradientsButton) self.viewMenu.addAction(self.invertYButton) # MODE MENU self.modeGroup = QtGui.QActionGroup(self) self.waveFormButton = QtGui.QAction('Wave Forms',self,checkable=True) self.contourButton = QtGui.QAction('Contours',self,checkable=True) self.waveFormButton.setActionGroup(self.modeGroup) self.contourButton.setActionGroup(self.modeGroup) self.contourButton.setChecked(True) self.modeMenu.addAction(self.waveFormButton) self.modeMenu.addAction(self.contourButton) # INTERPRETATION MENU self.pickArrivalsButton = QtGui.QAction('Pick arrivals',self) self.handPickArrivalsButton = QtGui.QAction('Hand pick',self,checkable=True) self.moduliButton = QtGui.QAction('Elastic moduli',self) self.moduliButton.setDisabled(True) self.handPickArrivalsButton.setDisabled(True) self.intMenu.addAction(self.pickArrivalsButton) self.intMenu.addAction(self.handPickArrivalsButton) self.intMenu.addAction(self.moduliButton) # TRANSFORM MENU self.showForrierMagnitudeButton = QtGui.QAction('Fourrier magnitude',self) self.showForrierPhasesButton = QtGui.QAction('Fourrier phases',self) self.filteringButton = QtGui.QAction('Frequency filtering',self,checkable=True) self.transformMenu.addAction(self.showForrierMagnitudeButton) self.transformMenu.addAction(self.showForrierPhasesButton) self.transformMenu.addAction(self.filteringButton) # dict to store actions for y Axis self.yAxisButtons = {} self.yAxisGroup = QtGui.QActionGroup(self) self.yAxisButtons['Track #'] = QtGui.QAction('Track #',self,checkable=True) self.yAxisButtons['Track #'].setActionGroup(self.yAxisGroup) self.yAxisMenu.addAction(self.yAxisButtons['Track #']) self.yAxisButtons['Track #'].setChecked(True) # for wave in WaveTypes: # split main widget into plotting area and parameters area self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.layout.addWidget(self.splitter) # split parameter area into 3 for each wave self.treeSplitter = QtGui.QSplitter() self.treeSplitter.setOrientation(QtCore.Qt.Vertical) self.splitter.addWidget(self.treeSplitter) # create parameter trees self.trees={} for wave in WaveTypes: self.trees[wave] = ParameterTree(showHeader=False) self.treeSplitter.addWidget(self.trees[wave]) # create layout for the plotting area self.sublayout = pg.GraphicsLayoutWidget() self.splitter.addWidget(self.sublayout) self.params = {} self.plots = {} for wave in WaveTypes: # create parameter instances self.params[wave] = Parameter.create(name=wave + ' wave', type='group',children=Parameters) self.trees[wave].setParameters(self.params[wave],showTop=True) # fill plotting area with 3 plots # self.plots[wave] = self.sublayout.addPlot() self.plots[wave] = self.sublayout.addPlot(viewBox=ViewBox()) setup_plot(self.plots[wave]) self.sublayout.nextRow() self.params['Sx'].param('Arrival times').param('BTA').setValue(36) self.params['Sx'].param('Arrival times').param('ATA').setValue(5) self.params['Sx'].param('Arrival times').param('DTA').setValue(20) self.params['Sy'].param('Arrival times').param('BTA').setValue(100) self.params['Sy'].param('Arrival times').param('ATA').setValue(5) self.params['Sy'].param('Arrival times').param('DTA').setValue(30) # create table widget to show arrival times self.QTable = TableWidget(['Number P','Number Sx','Number Sy','P','Sx','Sy']) # self.splitter.addWidget(self.QTable) self.QTable.setColumnCount(6) self.QTable.hide() self.splitter.setSizes([int(self.width()*0.30), int(self.width()*0.35), int(self.width()*0.35) ]) self.splitter.setStretchFactor(0, 0) self.splitter.setStretchFactor(1, 1) self.splitter.setStretchFactor(2, 0)