#/usr/bin/env python import sys import readline try: from akvo.gui.main_ui import Ui_MainWindow uicerr = False except: # Fallback from akvo.gui.mainui import Ui_MainWindow uicerr = """ USING THE DEFAULT GUI FILES, AKVO MAY NOT WORK CORRECTLY! See INSTALL.txt for details regarding GUI configuration if you are encountering problems. Clicking ignore will prevent this warning from showing each time you launch Akvo. """ import matplotlib #matplotlib.use("QT4Agg") from PyQt5 import QtCore, QtGui, QtWidgets import numpy as np import time import os from copy import deepcopy from matplotlib.backends.backend_qt4 import NavigationToolbar2QT #as NavigationToolbar import datetime, time import yaml from akvo.tressel import mrsurvey import pkg_resources # part of setuptools version = pkg_resources.require("Akvo")[0].version # Writes out numpy arrays into Eigen vectors as serialized by Lemma class MatrixXr(yaml.YAMLObject): yaml_tag = u'!MatrixXr' def __init__(self, name, hp, ac, attacks): self.name = name self.hp = hp self.ac = ac self.attacks = attacks def __repr__(self): return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (self.__class__.__name__, self.name, self.hp, self.ac, self.attacks) class VectorXr(yaml.YAMLObject): yaml_tag = r'VectorXr' def __init__(self, array): self.size = np.shape(array)[0] self.data = array.tolist() def __repr__(self): # Converts to numpy array on import return "np.array(%r)" % (self.data) try: import thread except ImportError: import _thread as thread #Py3K compatibility class MyPopup(QtWidgets.QWidget): def __init__(self, name): super().__init__() self.name = name self.initUI() def initUI(self): lblName = QtWidgets.QLabel(self.name, self) class ApplicationWindow(QtWidgets.QMainWindow): def __init__(self): QtWidgets.QMainWindow.__init__(self) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) akvohome = os.path.expanduser("~") + "/.akvo" if not os.path.exists(akvohome): os.makedirs(akvohome) self.ui = Ui_MainWindow() self.ui.setupUi(self) if uicerr != False and not os.path.exists(akvohome+"/pyuic-warned"): reply = QtGui.QMessageBox.warning(self, 'Warning', uicerr, QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ignore) if reply == 1024: # "0x400" in hex pass elif reply == 1048576: # "0x100000" in hex warn = open( akvohome+"/pyuic-warned" ,"w" ) warn.write("Gui files were not compiled locally using pyuic! Further warnings have been supressed") warn.close() self.RAWDataProc = None # initialise some stuff self.ui.lcdNumberTauPulse2.setEnabled(0) self.ui.lcdNumberTauPulse1.setEnabled(0) self.ui.lcdNumberNuTx.setEnabled(0) self.ui.lcdNumberTuneuF.setEnabled(0) self.ui.lcdNumberSampFreq.setEnabled(0) self.ui.lcdNumberTauDelay.setEnabled(0) self.ui.lcdNumberNQ.setEnabled(0) #MAK 20170126: add in a list to hold processing steps self.logText = [] #################### # Make connections # #################### # Menu items self.ui.actionOpen_GMR.triggered.connect(self.openGMRRAWDataset) self.ui.actionSave_Preprocessed_Dataset.triggered.connect(self.SavePreprocess) self.ui.actionExport_Preprocessed_Dataset.triggered.connect(self.ExportPreprocess) self.ui.actionExport_Preprocessed_Dataset.setEnabled(False) self.ui.actionOpen_Preprocessed_Dataset.triggered.connect(self.OpenPreprocess) self.ui.actionAboutAkvo.triggered.connect(self.about) # Buttons # #QtCore.QObject.connect(self.ui.fullWorkflowPushButton, QtCore.SIGNAL("clicked()"), self.preprocess ) self.ui.loadDataPushButton.pressed.connect(self.loadRAW) self.ui.sumDataGO.pressed.connect( self.sumDataChans ) self.ui.bandPassGO.pressed.connect( self.bandPassFilter ) self.ui.filterDesignPushButton.pressed.connect( self.designFilter ) self.ui.fdDesignPushButton.pressed.connect( self.designFDFilter ) self.ui.downSampleGO.pressed.connect( self.downsample ) self.ui.windowFilterGO.pressed.connect( self.windowFilter ) # self.ui.despikeGO.pressed.connect( self.despikeFilter ) # use smart stack instead self.ui.adaptGO.pressed.connect( self.adaptFilter ) self.ui.adaptFDGO.pressed.connect( self.adaptFilterFD ) self.ui.qdGO.pressed.connect( self.quadDet ) self.ui.gateIntegrateGO.pressed.connect( self.gateIntegrate ) self.ui.calcQGO.pressed.connect( self.calcQ ) self.ui.FDSmartStackGO.pressed.connect( self.FDSmartStack ) self.ui.plotQD.setEnabled(False) self.ui.plotQD.pressed.connect( self.plotQD ) self.ui.plotGI.setEnabled(False) self.ui.plotGI.pressed.connect( self.plotGI ) # Add progressbar to statusbar self.ui.barProgress = QtWidgets.QProgressBar() self.ui.statusbar.addPermanentWidget(self.ui.barProgress, 0); self.ui.barProgress.setMaximumSize(100, 16777215); self.ui.barProgress.hide(); self.ui.mplwidget_navigator.setCanvas(self.ui.mplwidget) self.ui.mplwidget_navigator_2.setCanvas(self.ui.mplwidget_2) ########################################################################## # modelling Table self.ui.loopTableWidget.setRowCount(40) self.ui.loopTableWidget.setColumnCount(5) self.ui.loopTableWidget.setHorizontalHeaderLabels( ["ch. tag", "Northing [m]","Easting [m]","Height [m]", "Radius"] ) self.ui.loopTableWidget.cellChanged.connect(self.cellChanged) self.ui.loopTableWidget.setDragDropOverwriteMode(False) self.ui.loopTableWidget.setDragEnabled(True) self.ui.loopTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) ########################################################################## # layer Table self.ui.layerTableWidget.setRowCount(80) self.ui.layerTableWidget.setColumnCount(3) self.ui.layerTableWidget.setHorizontalHeaderLabels( [r"top [m]", r"bottom [m]", "σ [ Ωm]" ] ) self.ui.layerTableWidget.setDragDropOverwriteMode(False) self.ui.layerTableWidget.setDragEnabled(True) self.ui.layerTableWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) pCell = QtWidgets.QTableWidgetItem() #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable #pCell.setBackground( QtGui.QColor("lightblue").lighter(125) ) pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) ) self.ui.layerTableWidget.setItem(0, 1, pCell) for ir in range(1, 80): for ic in range(0, 3): pCell = QtWidgets.QTableWidgetItem() #pCell.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) pCell.setFlags(QtCore.Qt.NoItemFlags) # not selectable pCell.setBackground( QtGui.QColor("lightgrey").lighter(110) ) self.ui.layerTableWidget.setItem(ir, ic, pCell) self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged) def sigmaCellChanged(self): self.ui.layerTableWidget.cellChanged.disconnect(self.sigmaCellChanged) # TODO consider building the model whenever this is called. Would be nice to be able to # do that. Would require instead dist of T2 I guess. jj = self.ui.layerTableWidget.currentColumn() ii = self.ui.layerTableWidget.currentRow() val = "class 'NoneType'>" try: val = eval (str( self.ui.layerTableWidget.item(ii, jj).text() )) except: #if jj != 0: # Error = QtWidgets.QMessageBox() # Error.setWindowTitle("Error!") # Error.setText("Non-numeric value encountered") self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged) return if jj == 1: #item.setFlags(QtCore.Qt.ItemIsEnabled) pCell = self.ui.layerTableWidget.item(ii, jj) pCell.setBackground( QtGui.QColor("white")) pCell = self.ui.layerTableWidget.item(ii+1, jj-1) if str(type(pCell)) == "": pCell = QtWidgets.QTableWidgetItem() pCell.setFlags(QtCore.Qt.ItemIsEnabled) self.ui.layerTableWidget.setItem(ii+1, jj-1, pCell) if ii == 0: pCell.setText(str(val)) #pCell3 = self.ui.layerTableWidget.item(ii+1, jj) #print ("setting", ii, jj, type(pCell3)) #print ( "setting", ii, jj, type(pCell3)) #pCell3.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled ) #pCell3.setFlags( QtCore.Qt.ItemIsEditable ) elif ii > 0: val2 = eval (str( self.ui.layerTableWidget.item(ii-1, jj).text() )) #print ("val2", val2, val, type(val)) #if str(type(pCell)) == "": if type(val) == str or val > val2: pCell.setText(str(val)) else: Error = QtWidgets.QMessageBox() Error.setWindowTitle("Error!") Error.setText("Non-increasing layer detected") Error.setDetailedText("Each layer interface must be below the one above it.") Error.exec_() pCell2 = self.ui.layerTableWidget.item(ii, jj) pCell2.setText(str("")) self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged) return print("I'm here joey") # enable next layer pCell4 = self.ui.layerTableWidget.item(ii+1, jj) pCell4.setBackground( QtGui.QColor("lightblue") ) #.lighter(110)) pCell4.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled ) pCell5 = self.ui.layerTableWidget.item(ii+1, jj+1) pCell5.setBackground( QtGui.QColor("white")) pCell5.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled ) print("ii", ii, "jj", jj) if ii == 0 and jj == 0: pCell = self.ui.layerTableWidget.item(0, 1) pCell.setBackground( QtGui.QColor("lightblue")) #.lighter(110) ) pCell.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled ) self.ui.layerTableWidget.cellChanged.connect(self.sigmaCellChanged) def cellChanged(self): # TODO consider building the model whenever this is called. Would be nice to be able to # do that. Would require instead dist of T2 I guess. jj = self.ui.loopTableWidget.currentColumn() ii = self.ui.loopTableWidget.currentRow() #if self.ui.loopTableWidget.item(ii, jj) == None: # return try: eval (str( self.ui.loopTableWidget.item(ii, jj).text() )) except: if jj != 0: Error = QtWidgets.QMessageBox() Error.setWindowTitle("Error!") Error.setText("Non-numeric value encountered") Error.setDetailedText("Modelling parameters must be able to be cast into numeric values.") Error.exec_() self.plotLoops() def plotLoops(self): #self.ui.mplwidget_3.fig.clear() self.ui.mplwidget_3.ax1.clear() self.ui.mplwidget_3.ax2.clear() nor = dict() eas = dict() dep = dict() for ii in range( self.ui.loopTableWidget.rowCount() ): for jj in range( self.ui.loopTableWidget.columnCount() ): tp = type(self.ui.loopTableWidget.item(ii, jj)) if str(tp) == "": # ugly hack needed by PySide for some strange reason. pass #print ("NONE") else: if jj == 0: idx = self.ui.loopTableWidget.item(ii, 0).text() if idx not in nor.keys(): nor[idx] = list() eas[idx] = list() dep[idx] = list() if jj == 1: nor[idx].append( eval(self.ui.loopTableWidget.item(ii, 1).text()) ) elif jj == 2: eas[idx].append( eval(self.ui.loopTableWidget.item(ii, 2).text()) ) elif jj == 3: dep[idx].append( eval(self.ui.loopTableWidget.item(ii, 3).text()) ) for ii in nor.keys(): try: self.ui.mplwidget_3.ax1.plot( np.array(nor[ii]), np.array(eas[ii]) ) except: pass self.ui.mplwidget_3.draw() def about(self): # TODO proper popup with info #self.w = MyPopup("""About Akvo \n # Akvo is an open source project developed primarily by Trevor Irons. #""") #self.w.setGeometry(100, 100, 400, 200) #self.w.show() # Just a splash screen for now logo = pkg_resources.resource_filename(__name__, 'akvo_about.png') pixmap = QtGui.QPixmap(logo) self.splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint) self.splash.show() def connectGMRDataProcessor(self): self.RAWDataProc = mrsurvey.GMRDataProcessor() self.RAWDataProc.progressTrigger.connect(self.updateProgressBar) self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP) self.RAWDataProc.doneTrigger.connect(self.doneStatus) self.RAWDataProc.updateProcTrigger.connect(self.updateProc) def openGMRRAWDataset(self): try: with open('.gmr.last.path') as f: fpath = f.readline() pass except IOError as e: fpath = '.' self.headerstr = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', fpath)[0] # arg2 = File Type 'All Files (*)' self.ui.headerFileTextBrowser.clear() self.ui.headerFileTextBrowser.append(self.headerstr) if len(self.headerstr) == 0: return # clear the processing log self.ui.logTextBrowser.clear() self.logText = [] #MAK 20170126 path,filen=os.path.split(str(self.headerstr)) f = open('.gmr.last.path', 'w') f.write( str(self.headerstr) ) # prompt last file self.connectGMRDataProcessor() self.RAWDataProc.readHeaderFile(str(self.headerstr)) # If we got this far, enable all the widgets self.ui.lcdNumberTauPulse1.setEnabled(True) self.ui.lcdNumberNuTx.setEnabled(True) self.ui.lcdNumberTuneuF.setEnabled(True) self.ui.lcdNumberSampFreq.setEnabled(True) self.ui.lcdNumberNQ.setEnabled(True) self.ui.headerFileBox.setEnabled(True) self.ui.inputRAWParametersBox.setEnabled(True) self.ui.loadDataPushButton.setEnabled(True) # make plots as you import the dataset self.ui.plotImportCheckBox.setEnabled(True) self.ui.plotImportCheckBox.setChecked(True) # Update info from the header into the GUI self.ui.pulseTypeTextBrowser.clear() self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType) self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq) self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0]) self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance) self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp) self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments) self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime) self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq ) if self.RAWDataProc.pulseType != "FID": self.ui.lcdNumberTauPulse2.setEnabled(1) self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1]) self.ui.lcdNumberTauDelay.setEnabled(1) self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay) self.ui.FIDProcComboBox.clear() if self.RAWDataProc.pulseType == "4PhaseT1": self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") self.ui.FIDProcComboBox.insertItem(1, "Pulse 2") self.ui.FIDProcComboBox.insertItem(2, "Both") self.ui.FIDProcComboBox.setCurrentIndex (1) elif self.RAWDataProc.pulseType == "FID": self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") self.ui.FIDProcComboBox.setCurrentIndex (0) def ExportPreprocess(self): try: with open('.akvo.last.yaml.path') as f: fpath = f.readline() pass except IOError as e: fpath = '.' fdir = os.path.dirname(fpath) # Pickle the preprocessed data dictionary SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Processed data (*.yaml)")[0] spath,filen=os.path.split(str(SaveStr)) f = open('.akvo.last.yaml.path', 'w') f.write( str(spath) ) # prompt last file INFO = {} INFO["headerstr"] = str(self.headerstr) INFO["pulseType"] = self.RAWDataProc.pulseType INFO["transFreq"] = self.RAWDataProc.transFreq.tolist() INFO["pulseLength"] = self.RAWDataProc.pulseLength.tolist() INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance.tolist() #INFO["samp"] = self.RAWDataProc.samp INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments #INFO["deadTime"] = self.RAWDataProc.deadTime INFO["transFreq"] = self.RAWDataProc.transFreq.tolist() INFO["processed"] = "Akvo v. 1.0, on " + time.strftime("%d/%m/%Y") #INFO["log"] = self.logText #MAK 20170128 # TI moved to direct write, this is already YAML compliant # Pulse current info ip = 0 INFO["Pulses"] = {} for pulse in self.RAWDataProc.DATADICT["PULSES"]: qq = [] qv = [] for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]): #for istack in self.RAWDataProc.DATADICT["stacks"]: # print ("stack q", self.RAWDataProc.DATADICT[pulse]["Q"][ipm,istack-1]) qq.append(np.mean( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]) ) qv.append(np.std( self.RAWDataProc.DATADICT[pulse]["Q"][ipm,:]/self.RAWDataProc.pulseLength[ip] )) INFO["Pulses"][pulse] = {} INFO["Pulses"][pulse]["units"] = "A" INFO["Pulses"][pulse]["current"] = VectorXr(np.array(qq)/self.RAWDataProc.pulseLength[ip]) INFO["Pulses"][pulse]["variance"] = VectorXr(np.array(qv)) ip += 1 # Data if self.RAWDataProc.gated == True: INFO["Gated"] = {} INFO["Gated"]["abscissa units"] = "ms" INFO["Gated"]["data units"] = "nT" for pulse in self.RAWDataProc.DATADICT["PULSES"]: INFO["Gated"][pulse] = {} INFO["Gated"][pulse]["abscissa"] = VectorXr( self.RAWDataProc.GATEDABSCISSA ) INFO["Gated"][pulse]["windows"] = VectorXr( self.RAWDataProc.GATEDWINDOW ) for ichan in self.RAWDataProc.DATADICT[pulse]["chan"]: INFO["Gated"][pulse]["Chan. " + str(ichan)] = {} INFO["Gated"][pulse]["Chan. " + str(ichan)]["STD"] = VectorXr( np.std(self.RAWDataProc.GATED[ichan]["NR"], axis=0) ) for ipm in range(self.RAWDataProc.DATADICT["nPulseMoments"]): INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " CA"] = VectorXr(self.RAWDataProc.GATED[ichan]["CA"][ipm]) INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " RE"] = VectorXr(self.RAWDataProc.GATED[ichan]["RE"][ipm]) INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IM"] = VectorXr(self.RAWDataProc.GATED[ichan]["IM"][ipm]) #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " IP"] = VectorXr(self.RAWDataProc.GATED[ichan]["IP"][ipm]) #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " NR"] = VectorXr(self.RAWDataProc.GATED[ichan]["NR"][ipm]) #INFO["Gated"][pulse]["Chan. " + str(ichan)]["Q-"+str(ipm) + " STD" ] = VectorXr(self.RAWDataProc.GATED[ichan]["SIGMA"][ipm]) # we have gated data # Window edges # Window centres with open(SaveStr, 'w') as outfile: for line in self.logText: outfile.write(line+"\n") yaml.dump(INFO, outfile, default_flow_style=False) def SavePreprocess(self): self.Log( ["Saved:" + datetime.datetime.now().isoformat()] ) import pickle, os try: with open('.akvo.last.path') as f: fpath = f.readline() pass except IOError as e: fpath = '.' fdir = os.path.dirname(fpath) # Pickle the preprocessed data dictionary SaveStr = QtWidgets.QFileDialog.getSaveFileName(self, "Save as", fdir, r"Pickle (*.dmp)") print(SaveStr) spath,filen=os.path.split(str(SaveStr[0])) f = open('.akvo.last.path', 'w') f.write( str(spath) ) # prompt last file save = open(SaveStr[0], 'wb') # Add some extra info INFO = {} INFO["pulseType"] = self.RAWDataProc.pulseType INFO["transFreq"] = self.RAWDataProc.transFreq INFO["pulseLength"] = self.RAWDataProc.pulseLength INFO["TuneCapacitance"] = self.RAWDataProc.TuneCapacitance INFO["samp"] = self.RAWDataProc.samp INFO["nPulseMoments"] = self.RAWDataProc.nPulseMoments INFO["deadTime"] = self.RAWDataProc.deadTime INFO["transFreq"] = self.RAWDataProc.transFreq INFO["headerstr"] = str(self.headerstr) INFO["log"] = self.logText #MAK 20170127 self.RAWDataProc.DATADICT["INFO"] = INFO pickle.dump(self.RAWDataProc.DATADICT, save) save.close() # Export XML file suitable for USGS ScienceBase Data Release def ExportXML(self): return 42 def OpenPreprocess(self): import pickle try: with open('.akvo.last.path') as f: fpath = f.readline() pass except IOError as e: fpath = '.' #filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', '.') fpath = QtWidgets.QFileDialog.getOpenFileName(self, 'Open preprocessed file', fpath, r"Pickle Files (*.dmp)")[0] f = open('.akvo.last.path', 'w') f.write( str(fpath) ) # prompt last file self.ui.logTextBrowser.clear() self.logText = [] if len(fpath) == 0: return pfile = open(fpath,'rb') unpickle = pickle.Unpickler(pfile) self.connectGMRDataProcessor() self.RAWDataProc.DATADICT = unpickle.load() self.RAWDataProc.readHeaderFile(self.RAWDataProc.DATADICT["INFO"]["headerstr"]) self.headerstr = self.RAWDataProc.DATADICT["INFO"]["headerstr"] self.RAWDataProc.pulseType = self.RAWDataProc.DATADICT["INFO"]["pulseType"] self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"] self.RAWDataProc.pulseLength = self.RAWDataProc.DATADICT["INFO"]["pulseLength"] self.RAWDataProc.TuneCapacitance = self.RAWDataProc.DATADICT["INFO"]["TuneCapacitance"] self.RAWDataProc.samp = self.RAWDataProc.DATADICT["INFO"]["samp"] self.RAWDataProc.nPulseMoments = self.RAWDataProc.DATADICT["INFO"]["nPulseMoments"] self.RAWDataProc.deadTime = self.RAWDataProc.DATADICT["INFO"]["deadTime"] self.RAWDataProc.transFreq = self.RAWDataProc.DATADICT["INFO"]["transFreq"] self.RAWDataProc.dt = 1./self.RAWDataProc.samp self.dataChan = self.RAWDataProc.DATADICT[ self.RAWDataProc.DATADICT["PULSES"][0] ]["chan"] #To keep backwards compatibility with prior saved pickles try: self.logText = self.RAWDataProc.DATADICT["INFO"]["log"] for a in self.logText: self.ui.logTextBrowser.append(str(a)) except KeyError: pass self.Log( ["Loaded:" + datetime.datetime.now().isoformat()] ) # If we got this far, enable all the widgets self.ui.lcdNumberTauPulse1.setEnabled(True) self.ui.lcdNumberNuTx.setEnabled(True) self.ui.lcdNumberTuneuF.setEnabled(True) self.ui.lcdNumberSampFreq.setEnabled(True) self.ui.lcdNumberNQ.setEnabled(True) self.ui.headerFileBox.setEnabled(True) self.ui.inputRAWParametersBox.setEnabled(True) self.ui.loadDataPushButton.setEnabled(True) # make plots as you import the dataset self.ui.plotImportCheckBox.setEnabled(True) self.ui.plotImportCheckBox.setChecked(True) # Update info from the header into the GUI self.ui.pulseTypeTextBrowser.clear() self.ui.pulseTypeTextBrowser.append(self.RAWDataProc.pulseType) self.ui.lcdNumberNuTx.display(self.RAWDataProc.transFreq) self.ui.lcdNumberTauPulse1.display(1e3*self.RAWDataProc.pulseLength[0]) self.ui.lcdNumberTuneuF.display(self.RAWDataProc.TuneCapacitance) self.ui.lcdNumberSampFreq.display(self.RAWDataProc.samp) self.ui.lcdNumberNQ.display(self.RAWDataProc.nPulseMoments) self.ui.DeadTimeSpinBox.setValue(1e3*self.RAWDataProc.deadTime) self.ui.CentralVSpinBox.setValue( self.RAWDataProc.transFreq ) if self.RAWDataProc.pulseType != "FID": self.ui.lcdNumberTauPulse2.setEnabled(1) self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1]) self.ui.lcdNumberTauDelay.setEnabled(1) self.ui.lcdNumberTauDelay.display(1e3*self.RAWDataProc.interpulseDelay) self.ui.FIDProcComboBox.clear() if self.RAWDataProc.pulseType == "4PhaseT1": self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() ) self.ui.FIDProcComboBox.insertItem(1, "Pulse 2") #, const QVariant & userData = QVariant() ) self.ui.FIDProcComboBox.insertItem(2, "Both") #, const QVariant & userData = QVariant() ) if len( self.RAWDataProc.DATADICT["PULSES"]) == 2: self.ui.FIDProcComboBox.setCurrentIndex (2) elif self.RAWDataProc.DATADICT["PULSES"][0] == "Pulse 1": self.ui.FIDProcComboBox.setCurrentIndex (0) else: self.ui.FIDProcComboBox.setCurrentIndex (1) elif self.RAWDataProc.pulseType == "FID": self.ui.FIDProcComboBox.insertItem(0, "Pulse 1") #, const QVariant & userData = QVariant() ) self.ui.FIDProcComboBox.setCurrentIndex (0) # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar) # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP) # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus) self.RAWDataProc.progressTrigger.connect(self.updateProgressBar) self.RAWDataProc.enableDSPTrigger.connect(self.enableDSP) self.RAWDataProc.doneTrigger.connect(self.doneStatus) self.enableAll() def loadRAW(self): ################################################# # Check to make sure we are ready to process # Header if self.RAWDataProc == None: err_msg = "You need to load a header first." reply = QtGui.QMessageBox.critical(self, 'Error', err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) return # Stacks try: self.procStacks = np.array(eval(str("np.r_["+self.ui.stacksLineEdit.text())+"]")) except: err_msg = "You need to set your stacks correctly.\n" + \ "This should be a Python Numpy interpretable list\n" + \ "of stack indices. For example 1:24 or 1:4,8:24" QtGui.QMessageBox.critical(self, 'Error', err_msg) return # Data Channels #Chan = np.arange(0,9,1) try: self.dataChan = np.array(eval(str("np.r_["+self.ui.dataChanLineEdit.text())+"]")) except: #QMessageBox messageBox; #messageBox.critical(0,"Error","An error has occured !"); #messageBox.setFixedSize(500,200); #quit_msg = "Are you sure you want to exit the program?" #reply = QtGui.QMessageBox.question(self, 'Message', # quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) err_msg = "You need to set your data channels correctly.\n" + \ "This should be a Python Numpy interpretable list\n" + \ "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \ "valid GMR data channels fall between 1 and 8. Note that\n" +\ "1:3 is not inclusive of 3 and is the same as 1,2 " reply = QtGui.QMessageBox.critical(self, 'Error', err_msg) #, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) return ############################# # Reference Channels # TODO make sure no overlap between data and ref channels self.refChan = np.array( () ) if str(self.ui.refChanLineEdit.text()): # != "none": try: self.refChan = np.array(eval(str("np.r_["+self.ui.refChanLineEdit.text())+"]")) except: err_msg = "You need to set your reference channels correctly.\n" + \ "This should be a Python Numpy interpretable list\n" + \ "of indices. For example 1 or 1:3 or 1:3 5\n\n" + \ "valid GMR data channels fall between 1 and 8. Note that\n" +\ "1:3 is not inclusive of 3 and is the same as 1,2 " QtGui.QMessageBox.critical(self, 'Error', err_msg) return ##################################################### # Load data self.lock("loading RAW GMR dataset") if self.RAWDataProc.pulseType == "FID": self.procThread = thread.start_new_thread(self.RAWDataProc.loadFIDData, \ (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \ str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \ 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self)) elif self.RAWDataProc.pulseType == "4PhaseT1": self.procThread = thread.start_new_thread(self.RAWDataProc.load4PhaseT1Data, \ (str(self.headerstr), self.procStacks, self.dataChan, self.refChan, \ str(self.ui.FIDProcComboBox.currentText()), self.ui.mplwidget, \ 1e-3 * self.ui.DeadTimeSpinBox.value( ), self.ui.plotImportCheckBox.isChecked() )) #, self)) nlogText = [] nlogText.append( "!" ) nlogText.append( "Akvo_VERSION: " + str(1.0)) nlogText.append( "Import: " ) nlogText.append( " GMR Header: " + self.headerstr ) nlogText.append( " opened: " + datetime.datetime.now().isoformat() ) nlogText.append( " pulse Type: " + str(self.RAWDataProc.pulseType) ) nlogText.append( " stacks: " + str(self.procStacks) ) nlogText.append( " data channels: " + str(self.dataChan) ) nlogText.append( " reference channels: " + str(self.refChan) ) nlogText.append( " pulse records: " + str(self.ui.FIDProcComboBox.currentText()) ) nlogText.append( " instrument dead time: " + str(1e-3 * self.ui.DeadTimeSpinBox.value( )) ) self.Log ( nlogText ) # should be already done # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("updateProgress(int)"), self.updateProgressBar) # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("enableDSP()"), self.enableDSP) # QtCore.QObject.connect(self.RAWDataProc, QtCore.SIGNAL("doneStatus()"), self.doneStatus) self.ui.ProcessedBox.setEnabled(True) self.ui.lcdNumberFID1Length.setEnabled(1) self.ui.lcdNumberFID2Length.setEnabled(1) self.ui.lcdNumberResampFreq.setEnabled(1) self.ui.lcdTotalDeadTime.setEnabled(1) self.ui.lcdTotalDeadTime.display( self.ui.DeadTimeSpinBox.value( ) ) #self.ui.lcdNumberFID1Length.display(0) #self.ui.lcdNumberFID2Length.display(0) #self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp ) self.mpl_toolbar = NavigationToolbar2QT(self.ui.mplwidget, self.ui.mplwidget) self.ui.mplwidget.draw() def Log(self, nlogText): for line in nlogText: self.ui.logTextBrowser.append( line ) self.logText.append( line ) def disable(self): self.ui.BandPassBox.setEnabled(False) self.ui.downSampleGroupBox.setEnabled(False) self.ui.windowFilterGroupBox.setEnabled(False) # self.ui.despikeGroupBox.setEnabled(False) self.ui.adaptBox.setEnabled(False) self.ui.adaptFDBox.setEnabled(False) self.ui.qCalcGroupBox.setEnabled(False) self.ui.FDSmartStackGroupBox.setEnabled(False) self.ui.sumDataBox.setEnabled(False) self.ui.qdGroupBox.setEnabled(False) self.ui.gateBox.setEnabled(False) def enableAll(self): self.enableDSP() self.enableQC() def enableDSP(self): # Bandpass filter self.ui.BandPassBox.setEnabled(True) self.ui.BandPassBox.setChecked(True) self.ui.bandPassGO.setEnabled(False) # need to design first self.ui.plotBP.setEnabled(True) self.ui.plotBP.setChecked(True) # downsample self.ui.downSampleGroupBox.setEnabled(True) self.ui.downSampleGroupBox.setChecked(True) # window self.ui.windowFilterGroupBox.setEnabled(True) self.ui.windowFilterGroupBox.setChecked(True) # Despike # self.ui.despikeGroupBox.setEnabled(True) # self.ui.despikeGroupBox.setChecked(False) # Adaptive filtering self.ui.adaptBox.setEnabled(True) self.ui.adaptBox.setChecked(True) # FD Adaptive filtering self.ui.adaptFDBox.setEnabled(True) self.ui.adaptFDBox.setChecked(True) # sum group box try: if len(self.dataChan) > 1: self.ui.sumDataBox.setEnabled(True) self.ui.sumDataBox.setChecked(True) except: pass # Quadrature Detect self.ui.qdGroupBox.setEnabled(True) self.ui.qdGroupBox.setChecked(True) self.enableQC() def enableQC(self): # Q calc self.ui.qCalcGroupBox.setEnabled(True) self.ui.qCalcGroupBox.setChecked(True) # FD SmartStack self.ui.FDSmartStackGroupBox.setEnabled(True) self.ui.FDSmartStackGroupBox.setChecked(True) # Quadrature detect try: for pulse in self.RAWDataProc.DATADICT["PULSES"]: np.shape(self.RAWDataProc.DATADICT[pulse]["Q"]) self.RAWDataProc.DATADICT["stack"] self.ui.qdGroupBox.setEnabled(True) self.ui.qdGroupBox.setChecked(True) except: self.ui.qdGroupBox.setEnabled(False) self.ui.qdGroupBox.setChecked(False) # Gating try: self.RAWDataProc.DATADICT["CA"] self.ui.gateBox.setEnabled(True) self.ui.gateBox.setChecked(True) except: self.ui.gateBox.setEnabled(False) self.ui.gateBox.setChecked(False) def despikeFilter(self): self.lock("despike filter") thread.start_new_thread(self.RAWDataProc.despike, \ (self.ui.windowSpinBox.value(), \ self.ui.thresholdSpinBox.value(), \ str(self.ui.replComboBox.currentText()), \ self.ui.rollOnSpinBox.value(), \ self.ui.despikeInterpWinSpinBox.value(), self.ui.mplwidget)) def calcQ(self): self.lock("pulse moment calculation") thread.start_new_thread(self.RAWDataProc.effectivePulseMoment, \ (self.ui.CentralVSpinBox.value(), \ self.ui.mplwidget_2)) def FDSmartStack(self): self.lock("time-domain smart stack") nlogText = [] nlogText.append("TD_stack: ") nlogText.append(" outlier: " + str( self.ui.outlierTestCB.currentText() ) ) nlogText.append(" cutoff: " + str( self.ui.MADCutoff.value() ) ) self.Log(nlogText) thread.start_new_thread(self.RAWDataProc.TDSmartStack, \ (str(self.ui.outlierTestCB.currentText()), \ self.ui.MADCutoff.value(), self.ui.mplwidget_2)) def adaptFilter(self): self.lock("TD noise cancellation filter") nlogText = [] nlogText.append("TD_noise_cancellation: ") nlogText.append(" n_Taps: " + str(self.ui.MTapsSpinBox.value()) ) nlogText.append(" lambda: " + str(self.ui.adaptLambdaSpinBox.value()) ) nlogText.append(" truncate: " + str(self.ui.adaptTruncateSpinBox.value()) ) nlogText.append(" mu: " + str(self.ui.adaptMuSpinBox.value()) ) nlogText.append(" PCA: " + str(self.ui.PCAComboBox.currentText()) ) self.Log(nlogText) thread.start_new_thread(self.RAWDataProc.adaptiveFilter, \ (self.ui.MTapsSpinBox.value(), \ self.ui.adaptLambdaSpinBox.value(), \ self.ui.adaptTruncateSpinBox.value(), \ self.ui.adaptMuSpinBox.value(), \ str(self.ui.PCAComboBox.currentText()), \ self.ui.mplwidget)) def sumDataChans(self): self.lock("Summing data channels") nlogText = [] nlogText.append("Data_sum: ") nlogText.append( " summed_channel: " + str(self.dataChan[0]) ) self.Log(nlogText) self.dataChan = [self.dataChan[0]] self.ui.sumDataBox.setEnabled(False) thread.start_new_thread( self.RAWDataProc.sumData, ( self.ui.mplwidget, 7 ) ) def adaptFilterFD(self): self.lock("FD noise cancellation filter") thread.start_new_thread(self.RAWDataProc.adaptiveFilterFD, \ (str(self.ui.windowTypeComboBox.currentText()), \ self.ui.windowBandwidthSpinBox.value(), \ self.ui.CentralVSpinBox.value(), \ self.ui.mplwidget)) def bandPassFilter(self): self.lock("bandpass filter") nlogText = [] nlogText.append("bandpass_filter: ") nlogText.append(" central_nu: "+str(self.ui.CentralVSpinBox.value())) nlogText.append(" passband: "+str(self.ui.passBandSpinBox.value()) ) nlogText.append(" stopband: "+str(self.ui.stopBandSpinBox.value()) ) nlogText.append(" gpass: "+str(self.ui.gpassSpinBox.value()) ) nlogText.append(" gstop: "+str(self.ui.gstopSpinBox.value()) ) nlogText.append(" type: "+str(self.ui.fTypeComboBox.currentText()) ) self.Log(nlogText) nv = self.ui.lcdTotalDeadTime.value( ) + self.ui.lcdNumberFTauDead.value() self.ui.lcdTotalDeadTime.display( nv ) thread.start_new_thread(self.RAWDataProc.bandpassFilter, \ (self.ui.mplwidget, 0, self.ui.plotBP.isChecked() )) def downsample(self): self.lock("resampling") nlogText = list(['Resample: ']) nlogText.append(" downsample_factor: " + str(self.ui.downSampleSpinBox.value() ) ) nlogText.append(" truncate_length: " + str( self.ui.truncateSpinBox.value() ) ) self.Log(nlogText) thread.start_new_thread(self.RAWDataProc.downsample, \ (self.ui.truncateSpinBox.value(), \ self.ui.downSampleSpinBox.value(), self.ui.mplwidget)) def quadDet(self): self.lock("quadrature detection") nlogText = [] nlogText.append("quadrature_detection: ") nlogText.append(" trim: " + str( self.ui.trimSpin.value() )) #nlogText.append(" representation:" + str( self.ui.QDType.currentText() )) self.Log(nlogText) thread.start_new_thread(self.RAWDataProc.quadDet, \ (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget_2)) self.ui.plotQD.setEnabled(True) def plotQD(self): self.lock("plot QD") thread.start_new_thread(self.RAWDataProc.plotQuadDet, \ (self.ui.trimSpin.value(), int(self.ui.QDType.currentIndex()), self.ui.mplwidget_2)) def gateIntegrate(self): self.lock("gate integration") nlogText = [] nlogText.append("gate_integrate: ") nlogText.append(" gpd: " + str(self.ui.GPDspinBox.value( ) )) self.Log(nlogText) thread.start_new_thread(self.RAWDataProc.gateIntegrate, \ (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), self.ui.mplwidget_2)) self.ui.actionExport_Preprocessed_Dataset.setEnabled(True) self.ui.plotGI.setEnabled(True) def plotGI(self): self.lock("plot gate integrate") thread.start_new_thread(self.RAWDataProc.plotGateIntegrate, \ (self.ui.GPDspinBox.value(), self.ui.trimSpin.value(), \ self.ui.QDType_2.currentIndex(), self.ui.mplwidget_2)) def designFilter(self): [bord, fe] = self.RAWDataProc.designFilter( \ self.ui.CentralVSpinBox.value(), \ self.ui.passBandSpinBox.value(), \ self.ui.stopBandSpinBox.value(), \ self.ui.gpassSpinBox.value(), \ self.ui.gstopSpinBox.value(), \ str(self.ui.fTypeComboBox.currentText()), self.ui.mplwidget) self.ui.lcdNumberFilterOrder.display(bord) self.ui.lcdNumberFTauDead.display(1e3*fe) #self.ui.lcdNumberFilterOrder.display(bord) self.ui.bandPassGO.setEnabled(1) # self.ui.lcdNumberTauPulse2.display(1e3*self.RAWDataProc.pulseLength[1]) def windowFilter(self): self.lock("window filter") nlogText = [] nlogText.append("FD_window: ") nlogText.append(" type: " + str(self.ui.windowTypeComboBox.currentText()) ) nlogText.append(" width: " + str(self.ui.windowBandwidthSpinBox.value()) ) nlogText.append(" centre: " + str(self.ui.CentralVSpinBox.value() )) self.Log(nlogText) thread.start_new_thread(self.RAWDataProc.windowFilter, \ (str(self.ui.windowTypeComboBox.currentText()), \ self.ui.windowBandwidthSpinBox.value(), \ self.ui.CentralVSpinBox.value(), \ self.ui.mplwidget)) def designFDFilter(self): # thread.start_new_thread(self.RAWDataProc.computeWindow, ( \ # "Pulse 1", # self.ui.windowBandwidthSpinBox.value(), \ # self.ui.CentralVSpinBox.value(), \ # str(self.ui.windowTypeComboBox.currentText()), \ # self.ui.mplwidget )) a,b,c,d,dead = self.RAWDataProc.computeWindow( \ "Pulse 1", self.ui.windowBandwidthSpinBox.value(), \ self.ui.CentralVSpinBox.value(), \ str(self.ui.windowTypeComboBox.currentText()), \ self.ui.mplwidget ) self.ui.lcdWinDead.display(dead) def updateProgressBar(self, percent): self.ui.barProgress.setValue(percent) def updateProc(self): if str(self.ui.FIDProcComboBox.currentText()) == "Pulse 1": self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]) elif str(self.ui.FIDProcComboBox.currentText()) == "Pulse 2": self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0]) else: self.ui.lcdNumberFID1Length.display(self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 1"]["TIMES"][0]) self.ui.lcdNumberFID2Length.display(self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][-1]- self.RAWDataProc.DATADICT["Pulse 2"]["TIMES"][0]) self.ui.lcdNumberResampFreq.display( self.RAWDataProc.samp ) def doneStatus(self): # unlocks GUI self.ui.statusbar.clearMessage ( ) self.ui.barProgress.hide() self.updateProc() self.enableAll() def lock(self, string): self.ui.statusbar.showMessage ( string ) self.ui.barProgress.show() self.ui.barProgress.setValue(0) self.disable() def unlock(self): self.ui.statusbar.clearMessage ( ) self.ui.barProgress.hide() self.enableAll() def done(self): self.ui.statusbar.showMessage ( "" ) ################################################################ ################################################################ # Boiler plate main function import pkg_resources from pkg_resources import resource_string import matplotlib.image as mpimg import matplotlib.pyplot as plt def main(): # splash screen logo logo = pkg_resources.resource_filename(__name__, 'akvo.png') logo2 = pkg_resources.resource_filename(__name__, 'akvo2.png') qApp = QtWidgets.QApplication(sys.argv) ssplash = False if ssplash: pixmap = QtGui.QPixmap(logo) splash = QtWidgets.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint) splash.show() aw = ApplicationWindow() img=mpimg.imread(logo) for ax in [ aw.ui.mplwidget ]: ax.fig.clear() subplot = ax.fig.add_subplot(111) ax.fig.patch.set_facecolor( None ) ax.fig.patch.set_alpha( .0 ) subplot.imshow(img) subplot.xaxis.set_major_locator(plt.NullLocator()) subplot.yaxis.set_major_locator(plt.NullLocator()) ax.draw() if ssplash: splash.showMessage("Loading modules") splash.finish(aw) #time.sleep(1) aw.setWindowTitle("Akvo v"+str(version)) aw.show() qApp.setWindowIcon(QtGui.QIcon(logo2)) sys.exit(qApp.exec_()) if __name__ == "__main__": main()