class FigureWidget(QtGui.QWidget): """ A QWidget that contains a matplotlib plot that plots a matrix as a series of line plots. """ def __init__(self, parent=None): super(FigureWidget, self).__init__(parent) self.fig = plt.Figure() self.setMinimumSize(500,300) self.canvas = FigureCanvasQTAgg(self.fig) self.canvas.setParent(self) self.create_plots(1) # set the plot background color to the window background color color = QtGui.QPalette().window().color() self.fig.set_facecolor((color.redF(), color.greenF(), color.blueF())) self.canDraw = True def create_plots(self, num_plots): """ Create enough subplots to hold `num_plots` plots. """ self.canDraw = False self.fig.clear() self.axes = [self.fig.add_subplot(1,num_plots,n+1) for n in range(num_plots)] self.lines = [ax.plot(numpy.zeros(1024))[0] for ax in self.axes] for ax in self.axes: ax.set_ylim((-1,1)) ax.set_xlim((0,1024)) # move the spines out of the plot araea so it won't get # clobbered by the partial redrawing during `self.draw()`. ax.spines['bottom'].set_position(('outward', 5)) ax.spines['left'].set_position(('outward', 5)) ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) self.fig.tight_layout() self.canvas.draw() self.canDraw = True def resizeEvent(self, event): """ Scale the figure in tandem with the widget. """ self.fig.set_size_inches(self.width()/80, self.height()/80) self.canvas.draw() def showEvent(self, event): """ Called on the first draw. Sets up the correct window geometry. """ self.resizeEvent(None) def draw(self, data): """ Update the plots as quickly as possible. """ if not self.canDraw: return() for n in range(data.shape[1]): self.lines[n].set_ydata(data[:,n]) self.axes[n].draw_artist(self.axes[n].patch) self.axes[n].draw_artist(self.lines[n]) self.canvas.update()
class FigureWidget(QtGui.QWidget): """ A QWidget that contains a matplotlib plot that plots a matrix as a series of line plots. """ def __init__(self, parent=None): super(FigureWidget, self).__init__(parent) self.fig = plt.Figure() self.setMinimumSize(500, 300) self.canvas = FigureCanvasQTAgg(self.fig) self.canvas.setParent(self) self.create_plots(1) # set the plot background color to the window background color color = QtGui.QPalette().window().color() self.fig.set_facecolor((color.redF(), color.greenF(), color.blueF())) self.canDraw = True def create_plots(self, num_plots): """ Create enough subplots to hold `num_plots` plots. """ self.canDraw = False self.fig.clear() self.axes = [ self.fig.add_subplot(1, num_plots, n + 1) for n in range(num_plots) ] self.lines = [ax.plot(numpy.zeros(1024))[0] for ax in self.axes] for ax in self.axes: ax.set_ylim((-1, 1)) ax.set_xlim((0, 1024)) # move the spines out of the plot araea so it won't get # clobbered by the partial redrawing during `self.draw()`. ax.spines['bottom'].set_position(('outward', 5)) ax.spines['left'].set_position(('outward', 5)) ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) self.fig.tight_layout() self.canvas.draw() self.canDraw = True def resizeEvent(self, event): """ Scale the figure in tandem with the widget. """ self.fig.set_size_inches(self.width() / 80, self.height() / 80) self.canvas.draw() def showEvent(self, event): """ Called on the first draw. Sets up the correct window geometry. """ self.resizeEvent(None) def draw(self, data): """ Update the plots as quickly as possible. """ if not self.canDraw: return () for n in range(data.shape[1]): self.lines[n].set_ydata(data[:, n]) self.axes[n].draw_artist(self.axes[n].patch) self.axes[n].draw_artist(self.lines[n]) self.canvas.update()
class mpl_widget(QWidget): def __init__(self, parent=None, mainWidget=None): self._SELECTEDCELLS = list() # container for instances of selected cells, so we can delete them when we want self._SELECTEDCELLS_IJ = list() # container for coords of selected cells, so we can delete them when we want self._SELECTEDCELLLINES = list() # container for instances of selected cells, so we can delete them when we want self._GRIDLINES = None QWidget.__init__(self, parent) self.mainWidget = mainWidget self.create_main_frame() self.mpl_menu = mpl_menu(self) self.shift_is_held = False #self.connect(self.mpl_menu, QtCore.SIGNAL('mySignal'), self.mySlot) #print 'my parent is:', parent self.clear_selection() self.init_tooltips() def init_tooltips(self): self.canvas.setToolTip('If 2D plot => RMB click toggles menu <br> - RMB click selects cell <br> - selected cells are drawn with black border') self.grid_cb.setToolTip('If 2D plot => show computational grid <br> If 1D plot => show normal gridlines') self.cbar_button.setToolTip('If 2D plot => controls the color range. <br> Note: <br> - pressing UP and DOWN arrows cycles through colormaps <br> - dragging colorbar with RMB scales the color-range <br> - dragging colorbar with LMB shifts the color-range') self.mpl_toolbar.setToolTip('Shows coordinates (i,j, lat,lon) and data-value(z) under the cursor. <br> if you see <i>>>></i> coordinates are not visible. Enlarge the window') def create_main_frame(self): self.fig = Figure(dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.canvas.setFocusPolicy( Qt.ClickFocus ) self.canvas.setFocus() self.mpl_toolbar = myNavigationToolbar(self.canvas, self) self.canvas.mpl_connect('button_press_event', self.on_click) self.canvas.mpl_connect('key_press_event', self.on_key_press) self.canvas.mpl_connect('key_release_event', self.on_key_release) #self.canvas.mpl_connect('button_press_event', self.disable_clicks) self.cbar_button = QPushButton("Color Range") self.cbar_button.setFocusPolicy( Qt.NoFocus ) self.grid_cb = QCheckBox("Show Grid") self.grid_cb.setFocusPolicy( Qt.NoFocus ) self.grid_cb.stateChanged.connect(self.showGrid) vbox = QVBoxLayout() hbox = QHBoxLayout() vbox.addWidget(self.canvas) # the matplotlib canvas hbox.addWidget(self.mpl_toolbar) hbox.addWidget(self.cbar_button) hbox.addWidget(self.grid_cb) vbox.addLayout(hbox) self.setLayout(vbox) def on_click(self, event): if event.inaxes != self.get_axes()[0]: return #if self.get_axes()[0].format_coord(event.x, event.y) == 'outside data area': return if self.allow_menu(): self.allow_popup_menu = True if self.shift_is_held: self.allow_popup_menu = False point = [int(event.xdata + .5), int(event.ydata + .5)] #print '>>>', point, '\t currently {0} selected'.format(len(self._SELECTEDCELLS)) if event.button == 3 : #if RMB is clicked # working with dialog for transect! if self.mainWidget.transect_dlg: if self.mainWidget.transect_dlg.toogle_show_after_selected_cell: realx, realy = self.get_real_xy(event.xdata, event.ydata, self.mainWidget.detect_variable_dimensions()) realpoint = [realy, realx] #print 'real xy:', realpoint if self.mainWidget.transect_dlg.toogle_show_after_selected_cell == 1: # select point 1 self.allow_popup_menu = False self.mainWidget.transect_dlg.data.set_p1(realpoint) elif self.mainWidget.transect_dlg.toogle_show_after_selected_cell == 2: # select point 2 self.allow_popup_menu = False self.mainWidget.transect_dlg.data.set_p2(realpoint) self.mainWidget.transect_dlg.update() self.mainWidget.transect_dlg.show() # working with dialog for flux! if self.mainWidget.flux_dlg: if self.mainWidget.flux_dlg.toogle_show_after_selected_cell: if self.mainWidget.flux_dlg.toogle_show_after_selected_cell == 1: # select point 1 self.allow_popup_menu = False self.mainWidget.flux_dlg.data.set_p1(point) elif self.mainWidget.flux_dlg.toogle_show_after_selected_cell == 2: # select point 2 self.allow_popup_menu = False self.mainWidget.flux_dlg.data.set_p2(point) self.mainWidget.flux_dlg.update() self.mainWidget.flux_dlg.show() if len(self._SELECTEDCELLS) == 0: # if no cell is selected self.add_selected_cell(point) else: # if some cells are already selected if self.mpl_menu.allow_rmb_select_cells() or self.shift_is_held: # check if this point is already selected: already_selected = False for p in self._SELECTEDCELLS_IJ: if (point[0] == p[0]) and (point[1] == p[1]): already_selected = True print 'cell already selected... is not added' if not already_selected: self.add_selected_cell(point) else: pass #self.clear_selection() #self.add_selected_cell(point) def cells_selected(self): if self._SELECTEDCELLS: return len(self._SELECTEDCELLS) else: return False def add_selected_cell(self, point): ''' point = [i, j]''' print 'selected cell:', point[0], point[1] c = self.draw_picked_cell(point) self._SELECTEDCELLS.append(c) self._SELECTEDCELLS_IJ.append(point) def get_selected_cells_ij(self): return self._SELECTEDCELLS_IJ def clear_selection(self): ''' delete all graphical objects of selected cells redraw canvas ''' print 'clearing stuff' if len(self._SELECTEDCELLLINES) > 0: for line in self._SELECTEDCELLLINES: l = line.pop(0) l.remove() del l del self._SELECTEDCELLLINES[:] #print 'cells ---- before:', len(self._SELECTEDCELLS) if len(self._SELECTEDCELLS) > 0: for cell in self._SELECTEDCELLS: for line in cell: l = line.pop(0) l.remove() del l del self._SELECTEDCELLS[:] #print 'cells ---- left:', len(self._SELECTEDCELLS) #print 'cells-coords ----' #print len(self._SELECTEDCELLS_IJ) if self._SELECTEDCELLS_IJ: for cellcoords in self._SELECTEDCELLS_IJ: #cc = cellcoords.pop(0) #cellcoords.remove() del cellcoords del self._SELECTEDCELLS_IJ[:] #print 'cells ---- left,', len(self._SELECTEDCELLS_IJ) if len(self._SELECTEDCELLS) != 0: raise ValueError('List "self._SELECTEDCELLS" was not flushed') if len(self._SELECTEDCELLLINES) != 0: raise ValueError('List "self._SELECTEDCELLLINES" was not flushed') if len(self._SELECTEDCELLS_IJ) != 0: raise ValueError('List "self._SELECTEDCELLLINES" was not flushed') # update plot self.canvas.draw() #print 'finishing clear: cells left', len(self._SELECTEDCELLS) def showGrid(self, state): if self.fig.axes: current_plot = self.mainWidget.get_plotType() current_plot2D = self.mainWidget.get_plotType_for_timeseries() if state == Qt.Checked: if current_plot == '1D' or (current_plot2D =="2DZT"): self.fig.axes[0].grid(True) elif current_plot == '2D' and (not current_plot2D =="2DZT"): self.draw_pixel_grid(True) else: if current_plot == '1D' or (current_plot2D =="2DZT"): self.fig.axes[0].grid(False) elif current_plot == '2D' and (not current_plot2D =="2DZT"): self.draw_pixel_grid(False) self.canvas.draw() def draw_picked_cell(self, point): x = point[0] y = point[1] ''' approach drawing a patch... not working cell_bnd = patches.Rectangle((x-.5, y-.5), 1, 1, fill=False, edgecolor="black", hatch=None, linewidth=1.) cell_instance = self.fig.axes[0].add_patch(cell_bnd) ''' b_line = [(x-.5, x+.5), (y-.5, y-.5)] r_line = [(x+.5, x+.5), (y-.5, y+.5)] t_line = [(x-.5, x+.5), (y+.5, y+.5)] l_line = [(x-.5, x-.5), (y-.5, y+.5)] cell = [b_line, r_line, t_line, l_line] for i, l in enumerate(cell): ll = self.fig.axes[0].plot(l[0], l[1], 'k-', lw=.8) cell[i] = ll # overwriting current Line2D object with object binded to an axes #self._SELECTEDCELLS.append(cell) # collecting reference to this cell to be able to delete it #self._SELECTEDCELLS_IJ.append(point) # collecting reference to this cell to be able to delete it self.canvas.draw() return cell def draw_line(self, point1, point2): line = [(point1[0], point2[0]), (point1[1], point2[1])] l = self.fig.axes[0].plot(line[0], line[1], 'k-', lw=2) return l def draw_pixel_grid(self, enable=True): if enable: dx = 1 dy = 1 x0 = -.5 y0 = -.5 if self.mainWidget.get_plotType_for_timeseries() == '2DXY': nx = self.mainWidget.get_nX() ny = self.mainWidget.get_nY() elif self.mainWidget.get_plotType_for_timeseries() == '2DZY': nx = self.mainWidget.get_nY() ny = self.mainWidget.get_nZ() elif self.mainWidget.get_plotType_for_timeseries() == '2DZX': nx = self.mainWidget.get_nX() ny = self.mainWidget.get_nZ() self._GRIDLINES = list() for n_hline in np.arange(ny+1): hline = [(x0, x0+nx), (y0+n_hline, y0+n_hline)] l = self.fig.axes[0].plot(hline[0], hline[1], 'k-', lw=.2) self._GRIDLINES.append(l) # collecting reference to this line to be able to delete it for n_vline in np.arange(nx+1): vline = [(x0+n_vline, x0+n_vline), (y0, y0+ny)] l = self.fig.axes[0].plot(vline[0], vline[1], 'k-', lw=.2) self._GRIDLINES.append(l) # collecting reference to this line to be able to delete it if not enable: #print 'deleting lines...' if self._GRIDLINES: # if lines were created #print 'lines are here...' for line in self._GRIDLINES: #print line l = line.pop(0) l.remove() del l self.fig.canvas.draw() def on_key_press(self, event): #print 'key pressed:', event.key if event.key == 'shift': self.shift_is_held = True def on_key_release(self, event): #print 'key released:', event.key if event.key == 'shift': self.shift_is_held = False elif event.key == 'escape': self.clear_selection() def change_coordinate_formatter(self, ax, data2d, bruteforce_flag=None, bruteforce_dims=None): ''' see http://stackoverflow.com/questions/14754931/matplotlib-values-under-cursor ''' numrows, numcols = data2d.shape bruteforce_mode_on = False bruteforce_mode_on = (bruteforce_flag == '2DXY' and bruteforce_dims[-1] and bruteforce_dims[-2]) def format_coord(x, y): col = int(x+0.5) row = int(y+0.5) if not bruteforce_mode_on: if col >= 0 and col < numcols and row >= 0 and row < numrows: #z = data2d[row, col] # sice we have artificially reversed y-coordinate axes, now reverse data! # numrows-1, because if nrows=10 => row=[0:9] z = data2d[numrows-1-row, col] #return 'x=%1.1f y=%1.1f z=%1.6f' % (x, y, z) return 'i=%d j=%d z=%.6f' % (col, row, z) else: #return 'x=%1.4f, y=%1.4f' % (x, y) return 'outside data area' elif bruteforce_flag == '2DXY' and bruteforce_dims[-1] and bruteforce_dims[-2]: ''' our extend in X=[-0.5:numcols-0.5], Y=[-0.5:numrows-0.5], because col,row is cell center! ''' if col >= 0 and col < numcols and row >= 0 and row < numrows: #z = data2d[row, col] # sice we have artificially reversed y-coordinate axes, now reverse data! # numrows-1, because if nrows=10 => row=[0:9] z = data2d[numrows-1-row, col] real_x, real_y = self.get_real_xy(x, y, bruteforce_dims) #return 'x=%1.1f y=%1.1f z=%1.6f' % (x, y, z) #return 'i=%d j=%d z=%.3f x=%.4f y=%.4f' % (col, row, z, real_x, real_y) return 'i=%d j=%d z=%.3f, %s=%.2f %s=%.2f' % ( col, row, z, bruteforce_dims[-1], real_x, bruteforce_dims[-2], real_y) else: #return 'x=%1.4f, y=%1.4f' % (x, y) return 'outside data area' else: raise ValueError('bruteforce_flag can be $None$ or $"2DXY"$. Passed %s' % bruteforce_flag) ax.format_coord = format_coord def allow_menu(self): allow = False #print "self.mainWidget.get_plotType():", self.mainWidget.get_plotType() #print "self.mainWidget.get_plotType_for_timeseries():", self.mainWidget.get_plotType_for_timeseries() if self.mainWidget.get_plotType() == "2D" and not self.mainWidget.get_plotType_for_timeseries() == "2DZT": allow = True return allow def get_real_xy(self, i, j, dimension_list): ''' functions returns values of x,y based on passed indexes i, j ''' if any(dimension_list[-2:-1]) is None: print 'Dimensions X,Y of current variable are not specified (variables that have same name as dimensions not found)' raise ValueError('Dimensions X,Y of current variable are not specified (variables that have same name as dimensions not found)') nc = self.mainWidget.get_selected_ncfile_instance() try: x_var = nc.variables[dimension_list[-1]] y_var = nc.variables[dimension_list[-2]] except: print ('Failed to load variables: {0}, {1}'.format(dimension_list[-1], dimension_list[-2])) raise ValueError('Failed to load variables: {0}, {1}'.format(dimension_list[-1], dimension_list[-2])) x_ratio = (x_var[-1]-x_var[0])/(len(x_var)-1) y_ratio = (y_var[-1]-y_var[0])/(len(y_var)-1) #x[i] = x_var[0]+x_ratio*i #y[j] = y_var[0]+y_ratio*j x = x_var[0] + x_ratio*i y = y_var[0] + y_ratio*j nc.close() return (x, y) def get_axes(self): return self.fig.get_axes() def fast_redraw(self, artist): background = [self.canvas.copy_from_bbox(self.get_axes()[0].bbox)] self.get_axes()[0].draw_artist(artist) self.canvas.restore_region(background) self.canvas.blit(self.get_axes()[0].bbox) self.canvas.update() self.canvas.flush_events()
class AniWindow(QtWidgets.QDialog): ## Class to create animation object that plots real-time voltage vs time def __init__(self, fs, N_samples): super(AniWindow, self).__init__() self.fs = fs self.N_samples = N_samples ## Animation figure self.fig = Figure(figsize=(5, 4), dpi=100) self.canvas = FigureCanvas(self.fig) ## Animate button self.button = QtWidgets.QPushButton('Animate') self.button.clicked.connect(self.animate) ## Set the layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.canvas) layout.addWidget(self.button) self.setLayout(layout) def animate(self): ## Animation figure settings self.ax = self.fig.add_subplot(111) self.line, = self.ax.plot([], [], lw=1) self.ax.grid() self.ax.set_ylim(-0.5, 0.5) self.ax.set_xlim(0, .2) self.ax.set_xlabel('X [m]') self.ax.set_ylabel('Y [m]') self.xdata, self.ydata = [], [] mag = 100 ## Magnify tip displacements self.ax.set_title( 'Real-Time Tip Displacement of Beam, Magnification Factor of ' + str(mag)) def modeShapes(L): ## Generate first mode of a cantilever beam alpha = np.zeros(1) R = np.zeros(1) x = np.arange(0.0, L + 0.01, 0.01) PHI = np.zeros([1, len(x)]) for t in range(len(alpha)): if t == 0: alpha[t] = 0.59686 * np.pi elif t == 1: alpha[t] = 1.49418 * np.pi R[t] = (cos(alpha[t]) + cosh(alpha[t])) / (sin(alpha[t]) + sinh(alpha[t])) PHI[t] = cosh(alpha[t] * x / L) - cos( alpha[t] * x / L) + R[t] * (sin(alpha[t] * x / L) - sinh(alpha[t] * x / L)) return PHI def data_gen(t=0): ## Generate real-time tip displacement run = Measurement( fs=self.fs, active_channels=[0, 1]) ## Instance of measurement class cnt = 0 while cnt < self.N_samples: cnt = cnt + 1 ## Make beam points and mode shape L = 15 / 100 zero_displ_V = 1.9 x = np.arange(0.0, L + .01, 0.01) PHI = modeShapes(L) ## Get real-time tip displacement data_loop(run) ## Adds point to end of vtime and data list tip_displ = (run.data[-1][1] - zero_displ_V ) / 1000 ## CONVERSION: 1mm / V * 1m/1000mm print(x) print(PHI[0] * tip_displ * mag) yield x, PHI[0] * tip_displ * mag ## ~Run animation functioion~ self.anim = animation.FuncAnimation(self.fig, self.animate_loop, data_gen, blit=True, interval=.001, repeat=False, init_func=self.initial) ## Update figure in GUI self.canvas.update() def initial(self): ## Clear data self.line.set_data([], []) return self.line, def animate_loop(self, data): ## Update data x, y = data self.xdata = x self.ydata = y self.line.set_data(self.xdata, self.ydata) return self.line,
class mGraph(QtGui.QWidget): def __init__(self, device, parent=None): QtGui.QWidget.__init__(self, parent) # Create a matplotlib figure. self.figure = plt.figure() self.figure.set_facecolor('r') # Create a QFrame to house the plot. This is not necessary, # just makes it look nice. self.matframe = QtGui.QFrame() self.matLayout = QtGui.QVBoxLayout() self.matLayout.setSpacing(0) self.matframe.setLayout(self.matLayout) self.matframe.setFrameShape(QtGui.QFrame.Panel) self.matframe.setFrameShadow(QtGui.QFrame.Plain) self.matframe.setStyleSheet( "background-color: rgb(70,80,88); " "margin:0px; border:2px solid rgb(0, 0, 0); ") self.canvas = FigureCanvas(self.figure) self.canvas.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) # This is the device we want to use. self.device = device # This sets up axis on which to plot. color = (189. / 255, 195. / 255, 199. / 255) self.ax = self.figure.add_subplot(111, axisbg=color) ax = self.ax # Add the matplotlib canvas to the QFrame. self.matLayout.addWidget(self.canvas) # The following lines set up all the colors, makes it look nice. # The code to do it is far from pretty and I am planning # on cleaning this up a bit. self.figure.patch.set_color((70. / 255, 80. / 255, 88. / 255)) self.figure.patch.set_edgecolor((70. / 255, 80. / 255, 88. / 255)) ax.spines['bottom'].set_color(color) ax.spines['top'].set_color(color) ax.spines['right'].set_color(color) ax.spines['left'].set_color(color) ax.tick_params(axis='x', colors=color) ax.tick_params(axis='y', colors=color) ax.title.set_color(color) ax.yaxis.label.set_color(color) ax.xaxis.label.set_color(color) ax.xaxis.get_offset_text().set_color(color) ax.yaxis.get_offset_text().set_color(color) # This is an array of all the lines on the plot. A line for # every parameter. self.line = [] self.mins = 0 self.maxes = 1 # Each element of line holds a plot, to be combined onto # the same graph. self.line.append(ax.plot(1, 1, label="Getting Data...")[0]) # In order to handle interactivity, I had to do some odd stuff # with the toolbar buttons: self.home holds the original # function called when the home button on the toolbar # is clicked. self.home = NavigationToolbar.home # We now change the function that is called when the toolbar is # clicked. NavigationToolbar.home = self.enableAutoScaling self.toolbar = NavigationToolbar(self.canvas, self) self.cid = self.canvas.mpl_connect('button_press_event', self.disableAutoScaling) self.setStyleSheet("QPushButton{\ color:rgb(189,195, 199); \ background:rgb(70, 80, 88)};") self.fullGraphBtn = QtGui.QPushButton("Show Interactive Graph") self.fullGraphBtn.clicked.connect(self.openFullGraphGui) self.toolbarFrame = QtGui.QFrame() toolbarFrameLayout = QtGui.QVBoxLayout() toolbarFrameLayout.addWidget(self.toolbar) self.toolbar.setParent(None) self.toolbarFrame.setLayout(toolbarFrameLayout) self.toolbarFrame.setStyleSheet("\ border:2px solid rgb(0,0,0);\ color:rgb(189,195,199); \ background:rgb(70, 80, 88);") self.toolbar.setStyleSheet("\ border:0px solid rgb(0,0,0);\ QDialog{background:rgb(70, 80, 88)}") self.matPlotInfo = QtGui.QLabel() self.alertFont = QtGui.QFont() self.alertFont.setPointSize(12) self.matPlotInfo.setStyleSheet("color:rgb(200, 69, 50);") self.matPlotInfo.setText("Auto refresh disabled, " "click HOME button to enable.") self.matPlotInfo.setFont(self.alertFont) #self.refreshRateSec = device.getFrame().getPlotRefreshRate() self.refreshRateSec = device.getFrame().getPlotRefreshRate() self.timer = QtCore.QTimer(self) self.hidden = True self.home = True self.initialized = False self.currTimeRange = 120 self.lineSelect = MCheckableComboBox() self.lineSelect.setSizeAdjustPolicy(0) self.lineSelect.setStyleSheet("\ background-color:rgb(70, 80, 88);\ color:rgb(189,195, 199);") self.plot(self.currTimeRange) self.timer.timeout.connect(partial(self.plot, self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) # Did it store data? self.dataOk = True self.hideButton = QtGui.QPushButton("Show Plot") self.hideButton.clicked.connect(self.togglePlot) self.oneMinButton = QtGui.QPushButton("1 min") self.oneMinButton.clicked.connect(partial(self.plot, 60)) self.tenMinButton = QtGui.QPushButton("10 min") self.tenMinButton.clicked.connect(partial(self.plot, 600)) self.twoHrButton = QtGui.QPushButton("2 hr") self.twoHrButton.clicked.connect(partial(self.plot, 7200)) self.twelveHrButton = QtGui.QPushButton("12 hr") self.twelveHrButton.clicked.connect(partial(self.plot, 43200)) self.threeDayButton = QtGui.QPushButton("3 day") self.threeDayButton.clicked.connect(partial(self.plot, 259200)) self.oneWkButton = QtGui.QPushButton("1 week") self.oneWkButton.clicked.connect(partial(self.plot, 604800)) self.allButton = QtGui.QPushButton("All Time") self.allButton.clicked.connect(partial(self.plot, None)) self.canvas.hide() self.toolbar.hide() # Set the layout. buttonLayout1 = QtGui.QHBoxLayout() buttonLayout1.addWidget(self.hideButton) buttonLayout1.addWidget(self.fullGraphBtn) buttonLayout1.addStretch(0) buttonLayout2 = QtGui.QHBoxLayout() settingsbuttons1 = QtGui.QHBoxLayout() buttonLayout2.addWidget(self.oneMinButton) buttonLayout2.addWidget(self.tenMinButton) buttonLayout2.addWidget(self.twoHrButton) buttonLayout2.addWidget(self.twelveHrButton) buttonLayout2.addWidget(self.threeDayButton) buttonLayout2.addWidget(self.oneWkButton) buttonLayout2.addWidget(self.allButton) buttonLayout2.addStretch(0) self.oneMinButton.hide() self.tenMinButton.hide() self.twoHrButton.hide() self.twelveHrButton.hide() self.threeDayButton.hide() self.oneWkButton.hide() self.allButton.hide() self.lineSelect.hide() self.matframe.hide() self.matPlotInfo.hide() self.toolbarFrame.hide() settingsbuttons1.addWidget(self.lineSelect) layout = QtGui.QVBoxLayout() allButtonsLayout = QtGui.QHBoxLayout() timeButtonsLayout = QtGui.QVBoxLayout() allButtonsLayout.addLayout(timeButtonsLayout) layout.addLayout(allButtonsLayout) allButtonsLayout.addLayout(settingsbuttons1) timeButtonsLayout.addLayout(buttonLayout1) timeButtonsLayout.addLayout(buttonLayout2) timeButtonsLayout.addWidget(self.matPlotInfo) layout.addWidget(self.matframe) layout.addWidget(self.toolbarFrame) self.setLayout(layout) def enableAutoScaling(self): self.timer.start(self.refreshRateSec * 1000) self.home = True self.matPlotInfo.hide() self.plot(self.currTimeRange) def disableAutoScaling(self, event): self.home = False self.matPlotInfo.show() self.canvas.update() self.timer.stop() def togglePlot(self): if not self.hidden: self.canvas.hide() self.toolbar.hide() self.oneMinButton.hide() self.tenMinButton.hide() self.twoHrButton.hide() self.twelveHrButton.hide() self.threeDayButton.hide() self.oneWkButton.hide() self.allButton.hide() self.matPlotInfo.hide() self.matframe.hide() self.lineSelect.hide() self.toolbarFrame.hide() self.timer.stop() self.hideButton.setText("Show Plot") self.hidden = True elif self.hidden: self.canvas.show() self.toolbar.show() self.oneMinButton.show() self.tenMinButton.show() self.twoHrButton.show() self.twelveHrButton.show() self.threeDayButton.show() self.oneWkButton.show() self.allButton.show() self.plot(self.currTimeRange) self.matframe.show() self.lineSelect.show() self.toolbarFrame.show() self.timer.start(self.refreshRateSec * 1000) self.hideButton.setText("Hide Plot") self.enableAutoScaling() self.hidden = False def initializePlot(self, dataSet): if dataSet: varNames = dataSet.getVariables() varNames = [varNames[1][i][0] for i in range(len(varNames[1]))] self.dropdownFont = QtGui.QFont() self.dropdownFont.setPointSize(12) if dataSet is not None: self.initialized = True self.line[0].remove() self.line = [] for i in range(len(varNames)): self.line.append(self.ax.plot(1, 1, label=varNames[i])[0]) text = QtCore.QString(varNames[i]) self.lineSelect.addItem(text) self.lineSelect.setFont(self.dropdownFont) self.lineSelect.setChecked(i, True) def changeIndependenVarRange(self, timeRange): if not self.hidden: if timeRange != self.currTimeRange: self.timer.stop() self.timer.timeout.disconnect() self.currTimeRange = timeRange self.timer.timeout.connect( lambda: self.plot(self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) plotRefreshRate = self.device.getFrame().getPlotRefreshRate() if self.refreshRateSec != plotRefreshRate: self.refreshRateSec = plotRefreshRate self.timer.stop() self.timer.timeout.disconnect() self.currTimeRange = timeRange self.timer.timeout.connect( lambda: self.plot(self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) def getDataRangeFromDataSet(self, dataSet, time): if dataSet: data = dataSet.getData() i = len(data) - 1 if time: while data[i][0] > (data[-1][0] - time): i -= 1 if -1 * i > len(data): return data data = data[i:-1] return data else: return None def openFullGraphGui(self): # print "opening full graph gui." dataSet = self.device.getFrame().getDataSet().getData() # print dataSet times = [dt.datetime.fromtimestamp(elem[0]) for elem in dataSet] vars = self.device.getFrame().getDataSet().getVariables() self.fullgraphcont = fullGraphContainer(times, vars, dataSet) self.fullgraphcont.show() def plot(self, time): times = None self.changeIndependenVarRange(time) dataSet = self.device.getFrame().getDataSet() if not self.initialized: self.initializePlot(dataSet) self.legend = self.ax.legend(loc='upper left') # This is the ONLY time canvas.draw is called. It should # NOT be called anywhere else if the graphing speed is # to be fast. self.canvas.draw() else: data = self.getDataRangeFromDataSet(dataSet, time) for i in range(len(data[0]) - 1): if self.lineSelect.isChecked(i): times = [dt.datetime.fromtimestamp(row[0]) for row in data] column = [row[i + 1] for row in data] if not self.line[i].get_visible(): self.line[i].set_visible(True) self.line[i].set_data(times, column) self.legend = self.ax.legend(loc='upper left') self.ax.grid(True) self.ax.hold(True) else: self.line[i].set_visible(False) pass self.ax.set_title(self.device.getFrame().getTitle(), color=(189. / 255, 195. / 255, 199. / 255)) if self.home and times: self.ax.set_xlim(times[0], times[-1]) self.ax.relim(visible_only=True) self.ax.autoscale(axis='y') frame = self.device.getFrame() yLabel = frame.getYLabel() if yLabel is not None: if frame.getCustomUnits(): self.ax.set_ylabel("%s (%s)" % (yLabel, frame.getCustomUnits())) elif frame.getUnits()[i - 1]: self.ax.set_ylabel("%s (%s)" % (yLabel, frame.getUnits()[i - 1])) locator = AutoDateLocator() self.ax.xaxis.set_major_locator(locator) self.ax.xaxis.set_major_formatter(DateFormatter('%m/%d %H:%M:%S')) self.figure.autofmt_xdate() self.ax.draw_artist(self.figure) self.ax.draw_artist(self.ax.patch) self.ax.draw_artist(self.ax.yaxis) self.ax.draw_artist(self.ax.xaxis) for i, line in enumerate(self.line): self.ax.draw_artist(line) self.ax.set_xlabel("Time") self.ax.draw_artist(self.legend) self.canvas.update() self.canvas.flush_events()
class mGraph(QtGui.QWidget): def __init__(self, device, parent=None): QtGui.QWidget.__init__(self, parent) # Create a matplotlib figure self.figure = plt.figure() self.figure.set_facecolor("r") # Create a QFrame to house the plot. This is not necessary, just makes it look nice self.matframe = QtGui.QFrame() self.matLayout = QtGui.QVBoxLayout() self.matLayout.setSpacing(0) self.matframe.setLayout(self.matLayout) self.matframe.setFrameShape(QtGui.QFrame.Panel) self.matframe.setFrameShadow(QtGui.QFrame.Plain) self.matframe.setStyleSheet("background-color: rgb(70,80,88); margin:0px; border:2px solid rgb(0, 0, 0); ") self.canvas = FigureCanvas(self.figure) self.canvas.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) # This is the device we want to use self.device = device # This sets up axis on which to plot self.ax = self.figure.add_subplot(111, axisbg=(189.0 / 255, 195.0 / 255, 199.0 / 255)) # Add the matplotlib canvas to the QFrame self.matLayout.addWidget(self.canvas) # The following lines set up all the colors, makes it look nice. The code to do it is # far from pretty and I am planning on cleaning this up a bit. self.figure.patch.set_color((70.0 / 255, 80.0 / 255, 88.0 / 255)) self.figure.patch.set_edgecolor((70.0 / 255, 80.0 / 255, 88.0 / 255)) self.ax.spines["bottom"].set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.spines["top"].set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.spines["right"].set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.spines["left"].set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.tick_params(axis="x", colors=(189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.tick_params(axis="y", colors=(189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.title.set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.yaxis.label.set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.xaxis.label.set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.xaxis.get_offset_text().set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) self.ax.yaxis.get_offset_text().set_color((189.0 / 255, 195.0 / 255, 199.0 / 255)) # This is an array of all the lines on the plot. A line for every parameter self.line = [] # Each element of line holds a plot, to be combined onto the same graph self.line.append(self.ax.plot(1, 1, label="Getting Data...")[0]) # This is the ONLY time canvas.draw is called. It should NOT be called anywhere else if # the graphing speed is to be fast. self.canvas.draw() # In order to handle interactivity, I had to do some odd stuff with the # toolbar buttons. Self.home holds the original function called when the home button on the toolbar # is clicked. self.home = NavigationToolbar.home # We now change the function that is called when the toolbar is clicked. NavigationToolbar.home = self.enableAutoScaling self.toolbar = NavigationToolbar(self.canvas, self) # print [item for item in dir(self.toolbar) if type(item) == QtGui.QDialog] self.cid = self.canvas.mpl_connect("button_press_event", self.disableAutoScaling) self.setStyleSheet( "QPushButton{\ color:rgb(189,195, 199); \ background:rgb(70, 80, 88)}" ) self.toolbarFrame = QtGui.QFrame() toolbarFrameLayout = QtGui.QVBoxLayout() toolbarFrameLayout.addWidget(self.toolbar) self.toolbar.setParent(None) self.toolbarFrame.setLayout(toolbarFrameLayout) self.toolbarFrame.setStyleSheet( "\ border:2px solid rgb(0,0,0);\ color:rgb(189,195,199); \ background:rgb(70, 80, 88);\ " ) self.toolbar.setStyleSheet( "\ border:0px solid rgb(0,0,0);\ QDialog{background:rgb(250, 80, 88)}\ " ) # print dir(self.toolbar) # print self.toolbar.children() # print self.toolbar.setPalette self.matPlotInfo = QtGui.QLabel() self.alertFont = QtGui.QFont() self.alertFont.setPointSize(12) self.matPlotInfo.setStyleSheet("color:rgb(200, 69, 50);") self.matPlotInfo.setText("Auto refresh disabled, click HOME button to enable.") self.matPlotInfo.setFont(self.alertFont) self.refreshRateSec = device.getFrame().getPlotRefreshRate() self.timer = QtCore.QTimer(self) self.hidden = True self.home = True self.currTimeRange = 120 self.plot(self.currTimeRange) self.timer.timeout.connect(partial(self.plot, self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) # did it store data? self.dataOk = True self.hideButton = QtGui.QPushButton("Show Plot") self.hideButton.clicked.connect(self.togglePlot) self.thrtysecButton = QtGui.QPushButton("30 Sec") self.thrtysecButton.clicked.connect(partial(self.plot, 30)) self.twoMinButton = QtGui.QPushButton("2 Min") self.twoMinButton.clicked.connect(partial(self.plot, 120)) self.fiveMinButton = QtGui.QPushButton("5 Min") self.fiveMinButton.clicked.connect(partial(self.plot, 300)) self.thrtyMinButton = QtGui.QPushButton("30 Min") self.thrtyMinButton.clicked.connect(partial(self.plot, 1800)) self.twoHrButton = QtGui.QPushButton("2 Hr") self.twoHrButton.clicked.connect(partial(self.plot, 7200)) self.tenHrButton = QtGui.QPushButton("10 Hr") self.tenHrButton.clicked.connect(partial(self.plot, 36000)) self.oneDayButton = QtGui.QPushButton("24 Hr") self.oneDayButton.clicked.connect(partial(self.plot, 86400)) self.oneWkButton = QtGui.QPushButton("1 Wk") self.oneWkButton.clicked.connect(partial(self.plot, 604800)) self.twoWkButton = QtGui.QPushButton("2 Wk") self.twoWkButton.clicked.connect(partial(self.plot, 1209600)) self.allButton = QtGui.QPushButton("All Time") self.allButton.clicked.connect(partial(self.plot, None)) self.canvas.hide() self.toolbar.hide() # set the layout buttonLayout = QtGui.QHBoxLayout() buttonLayout.addWidget(self.hideButton) buttonLayout.addStretch(0) buttonLayout2 = QtGui.QHBoxLayout() buttonLayout3 = QtGui.QHBoxLayout() buttonLayout2.addWidget(self.thrtysecButton) buttonLayout2.addWidget(self.twoMinButton) buttonLayout2.addWidget(self.fiveMinButton) buttonLayout2.addWidget(self.thrtyMinButton) buttonLayout2.addWidget(self.twoHrButton) buttonLayout2.addStretch(0) buttonLayout3.addWidget(self.tenHrButton) buttonLayout3.addWidget(self.oneDayButton) buttonLayout3.addWidget(self.oneWkButton) buttonLayout3.addWidget(self.twoWkButton) buttonLayout3.addWidget(self.allButton) buttonLayout3.addStretch(0) self.thrtysecButton.hide() self.twoMinButton.hide() self.fiveMinButton.hide() self.thrtyMinButton.hide() self.twoHrButton.hide() self.tenHrButton.hide() self.oneDayButton.hide() self.oneWkButton.hide() self.twoWkButton.hide() self.allButton.hide() self.matframe.hide() self.matPlotInfo.hide() self.toolbarFrame.hide() layout = QtGui.QVBoxLayout() layout.addLayout(buttonLayout) layout.addLayout(buttonLayout2) layout.addLayout(buttonLayout3) layout.addWidget(self.matPlotInfo) layout.addWidget(self.matframe) layout.addWidget(self.toolbarFrame) self.setLayout(layout) def enableAutoScaling(self): self.timer.start(self.refreshRateSec * 1000) # self.canvas.mpl_disconnect(self.cid) # self.cid = self.canvas.mpl_connect('button_press_event', self.disableAutoScaling) self.home = True self.matPlotInfo.hide() # self.deviceThread = threading.Thread(target = # self.plot, args=[self.currTimeRange]) # If the main thread stops, stop the child thread # self.deviceThread.daemon = True # Start the thread # self.deviceThread.start() self.plot(self.currTimeRange) def disableAutoScaling(self, event): self.home = False self.matPlotInfo.show() self.canvas.update() # plt.show() # print event.name # self.canvas.mpl_disconnect(self.cid) # self.cid = self.canvas.mpl_connect('button_press_event', self.enableAutoScaling) self.timer.stop() # self.zoom(self.toolbar) def togglePlot(self): if not self.hidden: self.canvas.hide() self.toolbar.hide() self.thrtysecButton.hide() self.twoMinButton.hide() self.fiveMinButton.hide() self.thrtyMinButton.hide() self.twoHrButton.hide() self.tenHrButton.hide() self.oneDayButton.hide() self.oneWkButton.hide() self.twoWkButton.hide() self.allButton.hide() self.matPlotInfo.hide() self.matframe.hide() self.toolbarFrame.hide() self.timer.stop() self.hideButton.setText("Show Plot") self.hidden = True elif self.hidden: self.canvas.show() self.toolbar.show() self.thrtysecButton.show() self.twoMinButton.show() self.fiveMinButton.show() self.thrtyMinButton.show() self.twoHrButton.show() self.tenHrButton.show() self.oneDayButton.show() self.oneWkButton.show() self.twoWkButton.show() self.allButton.show() self.plot(self.currTimeRange) self.matframe.show() self.toolbarFrame.show() self.timer.start(self.refreshRateSec * 1000) self.hideButton.setText("Hide Plot") self.enableAutoScaling() self.hidden = False def plot(self, timeRange): if not self.hidden: if timeRange != self.currTimeRange: self.timer.stop() self.timer.timeout.disconnect() self.currTimeRange = timeRange self.timer.timeout.connect(lambda: self.plot(self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) if self.refreshRateSec != self.device.getFrame().getPlotRefreshRate(): # print "New plot refresh rate: ", self.device.getFrame().getPlotRefreshRate() self.refreshRateSec = self.device.getFrame().getPlotRefreshRate() self.timer.stop() self.timer.timeout.disconnect() self.currTimeRange = timeRange self.timer.timeout.connect(lambda: self.plot(self.currTimeRange)) self.timer.start(self.refreshRateSec * 1000) dataSet = self.device.getFrame().getDataSet() # If the dataset exists if dataSet is not None: # Get all data from the dataset data = dataSet.getData() self.ax.hold(False) try: # for each entry in the dataset [[time], [[data], [data], [data...]]] # print data # Get the corresponding times that the values were recorded for i in range(1, len(data[-1])): # Get colum. aka all values from parameter i over time column = [row[i] for row in data] # print times # If the there is no defined a time range if self.currTimeRange is None: times = [datetime.datetime.fromtimestamp(row[0]) for row in data] # Plot all of the data (columns) vs time # self.ax.plot_date(times, column, label = # dataSet.getVariables()[1][i-1][0]) pass else: # Otherwise, if the user PREVIOUSLY defined a time range, # we need to look for the beginning of it. # Start by getting the current time dstamp = dateStamp() # The dataset should be from now to -timerange # time(now)-time(range) startTime = dstamp.utcNowFloat() - self.currTimeRange # If timeRange is not None, then we know we need # to display only a certain range of values # However, if the starttime defined is less than the lowest time, we # do not have enough data to display the whole thing, so we must # display all that we have instead. We do this by setting # currTimeRange = 0. if timeRange is not None and startTime < float(data[0][0]): self.currTimeRange = None # For all entries in data for y in range(len(data)): # We are searching backwards through the dataset to find a time # just before the time range specified if data[len(data) - y - 1][0] < startTime: # once we find it, we know the beginning index of the data to be # displayed index = y # Get the times and datafrom the index and columns to the end of the dataset times = [datetime.datetime.fromtimestamp(row[0]) for row in data[-index:]] # print times[0] column = [row[i] for row in data[-index:]] # Exit the loop break try: while len(self.line) <= i: self.line.append(self.ax.plot(1, 1, label=dataSet.getVariables()[1][i - 1][0])[0]) self.line[i].set_data(times, column) self.ax.legend(loc="upper left", shadow=True, fancybox=True) # maxi = max(column) # mini = min(column) # newMax = max(column) # newMini = min(column) # if(newMax>maxi) # maxi=newMax # self.ax.set_ylim(mini-mini/2, maxi+maxi/2) # if(newMini<mini) # self.ax.set_ylim(mini-mini/2, maxi+maxi/2) # maxi = max(column) # mini = min(column) # self.ax.set_ylim(mini-mini/2, maxi+maxi/2) # self.ax.set_xlim(min(times), max(times)) # self.ax.draw_artist(self.line[i]) except: traceback.print_exc() # print "Failed to log data" # Add a legend legend = self.ax.legend(loc="upper left") self.ax.set_title( self.device.getFrame().getTitle(), color=(189.0 / 255, 195.0 / 255, 199.0 / 255) ) if ( self.device.getFrame().getYLabel() is not None and len(self.device.getFrame().getCustomUnits()) is not 0 ): self.ax.set_ylabel( self.device.getFrame().getYLabel() + " (" + self.device.getFrame().getCustomUnits() + ")" ) elif ( self.device.getFrame().getYLabel() is not None and len(self.device.getFrame().getUnits()[i - 1]) is not 0 ): self.ax.set_ylabel( self.device.getFrame().getYLabel() + " (" + self.device.getFrame().getUnits()[i - 1] + ")" ) self.ax.set_xlabel("Time") self.ax.hold(True) # locator = AutoDateLocator() # self.ax.fmt_xdata = AutoDateFormatter() # self.ax.xaxis.set_major_locator(locator) # self.ax.xaxis.set_major_locator(locator) # self.ax.xaxis.set_major_formatter(DateFormatter('%m/%d')) # self.ax.fmt_xdata = mdates.DateFormatter('%m/%d %H:%M:%S') # print "type: ", type(times[-1]) # print "time[-1]: ",times[-1] # self.ax.set_ylim(bottom = 733681, top = 733682) # self.figure.tight_layout() self.ax.grid(True) except Exception as e: print "Error" try: self.ax.grid(True) # self.ax.clear(self.ax.yaxis) # self.ax.cla() if self.home: self.ax.set_xlim(times[0], times[-1]) self.ax.relim() self.ax.autoscale() # print self.ax.get_data_interval() self.ax.draw_artist(self.figure) self.ax.draw_artist(self.ax.patch) locator = AutoDateLocator() self.ax.xaxis.set_major_locator(locator) self.ax.xaxis.set_major_formatter(DateFormatter("%m/%d %H:%M:%S")) self.figure.autofmt_xdate() # print [time.toordinal() for time in times] self.ax.draw_artist(self.ax.yaxis) self.ax.draw_artist(self.ax.xaxis) for line in self.line: self.ax.draw_artist(line) # self.ax.axis('off') self.ax.draw_artist(legend) self.canvas.update() self.canvas.flush_events() except: times = [datetime.datetime.fromtimestamp(row[0]) for row in data] traceback.print_exc() self.ax.set_xlim(times[0], times[-1]) self.ax.relim() self.ax.autoscale() # print self.ax.get_data_interval() pass
class TimeWaveform(QDialog): def __init__(self, parent=None): super(TimeWaveform, self).__init__(parent) self.x = None self.y1 = None self.y2 = None self.y3 = None self.y4 = None self.showType = "realtime" self.showTypeBtn = None # added push button self.showTypeBtn = QPushButton(u"realtiime", self) self.showTypeBtn.setFlat(True) self.showTypeBtn.setStyleSheet('QPushButton {font: bold 20px;}') self.showTypeBtn.clicked.connect(self.showTypeBtnClicked) buttonWidget = QWidget(self) layout2 = QHBoxLayout(buttonWidget) layout2.setAlignment(Qt.AlignHCenter) layout2.setContentsMargins(0, 0, 0, 0) layout2.setSpacing(10) layout2.addWidget(self.showTypeBtn) layout = QVBoxLayout() layout.addWidget(buttonWidget) self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.Dialog) self.setWindowTitle(u"tool ") self.mainLayout = QHBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.splitter = QSplitter(self) self.splitterLayout = QHBoxLayout(self.splitter) self.treeView = QTreeView(self) self.model = QStandardItemModel(self) self.treeView.setModel(self.model) self.treeView.setHeaderHidden(True) custom = ["yk001", "yk002", "yk003"] for cm in custom: custom = QStandardItem(cm) custom.setToolTip(cm) fnames = database.getTableName(cm) print "fnames == ", fnames for f in fnames: ff = QStandardItem(f) ff.setToolTip(f) custom.appendRow(ff) ff.setData({'custom_name': cm, 'datetime_data': f}, Qt.UserRole) self.model.appendRow(custom) self.treeView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.splitterLayout.addWidget(self.treeView) self.treeView.header().setResizeMode(QHeaderView.ResizeToContents) self.frame = QWidget(self) self.frameLayout = QVBoxLayout(self.frame) self.splitterLayout.addWidget(self.frame) self.mainLayout.addWidget(self.splitter) self.splitter.setSizes([20, 400]) self.figure = Figure(figsize=(400, 400), dpi=72, facecolor=('none'), edgecolor=('none'), frameon=False) self.figure.subplots_adjust(hspace=0.2) self.ax = self.figure.add_subplot(412) self.ax2 = self.figure.add_subplot(413, sharex=self.ax, sharey=self.ax) self.ax3 = self.figure.add_subplot(414, sharex=self.ax, sharey=self.ax) self.ax4 = self.figure.add_subplot(411, sharex=self.ax) self.canvas = FigureCanvas(self.figure) self.treeView.doubleClicked.connect(self.showChart) self.toolBar = NavigationToolbar(self.canvas, self) self.frameLayout.addWidget(self.toolBar) self.frameLayout.addWidget(buttonWidget) self.frameLayout.addWidget(self.canvas) # load multi thread self.loadRealTimeThread = LoadRealTimeThread(waveform=self, parent=self) self.loadRealTimeThread.finished.connect(self.onFinished) self.loadBrakeAmplitudeThread = LoadBrakeAmplitudeThread(waveform=self, parent=self) self.loadBrakeAmplitudeThread.finished.connect(self.onFinished) def onFinished(self): self.ax.clear() self.ax2.clear() self.ax3.clear() self.ax4.clear() self.plots() self.canvas.draw() def showChart(self, s): self.showType = "realtime" self.showTypeBtn.setText(u"rl") data_tree = s.data(Qt.UserRole) if not data_tree: return sharemem.Set('data_tree', data_tree) self.loadRealTimeThread.start() self.showLoading() def plots(self): self.ax.plot(self.x, self.y1, label='max_c1', linestyle='solid', color='orange', linewidth=0.5) self.ax.set_ylabel(u"Amp") self.ax.set_ylim(np.min([self.y1.min(), self.y2.min(), self.y3.min()]) - 1, np.max([self.y1.max(), self.y2.max(), self.y3.max()]) + 3) self.ax.legend() self.ax2.plot(self.x, self.y2, label='max_c2', linestyle='solid', color='green', linewidth=0.5) self.ax2.set_ylabel(u"Amp") self.ax2.legend() self.ax3.plot(self.x, self.y3, label='max_c3', linestyle='solid', color='red', linewidth=0.5) self.ax3.set_xlabel(u"Time") self.ax3.set_ylabel(u"Amp") self.ax3.legend() self.ax4.plot(self.x, self.y4, label='speed', linestyle='solid', color='blue', linewidth=0.5) self.ax4.set_title((str(self.x[0]))[:-3] + "~" + (str(self.x[-1]))[:-3]) self.ax4.set_ylabel(u"Speed") self.ax4.legend() def onClicked(self): if self.showType == "realtime": self.loadRealTimeThread.start() self.showLoading() elif self.showType == "brake": self.loadBrakeAmplitudeThread.start() self.showLoading() def showTypeBtnClicked(self): if self.showType == "realtime": self.showType = "brake" self.showTypeBtn.setText(u"br") self.onClicked() elif self.showType == "brake": self.showType = "realtime" self.showTypeBtn.setText(u"rl") self.onClicked() def showLoading(self): self.ax.clear() self.ax2.clear() self.ax3.clear() self.ax4.clear() self.ax4.set_title("Loading...") self.canvas.update()
class Window(QMainWindow, Ui_MainWindow): def __init__(self, parent = None): QMainWindow.__init__(self, parent) self.setupUi(self) #defines thread get_temp self.get_temp = Get_Temp() #defines thread get_data self.get_data = Get_Data() #defines timer self.timer = QtCore.QTimer(self) #signal to start threads self.connect(self.get_temp, SIGNAL("display_temp()"),self.display_temp,Qt.DirectConnection) self.connect(self.get_data, SIGNAL("plot()"),self.plot,Qt.DirectConnection) #defines a graph and plots it in vertical layout self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.verticalLayout.addWidget(self.canvas) #starts get_temp thread self.get_temp.start() #starts timer self.timer.timeout.connect(self.Time) #HLT timer button signal self.HTL_Start.clicked.connect(self.Set) #defines and starts timer2 self.timer2 = QtCore.QTimer(self) self.timer2.timeout.connect(self.Time2) #Boil timer button signal self.BOIL_TIMER_START_2.clicked.connect(self.Set2) #defines and starts timer3 self.timer3 = QtCore.QTimer(self) self.timer3.timeout.connect(self.Time3) #signals for graph timmer buttons self.START_TIMER.clicked.connect(self.Start) self.STOP_TIMER.clicked.connect(lambda: self.timer3.stop()) self.RESET_TIMER.clicked.connect(self.Reset) self.ALARM_RESET.clicked.connect(self.Alarm_Reset) #dictionaries for alarm values global alarm1,alarm2 alarm1 = {self.HLT_alarm_set1:self.ALARM_HLT_1,self.HLT_alarm_set1_2:self.ALARM_HLT_2,self.HLT_alarm_set1_3:self.ALARM_HLT_3,self.HLT_alarm_set1_4:self.ALARM_HLT_4,self.HLT_alarm_set1_5:self.ALARM_HLT_5} alarm2 = {self.Boil_alarm_set1:self.ALARM_BOIL_1,self.Boil_alarm_set1_2:self.ALARM_BOIL_2,self.Boil_alarm_set1_3:self.ALARM_BOIL_3,self.Boil_alarm_set1_4:self.ALARM_BOIL_4,self.Boil_alarm_set1_5:self.ALARM_BOIL_5} #signals for file dropdown buttons self.actionQuit.triggered.connect(self.close_application) self.actionSave.triggered.connect(self.save_application) self.actionLoad.triggered.connect(self.load_application) self.actionNew.triggered.connect(self.reset_data) #closes the application def close_application(self): print("window close") sys.exit() #gets data from form and saves it to a file def save_application(self): self.save_data() text2 = [] name = QtGui.QFileDialog.getSaveFileName() file = open(name,'w') for i in self.form_field: file.write(i + "\n") file.close() file = "" self.form_field = [] print ("saved") #Gets data from a file and send it to get_data def load_application(self): self.reset_data() temp=[] name = QtGui.QFileDialog.getOpenFileName() file = open(name,'r') for i in file: temp1 = i[:-1] temp.append(temp1) file.close() file = "" self.load_data(temp) print ("loaded") #Gets data from Receipe form def save_data(self): self.form_field = [self.Brewer_name_txt.text(), self.Brew_Date_txt.text(), self.Batch_size_txt.text(), self.boil_time_txt.text(), self.Ingredient_one.text(), self.Amount_one.text(), self.Ingredient_three.text(), self.Amount_three.text(), self.Ingredient_two.text(), self.Amount_two.text(), self.Ingredient_four.text(), self.Alcohol_volume_txt.text(), self.Amount_four.text(), self.Ingredient_five.text(), self.Amount_five.text(), self.Hop_one.text(), self.hop_amount_one.text(), self.hop_AA_one.text(), self.hop_boil_one.text(), self.hop_amount_two.text(), self.hop_boil_two.text(), self.hop_AA_two.text(), self.hop_two.text(), self.hop_amount_three.text(), self.hop_boil_three.text(), self.hop_AA_three.text(), self.hop_3.text(), self.hop_amount_four.text(), self.hop_boil_four.text(), self.hop_AA_four.text(), self.hop_4.text(), self.hop_amount_five.text(), self.hop_boil_five.text(), self.hop_AA_five.text(), self.hop_five.text(), self.original_gravity_txt.text(), self.final_gravity_txt.text(), self.IBU_txt.text(), self.SRM_txt.text(), self.Brewhouse_efficiency_txt.text(), self.Carbonation_level_txt.text(), self.hydrometer_preboil_date_txt.text(), self.hydrometer_afterboil_date_txt.text(), self.hydrometer_racked_date_txt.text(), self.hydrometer_final_date_txt.text(), self.hydrometer_preboil_gravity_txt.text(), self.hydrometer_racked_gravity_txt.text(), self.hydrometer_final_gravity_txt.text(), self.hydrometer_afterboil_gravity_txt.text(), self.Recipe_name_txt.text(), self.beer_type_txt.text(), self.Batch_txt.text(), self.efficiency_txt.text(), self.infusion_one_txt.text(), self.infusion_temp_one_txt.text(), self.infusion_three_txt.text(), self.infusion_temp_three_txt.text(), self.infusion_two_txt.text(), self.infusion_temp_two_txt.text(), self.infusion_four_txt.text(), self.infusion_temp_four_txt.text(), self.infusion_five_txt.text(), self.infusion_temp_five_txt.text(), self.cost_grains_txt.text(), self.cost_grains_txt_2.text(), self.cost_yeast_txt.text(), self.cost_other_txt.text(), self.infusion_time_one_txt.text(), self.infusion_time_four_txt.text(), self.infusion_time_five_txt.text(), self.infusion_time_two_txt.text(), self.infusion_time_three_txt.text(), self.yeat_starter_txt.text(), self.yeast_attenuation_txt.text(), self.yeast_type_txt.text(), self.cost_total_txt.text(), self.Notes.toPlainText()] #fills the recipe form with data from a file def load_data(self,x): self.Brewer_name_txt.setText(x[0]) self.Brew_Date_txt.setText(x[1]) self.Batch_size_txt.setText(x[2]) self.boil_time_txt.setText(x[3]) self.Ingredient_one.setText(x[4]) self.Amount_one.setText(x[5]) self.Ingredient_three.setText(x[6]) self.Amount_three.setText(x[7]) self.Ingredient_two.setText(x[8]) self.Amount_two.setText(x[9]) self.Ingredient_four.setText(x[10]) self.Alcohol_volume_txt.setText(x[11]) self.Amount_four.setText(x[12]) self.Ingredient_five.setText(x[13]) self.Amount_five.setText(x[14]) self.Hop_one.setText(x[15]) self.hop_amount_one.setText(x[16]) self.hop_AA_one.setText(x[17]) self.hop_boil_one.setText(x[18]) self.hop_amount_two.setText(x[19]) self.hop_boil_two.setText(x[20]) self.hop_AA_two.setText(x[21]) self.hop_two.setText(x[22]) self.hop_amount_three.setText(x[23]) self.hop_boil_three.setText(x[24]) self.hop_AA_three.setText(x[25]) self.hop_3.setText(x[26]) self.hop_amount_four.setText(x[27]) self.hop_boil_four.setText(x[28]) self.hop_AA_four.setText(x[29]) self.hop_4.setText(x[30]) self.hop_amount_five.setText(x[31]) self.hop_boil_five.setText(x[32]) self.hop_AA_five.setText(x[33]) self.hop_five.setText(x[34]) self.original_gravity_txt.setText(x[35]) self.final_gravity_txt.setText(x[36]) self.IBU_txt.setText(x[37]) self.SRM_txt.setText(x[38]) self.Brewhouse_efficiency_txt.setText(x[39]) self.Carbonation_level_txt.setText(x[40]) self.hydrometer_preboil_date_txt.setText(x[41]) self.hydrometer_afterboil_date_txt.setText(x[42]) self.hydrometer_racked_date_txt.setText(x[43]) self.hydrometer_final_date_txt.setText(x[44]) self.hydrometer_preboil_gravity_txt.setText(x[45]) self.hydrometer_racked_gravity_txt.setText(x[46]) self.hydrometer_final_gravity_txt.setText(x[47]) self.hydrometer_afterboil_gravity_txt.setText(x[48]) self.Recipe_name_txt.setText(x[49]) self.beer_type_txt.setText(x[50]) self.Batch_txt.setText(x[51]) self.efficiency_txt.setText(x[52]) self.infusion_one_txt.setText(x[53]) self.infusion_temp_one_txt.setText(x[54]) self.infusion_three_txt.setText(x[55]) self.infusion_temp_three_txt.setText(x[56]) self.infusion_two_txt.setText(x[57]) self.infusion_temp_two_txt.setText(x[58]) self.infusion_four_txt.setText(x[59]) self.infusion_temp_four_txt.setText(x[60]) self.infusion_five_txt.setText(x[61]) self.infusion_temp_five_txt.setText(x[62]) self.cost_grains_txt.setText(x[63]) self.cost_grains_txt_2.setText(x[64]) self.cost_yeast_txt.setText(x[65]) self.cost_other_txt.setText(x[66]) self.infusion_time_one_txt.setText(x[67]) self.infusion_time_four_txt.setText(x[68]) self.infusion_time_five_txt.setText(x[69]) self.infusion_time_two_txt.setText(x[70]) self.infusion_time_three_txt.setText(x[71]) self.yeat_starter_txt.setText(x[72]) self.yeast_attenuation_txt.setText(x[73]) self.yeast_type_txt.setText(x[74]) self.cost_total_txt.setText(x[75]) for i in range(76,len(x),1): temp = x[i] temp = temp[:-1] self.Notes.append(temp) #fills recipe form with blank spaces def reset_data(self): x=" " self.Brewer_name_txt.setText(x) self.Brew_Date_txt.setText(x) self.Batch_size_txt.setText(x) self.boil_time_txt.setText(x) self.Ingredient_one.setText(x) self.Amount_one.setText(x) self.Ingredient_three.setText(x) self.Amount_three.setText(x) self.Ingredient_two.setText(x) self.Amount_two.setText(x) self.Ingredient_four.setText(x) self.Alcohol_volume_txt.setText(x) self.Amount_four.setText(x) self.Ingredient_five.setText(x) self.Amount_five.setText(x) self.Hop_one.setText(x) self.hop_amount_one.setText(x) self.hop_AA_one.setText(x) self.hop_boil_one.setText(x) self.hop_amount_two.setText(x) self.hop_boil_two.setText(x) self.hop_AA_two.setText(x) self.hop_two.setText(x) self.hop_amount_three.setText(x) self.hop_boil_three.setText(x) self.hop_AA_three.setText(x) self.hop_3.setText(x) self.hop_amount_four.setText(x) self.hop_boil_four.setText(x) self.hop_AA_four.setText(x) self.hop_4.setText(x) self.hop_amount_five.setText(x) self.hop_boil_five.setText(x) self.hop_AA_five.setText(x) self.hop_five.setText(x) self.original_gravity_txt.setText(x) self.final_gravity_txt.setText(x) self.IBU_txt.setText(x) self.SRM_txt.setText(x) self.Brewhouse_efficiency_txt.setText(x) self.Carbonation_level_txt.setText(x) self.hydrometer_preboil_date_txt.setText(x) self.hydrometer_afterboil_date_txt.setText(x) self.hydrometer_racked_date_txt.setText(x) self.hydrometer_final_date_txt.setText(x) self.hydrometer_preboil_gravity_txt.setText(x) self.hydrometer_racked_gravity_txt.setText(x) self.hydrometer_final_gravity_txt.setText(x) self.hydrometer_afterboil_gravity_txt.setText(x) self.Recipe_name_txt.setText(x) self.beer_type_txt.setText(x) self.Batch_txt.setText(x) self.efficiency_txt.setText(x) self.infusion_one_txt.setText(x) self.infusion_temp_one_txt.setText(x) self.infusion_three_txt.setText(x) self.infusion_temp_three_txt.setText(x) self.infusion_two_txt.setText(x) self.infusion_temp_two_txt.setText(x) self.infusion_four_txt.setText(x) self.infusion_temp_four_txt.setText(x) self.infusion_five_txt.setText(x) self.infusion_temp_five_txt.setText(x) self.cost_grains_txt.setText(x) self.cost_grains_txt_2.setText(x) self.cost_yeast_txt.setText(x) self.cost_other_txt.setText(x) self.infusion_time_one_txt.setText(x) self.infusion_time_four_txt.setText(x) self.infusion_time_five_txt.setText(x) self.infusion_time_two_txt.setText(x) self.infusion_time_three_txt.setText(x) self.yeat_starter_txt.setText(x) self.yeast_attenuation_txt.setText(x) self.yeast_type_txt.setText(x) self.cost_total_txt.setText(x) self.Notes.setText(x) #resets the alarm and sets gpio 18 to low def Alarm_Reset(self): os.system('sh -c "echo low > /sys/class/gpio/gpio18/direction"') #Resets timmer for graph def Reset(self): global s3,m3,h3 self.timer3.stop() s3=0 m3=0 h3=0 self.get_data.start() time = "{0}:{1}:{2}".format(h3,m3,s3) self.TIMER_DISPLAY.setDigitCount(len(time)) self.TIMER_DISPLAY.display(time) #starts timer for graph def Start(self): global s3,m3,h3 self.timer3.start(1000) #Timer for graph and displays time (counts up) def Time3(self): global s3,m3,h3 if s3 == 0: self.get_data.start() if s3 == 30: self.get_data.start() if s3<59: s3 += 1 else: if m3 < 59: s3 = 0 m3 += 1 elif m3 == 59 and h3 < 24: h3 += 1 m3 = 0 s3= 0 else: self.timer3.stop() time = "{0}:{1}:{2}".format(h3,m3,s3) self.TIMER_DISPLAY.setDigitCount(len(time)) self.TIMER_DISPLAY.display(time) #Sets HLT timer def Set(self): global t,h,m,s t = self.HLT_TIMER_SET.time() self.HLT_Timer_DISPLAY.display(t.toString()) self.timer.start(1000) h = t.hour() m = t.minute() s = t.second() #Timer for HLT timer(counts the timer down) def Time(self): global t,h,m,s,time1 if s > 0: s -= 1 else: if m > 0: m -= 1 s = 59 elif m == 0 and h > 0: h -= 1 m = 59 s = 59 else: self.timer.stop() time1 = ("{0}:{1}:{2}".format(h,m,s)) self.Alarm() self.HLT_Timer_DISPLAY.setDigitCount(len(time1)) self.HLT_Timer_DISPLAY.display(time1) #Sets boil timer def Set2(self): global t2,h2,m2,s2 t2 = self.BOIL_TIMER_SET.time() self.BOIL_TIMER_DISPLAY.display(t2.toString()) self.timer2.start(1000) h2 = t2.hour() m2 = t2.minute() s2 = t2.second() #timer for boil timer(counts the timer down) def Time2(self): global t2,h2,m2,s2,time2 if s2 > 0: s2 -= 1 else: if m2 > 0: m2 -= 1 s2 = 59 elif m2 == 0 and h2 > 0: h2 -= 1 m2 = 59 s2 = 59 else: self.timer2.stop() time2 = ("{0}:{1}:{2}".format(h2,m2,s2)) self.Alarm() self.BOIL_TIMER_DISPLAY.setDigitCount(len(time2)) self.BOIL_TIMER_DISPLAY.display(time2) #checks to see if alarm has been triggered and sets gpio 18 to high def Alarm(self): global alarm1,alarm2,time1,time2 for x, y in alarm1.iteritems(): if x.isChecked(): a = y.time() h = a.hour() m = a.minute() s = a.second() time4 = ("{0}:{1}:{2}".format(h,m,s)) if time4 == time1: print "ALARM 1 ACTIVE" os.system('sh -c "echo low > /sys/class/gpio/gpio18/direction"') for x, y in alarm2.iteritems(): if x.isChecked(): a = y.time() h = a.hour() m = a.minute() s = a.second() time4 = ("{0}:{1}:{2}".format(h,m,s)) if time4 == time2: print "ALARM 2 ACTIVE" os.system('sh -c "echo high > /sys/class/gpio/gpio18/direction"') #displays temps by calling settemp from temprature.py def display_temp(self): temp = sent_temp() self.HLT_TEMP.display(temp[0]) self.MASH_TEMP.display(temp[1]) self.Boil_TEMP.display(temp[2]) #creates a graph and displays it def plot(self): temp = sent_temp() temp1.append(temp[0]) temp2.append(temp[1]) temp3.append(temp[2]) M1.append(m3) XHLT= self.figure.add_subplot(111) XHLT.plot(M1,temp1,'b-',label = "HLT") XHLT.plot(M1,temp2,'r-',label = "MASH") XHLT.plot(M1,temp3,'g-',label = "BOIL") self.canvas.draw() self.canvas.update() if m3 == 0 and h3 == 0 and s3 == 0: XHLT.hold(False)
def update(self): self.fig.tight_layout() FigureCanvas.update(self)
class Window(QtWidgets.QDialog): ## Class to create animation object that plots real-time voltage vs time def __init__(self, channel, fs, N_samples): super(Window, self).__init__() self.channel = channel self.fs = fs self.N_samples = N_samples ## Animation figure self.fig = Figure(figsize=(5, 4), dpi=100) self.canvas = FigureCanvas(self.fig) ## Animate button self.button = QtWidgets.QPushButton('Animate') self.button.clicked.connect(self.animate) ## Set the layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.canvas) layout.addWidget(self.button) self.setLayout(layout) def animate(self): ## Animation figure settings self.ax = self.fig.add_subplot(111) self.line, = self.ax.plot([], [], lw=1) self.ax.grid() self.ax.set_ylim(-5, 5) self.ax.set_xlim(0, 10) self.ax.set_xlabel('Time [sec]') self.ax.set_ylabel('Voltage Out [V]') self.ax.set_title('Channel ' + str(self.channel)) self.xdata, self.ydata = [], [] def data_gen(t=0): ## Generate real-time time and voltage for each frame run = Measurement( fs=self.fs, active_channels=[0, 1]) ## Instance of measurement class cnt = 0 while cnt < self.N_samples: cnt = cnt + 1 data_loop(run) ## Adds point to end of vtime and data list yield run.time[-1], run.data[-1][self.channel] ## ~Run animation functioion~ self.anim = animation.FuncAnimation(self.fig, self.animate_loop, data_gen, blit=True, interval=.001, repeat=False, init_func=self.initial) ## Update figure in GUI self.canvas.update() def initial(self): ## Clear data self.line.set_data([], []) return self.line, def animate_loop(self, data): ## Update data t, y = data self.xdata.append(t) self.ydata.append(y) xmin, xmax = self.ax.get_xlim() ymin, ymax = self.ax.get_ylim() ## Adjust plot boundaries accordingly if t >= xmax: self.ax.set_xlim(xmin, 2 * xmax) self.ax.figure.canvas.draw() if y >= ymax: self.ax.set_ylim(ymin, 2 * ymax) self.ax.figure.canvas.draw() if ymin < 0: ## Make sure ymin limit is negative if this is used if y <= ymin: self.ax.set_ylim(2 * ymin, ymax) self.ax.figure.canvas.draw() self.line.set_data(self.xdata, self.ydata) return self.line,
class InteractiveVelocityPlot(VelocityPlot): """ Visual tool to help with fitting Voigt profiles to absorption lines in QSO spectra. """ def __init__(self, filename, transitions, wavelength, flux, error, continuum, redshift, **kwargs): # Main window: self.window = QMainWindow() # Host widget for plot, push button, and checkboxes: self.main_frame = QWidget() # Spectrum filename: self.filename = filename # Plotting options: self.options = kwargs # Optimise screen usage: if len(transitions) > 20: ncols = int(ceil(len(transitions) / 10)) else: ncols = int(ceil(len(transitions) / 5)) # Initialise plot: super(InteractiveVelocityPlot, self).__init__( transitions, ncols=ncols, aspect=0.45, **self.options['WINDOW']) # Attach canvas to host widget: self.canvas = FigureCanvasQTAgg(self) self.canvas.setParent(self.main_frame) # Text input/output: self.text_output = QTextEdit() # Push buttons: self.load_button = QPushButton('&Load') self.save_button = QPushButton('&Save') self.preview_button = QPushButton('&Preview') self.clear_button = QPushButton('&Clear') self.refresh_plot_button = QPushButton('&Refresh plot') self.plot_model_button = QPushButton('&Plot model') self.plot_all_models_button = QPushButton('&Plot all models') self.clear_models_button = QPushButton('&Clear models') self.runvpfit_button = QPushButton('&Run VPFIT') self.set_resolution = QPushButton('&Set resolution') self.help = QPushButton('&Help') self.quit = QPushButton('&Quit') # Checkboxes: self.cos_fuv_checkbox = QCheckBox('&use COS FUV LSF') self.cos_nuv_checkbox = QCheckBox('&use COS NUV LSF') self.include_checkbox = QCheckBox('&include previous') # Push button `clicked` connections: self.load_button.clicked.connect(self.on_load) self.save_button.clicked.connect(self.on_save) self.preview_button.clicked.connect(self.on_preview) self.clear_button.clicked.connect(self.on_clear) self.refresh_plot_button.clicked.connect(self.on_refresh) self.plot_model_button.clicked.connect(self.on_plot_model) self.plot_all_models_button.clicked.connect(self.on_plot_all_models) self.clear_models_button.clicked.connect(self.on_clear_models) self.runvpfit_button.clicked.connect(self.on_runvpfit) self.set_resolution.clicked.connect(self.on_resolution) self.help.clicked.connect(self.on_help) self.quit.clicked.connect(self.window.close) # Checkbox `stateChanged` connections: self.cos_fuv_checkbox.stateChanged.connect(self.on_cos_fuv_checkbox) self.cos_nuv_checkbox.stateChanged.connect(self.on_cos_nuv_checkbox) self.include_checkbox.stateChanged.connect(self.on_include_checkbox) # Set up grid layout: grid = QGridLayout() grid.setSpacing(10) # Add widgets: grid.addWidget(self.text_output, 1, 1, 4, 3) grid.addWidget(self.load_button, 1, 4) grid.addWidget(self.save_button, 2, 4) grid.addWidget(self.preview_button, 3, 4) grid.addWidget(self.clear_button, 4, 4) grid.addWidget(self.refresh_plot_button, 1, 5) grid.addWidget(self.plot_model_button, 2, 5) grid.addWidget(self.plot_all_models_button, 3, 5) grid.addWidget(self.clear_models_button, 4, 5) grid.addWidget(self.runvpfit_button, 1, 6) grid.addWidget(self.cos_fuv_checkbox, 2, 6) grid.addWidget(self.cos_nuv_checkbox, 3, 6) grid.addWidget(self.include_checkbox, 4, 6) grid.addWidget(self.set_resolution, 1, 7) grid.addWidget(self.help, 3, 7) grid.addWidget(self.quit, 4, 7) # Place plotting canvas above the options grid: vbox = QVBoxLayout() vbox.addWidget(self.canvas) vbox.addLayout(grid) # Set the layout to the host widget: self.main_frame.setLayout(vbox) # Store all static elements (can be very slow to re-draw these): self.canvas.draw() self.backgrounds = [self.canvas.copy_from_bbox(ax.bbox) for ax in self.axes] # Plot the data: self.plot_data(wavelength, flux, error, continuum, redshift, **self.options['DATA']) # Set the window title: self.window.setWindowTitle('vpguess z = {0:.3f}'.format(self.redshift)) # Give keyboard focus to the figure: self.canvas.setFocusPolicy(Qt.StrongFocus) self.canvas.setFocus() # Variable defaults: self.cos_fuv = False self.cos_nuv = False self.include = False self.last_loaded = None self.resolution = None # Keypress variables: self.previous_keypress = None self.previous_wavelength = None # Set up the key-press events: self.canvas.mpl_connect('key_press_event', self.on_keypress) # Set the main frame as the central widget: self.window.setCentralWidget(self.main_frame) # Resize the window so it will display the canvas with the # requested size: layout_height = vbox.sizeHint().height() layout_width = vbox.sizeHint().width() status_bar_height = self.window.statusBar().sizeHint().height() height = layout_height + status_bar_height self.window.resize(layout_width, height) # Re-do labels: del self.texts[:] self.text(0.45, 0.02, 'Velocity offset (km s$^{-1}$)') self.text(0.01, 0.57, 'Transmission', rotation=90) # Disable any existing callbacks: self.cids = dict() cids1 = list(self.canvas.callbacks.callbacks['key_press_event']) cids2 = list(self.canvas.callbacks.callbacks['button_press_event']) cids = cids1 + cids2 for cid in cids: self.canvas.callbacks.disconnect(cid) # Connect new callbacks: self.connect() def update_plot(self, redshift): # Restore background regions: [self.canvas.restore_region(background) for background in self.backgrounds] # Plot data: [data.pop(0).remove() for data in self.data] self.plot_data( self.wavelength, self.flux, self.error, self.continuum, redshift, **self.options['DATA']) # Draw the artists: for artists in self.data: for element in artists: ax = element.get_axes() ax.draw_artist(element) # Plot the models (if any): if self.options['MODEL']['absorbers'] is not None: self.plot_models(resolution=self.resolution, convolve_with_cos_fuv=self.cos_fuv, convolve_with_cos_nuv=self.cos_nuv, **self.options['MODEL']) # Draw the artists: for artists in self.models: for element in artists: ax = element.get_axes() ax.draw_artist(element) # Draw new panel labels: for i, transition in enumerate(self.transitions): ax = self.axes[self._ind[i]] transf = blended_transform_factory(ax.transAxes, ax.transData) name = transition.name # Use TeX fonts if specified: if self.usetex: name = name.split() if name[0][1].islower(): name = name[0][:2] + '$\;$\\textsc{' + \ name[0][2:].lower() + '} $\lambda$' + name[1] else: name = name[0][:1] + '$\;$\\textsc{' + \ name[0][1:].lower() + '} $\lambda$' + name[1] label = ax.text(0.03, 0.5, name, fontsize=self.label_fontsize, bbox=bbox, transform=transf) ax.draw_artist(label) # Update: self.canvas.update() self.window.setWindowTitle( 'vpguess z = {0:.3f}'.format(self.redshift)) @staticmethod def concatenate_results(): from glob import glob results = glob('*.result') with open('.all_results', 'wb') as combined: for result in results: with open(result, 'rb') as single: combined.write(single.read()) @pyqtSlot(str) def on_output(self, output): self.text_output.moveCursor(QTextCursor.End) self.text_output.insertPlainText(output) def on_load(self): self.text_output.clear() directory = os.getcwd() filename = QFileDialog.getOpenFileName( self.window, 'Select f26 file', directory) with open(filename, 'rb') as f26: self.text_output.setText(f26.read()) self.last_loaded = filename def on_save(self): directory = os.getcwd() filename, ok = QFileDialog.getSaveFileName( self.window, 'Save f26 file', directory) with open(filename, 'w') as f26: f26.write(str(self.text_output.toPlainText())) self.text_output.clear() self.last_loaded = None def on_preview(self): self.concatenate_results() with open('.f26_preview', 'wb') as preview: with open('.all_results', 'rb') as results: preview.write(str(self.text_output.toPlainText())) preview.write(results.read()) f26 = read_f26('.f26_preview') self.options['MODEL']['absorbers'] = f26.absorbers self.update_plot(self.redshift) def on_clear(self): self.text_output.clear() self.last_loaded = None def on_refresh(self): self.update_plot(self.redshift) def on_plot_model(self): directory = os.getcwd() filename = QFileDialog.getOpenFileName( self.window, 'Select f26 file', directory) f26 = read_f26(filename) self.options['MODEL']['absorbers'] = f26.absorbers if f26.absorbers is not None: self.update_plot(self.redshift) def on_plot_all_models(self): self.concatenate_results() f26 = read_f26('.all_results') self.options['MODEL']['absorbers'] = f26.absorbers if f26.absorbers is not None: self.update_plot(self.redshift) def on_clear_models(self): self.options['MODEL']['absorbers'] = None self.update_plot(self.redshift) def on_runvpfit(self): from .vpfit import run_vpfit directory = os.getcwd() if self.last_loaded is not None: filename = self.last_loaded if self.text_output.document().isModified(): with open(filename, 'w') as f26: f26.write(str(self.text_output.toPlainText())) else: filename = QFileDialog.getSaveFileName( self.window, 'Save f26 file', directory) with open(filename, 'w') as f26: f26.write(str(self.text_output.toPlainText())) self.concatenate_results() inc = '.all_results' if self.include else None self.text_output.clear() fwhm = self.resolution if self.resolution is not None else 10 run_vpfit(filename, inc, fwhm=fwhm, cos_fuv=self.cos_fuv, cos_nuv=self.cos_nuv) self.concatenate_results() f26 = read_f26('.all_results') self.options['MODEL']['absorbers'] = f26.absorbers if f26.absorbers is not None: self.update_plot(self.redshift) self.last_loaded = None def on_cos_fuv_checkbox(self, state): if state == Qt.Checked: self.cos_fuv = True else: self.cos_fuv = False def on_cos_nuv_checkbox(self, state): if state == Qt.Checked: self.cos_nuv = True else: self.cos_nuv = False def on_include_checkbox(self, state): if state == Qt.Checked: self.include = True else: self.include = False def on_resolution(self): resolution, ok = SpectralResolutionDialog.get_spectral_resolution( self.main_frame) if ok: self.resolution = resolution def on_help(self): QMessageBox.information(self.main_frame, 'Help', info, False) def on_buttonpress(self, event): if event.inaxes is None: return i = self.axes.index(event.inaxes) transition = self.transitions[np.where(self._ind == i)[0]] z = (1 + event.xdata / c_kms) * (1 + self.redshift) - 1 wavelength = transition.wavelength.value * (1 + z) isort = np.argsort(self.ticks['wavelength']) wavelengths = self.ticks['wavelength'][isort] transitions = self.ticks['transition'][isort] idx = wavelengths.searchsorted(wavelength) wavelength = wavelengths[idx] transition = atom.get_transition(transitions[idx]) z = wavelength / transition.wavelength.value - 1 message = '{0}, z = {1:.3f}'.format(transition.name, z) QMessageBox.information(self.main_frame, 'Transition', message, False) def on_keypress(self, event): if event.key == ' ' and event.inaxes is not None: z = self.redshift # Get amount to add to redshift: dz = (event.xdata / c_kms) * (1 + z) # Get new axis limits, if any: vmin, vmax = event.inaxes.get_xlim() self.vmin = min(0, vmin) self.vmax = max(0, vmax) self.update_plot(z + dz) if event.key == 'z': redshift, ok = QInputDialog.getText( self.main_frame, 'New Redshift', 'Enter redshift: ', False) if ok: self.update_plot(float(redshift)) if event.key == 'b': i = self.axes.index(event.inaxes) transition = self.transitions[np.where(self._ind == i)[0]] z = (1 + event.xdata / c_kms) * (1 + self.redshift) - 1 wavelength = transition.wavelength.value * (1 + z) if (self.previous_keypress == 'b' and self.previous_wavelength is not None): wmin = self.previous_wavelength wmax = wavelength if wmin > wmax: wmin, wmax = wmax, wmin print('%% {0} 1 {1:.3f} {2:.3f} vfwhm=10.0'.format( self.filename, wmin, wmax)) self.previous_keypress = None self.previous_wavelength = None else: self.previous_wavelength = wavelength if event.key == 'l': from ..calculations.absorption import logn_from_tau_peak i = self.axes.index(event.inaxes) transition = self.transitions[np.where(self._ind == i)[0]] z = (1 + event.xdata / c_kms) * (1 + self.redshift) - 1 wavelength = transition.wavelength.value * (1 + z) index = self.wavelength.searchsorted(wavelength) flux = self.flux[index - 1:index + 1] error = self.error[index - 1:index + 1] continuum = self.continuum[index - 1:index + 1] flux_norm = flux / continuum error_norm = error / continuum valid = (error_norm > 0) & ~np.isnan(flux_norm) if not any(valid): print('No good pixels!') return flux_norm = np.median(flux_norm[valid]) error_norm = np.median(error_norm[valid]) if flux_norm < error_norm: flux_norm = error_norm elif flux_norm > 1 - error_norm: flux_norm = 1 - error_norm b = 20 # assume 20 km/s tau = -np.log(flux_norm) logn = logn_from_tau_peak(transition, tau, b) print('{0:6s} {1:8.6f} 0.0 {2:4.1f} 0.0 {3:4.1f} 0.0'.format( transition.parent, z, b, logn)) if event.key == 'S': filename, ok = QInputDialog.getText( self.main_frame, 'Save Figure', 'Enter filename: ', False) if ok: self.savefig(filename) self.previous_keypress = event.key def connect(self): cids = dict() cids['key_press_event'] = self.canvas.mpl_connect( 'key_press_event', self.on_keypress) cids['button_press_event'] = self.canvas.mpl_connect( 'button_press_event', self.on_buttonpress) self.cids.update(cids)