class matplotlibWidget(QWidget): def __init__(self, parent = None): QWidget.__init__(self, parent) self.canvas = MplCanvas() self.gl = QGridLayout() alignment = Qt.Alignment() self.gl.addWidget(self.canvas,0,0,-1,-1,alignment) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button1 = QPushButton('Zoom') self.button1.clicked.connect(self.zoom) self.button2 = QPushButton('Pan') self.button2.clicked.connect(self.pan) self.button3 = QPushButton('Home') self.button3.clicked.connect(self.home) self.gl.addWidget(self.toolbar,1,0,alignment) self.gl.addWidget(self.button1,1,1,alignment) self.gl.addWidget(self.button2,1,2,alignment) self.gl.addWidget(self.button3,1,3,alignment) self.setLayout(self.gl) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan()
class Window(QtWidgets.QDialog): def __init__(self, data, parent=None): super(Window, self).__init__(parent) self.data = data self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() self.button = QtWidgets.QPushButton('Plot') self.button.clicked.connect(self.plot) self.button1 = QtWidgets.QPushButton('Zoom') self.button1.clicked.connect(self.zoom) self.button2 = QtWidgets.QPushButton('Pan') self.button2.clicked.connect(self.pan) self.button3 = QtWidgets.QPushButton('Home') self.button3.clicked.connect(self.home) layout = QtWidgets.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) self.setLayout(layout) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): # PlotCanvas(self.data) data = self.data ax = self.figure.add_subplot(111) ax.hold(False) ax.set_title("Basic Distribution") ax.plot(data, 'r*-') self.canvas.draw()
class Window(QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button = QPushButton('Plot') self.button.clicked.connect(self.plot) self.button1 = QPushButton('Zoom') self.button1.clicked.connect(self.zoom) self.button2 = QPushButton('Pan') self.button2.clicked.connect(self.pan) self.button3 = QPushButton('Home') self.button3.clicked.connect(self.home) # set the layout layout = QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) self.setLayout(layout) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] ax = self.figure.add_subplot(111) ax.hold(False) ax.plot(data, '*-') self.canvas.draw()
def home(self): # always unzoom completely if hasattr(self, '_views'): self._views.clear() if hasattr(self, '_positions'): self._positions.clear() self.canvas.figure.gca().autoscale() self.canvas.draw() return NavigationToolbar2QT.home(self)
class PulsedNMR(QMainWindow, Ui_PulsedNMR): rates = {0:25.0e3, 1:50.0e3, 2:250.0e3, 3:500.0e3, 4:2500.0e3} def __init__(self): super(PulsedNMR, self).__init__() self.setupUi(self) self.rateValue.addItems(['25', '50', '250', '500', '2500']) # IP address validator rx = QRegExp('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$') self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue)) # state variable self.idle = True # number of samples to show on the plot self.size = 50000 # buffer and offset for the incoming samples self.buffer = bytearray(8 * self.size) self.offset = 0 # create figure figure = Figure() figure.set_facecolor('none') self.axes = figure.add_subplot(111) self.canvas = FigureCanvas(figure) self.plotLayout.addWidget(self.canvas) # create navigation toolbar self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False) # remove subplots action actions = self.toolbar.actions() self.toolbar.removeAction(actions[7]) self.plotLayout.addWidget(self.toolbar) # create TCP socket self.socket = QTcpSocket(self) self.socket.connected.connect(self.connected) self.socket.readyRead.connect(self.read_data) self.socket.error.connect(self.display_error) # connect signals from buttons and boxes self.startButton.clicked.connect(self.start) self.freqValue.valueChanged.connect(self.set_freq) self.awidthValue.valueChanged.connect(self.set_awidth) self.deltaValue.valueChanged.connect(self.set_delta) self.rateValue.currentIndexChanged.connect(self.set_rate) # set rate self.rateValue.setCurrentIndex(2) # create timer for the repetitions self.timer = QTimer(self) self.timer.timeout.connect(self.fire) def start(self): if self.idle: self.startButton.setEnabled(False) self.socket.connectToHost(self.addrValue.text(), 1001) else: self.idle = True self.timer.stop() self.socket.close() self.offset = 0 self.startButton.setText('Start') self.startButton.setEnabled(True) def connected(self): self.idle = False self.set_freq(self.freqValue.value()) self.set_rate(self.rateValue.currentIndex()) self.set_awidth(self.awidthValue.value()) self.fire() self.timer.start(self.deltaValue.value()) self.startButton.setText('Stop') self.startButton.setEnabled(True) def read_data(self): size = self.socket.bytesAvailable() if self.offset + size < 8 * self.size: self.buffer[self.offset:self.offset + size] = self.socket.read(size) self.offset += size else: self.buffer[self.offset:8 * self.size] = self.socket.read(8 * self.size - self.offset) self.offset = 0 # plot the signal envelope data = np.frombuffer(self.buffer, np.complex64) self.curve.set_ydata(np.abs(data)) self.canvas.draw() def display_error(self, socketError): if socketError == QAbstractSocket.RemoteHostClosedError: pass else: QMessageBox.information(self, 'PulsedNMR', 'Error: %s.' % self.socket.errorString()) self.startButton.setText('Start') self.startButton.setEnabled(True) def set_freq(self, value): if self.idle: return self.socket.write(struct.pack('<I', 0<<28 | int(1.0e6 * value))) def set_rate(self, index): # time axis rate = float(PulsedNMR.rates[index]) time = np.linspace(0.0, (self.size - 1) * 1000.0 / rate, self.size) # reset toolbar self.toolbar.home() self.toolbar._views.clear() self.toolbar._positions.clear() # reset plot self.axes.clear() self.axes.grid() # plot zeros and get store the returned Line2D object self.curve, = self.axes.plot(time, np.zeros(self.size)) x1, x2, y1, y2 = self.axes.axis() # set y axis limits self.axes.axis((x1, x2, -0.1, 0.4)) self.axes.set_xlabel('time, ms') self.canvas.draw() # set repetition time minimum = self.size / rate * 2000.0 if minimum < 100.0: minimum = 100.0 self.deltaValue.setMinimum(minimum) self.deltaValue.setValue(minimum) if self.idle: return self.socket.write(struct.pack('<I', 1<<28 | index)) def set_awidth(self, value): if self.idle: return self.socket.write(struct.pack('<I', 2<<28 | int(1.0e1 * value))) def set_delta(self, value): if self.idle: return self.timer.stop() self.timer.start(value) def fire(self): if self.idle: return self.socket.write(struct.pack('<I', 3<<28))
def home(self, *args): # call super's home() method NavigationToolbar2QT.home(self, args) # send a signal to parent class for further operation self.home_button_pressed.emit()
class PulsedNMR(QMainWindow, Ui_PulsedNMR): rates = {0:25.0e3, 1:50.0e3, 2:125.0e3, 3:250.0e3, 4:500.0e3, 5:1250.0e3} def __init__(self): super(PulsedNMR, self).__init__() self.setupUi(self) self.rateValue.addItems(['25', '50', '125', '250', '500', '1250']) # IP address validator rx = QRegExp('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|rp-[0-9A-Fa-f]{6}\.local$') self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue)) # state variable self.idle = True # number of samples to show on the plot self.size = 50000 # buffer and offset for the incoming samples self.buffer = bytearray(16 * self.size) self.offset = 0 self.data = np.frombuffer(self.buffer, np.int32) # create figure figure = Figure() figure.set_facecolor('none') self.axes = figure.add_subplot(111) self.canvas = FigureCanvas(figure) self.plotLayout.addWidget(self.canvas) # create navigation toolbar self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False) # remove subplots action actions = self.toolbar.actions() if int(matplotlib.__version__[0]) < 2: self.toolbar.removeAction(actions[7]) else: self.toolbar.removeAction(actions[6]) self.plotLayout.addWidget(self.toolbar) # create TCP socket self.socket = QTcpSocket(self) self.socket.connected.connect(self.connected) self.socket.readyRead.connect(self.read_data) self.socket.error.connect(self.display_error) # connect signals from buttons and boxes self.startButton.clicked.connect(self.start) self.freqValue.valueChanged.connect(self.set_freq) self.deltaValue.valueChanged.connect(self.set_delta) self.rateValue.currentIndexChanged.connect(self.set_rate) # set rate self.rateValue.setCurrentIndex(3) # create timer for the repetitions self.startTimer = QTimer(self) self.startTimer.timeout.connect(self.timeout) self.timer = QTimer(self) self.timer.timeout.connect(self.start_sequence) def start(self): if self.idle: self.startButton.setEnabled(False) self.socket.connectToHost(self.addrValue.text(), 1001) self.startTimer.start(5000) else: self.stop() def stop(self): self.idle = True self.timer.stop() self.socket.abort() self.offset = 0 self.startButton.setText('Start') self.startButton.setEnabled(True) def timeout(self): self.display_error('timeout') def connected(self): self.startTimer.stop() self.idle = False self.set_freq(self.freqValue.value()) self.set_rate(self.rateValue.currentIndex()) self.start_sequence() self.timer.start(self.deltaValue.value()) self.startButton.setText('Stop') self.startButton.setEnabled(True) def read_data(self): size = self.socket.bytesAvailable() if self.offset + size < 16 * self.size: self.buffer[self.offset:self.offset + size] = self.socket.read(size) self.offset += size else: self.buffer[self.offset:16 * self.size] = self.socket.read(16 * self.size - self.offset) self.offset = 0 # plot the signal envelope self.curve.set_ydata(np.abs(self.data.astype(np.float32).view(np.complex64)[0::2] / (1 << 30))) self.canvas.draw() def display_error(self, socketError): self.startTimer.stop() if socketError == 'timeout': QMessageBox.information(self, 'PulsedNMR', 'Error: connection timeout.') else: QMessageBox.information(self, 'PulsedNMR', 'Error: %s.' % self.socket.errorString()) self.stop() def set_freq(self, value): if self.idle: return self.socket.write(struct.pack('<Q', 0<<60 | int(1.0e6 * value))) self.socket.write(struct.pack('<Q', 1<<60 | int(1.0e6 * value))) def set_rate(self, index): # time axis rate = float(PulsedNMR.rates[index]) time = np.linspace(0.0, (self.size - 1) * 1000.0 / rate, self.size) # reset toolbar self.toolbar.home() self.toolbar.update() # reset plot self.axes.clear() self.axes.grid() # plot zeros and get store the returned Line2D object self.curve, = self.axes.plot(time, np.zeros(self.size)) x1, x2, y1, y2 = self.axes.axis() # set y axis limits self.axes.axis((x1, x2, -0.1, 1.1)) self.axes.set_xlabel('time, ms') self.canvas.draw() if self.idle: return self.socket.write(struct.pack('<Q', 2<<60 | int(125.0e6 / rate / 2))) def set_delta(self, value): if self.idle: return self.timer.stop() self.timer.start(value) def clear_pulses(self): if self.idle: return self.socket.write(struct.pack('<Q', 7<<60)) def add_delay(self, width): if self.idle: return self.socket.write(struct.pack('<Q', 8<<60 | int(width - 4))) def add_pulse(self, level, phase, width): if self.idle: return self.socket.write(struct.pack('<Q', 8<<60 | int(width))) self.socket.write(struct.pack('<Q', 9<<60 | int(phase << 16 | level))) def start_sequence(self): if self.idle: return awidth = 125 * self.awidthValue.value() bwidth = 125 * self.bwidthValue.value() delay = 125 * self.delayValue.value() size = self.size self.clear_pulses() self.add_pulse(32766, 0, awidth) self.add_delay(delay) self.add_pulse(32766, 0, bwidth) self.socket.write(struct.pack('<Q', 10<<60 | int(size)))
class spectralPattern_window(QDialog): def __init__(self,pxx,frequencies,data,Fs): QDialog.__init__(self); loadUi('graph_spectral.ui',self); self.setWindowIcon(QtGui.QIcon("logo.png")) self.label_title.setText('Eliminación de artefactos por espectro de potencia') self.label_maxValue.setText('Valor máximo [potencia]') self.data=data self.Fs=Fs self.channels,self.points=shape(self.data) self.epochs(self.data, self.channels, self.points) self.pxx=pxx self.frequencies=frequencies self.button_zoom.clicked.connect(self.zoom) self.button_pan.clicked.connect(self.pan) self.button_home.clicked.connect(self.home) self.button_apply.clicked.connect(self.implementation) self.button_cancel.clicked.connect(self.cancelar) self.figure = Figure(figsize=(5,4), dpi=100) self.canvas = FigureCanvas(self.figure) self.axes=self.figure.add_subplot(111) self.toolbar=NavigationToolbar(self.canvas,self) self.toolbar.hide() layout=QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) self.field_graph.setLayout(layout) self.axes.clear() self.canvas.draw() self.plot() def cancelar(self): spectralPattern_window.close(self); def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): legends=['Ch 1','Ch 2','Ch 3','Ch 4','Ch 5','Ch 6','Ch 7','Ch 8'] r=[] for c in range(shape(self.pxx)[0]): r.append(c*35) self.axes.plot(self.frequencies[c,::],sqrt(self.pxx[c,::])+c*35,linewidth=0.5) self.axes.set_yticklabels(legends) self.axes.set_yticks(r) self.axes.grid(True) self.axes.set_xlim([0,40]) self.axes.set_xlabel('Frecuency [Hz]') self.axes.set_ylabel('Power density [V^2/Hz]') self.axes.set_title('Periodograma de Welch') def epochs(self,data,channels,points): self.filtered_signal=data self.size_epoch=self.Fs*2 self.num_epoch=points/self.size_epoch delete=points%self.size_epoch self.filtered_signal=self.filtered_signal[::,0:(points-delete)] self.epochs_file=reshape(self.filtered_signal,(channels,int(self.size_epoch),int((points-delete)/self.size_epoch)),order='F') return(self.epochs_file) # def implementation(self): max_value=float(self.field_maxValue.text()) self.myepochs=self.epochs(self.data, self.channels, self.points) x,y=spectral_pattern.spectral(self.myepochs, max_value,self.Fs) newSignal=reshape(x,(shape(x)[0],shape(x)[1]*shape(x)[2]),order='F') self.graph_method = window_graph(self.data, self.Fs,3,newSignal,y,shape(self.myepochs)[2]); self.graph_method.show();
class TimeSeries(QWidget): def __init__(self, label, parent = None): super(TimeSeries, self).__init__(parent) self.label = label self.init() self.implementGrid() self.new_series = [] self.new_series_labels = [] def init(self): # FigureCanvas to show the mesh in self.figure = plt.figure() self.figure.set_facecolor((45/255, 45/255, 45/255)) self.canvas = FigureCanvas(self.figure) self.canvas.setFixedSize(750,276) self.figure.subplots_adjust(left = 0.1, right = 0.94, bottom = 0.1, top = 0.9) self.ax = self.figure.add_subplot(111) self.ax.set_xlim(0,1.25) self.ax.set_facecolor((45/255, 45/255, 45/255)) broken_white = (150/255, 150/255, 150/255) self.ax.grid('on', color = broken_white) self.ax.spines['bottom'].set_color(broken_white) self.ax.spines['top'].set_color(broken_white) self.ax.spines['right'].set_color(broken_white) self.ax.spines['left'].set_color(broken_white) self.ax.tick_params(axis='x', colors=broken_white, labelsize = 7) self.ax.tick_params(axis='y', colors=broken_white, labelsize = 7) self.ax.xaxis.label.set_color(broken_white) self.ax.yaxis.label.set_color(broken_white) self.ax.set_ylabel(self.label, fontweight = 'bold', fontsize = 9) self.Export = QPushButton() self.Export.setToolTip('Export graph as PNG') im = QIcon('support_files/export.png') self.Export.setIcon(im) self.Export.setDisabled(True) self.Export.clicked.connect(self.exportGraph) self.Export.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 0px; color: rgb(180,180,180); background-color: rgb(55, 55, 60, 0); } QPushButton:pressed { color: rgb(100,100,100,150); background-color: rgb(25, 25, 25, 150); } """) self.AddExtSeries = QPushButton() self.AddExtSeries.setToolTip('Add a series from a npy file') im = QIcon('support_files/add.png') self.AddExtSeries.setIcon(im) self.AddExtSeries.setDisabled(True) self.AddExtSeries.clicked.connect(self.addExtraSeries) self.AddExtSeries.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 0px; color: rgb(180,180,180); background-color: rgb(55, 55, 60, 0); } QPushButton:pressed { color: rgb(100,100,100,150); background-color: rgb(25, 25, 25, 150); } """) self.SaveNPY = QPushButton() self.SaveNPY.setToolTip('Save the series in a numpy array file (.npy)') im = QIcon('support_files/save_npy.png') self.SaveNPY.setIcon(im) self.SaveNPY.setDisabled(True) self.SaveNPY.clicked.connect(self.saveNPY) self.SaveNPY.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 0px; color: rgb(180,180,180); background-color: rgb(55, 55, 60, 0); } QPushButton:pressed { color: rgb(100,100,100,150); background-color: rgb(25, 25, 25, 150); } """) # buttons to zoom and pan self.zoombut = QPushButton() self.zoombut.setCheckable(True) self.zoombut.setEnabled(False) im = QIcon('support_files/zoom_trans.png') self.zoombut.setIcon(im) self.zoombut.setDisabled(True) self.zoombut.clicked.connect(self.zoom) self.zoombut.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 0px; color: rgb(180,180,180); background-color: rgb(55, 55, 60, 0); } QPushButton:checked { color: rgb(100,100,100,150); background-color: rgb(255, 128, 0); } """) self.homebut = QPushButton() self.homebut.setEnabled(False) im = QIcon('support_files/home_trans.png') self.homebut.setIcon(im) self.homebut.setDisabled(True) self.homebut.clicked.connect(self.home) self.homebut.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 0px; color: rgb(180,180,180,50); background-color: rgb(25, 25, 60, 0); } QPushButton:pressed { color: rgb(100,100,100,150); background-color: rgb(255, 128, 0); } """) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() def implementGrid(self): grid = QGridLayout() grid.addWidget(self.canvas,0,0) box1 = QVBoxLayout() box1.addSpacing(30) box1.addWidget(self.Export) box1.addWidget(self.AddExtSeries) box1.addWidget(self.SaveNPY) box1.addStretch() box1.addWidget(self.zoombut) box1.addWidget(self.homebut) box1.addWidget(QLabel()) box2 = QHBoxLayout() box2.addStretch() box2.addLayout(box1) box2.addSpacing(15) grid.addLayout(box2,0,0) self.setLayout(grid) def plotSeries(self, T, var, t0, t1, x, y): self.Export.setEnabled(True) self.AddExtSeries.setEnabled(True) self.SaveNPY.setEnabled(True) self.zoombut.setEnabled(True) self.homebut.setEnabled(True) self.new_series = [] self.new_series_labels = [] self.x, self.y = x, y self.T = T self.var = var self.t0 = t0 self.t1 = t1 mask = (T>t0)*(T<t1) self.mask = mask self.varmin = np.min(var[mask]) self.varmax = np.max(var[mask]) self.varrange = self.varmax - self.varmin self.ax.set_xlim(t0,t1) self.ax.clear() self.ax.grid('on') self.ax.plot(T, var,'.-', color = (1, 128/255, 0), label = 'active output') self.ax.set_ylim(max(-999,self.varmin - 0.1*self.varrange), min(999,self.varmax + 0.1*self.varrange)) self.ax.set_ylabel(self.label, fontweight = 'bold', fontsize = 9) self.canvas.draw() def exportGraph(self): lab = 'x: %d, y: %d' % (self.x, self.y) fn, _ = QFileDialog.getSaveFileName(self,"QFileDialog.getSaveFileName()","","All Files (*);;PNG Files (*.png)", options=QFileDialog.Options()) if len(fn) > 0: f, a = plt.subplots(figsize = (15,4)) f.subplots_adjust(left = 0.1, right = 0.94, bottom = 0.1, top = 0.9) a.plot(self.T, self.var,'.-', color = (1, 128/255, 0), label = lab) a.grid('on') a.set_ylabel(self.label, fontweight = 'bold', fontsize = 11) a.set_xlim(self.t0,self.t1) a.set_ylim(max(-999,self.varmin - 0.1*self.varrange), min(999,self.varmax + 0.1*self.varrange)) for i in range(len(self.new_series)): series = self.new_series[i] lab = self.new_series_labels[i] T = np.array(series[:,0], dtype = 'datetime64') V = series[:,1] a.plot(T, V, '.-', label = lab) a.set_ylim(max(-999,self.varmin - 0.1*self.varrange), min(999,self.varmax + 0.1*self.varrange)) a.legend(loc = 1) f.savefig(fn) f.clear() def saveNPY(self): fn, _ = QFileDialog.getSaveFileName(self,"QFileDialog.getSaveFileName()","","All Files (*);;Numpy Files (*.npy)", options=QFileDialog.Options()) if len(fn) > 0: if fn[-4:] != '.npy': fn + '.npy' T = self.T - np.timedelta64(3600,'s') var = self.var arr = np.empty((T.shape[0], 2)) arr[:,0] = T arr[:,1] = var np.save(fn, arr) def addExtraSeries(self): options = QFileDialog.Options() fn, _ = QFileDialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","Numpy files (*.npy)", options=options) if len(fn) > 0: arr = np.load(fn) if arr.shape[1] != 2: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Not a valid numpy file. This array does not have two columns.") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) else: self.new_series.append(arr) lab = fn.split('/')[-1][:-4].replace('_',' ') self.new_series_labels.append(lab) T = np.array(arr[:,0], dtype = 'datetime64') + np.timedelta64(3600,'s') self.ax.plot(T, arr[:,1], '.-', label = lab, scalex = False, scaley = False) self.ax.legend(loc = 1) self.varmin = np.min([self.varmin, np.min(arr[:,1])]) self.varmax = np.max([self.varmax, np.max(arr[:,1])]) self.varrange = abs(self.varmax - self.varmin) #self.ax.set_ylim(max(-999,self.varmin - 0.1*self.varrange), min(999,self.varmax + 0.1*self.varrange)) self.canvas.draw() def home(self): self.toolbar.home() def zoom(self): if self.zoombut.isChecked(): self.toolbar.zoom() self.record_pressing_event = False else: self.toolbar.zoom(False)
class MainWindow(QtWidgets.QMainWindow, mw.Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.datalst = [] self.modellst = [] self.lstdatamodel = QtGui.QStandardItemModel(self.listView) self.listView.setModel(self.lstdatamodel) self.current_lst_index = -1 self.addButton.clicked.connect(self.add) self.removeButton.clicked.connect(self.remove) self.actionCalcLSSParameter.triggered.connect(self.calculatelss) self.actionAutomaticElutionWindowStretching.triggered.connect( self.calcautelwindowstretch) self.actionSelectivityMap.triggered.connect(self.pltselectivitymap) self.actionResolutionMap.triggered.connect(self.pltresolutionmap) self.actionAbout.triggered.connect(self.about) self.actionQuit.triggered.connect(self.quit) self.listView.clicked.connect(self.viewmatrix) self.toolBox.currentChanged.connect(self.viewmatrix) self.zoomButton.clicked.connect(self.zoom) self.panButton.clicked.connect(self.pan) self.rescaleButton.clicked.connect(self.home) self.exportchromatogramButton.clicked.connect(self.exportchromatogram) self.setplotoptionsButton.clicked.connect(self.setplotoptions) self.modelBox.currentIndexChanged.connect(self.gradientanalyser) self.doubleSpinBox_1.valueChanged.connect(self.gradientanalyser) self.doubleSpinBox_2.valueChanged.connect(self.gradientanalyser) self.doubleSpinBox_3.valueChanged.connect(self.gradientanalyser) self.doubleSpinBox_4.valueChanged.connect(self.gradientanalyser) self.doubleSpinBox_5.valueChanged.connect(self.gradientanalyser) self.doubleSpinBox_6.valueChanged.connect(self.gradientanalyser) self.ColumnLenghtSpinBox.valueChanged.connect(self.gradientanalyser) self.CulumnDiameterSpinBox.valueChanged.connect(self.gradientanalyser) self.ColumnPorositySpinBox.valueChanged.connect(self.gradientanalyser) # Add plot self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # set the layout layout_chormatogram = QtWidgets.QVBoxLayout() layout_chormatogram.addWidget(self.canvas) self.plotterBox.setLayout(layout_chormatogram) # Add selectivity map plot #self.figure_smap = plt.figure() #self.canvas_smap = FigureCanvas(self.figure_smap) #self.toolbar_smap = NavigationToolbar(self.canvas_smap, self) #self.toolbar_smap.hide() #layout_smap = QtWidgets.QVBoxLayout() #layout_smap.addWidget(self.canvas_smap) #self.plotterBox_2.setLayout(layout_smap) self.tablemodel = TableModel(self) self.tableView.setModel(self.tablemodel) self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tableView.customContextMenuRequested.connect(self.openTableMenu) # constant parameters self.crit_resolution = 1.8 self.crit_alpha = 1.1 self.peaks = None self.crit_peaks = None def openTableMenu(self, position): """ context menu event """ menu = QtWidgets.QMenu(self) exportAction = menu.addAction("Export table as CSV") action = menu.exec_(self.tableView.viewport().mapToGlobal(position)) if action == exportAction: fname, _ = QtWidgets.QFileDialog.getSaveFileName( self, "Save File", "CSV (*.csv)") self.tablemodel.SaveTable(fname) else: return return def keyPressEvent(self, e): if (e.modifiers() & QtCore.Qt.ControlModifier): if e.key() == QtCore.Qt.Key_C: #copy if len(self.tableView.selectionModel().selectedIndexes()) > 0: previous = self.tableView.selectionModel().selectedIndexes( )[0] columns = [] rows = [] for index in self.tableView.selectionModel( ).selectedIndexes(): if previous.column() != index.column(): columns.append(rows) rows = [] rows.append(str(index.data().toPyObject())) previous = index columns.append(rows) # add rows and columns to clipboard clipboard = "" nrows = len(columns[0]) ncols = len(columns) for r in xrange(nrows): for c in xrange(ncols): clipboard += columns[c][r] if c != (ncols - 1): clipboard += '\t' clipboard += '\n' # copy to the system clipboard sys_clip = QtWidgets.QApplication.clipboard() sys_clip.setText(clipboard) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def setplotoptions(self): return def exportchromatogram(self): if self.peaks != None and self.crit_peaks != None: fname, _ = QtWidgets.QFileDialog.getSaveFileName( self, "Save File", "CSV (*.csv)") print(os.path.exists(fname)) if not os.path.exists(fname): y = [] x = [] for i in range(len(self.peaks)): x.append(self.peaks[i][0]) y.append(0.) for j in range(1, len(self.peaks[0])): y[-1] += self.peaks[i][j] crit_y = [] crit_x = [] for i in range(len(self.crit_peaks)): crit_x.append(self.crit_peaks[i][0]) crit_y.append(0.) for j in range(1, len(self.crit_peaks[0])): crit_y[-1] += self.crit_peaks[i][j] fo = open(fname, "w") for i in range(len(x)): fo.write("%.4f;%.4f\n" % (x[i], y[i])) for i in range(len(crit_x)): fo.write("%.4f;%.4f\n" % (crit_x[i], crit_y[i])) fo.close() else: return def plotchromatogram(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] ax = self.figure.add_subplot(111) ax.clear() ax.plot(data, '*-') self.canvas.draw() def add(self): idialog = ImportDialog() if idialog.exec_() == 1: [ name, molname, trdata, grad, tg, td, t0, flow, c_length, c_diameter, c_particle ] = idialog.getdata() self.datalst.append( Data(name, molname, trdata, grad, tg, td, t0, flow, c_length, c_diameter, c_particle)) self.lstdatamodel.appendRow(QtGui.QStandardItem(name)) def remove(self): if self.current_lst_index >= 0 and self.current_lst_index < len( self.datalst): del self.datalst[self.current_lst_index] self.lstdatamodel.removeRow(self.current_lst_index) def viewmatrix(self, indx): if self.toolBox.currentIndex() == 0: if indx: self.current_lst_index = indx.row() del self.tablemodel.arraydata[:] del self.tablemodel.header[:] self.tablemodel.clean() self.tableView.model().layoutChanged.emit() molname = self.datalst[self.current_lst_index].molname trdata = self.datalst[self.current_lst_index].trdata grad = self.datalst[self.current_lst_index].grad tg = self.datalst[self.current_lst_index].tg header = ["Molecule"] for j in range(len(tg)): header.append( str("%.1f%% %.1f%% %.1f min" % (round(grad[j][0] * 100, 1), round(grad[j][1] * 100, 1), tg[j]))) self.tablemodel.setHeader(header) for i in range(len(trdata)): row = [molname[i]] for j in range(len(trdata[i])): row.append(round(trdata[i][j], 2)) self.tablemodel.addRow(row) else: del self.tablemodel.arraydata[:] del self.tablemodel.header[:] self.tablemodel.clean() self.tableView.model().layoutChanged.emit() self.gradientanalyser() def about(self): adialog = AboutDialog() adialog.exec_() def quit(self): QtWidgets.QApplication.quit() def calculatelss(self): items = [] lstmodel = self.listView.model() for index in range(lstmodel.rowCount()): item = lstmodel.item(index) items.append(item.text()) runlss = ComputeLSS(items) if runlss.exec_() == 1: [indx, modelname] = runlss.getdata() t0 = self.datalst[indx].t0 v_d = self.datalst[indx].vd flow = self.datalst[indx].flow lssmol = SSGenerator(None, None, None, t0, v_d, flow) self.modellst.append(Model()) self.modellst[-1].modname = modelname self.modellst[-1].molname = self.datalst[indx].molname self.modellst[-1].flow = self.datalst[indx].flow self.modellst[-1].c_length = self.datalst[indx].c_length self.modellst[-1].c_diameter = self.datalst[indx].c_diameter self.modellst[-1].c_particle = self.datalst[indx].c_particle self.modelBox.addItem(modelname) tg = self.datalst[indx].tg init_B = [] final_B = [] for i in range(len(tg)): init_B.append(self.datalst[indx].grad[i][0]) final_B.append(self.datalst[indx].grad[i][1]) self.modellst[-1].v_d = v_d self.modellst[-1].v_m = t0 * flow for row in self.datalst[indx].trdata: lss_logkw, lss_s = lssmol.getlssparameters( row, tg, init_B, final_B) self.modellst[-1].lss.append([lss_logkw, lss_s]) if len(self.modellst) == 1: self.gradientanalyser() def calcautelwindowstretch(self): aws = AutomaticElutionWindowStretching(self.modellst) aws.exec_() def pltselectivitymap(self): smap = PlotMaps(self.modellst, "sel") smap.exec_() def pltresolutionmap(self): rsmap = PlotMaps(self.modellst, "res") rsmap.exec_() def gradientanalyser(self): indx = self.modelBox.currentIndex() del self.tablemodel.arraydata[:] del self.tablemodel.header[:] self.tablemodel.clean() header = ["Molecule", "log kW", "S", "tR"] self.tablemodel.setHeader(header) self.tableView.model().layoutChanged.emit() if indx >= 0 and indx < len(self.modellst): #predict the retention time for each compound molname = [name for name in self.modellst[indx].molname] lss = self.modellst[indx].lss flow_sofware = float(self.doubleSpinBox_1.value()) init_B_soft = float(self.doubleSpinBox_2.value()) / 100. final_B_soft = float(self.doubleSpinBox_3.value()) / 100. tg_soft = float(self.doubleSpinBox_4.value()) c_length = self.ColumnLenghtSpinBox.value() c_diameter = self.CulumnDiameterSpinBox.value() c_particle = self.ColumnPorositySpinBox.value() t0_soft = 0. td_soft = 0. v_m = None v_d = float(self.doubleSpinBox_5.value()) #if c_length > 0 and c_diameter > 0 and c_porosity > 0: # v_m = ((square(self.c_diameter)*self.c_length*pi*self.c_porosity)/4.)/1000. #else: # #v_m = self.modellst[indx].v_m #t0_soft = float(v_m/flow_sofware) t0_soft = float(self.doubleSpinBox_6.value()) td_soft = float(v_d / flow_sofware) A = 1.0 #N = (c_length*10000.)/(3.4*c_particle) trtab = [] lssmol = SSGenerator(None, None, None, t0_soft, float(self.modellst[indx].v_d), flow_sofware) i = 0 trlst = [] for row in lss: lss_logkw = float(row[0]) lss_s = float(row[1]) W = get_lss_peak_width(c_length, c_particle, lss_logkw, lss_s, init_B_soft, final_B_soft, tg_soft, flow_sofware, self.modellst[indx].v_m, self.modellst[indx].v_d, None) tr = lssmol.rtpred(lss_logkw, lss_s, tg_soft, init_B_soft, final_B_soft, t0_soft, td_soft) if tr < t0_soft: trtab.append([t0_soft, A, W]) else: trtab.append([tr, A, W]) trlst.append([round(trtab[-1][0], 2), W, molname[i]]) row = [ molname[i], round(lss_logkw, 3), round(lss_s, 3), round(trtab[-1][0], 2) ] self.tablemodel.addRow(row) self.tableView.model().layoutChanged.emit() i += 1 # Calculate the critical resolution trlst = sorted(trlst, key=lambda x: x[0]) # get min and max time tr_min = tr_max = 0. if len(trlst) > 0: tr_min = trlst[0][0] tr_max = trlst[-1][0] # calculate resolution and critical couple # get the peak width at base multiplying by 1.7 self.plainTextEdit.clear() text = "Critical couples:\n" self.plainTextEdit.appendPlainText(text) crit_trtab = [] crit_molname = [] ncc = 0 for i in range(1, len(trlst)): width1 = trlst[i][1] * 1.7 width2 = trlst[i - 1][1] * 1.7 tr1 = trlst[i - 1][0] tr2 = trlst[i][0] tmp_rs = (2 * (tr2 - tr1)) / (width1 + width2) if tmp_rs < self.crit_resolution: molname_a = trlst[i - 1][2] molname_b = trlst[i][2] text = " - %s %.2f min\n" % ( molname_a, round(trlst[i - 1][0], 2)) text += " - %s %.2f min\n" % (molname_b, round(trlst[i][0], 2)) text += "Rs: %.2f\n" % round(tmp_rs, 2) text += "#" * 20 text += "\n" self.plainTextEdit.appendPlainText(text) ncc += 1 if molname_a not in crit_molname: # add to critical tr tab a_indx = molname.index(molname_a) crit_trtab.append(trtab.pop(a_indx)) crit_molname.append(molname.pop(a_indx)) if molname_b not in crit_molname: b_indx = molname.index(molname_b) crit_trtab.append(trtab.pop(b_indx)) crit_molname.append(molname.pop(b_indx)) else: continue self.plainTextEdit.appendPlainText( "Total critical couples: %d" % (ncc)) #Create a cromatogram self.peaks = list( zip(*BuildChromatogram(trtab, tg_soft, 0.01))) self.crit_peaks = list( zip(*BuildChromatogram(crit_trtab, tg_soft, 0.01))) y = [] x = [] for i in range(len(self.peaks)): x.append(self.peaks[i][0]) y.append(0.) #len(self.peaks[0]) for j in range(1, len(self.peaks[0])): y[-1] += self.peaks[i][j] crit_y = [] crit_x = [] for i in range(len(self.crit_peaks)): crit_x.append(self.crit_peaks[i][0]) crit_y.append(0.) #len(peaks[0]) for j in range(1, len(self.crit_peaks[0])): crit_y[-1] += self.crit_peaks[i][j] self.figure.clear() ax = self.figure.add_subplot(111) ax.clear() ax.plot(x, y, "b", crit_x, crit_y, "r") #ax.plot(x, y, '-', color='blue') #ax.plot(crit_x, crit_y, '-', color='red') plt.xlabel('Time') plt.ylabel('Signal') plt.xlim([ tr_min - ((tr_min * 10.) / 100.), tr_max + ((tr_max * 10.) / 100.) ]) self.canvas.draw()
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName(_fromUtf8("Data View")) #MainWindow.resize(539, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) self.splitter = QtWidgets.QSplitter(self.centralwidget) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setObjectName(_fromUtf8("splitter")) # File navigation self.fileSystemModel = QtWidgets.QDirModel(self.splitter) self.fileSystemModel.setObjectName(_fromUtf8("fileSystemModel")) currentDir = str(QtCore.QDir.currentPath()) index = self.fileSystemModel.index(currentDir) self.treeView = QtWidgets.QTreeView(self.splitter) self.treeView.setObjectName(_fromUtf8("treeView")) self.treeView.setModel(self.fileSystemModel) if len(sys.argv)>1: self.currentFile = currentDir + '/' + sys.argv[1] else: self.currentFile = None self.recursive_expand( index, self.treeView ) tVheader = self.treeView.header() for i in range(1,4): tVheader.hideSection(i) self.treeView.doubleClicked.connect(self.on_treeView_doubleClicked) # Plots tab self.tabWidget = QtWidgets.QTabWidget(self.splitter) self.tabWidget.setObjectName(_fromUtf8("tabWidget")) self.tab = QtWidgets.QWidget() self.tab.setObjectName(_fromUtf8("tab")) self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab) self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) self.figure = plt.figure(figsize=(15,5)) self.canvas = FigureCanvas(self.figure) self.canvas.setObjectName(_fromUtf8("canvas")) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() self.verticalLayout_2.addWidget(self.canvas) # Plot buttons self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout_plotButtons")) self.plotTypeCombo = QtWidgets.QComboBox(self.tab) self.plotTypeCombo.setObjectName(_fromUtf8("plotTypeCombo")) self.plotTypeCombo.currentIndexChanged.connect(self.ChangePlotType) self.horizontalLayout.addWidget(self.plotTypeCombo) self.btnPlot = QtWidgets.QPushButton(self.tab) self.btnPlot.setObjectName(_fromUtf8("btnPlot")) self.btnPlot.clicked.connect(self.drawPlot) self.horizontalLayout.addWidget(self.btnPlot) self.btnZoom = QtWidgets.QPushButton(self.tab) self.btnZoom.setObjectName(_fromUtf8("btnZoom")) self.btnZoom.clicked.connect(self.plotZoom) self.horizontalLayout.addWidget(self.btnZoom) self.btnPan = QtWidgets.QPushButton(self.tab) self.btnPan.setObjectName(_fromUtf8("btnPan")) self.btnPan.clicked.connect(self.plotPan) self.horizontalLayout.addWidget(self.btnPan) self.btnHome = QtWidgets.QPushButton(self.tab) self.btnHome.setObjectName(_fromUtf8("btnHome")) self.btnHome.clicked.connect(self.plotHome) self.horizontalLayout.addWidget(self.btnHome) self.verticalLayout_2.addLayout(self.horizontalLayout) # x axis options self.horizontalLayout_xAxis = QtWidgets.QHBoxLayout() self.horizontalLayout_xAxis.setObjectName(_fromUtf8("horizontalLayout_xAxis")) self.xColSelect = QtWidgets.QComboBox(self.tab) self.xColSelect.setObjectName(_fromUtf8("xColSelect")) self.xColSelect.currentIndexChanged.connect(self.ResetUserSelections) self.horizontalLayout_xAxis.addWidget(self.xColSelect) self.horizontalLayout_xAxis.setStretchFactor(self.xColSelect,2) self.xbinsLabel = QtWidgets.QLabel(self.tab) self.xbinsLabel.setText("X Bins:") self.horizontalLayout_xAxis.addWidget( self.xbinsLabel ) self.xnBinsSpin = QtWidgets.QSpinBox(self.tab) self.xnBinsSpin.setObjectName(_fromUtf8("xnBinsSpin")) self.xnBinsSpin.valueChanged.connect(self.XChangeBinning) self.xnBinsSpin.setRange(1,10000) self.horizontalLayout_xAxis.addWidget( self.xnBinsSpin ) self.horizontalLayout_xAxis.setStretchFactor(self.xnBinsSpin,2) self.xminLabel = QtWidgets.QLabel(self.tab) self.xminLabel.setText("X Min:") self.horizontalLayout_xAxis.addWidget( self.xminLabel ) self.xnMinSpin = QtWidgets.QDoubleSpinBox(self.tab) self.xnMinSpin.setObjectName(_fromUtf8("xnMinSpin")) self.xnMinSpin.valueChanged.connect(self.XChangeMin) self.xnMinSpin.setRange( -1e20, 1e20 ) self.horizontalLayout_xAxis.addWidget( self.xnMinSpin ) self.horizontalLayout_xAxis.setStretchFactor(self.xnMinSpin,2) self.xmaxLabel = QtWidgets.QLabel(self.tab) self.xmaxLabel.setText("X Max:") self.horizontalLayout_xAxis.addWidget( self.xmaxLabel ) self.xnMaxSpin = QtWidgets.QDoubleSpinBox(self.tab) self.xnMaxSpin.setObjectName(_fromUtf8("xnMaxSpin")) self.xnMaxSpin.setRange( -1e20, 1e20 ) self.xnMaxSpin.valueChanged.connect(self.XChangeMax) self.horizontalLayout_xAxis.addWidget( self.xnMaxSpin ) self.horizontalLayout_xAxis.setStretchFactor(self.xnMaxSpin,2) self.xTypeCombo = QtWidgets.QComboBox(self.tab) self.xTypeCombo.setObjectName(_fromUtf8("xTypeCombo")) self.xTypeCombo.addItems( ['int','float','str','datetime'] ) self.xTypeCombo.currentIndexChanged.connect(self.ChangeXDataType) self.horizontalLayout_xAxis.addWidget(self.xTypeCombo) self.horizontalLayout_xAxis.setStretchFactor(self.xTypeCombo,2) self.verticalLayout_2.addLayout(self.horizontalLayout_xAxis ) # y axis options self.horizontalLayout_yAxis = QtWidgets.QHBoxLayout() self.horizontalLayout_yAxis.setObjectName(_fromUtf8("horizontalLayout_yAxis")) self.yColSelect = QtWidgets.QComboBox(self.tab) self.yColSelect.setObjectName(_fromUtf8("yColSelect")) self.yColSelect.currentIndexChanged.connect(self.ResetUserSelections) self.horizontalLayout_yAxis.addWidget(self.yColSelect) self.horizontalLayout_yAxis.setStretchFactor(self.yColSelect,2) self.ybinsLabel = QtWidgets.QLabel(self.tab) self.ybinsLabel.setText("Y Bins:") self.horizontalLayout_yAxis.addWidget( self.ybinsLabel ) self.ynBinsSpin = QtWidgets.QSpinBox(self.tab) self.ynBinsSpin.setObjectName(_fromUtf8("ynBinsSpin")) self.ynBinsSpin.valueChanged.connect(self.YChangeBinning) self.horizontalLayout_yAxis.addWidget( self.ynBinsSpin ) self.horizontalLayout_yAxis.setStretchFactor(self.ynBinsSpin,2) self.yminLabel = QtWidgets.QLabel(self.tab) self.yminLabel.setText("Y Min:") self.horizontalLayout_yAxis.addWidget( self.yminLabel ) self.ynMinSpin = QtWidgets.QDoubleSpinBox(self.tab) self.ynMinSpin.setObjectName(_fromUtf8("ynMinSpin")) self.ynMinSpin.setRange( -1e20, 1e20 ) self.ynMinSpin.valueChanged.connect(self.YChangeMin) self.horizontalLayout_yAxis.addWidget( self.ynMinSpin ) self.horizontalLayout_yAxis.setStretchFactor(self.ynMinSpin,2) self.ymaxLabel = QtWidgets.QLabel(self.tab) self.ymaxLabel.setText("Y Max:") self.horizontalLayout_yAxis.addWidget( self.ymaxLabel ) self.ynMaxSpin = QtWidgets.QDoubleSpinBox(self.tab) self.ynMaxSpin.setObjectName(_fromUtf8("ynMaxSpin")) self.ynMaxSpin.setRange( -1e20, 1e20 ) self.ynMaxSpin.valueChanged.connect(self.YChangeMax) self.horizontalLayout_yAxis.addWidget( self.ynMaxSpin ) self.horizontalLayout_yAxis.setStretchFactor(self.ynMaxSpin,2) self.yTypeCombo = QtWidgets.QComboBox(self.tab) self.yTypeCombo.setObjectName(_fromUtf8("yTypeCombo")) self.yTypeCombo.addItems( ['int','float','str','datetime'] ) self.yTypeCombo.currentIndexChanged.connect(self.ChangeYDataType) self.horizontalLayout_yAxis.addWidget(self.yTypeCombo) self.horizontalLayout_yAxis.setStretchFactor(self.yTypeCombo,2) #self.verticalLayout_2.addLayout(self.horizontalLayout_yAxis ) self.yAxisItems = [ self.yColSelect, self.ybinsLabel, self.ynBinsSpin, self.yminLabel, self.ynMinSpin, self.ymaxLabel, self.ynMaxSpin, self.yTypeCombo ] self.binningChoices = [ self.ybinsLabel, self.ynBinsSpin, self.xbinsLabel, self.xnBinsSpin ] # Data tab self.tabWidget.addTab(self.tab, _fromUtf8("")) self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName(_fromUtf8("tab_2")) self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tab_2) self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3")) self.tableView = QtWidgets.QTableView(self.tab_2) self.tableView.setObjectName(_fromUtf8("tableView")) self.verticalLayout_3.addWidget(self.tableView) # Filter text entry self.filterHorLayout = QtWidgets.QHBoxLayout() self.filterHorLayout.setObjectName(_fromUtf8("filterHorLayout")) self.filterBox = QtWidgets.QLineEdit(self.centralwidget) self.filterBox.setObjectName(_fromUtf8("filterBox")) self.btnFilter = QtWidgets.QPushButton(self.centralwidget) self.btnFilter.setObjectName(_fromUtf8("btnFilter")) self.btnFilter.clicked.connect(self.updateTable) self.filterHorLayout.addWidget(self.filterBox) self.filterHorLayout.addWidget(self.btnFilter) self.verticalLayout.addLayout(self.filterHorLayout) # Setup self.treeView.raise_() self.tabWidget.addTab(self.tab_2, _fromUtf8("")) self.verticalLayout.addWidget(self.splitter) self.splitter.setStretchFactor(1, 2) self.centralwidget.showFullScreen() MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName(_fromUtf8("statusbar")) MainWindow.setStatusBar(self.statusbar) # Set the default picture import matplotlib.image as mpimg img=mpimg.imread(r'H:\stash_projects\DataView\PandaViz.jpg') plt.imshow(img) self.hdfStore = None self.plotTypeCombo.addItems( ['Scatter','Line','Hist','Hist2d'] ) self.userxBinning = False self.userxMax = False self.userxMin = False self.useryBinning = False self.useryMax = False self.useryMin = False self.fileName = "" self.df = None self.orig_df = None self.filterStr = None self.lastFilterStr = None self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) if self.currentFile is not None: if len(self.currentFile.split( r':' )) > 1: self.currentFile = self.currentFile.split( r':' )[1][-1] + r':' + self.currentFile.split( r':' )[2] self.treeView.setCurrentIndex( self.fileSystemModel.index( self.currentFile ) ) self.recursive_expand( index, self.treeView ) #self.on_treeView_doubleClicked( self.fileSystemModel.index( self.currentFile ) ) self.on_treeView_doubleClicked(self.fileSystemModel.index( self.currentFile ) ,self.currentFile ) def setupCsv(self): self.data() self.columns = self.df.columns.tolist() self.xColSelect.clear() self.xColSelect.addItems( self.columns ) self.yColSelect.clear() self.yColSelect.addItems( self.columns ) self.xTypeCombo.Text = str(self.df[ self.columns[0] ].dtype) self.updateTable() def setupH5(self): self.h5keys = self.hdfStore.keys() if len(self.h5keys) > 1: self.chosen_h5key = str( SelectDialog.SelectDialog.getOptions( self.h5keys ) ) else: self.chosen_h5key = "" if self.chosen_h5key == "": self.orig_df = self.hdfStore[ self.h5keys[0] ] else: self.orig_df = self.hdfStore[ self.chosen_h5key ] self.setupCsv() def plotLine(self): if self.data() is None: return plt.clf() xCol = str( self.xColSelect.currentText() ) yCol = str( self.yColSelect.currentText() ) ax = plt.gca() ax.plot( self.df[ xCol ].tolist(), self.df[ yCol ].tolist(), label=xCol + ' v ' + yCol ) if self.userxMin or self.userxMax or self.useryMin or self.useryMax: ax.set_xlim( self.xnMinSpin.value(), self.xnMaxSpin.value() ) ax.set_ylim( self.ynMinSpin.value(), self.ynMaxSpin.value() ) else: self.xnMinSpin.setValue( ax.get_xlim()[0] ) self.xnMaxSpin.setValue( ax.get_xlim()[1] ) self.ynMinSpin.setValue( ax.get_ylim()[0] ) self.ynMaxSpin.setValue( ax.get_ylim()[1] ) ax.set_xlabel( xCol ) ax.set_ylabel( yCol ) self.canvas.draw() def plotHist(self): if self.data() is None: return plt.clf() col = str( self.xColSelect.currentText() ) if self.userxBinning: bins = self.xnBinsSpin.value() else: bins = 10 if not self.userxBinning: self.xnBinsSpin.setValue( bins ) if self.userxMin: Min = self.xnMinSpin.value() else: Min = self.df[col].min() try: self.xnMinSpin.setValue( Min ) except: self.xnMinSpin.setValue( 0. ) if self.userxMax: Max = self.xnMaxSpin.value() else: Max = self.df[col].max() try: self.xnMaxSpin.setValue( Max ) except: self.xnMaxSpin.setValue( 0. ) plt.hist( sorted(self.df[ col ].tolist()), bins=bins, range=(Min,Max) ) plt.xlabel( col ) self.canvas.draw() def plotScatter(self): if self.data() is None: return plt.clf() xCol = str( self.xColSelect.currentText() ) yCol = str( self.yColSelect.currentText() ) ax = plt.gca() ax.scatter( self.df[ xCol ].tolist(), self.df[ yCol ].tolist(), label=xCol + ' v ' + yCol ) if self.userxMin or self.userxMax or self.useryMin or self.useryMax: ax.set_xlim( self.xnMinSpin.value(), self.xnMaxSpin.value() ) ax.set_ylim( self.ynMinSpin.value(), self.ynMaxSpin.value() ) else: self.xnMinSpin.setValue( ax.get_xlim()[0] ) self.xnMaxSpin.setValue( ax.get_xlim()[1] ) self.ynMinSpin.setValue( ax.get_ylim()[0] ) self.ynMaxSpin.setValue( ax.get_ylim()[1] ) ax.set_xlabel( xCol ) ax.set_ylabel( yCol ) self.canvas.draw() def plotHist2d(self): if self.data() is None: return plt.clf() xCol = str( self.xColSelect.currentText() ) yCol = str( self.yColSelect.currentText() ) ax = plt.gca() if self.userxBinning: bins = self.xnBinsSpin.value() else: bins = 10 ax.hist2d( self.df[xCol].tolist(), self.df[yCol].tolist(), bins=bins ) if not self.userxBinning: self.xnBinsSpin.setValue( bins ) if not self.userxMin: self.xnMinSpin.setValue( ax.get_xlim()[0] ) else: ax.set_xlim([self.xnMinSpin.value(), ax.get_xlim()[1] ] ) if not self.userxMax: self.xnMaxSpin.setValue( ax.get_xlim()[1] ) else: ax.set_xlim([ax.get_xlim()[0], self.xnMaxSpin.value() ] ) if not self.useryMin: self.ynMinSpin.setValue( ax.get_ylim()[0] ) else: ax.set_ylim([self.ynMinSpin.value(), ax.get_ylim()[1] ] ) if not self.useryMax: self.ynMaxSpin.setValue( ax.get_ylim()[1] ) else: ax.set_ylim([ax.get_ylim()[0], self.ynMaxSpin.value() ] ) plt.xlabel( xCol ) plt.ylabel( yCol ) self.canvas.draw() def data(self): if self.orig_df is None: return None self.filterStr = str(self.filterBox.text()) if self.filterStr is not None and self.filterStr != "": if self.filterStr != self.lastFilterStr: try: exec("self.df = self.orig_df[" + self.filterStr.replace("df","self.orig_df") + "]" ) self.lastFilterStr = self.filterStr except Exception as e: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Filtering failed") msg.setWindowTitle("Error") msg.setDetailedText( str(e) ) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() pass pass pass else: self.df = self.orig_df return True def updateTable(self): if self.data() is None: return header = self.columns tm = MyTableModel.MyTableModel(self.df.values, header, self) self.tableView.setModel(tm) vh = self.tableView.verticalHeader() vh.setVisible(False) hh = self.tableView.horizontalHeader() hh.setStretchLastSection(True) self.tableView.setSortingEnabled(True) #self.tableView.sortByColumn(0); tm.sort( 0, Qt.AscendingOrder ) def plotZoom(self): self.toolbar.zoom() def plotPan(self): self.toolbar.pan() def plotHome(self): self.toolbar.home() def on_treeView_doubleClicked(self, index, fileName = '' ): if fileName == '': fileName = str(index.model().filePath(index)) if self.fileName == fileName: return if self.hdfStore is not None: self.hdfStore.close() if fileName.endswith( ".csv" ): self.hdfStore = None self.fileName = fileName self.isCsv = True self.isH5 = False self.orig_df = pd.read_csv( fileName ) self.setupCsv() elif fileName.endswith(".h5"): self.fileName = fileName self.isCsv = False self.isH5 = True self.hdfStore = pd.HDFStore( fileName, 'r' ) self.setupH5() def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "PandaViz", None)) import os.path as osp path = osp.join(osp.dirname(sys.modules[__name__].__file__), 'PandaViz.jpg') MainWindow.setWindowIcon(QIcon(path)) self.btnZoom.setText(_translate("MainWindow", "Zoom", None)) self.btnPlot.setText(_translate("MainWindow", "Draw", None)) self.btnPan.setText(_translate("MainWindow", "Pan", None)) self.btnHome.setText(_translate("MainWindow", "Reset", None)) self.btnFilter.setText(_translate("MainWindow","Update Table", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Plot", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Data", None)) def recursive_expand(self, index, treeView): treeView.expand( index ) parent = index.parent() if parent != index: self.recursive_expand( parent, treeView ) def drawPlot(self): pType = self.plotTypeCombo.currentText() if pType == 'Scatter': self.plotScatter() elif pType == 'Hist': self.plotHist() elif pType == 'Hist2d': self.plotHist2d() elif pType == 'Line': self.plotLine() def ChangeXDataType(self): if self.data() is None: return col = str( self.xColSelect.currentText() ) changeType = str( self.xTypeCombo.currentText() ) try: if changeType == 'datetime': self.df[ col ] = pd.to_datetime( self.df[ col ]) else: exec("self.df[ col ] = self.df[ col ].astype("+ changeType + ")") except Exception as e: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Type Conversion Failed") msg.setWindowTitle("Error") msg.setDetailedText( str(e) ) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() pass pass def ChangeYDataType(self): if self.data() is None: return col = str( self.yColSelect.currentText() ) changeType = str( self.yTypeCombo.currentText() ) try: if changeType == 'datetime': self.df[ col ] = pd.to_datetime( self.df[ col ]) else: exec("self.df[ col ] = self.df[ col ].astype("+ changeType + ")") except Exception as e: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText("Type Conversion Failed") msg.setWindowTitle("Error") msg.setDetailedText( str(e) ) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() pass pass def ChangePlotType(self): self.userBinning = False pType = self.plotTypeCombo.currentText() if pType == 'Scatter' or pType == 'Line' or pType == 'Hist2d': [ x.show() for x in self.yAxisItems ] found = False for i in range( self.verticalLayout_2.count() ): if self.verticalLayout_2.itemAt(i) == self.horizontalLayout_yAxis: found=True if not found: self.verticalLayout_2.addLayout( self.horizontalLayout_yAxis ) if pType == 'Scatter' or pType == 'Line': [ x.hide() for x in self.binningChoices ] else: [ x.show() for x in self.binningChoices ] else: [ x.show() for x in self.binningChoices ] [ x.hide() for x in self.yAxisItems ] for i in range( self.verticalLayout_2.count() ): if self.verticalLayout_2.itemAt(i) == self.horizontalLayout_yAxis: self.verticalLayout_2.removeItem( self.horizontalLayout_yAxis ) self.verticalLayout_2.update() def XChangeBinning(self): self.userxBinning = True def YChangeBinning(self): self.useryBinning = True def XChangeMax(self): self.userxMax = True def YChangeMax(self): self.useryMax = True def XChangeMin(self): self.userxMin = True def YChangeMin(self): self.useryMin = True def ResetUserSelections(self): self.userxMin = False self.useryMin = False self.userxMax = False self.useryMax = False self.userxBinning = False self.useryBinning = False
class MCS(QMainWindow, Ui_MCS): """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(MCS, self).__init__(parent) self.setupUi(self) # 添加 matplotlib 画布组件用于绘图 self.canvas1 = Canvas(self.frame, xlabel="Time(s)", title="Sampled waveform") self.canvas1.get_default_filename = lambda: 'Sampled waveform.png' self.horizontalLayout_15.addWidget(self.canvas1) self.canvas2 = Canvas(self.frame, xlabel="Frequency(Hz)", title="FFT of Sampled waveform") self.canvas2.get_default_filename = lambda: ('FFT of Sampled ' 'waveform.png') self.horizontalLayout_14.addWidget(self.canvas2) # 添加 matplotlib 导航工具栏用于操作图像。 self.toolbar1 = NavigationToolbar(self.canvas1, self) self.toolbar1.hide() self.toolbar2 = NavigationToolbar(self.canvas2, self) self.toolbar2.hide() # 为文本框添加 validator regex = QRegExp(r'^400(\.0)?$|^[1-3]?[0-9]{1,2}(\.[0-9])?$') self.lineEdit_4.setValidator(QRegExpValidator(regex, self)) self.lineEdit_5.setValidator( QRegExpValidator(QRegExp(r'^([1-9][0-9]{0,1}|100)$'), self)) # 采样时间限制 # 一些初始化变量值 self.scrollbar_value = 1 self.signal_wave = None self.amplitude = 2.5, 2.5 self.data = None self.external_flag = False self.sample_freq_value = 0.1 self.axes_color = "w" self.figure_color = None self.line_color = "C0" self.sample_time = 5 # 将菜单栏中的 signal 选项改为单选。 self.menuGroupSingal = QActionGroup(self.menuSignal) self.menuGroupSingal.addAction(self.actionSquare) self.menuGroupSingal.addAction(self.actionTriangle) self.menuGroupSingal.addAction(self.actionSin) self.menuGroupSingal.setExclusive(True) def zoom(self): """缩放图像。""" self.toolbar1.zoom() self.toolbar2.zoom() def pan(self): """拖动图像。""" self.toolbar1.pan() self.toolbar2.pan() def save(self): """保存图像。""" self.toolbar1.save_figure() self.toolbar2.save_figure() def generate_signal(self, freq, sample_point): """根据传入参数及预设,生成对应信号。""" # 函数的相位 phase = 2 * np.pi * freq * sample_point # 模拟产生噪音信号 noise = np.random.randn(*np.shape(sample_point)) / 50 # noise = 0 if self.signal_wave == 3: # 返回正弦波 return self.amplitude[0] * np.sin( phase) + noise + self.amplitude[1] elif self.signal_wave == 2: # 返回三角波 return (self.amplitude[0] * signal.sawtooth(phase, 0.5) + noise + self.amplitude[1]) else: # 返回方波 return (self.amplitude[0] * signal.square(phase) + noise + self.amplitude[1]) def plot(self): """绘制图像。""" # 采样时间 T = self.sample_time if self.external_flag: x, y, N, f_s = self.resume_data_from_file() self.horizontalScrollBar.setValue(int(N / 10)) self.external_flag = False else: # f_s 范围 0.1k~400K 而 scrollbar_value 范围 1~1000 f_s = int(self.scrollbar_value * 10) # 采样点数 N = T * f_s N = T * f_s # 生成采样点集,范围从 0-T 均分 N个点。 x = np.linspace(0, T, N, endpoint=False) # 设置产生信号的频率 freq = signal_dlg.freq # 采样点 sample_point = x # 生成指定信号 y = self.generate_signal(freq, sample_point) # 生成用于导出的数据 self.generate_export_data(x, y, N, f_s) # FFT 变换 yf2 = fft(y) f = fftfreq(N, 1.0 / f_s) mask = np.where(f >= 0) xf2 = f[mask] yf2 = abs(yf2[mask] / N) self.lineEdit.setText(f"{np.max(y) - np.mean(y):.4f}") y_ac = y - np.mean(y) count = ((y_ac[:-1] * y_ac[1:]) < 0).sum() count = count if count % 2 == 0 else count + 1 self.lineEdit_3.setText(f"{2*T/count:.4f}") # self.lineEdit_3.setText(f"{((y_ac[:-1] * y_ac[1:]) < 0).sum():.5f}") self.lineEdit_2.setText(f"{count/(2*T):.2f}") self.canvas1.plot(x, y, "Time(s)", "Amplitude(V)", "Sampled waveform", self.line_color, self.axes_color, self.figure_color) self.canvas2.plot(xf2, yf2, "Frequency(Hz)", "Amplitude(V)", "FFT of Sampled waveform", self.line_color, self.axes_color, self.figure_color) def generate_export_data(self, x, y, N, f_s): """生成用于输出的数据。""" self.data = f"{N}\n{f_s}\n" + "\n".join([str(i) for i in zip(x, y)]) def resume_data_from_file(self): """从文件中恢复数据。""" data = self.data.split("\n") list_data = [eval(i) for i in data[2:]] N = int(data[0]) f_s = int(data[1]) x, y = map(list, zip(*list_data)) x = np.array(x) y = np.array(y) return x, y, N, f_s @pyqtSlot() def on_pushButton_clicked(self): """pushButton 被点击时,绘制图像。""" self.plot() @pyqtSlot() def on_pushButton_2_clicked(self): """pushButton2 被点击时,允许缩放图像。""" self.zoom() @pyqtSlot() def on_pushButton_3_clicked(self): """pushButton3 被点击时,允许拖动图像。""" self.pan() @pyqtSlot() def on_pushButton_4_clicked(self): """ 点击 pushButton_4(还原采样波形) 触发采样波形恢复。 """ self.toolbar1.home() @pyqtSlot() def on_pushButton_5_clicked(self): """ 点击 pushButton_5(缩放) 允许缩放波形。 """ self.zoom() @pyqtSlot() def on_pushButton_6_clicked(self): """ 点击 pushButton_6(拖动) 允许拖动波形。 """ self.pan() @pyqtSlot() def on_pushButton_7_clicked(self): """ 点击 pushButton_7(保存) 依次弹出保存图形窗口。 """ self.save() @pyqtSlot() def on_pushButton_8_clicked(self): """ 点击 pushButton_8(还原FFT) 触发FFT波形恢复 """ self.toolbar2.home() @pyqtSlot() def on_pushButton_9_clicked(self): """ 点击 pushButton_9(采样数据),从 self.data 中读取数据,并写入弹出对话框中的 文本框;如果 self.data 为空,则向文本框中写入报错信息。 """ if self.data: dlg_ui.textEdit.setText(self.data) else: dlg_ui.textEdit.setText("请先采集数据或导入数据。") Dialog.show() @pyqtSlot() def on_pushButton_10_clicked(self): """ 点击 pushButton_10(频率设置) 弹出频率设置对话框。 """ signal_dlg.show() @pyqtSlot() def on_action_Exit_triggered(self): """ 点击 File-Exit 退出程序。 """ self.close() @pyqtSlot(int) def on_horizontalScrollBar_valueChanged(self, value): """ 将水平滑动控件与 lineEdit_4 绑定,当滑条数值改变时,对应改变文本框中的数值。 @param value DESCRIPTION @type self, int """ # ScrollBar 范围为 1-1000 所以将从其获得的值除以十倍置于 lineEdit_4。 self.lineEdit_4.setText(str(value / 10)) self.scrollbar_value = value @pyqtSlot() def on_lineEdit_4_editingFinished(self): """ 当 lineEdit_4 完成编辑,即光标焦点移开或者是敲击 Enter 或 Return 后, 该方法生效。 """ if self.lineEdit_4.text(): # ScrollBar 范围为 1-1000 所以将从文本框中获得的值乘十设置为滑块值。 value = int(float(self.lineEdit_4.text()) * 10) self.horizontalScrollBar.setValue(value) else: self.horizontalScrollBar.setValue(0.1) @pyqtSlot(bool) def on_actionSquare_triggered(self, checked): """ 点击 View-Signal-Square 时,将类属性 signal_wave 设置为1,即表示方波。 @param checked DESCRIPTION @type self, bool """ self.signal_wave = 1 if checked else None @pyqtSlot(bool) def on_actionTriangle_triggered(self, checked): """ 点击 View-Signal-Triangle 时,将类属性 signal_wave 设置为2,即表示三角波。 @param checked DESCRIPTION @type self, bool """ self.signal_wave = 2 if checked else None @pyqtSlot(bool) def on_actionSin_triggered(self, checked): """ 点击 View-Signal-Sine 时,将类属性 signal_wave 设置为3,即表示正弦波。 @param checked DESCRIPTION @type self, bool """ self.signal_wave = 3 if checked else None # 单选框代码,即选则输入电压。 @pyqtSlot(bool) def on_radioButton_toggled(self, checked): """ 选中 radioButton 时,将类属性 amplitude 设置为 (2.5, 2.5), 即输入电压为 0~5V。 @param checked DESCRIPTION @type self, bool """ if checked: self.amplitude = 2.5, 2.5 @pyqtSlot(bool) def on_radioButton_2_toggled(self, checked): """ 选中 radioButton_2 时,将类属性 amplitude 设置为 (5, 5), 即输入电压为 0~10V。 @param checked DESCRIPTION @type self, bool """ if checked: self.amplitude = 5, 5 @pyqtSlot(bool) def on_radioButton_3_toggled(self, checked): """ 选中 radioButton_3 时,将类属性 amplitude 设置为 (5, 0), 即输入电压为 -5~+5V。 @param checked DESCRIPTION @type self, bool """ if checked: self.amplitude = 5, 0 @pyqtSlot(bool) def on_radioButton_4_toggled(self, checked): """ 选中 radioButton_4 时,将类属性 amplitude 设置为 (10, 0), 即输入电压为 -10~+10V。 @param checked DESCRIPTION @type self, bool """ if checked: self.amplitude = 10, 0 @pyqtSlot() def on_actionExport_Data_triggered(self): """ 点击 File—Export Data,将储存在 self.data中的数据导出到文件。 """ # todo: 导出到 json if self.data: fileName, _ = QFileDialog.getSaveFileName(self, "Export Data") if fileName: file = open(fileName, 'w') text = self.data file.write(text) file.close() else: # 如果没有采集数据,则弹出警告。 reply = QMessageBox.warning(self, "警告", "请先采集数据!", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) @pyqtSlot() def on_actionSave_triggered(self): """ Slot documentation goes here. """ self.save() @pyqtSlot() def on_actionOpen_triggered(self): """ Slot documentation goes here. """ # TODO: not implemented yet fileName, _ = QFileDialog.getOpenFileName(self, "Open File") if fileName: file = open(fileName, "r") self.data = file.read() # 抛出错误? self.external_flag = True file.close() @pyqtSlot() def on_actionLine_Color_triggered(self): """ Slot documentation goes here. """ color = QColorDialog.getColor() self.line_color = color.name() @pyqtSlot() def on_actionFigure_Color_triggered(self): """ Slot documentation goes here. """ color = QColorDialog.getColor() self.figure_color = color.name() @pyqtSlot() def on_actionAxes_Color_triggered(self): """ Slot documentation goes here. """ color = QColorDialog.getColor() self.axes_color = color.name() @pyqtSlot() def on_lineEdit_5_editingFinished(self): """ Slot documentation goes here. """ if self.lineEdit_5.text(): self.sample_time = int(self.lineEdit_5.text()) @pyqtSlot() def on_actionabout_some_triggered(self): """ Slot documentation goes here. """ reply = QMessageBox.about(self, "About", ("This program is designed " "for Measurement and Control " "System course.\n" "Author: Weiliang Liu, " "Yichen Zhang")) @pyqtSlot() def on_actionsome_help_triggered(self): """ Slot documentation goes here. """ reply = QMessageBox.information(self, "帮助", "没有什么帮助!", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
def home(self): if self.ongoing: if not self.figurecanvas.timerIsActive(): self.figurecanvas.startTimer() else: NT.home(self)
class Window(QMainWindow): def __init__(self, camera=None, calibration=None): #Inherit properies from QMainWindow super().__init__() #Setting geometry attributes of MainWindow self.left = 10 self.top = 10 self.width = 720 self.height = 480 self.project_num = 0 self.project_name = "Calib_" self.project_list = [] #Design GUI elements self.initUI() #Declare Camera, calibration instances self.camera = camera self.calib = calibration self.criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) #GUI elements design def initUI(self): # Matplotlib figure to draw image frame self.figure = plt.figure() # Window canvas to host matplotlib figure self.canvas = FigureCanvas(self.figure) # ToolBar to navigate image frame self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() #Setting Title and StatusBar self.setWindowTitle('Ứng dụng kiểm chuẩn máy ảnh số phổ thông') self.statusBar().showMessage("Trạng thái tác vụ: ") #Setting main menu mainMenu = self.menuBar() fileMenu = mainMenu.addMenu('Thao tác tệp tin') toolsMenu = mainMenu.addMenu('Xử lý dữ liệu') viewMenu = mainMenu.addMenu('Xem thông tin') editMenu = mainMenu.addMenu('Biên tập') searchMenu = mainMenu.addMenu('Tìm kiếm') helpMenu = mainMenu.addMenu('Trợ giúp') #Setting fileMenu fileMenu.addAction('Thiết lập dự án mới', self.on_file_setnewproject) fileMenu.addAction('Mở kho ảnh', self.on_open_imagestore) #Setting ToolsMenu toolsMenu.addAction('Tiền xử lý ảnh', self.on_preprocessing_image) toolsMenu.addAction('Kiểm chuẩn máy ảnh', self.on_calibrate_image) #Setting viewMenu viewMenu.addAction('Thông tin dự án', self.on_view_project_info) viewMenu.addAction('Dữ liệu kiểm chuẩn', self.on_view_calib_info) # Create central Widget self.central_widget = QWidget() # Just some button self.button = QPushButton('Chụp ảnh', self.central_widget) self.button1 = QPushButton('Phóng ảnh', self.central_widget) self.button2 = QPushButton('Điều hướng ảnh', self.central_widget) self.button3 = QPushButton('Về gốc', self.central_widget) #Put Buttons to HBoxLayout hBox = QHBoxLayout() hBox.addWidget(self.button) hBox.addWidget(self.button1) hBox.addWidget(self.button2) hBox.addWidget(self.button3) # set QVBoxLayout as the layout self.layout = QVBoxLayout(self.central_widget) self.layout.addWidget(self.toolbar) self.layout.addWidget(self.canvas) #Add hBoxLayout to VBoxLayout self.layout.addLayout(hBox) self.textedit = QTextEdit() font = QtGui.QFont() font.setPointSize(9) self.textedit.setFont(font) self.layout.addWidget(self.textedit) #Set central widget self.setCentralWidget(self.central_widget) # Events handling self.button.clicked.connect(self.plot) self.button1.clicked.connect(self.zoom) self.button2.clicked.connect(self.pan) self.button3.clicked.connect(self.home) #Events processing methods # Open image store @QtCore.pyqtSlot() def on_open_imagestore(self): #extract file name in a directory self.statusBar().showMessage( "Chương trình đang xử lý tác vụ: Mở kho ảnh") filepath = QFileDialog().getExistingDirectory( self, "Chọn đường dẫn tới kho ảnh") if filepath: images = Path(filepath).glob('*.jpg') imagelist = [str(image) for image in images] self.statusBar().showMessage(str("Kho ảnh nằm tại: ") + filepath) # check filename list and display first image if len(imagelist) > 2: #self.calib.imagelist = imagelist if self.project_num == 0: self.project_num += 1 self.calib.imagelist = imagelist self.calib.project_name = str("Calib_") + str( self.project_num) else: self.calib.project_name = str("Calib_") + str( self.project_num) self.project_list.append(self.calib) self.project_num += 1 newcalib = Calibration() newcalib.project_num = self.project_num newcalib.imagelist = imagelist self.calib = newcalib img = cv2.imread(imagelist[0]) pic = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(pic) self.canvas.draw() else: self.statusBar().showMessage( "Không có ảnh trong thư mục được chọn!") else: self.statusBar().showMessage(filepath) #Setting info for new project @QtCore.pyqtSlot() def on_file_setnewproject(self): self.statusBar().showMessage( "Chương trình đang xử lý tác vụ: Thiết lập tham số cho dự án mới") #Preprocessing images of current project @QtCore.pyqtSlot() def on_preprocessing_image(self): if len(self.calib.imagelist) > 0: self.calib.refresh() self.statusBar().showMessage( "Chương trình đang xử lý tác vụ: Tiền xử lý ảnh - ") #self.textedit.clear() self.textedit.append("") self.textedit.append("***********************************") #self.textedit.append("") self.textedit.append( str("Tiền xử lý ảnh dự án Calib_") + str(self.project_num) + str(":")) self.thread_image_preprocessing = Calib_Preprocess_Thread( self.calib) self.thread_image_preprocessing.sig1.connect( self.on_image_preprocessing_display) self.thread_image_preprocessing.sig2.connect( self.on_image_preprocessed_display) self.thread_image_preprocessing.sig3.connect( self.on_image_preprocessed_result) self.thread_image_preprocessing.start() #Calibrate current project @QtCore.pyqtSlot() def on_calibrate_image(self): if self.calib.preprocessing_done == True: # Calibrate if calib has not done if self.calib.calibrated == False: self.thread_calib = Calib_Calibrate_Thread(self.calib) self.thread_calib.sig1.connect(self.on_calibtation_processed) self.thread_calib.start() @QtCore.pyqtSlot() def on_view_project_info(self): pass @QtCore.pyqtSlot() def on_view_calib_info(self): calib_list = [] if len(self.project_list) > 0: for calib in self.project_list: clone_calib = calib.clone() calib_list.append(clone_calib) if self.calib.calibrated == True: clone_calib = self.calib.clone() clone_calib.project_name = str("Calib_") + str(self.project_num) calib_list.append(clone_calib) if len(calib_list) > 0: self.calib_info = Total_Calib_Info(calib_list) self.calib_info.show() else: msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("Chưa có dự án kiểm chuẩn được thực hiện hoàn chỉnh!") msg.setWindowTitle("Thông báo") msg.exec_() def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom(0.5) def pan(self): self.toolbar.pan() def plot(self): #Moving Camera class to a thread and emit signal from that thread self.thread1 = Frame_Capture_Thread(self.camera) self.thread1.sig1.connect(self.on_frame) self.thread1.start() def on_frame(self, frame): plt.imshow(frame) self.canvas.draw() #Update current image name being processed: fname is image name obtained from signal sig1 of Calib_Preprocess_Thread def on_image_preprocessing_display(self, fname): filename = fname.split('\\')[-1] filename_message = str( "Chương trình đang xử lý tác vụ: Tiền xử lý ảnh - đang xử lý file ảnh: " ) + filename self.statusBar().showMessage(filename_message) self.textedit.append( str("Tiền xử lý ảnh - đang xử lý file ảnh: ") + str(filename) + str("...")) #Update last processed image on display : pic is image data obtained from signal sig2 of Calib_Preprocess_Thread def on_image_preprocessed_display(self, pic): plt.imshow(pic) self.canvas.draw() #Update preprocessing result - def on_image_preprocessed_result(self, result): redColor = QtGui.QColor(255, 0, 0) blackColor = QtGui.QColor(0, 0, 0) ret = result[0] fname = result[1] filename = fname.split('\\')[-1] if ret == True: self.textedit.setTextColor(blackColor) msg = str("Xử lý xong ảnh ") + filename + str( " - ảnh hợp lệ cho kiểm chuẩn!") self.textedit.append(msg) else: self.textedit.setTextColor(redColor) msg = str("Xử lý xong ảnh ") + filename + str( " - ảnh không hợp lệ cho kiểm chuẩn!") self.textedit.append(msg) self.textedit.setTextColor(blackColor) if self.calib.preprocessing_done == True: msg = str("Tổng số ảnh tiền xử lý: ") + str( self.calib.processed_count) self.textedit.append(msg) msg = str("Số ảnh hợp lệ cho kiểm chuẩn: ") + str( self.calib.validated_count) self.textedit.append(msg) msg = str("Số ảnh không hợp lệ cho kiểm chuẩn: ") + str( self.calib.processed_count - self.calib.validated_count) self.textedit.append(msg) self.statusBar().showMessage( "Hoàn thành tác vụ tiền xử lý ảnh - dự án Calib_" + str(self.project_num)) def on_calibtation_processed(self): self.calib.project_name = str("Calib_") + str(self.project_num) self.calib_info_window = Calib_Info(self.calib) self.calib_info_window.show()
class window_graph(QDialog): def __init__(self,data,Fs,status,methodValues=0,deletedEpochs=0,totalepochs=0): QDialog.__init__(self); loadUi('graph.ui',self); self.setWindowIcon(QtGui.QIcon("logo.png")) self.mySignal=data self.myFs=Fs self.status=status self.methodSignal=methodValues self.deletedEpochs=deletedEpochs self.numEpochs=totalepochs self.channels, self.points = shape(self.mySignal) #self.time_array=arange(0,self.points/self.myFs,1/self.myFs) self.button_zoom.clicked.connect(self.zoom) self.button_pan.clicked.connect(self.pan) self.button_home.clicked.connect(self.home) self.figure = Figure(figsize=(5,4), dpi=100) self.canvas = FigureCanvas(self.figure) self.axes=self.figure.add_subplot(111) self.toolbar=NavigationToolbar(self.canvas,self) self.toolbar.hide() layout=QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) self.field_graph.setLayout(layout) self.axes.clear() self.canvas.draw() self.plot() def plot(self): legends=['Ch 1','Ch 2','Ch 3','Ch 4','Ch 5','Ch 6','Ch 7','Ch 8'] if self.status==1: for c in range(self.channels): self.axes.plot(self.mySignal[c,::]) self.axes.legend(legends) self.axes.set_title('Señal original') if self.status==2: r=[] for c in range(self.channels): r.append(c*150) self.axes.plot(self.mySignal[c,::]+c*150) self.axes.set_yticklabels(legends) self.axes.set_yticks(r) self.axes.set_title('Señal filtrada') if self.status==3: r=[] for c in range(self.channels): r.append(c*150) self.axes.plot(self.mySignal[c,::]+c*150) self.axes.plot(self.methodSignal[c,::]+c*150,'r') self.axes.set_yticklabels(legends) self.axes.set_yticks(r) self.axes.set_title('Eliminación de épocas') msg = QMessageBox(self) msg.setIcon(QMessageBox.Information) msg.setText("Se eliminaron las épocas : "+' '.join(str(ep) for ep in self.deletedEpochs)) msg.setWindowTitle("Épocas eliminadas") msg.setInformativeText("Épocas iniciales: "+str(self.numEpochs)+'\tÉpocas restantes: '+str(self.numEpochs-len(self.deletedEpochs))) msg.show(); self.axes.set_ylabel('Voltaje [uV]') self.axes.set_xlabel('Muestras') self.axes.grid(True) self.axes.set_xlim([0,4000]) self.canvas.draw() def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan()
class PulsedNMR(QMainWindow, Ui_PulsedNMR): rates = {0: 25.0e3, 1: 50.0e3, 2: 250.0e3, 3: 500.0e3, 4: 2500.0e3} def __init__(self): super(PulsedNMR, self).__init__() self.setupUi(self) self.rateValue.addItems(['25', '50', '250', '500', '2500']) # IP address validator rx = QRegExp( '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' ) self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue)) # state variable self.idle = True # number of samples to show on the plot self.size = 50000 # buffer and offset for the incoming samples self.buffer = bytearray(8 * self.size) self.offset = 0 self.data = np.frombuffer(self.buffer, np.complex64) # create figure figure = Figure() figure.set_facecolor('none') self.axes = figure.add_subplot(111) self.canvas = FigureCanvas(figure) self.plotLayout.addWidget(self.canvas) # create navigation toolbar self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False) # remove subplots action actions = self.toolbar.actions() self.toolbar.removeAction(actions[7]) self.plotLayout.addWidget(self.toolbar) # create TCP socket self.socket = QTcpSocket(self) self.socket.connected.connect(self.connected) self.socket.readyRead.connect(self.read_data) self.socket.error.connect(self.display_error) # connect signals from buttons and boxes self.startButton.clicked.connect(self.start) self.freqValue.valueChanged.connect(self.set_freq) self.awidthValue.valueChanged.connect(self.set_awidth) self.deltaValue.valueChanged.connect(self.set_delta) self.rateValue.currentIndexChanged.connect(self.set_rate) # set rate self.rateValue.setCurrentIndex(2) # create timer for the repetitions self.timer = QTimer(self) self.timer.timeout.connect(self.fire) def start(self): if self.idle: self.startButton.setEnabled(False) self.socket.connectToHost(self.addrValue.text(), 1001) else: self.idle = True self.timer.stop() self.socket.close() self.offset = 0 self.startButton.setText('Start') self.startButton.setEnabled(True) def connected(self): self.idle = False self.set_freq(self.freqValue.value()) self.set_rate(self.rateValue.currentIndex()) self.set_awidth(self.awidthValue.value()) self.fire() self.timer.start(self.deltaValue.value()) self.startButton.setText('Stop') self.startButton.setEnabled(True) def read_data(self): size = self.socket.bytesAvailable() if self.offset + size < 8 * self.size: self.buffer[self.offset:self.offset + size] = self.socket.read(size) self.offset += size else: self.buffer[self.offset:8 * self.size] = self.socket.read(8 * self.size - self.offset) self.offset = 0 # plot the signal envelope self.curve.set_ydata(np.real(self.data)) self.canvas.draw() def display_error(self, socketError): if socketError == QAbstractSocket.RemoteHostClosedError: pass else: QMessageBox.information(self, 'PulsedNMR', 'Error: %s.' % self.socket.errorString()) self.startButton.setText('Start') self.startButton.setEnabled(True) def set_freq(self, value): if self.idle: return self.socket.write(struct.pack('<I', 0 << 28 | int(1.0e6 * value))) def set_rate(self, index): # time axis rate = float(PulsedNMR.rates[index]) time = np.linspace(0.0, (self.size - 1) * 1000.0 / rate, self.size) # reset toolbar self.toolbar.home() self.toolbar._views.clear() self.toolbar._positions.clear() # reset plot self.axes.clear() self.axes.grid() # plot zeros and get store the returned Line2D object self.curve, = self.axes.plot(time, np.zeros(self.size)) x1, x2, y1, y2 = self.axes.axis() # set y axis limits self.axes.axis((x1, x2, -0.1, 0.4)) self.axes.set_xlabel('time, ms') self.canvas.draw() # set repetition time minimum = self.size / rate * 2000.0 if minimum < 100.0: minimum = 100.0 self.deltaValue.setMinimum(minimum) self.deltaValue.setValue(minimum) if self.idle: return self.socket.write(struct.pack('<I', 1 << 28 | index)) def set_awidth(self, value): if self.idle: return self.socket.write(struct.pack('<I', 2 << 28 | int(1.0e1 * value))) def set_delta(self, value): if self.idle: return self.timer.stop() self.timer.start(value) def fire(self): if self.idle: return self.socket.write(struct.pack('<I', 3 << 28))
class MyTableWidget(QWidget): sig = pyqtSignal(list) sigload = pyqtSignal(list) def __init__(self, parent): super(QWidget, self).__init__(parent) self.videosettingschanged = False #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%# #-------------- Make the input widges --------------# #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%# # ------------------------# # Main buttons ans inputs # # ------------------------# # Push button to load telemac 2d output Load = QPushButton('Load .slf or .npy') Load.clicked.connect(self.openFileNameDialog) Load.setToolTip('Load the output from a TELEMAC 2D simulation') Load.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } """) Load.setFixedWidth(150) # label to show the path of the loaded selafin file self.Path_label = QLabel() self.Path_label.setStyleSheet(""" QLabel { color: rgb(180,180,180); padding: 10px; } """) # Spin box for X X_label = QLabel('X-coordinate:') X_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) X_label.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); } """) Y_label = QLabel('Y-coordinate:') Y_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) Y_label.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); } """) # Spin box for Y self.X_box = QLabel(' ') self.X_box.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); max-height: 30px; min-width: 160px; } """) self.Y_box = QLabel(' ') self.Y_box.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); max-height: 30px; min-width: 160px; } """) # date and time start_time = QLabel('Start Date & Time:') start_time.setAlignment(Qt.AlignRight | Qt.AlignVCenter) start_time.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); }""") end_time = QLabel('End Date & Time:') end_time.setAlignment(Qt.AlignRight | Qt.AlignVCenter) end_time.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); }""") self.start_time = QLineEdit() self.start_time.setStyleSheet(""" QLineEdit { color: rgb(180,180,180); background-color: rgb(25,25,25); }""") self.end_time = QLineEdit() self.end_time.setStyleSheet(""" QLineEdit { color: rgb(180,180,180); background-color: rgb(25,25,25); }""") # Push button to load telemac 2d output self.PlotSeries = QPushButton('Plot Series') self.PlotSeries.setDisabled(True) self.PlotSeries.clicked.connect(self.plotTimeSeries) self.PlotSeries.setToolTip('Plot time series of surface elevation at selected area.') self.PlotSeries.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } QPushButton:disabled { color: rgb(50,50,50); background-color: rgb(25, 25, 25); } """) # Push button to load telemac 2d output self.Video = QPushButton('Generate a video') self.Video.setDisabled(True) self.Video.clicked.connect(self.plotVideo) self.Video.setToolTip('Generate a video of the water surface elevation over time.') self.Video.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } QPushButton:disabled { color: rgb(50,50,50); background-color: rgb(25, 25, 25); } """) # Push button to load telemac 2d output self.VideoSettings = QPushButton('Video settings') #self.VideoSettings.setDisabled(True) self.VideoSettings.clicked.connect(self.setVideoSettings) self.VideoSettings.setToolTip('Change the settings of the video export.') self.VideoSettings.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } QPushButton:disabled { color: rgb(50,50,50); background-color: rgb(25, 25, 25); } """) # Push button to plot a variable along the mesh self.PlotMesh = QPushButton('Plot variable on mesh') self.PlotMesh.setDisabled(True) self.PlotMesh.clicked.connect(self.plotMeshVar) self.PlotMesh.setToolTip('Generate a map with a given variable.') self.PlotMesh.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } QPushButton:disabled { color: rgb(50,50,50); background-color: rgb(25, 25, 25); } """) # Push button to reload general mesh view self.ReloadMesh = QPushButton('Reload mesh view') self.ReloadMesh.setDisabled(True) self.ReloadMesh.clicked.connect(self.reloadMesh) self.ReloadMesh.setToolTip('Reload the general mesh view.') self.ReloadMesh.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } QPushButton:disabled { color: rgb(50,50,50); background-color: rgb(25, 25, 25); } """) # Push button to open dialog to locate a value self.LocateValue = QPushButton('Locate value') self.LocateValue.setDisabled(True) self.LocateValue.clicked.connect(self.locateValue) self.LocateValue.setToolTip('Locate a value on the mesh (e.g. maximum h in mangroves).') self.LocateValue.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } QPushButton:disabled { color: rgb(50,50,50); background-color: rgb(25, 25, 25); } """) self.LoadPrevious = QCheckBox('Ignore previously saved meshes') self.LoadPrevious.setChecked(True) self.LoadPrevious.setToolTip('Ignore existing files in previously_loaded_meshes and copy loaded files to this directory.') self.LoadPrevious.setStyleSheet(""" QCheckBox { color: rgb(120,120,120); background-color: rgb(35,35,35); } """) self.RemovePrevious = QCheckBox('Clear previously saved meshes') self.RemovePrevious.setChecked(True) self.RemovePrevious.setToolTip('Clear all files tores in previously_loaded_meshes when closing.') self.RemovePrevious.setStyleSheet(""" QCheckBox { color: rgb(120,120,120); background-color: rgb(35,35,35); } """) # ------------# # Time Series # # ------------# # time series objects self.WSE_series = TimeSeries('Water Surface Elevation [m]') self.Vel_series = TimeSeries('Water Velocity [m/s]') # ----------------------# # Main window with mesh # # ----------------------# # FigureCanvas to show the mesh in self.figure = plt.figure() self.figure.set_facecolor((45/255, 45/255, 45/255)) self.canvas = FigureCanvas(self.figure) self.canvas.setFixedSize(700,700) # buttons to zoom and pan self.zoombut = QPushButton() self.zoombut.setCheckable(True) self.zoombut.setEnabled(False) im = QIcon('support_files/zoom.png') self.zoombut.setIcon(im) self.zoombut.clicked.connect(self.zoom) self.zoombut.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:checked { color: rgb(25,25,25); background-color: rgb(255, 128, 0); } """) self.panbut = QPushButton() self.panbut.setCheckable(True) self.panbut.setEnabled(False) im = QIcon('support_files/pan.png') self.panbut.setIcon(im) self.panbut.clicked.connect(self.pan) self.panbut.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:checked { color: rgb(25,25,25); background-color: rgb(255, 128, 0); } """) self.locbut = QPushButton() self.locbut.setCheckable(True) self.locbut.setEnabled(False) im = QIcon('support_files/loc.png') self.locbut.setIcon(im) self.locbut.clicked.connect(self.loc) self.locbut.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:checked { color: rgb(25,25,25); background-color: rgb(255, 128, 0); } """) self.canvas.mpl_connect("button_press_event", self.on_press) self.record_pressing_event = False self.addcoor = QPushButton('xy') self.addcoor.setEnabled(False) self.addcoor.clicked.connect(self.addCoorToMap) self.addcoor.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } """) self.homebut = QPushButton() self.homebut.setEnabled(False) im = QIcon('support_files/home.png') self.homebut.setIcon(im) self.homebut.clicked.connect(self.home) self.homebut.setStyleSheet(""" QPushButton { border-width: 25px solid white; border-radius: 5px; color: rgb(180,180,180); background-color: rgb(55, 55, 60); min-height: 40px; } QPushButton:pressed { color: rgb(120,120,120); background-color: rgb(75, 75, 80); } """) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # label to show bathymetry self.Bath_label = QLabel() self.Bath_label.setFixedWidth(125) self.Bath_label.setStyleSheet(""" QLabel { color: rgb(255,128,0); font-size: 8pt; background-color: rgb(35, 35, 35); } """) # label to show bathymetry self.Station_label = QLabel() self.Station_label.setFixedWidth(125) self.Station_label.setStyleSheet(""" QLabel { color: rgb(255,128,0); font-size: 10pt; background-color: rgb(35, 35, 35); } """) #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%# #-------------- Organize and set the layout --------------# #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%# self.grid = QGridLayout() self.grid.setSpacing(10) self.grid.addWidget(self.canvas, 0, 0, 9, 10) self.grid.addWidget(self.zoombut, 9, 0, 1, 1) self.grid.addWidget(self.panbut, 9, 1, 1, 1) self.grid.addWidget(self.locbut, 9, 2, 1, 1) self.grid.addWidget(self.addcoor, 9 , 3, 1, 1) self.grid.addWidget(self.homebut, 9, 4, 1, 1) self.grid.addWidget(self.Bath_label, 9, 5) self.grid.addWidget(self.Station_label, 9, 6) self.grid.addWidget(Load,0,11,1,1) self.grid.addWidget(self.Path_label, 0,12,1,3) self.grid.addWidget(X_label, 1,11,1,1) self.grid.addWidget(Y_label, 2,11,1,1) self.grid.addWidget(self.X_box, 1,12,1,1) self.grid.addWidget(self.Y_box, 2,12,1,1) self.grid.addWidget(start_time, 1, 13) self.grid.addWidget(end_time, 2, 13) self.grid.addWidget(self.start_time, 1, 14) self.grid.addWidget(self.end_time, 2, 14) self.box_buttons = QVBoxLayout() self.box_buttons.addWidget(self.PlotSeries) self.box_buttons.addWidget(self.Video) self.box_buttons.addWidget(self.VideoSettings) self.box_buttons.addWidget(self.PlotMesh) self.box_buttons.addWidget(self.ReloadMesh) self.box_buttons.addWidget(self.LocateValue) self.box_buttons.addWidget(self.LoadPrevious) self.box_buttons.addWidget(self.RemovePrevious) self.box_buttons.addStretch() self.grid.addLayout(self.box_buttons, 0, 15, 10, 1) self.grid.addWidget(self.WSE_series,3,11,3,4) self.grid.addWidget(self.Vel_series,6,11,3,4) self.setLayout(self.grid) self.show() #-------------------------------------# #-------------- Methods --------------# #-------------------------------------# def openFileNameDialog(self): options = QFileDialog.Options() self.fileName, self.cancel = QFileDialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","Numpy files (*.npy);; Selafin Files (*.slf)", options=options) print('Loading file...') try: self.loadMesh() self.Path_label.setText(self.fileName.split('/')[-1]) except: self.Path_label.setText('Something went wrong!') print("Unexpected error:", sys.exc_info()[0]) def loadMesh(self): if self.LoadPrevious.isChecked(): ignore_previously_saved_files = True else : ignore_previously_saved_files = False self.name, self.ax, self.tc = loadMeshFromSLF(self.fileName, self.figure, self.canvas, ignore_previously_saved_files = ignore_previously_saved_files, return_tc = True) self.canvas.draw() self.loadArrays() self.zoombut.setEnabled(True) self.panbut.setEnabled(True) self.locbut.setEnabled(True) self.homebut.setEnabled(True) self.addcoor.setEnabled(True) self.Video.setEnabled(True) self.LocateValue.setEnabled(True) self.VideoSettings.setEnabled(True) self.PlotSeries.setEnabled(True) self.PlotMesh.setEnabled(True) def loadArrays(self): fn = str('./previously_loaded_meshes/'+self.name) self.fn = fn data = np.load(fn + '_data.npy') X = np.load(fn + '_x.npy') Y = np.load(fn + '_y.npy') self.ikle = np.load(fn + '_ikle.npy') self.times = np.load(fn + '_times.npy') # get properties U = data[0] V = data[1] H = data[2] B = data[3] N = data[4] self.U = U self.V = V self.Vel = np.sqrt(U**2+V**2) self.H = H self.SE = H+B self.B = B self.N = N self.X = X self.Y = Y self.XY = np.empty([np.shape(X)[0], 2]) self.XY[:,0], self.XY[:,1] = X, Y # time series start_date = np.datetime64('2019-10-07T04:00:00') T = np.array([start_date], dtype = np.datetime64) for i in range(1,np.shape(self.times)[0]): td = np.timedelta64(int(self.times[i]),'s') T = np.append(T,start_date + td) self.T = T start_t = str(self.T[0]) self.start_time.setText(start_t) end_t = str(self.T[-1]) self.end_time.setText(end_t) def plotTimeSeries(self): start_time = np.datetime64(self.start_time.text()) end_time = np.datetime64(self.end_time.text()) x = float(self.X_box.text()) y = float(self.Y_box.text()) X = self.XY[:,0] Y = self.XY[:,1] # find the closest node to the requested lat and lon neighxy= getNeighbor([x, y], self.XY, return_index = False) x_node, y_node = neighxy rx = np.where(X == x_node) ry = np.where(Y == y_node) i = np.intersect1d(rx,ry)[0] self.WSE_series.plotSeries(T = self.T, var = self.SE[i,:], t0 = start_time, t1 = end_time, x = X[i], y = Y[i]) self.Vel_series.plotSeries(T = self.T, var = self.Vel[i,:], t0 = start_time, t1 = end_time, x = X[i], y = Y[i]) self.i = i try: self.scat2.remove() except: pass self.scat2 = self.ax.scatter(neighxy[0], neighxy[1], s = 25, color = (1, 1, 1, 0), edgecolor = (1, 128/255, 0), zorder = 1e9) self.canvas.draw() self.X_box.setText('%.2f' % neighxy[0]) self.Y_box.setText('%.2f' % neighxy[1]) self.X_box.setStyleSheet(""" QLabel { color: rgb(255,128,0); background-color: rgb(35, 35, 35); max-height: 30px; min-width: 160px; } """) self.Y_box.setStyleSheet(""" QLabel { color: rgb(255,128,0); background-color: rgb(35, 35, 35); max-height: 30px; min-width: 160px; } """) bath_str = '%.2f' % self.B[i,0] frict_str = '%.3f' % self.N[i,0] i_str = str(i) self.Bath_label.setText('Bath: ' + bath_str + " m\nManning's n: " + frict_str + '\nIndex: ' + i_str) def setVideoSettings(self): dlg = VideoSettingDialog(self.ax.get_xlim() + self.ax.get_ylim()) if self.videosettingschanged: if self.videolims != None: dlg.SetWinLim.setChecked(True) dlg.WinLeft.setValue(self.videolims[0]) dlg.WinRight.setValue(self.videolims[1]) dlg.WinTop.setValue(self.videolims[2]) dlg.WinBot.setValue(self.videolims[3]) dlg.Min.setValue(self.videomin) dlg.Max.setValue(self.videomax) dlg.exec_( ) if dlg.good_exit: self.videosettingschanged = True self.videovar = dlg.var self.videomin = dlg.min self.videomax = dlg.max self.videolims = dlg.lims if len(np.unique(self.videolims)) == 1: self.videolims = None def plotVideo(self): if self.videosettingschanged == False: self.videovar = 0 self.videomin = -1 self.videomax = 5 self.videolims = None options = QFileDialog.Options() fn, _ = QFileDialog.getSaveFileName(self,"QFileDialog.getSaveFileName()","","All Files (*);;Text Files (*.txt)", options=options) if fn: self.thread = VideoThread() self.sig.connect(self.thread.on_source) self.sig.emit([self.fn, fn, [self.videovar, self.videomin, self.videomax, self.videolims]]) self.thread.start() self.thread.sig1.connect(self.on_info) def on_info(self, info): self.Path_label.setText(str(info)) def home(self): self.toolbar.home() def zoom(self): self.panbut.setChecked(False) self.locbut.setChecked(False) if self.zoombut.isChecked(): self.toolbar.zoom() self.record_pressing_event = False def pan(self): self.zoombut.setChecked(False) self.locbut.setChecked(False) if self.panbut.isChecked(): self.toolbar.pan() self.record_pressing_event = False def loc(self): self.zoombut.setChecked(False) self.panbut.setChecked(False) if self.toolbar._active == "PAN": self.toolbar.pan() elif self.toolbar._active == "ZOOM": self.toolbar.zoom() if self.locbut.isChecked(): self.record_pressing_event = True else: self.record_pressing_event = False def on_press(self, event): if self.record_pressing_event: self.X_box.setText('%.2f' % event.xdata) self.Y_box.setText('%.2f' % event.ydata) self.X_box.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); max-height: 30px; min-width: 160px; } """) self.Y_box.setStyleSheet(""" QLabel { color: rgb(180,180,180); background-color: rgb(35, 35, 35); max-height: 30px; min-width: 160px; } """) try: self.scat1.remove() except: pass self.scat1 = self.ax.scatter(event.xdata, event.ydata, s = 25, color = (1, 128/255, 0), zorder = 1e9) self.canvas.draw() self.Station_label.setText('') def addCoorToMap(self): dlg = AddCoorDialog(None) dlg.exec_() if dlg.good_exit: x = dlg.x y = dlg.y try: self.scat1.remove() except: pass self.scat1 = self.ax.scatter(x, y, s = 25, color = (1, 128/255, 0), zorder = 1e9) self.canvas.draw() self.X_box.setText('%.2f' % x) self.Y_box.setText('%.2f' % y) self.Station_label.setText(dlg.StationName) def plotMeshVar(self): dlg = PlotMeshVarDialog(None) dlg.time.setRange(0, len(self.times)-1) dlg.time.setValue(len(self.times)-1) dlg.exec_( ) if dlg.variable == 1: var = self.U; label_str = 'U [m/s] at timestep %d' % dlg.t if dlg.variable == 2: var = self.V; label_str = 'V [m/s] at timestep %d' % dlg.t if dlg.variable == 3: var = self.H; label_str = 'Water Depth [m] at timestep %d' % dlg.t if dlg.variable == 4: var = self.SE; label_str = 'Water Surface Elevation [m] at timestep %d' % dlg.t if dlg.variable == 5: var = self.B; label_str = 'Bathymetry [m] at timestep %d' % dlg.t if dlg.variable == 6: var = self.N; label_str = "Manning's n at timestep %d" % dlg.t if dlg.variable == 7: var = np.max(self.SE, axis = 1); label_str = "Maximum Water Surface Elevation [m]" if dlg.variable == 8: var = np.min(self.SE, axis = 1); label_str = "Maximum Water Surface Elevation [m]" if dlg.variable == 9: var = np.max(self.H, axis = 1); label_str = "Minimum Water Depth [m]" if dlg.variable == 10: var = np.min(self.H, axis = 1); label_str = "Minimum Water Depth [m]" if dlg.variable != None: if var.ndim == 2 and dlg.variable < 10: var = var[:,dlg.t] if len(dlg.min.text()) == 0 or len(dlg.max.text()) == 0: varmin, varmax = np.min(var),np.max(var) else: varmin, varmax = float(dlg.min.text()),float(dlg.max.text()) self.ax.clear() self.figure.clf() self.ax = self.figure.add_subplot(111) plotVarMesh(self.X, self.Y, self.ikle, var, label_str, min = varmin, max = varmax, ax = self.ax, fig = self.figure, showedges = dlg.showgridedges, showgrid=dlg.showagrid) self.canvas.draw() self.ReloadMesh.setDisabled(False) self.LocateValue.setDisabled(False) def locateValue(self): dlg = LocateValueDialog(None) dlg.exec_( ) if dlg.variable != None: if dlg.var.currentIndex() == 1: var = self.U; unit_str = 'm/s'; var_str = 'u' if dlg.var.currentIndex() == 2: var = self.V; unit_str = 'm/s'; var_str = 'v' if dlg.var.currentIndex() == 3: var = self.H; unit_str = 'm'; var_str = 'h' if dlg.var.currentIndex() == 4: var = self.SE; unit_str = 'm'; var_str = 'SE' #if dlg.reducer.currentText() == 'maximum': var = np.max(var, axis = 1) #if dlg.reducer.currentText() == 'minimum': var = np.min(var, axis = 1) if dlg.constvar.currentIndex() == 0: mask = self.B[:,0] if dlg.constvar.currentIndex() == 1: mask = self.N[:,0] if dlg.rel.currentText() == '>': mask = (mask < float(dlg.tresh.text())) elif dlg.rel.currentText() == '<': mask = (mask > float(dlg.tresh.text())) elif dlg.rel.currentText() == '=': mask = (mask == float(dlg.tresh.text())) else: print('woops') var_masked = var[mask] if dlg.reducer.currentText() == 'maximum':m = np.max(var_masked); am = np.where(var == m); lab = ' max ' if dlg.reducer.currentText() == 'minimum':m = np.min(var_masked); am = np.where(var == m); lab = ' min ' am = am[0][0] x = self.X[am] y = self.Y[am] self.locval = self.ax.scatter(x,y,s = 60,c = 'aquamarine') lab += '%s: %.2f %s' % (var_str, m, unit_str) self.loclabel = self.ax.annotate(lab,(x,y),fontsize = 8, c = 'aquamarine', bbox =dict(boxstyle="square", fc="0.1")) self.canvas.draw() def reloadMesh(self): self.ax.clear() self.ax = plotMesh(self.name, self.figure) self.canvas.draw() self.ReloadMesh.setDisabled(True)