class MplCanvas(FigureCanvasQTAgg, customthreads.StoppableThread): def __init__(self, parent=None, width=5, height=4, channel=1, dpi=100, *args, **kwargs): customthreads.StoppableThread.__init__(self, *args, **kwargs) self.in_queue = queue.Queue() self.fig = Figure(figsize=(width, height), dpi=dpi) FigureCanvasQTAgg.__init__(self, self.fig) FigureCanvasQTAgg.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) FigureCanvasQTAgg.updateGeometry(self) self.axes_list = [] self.ylim = None self.setParent(parent) self.set_channel(channel) # self.axes = self.fig.add_subplot(111) # self.axes.hold(False) def set_channel(self, channel): self.channel = channel '''clear subplots''' if(self.axes_list is not []): for ax in self.axes_list: self.fig.delaxes(ax) self.axes_list = [] for i in range(1, self.channel+1): self.axes_list.append(self.fig.add_subplot(self.channel, 1, i)) for ax in self.axes_list: ax.hold(False) def set_lim(self, dtype): self.typeinfo = numpy.iinfo(dtype) self.ylim = [self.typeinfo.min, self.typeinfo.max] def split_channel(self, data): return numpy.transpose(numpy.reshape(data, (len(data)/self.channel, self.channel))) def run(self): '''Thread Loop''' while(self.is_stopped() is False): try: data = self.in_queue.get_nowait() split_data = self.split_channel(data) for i in range(self.channel): # print(split_data[i], len(split_data[i])) self.axes_list[i].plot(range(len(split_data[i])), split_data[i], 'b') self.axes_list[i].set_ylim(self.ylim) self.draw() except queue.Empty: '''do nothing''' pass
class QTwostageModelWindow(QTclPopupWindow): def __init__(self, parent, title, twostage_inp, is_modal=False): self.dresult = "NONE" self.durvar = self.getvar(twostage_inp.duration) self.cNTvar = self.getvar(twostage_inp.cNT) self.caggvar = self.getvar(twostage_inp.cagg) self.rNTvar = self.getvar(twostage_inp.rNT) self.raggvar = self.getvar(twostage_inp.ragg) super().__init__(parent, title, is_modal) def loaded(self): pass def make_gui(self, title): self.setwintitle(title) row = 0 setfr = self.make_label_frame(lrow=row, caption='Enter data for core and rim', padx=(5, 2), pady=(5, 5)) irow = 0 self.makelabel(setfr, lrow=irow, lcol=1, caption='core', sticky=tk.EW) self.makelabel(setfr, lrow=irow, lcol=2, caption='rim', sticky=tk.EW) irow += 1 self.cNT, self.rNT = self.make_double_entrypair(setfr, lrow=irow, e1row=irow, e2row=irow, caption='[NT]: ', var1=self.cNTvar, var2=self.rNTvar, padx=(5, 5), pady=(5, 2)) self.makelabel(setfr, lrow=irow, lcol=3, caption='(ppm)', sticky=tk.W) irow += 1 self.cNT, self.rNT = self.make_double_entrypair(setfr, lrow=irow, e1row=irow, e2row=irow, caption='[NB]/[NT]: ', var1=self.caggvar, var2=self.raggvar, padx=(5, 5), pady=(2, 2)) self.makelabel(setfr, lrow=irow, lcol=3, caption='(-)', sticky=tk.W) irow += 1 self.make_double_entry(setfr, lrow=irow, erow=irow, caption='Total duration: ', textvariable=self.durvar, padx=(2, 2), pady=(2, 5)) self.makelabel(setfr, lrow=irow, lcol=2, caption='(Ma)', sticky=tk.W) irow += 1 self.makebutton(setfr, erow=irow, ecol=1, cmd=self.calc_model, caption='Calculate') self.savebutton = self.makebutton(setfr, erow=irow, ecol=2, cmd=self.save_to_file, caption='Save results to file') self.savebutton.config(state=tk.DISABLED) plotfr = self.make_label_frame(lrow=row, lcol=2, caption='Model', pady=(5, 5)) self.fig = Figure(dpi=100) jrow = 0 self.canv = self.make_mplcanvas(plotfr, fig=self.fig, erow=jrow) jrow += 1 toolbar_fr = self.make_frame(plotfr, erow=jrow) self.toolbar = NavigationToolbar2Tk(self.canv, toolbar_fr) row += 1 self.add_std_buttons(row=row, dismisscol=0) def calc_model(self): for ax in self.fig.get_axes(): self.fig.delaxes(ax) self.durations, self.temps1, self.temps2 = ts.model( self.durvar.get(), self.cNTvar.get(), self.caggvar.get(), self.rNTvar.get(), self.raggvar.get()) sp = self.fig.add_subplot(111) sp.plot(self.durations, self.temps1, 'r.', label='core') sp.plot(self.durations, self.temps2, 'b.', label='rim') sp.set(ylim=(1000, 1500), xlim=(0, float(self.durvar.get())), xlabel='Duration of first anneal (Ma)', ylabel='Temperature ($\mathregular{^{\circ}}$C)') sp.legend(loc='best') self.canv.draw() self.savebutton.config(state=tk.NORMAL) def save_to_file(self): fname = fd.asksaveasfilename(title='Save results to...', initialdir=QSettings.userhome, defaultextension='.csv') if fname != '': data = np.column_stack((self.durations, self.temps1, self.temps2)) header = 'two-stage model with {} Ma; core: NT {} agg {}; rim: NT {} ragg {}\nduration of first anneal, T_core, T_rim'.format( self.durvar.get(), self.cNTvar.get(), self.caggvar.get(), self.rNTvar.get(), self.raggvar.get()) np.savetxt(fname, data, delimiter=',', header=header) else: raise NameError('No file created, results not saved.')
class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.musics = None self.t_end = 0 self.dat_idx = None self.selected_clusters = None self.mainLayout = QtGui.QHBoxLayout() self.open_folder_button = QtGui.QPushButton('open folder') self.open_folder_button.setFixedWidth(100) self.connect(self.open_folder_button, QtCore.SIGNAL('clicked()'), self.open_folder) self.statusBar().showMessage('Welcome') self.num_of_clusters = QtGui.QLineEdit() self.num_of_clusters.setFixedWidth(20) self.num_of_clusters.setText('12') self.num_of_clusters.setAlignment(QtCore.Qt.AlignLeft) self.mode_select = QtGui.QButtonGroup() lyrics = QtGui.QRadioButton('only lyrics') chords = QtGui.QRadioButton('only chords') both = QtGui.QRadioButton('both') both.setChecked(True) self.mode_select.addButton(lyrics, 0) self.mode_select.addButton(chords, 1) self.mode_select.addButton(both, 2) self.start_button = QtGui.QPushButton('start') self.start_button.setFixedWidth(100) self.connect(self.start_button, QtCore.SIGNAL('clicked()'), self.main) self.cluster_select = QtGui.QComboBox() self.cluster_select.setEditable(False) self.cluster_select.activated[str].connect(self.select_cluster) font = QtGui.QFont() font.setPointSize(12) self.results = QtGui.QTreeView() self.results.header().setFont(font) self.stdItemModel = QtGui.QStandardItemModel(0, 3) self.stdItemModel.setHeaderData(0, QtCore.Qt.Horizontal, 'Title') self.stdItemModel.setHeaderData(1, QtCore.Qt.Horizontal, 'Artist') self.stdItemModel.setHeaderData(2, QtCore.Qt.Horizontal, 'Original Key') self.results.setModel(self.stdItemModel) self.results.clicked.connect(self.plot_a_score) self.draw_frame = QtGui.QWidget() self.dpi = 100 self.fig = Figure((5.0, 5.0), dpi=self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.draw_frame) self.axes = self.fig.add_axes([0.1, 0.1, 0.8, 0.8]) self.mpl_toolbar = NavigationToolbar(self.canvas, self.draw_frame) leftLayout = QtGui.QVBoxLayout() label1 = QtGui.QLabel('properties') label1.setAlignment(QtCore.Qt.AlignTop) properties = QtGui.QHBoxLayout() pl = QtGui.QVBoxLayout() op = QtGui.QHBoxLayout() op.addWidget(self.open_folder_button) self.label2 = QtGui.QLabel('opened folder:') op.addWidget(self.label2) pl.addLayout(op) cl = QtGui.QHBoxLayout() label3 = QtGui.QLabel('number of clusters:') cl.addWidget(label3) cl.addWidget(self.num_of_clusters) cl.addStretch(1) pl.addLayout(cl) pr = QtGui.QVBoxLayout() pr.addWidget(lyrics) pr.addWidget(chords) pr.addWidget(both) properties.addLayout(pl) properties.addLayout(pr) label4 = QtGui.QLabel('results') leftLayout.addWidget(label1) leftLayout.addLayout(properties) leftLayout.addWidget(self.start_button) leftLayout.addWidget(label4) leftLayout.addWidget(self.cluster_select) leftLayout.addWidget(self.results) self.mainLayout.addLayout(leftLayout) rightLayout = QtGui.QVBoxLayout() rightLayout.addWidget(self.canvas) rightLayout.addWidget(self.mpl_toolbar) self.mainLayout.addLayout(rightLayout) self.main_widget = QtGui.QWidget() self.main_widget.setLayout(self.mainLayout) self.setCentralWidget(self.main_widget) self.setWindowTitle('Main App') self.setMinimumSize(1200, 700) self.files = None # ファイルをロードするためのメソッド def open_folder(self): fname = QtGui.QFileDialog.getExistingDirectory(self, 'Open Directory', os.path.expanduser('~' + '/research/Musics')) files = glob.glob(str(fname) + '/*') self.fname = fname self.files = files musics = load_data(files) self.musics = musics self.label2.setText('opened folder: ' + fname) self.statusBar().showMessage('opened ' + fname + ' successfully') # 多次元尺度構成法 (MDS) によるプロットを行うメソッド def plot_mds(self, labels, data): leds = [ 'cluster ' + str(i) for i in xrange(self.k) ] pt = ['o', '+', 'x', '4'] mds = manifold.MDS(n_components=2, dissimilarity='euclidean') y = mds.fit_transform(data) self.fig.delaxes(self.fig.axes[0]) self.axes = self.fig.add_axes([0.1, 0.1, 0.8, 0.8]) for i in xrange(self.k): dat = y[np.where(labels==i)] self.axes.plot(dat[:, 0], dat[:, 1], pt[i/6], label=leds[i]) self.axes.set_xlim(np.min(y[:, 0]) - 0.5, np.max(y[:, 0]) + 1.5) self.axes.set_ylim(np.min(y[:, 1]) - 0.5, np.max(y[:, 1]) + 1.5) self.axes.set_title('MDS Scatter Plots') self.axes.legend(loc='upper right', fontsize='x-small') self.canvas.draw() # 感情スコアをプロットするメソッド @QtCore.pyqtSlot(QtCore.QModelIndex) def plot_a_score(self, index): checked = self.mode_select.checkedId() if checked == 1: return props = [ 'ecstasy', 'admiration', 'terror', 'amazement', 'grief', 'loathing', 'rage', 'vigilance', ] self.fig.delaxes(self.fig.axes[0]) self.axes = self.fig.add_axes([0.1, 0.05, 0.8, 0.8], polar=True) cols = [ 'yellow', 'lime', 'darkgreen', 'cyan', 'blue', 'magenta', 'red', 'orange', ] theta = np.pi/2 - np.arange(0.0, 2*np.pi, 2*np.pi/8) - np.pi/16 score = self.clusters[self.selected_cluster][index.row()].score width = np.pi/8 * np.ones(8) bars = self.axes.bar(theta, score, width=width, bottom=0.0) idx = 0 for r, bar in zip(score, bars): bar.set_facecolor(cols[idx]) idx += 1 t = np.arange(0, 2*np.pi, 2*np.pi/8) self.axes.set_xticks(t, []) self.axes.set_xticklabels([]) self.axes.set_yticks(np.linspace(0, 1.0, 11)) yticklabels = ['0.0', '', '', '', '', '0.5', '', '', '', '', '1.0'] self.axes.set_yticklabels(yticklabels) self.axes.set_ylim(0, 1.0) for i in xrange(8): ang_rad = np.pi/2 -i / 8.0 * 2 * np.pi ang_deg = -i / 8.0 * 360 ha = 'right' if ang_rad < np.pi/2 or ang_rad > 3*np.pi/2: ha = 'left' self.axes.text(ang_rad, 1.1, props[i], size=20, rotation=ang_deg, horizontalalignment='center', verticalalignment='center' ) self.canvas.draw() # 分類結果として確認するクラスタを変更するメソッド def select_cluster(self): font = QtGui.QFont() self.stdItemModel = QtGui.QStandardItemModel(0, 3) self.stdItemModel.setHeaderData(0, QtCore.Qt.Horizontal, 'Title') self.stdItemModel.setHeaderData(1, QtCore.Qt.Horizontal, 'Artist') self.stdItemModel.setHeaderData(2, QtCore.Qt.Horizontal, 'Original Key') self.results.setModel(self.stdItemModel) self.dat_idx = 0 selected = int(str(self.cluster_select.currentText()).split()[1]) self.selected_cluster = selected font = QtGui.QFont() font.setPointSize(12) for music in self.clusters[selected]: title = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.title)) title.setFont(font) artist = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.artist)) artist.setFont(font) org = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.keys[0])) org.setFont(font) self.stdItemModel.setItem(self.dat_idx, 0, title) self.stdItemModel.setItem(self.dat_idx, 1, artist) self.stdItemModel.setItem(self.dat_idx, 2, org) self.dat_idx += 1 self.results.resizeColumnToContents(0) self.results.resizeColumnToContents(1) self.results.resizeColumnToContents(2) # メインメソッド def main(self): if self.musics is None: qm = QtGui.QMessageBox.critical(self, 'ExectionError', 'No directory is selected!', QtGui.QMessageBox.Ok) return try: k = int(self.num_of_clusters.text()) except ValueError: qm = QtGui.QMessageBox.critical(self, 'ValueError', 'Invalid type for number of clusters!', QtGui.QMessageBox.Ok) return if k <= 0: qm = QtGui.QMessageBox.critical(self, 'ValueError', 'Number of clusters must be a positive integer!', QtGui.QMessageBox.Ok) return self.stdItemModel.clear() self.stdItemModel = QtGui.QStandardItemModel(0, 3) self.stdItemModel.setHeaderData(0, QtCore.Qt.Horizontal, 'Title') self.stdItemModel.setHeaderData(1, QtCore.Qt.Horizontal, 'Artist') self.stdItemModel.setHeaderData(2, QtCore.Qt.Horizontal, 'Original Key') self.results.setModel(self.stdItemModel) self.k = k self.cluster_select.clear() for i in xrange(k): self.cluster_select.addItem('cluster ' + str(i)) self.selected_cluster = 0 checked = self.mode_select.checkedId() labels = None data = None if checked == 0: labels, data = clustering_by_lyrics(self.musics, k) elif checked == 1: labels, data = clustering_by_chords(self.musics, k) elif checked == 2: labels, data = clustering_by_chords_and_lyrics(self.musics, k) self.statusBar().showMessage('Finish') self.plot_mds(labels, data) self.dat_idx = 0 clusters = { i:[] for i in xrange(k) } for idx, label in enumerate(labels): clusters[label].append(self.musics[idx]) self.clusters = clusters font = QtGui.QFont() font.setPointSize(12) for music in clusters[0]: title = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.title)) title.setFont(font) artist = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.artist)) artist.setFont(font) org = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.keys[0])) org.setFont(font) self.stdItemModel.setItem(self.dat_idx, 0, title) self.stdItemModel.setItem(self.dat_idx, 1, artist) self.stdItemModel.setItem(self.dat_idx, 2, org) self.dat_idx += 1 self.results.resizeColumnToContents(0) self.results.resizeColumnToContents(1) self.results.resizeColumnToContents(2)
class DensityPanel(FigureCanvasWxAgg): def __init__(self, parent, **kwargs): self.figure = Figure() FigureCanvasWxAgg.__init__(self, parent, -1, self.figure, **kwargs) self.canvas = self.figure.canvas self.SetMinSize((100,100)) self.figure.set_facecolor((1,1,1)) self.figure.set_edgecolor((1,1,1)) self.canvas.SetBackgroundColour('white') self.subplot = self.figure.add_subplot(111) self.gate_helper = GatingHelper(self.subplot, self) self.navtoolbar = None self.point_list = [] self.gridsize = 50 self.cb = None self.x_scale = LINEAR_SCALE self.y_scale = LINEAR_SCALE self.color_scale = None self.x_label = '' self.y_label = '' self.cmap ='jet' self.canvas.mpl_connect('button_release_event', self.on_release) def setpointslists(self, points): self.subplot.clear() self.point_list = points plot_pts = np.array(points).astype(float) if self.x_scale == LOG_SCALE: plot_pts = plot_pts[(plot_pts[:,0]>0)] if self.y_scale == LOG_SCALE: plot_pts = plot_pts[(plot_pts[:,1]>0)] hb = self.subplot.hexbin(plot_pts[:, 0], plot_pts[:, 1], gridsize=self.gridsize, xscale=self.x_scale, yscale=self.y_scale, bins=self.color_scale, cmap=matplotlib.cm.get_cmap(self.cmap)) if self.cb: # Remove the existing colorbar and reclaim the space so when we add # a colorbar to the new hexbin subplot, it doesn't get indented. self.figure.delaxes(self.figure.axes[1]) self.figure.subplots_adjust(right=0.90) self.cb = self.figure.colorbar(hb) if self.color_scale==LOG_SCALE: self.cb.set_label('log10(N)') self.subplot.set_xlabel(self.x_label) self.subplot.set_ylabel(self.y_label) xmin = np.nanmin(plot_pts[:,0]) xmax = np.nanmax(plot_pts[:,0]) ymin = np.nanmin(plot_pts[:,1]) ymax = np.nanmax(plot_pts[:,1]) # Pad all sides if self.x_scale==LOG_SCALE: xmin = xmin/1.5 xmax = xmax*1.5 else: xmin = xmin-(xmax-xmin)/20. xmax = xmax+(xmax-xmin)/20. if self.y_scale==LOG_SCALE: ymin = ymin/1.5 ymax = ymax*1.5 else: ymin = ymin-(ymax-ymin)/20. ymax = ymax+(ymax-ymin)/20. self.subplot.axis([xmin, xmax, ymin, ymax]) self.reset_toolbar() def getpointslists(self): return self.point_list def setgridsize(self, gridsize): self.gridsize = gridsize def set_x_scale(self, scale): self.x_scale = scale def set_y_scale(self, scale): self.y_scale = scale def set_color_scale(self, scale): if scale==LINEAR_SCALE: scale = None self.color_scale = scale def set_x_label(self, label): self.x_label = label def set_y_label(self, label): self.y_label = label def set_colormap(self, cmap): self.cmap = cmap self.draw() def get_toolbar(self): if not self.navtoolbar: self.navtoolbar = NavigationToolbar(self.canvas) return self.navtoolbar def reset_toolbar(self): # Cheat since there is no way reset if self.navtoolbar: self.navtoolbar._views.clear() self.navtoolbar._positions.clear() self.navtoolbar.push_current() def set_configpanel(self,configpanel): '''Allow access of the control panel from the plotting panel''' self.configpanel = configpanel def on_release(self, evt): if evt.button == 3: # right click self.show_popup_menu((evt.x, self.canvas.GetSize()[1]-evt.y), None) def show_popup_menu(self, (x,y), data): self.popup_menu_filters = {} popup = wx.Menu() loadimages_table_item = popup.Append(-1, 'Create gated table for CellProfiler LoadImages') selected_gate = self.configpanel.gate_choice.get_gatename_or_none() selected_gates = [] if selected_gate: selected_gates = [selected_gate] self.Bind(wx.EVT_MENU, lambda(e):ui.prompt_user_to_create_loadimages_table(self, selected_gates), loadimages_table_item) show_images_in_gate_item = popup.Append(-1, 'Show images in gate') show_images_in_gate_item.Enable(selected_gate is not None) self.Bind(wx.EVT_MENU, self.show_images_from_gate, show_images_in_gate_item) if p.object_table: show_objects_in_gate_item = popup.Append(-1, 'Show %s in gate'%(p.object_name[1])) show_objects_in_gate_item.Enable(selected_gate is not None) self.Bind(wx.EVT_MENU, self.show_objects_from_gate, show_objects_in_gate_item) self.PopupMenu(popup, (x,y))
class GraphPanel(wx.Panel): """Graph panel draws the runtime graph""" def __init__(self,parent): wx.Panel.__init__(self,parent) self.SetBackgroundColour('#FFFFFF') self.SetSizeWH(500,600) self.initGraph() wx.EVT_PAINT(self, self.OnPaint) self.redraw_bars = False self.brother = None def drawSpans(self,FirstLoad=False): """ draws interval spans""" global lastTrialDuration global newWaitDuration startAt = self.trial-0.5 h= 1.0 if self.trial==1: startAt=0 h=1.5 drawX = 0.0 del graphStartTimes[:] for i in X.intervalList: graphStartTimes.append(drawX) color = uv.iColors[i.type] if isinstance(i, Intervals.ToneInt): color = uv.freq2color(i.freq) self.axes.bar(drawX, h, color=color,zorder=0,lw=0.0, width=i.duration, bottom=startAt,) else: self.axes.bar(drawX, h, color=color,zorder=0,lw=0.0, width=i.duration, bottom=startAt,) drawX+=i.duration #raj-changed the value from i.maxDuration to i.duration to make the graph change dynamically based on lever press def initGraph(self): """ initalize graph to draw spans """ self.trial = 1 self.sbs = {} self.sbs['Lever'] = ScatterBrain('Lever','#3399FF','o') self.sbs['Mark'] = ScatterBrain('Mark','#000000','x') for i in range(0,5): name = 'aTaste%d'%i self.sbs[name] = ScatterBrain(name,uv.TasteColors[i],'s') name2 = 'mTaste%d'%i self.sbs[name2] = ScatterBrain(name2,uv.TasteColors[i],'s',False) self.figure = Figure(dpi=100,figsize=(5,5.5)) self.axes = self.figure.add_subplot(111) print 'X.trial', X.trialDuration self.axes.axis([0,X.trialDuration,0,1.5]) self.axes.set_xlabel('time (s)') self.drawSpans(True) LText = FontProperties() LText.set_size("small") self.axes.legend((self.sbs['Lever'].getPlot(self.axes),self.sbs['Mark'].getPlot(self.axes), self.sbs['aTaste1'].getPlot(self.axes),self.sbs['mTaste1'].getPlot(self.axes)), ("Lever Press","Time Marked", "Reward","Manual Reward"), prop=LText, fancybox=True, bbox_to_anchor=(0., 1.02, 1., .102), loc=1, ncol=2, mode="expand", borderaxespad=0) self.canvas = FigureCanvas(self, -1, self.figure) def clearGraph(self): """ clear graph""" self.figure.delaxes(self.axes) self.initGraph() self.Refresh() def addPoint(self,i,t,pcat): """ add point to a scatter plot Args: i (int): index of intervals t (float): time to point to pcat (int): which scatter plot to add point to """ ti = t if i!=-1: ti+= graphStartTimes[i] if pcat<8: self.sbs['aTaste%d'%pcat].addPoint(ti,self.trial) elif pcat<16: self.sbs['mTaste%d'%(pcat-8)].addPoint(ti,self.trial) elif pcat==30: self.sbs['Lever'].addPoint(ti,self.trial) elif pcat==31: self.sbs['Mark'].addPoint(ti,self.trial) def shiftPoints(self, offset): """ Move points """ lvlen = len(self.sbs['Lever'].x) r = range(0,lvlen) r.reverse() for i in r: if self.sbs['Lever'].y[i]==self.trial: self.sbs['Lever'].x[i]-= offset else: break def newTrial(self): """ prepare graph for new trial""" self.trial+=1 self.axes.set_ylim(top=(self.trial+0.5)) self.redraw_bars = True def OnPaint(self, event): """ Redraw """ """ if self.redraw_bars: self.redraw_bars = False self.drawSpans() for k,v in self.sbs.items(): v.getPlot(self.axes) del v.x[:] del v.y[:] self.canvas.draw() """ d = DrawThread(self) d.start() event.Skip() def OnSetFocus(self, event): self.color = 'yellow' self.Refresh() def OnKillFocus(self, event): self.color = '#b3b3b3' self.Refresh() def saveGraph(self,filename="graph.png"): """Save graph as file""" self.figure.savefig(filename)
class PyAbel: #(tk.Tk): def __init__(self, parent): self.parent = parent self.initialize() def initialize(self): self.fn = None self.old_fn = None self.old_method = None self.old_fi = None self.AIM = None self.rmx = (368, 393) # matplotlib figure self.f = Figure(figsize=(2, 6)) self.gs = gridspec.GridSpec(2, 2, width_ratios=[1, 2]) self.gs.update(wspace=0.2, hspace=0.2) self.plt = [] self.plt.append(self.f.add_subplot(self.gs[0])) self.plt.append(self.f.add_subplot(self.gs[1])) self.plt.append( self.f.add_subplot(self.gs[2], sharex=self.plt[0], sharey=self.plt[0])) self.plt.append(self.f.add_subplot(self.gs[3])) for i in [0, 2]: self.plt[i].set_adjustable('box-forced') # hide until have data for i in range(4): self.plt[i].axis("off") # tkinter # set default font size for buttons self.font = tkFont.Font(size=11) self.fontB = tkFont.Font(size=12, weight='bold') #frames top (buttons), text, matplotlib (canvas) self.main_container = tk.Frame(self.parent, height=10, width=100) self.main_container.pack(side="top", fill="both", expand=True) self.button_frame = tk.Frame(self.main_container) #self.info_frame = tk.Frame(self.main_container) self.matplotlib_frame = tk.Frame(self.main_container) self.button_frame.pack(side="top", fill="x", expand=True) #self.info_frame.pack(side="top", fill="x", expand=True) self.matplotlib_frame.pack(side="top", fill="both", expand=True) self._menus() self._button_area() self._plot_canvas() self._text_info_box() def _button_frame(self): self.button_frame = tk.Frame(self.main_container) self.button_frame.pack(side="top", fill="x", expand=True) self._menus() def _menus(self): # menus with callback ---------------- # duplicates the button interface self.menubar = tk.Menu(self.parent) self.transform_method = tk.IntVar() self.center_method = tk.IntVar() # File - menu self.filemenu = tk.Menu(self.menubar, tearoff=0) self.filemenu.add_command(label="Load image file", command=self._loadimage) self.filemenu.add_separator() self.filemenu.add_command(label="Exit", command=self._quit) self.menubar.add_cascade(label="File", menu=self.filemenu) # Process - menu self.processmenu = tk.Menu(self.menubar, tearoff=0) #self.processmenu.add_command(label="Center image", command=self._center) self.subcent = tk.Menu(self.processmenu) for cent in center_methods: self.subcent.add_radiobutton(label=cent, var=self.center_method, val=center_methods.index(cent), command=self._center) self.processmenu.add_cascade(label="Center image", menu=self.subcent, underline=0) self.submenu = tk.Menu(self.processmenu) for method in Abel_methods: self.submenu.add_radiobutton(label=method, var=self.transform_method, val=Abel_methods.index(method), command=self._transform) self.processmenu.add_cascade(label="Inverse Abel transform", menu=self.submenu, underline=0) self.processmenu.add_command(label="Speed distribution", command=self._speed) self.processmenu.add_command(label="Angular distribution", command=self._anisotropy) self.angmenu = tk.Menu(self.processmenu) self.menubar.add_cascade(label="Processing", menu=self.processmenu) # view - menu self.viewmenu = tk.Menu(self.menubar, tearoff=0) self.viewmenu.add_command(label="Raw image", command=self._display) self.viewmenu.add_command(label="Inverse Abel transformed image", command=self._transform) self.viewmenu.add_command(label="view buttons", command=self._on_buttons) self.menubar.add_cascade(label="View", menu=self.viewmenu) def _button_area(self): # grid layout # make expandable for col in range(5): self.button_frame.columnconfigure(col, weight=1) self.button_frame.rowconfigure(col, weight=1) # column 0 --------- # load image file button self.load = tk.Button(master=self.button_frame, text="load image", font=self.fontB, fg="dark blue", command=self._loadimage) self.load.grid(row=0, column=0, sticky=tk.W, padx=(5, 10), pady=(5, 0)) self.sample_image = ttk.Combobox(master=self.button_frame, font=self.font, values=[ "from file", "from transform", "sample dribinski", "sample Ominus" ], width=14, height=4) self.sample_image.current(0) self.sample_image.grid(row=1, column=0, padx=(5, 10)) # quit self.quit = tk.Button(master=self.button_frame, text="Quit", font=self.fontB, fg="dark red", command=self._quit) self.quit.grid(row=3, column=0, sticky=tk.W, padx=(5, 10), pady=(0, 5)) # column 1 ----------- # center image self.center = tk.Button(master=self.button_frame, text="center image", anchor=tk.W, font=self.fontB, fg="dark blue", command=self._center) self.center.grid(row=0, column=1, padx=(0, 20), pady=(5, 0)) self.center_method = ttk.Combobox(master=self.button_frame, font=self.font, values=center_methods, width=11, height=4) self.center_method.current(1) self.center_method.grid(row=1, column=1, padx=(0, 20)) # column 2 ----------- # Abel transform image self.recond = tk.Button(master=self.button_frame, text="Abel transform image", font=self.fontB, fg="dark blue", command=self._transform) self.recond.grid(row=0, column=2, padx=(0, 10), pady=(5, 0)) self.transform = ttk.Combobox(master=self.button_frame, values=Abel_methods, font=self.font, width=10, height=len(Abel_methods)) self.transform.current(2) self.transform.grid(row=1, column=2, padx=(0, 20)) self.direction = ttk.Combobox(master=self.button_frame, values=["inverse", "forward"], font=self.font, width=8, height=2) self.direction.current(0) self.direction.grid(row=2, column=2, padx=(0, 20)) # column 3 ----------- # speed button self.speed = tk.Button(master=self.button_frame, text="speed", font=self.fontB, fg="dark blue", command=self._speed) self.speed.grid(row=0, column=5, padx=20, pady=(5, 0)) self.speedclr = tk.Button(master=self.button_frame, text="clear plot", font=self.font, command=self._speed_clr) self.speedclr.grid(row=1, column=5, padx=20) # column 4 ----------- # anisotropy button self.aniso = tk.Button(master=self.button_frame, text="anisotropy", font=self.fontB, fg="dark blue", command=self._anisotropy) self.aniso.grid(row=0, column=6, pady=(5, 0)) self.subframe = tk.Frame(self.button_frame) self.subframe.grid(row=1, column=6) self.rmin = tk.Entry(master=self.subframe, text='rmin', width=3, font=self.font) self.rmin.grid(row=0, column=0) self.rmin.delete(0, tk.END) self.rmin.insert(0, self.rmx[0]) self.lbl = tk.Label(master=self.subframe, text="to", font=self.font) self.lbl.grid(row=0, column=1) self.rmax = tk.Entry(master=self.subframe, text='rmax', width=3, font=self.font) self.rmax.grid(row=0, column=2) self.rmax.delete(0, tk.END) self.rmax.insert(0, self.rmx[1]) # turn off button interface self.hide_buttons = tk.Button(master=self.button_frame, text="hide buttons", font=self.fontB, fg='grey', command=self._hide_buttons) self.hide_buttons.grid(row=3, column=6, sticky=tk.E, pady=(0, 20)) def _text_info_box(self): # text info box --------------------- self.text = ScrolledText(master=self.button_frame, height=6, fg="mediumblue", bd=1, relief=tk.SUNKEN) self.text.insert( tk.END, "Work in progress, some features may" " be incomplete ...\n") self.text.insert( tk.END, "To start: load an image data file using" " e.g. data/O2-ANU1024.txt.bz2\n" " (1) load image button (or file menu)\n" " (2) center image\n" " (3) Abel transform\n" " (4) speed\n" " (5) anisotropy\n" " (6) Abel transform <- change\n" " (:) repeat\n") self.text.grid(row=3, column=1, columnspan=3, padx=5) def _plot_canvas(self): # matplotlib canvas -------------------------- self.canvas = FigureCanvasTkAgg(self.f, master=self.matplotlib_frame) #self.cid = self.canvas.mpl_connect('button_press_event', self._onclick) self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.parent) self.toolbar.update() self.canvas._tkcanvas.pack(anchor=tk.W, side=tk.TOP, fill=tk.BOTH, expand=1) def _onclick(self, event): print('button={:d}, x={:f}, y={:f}, xdata={:f}, ydata={:f}'.format( event.button, event.x, event.y, event.xdata, event.ydata)) # call back functions ----------------------- def _display(self): if self.fn is None: self._loadimage() # display image self.plt[0].imshow(self.IM, vmin=0) #rows, cols = self.IM.shape #r2 = rows/2 #c2 = cols/2 #self.a.plot((r2, r2), (0, cols), 'r--', lw=0.1) #self.a.plot((0, rows), (c2, c2),'r--', lw=0.1) #self.f.colorbar(self.a.get_children()[2], ax=self.f.gca()) self.plt[0].set_title("raw image", fontsize=10) self.canvas.show() def _loadimage(self): if self.fn is not None: # clear old plot for i in range(4): self._clr_plt(i) self.plt[i].axis("off") self.fn = self.sample_image.get() # update what is occurring text box self.text.insert(tk.END, "\nloading image file {:s}".format(self.fn)) self.text.see(tk.END) self.canvas.show() if self.fn == "from file": self.fn = askopenfilename() # read image file if ".txt" in self.fn: self.IM = np.loadtxt(self.fn) else: self.IM = imread(self.fn) elif self.fn == "from transform": self.IM = self.AIM self.AIM = None for i in range(1, 4): self._clr_plt(i) self.plt[i].axis("off") self.direction.current(0) else: self.fn = self.fn.split(' ')[-1] self.IM = abel.tools.analytical.sample_image(n=1001, name=self.fn) self.direction.current(1) # raw images require 'forward' transform self.text.insert(tk.END, "\nsample image: (1) Abel transform 'forward', ") self.text.insert(tk.END, " (2) load 'from transform', ") self.text.insert(tk.END, " (3) Abel transform 'inverse', ") self.text.insert(tk.END, " (4) Speed") self.text.see(tk.END) # if even size image, make odd if self.IM.shape[0] % 2 == 0: self.IM = shift(self.IM, (-0.5, -0.5))[:-1, :-1] self.old_method = None self.AIM = None self.action = "file" self.rmin.delete(0, tk.END) self.rmin.insert(0, self.rmx[0]) self.rmax.delete(0, tk.END) self.rmax.insert(0, self.rmx[1]) # show the image self._display() def _center(self): self.action = "center" center_method = self.center_method.get() # update information text box self.text.insert(tk.END, "\ncentering image using {:s}".\ format(center_method)) self.canvas.show() # center image via chosen method self.IM = abel.tools.center.center_image(self.IM, center=center_method, odd_size=True) #self.text.insert(tk.END, "\ncenter offset = {:}".format(self.offset)) self.text.see(tk.END) self._display() def _transform(self): #self.method = Abel_methods[self.transform_method.get()] self.method = self.transform.get() self.fi = self.direction.get() if self.method != self.old_method or self.fi != self.old_fi: # Abel transform of whole image self.text.insert(tk.END,"\n{:s} {:s} Abel transform:".\ format(self.method, self.fi)) if self.method == "basex": self.text.insert( tk.END, "\nbasex: first time calculation of the basis" " functions may take a while ...") elif self.method == "direct": self.text.insert( tk.END, "\ndirect: calculation is slowed if Cython unavailable ..." ) self.canvas.show() if self.method == 'linbasex': self.AIM = abel.Transform( self.IM, method=self.method, direction=self.fi, transform_options=dict(return_Beta=True)) else: self.AIM = abel.Transform( self.IM, method=self.method, direction=self.fi, transform_options=dict(basis_dir='bases'), symmetry_axis=None) self.rmin.delete(0, tk.END) self.rmin.insert(0, self.rmx[0]) self.rmax.delete(0, tk.END) self.rmax.insert(0, self.rmx[1]) if self.old_method != self.method or self.fi != self.old_fi or\ self.action not in ["speed", "anisotropy"]: self.plt[2].set_title(self.method + " {:s} Abel transform".format(self.fi), fontsize=10) self.plt[2].imshow(self.AIM.transform, vmin=0, vmax=self.AIM.transform.max() / 5.0) #self.f.colorbar(self.c.get_children()[2], ax=self.f.gca()) #self.text.insert(tk.END, "{:s} inverse Abel transformed image".format(self.method)) self.text.see(tk.END) self.old_method = self.method self.old_fi = self.fi self.canvas.show() def _speed(self): self.action = "speed" # inverse Abel transform self._transform() # update text box in case something breaks self.text.insert(tk.END, "\nspeed distribution") self.text.see(tk.END) self.canvas.show() if self.method == 'linbasex': self.speed_dist = self.AIM.Beta[0] self.radial = self.AIM.radial else: # speed distribution self.radial, self.speed_dist = abel.tools.vmi.angular_integration( self.AIM.transform) self.plt[1].axis("on") self.plt[1].plot(self.radial, self.speed_dist / self.speed_dist[10:].max(), label=self.method) # make O2- look nice if self.fn.find('O2-ANU1024') > -1: self.plt[1].axis(xmax=500, ymin=-0.05) elif self.fn.find('VMI_art1') > -1: self.plt[1].axis(xmax=260, ymin=-0.05) self.plt[1].set_xlabel("radius (pixels)", fontsize=9) self.plt[1].set_ylabel("normalized intensity") self.plt[1].set_title("radial speed distribution", fontsize=12) self.plt[1].legend(fontsize=9, loc=0, frameon=False) self.action = None self.canvas.show() def _speed_clr(self): self._clr_plt(1) def _clr_plt(self, i): self.f.delaxes(self.plt[i]) self.plt[i] = self.f.add_subplot(self.gs[i]) self.canvas.show() def _anisotropy(self): def P2(x): # 2nd order Legendre polynomial return (3 * x * x - 1) / 2 def PAD(theta, beta, amp): return amp * (1 + beta * P2(np.cos(theta))) self.action = "anisotropy" self._transform() if self.method == 'linbasex': self.text.insert(tk.END, "\nanisotropy parameter pixel range 0 to {}: "\ .format(self.rmx[1])) else: # radial range over which to follow the intensity variation with angle self.rmx = (int(self.rmin.get()), int(self.rmax.get())) self.text.insert(tk.END, "\nanisotropy parameter pixel range {:} to {:}: "\ .format(*self.rmx)) self.canvas.show() # inverse Abel transform self._transform() if self.method == 'linbasex': self.beta = self.AIM.Beta[1] self.radial = self.AIM.radial self._clr_plt(3) self.plt[3].axis("on") self.plt[3].plot(self.radial, self.beta, 'r-') self.plt[3].set_title("anisotropy", fontsize=12) self.plt[3].set_xlabel("radius", fontsize=9) self.plt[3].set_ylabel("anisotropy parameter") # make O2- look nice if self.fn.find('O2-ANU1024') > -1: self.plt[3].axis(xmax=500, ymin=-1.1, ymax=0.1) elif self.fn.find('VMI_art1') > -1: self.plt[3].axis(xmax=260, ymin=-1.1, ymax=2) else: # intensity vs angle self.beta, self.amp, self.rad, self.intensity, self.theta =\ abel.tools.vmi.radial_integration(self.AIM.transform,\ radial_ranges=[self.rmx,]) self.text.insert(tk.END, " beta = {:g}+-{:g}".format(*self.beta[0])) self._clr_plt(3) self.plt[3].axis("on") self.plt[3].plot(self.theta, self.intensity[0], 'r-') self.plt[3].plot(self.theta, PAD(self.theta, self.beta[0][0], self.amp[0][0]), 'b-', lw=2) self.plt[3].annotate( "$\\beta({:d},{:d})={:.2g}\pm{:.2g}$".format(*self.rmx + self.beta[0]), (-3, self.intensity[0].min() / 0.8)) self.plt[3].set_title("anisotropy", fontsize=12) self.plt[3].set_xlabel("angle", fontsize=9) self.plt[3].set_ylabel("intensity") self.action = None self.canvas.show() def _hide_buttons(self): self.button_frame.destroy() def _on_buttons(self): self._button_frame() def _quit(self): self.parent.quit() # stops mainloop self.parent.destroy() # this is necessary on Windows to prevent
class MplCanvas(FigureCanvas): subscriptions = [rc.MT_PING, MT_EXIT, rc.MT_TASK_STATE_CONFIG, rc.MT_ROBOT_CONTROL_SPACE_ACTUAL_STATE, rc.MT_GROBOT_SEGMENT_PERCEPTS, rc.MT_GROBOT_RAW_FEEDBACK, rc.MT_END_TASK_STATE] def __init__(self, parent=None, width=8, height=10, dpi=80): self.parent = parent self.paused = False self.LiveData = None self.fdbk_actual_pos = None self.fdbk_actual_cori = None self.tsc_mdf = None self.ets_mdf = None self.fdbk_percepts = [0] * 16 self.fdbk_torques = [0] * 16 self.redraw_yticks = True self.figure = Figure(figsize=(width, height), dpi=dpi, facecolor='#bbbbbb') FigureCanvas.__init__(self, self.figure) self.setParent(parent) FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) def init_judge_display(self): N = self.config['config']['number_of_data_points'] self.LiveData = {'ActualPos': {}, 'ThreshUpper': {}, 'ThreshLower': {}, 'JudgingMethod': {}, 'JudgingPolarity': {}, 'max_scale': {}, 'min_scale': {} } allDims = 1 + 1 + 10 + 15 + 28 # trans + ori + finger + force + torque for d in range(allDims): self.LiveData['ActualPos'][d] = np.zeros(N) self.LiveData['ThreshUpper'][d] = nan_array(N) self.LiveData['ThreshLower'][d] = nan_array(N) self.LiveData['JudgingMethod'][d] = nan_array(N) self.LiveData['JudgingPolarity'][d] = nan_array(N) self.LiveData['max_scale'][d] = np.finfo(float).eps self.LiveData['min_scale'][d] = -np.finfo(float).eps # self.LiveData['TaskStateNo'] = np.zeros(N) self.LiveData['TaskStateVerdict'] = np.ones(N) def run(self, config_file, server): self.mod = RTMA_Module(0, 0) self.mod.ConnectToMMM(server) for sub in self.subscriptions: self.mod.Subscribe(sub) self.mod.SendModuleReady() print "Connected to RTMA at", server self.config_file = config_file self.load_config() self.init_judge_display() self.init_plot() self.init_legend() timer = QtCore.QTimer(self) QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.timer_event) timer.start(10) def update_scales(self, d): min_data = np.nanmin(self.LiveData['ActualPos'][d]) if min_data < self.LiveData['min_scale'][d]: self.LiveData['min_scale'][d] = min_data; max_data = np.nanmax(self.LiveData['ActualPos'][d]) if max_data > self.LiveData['max_scale'][d]: self.LiveData['max_scale'][d] = max_data; def update_judging_data(self): # this loop is so we can update finger pos data even if we haven't # received any TASK_STATE_CONFIG msg for i in range(self.nDims): d = self.dims[i] - 1 if d > 1: # fingers finger_idx = d-2 actual_pos = self.fdbk_actual_pos[8+finger_idx]; self.LiveData['ActualPos'][d] = self.add_to_windowed_array(self.LiveData['ActualPos'][d], actual_pos) self.update_scales(d) if self.tsc_mdf is None: return trans_thresh = self.tsc_mdf.trans_threshold ori_threshold = self.tsc_mdf.ori_threshold finger_thresh = np.array(self.tsc_mdf.finger_threshold, dtype=float) finger_dofs_to_judge = np.where(~np.isnan(finger_thresh)==True)[0] for i in range(self.nDims): d = self.dims[i] - 1 threshU = np.NAN threshL = np.NAN method = np.NAN polarity = np.NAN if d == 0: # trans tgt_pos = np.array(self.tsc_mdf.target[0:3]) act_pos = np.array(self.fdbk_actual_pos[0:3]) tgt_disp = tgt_pos - act_pos; tgt_dist = np.sqrt(np.sum(np.power(tgt_disp,2))) self.LiveData['ActualPos'][d] = self.add_to_windowed_array(self.LiveData['ActualPos'][d], tgt_dist) self.update_scales(d) threshU = trans_thresh threshL = -trans_thresh method = 1 # dist polarity = 2 # less than (inverted) elif d == 1: # ori tgt_cori = np.array(self.tsc_mdf.coriMatrix).reshape((3,3)).T act_cori = np.array(self.fdbk_actual_cori).reshape((3,3)).T cori_diff_matrix = tgt_cori * act_cori.T [diff_rotaxis, diff_angle] = rotmat2rotvec( cori_diff_matrix) self.LiveData['ActualPos'][d] = self.add_to_windowed_array(self.LiveData['ActualPos'][d], diff_angle) self.update_scales(d) print diff_angle print ori_threshold print "-----" threshU = ori_threshold threshL = -ori_threshold method = 1 # dist polarity = 2 # less than (inverted) else: # fingers finger_idx = d-2 if np.where(finger_dofs_to_judge == finger_idx)[0].size > 0: thresh = self.tsc_mdf.finger_threshold[finger_idx] method = self.tsc_mdf.finger_threshold_judging_method[finger_idx] polarity = self.tsc_mdf.finger_threshold_judging_polarity[finger_idx] # invert polarities (because we plot "keep out" zones) if (polarity > 0) and (self.tsc_mdf.timed_out_conseq == 0): polarity = ~polarity & 3; # finger_threshold_judging_method: 1=distance (default), 2=absolute if method == 1: # dist target = self.tsc_mdf.target[8+finger_idx] threshU = target + thresh threshL = target - thresh else: # abs threshU = thresh # insert new data to plotting arrays self.LiveData['ThreshUpper'][d] = self.add_to_windowed_array(self.LiveData['ThreshUpper'][d], threshU) self.LiveData['ThreshLower'][d] = self.add_to_windowed_array(self.LiveData['ThreshLower'][d], threshL) self.LiveData['JudgingMethod'][d] = self.add_to_windowed_array(self.LiveData['JudgingMethod'][d], method) self.LiveData['JudgingPolarity'][d] = self.add_to_windowed_array(self.LiveData['JudgingPolarity'][d], polarity) self.LiveData['TaskStateNo'] = self.add_to_windowed_array(self.LiveData['TaskStateNo'], self.tsc_mdf.id) if self.ets_mdf is not None: self.LiveData['TaskStateVerdict'][-2] = self.ets_mdf.outcome self.LiveData['TaskStateVerdict'][-1] = self.ets_mdf.outcome self.LiveData['TaskStateVerdict'] = self.add_to_windowed_array(self.LiveData['TaskStateVerdict'], self.ets_mdf.outcome) self.ets_mdf = None else: self.LiveData['TaskStateVerdict'] = self.add_to_windowed_array(self.LiveData['TaskStateVerdict'], 1) def add_to_windowed_array(self, arr, data): arr = np.append(arr, data) arr = np.delete(arr, 0) return arr def load_config(self): self.config = ConfigObj(self.config_file, unrepr=True) def reload_config(self): self.load_config() for ax in self.figure.axes: self.figure.delaxes(ax) self.figure.clear() self.draw() self.init_plot(True) self.init_legend() self.redraw_yticks = True def init_plot(self, clear=False): self.figure.subplots_adjust(bottom=.05, right=.98, left=.08, top=.98, hspace=0.07) trans_dim = 0 if 'plot_translation' in self.config['config']: trans_dim = self.config['config']['plot_translation'] ori_dim = 0 if 'plot_orientation' in self.config['config']: ori_dim = self.config['config']['plot_orientation'] finger_dims = [] if 'active_finger_dims' in self.config['config']: finger_dims = self.config['config']['active_finger_dims'] force_dims = [] if 'active_force_dims' in self.config['config']: force_dims = self.config['config']['active_force_dims'] torque_dims = [] if 'active_torque_dims' in self.config['config']: torque_dims = self.config['config']['active_torque_dims'] axis_labels = [] self.dims = [] if trans_dim == 1: self.dims.append(1) axis_labels.extend(['XYZ tgt dist']) if ori_dim == 1: self.dims.append(2) axis_labels.extend(['ORI tgt dist']) if finger_dims: for f in finger_dims: if (f>0) and (f<=10): self.dims.extend([f+2]) axis_labels.extend(['finger #%d' % f]) else: print "Warning: invalid finger dim specified: %f, skipping.." % f if force_dims: force_labels = ['ifx', 'ify', 'ifz', 'mfx', 'mfy', 'mfz', 'rfx', \ 'rfy', 'rfz', 'lfx', 'lfy', 'lfz', 'tfx', 'tfy', 'tfz'] for f in force_dims: if (f>0) and (f<=15): self.dims.extend([f+12]) axis_labels.extend(['force #%d (%s)' % (f, force_labels[f-1])]) else: print "Warning: invalid force dim specified: %d, skipping.." % f if torque_dims: for f in torque_dims: if (f>0) and (f<=28): self.dims.extend([f+27]) axis_labels.extend(['trq #%d' % f]) else: print "Warning: invalid torque dim specified: %d, skipping.." % f self.nDims = trans_dim + ori_dim + len(finger_dims) + len(force_dims) + len(torque_dims) self.xN = self.config['config']['number_of_data_points'] self.bg = self.config['marked_task_states'].keys() self.max_scale = self.config['config']['max_scale'] if len(self.max_scale) < self.nDims: self.max_scale.extend([np.finfo(float).eps] * (self.nDims - len(self.max_scale))) self.min_scale = self.config['config']['min_scale'] if len(self.min_scale) < self.nDims: self.min_scale.extend([-np.finfo(float).eps] * (self.nDims - len(self.min_scale))) self.ax = [] self.old_size = [] self.ax_bkg = [] self.finger_pos = [] self.zones = {} self.zone_idx = [] for d in range(self.nDims): ax = self.figure.add_subplot(self.nDims,1,d+1) self.reset_axis(ax, axis_labels[d]) self.draw() bbox_width = ax.bbox.width bbox_height = ax.bbox.height if clear == True: # force to redraw bbox_width = 0 bbox_height = 0 self.old_size.append( (bbox_width, bbox_height) ) self.ax_bkg.append(self.copy_from_bbox(ax.bbox)) line, = ax.plot([], [], 'k-', lw=1.0, aa=None, animated=True) line.set_xdata(range(self.xN)) line.set_ydata([0.0]*self.xN) self.finger_pos.append(line) self.draw() self.zones[d] = [] self.zone_idx.append(0) for z in range(60): patch = ax.add_patch(Polygon([[0, 1e-12],[1e-12, 0],[1e-12, 1e-12],[0, 1e-12]], fc='none', ec='none', fill=True, closed=True, aa=None, animated=True)) self.zones[d].append(patch) self.draw() self.ax.append(ax) def reset_axis(self, ax, label): ax.grid(True) ax.set_xlim(0, self.xN-1) ax.set_autoscale_on(False) ax.set_ylabel(label, fontsize='small') ax.get_xaxis().set_ticks([]) ax.yaxis.set_major_formatter(FormatStrFormatter('%.02f')) for tick in ax.get_yticklabels(): tick.set_fontsize(9) def init_legend(self): legnd = [] line = matplotlib.lines.Line2D([0,0], [0,0], color='k') legnd.append(line) for d in range(len(self.bg)): b_color = self.config['marked_task_states'][self.bg[d]]['color'] patch = Polygon([[0,0],[0, 0],[0, 0],[0, 0]], fc=b_color, ec='none', fill=True, closed=True, alpha=0.65) legnd.append(patch) self.figure.legend(legnd, ['Position']+self.bg, loc='lower center', frameon=False, ncol=20, prop={'size':'11'}, columnspacing=.5) self.draw() def plot_bg_mask(self, ax, idx, x, mask, ylim, fc, ec, hatch, alpha): # Find starts and ends of contiguous regions of true values in mask because # we want just one patch object per contiguous region _mask = np.asarray(np.insert(mask, 0, 0), dtype=int) begin_indices = np.where( np.diff( _mask) == 1)[0] _mask = np.asarray(np.append(mask, 0), dtype=int) end_indices = np.where( np.diff( _mask) == -1)[0] # Get DeltaX dx = np.mean( np.diff(x)) # Get YLim if it was not given if len(ylim) == 0: ylim = ax.get_ylim() z = self.zones[idx] a = self.zone_idx[idx] for i in range(len( begin_indices)): b = begin_indices[i] e = end_indices[i] xb = x[b] - dx/2; xe = x[e] + dx/2; patch = z[a] patch.set_xy([[xb, ylim[0]],[xe, ylim[0]],[xe, ylim[1]],[xb, ylim[1]]]) patch.set_edgecolor(ec) patch.set_facecolor(fc) patch.set_hatch(hatch) patch.set_alpha(alpha) ax.draw_artist(patch) a = a + 1 self.zone_idx[idx] = a def timer_event(self): done = False while not done: msg = CMessage() rcv = self.mod.ReadMessage(msg, 0) if rcv == 1: msg_type = msg.GetHeader().msg_type if msg_type == rc.MT_TASK_STATE_CONFIG: self.tsc_mdf = rc.MDF_TASK_STATE_CONFIG() copy_from_msg(self.tsc_mdf, msg) elif msg_type == rc.MT_ROBOT_CONTROL_SPACE_ACTUAL_STATE: mdf = rc.MDF_ROBOT_CONTROL_SPACE_ACTUAL_STATE() copy_from_msg(mdf, msg) self.fdbk_actual_cori = mdf.CoriMatrix self.fdbk_actual_pos = [] self.fdbk_actual_pos.extend(mdf.pos) self.fdbk_actual_pos.extend(self.fdbk_percepts) self.fdbk_actual_pos.extend(self.fdbk_torques) self.update_judging_data() elif msg_type == rc.MT_GROBOT_SEGMENT_PERCEPTS: mdf = rc.MDF_GROBOT_SEGMENT_PERCEPTS() copy_from_msg(mdf, msg) self.fdbk_percepts = [] self.fdbk_percepts.extend(mdf.ind_force[:]) self.fdbk_percepts.extend(mdf.mid_force[:]) self.fdbk_percepts.extend(mdf.rng_force[:]) self.fdbk_percepts.extend(mdf.lit_force[:]) self.fdbk_percepts.extend(mdf.thb_force[:]) elif msg_type == rc.MT_GROBOT_RAW_FEEDBACK: mdf = rc.MDF_GROBOT_RAW_FEEDBACK() copy_from_msg(mdf, msg) self.fdbk_torques = mdf.j_trq elif msg_type == rc.MT_END_TASK_STATE: self.ets_mdf = rc.MDF_END_TASK_STATE() copy_from_msg(self.ets_mdf, msg) elif msg_type == rc.MT_PING: respond_to_ping(self.mod, msg, 'SimpleJudgeDisplay') elif msg_type == MT_EXIT: self.exit() done = True else: done = True self.update_plot() def update_plot(self): if self.paused == False: LiveData = self.LiveData else: LiveData = self.PausedData for i in range(self.nDims): ax = self.ax[i] d = self.dims[i] - 1 current_size = ax.bbox.width, ax.bbox.height if self.old_size[i] != current_size: self.old_size[i] = current_size self.draw() self.ax_bkg[i] = self.copy_from_bbox(ax.bbox) self.restore_region(self.ax_bkg[i]) self.zone_idx[i] = 0 min_scale = LiveData['min_scale'][d]; if 'min_scale' in self.config['config']: min_scale = self.min_scale[i] max_scale = LiveData['max_scale'][d]; if 'max_scale' in self.config['config']: max_scale = self.max_scale[i] ax.set_ylim(min_scale, max_scale) yLimG = ax.get_ylim() for b in range(len(self.bg)): b_id = self.config['marked_task_states'][self.bg[b]]['id'] b_color = self.config['marked_task_states'][self.bg[b]]['color'] mask = np.where(LiveData['TaskStateNo']==b_id, 1, 0) if np.sum(mask) > 0: self.plot_bg_mask(ax, i, range(self.xN), mask, [], b_color, 'none', None, 0.65) else: # always draw patch for all colors so that they will always show up in the legend z = self.zones[i] patch = z[self.zone_idx[i]] patch.set_xy([[0, 0],[0, 0],[0, 0],[0, 0]]) ax.draw_artist(patch) self.zone_idx[i] = self.zone_idx[i] + 1 # finger_threshold_judging_method: 1=distance, 2=absolute # finger threshold_judging_polarity: 1 = <, 2 = > methods = ~np.isnan(LiveData['JudgingMethod'][d]) if np.sum(methods) > 0: methods = np.unique(LiveData['JudgingMethod'][d][methods]) for m in range(len(methods)): method = methods[m] met_mask = np.where(LiveData['JudgingMethod'][d] == method, True, False) polaritys = np.unique(LiveData['JudgingPolarity'][d][met_mask]) for p in range(len(polaritys)): polarity = polaritys[p] pol_mask = np.where(LiveData['JudgingPolarity'][d] == polarity, True, False) mask = met_mask & pol_mask yLimUs = np.unique(LiveData['ThreshUpper'][d][mask]) for b in range(len(yLimUs)): yLimU = yLimUs[b] submask = np.where(LiveData['ThreshUpper'][d] == yLimU, True, False) & mask if method == 1: # dist yLimLs = np.unique(LiveData['ThreshLower'][d][submask]) for k in range(len(yLimLs)): yLimL = yLimLs[k] submask2 = np.where(LiveData['ThreshLower'][d] == yLimL, True, False) & submask if polarity == 1: # < self.plot_bg_mask(ax, i, range(self.xN), submask2, [yLimL, yLimU], 'none', 'black', '//', 1) else: self.plot_bg_mask(ax, i, range(self.xN), submask2, [yLimG[0], yLimL], 'none', 'black', '//', 1) self.plot_bg_mask(ax, i, range(self.xN), submask2, [yLimU, yLimG[1]], 'none', 'black', '//', 1) else: # abs if polarity == 1: # < self.plot_bg_mask(ax, i, range(self.xN), submask, [yLimG[0], yLimU], 'none', 'black', '//', 1) else: self.plot_bg_mask(ax, i, range(self.xN), submask, [yLimU, yLimG[1]], 'none', 'black', '//', 1) fail_mask = np.where(LiveData['TaskStateVerdict']==0, True, False) self.plot_bg_mask(ax, i, range(self.xN), fail_mask, [], 'red', 'none', None, 0.65) self.finger_pos[i].set_ydata(LiveData['ActualPos'][d]) ax.draw_artist(self.finger_pos[i]) self.blit(ax.bbox) if self.zone_idx[i] > 60: print "ERROR: too many zones! Increase number of preallocated patches" # need to redraw once to update y-ticks if self.redraw_yticks == True: self.draw() self.redraw_yticks = False def pause(self, pause_state): self.paused = pause_state self.PausedData = copy.deepcopy(self.LiveData) def exit(self): print "exiting" self.parent.exit_app() def stop(self): print 'disconnecting' self.mod.SendSignal(rc.MT_EXIT_ACK) self.mod.DisconnectFromMMM()
class MainFrame(BaseFrame): """Contains the main GUI and button boxes""" def __init__(self, parent, config, video, shuffle, Dataframe, savelabeled, multianimal): super(MainFrame, self).__init__("DeepLabCut2.0 - Manual Outlier Frame Extraction", parent) ################################################################################################################################################### # Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting! # topSplitter = wx.SplitterWindow(self) # # self.image_panel = ImagePanel(topSplitter, config,video,shuffle,Dataframe,self.gui_size) # self.widget_panel = WidgetPanel(topSplitter) # # topSplitter.SplitHorizontally(self.image_panel, self.widget_panel,sashPosition=self.gui_size[1]*0.83)#0.9 # topSplitter.SetSashGravity(1) # sizer = wx.BoxSizer(wx.VERTICAL) # sizer.Add(topSplitter, 1, wx.EXPAND) # self.SetSizer(sizer) # Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting! topSplitter = wx.SplitterWindow(self) vSplitter = wx.SplitterWindow(topSplitter) self.image_panel = ImagePanel(vSplitter, config, self.gui_size) self.choice_panel = ScrollPanel(vSplitter) vSplitter.SplitVertically(self.image_panel, self.choice_panel, sashPosition=self.gui_size[0] * 0.8) vSplitter.SetSashGravity(1) self.widget_panel = WidgetPanel(topSplitter) topSplitter.SplitHorizontally(vSplitter, self.widget_panel, sashPosition=self.gui_size[1] * 0.83) # 0.9 topSplitter.SetSashGravity(1) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(topSplitter, 1, wx.EXPAND) self.SetSizer(sizer) ################################################################################################################################################### # Add Buttons to the WidgetPanel and bind them to their respective functions. widgetsizer = wx.WrapSizer(orient=wx.HORIZONTAL) self.load_button_sizer = wx.BoxSizer(wx.VERTICAL) self.help_button_sizer = wx.BoxSizer(wx.VERTICAL) self.help = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Help") self.help_button_sizer.Add(self.help, 1, wx.ALL, 15) # widgetsizer.Add(self.help , 1, wx.ALL, 15) self.help.Bind(wx.EVT_BUTTON, self.helpButton) widgetsizer.Add(self.help_button_sizer, 1, wx.ALL, 0) self.grab = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Grab Frames") widgetsizer.Add(self.grab, 1, wx.ALL, 15) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.grab.Enable(True) widgetsizer.AddStretchSpacer(5) self.slider = wx.Slider( self.widget_panel, id=wx.ID_ANY, value=0, minValue=0, maxValue=1, size=(200, -1), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS, ) widgetsizer.Add(self.slider, 1, wx.ALL, 5) self.slider.Bind(wx.EVT_SLIDER, self.OnSliderScroll) widgetsizer.AddStretchSpacer(5) self.start_frames_sizer = wx.BoxSizer(wx.VERTICAL) self.end_frames_sizer = wx.BoxSizer(wx.VERTICAL) self.start_frames_sizer.AddSpacer(15) # self.startFrame = wx.SpinCtrl(self.widget_panel, value='0', size=(100, -1), min=0, max=120) self.startFrame = wx.SpinCtrl(self.widget_panel, value="0", size=(100, -1)) # ,style=wx.SP_VERTICAL) self.startFrame.Enable(False) self.start_frames_sizer.Add(self.startFrame, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) start_text = wx.StaticText(self.widget_panel, label="Start Frame Index") self.start_frames_sizer.Add(start_text, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) self.checkBox = wx.CheckBox(self.widget_panel, id=wx.ID_ANY, label="Range of frames") self.checkBox.Bind(wx.EVT_CHECKBOX, self.activate_frame_range) self.start_frames_sizer.Add(self.checkBox, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) # self.end_frames_sizer.AddSpacer(15) self.endFrame = wx.SpinCtrl(self.widget_panel, value="1", size=(160, -1)) # , min=1, max=120) self.endFrame.Enable(False) self.end_frames_sizer.Add(self.endFrame, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) end_text = wx.StaticText(self.widget_panel, label="Number of Frames") self.end_frames_sizer.Add(end_text, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) self.updateFrame = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Update") self.end_frames_sizer.Add(self.updateFrame, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) self.updateFrame.Bind(wx.EVT_BUTTON, self.updateSlider) self.updateFrame.Enable(False) widgetsizer.Add(self.start_frames_sizer, 1, wx.ALL, 0) widgetsizer.AddStretchSpacer(5) widgetsizer.Add(self.end_frames_sizer, 1, wx.ALL, 0) widgetsizer.AddStretchSpacer(15) self.quit = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Quit") widgetsizer.Add(self.quit, 1, wx.ALL, 15) self.quit.Bind(wx.EVT_BUTTON, self.quitButton) self.quit.Enable(True) self.widget_panel.SetSizer(widgetsizer) self.widget_panel.SetSizerAndFit(widgetsizer) # Variables initialization self.numberFrames = 0 self.currFrame = 0 self.figure = Figure() self.axes = self.figure.add_subplot(111) self.drs = [] self.extract_range_frame = False self.firstFrame = 0 self.Colorscheme = [] # Read confing file self.cfg = auxiliaryfunctions.read_config(config) self.Task = self.cfg["Task"] self.start = self.cfg["start"] self.stop = self.cfg["stop"] self.date = self.cfg["date"] self.trainFraction = self.cfg["TrainingFraction"] self.trainFraction = self.trainFraction[0] self.videos = self.cfg["video_sets"].keys() self.bodyparts = self.cfg["bodyparts"] self.colormap = plt.get_cmap(self.cfg["colormap"]) self.colormap = self.colormap.reversed() self.markerSize = self.cfg["dotsize"] self.alpha = self.cfg["alphavalue"] self.iterationindex = self.cfg["iteration"] self.cropping = self.cfg["cropping"] self.video_names = [Path(i).stem for i in self.videos] self.config_path = Path(config) self.video_source = Path(video).resolve() self.shuffle = shuffle self.Dataframe = Dataframe self.savelabeled = savelabeled self.multianimal = multianimal if self.multianimal: from deeplabcut.utils import auxfun_multianimal ( self.individual_names, self.uniquebodyparts, self.multianimalbodyparts, ) = auxfun_multianimal.extractindividualsandbodyparts(self.cfg) self.choiceBox, self.visualization_rdb = self.choice_panel.addRadioButtons( ) self.Colorscheme = visualization.get_cmap( len(self.individual_names), self.cfg["colormap"]) self.visualization_rdb.Bind(wx.EVT_RADIOBOX, self.clear_plot) # Read the video file self.vid = VideoWriter(str(self.video_source)) if self.cropping: self.vid.set_bbox(self.cfg["x1"], self.cfg["x2"], self.cfg["y1"], self.cfg["y2"]) self.filename = Path(self.video_source).name self.numberFrames = len(self.vid) self.strwidth = int(np.ceil(np.log10(self.numberFrames))) # Set the values of slider and range of frames self.startFrame.SetMax(self.numberFrames - 1) self.slider.SetMax(self.numberFrames - 1) self.endFrame.SetMax(self.numberFrames - 1) self.startFrame.Bind(wx.EVT_SPINCTRL, self.updateSlider) # wx.EVT_SPIN # Set the status bar self.statusbar.SetStatusText("Working on video: {}".format( self.filename)) # Adding the video file to the config file. if self.vid.name not in self.video_names: add.add_new_videos(self.config_path, [self.video_source]) self.update() self.plot_labels() self.widget_panel.Layout() def quitButton(self, event): """ Quits the GUI """ self.statusbar.SetStatusText("") dlg = wx.MessageDialog(None, "Are you sure?", "Quit!", wx.YES_NO | wx.ICON_WARNING) result = dlg.ShowModal() if result == wx.ID_YES: print("Quitting for now!") self.Destroy() def updateSlider(self, event): self.slider.SetValue(self.startFrame.GetValue()) self.startFrame.SetValue(self.slider.GetValue()) self.axes.clear() self.figure.delaxes(self.figure.axes[1]) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.currFrame = self.slider.GetValue() self.update() self.plot_labels() def activate_frame_range(self, event): """ Activates the frame range boxes """ self.checkSlider = event.GetEventObject() if self.checkSlider.GetValue(): self.extract_range_frame = True self.startFrame.Enable(True) self.startFrame.SetValue(self.slider.GetValue()) self.endFrame.Enable(True) self.updateFrame.Enable(True) self.grab.Enable(False) else: self.extract_range_frame = False self.startFrame.Enable(False) self.endFrame.Enable(False) self.updateFrame.Enable(False) self.grab.Enable(True) def line_select_callback(self, eclick, erelease): "eclick and erelease are the press and release events" self.new_x1, self.new_y1 = eclick.xdata, eclick.ydata self.new_x2, self.new_y2 = erelease.xdata, erelease.ydata def OnSliderScroll(self, event): """ Slider to scroll through the video """ self.axes.clear() self.figure.delaxes(self.figure.axes[1]) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.currFrame = self.slider.GetValue() self.startFrame.SetValue(self.currFrame) self.update() self.plot_labels() def update(self): """ Updates the image with the current slider index """ self.grab.Enable(True) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.figure, self.axes, self.canvas = self.image_panel.getfigure() self.vid.set_to_frame(self.currFrame) frame = self.vid.read_frame(crop=self.cropping) if frame is not None: frame = img_as_ubyte(frame) self.ax = self.axes.imshow(frame, cmap=self.colormap) self.axes.set_title( str( str(self.currFrame) + "/" + str(self.numberFrames - 1) + " " + self.filename)) self.figure.canvas.draw() else: print("Invalid frame") def chooseFrame(self): frame = img_as_ubyte(self.vid.read_frame(crop=self.cropping)) fname = Path(self.filename) output_path = self.config_path.parents[0] / "labeled-data" / fname.stem self.machinefile = os.path.join( str(output_path), "machinelabels-iter" + str(self.iterationindex) + ".h5") name = str(fname.stem) DF = self.Dataframe.iloc[[self.currFrame]] DF.index = [ os.path.join("labeled-data", name, "img" + str(index).zfill(self.strwidth) + ".png") for index in DF.index ] img_name = (str(output_path) + "/img" + str(self.currFrame).zfill( int(np.ceil(np.log10(self.numberFrames)))) + ".png") labeled_img_name = (str(output_path) + "/img" + str( self.currFrame).zfill(int(np.ceil(np.log10(self.numberFrames)))) + "labeled.png") # Check for it output path and a machine label file exist if output_path.exists() and Path(self.machinefile).is_file(): io.imsave(img_name, frame) if self.savelabeled: self.figure.savefig(labeled_img_name, bbox_inches="tight") Data = pd.read_hdf(self.machinefile) DataCombined = pd.concat([Data, DF]) DataCombined = DataCombined[~DataCombined.index.duplicated( keep="first")] DataCombined.to_hdf(self.machinefile, key="df_with_missing", mode="w") DataCombined.to_csv( os.path.join(str(output_path), "machinelabels.csv")) # If machine label file does not exist then create one elif output_path.exists() and not (Path(self.machinefile).is_file()): if self.savelabeled: self.figure.savefig(labeled_img_name, bbox_inches="tight") io.imsave(img_name, frame) # cv2.imwrite(img_name, frame) DF.to_hdf(self.machinefile, key="df_with_missing", mode="w") DF.to_csv(os.path.join(str(output_path), "machinelabels.csv")) else: print( "%s path not found. Please make sure that the video was added to the config file using the function 'deeplabcut.add_new_videos'.Quitting for now!" % output_path) self.Destroy() def grabFrame(self, event): """ Extracts the frame and saves in the current directory """ if self.extract_range_frame: num_frames_extract = self.endFrame.GetValue() for i in range(self.currFrame, self.currFrame + num_frames_extract): self.currFrame = i self.vid.set_to_frame(self.currFrame) self.chooseFrame() else: self.vid.set_to_frame(self.currFrame) self.chooseFrame() def clear_plot(self, event): self.figure.delaxes(self.figure.axes[1]) [p.remove() for p in reversed(self.axes.patches)] self.plot_labels() def plot_labels(self): """ Plots the labels of the analyzed video """ self.vid.set_to_frame(self.currFrame) frame = self.vid.read_frame() if frame is not None: divider = make_axes_locatable(self.axes) cax = divider.append_axes("right", size="5%", pad=0.05) if self.multianimal: # take into account of all the bodyparts for the colorscheme. Sort the bodyparts to have same order as in the config file self.all_bodyparts = np.array(self.multianimalbodyparts + self.uniquebodyparts) _, return_idx = np.unique(self.all_bodyparts, return_index=True) self.all_bodyparts = list( self.all_bodyparts[np.sort(return_idx)]) if (self.visualization_rdb.GetSelection() == 0 ): # i.e. for color scheme for individuals self.Colorscheme = visualization.get_cmap( len(self.individual_names), self.cfg["colormap"]) self.norm, self.colorIndex = self.image_panel.getColorIndices( frame, self.individual_names) cbar = self.figure.colorbar(self.ax, cax=cax, spacing="proportional", ticks=self.colorIndex) cbar.set_ticklabels(self.individual_names) else: # i.e. for color scheme for all bodyparts self.Colorscheme = visualization.get_cmap( len(self.all_bodyparts), self.cfg["colormap"]) self.norm, self.colorIndex = self.image_panel.getColorIndices( frame, self.all_bodyparts) cbar = self.figure.colorbar(self.ax, cax=cax, spacing="proportional", ticks=self.colorIndex) cbar.set_ticklabels(self.all_bodyparts) for ci, ind in enumerate(self.individual_names): col_idx = ( 0 ) # variable for iterating through the colorscheme for all bodyparts image_points = [] if ind == "single": if self.visualization_rdb.GetSelection() == 0: for c, bp in enumerate(self.uniquebodyparts): pts = self.Dataframe.xs( (ind, bp), level=("individuals", "bodyparts"), axis=1, ).values self.circle = patches.Circle( pts[self.currFrame, :2], radius=self.markerSize, fc=self.Colorscheme(ci), alpha=self.alpha, ) self.axes.add_patch(self.circle) else: for c, bp in enumerate(self.uniquebodyparts): pts = self.Dataframe.xs( (ind, bp), level=("individuals", "bodyparts"), axis=1, ).values self.circle = patches.Circle( pts[self.currFrame, :2], radius=self.markerSize, fc=self.Colorscheme(col_idx), alpha=self.alpha, ) self.axes.add_patch(self.circle) col_idx = col_idx + 1 else: if self.visualization_rdb.GetSelection() == 0: for c, bp in enumerate(self.multianimalbodyparts): pts = self.Dataframe.xs( (ind, bp), level=("individuals", "bodyparts"), axis=1, ).values self.circle = patches.Circle( pts[self.currFrame, :2], radius=self.markerSize, fc=self.Colorscheme(ci), alpha=self.alpha, ) self.axes.add_patch(self.circle) else: for c, bp in enumerate(self.multianimalbodyparts): pts = self.Dataframe.xs( (ind, bp), level=("individuals", "bodyparts"), axis=1, ).values self.circle = patches.Circle( pts[self.currFrame, :2], radius=self.markerSize, fc=self.Colorscheme(col_idx), alpha=self.alpha, ) self.axes.add_patch(self.circle) col_idx = col_idx + 1 self.figure.canvas.draw() else: self.norm, self.colorIndex = self.image_panel.getColorIndices( frame, self.bodyparts) cbar = self.figure.colorbar(self.ax, cax=cax, spacing="proportional", ticks=self.colorIndex) cbar.set_ticklabels(self.bodyparts) for bpindex, bp in enumerate(self.bodyparts): color = self.colormap(self.norm(self.colorIndex[bpindex])) self.points = [ self.Dataframe.xs((bp, "x"), level=(-2, -1), axis=1).values[self.currFrame], self.Dataframe.xs((bp, "y"), level=(-2, -1), axis=1).values[self.currFrame], 1.0, ] circle = [ patches.Circle( (self.points[0], self.points[1]), radius=self.markerSize, fc=color, alpha=self.alpha, ) ] self.axes.add_patch(circle[0]) self.figure.canvas.draw() else: print("Invalid frame") def helpButton(self, event): """ Opens Instructions """ wx.MessageBox( "1. Use the slider to select a frame in the entire video. \n\n2. Click Grab Frames button to save the specific frame.\ \n\n3. In the events where you need to extract a range of frames, then use the checkbox 'Range of frames' to select the starting frame index and the number of frames to extract.\ \n Click the update button to see the frame. Click Grab Frames to select the range of frames. \n\n Click OK to continue", "Instructions to use!", wx.OK | wx.ICON_INFORMATION, )
class PlotPanel3DPopulation(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) # Panel. panel_box = wx.BoxSizer(wx.VERTICAL) ## Canvas. self.figure = Figure() self.canvas = Canvas(self, -1, self.figure) self.axes = None panel_box.Add(self.canvas, 1, wx.EXPAND) self.SetSizer(panel_box) def plot_data(self, bd, cm=jet, xlabel=None, ylabel=None, zlabel=None): """ Plot energy level populations by temperature in 3D. bd: BoltzmannDistribution. cm: A matplotlib colormap. *label: Axis labels. """ if self.axes is not None: self.figure.delaxes(self.axes) self.axes = None self.axes = self.figure.gca(projection='3d') # Set up the data. xs = self._gen_temps() ys = bd.energies verts = [] # All the energy level populations at all the temperatures. populations = N.column_stack(bd.ps(x) for x in xs) for p in populations: # Add the points on the ends so that there is a bottom edge along # the polygon. points = [(xs[0], 0)] + list(zip(xs, p)) + [(xs[-1], 0)] verts.append(points) x_min, x_max = min(xs), max(xs) y_min, y_max = min(ys), max(ys) if y_max == y_min: colors = [cm(0.0) for i in bd.levels] else: colors = [cm((ys[i] - y_min) / (y_max - y_min)) for i in bd.levels] poly = PolyCollection(verts, facecolors=colors, linewidth=1.0, edgecolor='white') poly.set_alpha(0.7) # The directions here look somewhat confused, but that's just due to # the way the polygons are stacked. self.axes.add_collection3d(poly, zs=ys, zdir='y') if x_max == x_min: self.axes.set_xlim3d(x_min - 1, x_max + 1) else: self.axes.set_xlim3d(x_min, x_max) if y_max == y_min: self.axes.set_ylim3d(y_min - 1, y_max + 1) else: self.axes.set_ylim3d(y_min, y_max) self.axes.set_zlim3d(0, 1) if xlabel is not None: self.axes.set_xlabel(xlabel) if ylabel is not None: self.axes.set_ylabel(ylabel) if zlabel is not None: self.axes.set_zlabel(zlabel) self.figure.tight_layout() # Make sure that we redraw as the user drags. # # Using a list because we don't have nonlocal here. mouse_down = [False] def on_press(evt): mouse_down[0] = True def on_move(evt): if mouse_down[0]: self.canvas.draw() def on_release(evt): mouse_down[0] = False cid = self.canvas.mpl_connect('button_press_event', on_press) cid = self.canvas.mpl_connect('motion_notify_event', on_move) cid = self.canvas.mpl_connect('button_release_event', on_release) def _gen_temps(self): return N.linspace(0, 2000, 200)
class App: def __init__(self,master): frame = Frame(master) frame.pack() self.wdir = os.getcwd() + '/' self.I = pp.Image() self.enstep = Entry(frame,width=5) self.enstep.pack(side=LEFT) self.enstep.insert(0, "0") self.varkeys = self.loaddata().get_varinfo(w_dir=self.wdir)['allvars'] self.grid_dict= self.loaddata().grid(w_dir=self.wdir) self.ldatabutton=Button(frame,text="Load data",command=self.loaddata) self.ldatabutton.pack(side=LEFT) self.v = StringVar() self.v.set("rho") for variables in self.varkeys: self.ldata = Radiobutton(frame,text=variables,variable=self.v,value=variables,command=self.getmyvar) self.ldata.pack(side=LEFT) self.slvar = StringVar() self.slvar.set("Choose Slice") SliceList = ("Along x1","Along x2","Along x3","Along x1-x2","Along x2-x3","Along x3-x1") OptionMenu(frame, self.slvar, *SliceList, command=self.setslice).pack(side=LEFT) self.ex1 = Entry(frame,width=5) self.ex1.pack(side=LEFT) self.ex1.insert(0, "x1") self.ex2 = Entry(frame,width=5) self.ex2.pack(side=LEFT) self.ex2.insert(0, "x2") self.ex3 = Entry(frame,width=5) self.ex3.pack(side=LEFT) self.ex3.insert(0, "x3") self.xlb = Entry(frame,width=15) self.xlb.pack(side=LEFT) self.xlb.insert(0, "xlabel") self.ylb = Entry(frame,width=15) self.ylb.pack(side=LEFT) self.ylb.insert(0, "ylabel") self.logvar = IntVar() self.chkb = Checkbutton(frame,text="Enable Log",variable=self.logvar,onvalue=1,offvalue=0,command=self.logchkcall) self.chkb.pack(side=LEFT) self.polarvar = IntVar() self.polchkb = Checkbutton(frame,text="Polar",variable=self.polarvar,onvalue=1,offvalue=0,command=self.polchkcall) self.polchkb.pack(side=LEFT) # self.getplot= Button(frame,text='Plot',fg="black",command=self.plotfinal) # self.getplot.pack(side=LEFT) # place a graph somewhere here self.f = Figure(figsize=(8,8), dpi=100) self.a = self.f.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.f, master=root) self.canvas.show() self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1) #self.toolbar = NavigationToolbar2TkAgg(self.canvas,frame) #self.toolbar.update() #self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1) def loaddata(self): mynstep=int(self.enstep.get()) self.D = pp.pload(mynstep,w_dir=self.wdir) return self.D def getmyvar(self): self.myvar=self.v.get() def logchkcall(self): self.logchk = self.logvar.get() def polchkcall(self): self.polchk = self.polarvar.get() def setslice(self,event): self.slicename=self.slvar.get() def plotclear(self): self.a.clear() if len(self.f.axes)>1: self.f.delaxes(self.f.axes[1]) self.f.subplots_adjust(right=0.90) self.canvas.show() def plotfinal(self): if self.logvar.get() == 1: self.var = log10(self.D.__getattribute__(self.myvar)) else: self.var = self.D.__getattribute__(self.myvar) if self.slicename == "Along x1": self.x = self.D.x1 if self.grid_dict["n3"] == 1: self.var = self.var[:,int(self.ex2.get())] else: self.var = self.var[:,int(self.ex2.get()),int(self.ex3.get())] elif self.slicename == "Along x2": self.x = self.D.x2 if self.grid_dict["n3"] == 1: self.var = self.var[int(self.ex1.get()),:] else: self.var = self.var[int(self.ex1.get()),:,int(self.ex3.get())] else: self.x = self.D.x3 self.var = self.var[int(self.ex1.get()),int(self.ex2.get()),:] self.a.set_aspect('auto') self.a.plot(self.x,self.var) self.a.set_xlabel(self.xlb.get()) self.a.set_ylabel(self.ylb.get()) self.canvas.show() def plotsurface(self): if self.logvar.get() == 1: self.var = log10(self.D.__getattribute__(self.myvar)) else: self.var = self.D.__getattribute__(self.myvar) if self.slicename == "Along x1-x2": self.x = self.D.x1 self.y = self.D.x2 if self.grid_dict["n3"] == 1: self.var = self.var[:,:].T else: if self.polarvar.get() == 1: self.var = self.I.get_polar_plot(self.var[:,:,int(self.ex3.get())],rtheta=True) else: self.var = self.var[:,:,int(self.ex3.get())].T elif self.slicename == "Along x2-x3": self.x = self.D.x2 self.y = self.D.x3 self.var = self.var[int(self.ex1.get()),:,:].T else: self.x = self.D.x1 self.y = self.D.x3 if self.polarvar.get() == 1: self.var = self.I.get_polar_plot(self.var[:,int(self.ex2.get()),:],rphi=True) else: self.var = self.var[:,int(self.ex2.get()),:].T self.a.set_aspect('equal') if self.polarvar.get() == 1: # if self.slicename == "Along x1-x2":self.a.axis([0,max(self.D.n1),0,max(self.D.n2)]) #if self.slicename == "Along x3-x1":self.a.axis([0,max(self.D.n1),0,max(self.D.n3)]) self.image=self.a.pcolormesh(self.var,vmin=min(self.var),vmax=max(self.var)) else: self.a.axis([min(self.x),max(self.x),min(self.y),max(self.y)]) self.image=self.a.pcolormesh(self.x,self.y,self.var,vmin=min(self.var),vmax=max(self.var)) self.a.set_xlabel(self.xlb.get()) self.a.set_ylabel(self.ylb.get()) self.f.colorbar(self.image) self.canvas.show() def epssave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.eps') def pngsave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.png') def pdfsave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.pdf') def jpgsave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.jpg')
class Costmap2DFigure(FigureCanvas): costmap_changed = QtCore.Signal() """Implements an imshow figure for showing the costmap2d""" def __init__(self, costmap, parent=None, width=5.0, height=4.0, dpi=100, interpolation='nearest', show_start = True, show_goal = True, show_colorbar = True): self.lock = Lock() self.costmap = costmap self.freeze = False self.interpolation = interpolation self.fig = Figure(figsize=(width, height), dpi=dpi) self.axes = self.fig.add_subplot(1,1,1) # We want the axes cleared every time plot() is called self.axes.hold(False) self.show_start = show_start self.start_coord = (-0.5, -0.5) self.start = Rectangle(self.start_coord, 1, 1, color='g') self.show_goal = show_goal self.goal_coord = (self.costmap.width-1.5, self.costmap.height-1.5) self.goal = Rectangle(self.goal_coord, 1, 1, color='k') self.show_colorbar = show_colorbar self.compute_initial_figure() FigureCanvas.__init__(self, self.fig) self.setParent(parent) self.mpl_connect('button_release_event', self.on_mouse_release) FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) self.on_mouse_click = self.default_on_mouse_click # Idle control self.idle = True # Make Qt Connections self.connect_stuff() # Override costmap on change self.costmap.on_update = self.costmap_update_callback def on_mouse_release(self, e): """Gets called when a mouse button is released""" if self.on_mouse_click != None: self.on_mouse_click(e) def default_on_mouse_click(self, e): """Default function for mouse clicking""" if e.xdata == None or e.ydata == None: return from math import floor coord = (floor(e.xdata+0.5)-0.5, floor(e.ydata+0.5)-0.5) if -0.5 > coord[0] < self.costmap.width-1.5 or \ -0.5 > coord[1] < self.costmap.height-1.5: return if e.button == 1: self.start_coord = coord self.start = Rectangle(coord, 1, 1, color='g') elif e.button == 3: self.goal_coord = coord self.goal = Rectangle(coord, 1, 1, color='k') else: return self.on_map_update() def connect_stuff(self): """Make Qt connections""" self.costmap_changed.connect(self.on_map_update) def costmap_update_callback(self, key, val): """Callback to handle when the map is updated""" if self.idle: self.idle = False self.costmap_changed.emit() def compute_initial_figure(self): """Plot the imshow""" axes = self.axes.imshow(self.costmap.data.T, interpolation=self.interpolation) if self.show_colorbar: self.colorbar = self.fig.colorbar(axes) if self.show_start: self.axes.add_artist(self.start) if self.show_goal: self.axes.add_artist(self.goal) def on_map_update(self): """Slot to handle the costmap_changed signal""" if self.freeze: return self.lock.acquire() axes = self.axes.imshow(self.costmap.data.T, interpolation=self.interpolation) if self.show_colorbar: self.fig.delaxes(self.fig.axes[1]) self.fig.subplots_adjust(right=0.90) self.colorbar = self.fig.colorbar(axes) if self.show_start: self.axes.add_artist(self.start) if self.show_goal: self.axes.add_artist(self.goal) self.draw() self.idle = True self.lock.release()
class Qt4MplCanvas(FigureCanvas): """ A customized Qt widget for matplotlib figure. It can be used to replace GraphicsView of QtGui """ def __init__(self, parent): """ Initialization """ # Instantiate matplotlib Figure self.fig = Figure() self.fig.patch.set_facecolor('white') self.axes = self.fig.add_subplot( 111) # return: matplotlib.axes.AxesSubplot # Initialize parent class and set parent FigureCanvas.__init__(self, self.fig) self.setParent(parent) # Set size policy to be able to expanding and resizable with frame FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) # Variables to manage all lines/subplot self._lineDict = {} self._lineIndex = 0 # legend and color bar self.colorBar = None # self._myLegend = None return def add_plot1d(self, vec_x, vec_y, color=None, label="", x_label=None, y_label=None, marker=None, line_style=None, line_width=1, y_err=None): """ Add a 1D plot (line) to canvas :param vec_x: :param vec_y: :param color: :param label: :param x_label: :param y_label: :param marker: :param line_style: :param line_width: :param y_err: :return: """ # Check input if isinstance(vec_x, np.ndarray) is False or isinstance( vec_y, np.ndarray) is False: raise NotImplementedError( 'Input vec_x or vec_y for addPlot() must be numpy.array.') plot_error = y_err is not None if plot_error is True: if isinstance(y_err, np.ndarray) is False: raise NotImplementedError( 'Input y_err must be either None or numpy.array.') if len(vec_x) != len(vec_y): raise NotImplementedError( 'Input vec_x and vec_y must have same size.') if plot_error is True and len(y_err) != len(vec_x): raise NotImplementedError( 'Input vec_x, vec_y and y_error must have same size.') # Hold previous data self.axes.hold(True) # process inputs and defaults # self.x = vec_x # self.y = vec_y if color is None: color = (0, 1, 0, 1) if marker is None: marker = 'o' if line_style is None: line_style = '-' # color must be RGBA (4-tuple) if plot_error is False: r = self.axes.plot(vec_x, vec_y, color=color, marker=marker, linestyle=line_style, label=label, linewidth=line_width) # return: list of matplotlib.lines.Line2D object else: r = self.axes.errorbar(vec_x, vec_y, yerr=y_err, color=color, marker=marker, linestyle=line_style, label=label, linewidth=line_width) self.axes.set_aspect('auto') # set x-axis and y-axis label if x_label is not None: self.axes.set_xlabel(x_label, fontsize=20) if y_label is not None: self.axes.set_ylabel(y_label, fontsize=20) # set/update legend self._setupLegend() # Register if plot_error is True and len(r) == 3: # plot line with error bar. r[1] contains all lines self._lineDict[self._lineIndex] = r elif plot_error is False and len(r) == 1: # regular line self._lineDict[self._lineIndex] = r[0] else: print "Impoooooooooooooooosible! Number of returned tuple is %d" % ( len(r)) dbmsg = '' for sub_r in r: dbmsg += 'Type: %s, Value: %s\n' % (str( type(sub_r)), str(sub_r)) print dbmsg self._lineIndex += 1 # Flush/commit self.draw() return def addPlot2D(self, array2d, xmin, xmax, ymin, ymax, holdprev, yticklabels=None): """ Add a 2D plot Arguments: - yticklabels :: list of string for y ticks """ # Release the current image self.axes.hold(holdprev) # Do plot # y ticks will be shown on line 1, 4, 23, 24 and 30 # yticks = [1, 4, 23, 24, 30] # self.axes.set_yticks(yticks) print "[DBNOW] Before imshow(), number of axes = %d" % (len( self.fig.axes)) # show image imgplot = self.axes.imshow(array2d, extent=[xmin, xmax, ymin, ymax], interpolation='none') print "[DBNOW] After imshow(), number of axes = %d" % (len( self.fig.axes)) # set y ticks as an option: if yticklabels is not None: # it will always label the first N ticks even image is zoomed in print "--------> [FixMe]: Set up the Y-axis ticks is erroreous" #self.axes.set_yticklabels(yticklabels) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self.colorBar is None: # set color map type imgplot.set_cmap('spectral') self.colorBar = self.fig.colorbar(imgplot) else: self.colorBar.update_bruteforce(imgplot) print "[DBNOW] After colorbar is added, number of axes = %d" % (len( self.fig.axes)) # Flush... self._flush() return def addImage(self, imagefilename): """ Add an image by file """ #import matplotlib.image as mpimg # set aspect to auto mode self.axes.set_aspect('auto') img = matplotlib.image.imread(str(imagefilename)) # lum_img = img[:,:,0] # FUTURE : refactor for image size, interpolation and origin imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') # Set color bar. plt.colorbar() does not work! if self.colorBar is None: # set color map type imgplot.set_cmap('spectral') self.colorBar = self.fig.colorbar(imgplot) else: self.colorBar.update_bruteforce(imgplot) self._flush() return def clearAllLines(self): """ Remove all lines from the canvas """ for ikey in self._lineDict.keys(): plot = self._lineDict[ikey] if plot is None: continue if isinstance(plot, tuple) is False: try: self.axes.lines.remove(plot) except ValueError as e: print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % ( str(plot), len(self.axes.lines), str(e)) self._lineDict[ikey] = None else: # error bar plot[0].remove() for line in plot[1]: line.remove() for line in plot[2]: line.remove() self._lineDict[ikey] = None # ENDIF(plot) # ENDFOR # Remove legend # only appied in new version of matplotlib # if self._myLegend is not None: # self._myLegend.remove() self._setupLegend() self.draw() return def clearCanvas(self): """ Clear data including lines and image from canvas """ # clear the image for next operation self.axes.hold(False) # Clear all lines self.clearAllLines() # clear image self.axes.cla() # Try to clear the color bar if len(self.fig.axes) > 1: self.fig.delaxes(self.fig.axes[1]) self.colorBar = None # This clears the space claimed by color bar but destroys sub_plot too. self.fig.clear() # Re-create subplot self.axes = self.fig.add_subplot(111) if len(self.fig.axes) > 0: print "[DBNOW] Type of axes[0] = %s" % (str(type( self.fig.axes[0]))) # flush/commit self._flush() return def getLastPlotIndexKey(self): """ Get the index/key of the last added line """ return self._lineIndex - 1 def getPlot(self): """ reture figure's axes to expose the matplotlib figure to PyQt client """ return self.axes def getXLimit(self): """ Get limit of Y-axis """ return self.axes.get_xlim() def getYLimit(self): """ Get limit of Y-axis """ return self.axes.get_ylim() def setXYLimit(self, xmin, xmax, ymin, ymax): """ """ # for X xlims = self.axes.get_xlim() xlims = list(xlims) if xmin is not None: xlims[0] = xmin if xmax is not None: xlims[1] = xmax self.axes.set_xlim(xlims) # for Y ylims = self.axes.get_ylim() ylims = list(ylims) if ymin is not None: ylims[0] = ymin if ymax is not None: ylims[1] = ymax self.axes.set_ylim(ylims) # try draw self.draw() return def removePlot(self, ikey): """ Remove the line with its index as key """ # self._lineDict[ikey].remove() lines = self.axes.lines print str(type(lines)), lines print "ikey = ", ikey, self._lineDict[ikey] self.axes.lines.remove(self._lineDict[ikey]) #self.axes.remove(self._lineDict[ikey]) print self._lineDict[ikey] self._lineDict[ikey] = None return def updateLine(self, ikey, vecx, vecy, linestyle=None, linecolor=None, marker=None, markercolor=None): """ """ line = self._lineDict[ikey] if vecx is not None and vecy is not None: line.set_xdata(vecx) line.set_ydata(vecy) if linecolor is not None: line.set_color(linecolor) if linestyle is not None: line.set_linestyle(linestyle) if marker is not None: line.set_marker(marker) if markercolor is not None: line.set_markerfacecolor(markercolor) oldlabel = line.get_label() line.set_label(oldlabel) self.axes.legend() # commit self.draw() return def getLineStyleList(self): """ """ return MplLineStyles def getLineMarkerList(self): """ """ return MplLineMarkers def getLineBasicColorList(self): """ """ return MplBasicColors def getDefaultColorMarkerComboList(self): """ Get a list of line/marker color and marker style combination as default to add more and more line to plot """ combolist = [] nummarkers = len(MplLineMarkers) numcolors = len(MplBasicColors) for i in xrange(nummarkers): marker = MplLineMarkers[i] for j in xrange(numcolors): color = MplBasicColors[j] combolist.append((marker, color)) # ENDFOR (j) # ENDFOR(i) return combolist def _flush(self): """ A dirty hack to flush the image """ w, h = self.get_width_height() self.resize(w + 1, h) self.resize(w, h) return def _setupLegend(self, location='best'): """ Set up legend self.axes.legend() Handler is a Line2D object. Lable maps to the line object """ loclist = [ "best", "upper right", "upper left", "lower left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center" ] # Check legend location valid or not if location not in loclist: location = 'best' handles, labels = self.axes.get_legend_handles_labels() # self._myLegend = self.axes.legend(handles, labels, loc=location) # print handles # print labels #self.axes.legend(self._myLegendHandlers, self._myLegentLabels) return
class CutePlot(QMainWindow): def __init__(self, parent=None): super(CutePlot, self).__init__(parent) # Default values for lower and upper bound self.LB_default = -10 self.UB_default = 10 # Create main plot area + menus + status bar self.create_main_frame() #self.textbox.setText() self.LB_UB_defaults() self.on_draw() self.statusBar() self.setWindowTitle('Graficador') self.create_menu() self.guardarImagen() def LB_UB_defaults(self): # Set default values for lower bound and upper bound self.lowerbound.setText(str(self.LB_default)) self.upperbound.setText(str(self.UB_default)) def create_main_frame(self): self.main_frame = QWidget() # 7x5 inches, 80 dots-per-inch self.dpi = 80 self.fig = Figure((7, 5), dpi = self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.main_frame) self.guardarImagen() self.is_data = False self.axes = self.fig.add_subplot(111) # axis_state keeps track of how many subplots are present # axis_state = 0: main plot only # axis_state = 1: horizontal split (quadrants 1 and 2) # axis_state = 2: vertical split (quadrants 1 and 4) # axis_state = 3: show all 4 subplots self.axis_state = 0 self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame) # f(x) textbox self.title = QLabel('<font size=4><em>f</em> (<em>x </em>) =</font>') self.textbox = QLineEdit() self.textbox.setMinimumWidth(200) self.connect(self.textbox, SIGNAL('returnPressed()'), self.on_draw) # Lowerbound and upperbound textboxes self.LB_title = QLabel('<font size=4>Min:</font>') self.lowerbound = QLineEdit() self.lowerbound.setMaximumWidth(30) self.connect(self.lowerbound, SIGNAL('returnPressed()'), self.on_draw) self.UB_title = QLabel('<font size=4>Max:</font>') self.upperbound = QLineEdit() self.upperbound.setMaximumWidth(30) self.connect(self.upperbound, SIGNAL('returnPressed()'), self.on_draw) # Plot button self.draw_button = QPushButton("&Plot") self.connect(self.draw_button, SIGNAL('clicked()'), self.on_draw) # Hold checkbox self.hold_cb = QCheckBox("&Hold") self.hold_cb.setChecked(False) self.connect(self.hold_cb, SIGNAL('stateChanged(int)'), self.on_minor_change) self.hold_cb.setToolTip('Prevent new plots from replacing old ones') self.hold_cb.setStatusTip('Prevent new plots from replacing old ones') # Log-x and log-y checkboxes self.logx_cb = QCheckBox("Log-&x") self.logx_cb.setChecked(False) self.connect(self.logx_cb, SIGNAL('stateChanged(int)'), self.on_draw) self.logx_cb.setToolTip('Change x-axis to logarithmic scale') self.logx_cb.setStatusTip('Change x-axis to logarithmic scale') self.logy_cb = QCheckBox("Log-&y") self.logy_cb.setChecked(False) self.connect(self.logy_cb, SIGNAL('stateChanged(int)'), self.on_draw) self.logy_cb.setToolTip('Change y-axis to logarithmic scale') self.logy_cb.setStatusTip('Change y-axis to logarithmic scale') # Truncated-log checkbox self.trunc_cb = QCheckBox("Show &Negative") self.trunc_cb.setChecked(False) self.connect(self.trunc_cb, SIGNAL('stateChanged(int)'), self.on_draw) self.trunc_cb.setToolTip('Plot negative values of log-transformed functions') self.trunc_cb.setStatusTip('Plot negative values of log-transformed functions') # Grid checkbox self.grid_cb = QCheckBox("&Grid") self.grid_cb.setChecked(False) self.connect(self.grid_cb, SIGNAL('stateChanged(int)'), self.on_minor_change) self.grid_cb.setToolTip('Show grid') self.grid_cb.setStatusTip('Show grid') # Grid layout grid = QGridLayout() grid.setSpacing(10) gridCol = 0 for w in [self.title, self.textbox, self.LB_title, self.lowerbound, self.UB_title, self.upperbound, self.draw_button]: grid.addWidget(w, 0, gridCol) gridCol += 1 grid2 = QGridLayout() grid2.setSpacing(10) gridCol = 0 for w in [self.logx_cb, self.logy_cb, self.trunc_cb, self.hold_cb, self.grid_cb]: grid2.addWidget(w, 0, gridCol) gridCol += 1 vbox = QVBoxLayout() vbox.addLayout(grid) vbox.addLayout(grid2) vbox.addWidget(self.canvas) vbox.addWidget(self.mpl_toolbar) self.main_frame.setLayout(vbox) self.setCentralWidget(self.main_frame) def on_minor_change(self): self.on_draw(self.is_data) def on_draw(self, *args): # Get x-domain from user input self.LB_input = unicode(self.lowerbound.text()) self.UB_input = unicode(self.upperbound.text()) # Message box error if the domain inputs aren't int or float types # If float, round to the nearest 0.1 round_to = 10 try: self.LB_float = int(self.LB_input)*round_to self.UB_float = int(self.UB_input)*round_to except: self.LB_UB_defaults() QMessageBox.question(self, 'Error', '<center>Minimum and maximum values must be<br />\ integer or floating-point numbers.</center>', QMessageBox.Ok) # Make sure UB > LB if self.UB_float <= self.LB_float: self.LB_UB_defaults() QMessageBox.question(self, 'Error', '<center>Maximum must be greater\ than minimum value.</center>', QMessageBox.Ok) # If plotting a function, then get x and y values if len(args) == 0: self.is_data = False # Set x values (/round_to is to use range() with floating-point numbers) self.input_x = range(self.LB_float, self.UB_float + 1) self.input_x = [i/float(round_to) for i in self.input_x] # Calculate f(x) values for specified function fx = unicode(self.textbox.text()) # If the f(x) field is empty, then default to y = 0 plot if fx == '': self.y = [0 for i in self.input_x] # Otherwise, evaluate the specified function and get ready to plot else: # Replace exp with numbers fx = fx.replace('exp', str(exp(1)) + '**') # Allow users to enter ^ for powers (replace ^ with **) fx = fx.replace('^', '**') # Try and evaluate; if there is an error, then shift slightly to the right try: self.y = [eval(fx) for x in self.input_x] except: fx = fx.replace('x', '(x + 10**(-6))') self.y = [eval(fx) for x in self.input_x] self.plot_symbol = '-' if self.is_data: self.plot_symbol = 'o' # If the hold box is checked, then new plots do not erase old ones new_state = self.quad_check() if self.axis_state == 0: self.axes.hold(self.hold_cb.isChecked()) else: if self.hold_cb.isChecked(): # If 'hold' is checked, see what quadrants will be shown # - if the quadrant state changes, remove subplots # - otherwise retain subplots if self.axis_state == 0 and new_state == 0: self.axes.hold(self.hold_cb.isChecked()) elif self.axis_state == 3 and new_state == 3: self.axes_Q1.hold(self.hold_cb.isChecked()) self.axes_Q2.hold(self.hold_cb.isChecked()) self.axes_Q3.hold(self.hold_cb.isChecked()) self.axes_Q4.hold(self.hold_cb.isChecked()) elif self.axis_state == 1 and new_state == 1: self.axes_Q1.hold(self.hold_cb.isChecked()) self.axes_Q2.hold(self.hold_cb.isChecked()) elif self.axis_state == 2 and new_state == 2: self.axes_Q1.hold(self.hold_cb.isChecked()) self.axes_Q4.hold(self.hold_cb.isChecked()) else: self.remove_subplots() else: self.remove_subplots() # If show negative box is unchecked if not self.trunc_cb.isChecked(): self.add_main() self.axes.plot(self.input_x, self.y, self.plot_symbol) if not self.logx_cb.isChecked() and not self.logy_cb.isChecked(): self.axes.set_xscale('linear') self.axes.set_yscale('linear') elif self.logx_cb.isChecked() and not self.logy_cb.isChecked(): self.axes.set_xscale('log') self.axes.set_yscale('linear') elif not self.logx_cb.isChecked() and self.logy_cb.isChecked(): self.axes.set_xscale('linear') self.axes.set_yscale('log') else: self.axes.set_xscale('log') self.axes.set_yscale('log') else: # Linear plot #if not self.logx_cb.isChecked() and not self.logy_cb.isChecked(): if new_state == 0: self.add_main() self.axes.plot(self.input_x,self.y,self.plot_symbol) # Log x, linear y plot #elif self.logx_cb.isChecked() and not self.logy_cb.isChecked(): elif new_state == 1: if not self.trunc_cb.isChecked(): self.add_main() self.axes.semilogx(self.input_x,self.y,self.plot_symbol) else: self.trunc_logx() # Linear x, log y plot #elif not self.logx_cb.isChecked() and self.logy_cb.isChecked(): elif new_state == 2: if not self.trunc_cb.isChecked(): self.add_main() self.axes.semilogy(self.input_x,self.y,self.plot_symbol) else: self.trunc_logy() # Log-log plot else: if not self.trunc_cb.isChecked(): self.add_main() self.axes.loglog(self.input_x,self.y,self.plot_symbol) else: self.trunc_loglog() # Add grid if grid checkbox is checked if self.axis_state == 0: self.axes.grid(self.grid_cb.isChecked()) else: if hasattr(self, 'axes_Q1'): self.axes_Q1.grid(self.grid_cb.isChecked()) if hasattr(self, 'axes_Q2'): self.axes_Q2.grid(self.grid_cb.isChecked()) if hasattr(self, 'axes_Q3'): self.axes_Q3.grid(self.grid_cb.isChecked()) if hasattr(self, 'axes_Q4'): self.axes_Q4.grid(self.grid_cb.isChecked()) self.axes.set_xlabel('$x$') self.axes.set_ylabel('$f(x)$') self.canvas.draw() self.guardarImagen() def remove_subplots(self): # Remove all subplots and axis flip flags if hasattr(self, 'axes_Q1'): self.fig.delaxes(self.axes_Q1) del self.axes_Q1 if hasattr(self, 'axes_Q2'): self.fig.delaxes(self.axes_Q2) del self.axes_Q2 if hasattr(self, 'flip_Q2'): del self.flip_Q2 if hasattr(self, 'axes_Q3'): self.fig.delaxes(self.axes_Q3) del self.axes_Q3 del self.flip_Q3 if hasattr(self, 'axes_Q4'): self.fig.delaxes(self.axes_Q4) del self.axes_Q4 if hasattr(self, 'flip_Q4'): del self.flip_Q4 def add_main(self): # Reinsert the main plot if self.axis_state > 0: self.remove_subplots() self.axes = self.fig.add_subplot(111) self.axis_state = 0 def create_menu(self): exitAction = QAction('Quit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(self.close) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') save_plot_action = self.create_action("&Save plot", shortcut = "Ctrl+S", slot = self.save_plot, tip = "Save image to file") import_data_action = self.create_action("&Import data", shortcut = "Ctrl+I", slot = self.import_data, tip = "Import data from file") fileMenu.addAction(save_plot_action) fileMenu.addAction(import_data_action) fileMenu.addAction(exitAction) helpMenu = self.menuBar().addMenu("&Help") about_action = self.create_action("&About", shortcut = 'F1', slot = self.on_about, tip = 'About CutePlot') helpMenu.addAction(about_action) def create_action(self, text, slot = None, shortcut = None, icon = None, tip = None, checkable = False, signal = "triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def save_plot(self): file_choices = "PNG (*.png)" path = unicode(QFileDialog.getSaveFileName(self, 'Save file', '', file_choices)) if path: self.canvas.print_figure(path, dpi = self.dpi) self.statusBar().showMessage('Saved to %s' % path, 2000) def import_data(self): file_choices = "*.csv;;*.txt;;*.tab;;*.dat;;*.*" self.path = QFileDialog.getOpenFileName(self, 'Import data', '', file_choices) if self.path: datafile = open(self.path[0], 'r') if datafile: self.is_data = True delimiter = ',' input_xy = [map(float, line.strip().split(delimiter)) for line in datafile] self.input_x, self.y = [[row[col] for row in input_xy] for col in [0, 1]] datafile.close() self.statusBar().showMessage('Imported data', 2000) self.on_draw(self.is_data) def on_about(self): msg = """<center><b>CutePlot v. 0.1</b></center> <center>Free, open-source plotting program,<br /> written in Python (PySide/Qt + matplotlib).</center> <center>(c) Jack Peterson, 2012</center> """ QMessageBox.about(self, "About", msg.strip()) def quad_check(self): # Q = quadrant Q1 = False Q2 = False Q3 = False Q4 = False # Split the x and y values by sign for j in range(0, len(self.input_x)): if self.input_x[j] > 0 and self.y[j] > 0: Q1 = True elif self.input_x[j] < 0 and self.y[j] > 0: Q2 = True elif self.input_x[j] < 0 and self.y[j] < 0: Q3 = True elif self.input_x[j] > 0 and self.y[j] < 0: Q4 = True if (Q3 or (Q2 and Q4) or ((Q2 or Q4) and self.axis_state == 3)) and self.logx_cb.isChecked() and self.logy_cb.isChecked(): new_state = 3 elif (Q2 and self.logx_cb.isChecked()) or (self.hold_cb.isChecked() and self.axis_state == 1): new_state = 1 elif (Q4 and self.logy_cb.isChecked()) or (self.hold_cb.isChecked() and self.axis_state == 2): new_state = 2 else: new_state = 0 return new_state def trunc_logx(self): # Q = quadrant Q1_x = [] Q1_y = [] Q2_x = [] Q2_y = [] # Split the x and y values by sign for j in range(0, len(self.input_x)): if self.input_x[j] > 0 and self.y[j] > 0: Q1_x.append(self.input_x[j]) Q1_y.append(self.y[j]) elif self.input_x[j] < 0 and self.y[j] > 0: Q2_x.append(-self.input_x[j]) Q2_y.append(self.y[j]) # If only Q1 is populated, then use an ordinary semilogx plot if Q2_x == [] and not self.hold_cb.isChecked(): self.add_main() self.axes.semilogx(self.input_x, self.y, self.plot_symbol) # Otherwise, create a truncated plot else: # Remove main axes if self.axis_state == 0: self.fig.delaxes(self.axes) if self.axis_state == 2 or self.axis_state == 3: self.axis_state = 3 else: self.axis_state = 1 # Create 2 subplots self.axes_Q1 = self.fig.add_subplot(122) self.axes_Q2 = self.fig.add_subplot(121) self.axes_Q1.autoscale(enable = True) self.axes_Q2.autoscale(enable = True) self.axes_Q1.semilogx(Q1_x, Q1_y, self.plot_symbol) self.axes_Q2.semilogx(Q2_x, Q2_y, self.plot_symbol) # Reverse Q2 x-axis if not hasattr(self, 'flip_Q2'): self.flip_Q2 = True self.axes_Q2.set_xlim(self.axes_Q2.get_xlim()[::-1]) # Set axis tickmarks at powers of 10 # Q1 axes if Q1_x == [] and not self.hold_cb.isChecked(): self.axes_Q1.set_xticklabels([]) else: try: x_UB_Q1 = int(ceil(log10(max(Q1_x)))) x_LB_Q1 = int(floor(log10(min(Q1_x)))) except: x_UB_Q1 = 2 x_LB_Q1 = -1 Q1_xlabels = [] for i in range(x_LB_Q1, x_UB_Q1 + 1): Q1_xlabels.append('$10^{%s}$' % str(i)) self.axes_Q1.set_xticklabels(Q1_xlabels) self.axes_Q1.xaxis.tick_bottom() self.axes_Q1.yaxis.tick_right() # Q2 axes if Q2_x == [] and not self.hold_cb.isChecked(): self.axes_Q2.set_xticklabels([]) else: try: x_UB_Q2 = int(ceil(log10(max(Q2_x)))) x_LB_Q2 = int(floor(log10(min(Q2_x)))) except: x_UB_Q2 = 2 x_LB_Q2 = -1 Q2_xlabels = [] for i in range(x_LB_Q2, x_UB_Q2 + 1): Q2_xlabels.append('$-10^{%s}$' % str(i)) self.axes_Q2.set_xticklabels(Q2_xlabels) self.axes_Q2.xaxis.tick_bottom() self.axes_Q2.yaxis.tick_left() def trunc_logy(self): # Q = quadrant Q1_x = [] Q1_y = [] Q4_x = [] Q4_y = [] # Split the x and y values by sign for j in range(0, len(self.input_x)): if self.input_x[j] > 0 and self.y[j] > 0: Q1_x.append(self.input_x[j]) Q1_y.append(self.y[j]) elif self.input_x[j] > 0 and self.y[j] < 0: Q4_x.append(self.input_x[j]) Q4_y.append(-self.y[j]) # If only Q1 is populated, then use an ordinary semilogy plot if Q4_x == [] and not self.hold_cb.isChecked(): self.add_main() self.axes.semilogy(self.input_x, self.y, self.plot_symbol) # Otherwise, create a truncated plot else: # Remove main axes if self.axis_state == 0: self.fig.delaxes(self.axes) if self.axis_state == 1 or self.axis_state == 3: self.axis_state = 3 else: self.axis_state = 2 # Create 2 subplots self.axes_Q1 = self.fig.add_subplot(211) self.axes_Q4 = self.fig.add_subplot(212) self.axes_Q1.autoscale(enable = True) self.axes_Q4.autoscale(enable = True) self.axes_Q1.semilogy(Q1_x, Q1_y, self.plot_symbol) self.axes_Q4.semilogy(Q4_x, Q4_y, self.plot_symbol) # Reverse Q4 y-axis if not hasattr(self, 'flip_Q4'): self.flip_Q4 = True self.axes_Q4.set_ylim(self.axes_Q4.get_ylim()[::-1]) # Set axis tickmarks at powers of 10 # Q1 axes if Q1_x == [] and not self.hold_cb.isChecked(): self.axes_Q1.set_yticklabels([]) else: try: y_UB_Q1 = int(ceil(log10(max(Q1_y)))) y_LB_Q1 = int(floor(log10(min(Q1_y)))) except: y_UB_Q1 = 2 y_LB_Q1 = -1 Q1_ylabels = [] for i in range(y_LB_Q1, y_UB_Q1 + 1): Q1_ylabels.append('$10^{%s}$' % str(i)) self.axes_Q1.set_yticklabels(Q1_ylabels) self.axes_Q1.xaxis.tick_top() self.axes_Q1.yaxis.tick_right() # Q4 axes if Q4_x == [] and not self.hold_cb.isChecked(): self.axes_Q4.set_yticklabels([]) else: try: y_UB_Q4 = int(ceil(log10(max(Q4_y)))) y_LB_Q4 = int(floor(log10(min(Q4_y)))) except: y_UB_Q4 = 2 y_LB_Q4 = -1 Q4_ylabels = [] for i in range(y_LB_Q4, y_UB_Q4 + 1): Q4_ylabels.append('$-10^{%s}$' % str(i)) self.axes_Q4.set_yticklabels(Q4_ylabels) self.axes_Q4.xaxis.tick_bottom() self.axes_Q4.yaxis.tick_right() def trunc_loglog(self): # Q = quadrant Q1_x = [] Q1_y = [] Q2_x = [] Q2_y = [] Q3_x = [] Q3_y = [] Q4_x = [] Q4_y = [] # Split the x and y values by sign for j in range(0, len(self.input_x)): if self.input_x[j] > 0 and self.y[j] > 0: Q1_x.append(self.input_x[j]) Q1_y.append(self.y[j]) elif self.input_x[j] < 0 and self.y[j] > 0: Q2_x.append(-self.input_x[j]) Q2_y.append(self.y[j]) elif self.input_x[j] < 0 and self.y[j] < 0: Q3_x.append(-self.input_x[j]) Q3_y.append(-self.y[j]) elif self.input_x[j] > 0 and self.y[j] < 0: Q4_x.append(self.input_x[j]) Q4_y.append(-self.y[j]) # If only Q1 is populated, then use an ordinary loglog plot if Q2_x == [] and Q3_x == [] and Q4_x == [] and not self.hold_cb.isChecked(): self.add_main() self.axes.loglog(self.input_x, self.y, self.plot_symbol) # Otherwise, create a truncated plot else: # Remove main axes if self.axis_state == 0: self.fig.delaxes(self.axes) self.axis_state = 3 # Create 4 subplots self.axes_Q1 = self.fig.add_subplot(222) self.axes_Q2 = self.fig.add_subplot(221) self.axes_Q3 = self.fig.add_subplot(223) self.axes_Q4 = self.fig.add_subplot(224) self.axes_Q1.autoscale(enable = True) self.axes_Q2.autoscale(enable = True) self.axes_Q3.autoscale(enable = True) self.axes_Q4.autoscale(enable = True) self.axes_Q1.loglog(Q1_x, Q1_y, self.plot_symbol) self.axes_Q2.loglog(Q2_x, Q2_y, self.plot_symbol) self.axes_Q3.loglog(Q3_x, Q3_y, self.plot_symbol) self.axes_Q4.loglog(Q4_x, Q4_y, self.plot_symbol) if not hasattr(self, 'flip_Q3'): self.flip_Q3 = True # Reverse Q2 x-axis self.axes_Q2.set_xlim(self.axes_Q2.get_xlim()[::-1]) # Reverse Q3 x- and y-axes self.axes_Q3.set_xlim(self.axes_Q3.get_xlim()[::-1]) self.axes_Q3.set_ylim(self.axes_Q3.get_ylim()[::-1]) # Reverse Q4 y-axis self.axes_Q4.set_ylim(self.axes_Q4.get_ylim()[::-1]) # Set axis tickmarks at powers of 10 # Q1 axes if Q1_x == [] and not self.hold_cb.isChecked(): self.axes_Q1.set_xticklabels([]) self.axes_Q1.set_yticklabels([]) else: try: x_UB_Q1 = int(ceil(log10(max(Q1_x)))) y_UB_Q1 = int(ceil(log10(max(Q1_y)))) x_LB_Q1 = int(floor(log10(min(Q1_x)))) y_LB_Q1 = int(floor(log10(min(Q1_y)))) except: x_UB_Q1 = 2 y_UB_Q1 = 2 x_LB_Q1 = -1 y_LB_Q1 = -1 Q1_xlabels = [] Q1_ylabels = [] for i in range(x_LB_Q1, x_UB_Q1 + 1): Q1_xlabels.append('$10^{%s}$' % str(i)) for i in range(y_LB_Q1, y_UB_Q1 + 1): Q1_ylabels.append('$10^{%s}$' % str(i)) self.axes_Q1.set_xticklabels(Q1_xlabels) self.axes_Q1.set_yticklabels(Q1_ylabels) self.axes_Q1.xaxis.tick_top() self.axes_Q1.yaxis.tick_right() # Q2 axes if Q2_x == [] and not self.hold_cb.isChecked(): self.axes_Q2.set_xticklabels([]) self.axes_Q2.set_yticklabels([]) else: try: x_UB_Q2 = int(ceil(log10(max(Q2_x)))) y_UB_Q2 = int(ceil(log10(max(Q2_y)))) x_LB_Q2 = int(floor(log10(min(Q2_x)))) y_LB_Q2 = int(floor(log10(min(Q2_y)))) except: x_UB_Q2 = 2 y_UB_Q2 = 2 x_LB_Q2 = -1 y_LB_Q2 = -1 Q2_xlabels = [] Q2_ylabels = [] for i in range(x_LB_Q2, x_UB_Q2 + 1): Q2_xlabels.append('$-10^{%s}$' % str(i)) for i in range(y_LB_Q2, y_UB_Q2 + 1): Q2_ylabels.append('$10^{%s}$' % str(i)) self.axes_Q2.set_xticklabels(Q2_xlabels) self.axes_Q2.set_yticklabels(Q2_ylabels) self.axes_Q2.xaxis.tick_top() self.axes_Q2.yaxis.tick_left() # Q3 axes if Q3_x == [] and not self.hold_cb.isChecked(): self.axes_Q3.set_xticklabels([]) self.axes_Q3.set_yticklabels([]) else: try: x_UB_Q3 = int(ceil(log10(max(Q3_x)))) y_UB_Q3 = int(ceil(log10(max(Q3_y)))) x_LB_Q3 = int(floor(log10(min(Q3_x)))) y_LB_Q3 = int(floor(log10(min(Q3_y)))) except: x_UB_Q3 = 2 y_UB_Q3 = 2 x_LB_Q3 = -1 y_LB_Q3 = -1 Q3_xlabels = [] Q3_ylabels = [] for i in range(x_LB_Q3, x_UB_Q3 + 1): Q3_xlabels.append('$-10^{%s}$' % str(i)) for i in range(y_LB_Q3, y_UB_Q3 + 1): Q3_ylabels.append('$-10^{%s}$' % str(i)) self.axes_Q3.set_xticklabels(Q3_xlabels) self.axes_Q3.set_yticklabels(Q3_ylabels) self.axes_Q3.xaxis.tick_bottom() self.axes_Q3.yaxis.tick_left() # Q4 axes if Q4_x == [] and not self.hold_cb.isChecked(): self.axes_Q4.set_xticklabels([]) self.axes_Q4.set_yticklabels([]) else: try: x_UB_Q4 = int(ceil(log10(max(Q4_x)))) y_UB_Q4 = int(ceil(log10(max(Q4_y)))) x_LB_Q4 = int(floor(log10(min(Q4_x)))) y_LB_Q4 = int(floor(log10(min(Q4_y)))) except: x_UB_Q4 = 2 y_UB_Q4 = 2 x_LB_Q4 = -1 y_LB_Q4 = -1 Q4_xlabels = [] Q4_ylabels = [] for i in range(x_LB_Q4, x_UB_Q4 + 1): Q4_xlabels.append('$10^{%s}$' % str(i)) for i in range(y_LB_Q4, y_UB_Q4 + 1): Q4_ylabels.append('$-10^{%s}$' % str(i)) self.axes_Q4.set_xticklabels(Q4_xlabels) self.axes_Q4.set_yticklabels(Q4_ylabels) self.axes_Q4.xaxis.tick_bottom() self.axes_Q4.yaxis.tick_right() def guardarImagen(self): path = os.path.abspath("untitled.png") self.canvas.resize(460,261 ) self.canvas.print_figure(path, dpi = self.dpi) self.statusBar().showMessage('Saved to %s' % path, 2000) self.canvas.resize(560,361 )
class MainFrame(wx.Frame): """Contains the main GUI and button boxes""" def __init__(self, parent,config,slider_width=25): # Settting the GUI size and panels design displays = (wx.Display(i) for i in range(wx.Display.GetCount())) # Gets the number of displays screenSizes = [display.GetGeometry().GetSize() for display in displays] # Gets the size of each display index = 0 # For display 1. screenWidth = screenSizes[index][0] screenHeight = screenSizes[index][1] self.gui_size = (screenWidth*0.7,screenHeight*0.85) wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = 'DeepLabCut2.0 - Manual Frame Extraction', size = wx.Size(self.gui_size), pos = wx.DefaultPosition, style = wx.RESIZE_BORDER|wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) self.statusbar = self.CreateStatusBar() self.statusbar.SetStatusText("") self.SetSizeHints(wx.Size(self.gui_size)) # This sets the minimum size of the GUI. It can scale now! ################################################################################################################################################### # Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting! topSplitter = wx.SplitterWindow(self) self.image_panel = ImagePanel(topSplitter, config,self.gui_size) self.widget_panel = WidgetPanel(topSplitter) topSplitter.SplitHorizontally(self.image_panel, self.widget_panel,sashPosition=self.gui_size[1]*0.83)#0.9 topSplitter.SetSashGravity(1) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(topSplitter, 1, wx.EXPAND) self.SetSizer(sizer) ################################################################################################################################################### # Add Buttons to the WidgetPanel and bind them to their respective functions. widgetsizer = wx.WrapSizer(orient=wx.HORIZONTAL) self.load = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Load Video") widgetsizer.Add(self.load , 1, wx.ALL, 15) self.load.Bind(wx.EVT_BUTTON, self.browseDir) self.help = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Help") widgetsizer.Add(self.help , 1, wx.ALL, 15) self.help.Bind(wx.EVT_BUTTON, self.helpButton) self.grab = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Grab Frames") widgetsizer.Add(self.grab , 1, wx.ALL, 15) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.grab.Enable(False) widgetsizer.AddStretchSpacer(5) size_x = round(self.gui_size[0] * (slider_width/100), 0) self.slider = wx.Slider(self.widget_panel, id=wx.ID_ANY, value = 0, minValue=0, maxValue=1,size=(size_x, -1), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS ) widgetsizer.Add(self.slider,1, wx.ALL,5) self.slider.Hide() widgetsizer.AddStretchSpacer(5) self.start_frames_sizer = wx.BoxSizer(wx.VERTICAL) self.end_frames_sizer = wx.BoxSizer(wx.VERTICAL) self.start_frames_sizer.AddSpacer(15) self.startFrame = wx.SpinCtrl(self.widget_panel, value='0', size=(100, -1), min=0, max=120) self.startFrame.Bind(wx.EVT_SPINCTRL,self.updateSlider) self.startFrame.Enable(False) self.start_frames_sizer.Add(self.startFrame,1, wx.EXPAND|wx.ALIGN_LEFT,15) start_text = wx.StaticText(self.widget_panel, label='Start Frame Index') self.start_frames_sizer.Add(start_text,1, wx.EXPAND|wx.ALIGN_LEFT,15) self.checkBox = wx.CheckBox(self.widget_panel, id=wx.ID_ANY,label = 'Range of frames') self.checkBox.Bind(wx.EVT_CHECKBOX,self.activate_frame_range) self.start_frames_sizer.Add(self.checkBox,1, wx.EXPAND|wx.ALIGN_LEFT,15) # self.end_frames_sizer.AddSpacer(15) self.endFrame = wx.SpinCtrl(self.widget_panel, value='1', size=(160, -1), min=1, max=120) self.endFrame.Enable(False) self.end_frames_sizer.Add(self.endFrame,1, wx.EXPAND|wx.ALIGN_LEFT,15) end_text = wx.StaticText(self.widget_panel, label='Number of Frames') self.end_frames_sizer.Add(end_text,1, wx.EXPAND|wx.ALIGN_LEFT,15) self.updateFrame = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Update") self.end_frames_sizer.Add(self.updateFrame,1, wx.EXPAND|wx.ALIGN_LEFT,15) self.updateFrame.Bind(wx.EVT_BUTTON, self.updateSlider) self.updateFrame.Enable(False) widgetsizer.Add(self.start_frames_sizer,1,wx.ALL,0) widgetsizer.AddStretchSpacer(5) widgetsizer.Add(self.end_frames_sizer,1,wx.ALL,0) widgetsizer.AddStretchSpacer(15) self.quit = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Quit") widgetsizer.Add(self.quit , 1, wx.ALL, 15) self.quit.Bind(wx.EVT_BUTTON, self.quitButton) self.quit.Enable(True) # Hiding these widgets and show them once the video is loaded self.start_frames_sizer.ShowItems(show=False) self.end_frames_sizer.ShowItems(show=False) self.widget_panel.SetSizer(widgetsizer) self.widget_panel.SetSizerAndFit(widgetsizer) self.widget_panel.Layout() # Variables initialization self.numberFrames = 0 self.currFrame = 0 self.figure = Figure() self.axes = self.figure.add_subplot(111) self.drs = [] self.cfg = auxiliaryfunctions.read_config(config) self.Task = self.cfg['Task'] self.start = self.cfg['start'] self.stop = self.cfg['stop'] self.date = self.cfg['date'] self.trainFraction = self.cfg['TrainingFraction'] self.trainFraction = self.trainFraction[0] self.videos = self.cfg['video_sets'].keys() self.bodyparts = self.cfg['bodyparts'] self.colormap = plt.get_cmap(self.cfg['colormap']) self.colormap = self.colormap.reversed() self.markerSize = self.cfg['dotsize'] self.alpha = self.cfg['alphavalue'] self.video_names = [Path(i).stem for i in self.videos] self.config_path = Path(config) self.extract_range_frame = False self.extract_from_analyse_video = False def quitButton(self, event): """ Quits the GUI """ self.statusbar.SetStatusText("") dlg = wx.MessageDialog(None,"Are you sure?", "Quit!",wx.YES_NO | wx.ICON_WARNING) result = dlg.ShowModal() if result == wx.ID_YES: print("Quitting for now!") self.Destroy() def updateSlider(self,event): self.slider.SetValue(self.startFrame.GetValue()) self.currFrame = (self.slider.GetValue()) if self.extract_from_analyse_video == True: self.figure.delaxes(self.figure.axes[1]) self.plot_labels() self.update() def activate_frame_range(self,event): """ Activates the frame range boxes """ self.checkSlider = event.GetEventObject() if self.checkSlider.GetValue() == True: self.extract_range_frame = True self.startFrame.Enable(True) self.startFrame.SetValue(self.slider.GetValue()) self.endFrame.Enable(True) self.updateFrame.Enable(True) self.grab.Enable(False) else: self.extract_range_frame = False self.startFrame.Enable(False) self.endFrame.Enable(False) self.updateFrame.Enable(False) self.grab.Enable(True) def line_select_callback(self,eclick, erelease): 'eclick and erelease are the press and release events' self.new_x1, self.new_y1 = eclick.xdata, eclick.ydata self.new_x2, self.new_y2 = erelease.xdata, erelease.ydata def CheckCropping(self): ''' Display frame at time "time" for video to check if cropping is fine. Select ROI of interest by adjusting values in myconfig.py USAGE for cropping: clip.crop(x1=None, y1=None, x2=None, y2=None, width=None, height=None, x_center=None, y_center=None) Returns a new clip in which just a rectangular subregion of the original clip is conserved. x1,y1 indicates the top left corner and x2,y2 is the lower right corner of the cropped region. All coordinates are in pixels. Float numbers are accepted. ''' videosource = self.video_source self.x1 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[0]) self.x2 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[1]) self.y1 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[2]) self.y2 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[3]) if self.cropping==True: # Select ROI of interest by drawing a rectangle self.cid = RectangleSelector(self.axes, self.line_select_callback,drawtype='box', useblit=False,button=[1], minspanx=5, minspany=5,spancoords='pixels',interactive=True) self.canvas.mpl_connect('key_press_event', self.cid) def OnSliderScroll(self, event): """ Slider to scroll through the video """ self.axes.clear() self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.currFrame = (self.slider.GetValue()) self.startFrame.SetValue(self.currFrame) self.update() def is_crop_ok(self,event): """ Checks if the cropping is ok """ self.grab.SetLabel("Grab Frames") self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.slider.Show() self.start_frames_sizer.ShowItems(show=True) self.end_frames_sizer.ShowItems(show=True) self.widget_panel.Layout() self.slider.SetMax(self.numberFrames) self.startFrame.SetMax(self.numberFrames-1) self.endFrame.SetMax(self.numberFrames) self.x1 = int(self.new_x1) self.x2 = int(self.new_x2) self.y1 = int(self.new_y1) self.y2 = int(self.new_y2) self.canvas.mpl_disconnect(self.cid) self.axes.clear() self.currFrame = (self.slider.GetValue()) self.update() # Update the config.yaml file self.cfg['video_sets'][self.video_source] = {'crop': ', '.join(map(str, [self.x1, self.x2, self.y1, self.y2]))} auxiliaryfunctions.write_config(self.config_path,self.cfg) def browseDir(self, event): """ Show the File Dialog and ask the user to select the video file """ self.statusbar.SetStatusText("Looking for a video to start extraction..") dlg = wx.FileDialog(self, "SELECT A VIDEO", os.getcwd(), "", "*.*", wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: self.video_source_original = dlg.GetPath() self.video_source = str(Path(self.video_source_original).resolve()) self.load.Enable(False) else: pass dlg.Destroy() self.Close(True) dlg.Destroy() selectedvideo = Path(self.video_source) self.statusbar.SetStatusText('Working on video: {}'.format(os.path.split(str(selectedvideo))[-1])) if str(selectedvideo.stem) in self.video_names : self.grab.Enable(True) self.vid = cv2.VideoCapture(self.video_source) self.videoPath = os.path.dirname(self.video_source) self.filename = Path(self.video_source).name self.numberFrames = int(self.vid.get(cv2.CAP_PROP_FRAME_COUNT)) # Checks if the video is corrupt. if not self.vid.isOpened(): msg = wx.MessageBox('Invalid Video file!Do you want to retry?', 'Error!', wx.YES_NO | wx.ICON_WARNING) if msg == 2: self.load.Enable(True) MainFrame.browseDir(self, event) else: self.Destroy() self.slider.Bind(wx.EVT_SLIDER, self.OnSliderScroll) self.update() cropMsg = wx.MessageBox("Do you want to crop the frames?",'Want to crop?',wx.YES_NO|wx.ICON_INFORMATION) if cropMsg == 2: self.cropping = True self.grab.SetLabel("Set cropping parameters") self.grab.Bind(wx.EVT_BUTTON, self.is_crop_ok) self.widget_panel.Layout() self.basefolder = 'data-' + self.Task + '/' MainFrame.CheckCropping(self) else: self.cropping = False self.slider.Show() self.start_frames_sizer.ShowItems(show=True) self.end_frames_sizer.ShowItems(show=True) self.widget_panel.Layout() self.slider.SetMax(self.numberFrames-1) self.startFrame.SetMax(self.numberFrames-1) self.endFrame.SetMax(self.numberFrames-1) else: wx.MessageBox('Video file is not in config file. Use add function to add this video in the config file and retry!', 'Error!', wx.OK | wx.ICON_WARNING) self.Close(True) def update(self): """ Updates the image with the current slider index """ self.grab.Enable(True) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.figure,self.axes,self.canvas = self.image_panel.getfigure() self.vid.set(1,self.currFrame) ret, frame = self.vid.read() if ret: frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) self.ax = self.axes.imshow(frame) self.axes.set_title(str(str(self.currFrame)+"/"+str(self.numberFrames-1) +" "+ self.filename)) self.figure.canvas.draw() def chooseFrame(self): ret, frame = self.vid.read() fname = Path(self.filename) output_path = self.config_path.parents[0] / 'labeled-data' / fname.stem if output_path.exists() : frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame=img_as_ubyte(frame) img_name = str(output_path) +'/img'+str(self.currFrame).zfill(int(np.ceil(np.log10(self.numberFrames)))) + '.png' if self.cropping: crop_img = frame[self.y1:self.y2, self.x1:self.x2] cv2.imwrite(img_name, cv2.cvtColor(crop_img, cv2.COLOR_RGB2BGR)) else: cv2.imwrite(img_name, cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)) else: print("%s path not found. Please make sure that the video was added to the config file using the function 'deeplabcut.add_new_videos'." %output_path) def grabFrame(self,event): """ Extracts the frame and saves in the current directory """ num_frames_extract = self.endFrame.GetValue() for i in range(self.currFrame,self.currFrame+num_frames_extract): self.currFrame = i self.vid.set(1,self.currFrame) self.chooseFrame() self.vid.set(1,self.currFrame) self.chooseFrame() def plot_labels(self): """ Plots the labels of the analyzed video """ self.vid.set(1,self.currFrame) ret, frame = self.vid.read() if ret: frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) self.norm = mcolors.Normalize(vmin=np.min(frame), vmax=np.max(frame)) self.colorIndex = np.linspace(np.min(frame),np.max(frame),len(self.bodyparts)) divider = make_axes_locatable(self.axes) cax = divider.append_axes("right", size="5%", pad=0.05) cbar = self.figure.colorbar(self.ax, cax=cax,spacing='proportional', ticks=self.colorIndex) cbar.set_ticklabels(self.bodyparts) for bpindex, bp in enumerate(self.bodyparts): color = self.colormap(self.norm(self.colorIndex[bpindex])) self.points = [self.Dataframe[self.scorer][bp]['x'].values[self.currFrame],self.Dataframe[self.scorer][bp]['y'].values[self.currFrame],1.0] circle = [patches.Circle((self.points[0], self.points[1]), radius=self.markerSize, fc = color , alpha=self.alpha)] self.axes.add_patch(circle[0]) self.figure.canvas.draw() def helpButton(self,event): """ Opens Instructions """ wx.MessageBox('1. Use the Load Video button to load a video. Use the slider to select a frame in the entire video. The number mentioned on the top of the slider represents the frame index. \n\n2. Click Grab Frames button to save the specific frame.\n\n3. In events where you need to extract a range of frames, then use the checkbox Range of frames to select the start frame index and number of frames to extract. Click the update button to see the start frame index. Click Grab Frames to select the range of frames. \n\n Click OK to continue', 'Instructions to use!', wx.OK | wx.ICON_INFORMATION)
class PlotPanel2DByTemperature(wx.Panel): DEFAULT_MIN_TEMP = 0 DEFAULT_MAX_TEMP = 2000 NUM_TEMPS = 200 def __init__(self, parent, min_temp=None): wx.Panel.__init__(self, parent) self.min_temp = min_temp if min_temp is not None else self.DEFAULT_MIN_TEMP self.max_temp = self.DEFAULT_MAX_TEMP self.data_cache = None # Panel. panel_box = wx.BoxSizer(wx.VERTICAL) ## Canvas. self.figure = Figure() self.canvas = Canvas(self, -1, self.figure) self.axes = None panel_box.Add(self.canvas, 1, wx.EXPAND) self.SetSizer(panel_box) def plot_data(self, fs, bds, xlabel=None, ylabel=None): self.data_cache = { 'fs': fs, 'bds': bds, 'xlabel': xlabel, 'ylabel': ylabel, } if self.axes is not None: self.figure.delaxes(self.axes) self.axes = None self.axes = self.figure.add_subplot(111) if xlabel is not None: self.axes.set_xlabel(xlabel) if ylabel is not None: self.axes.set_ylabel(ylabel) do_legend = False for f, bd in zip(fs, bds): label, color = bd.filename, bd.color if not do_legend and label is not None: do_legend = True xs = self._gen_temps() ys = [f(x) for x in xs] self.axes.plot(xs, ys, label=label, color=color) if do_legend: # Put the legend in the top-right corner, outside the axes. self.axes.legend(bbox_to_anchor=(0, 0, 1, 1), bbox_transform=self.figure.transFigure) self.figure.tight_layout() self.canvas.draw() def plot_cached_data(self): dc = self.data_cache if dc is None: return self.plot_data(dc['fs'], dc['bds'], xlabel=dc['xlabel'], ylabel=dc['ylabel']) def set_max_temp(self, temp): self.max_temp = temp self.plot_cached_data() def _gen_temps(self): return N.linspace(self.min_temp, self.max_temp, self.NUM_TEMPS)
class plothistogram(QFrame): def __init__(self, parent): print "__init__()" # DEBUG QFrame.__init__(self) self.parent=parent #self.setModal(False) self.data1=self.parent.y1 # get plotted y values from solutions plot self.data2=self.parent.y2 # get plotted y values from parameter plot self.nbins=50 # default=50 bins self.parameter=self.parent.parent.parametersComboBox.currentText() self.data=self.parent.y2 # set histogram to solver parameter data #print "self.data = ", self.data # DEBUG # Create canvas for plotting self.rim=0.1 self.fig = Figure((5, 4), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.fig.subplots_adjust(left=self.rim, right=1.0-self.rim, top=1.0-self.rim, bottom=self.rim) # set a small rim self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.mpl_toolbar.show() # first hide the toolbar self.ax=self.fig.add_subplot(111) self.createWidgets() self.createLayout() self.connectSignals() self.setLabels() self.plot() def createWidgets(self): #print "createWidgets()" # DEBUG self.closeButton=QPushButton("Close") self.closeButton.setToolTip("close this plotwindow") self.closeButton.show() self.histogramBinSpin=QSpinBox() # spinbox for histogram binsize self.histogramBinSpin.setToolTip("Number of bins to histogram into") self.histogramBinSpin.setMinimum(5) #self.histogramBinSpin.setMaximum(150) # set a maximum of 150 (reasonable?) self.histogramBinSpin.setSingleStep(10) # allow only stepping by 10 self.histogramBinSpin.setMaximumWidth(120) self.histogramBinSpin.setMinimumHeight(25) self.histogramBinSpin.setValue(self.nbins) self.histogramBinSpin.show() self.histogramBinLabel=QLabel("Bins") self.normedCheckBox=QCheckBox() self.normedCheckLabel=QLabel("Normalize") self.normedCheckBox.setToolTip("Normalize histogram") self.normedCheckBox.show() #self.dpi = 100 self.dataComboBox=QComboBox() self.dataComboBox.addItem(self.parent.parent.parmValueComboBox.currentText()) self.dataComboBox.addItem(self.parent.parent.parametersComboBox.currentText()) self.dataComboBox.setMaximumWidth(120) self.dataComboBox.setMinimumHeight(25) self.dataComboBox.setCurrentIndex(1) def createLayout(self): #print "createLayout()" # DEBUG self.normedLayout=QHBoxLayout() self.normedLayout.addWidget(self.normedCheckBox) self.normedLayout.addWidget(self.normedCheckLabel) self.buttonLayout=QVBoxLayout() self.plotLayout=QVBoxLayout() self.mainLayout=QHBoxLayout() self.buttonLayout.addLayout(self.normedLayout) #self.buttonLayout.addWidget(self.normedCheckBox) #self.buttonLayout.addWidget(self.normedCheckLabel) self.buttonLayout.addWidget(self.histogramBinSpin) self.buttonLayout.addWidget(self.dataComboBox) self.buttonLayout.insertStretch(-1) self.buttonLayout.addWidget(self.closeButton) self.plotLayout.addWidget(self.canvas) self.plotLayout.addWidget(self.mpl_toolbar) self.mainLayout.addLayout(self.buttonLayout) self.mainLayout.addLayout(self.plotLayout) self.setLayout(self.mainLayout) def setLabels(self): self.ax.xlabel="Bin" self.ax.ylabel="N" def setTitle(self): #=self.parent.parametersComboBox.currentText() #self.ax.xlabel=self.parmValueComboBox.currentText() #self.ax.xlabel="Bin No." #self.ax.ylabel="n" self.ax.title=self.parent.parent.parametersComboBox.currentText() def connectSignals(self): self.connect(self.closeButton, SIGNAL('clicked()'), SLOT('close()')) self.connect(self.histogramBinSpin, SIGNAL('valueChanged(int)'), self.on_changeBinSpin) self.connect(self.normedCheckBox, SIGNAL('stateChanged(int)'), self.on_normedCheckBox) self.connect(self.dataComboBox, SIGNAL('currentIndexChanged(int)'), self.on_data) def on_changeBinSpin(self): self.nbins=self.histogramBinSpin.value() # create histogram #n, bins = np.histogram(self.data, self.histogramBinSpin.value(), normed=self.normedCheckBox.isChecked()) #hist, bins=np.histogram(self.data, self.nbins, normed=self.normedCheckBox.isChecked()) #print "len(bins) = ", len(bins), " len(n) = ", len(n) #self.ax.plot(bins[1:], n, color='red') #self.canvas.draw() #self.ax.legend() #self.fig.draw_idle() # redraw (preferably when idle) self.plot() def on_normedCheckBox(self): self.plot() def on_data(self): print "on_data()" # DEBUG if self.dataComboBox.currentText()==self.parent.parent.parametersComboBox.currentText(): self.data=self.data2 else: self.data=self.data1 self.plot() def plot(self): self.fig.delaxes(self.ax) # delete all axes first self.ax=self.fig.add_subplot(111) n, bins = np.histogram(self.data, self.histogramBinSpin.value(), normed=self.normedCheckBox.isChecked()) self.xmin=bins[1] self.xmax=bins[len(bins)-1] self.ax.bar(bins[1:], n, color='blue', width=(self.xmax-self.xmin)/len(bins)) self.canvas.draw()
class PlotContour(object): #=========================================================================== def __init__(self, orientation='vertical', hover_target=None, **kwargs): if orientation in ['v', 'vertical']: self.vertical_orientation = True else: self.vertical_orientation = False self.event_dict = {} self.targets = [] self.hover_target = hover_target self.legend = None self.prop_fig = kwargs self._setup_figure() # self._add_event_hover() #=========================================================================== def _setup_figure(self): self.fig = Figure(**self.prop_fig) self.ax = self.fig.add_subplot(111) # =========================================================================== def _add_event_hover(self): try: self.disconnect_event('motion_notify_event') self.disconnect_event('button_press_event') except: pass self.add_event('motion_notify_event', self._on_movement_hover) #=========================================================================== def reset_plot(self): self.fig.delaxes(self.ax) #=========================================================================== def add_target(self, target): if target not in self.targets: self.targets.append(target) def add_legend(self, **kwargs): self.legend = self.fig.legend(**kwargs) self.call_targets() #========================================================================== def add_event(self, event_type, event_function): if event_type in self.event_dict: print('Event already added') return self.event_dict[event_type] = {} self.event_dict[event_type]['event_type'] = event_type self.event_dict[event_type]['event_function'] = event_function self.event_dict[event_type]['object'] = self.fig.canvas.mpl_connect(event_type, event_function) #========================================================================== def disconnect_event(self, event_type): if event_type in self.event_dict: self.fig.canvas.mpl_disconnect(self.event_dict[event_type]['object']) self.event_dict.pop(event_type) #========================================================================== def disconnect_all_events(self): event_list = self.event_dict.keys() for event_type in event_list: self.disconnect_event(event_type) #=========================================================================== def get_xlim(self): return self.ax.get_xlim() #=========================================================================== def get_ylim(self): return self.ax.get_ylim() #=========================================================================== def _on_click(self, event): pass def _on_movement_hover(self, event): self.hover_x = event.xdata self.hover_y = event.ydata self.call_target_hover() def call_target_hover(self): if self.hover_target: self.hover_target() #=========================================================================== def call_targets(self): """ Target is the mostly connected to updating a tk canvas. """ if self.targets: for target in self.targets: target() else: self.fig.draw() self.fig.show() #=========================================================================== def set_x_grid(self, grid_on=True, sync_color_with_line_id='default'): self.ax.grid(grid_on, axis='x', linestyle=':') #=========================================================================== def set_y_grid(self, grid_on=True, sync_color_with_line_id='default'): self.ax.grid(grid_on, axis='y', linestyle=':') #=========================================================================== def zoom_to_data(self, call_targets=True): ax = self._get_ax_object(ax) if ax: ax.set_x_limits(call_targets=False) ax.set_y_limits(call_targets=False) if call_targets: self.call_range_targets() def _set_date_ticks(self): start_date, end_date = self.get_xlim() start_date = datetime.datetime.fromordinal(int(start_date)) end_date = datetime.datetime.fromordinal(int(end_date)) dt = end_date - start_date nr_days = dt.days if nr_days <= 30: loc = mdates.DayLocator() fmt = mdates.DateFormatter('%Y-%m-%d') elif nr_days <= 100: loc = mdates.DayLocator(bymonthday=[1, 15]) fmt = mdates.DateFormatter('%Y-%m-%d') elif nr_days <= 365: loc = mdates.MonthLocator() fmt = mdates.DateFormatter('%Y-%m-%d') else: loc = mdates.MonthLocator(bymonthday=2) fmt = mdates.DateFormatter('%Y-%m-%d') self.ax.xaxis.set_major_locator(loc) self.ax.xaxis.set_major_formatter(fmt) #=========================================================================== def set_x_limits(self, limits=[], call_targets=True): x_min, x_max = limits self.ax.set_xlim([x_min, x_max]) # self._set_date_ticks() try: self._set_date_ticks() except: pass if call_targets: self.call_targets() #=========================================================================== def set_y_limits(self, limits=[], call_targets=True): y_min, y_max = limits self.ax.set_xlim([y_min, y_max]) if call_targets: self.call_targets() #=========================================================================== def set_data(self, x=False, y=False, z=None, line_id='default', exclude_index=[], ax='first', call_targets=True, **kwargs): try: x = [pd.to_datetime(item) for item in x] except: pass X, Y = np.meshgrid(x, y) self.data = dict() self.data['x'] = x self.data['y'] = y self.data['X'] = X self.data['Y'] = Y self.data['Z'] = z self.ax.contourf(X, Y, z, kwargs.get('nr_levels', 50)) if self.hover_target: self._add_event_hover() self.call_targets() #=========================================================================== def set_label(self, label): if self.vertical_orientation: self.ax.set_y_label(label) else: self.ax.set_x_label(label)
class SubWindow(QtGui.QWidget): "Base class for rasviewer document windows" cropChanged = QtCore.pyqtSignal() def __init__(self, ui_file, data_file, channel_file=None): super(SubWindow, self).__init__(None) self._load_interface(ui_file) try: self._load_data(data_file, channel_file) except (ValueError, IOError) as exc: QtGui.QMessageBox.critical(self, self.tr('Error'), str(exc)) self.close() return self._config_interface() self._config_handlers() self.channel_changed() def _load_interface(self, ui_file): "Called by __init__ to load the Qt interface file" self.ui = None self.ui = uic.loadUi(get_ui_file(ui_file), self) def _load_data(self, data_file, channel_file=None): "Called by __init__ to load the data file" self._file = None self._progress = 0 self._progress_update = None self._progress_dialog = None QtGui.QApplication.instance().setOverrideCursor(QtCore.Qt.WaitCursor) try: from rastools.data_parsers import DATA_PARSERS finally: QtGui.QApplication.instance().restoreOverrideCursor() # Open the selected file ext = os.path.splitext(data_file)[-1] parsers = dict( (ext, cls) for (cls, exts, _) in DATA_PARSERS for ext in exts) try: parser = parsers[ext] except KeyError: raise ValueError( self.tr('Unrecognized file extension "{0}"').format(ext)) self._file = parser(data_file, channel_file, delay_load=False, progress=( self.progress_start, self.progress_update, self.progress_finish, )) self.setWindowTitle(os.path.basename(data_file)) def _config_interface(self): "Called by __init__ to configure the interface elements" self._info_dialog = None self._drag_start = None self._pan_id = None self._pan_crop = None self._zoom_id = None self._zoom_rect = None # Create a figure in a tab for the file self.figure = Figure(figsize=(5.0, 5.0), dpi=FIGURE_DPI, facecolor='w', edgecolor='w') self.canvas = FigureCanvas(self.figure) self.image_axes = self.figure.add_axes((0.1, 0.1, 0.8, 0.8)) self.histogram_axes = None self.colorbar_axes = None self.title_axes = None self.ui.splitter.addWidget(self.canvas) # Set up the redraw timer self.redraw_timer = QtCore.QTimer() self.redraw_timer.setInterval(REDRAW_TIMEOUT_DEFAULT) self.redraw_timer.timeout.connect(self.redraw_timeout) # Set up the limits of the crop spinners self.ui.crop_left_spinbox.setRange(0, self._file.x_size - 1) self.ui.crop_right_spinbox.setRange(0, self._file.x_size - 1) self.ui.crop_top_spinbox.setRange(0, self._file.y_size - 1) self.ui.crop_bottom_spinbox.setRange(0, self._file.y_size - 1) # Configure the common combos default = -1 for interpolation in sorted(matplotlib.image.AxesImage._interpd): if interpolation == DEFAULT_INTERPOLATION: default = self.ui.interpolation_combo.count() self.ui.interpolation_combo.addItem(interpolation) self.ui.interpolation_combo.setCurrentIndex(default) if hasattr(self.ui, 'colorbar_check'): default = -1 for color in sorted(matplotlib.cm.datad): if not color.endswith('_r'): if color == DEFAULT_COLORMAP: default = self.ui.colormap_combo.count() self.ui.colormap_combo.addItem(color) self.ui.colormap_combo.setCurrentIndex(default) def _config_handlers(self): "Called by __init__ to connect events to handlers" # Set up common event connections self.ui.interpolation_combo.currentIndexChanged.connect( self.invalidate_image) self.ui.crop_top_spinbox.valueChanged.connect(self.crop_changed) self.ui.crop_left_spinbox.valueChanged.connect(self.crop_changed) self.ui.crop_right_spinbox.valueChanged.connect(self.crop_changed) self.ui.crop_bottom_spinbox.valueChanged.connect(self.crop_changed) self.ui.axes_check.toggled.connect(self.invalidate_image) self.ui.x_label_edit.textChanged.connect(self.invalidate_image) self.ui.y_label_edit.textChanged.connect(self.invalidate_image) self.ui.x_scale_spinbox.valueChanged.connect(self.x_scale_changed) self.ui.y_scale_spinbox.valueChanged.connect(self.y_scale_changed) self.ui.x_offset_spinbox.valueChanged.connect(self.x_offset_changed) self.ui.y_offset_spinbox.valueChanged.connect(self.y_offset_changed) self.ui.grid_check.toggled.connect(self.invalidate_image) self.ui.histogram_check.toggled.connect(self.invalidate_image) self.ui.histogram_bins_spinbox.valueChanged.connect( self.invalidate_image) self.ui.title_edit.textChanged.connect(self.invalidate_image) self.ui.default_title_button.clicked.connect( self.default_title_clicked) self.ui.clear_title_button.clicked.connect(self.clear_title_clicked) self.ui.title_info_button.clicked.connect(self.title_info_clicked) self.ui.splitter.splitterMoved.connect(self.splitter_moved) QtGui.QApplication.instance().focusChanged.connect(self.focus_changed) self.canvas.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.canvas.customContextMenuRequested.connect(self.canvas_popup) if hasattr(self.ui, 'colorbar_check'): self.ui.colorbar_check.toggled.connect(self.invalidate_image) self.ui.colormap_combo.currentIndexChanged.connect( self.invalidate_image) self.ui.reverse_check.toggled.connect(self.invalidate_image) self.press_id = self.canvas.mpl_connect('button_press_event', self.canvas_press) self.release_id = self.canvas.mpl_connect('button_release_event', self.canvas_release) self.motion_id = self.canvas.mpl_connect('motion_notify_event', self.canvas_motion) def splitter_moved(self, pos, index): self.invalidate_image() def progress_start(self): "Handler for loading progress start event" self._progress = 0 self._progress_dialog = ProgressDialog(self.window()) self._progress_dialog.show() self._progress_dialog.task = self.tr('Opening file') QtGui.QApplication.instance().setOverrideCursor(QtCore.Qt.WaitCursor) def progress_update(self, progress): "Handler for loading progress update event" now = time.time() if ((self._progress_update is None) or (now - self._progress_update) > 0.2): if self._progress_dialog.cancelled: raise KeyboardInterrupt self._progress_update = now if progress != self._progress: self._progress_dialog.progress = progress self._progress = progress def progress_finish(self): "Handler for loading progress finished event" QtGui.QApplication.instance().restoreOverrideCursor() if self._progress_dialog is not None: self._progress_dialog.close() self._progress_dialog = None def canvas_popup(self, pos): "Handler for canvas context menu event" menu = QtGui.QMenu(self) menu.addAction(self.window().ui.zoom_mode_action) menu.addAction(self.window().ui.pan_mode_action) menu.addSeparator() menu.addAction(self.window().ui.zoom_in_action) menu.addAction(self.window().ui.zoom_out_action) menu.addAction(self.window().ui.reset_zoom_action) menu.addSeparator() menu.addAction(self.window().ui.home_axes_action) menu.addAction(self.window().ui.reset_axes_action) menu.popup(self.canvas.mapToGlobal(pos)) def canvas_motion(self, event): "Handler for mouse movement over graph canvas" raise NotImplementedError def canvas_press(self, event): "Handler for mouse press on graph canvas" if event.button != 1: return if event.inaxes != self.image_axes: return self._drag_start = Coord(event.x, event.y) if self.window().ui.zoom_mode_action.isChecked(): self._zoom_id = self.canvas.mpl_connect('motion_notify_event', self.canvas_zoom_motion) elif self.window().ui.pan_mode_action.isChecked(): self._pan_id = self.canvas.mpl_connect('motion_notify_event', self.canvas_pan_motion) self._pan_crop = Crop(top=self.ui.crop_top_spinbox.value(), left=self.ui.crop_left_spinbox.value(), bottom=self.ui.crop_bottom_spinbox.value(), right=self.ui.crop_right_spinbox.value()) self.redraw_timer.setInterval(REDRAW_TIMEOUT_PAN) def canvas_pan_motion(self, event): "Handler for mouse movement in pan mode" inverse = self.image_axes.transData.inverted() start_x, start_y = inverse.transform_point(self._drag_start) end_x, end_y = inverse.transform_point((event.x, event.y)) delta = Coord(int(start_x - end_x), int(start_y - end_y)) if (self._pan_crop.left + delta.x >= 0) and (self._pan_crop.right - delta.x >= 0): self.ui.crop_left_spinbox.setValue(self._pan_crop.left + delta.x) self.ui.crop_right_spinbox.setValue(self._pan_crop.right - delta.x) if (self._pan_crop.top + delta.y >= 0) and (self._pan_crop.bottom - delta.y >= 0): self.ui.crop_top_spinbox.setValue(self._pan_crop.top + delta.y) self.ui.crop_bottom_spinbox.setValue(self._pan_crop.bottom - delta.y) def canvas_zoom_motion(self, event): "Handler for mouse movement in zoom mode" # Calculate the display coordinates of the selection box_left, box_top, box_right, box_bottom = self.image_axes.bbox.extents height = self.figure.bbox.height band_left = max(min(self._drag_start.x, event.x), box_left) band_right = min(max(self._drag_start.x, event.x), box_right) band_top = max(min(self._drag_start.y, event.y), box_top) band_bottom = min(max(self._drag_start.y, event.y), box_bottom) rectangle = (band_left, height - band_top, band_right - band_left, band_top - band_bottom) # Calculate the data coordinates of the selection. Note that top and # bottom are reversed by this conversion inverse = self.image_axes.transData.inverted() data_left, data_bottom = inverse.transform_point((band_left, band_top)) data_right, data_top = inverse.transform_point( (band_right, band_bottom)) # Ignore the drag operation until the total number of data-points in # the selection exceeds the threshold if (abs(data_right - data_left) * abs(data_bottom - data_top)) > ZOOM_THRESHOLD: self._zoom_rect = (data_left, data_top, data_right, data_bottom) self.window().statusBar().showMessage( self.tr('Crop from ({left:.0f}, {top:.0f}) to ' '({right:.0f}, {bottom:.0f})').format( left=data_left, top=data_top, right=data_right, bottom=data_bottom)) self.canvas.drawRectangle(rectangle) else: self._zoom_rect = None self.window().statusBar().clearMessage() self.canvas.draw() def canvas_release(self, event): "Handler for mouse release on graph canvas" if self._pan_id: self.window().statusBar().clearMessage() self.canvas.mpl_disconnect(self._pan_id) self._pan_id = None self.redraw_timer.setInterval(REDRAW_TIMEOUT_DEFAULT) if self._zoom_id: self.window().statusBar().clearMessage() self.canvas.mpl_disconnect(self._zoom_id) self._zoom_id = None if self._zoom_rect: ( data_left, data_top, data_right, data_bottom, ) = self._zoom_rect data_left = ((data_left / self.ui.x_scale_spinbox.value()) - self.ui.x_offset_spinbox.value()) data_right = ((data_right / self.ui.x_scale_spinbox.value()) - self.ui.x_offset_spinbox.value()) data_top = ((data_top / self.ui.y_scale_spinbox.value()) - self.ui.y_offset_spinbox.value()) data_bottom = ( (data_bottom / self.ui.y_scale_spinbox.value()) - self.ui.y_offset_spinbox.value()) self.ui.crop_left_spinbox.setValue(data_left) self.ui.crop_top_spinbox.setValue(data_top) self.ui.crop_right_spinbox.setValue(self._file.x_size - data_right) self.ui.crop_bottom_spinbox.setValue(self._file.y_size - data_bottom) self.canvas.draw() def channel_changed(self): "Handler for data channel change event" self.invalidate_data() self.crop_changed() def crop_changed(self, value=None): "Handler for crop_*_spinbox change event" self.cropChanged.emit() @property def zoom_factor(self): "Returns the percentage by which zoom in/out will operate" factor = 0.2 height, width = self.data_cropped.shape[:2] return (max(1.0, width * factor), max(1.0, height * factor)) @property def can_zoom_in(self): "Returns True if the image can be zoomed" height, width = self.data_cropped.shape[:2] x_factor, y_factor = self.zoom_factor return (width - x_factor * 2) * (height - y_factor * 2) > ZOOM_THRESHOLD @property def can_zoom_out(self): "Returns True if the image is zoomed" return (self.ui.crop_left_spinbox.value() > 0 or self.ui.crop_right_spinbox.value() > 0 or self.ui.crop_top_spinbox.value() > 0 or self.ui.crop_bottom_spinbox.value()) def zoom_in(self): "Zooms the image in by a fixed amount" x_factor, y_factor = self.zoom_factor self.ui.crop_left_spinbox.setValue(self.ui.crop_left_spinbox.value() + x_factor) self.ui.crop_right_spinbox.setValue( self.ui.crop_right_spinbox.value() + x_factor) self.ui.crop_top_spinbox.setValue(self.ui.crop_top_spinbox.value() + y_factor) self.ui.crop_bottom_spinbox.setValue( self.ui.crop_bottom_spinbox.value() + y_factor) def zoom_out(self): "Zooms the image out by a fixed amount" x_factor, y_factor = self.zoom_factor self.ui.crop_left_spinbox.setValue( max(0.0, self.ui.crop_left_spinbox.value() - x_factor)) self.ui.crop_right_spinbox.setValue( max(0.0, self.ui.crop_right_spinbox.value() - x_factor)) self.ui.crop_top_spinbox.setValue( max(0.0, self.ui.crop_top_spinbox.value() - y_factor)) self.ui.crop_bottom_spinbox.setValue( max(0.0, self.ui.crop_bottom_spinbox.value() - y_factor)) def reset_zoom(self): "Handler for reset_zoom_action triggered event" self.ui.crop_left_spinbox.setValue(0) self.ui.crop_right_spinbox.setValue(0) self.ui.crop_top_spinbox.setValue(0) self.ui.crop_bottom_spinbox.setValue(0) def reset_axes(self): "Handler for the reset_axes_action triggered event" self.ui.scale_locked_check.setChecked(True) self.ui.x_scale_spinbox.setValue(1.0) self.ui.y_scale_spinbox.setValue(1.0) self.ui.offset_locked_check.setChecked(True) self.ui.x_offset_spinbox.setValue(0.0) self.ui.y_offset_spinbox.setValue(0.0) def home_axes(self): "Handler for home_axes_action triggered event" self.ui.scale_locked_check.setChecked(True) self.ui.x_scale_spinbox.setValue(1.0) self.ui.y_scale_spinbox.setValue(1.0) self.ui.offset_locked_check.setChecked(False) self.ui.x_offset_spinbox.setValue(-self.ui.crop_left_spinbox.value()) self.ui.y_offset_spinbox.setValue(-self.ui.crop_top_spinbox.value()) def x_scale_changed(self, value): "Handler for x_scale_spinbox change event" if self.ui.scale_locked_check.isChecked(): self.ui.y_scale_spinbox.setValue(value) self.invalidate_image() def y_scale_changed(self, value): "Handler for y_scale_spinbox change event" if self.ui.scale_locked_check.isChecked(): self.ui.x_scale_spinbox.setValue(value) self.invalidate_image() def x_offset_changed(self, value): "Handler for x_offset_spinbox change event" if self.ui.offset_locked_check.isChecked(): self.ui.y_offset_spinbox.setValue(value) self.invalidate_image() def y_offset_changed(self, value): "Handler for x_offset_spinbox change event" if self.ui.offset_locked_check.isChecked(): self.ui.x_offset_spinbox.setValue(value) self.invalidate_image() def default_title_clicked(self): "Handler for default_title_button click event" raise NotImplementedError def clear_title_clicked(self): "Handler for clear_title_button click event" self.ui.title_edit.clear() def title_info_clicked(self, items): "Handler for title_info_button click event" from rastools.rasviewer.title_info_dialog import TitleInfoDialog if not self._info_dialog: self._info_dialog = TitleInfoDialog(self) self._info_dialog.ui.template_list.clear() for key, value in sorted(self.format_dict().items()): if isinstance(value, type('')): if '\n' in value: value = value.splitlines()[0].rstrip() self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem(['{{{0}}}'.format(key), value])) elif isinstance(value, int): self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem( ['{{{0}}}'.format(key), '{0}'.format(value)])) if 0 < value < 10: self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem([ '{{{0}:02d}}'.format(key), '{0:02d}'.format(value) ])) elif isinstance(value, float): self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem( ['{{{0}}}'.format(key), '{0}'.format(value)])) self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem( ['{{{0}:.2f}}'.format(key), '{0:.2f}'.format(value)])) elif isinstance(value, dt.datetime): self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem( ['{{{0}}}'.format(key), '{0}'.format(value)])) self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem([ '{{{0}:%Y-%m-%d}}'.format(key), '{0:%Y-%m-%d}'.format(value) ])) self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem([ '{{{0}:%H:%M:%S}}'.format(key), '{0:%H:%M:%S}'.format(value) ])) self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem([ '{{{0}:%A, %d %b %Y, %H:%M:%S}}'.format(key), '{0:%A, %d %b %Y, %H:%M:%S}'.format(value) ])) else: self._info_dialog.ui.template_list.addTopLevelItem( QtGui.QTreeWidgetItem( ['{{{0}}}'.format(key), '{0}'.format(value)])) self._info_dialog.show() @property def data(self): "Returns the original data array" raise NotImplementedError @property def data_cropped(self): "Returns the data after cropping" raise NotImplementedError @property def x_limits(self): "Returns a tuple of the X-axis limits after scaling and offset" if self.data_cropped is not None: return Range( (self.ui.x_scale_spinbox.value() or 1.0) * (self.ui.x_offset_spinbox.value() + self.ui.crop_left_spinbox.value()), (self.ui.x_scale_spinbox.value() or 1.0) * (self.ui.x_offset_spinbox.value() + self._file.x_size - self.ui.crop_right_spinbox.value())) @property def y_limits(self): "Returns a tuple of the Y-axis limits after scaling and offset" if self.data_cropped is not None: return Range( (self.ui.y_scale_spinbox.value() or 1.0) * (self.ui.y_offset_spinbox.value() + self._file.y_size - self.ui.crop_bottom_spinbox.value()), (self.ui.y_scale_spinbox.value() or 1.0) * (self.ui.y_offset_spinbox.value() + self.ui.crop_top_spinbox.value())) @property def axes_visible(self): "Returns True if the axes should be shown" return hasattr(self.ui, 'axes_check') and self.ui.axes_check.isChecked() @property def colorbar_visible(self): "Returns True if the colorbar should be shown" return hasattr( self.ui, 'colorbar_check') and self.ui.colorbar_check.isChecked() @property def histogram_visible(self): "Returns True if the histogram should be shown" return hasattr( self.ui, 'histogram_check') and self.ui.histogram_check.isChecked() @property def margin_visible(self): "Returns True if the image margins should be shown" return (self.axes_visible or self.histogram_visible or self.colorbar_visible or bool(self.image_title)) @property def x_margin(self): "Returns the size of the left and right margins when drawing" return 0.75 if self.margin_visible else 0.0 @property def y_margin(self): "Returns the size of the top and bottom margins when drawing" return 0.25 if self.margin_visible else 0.0 @property def sep_margin(self): "Returns the size of the separator between image elements" return 0.3 @property def image_title(self): "Returns the text of the image title after substitution" result = '' try: if self.ui.title_edit.toPlainText(): result = str(self.ui.title_edit.toPlainText()).format( **self.format_dict()) except KeyError as exc: self.ui.title_error_label.setText( 'Unknown template "{}"'.format(exc)) self.ui.title_error_label.show() except ValueError as exc: self.ui.title_error_label.setText(str(exc)) self.ui.title_error_label.show() else: self.ui.title_error_label.hide() return result @property def figure_box(self): "Returns the overall bounding box" return BoundingBox(0.0, 0.0, self.figure.get_figwidth(), self.figure.get_figheight()) @property def colorbar_box(self): "Returns the colorbar bounding box" return BoundingBox(self.x_margin, self.y_margin, self.figure_box.width - (self.x_margin * 2), 0.5 if self.colorbar_visible else 0.0) @property def title_box(self): "Returns the title bounding box" return BoundingBox( self.x_margin, self.figure_box.height - (self.y_margin + 1.0 if bool(self.image_title) else 0.0), self.figure_box.width - (self.x_margin * 2), 1.0 if bool(self.image_title) else 0.0) @property def histogram_box(self): "Returns the histogram bounding box" return BoundingBox( self.x_margin, self.colorbar_box.top + (self.sep_margin if self.colorbar_visible else 0.0), self.figure_box.width - (self.x_margin * 2), (self.figure_box.height - (self.y_margin * 2) - self.colorbar_box.height - self.title_box.height - (self.sep_margin if self.colorbar_visible else 0.0) - (self.sep_margin if bool(self.image_title) else 0.0)) / 2.0 if self.histogram_visible else 0.0) @property def image_box(self): "Returns the image bounding box" return BoundingBox( self.x_margin, self.histogram_box.top + (self.sep_margin if self.colorbar_visible or self.histogram_visible else 0.0), self.figure_box.width - (self.x_margin * 2), (self.figure_box.height - (self.y_margin * 2) - self.colorbar_box.height - self.title_box.height - self.histogram_box.height - (self.sep_margin if self.colorbar_visible else 0.0) - (self.sep_margin if self.histogram_visible else 0.0) - (self.sep_margin if bool(self.image_title) else 0.0))) def invalidate_image(self): "Invalidate the image" # Actually, this method doesn't immediately invalidate the image (as # this results in a horribly sluggish UI), but starts a timer which # causes a redraw after no invalidations have occurred for a period # (see __init__ for the duration) if self.redraw_timer.isActive(): self.redraw_timer.stop() self.redraw_timer.start() def redraw_timeout(self): "Handler for the redraw_timer's timeout event" self.redraw_timer.stop() self.redraw_figure() def redraw_figure(self): "Called to redraw the channel image" # The following tests ensure we don't try and draw anything while we're # still loading the file if self._file and self.data is not None: # Draw the various image elements within bounding boxes calculated # from the metrics above image = self.draw_image() self.draw_histogram() self.draw_colorbar(image) self.draw_title() self.canvas.draw() def draw_image(self): "Draws the image of the data within the specified figure" raise NotImplementedError def draw_histogram(self): "Draws the data's historgram within the figure" raise NotImplementedError def draw_colorbar(self, image): "Draws a range color-bar within the figure" raise NotImplementedError def draw_title(self): "Draws a title within the specified figure" box = self.title_box.relative_to(self.figure_box) if bool(self.image_title): if self.title_axes is None: self.title_axes = self.figure.add_axes(box) else: self.title_axes.clear() self.title_axes.set_position(box) self.title_axes.set_axis_off() # Render the title self.title_axes.text(0.5, 0, self.image_title, horizontalalignment='center', verticalalignment='baseline', multialignment='center', size='medium', family='sans-serif', transform=self.title_axes.transAxes) elif self.title_axes: self.figure.delaxes(self.title_axes) self.title_axes = None def format_dict(self): "Returns UI settings in a dict for use in format substitutions" raise NotImplementedError
class Plot: """ Plot class. Ultimately the aim is to pass this on to the GUI. """ def __init__(self, data=None, backend=None): """ Create a Plot object. Argument 'data' supplies a pandas.DataFrame with data to be plotted. Argument 'backend' is a str determining what backend the figure is for. This is passed on to matplotlib.use(). (Perhaps 'Qt5Agg'?) Default is to plot with the console's backend, so as to enable easier interactive testing. """ # Initialize some attributes. self.data = data if data is None: self.x = None self.y = None else: self.x = data.columns[0] self.y = data.columns[1] # Create the figure object that will be passed on, # depending on the requested mode. # Probably better not to determine the figure dimensions here, # but rather let the GUI alter them afterwards. if backend is None: self.fig = pyplot.figure() self.mode = 'console' else: matplotlib.use(backend) self.fig = Figure() self.mode = 'GUI' # Add the axes object to the figure. self.axes = self.fig.add_subplot(1, 1, 1) def clear(self): """ Clear the axes of data, ready for a new plot. """ self.fig.delaxes(self.axes) self.axes = self.fig.add_subplot(1, 1, 1) def get_figure(self): """ Get the current plot and return it as a matplotlib Figure. """ return self.fig def plot(self, x=None, y=None): """ Draw the data onto the axes. Arguments 'x' and 'y' are str names of columns in data. Default is to plot the first two columns as x and y. Multiple calls to plot() will plot over existing data. Use clear() to clear the axes for a new plot. """ # Use defaults if no input arguments. if x is None or y is None: x = self.x y = self.y # Draw. self.axes.plot(self.data[x], self.data[y]) def set_data(self, data): """ Change the data for the figure. Argument 'data' is a new pandas.DataFrame. """ self.data = data
class subplot(QtWidgets.QWidget): quickEditSignal = QtCore.Signal(object) rmSubplotSignal = QtCore.Signal(object) def __init__(self, context): super(subplot, self).__init__() self._context = context self.figure = Figure() self.figure.set_facecolor("none") self.canvas = FigureCanvas(self.figure) self._rm_window = None self._selector_window = None # update quick edit from tool bar self.canvas.mpl_connect("draw_event", self.draw_event_callback) self._ADSObserver = SubplotADSObserver(self) grid = QtWidgets.QGridLayout() # add toolbar self.toolbar = myToolbar(self.canvas, self) self.toolbar.update() grid.addWidget(self.toolbar, 0, 0) self.toolbar.setRmConnection(self._rm) self.toolbar.setRmSubplotConnection(self._rm_subplot) # add plot self.plotObjects = {} grid.addWidget(self.canvas, 1, 0) self.setLayout(grid) """ this is called when the zoom or pan are used. We want to send a signal to update the axis ranges """ def draw_event_callback(self, event): self.figure.tight_layout() for subplot in self.plotObjects.keys(): self.emit_subplot_range(subplot) def add_annotate(self, subplotName, label): if subplotName not in self._context.subplots.keys(): return self._context.add_annotate(subplotName, label) self.canvas.draw() def add_vline(self, subplotName, xvalue, name, color): if subplotName not in self._context.subplots.keys(): return self._context.add_vline(subplotName, xvalue, name, color) self.canvas.draw() def rm_annotate(self, subplotName, name): if subplotName not in self._context.subplots.keys(): return self._context.removeLabel(subplotName, name) self.canvas.draw() def rm_vline(self, subplotName, name): if subplotName not in self._context.subplots.keys(): return self._context.removeVLine(subplotName, name) self.canvas.draw() # plot a workspace, if a new subplot create it. def plot(self, subplotName, workspace, specNum=1): new = False if subplotName not in self._context.subplots.keys(): self.add_subplot(subplotName, len(list(self.plotObjects.keys()))) new = True self._add_plotted_line(subplotName, workspace, specNum=specNum) if new: self.emit_subplot_range(subplotName) def change_errors(self, state, subplotNames): for subplotName in subplotNames: self._context.subplots[subplotName].change_errors(state) self.canvas.draw() # adds plotted line to context and updates GUI def _add_plotted_line(self, subplotName, workspace, specNum): """ Appends plotted lines to the related subplot list. """ self._context.addLine(subplotName, workspace, specNum) self.canvas.draw() def add_subplot(self, subplotName, number): self._context.update_gridspec(number + 1) gridspec = self._context.gridspec self.plotObjects[subplotName] = self.figure.add_subplot( gridspec[number], label=subplotName, projection='mantid') self.plotObjects[subplotName].set_title(subplotName) self._context.addSubplot(subplotName, self.plotObjects[subplotName]) self._update() def _update(self): self._context.update_layout(self.figure) self.canvas.draw() def emit_subplot_range(self, subplotName): self.quickEditSignal.emit(subplotName) self._context.subplots[subplotName].redraw_annotations() def set_plot_x_range(self, subplotNames, range): for subplotName in subplotNames: # make a set method in context and set it there self.plotObjects[subplotName].set_xlim(range) self._context.subplots[subplotName].redraw_annotations() self.canvas.draw() def set_plot_y_range(self, subplotNames, y_range): for subplotName in subplotNames: self.plotObjects[subplotName].set_ylim(y_range) self._context.subplots[subplotName].redraw_annotations() self.canvas.draw() def connect_quick_edit_signal(self, slot): self.quickEditSignal.connect(slot) def disconnect_quick_edit_signal(self): self.quickEditSignal.disconnect() def connect_rm_subplot_signal(self, slot): self.rmSubplotSignal.connect(slot) def disconnect_rm_subplot_signal(self): self.rmSubplotSignal.disconnect() def set_y_autoscale(self, subplotNames, state): for subplotName in subplotNames: self._context.subplots[subplotName].change_auto(state) self.canvas.draw() def _rm(self): names = list(self._context.subplots.keys()) if len(names) == 1: if self._rm_window is not None: self._rm_window.show() else: self._get_rm_window(names[0]) else: if self._rm_window is not None: self._rm_window.close() self._rm_window = None self._close_selector_window() self._selector_window = self._createSelectWindow(names) self._selector_window.subplotSelectorSignal.connect(self._get_rm_window) self._selector_window.closeEventSignal.connect(self._close_selector_window) self._selector_window.setMinimumSize(300, 100) self._selector_window.show() def _rm_subplot(self): names = list(self._context.subplots.keys()) # If the selector is hidden then close it self._close_selector_window() self._selector_window = self._createSelectWindow(names) self._selector_window.subplotSelectorSignal.connect(self._remove_subplot) self._selector_window.subplotSelectorSignal.connect(self._close_selector_window) self._selector_window.closeEventSignal.connect(self._close_selector_window) self._selector_window.setMinimumSize(300, 100) self._selector_window.show() def _createSelectWindow(self, names): return SelectSubplot(names) def _close_selector_window(self): if self._selector_window is not None: self._selector_window.close() self._selector_window = None def _create_rm_window(self, subplotName): line_names = list(self._context.subplots[subplotName].lines.keys()) vline_names = self._context.subplots[subplotName].vlines return RemovePlotWindow(lines=line_names, vlines=vline_names, subplot=subplotName, parent=self) def _get_rm_window(self, subplotName): # always close selector after making a selection self._close_selector_window() # create the remove window self._rm_window = self._create_rm_window(subplotName=subplotName) self._rm_window.applyRemoveSignal.connect(self._applyRm) self._rm_window.closeEventSignal.connect(self._close_rm_window) self._rm_window.setMinimumSize(200, 200) self._rm_window.show() def _applyRm(self, names): remove_subplot = True # remove the lines from the subplot for name in names: if self._rm_window.getState(name): self._context.subplots[ self._rm_window.subplot].removeLine(name) else: remove_subplot = False # if all of the lines have been removed -> delete subplot if remove_subplot: self._remove_subplot(self._rm_window.subplot) else: self.canvas.draw() # if no subplots then close plotting window if len(self._context.subplots.keys()) == 0: self._close_rm_window() # close plot window once auto grid done else: self._close_rm_window() def _close_rm_window(self): self._rm_window.close self._rm_window = None def _remove_subplot(self, subplotName): self.figure.delaxes(self.plotObjects[subplotName]) del self.plotObjects[subplotName] self._context.delete(subplotName) self._context.update_gridspec(len(list(self.plotObjects.keys()))) self._update() self.rmSubplotSignal.emit(subplotName) def _rm_ws_from_plots(self, workspace_name): keys = deepcopy(self._context.subplots.keys()) for subplot in keys: labels = self._context.get_lines_from_WS(subplot, workspace_name) for label in labels: self._context.removePlotLine(subplot, label) self.canvas.draw() if self._context.is_subplot_empty(subplot): self._remove_subplot(subplot) def _replaced_ws(self, workspace): for subplot in self._context.subplots.keys(): redraw = self._context.subplots[subplot].replace_ws(workspace) if redraw: self.canvas.draw()
class PlotPanel(wx.Panel): def __init__(self, parent, selPanel,infoPanel=None, mainframe=None): # Superclass constructor super(PlotPanel,self).__init__(parent) # Font handling font = parent.GetFont() font.SetPointSize(font.GetPointSize()-1) self.SetFont(font) # Preparing a special font manager for chinese characters self.specialFont=None CH_F_PATHS = [ os.path.join(pyplot_rc['datapath'], 'fonts/ttf/SimHei.ttf'), os.path.join(os.path.dirname(__file__),'../SimHei.ttf')] for fpath in CH_F_PATHS: if os.path.exists(fpath): fontP = font_manager.FontProperties(fname=fpath) fontP.set_size(font.GetPointSize()) self.specialFont=fontP break # data self.selPanel = selPanel self.infoPanel=infoPanel self.parent = parent self.mainframe= mainframe self.plotData = [] if self.selPanel is not None: bg=self.selPanel.BackgroundColour self.SetBackgroundColour(bg) # sowhow, our parent has a wrong color # GUI self.fig = Figure(facecolor="white", figsize=(1, 1)) self.fig.set_tight_layout(True) # subplots_adjust(top=0.98,bottom=0.12,left=0.12,right=0.98) self.canvas = FigureCanvas(self, -1, self.fig) self.canvas.mpl_connect('motion_notify_event', self.onMouseMove) self.navTB = MyNavigationToolbar2Wx(self.canvas) # --- Tool Panel self.toolSizer= wx.BoxSizer(wx.VERTICAL) # --- PlotType Panel self.pltTypePanel= PlotTypePanel(self); # --- Plot type specific options self.spcPanel = SpectralCtrlPanel(self) self.pdfPanel = PDFCtrlPanel(self) self.cmpPanel = CompCtrlPanel(self) self.mmxPanel = MinMaxPanel(self) # --- Ctrl Panel self.ctrlPanel= wx.Panel(self) # Check Boxes self.cbScatter = wx.CheckBox(self.ctrlPanel, -1, 'Scatter',(10,10)) self.cbSub = wx.CheckBox(self.ctrlPanel, -1, 'Subplot',(10,10)) self.cbLogX = wx.CheckBox(self.ctrlPanel, -1, 'Log-x',(10,10)) self.cbLogY = wx.CheckBox(self.ctrlPanel, -1, 'Log-y',(10,10)) self.cbSync = wx.CheckBox(self.ctrlPanel, -1, 'Sync-x',(10,10)) self.cbXHair = wx.CheckBox(self.ctrlPanel, -1, 'CrossHair',(10,10)) #self.cbSub.SetValue(True) # DEFAULT TO SUB? self.cbSync.SetValue(True) self.cbXHair.SetValue(True) # Have cross hair by default self.Bind(wx.EVT_CHECKBOX, self.scatter_select, self.cbScatter) self.Bind(wx.EVT_CHECKBOX, self.redraw_event , self.cbSub ) self.Bind(wx.EVT_CHECKBOX, self.log_select , self.cbLogX ) self.Bind(wx.EVT_CHECKBOX, self.log_select , self.cbLogY ) self.Bind(wx.EVT_CHECKBOX, self.redraw_event , self.cbSync ) self.Bind(wx.EVT_CHECKBOX, self.crosshair_event, self.cbXHair ) # LAYOUT cb_sizer = wx.FlexGridSizer(rows=3, cols=2, hgap=2, vgap=0) cb_sizer.Add(self.cbScatter, 0, flag=wx.ALL, border=1) cb_sizer.Add(self.cbSub , 0, flag=wx.ALL, border=1) cb_sizer.Add(self.cbLogX , 0, flag=wx.ALL, border=1) cb_sizer.Add(self.cbLogY , 0, flag=wx.ALL, border=1) cb_sizer.Add(self.cbSync , 0, flag=wx.ALL, border=1) cb_sizer.Add(self.cbXHair , 0, flag=wx.ALL, border=1) self.ctrlPanel.SetSizer(cb_sizer) # --- Ctrl Panel crossHairPanel= wx.Panel(self) self.lbCrossHairX = wx.StaticText(crossHairPanel, -1, 'x= ... ') self.lbCrossHairY = wx.StaticText(crossHairPanel, -1, 'y= ... ') self.lbCrossHairX.SetFont(getMonoFont(self)) self.lbCrossHairY.SetFont(getMonoFont(self)) cbCH = wx.FlexGridSizer(rows=2, cols=1, hgap=2, vgap=0) cbCH.Add(self.lbCrossHairX , 0, flag=wx.ALL, border=1) cbCH.Add(self.lbCrossHairY , 0, flag=wx.ALL, border=1) crossHairPanel.SetSizer(cbCH) # --- layout of panels row_sizer = wx.BoxSizer(wx.HORIZONTAL) sl2 = wx.StaticLine(self, -1, size=wx.Size(1,-1), style=wx.LI_VERTICAL) sl3 = wx.StaticLine(self, -1, size=wx.Size(1,-1), style=wx.LI_VERTICAL) sl4 = wx.StaticLine(self, -1, size=wx.Size(1,-1), style=wx.LI_VERTICAL) row_sizer.Add(self.pltTypePanel , 0 , flag=wx.ALL|wx.CENTER , border=2) row_sizer.Add(sl2 , 0 , flag=wx.EXPAND|wx.CENTER , border=0) row_sizer.Add(self.navTB , 0 , flag=wx.LEFT|wx.RIGHT|wx.CENTER , border=2) row_sizer.Add(sl3 , 0 , flag=wx.EXPAND|wx.CENTER , border=0) row_sizer.Add(self.ctrlPanel , 1 , flag=wx.ALL|wx.EXPAND|wx.CENTER , border=2) row_sizer.Add(sl4 , 0 , flag=wx.EXPAND|wx.CENTER , border=0) row_sizer.Add(crossHairPanel,0, flag=wx.EXPAND|wx.CENTER|wx.LEFT , border=2) plotsizer = wx.BoxSizer(wx.VERTICAL) self.slCtrl = wx.StaticLine(self, -1, size=wx.Size(-1,1), style=wx.LI_HORIZONTAL) self.slCtrl.Hide() sl1 = wx.StaticLine(self, -1, size=wx.Size(-1,1), style=wx.LI_HORIZONTAL) plotsizer.Add(self.toolSizer,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10) plotsizer.Add(self.canvas ,1,flag = wx.EXPAND,border = 5 ) plotsizer.Add(sl1 ,0,flag = wx.EXPAND,border = 0) plotsizer.Add(self.spcPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10) plotsizer.Add(self.pdfPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10) plotsizer.Add(self.cmpPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10) plotsizer.Add(self.mmxPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10) plotsizer.Add(self.slCtrl ,0,flag = wx.EXPAND,border = 0) plotsizer.Add(row_sizer ,0,flag = wx.NORTH ,border = 5) self.show_hide(self.spcPanel, self.pltTypePanel.cbFFT.GetValue()) self.show_hide(self.cmpPanel, self.pltTypePanel.cbCompare.GetValue()) self.show_hide(self.pdfPanel, self.pltTypePanel.cbPDF.GetValue()) self.show_hide(self.mmxPanel, self.pltTypePanel.cbMinMax.GetValue()) self.SetSizer(plotsizer) self.plotsizer=plotsizer; def redraw_event(self, event): self.redraw_same_data() def log_select(self, event): if self.pltTypePanel.cbPDF.GetValue(): self.cbLogX.SetValue(False) self.cbLogY.SetValue(False) else: self.redraw_same_data() def crosshair_event(self, event): try: self.multiCursors.vertOn =self.cbXHair.GetValue() self.multiCursors.horizOn=self.cbXHair.GetValue() self.multiCursors._update() except: pass def scatter_select(self, event): self.cbScatter.SetValue(self.cbScatter.GetValue()) self.redraw_same_data() def show_hide(self,panel,bShow): if bShow: panel.Show() self.slCtrl.Show() else: panel.Hide() self.slCtrl.Hide() @property def sharex(self): return self.cbSync.IsChecked() and (not self.pltTypePanel.cbPDF.GetValue()) def set_subplots(self,nPlots): # Creating subplots for ax in self.fig.axes: self.fig.delaxes(ax) sharex=None for i in range(nPlots): # Vertical stack if i==0: ax=self.fig.add_subplot(nPlots,1,i+1) if self.sharex: sharex=ax else: ax=self.fig.add_subplot(nPlots,1,i+1,sharex=sharex) # Horizontal stack #self.fig.add_subplot(1,nPlots,i+1) def onMouseMove(self, event): if event.inaxes: x, y = event.xdata, event.ydata if abs(x)<1000 and abs(x)>1e-4: self.lbCrossHairX.SetLabel("x={:10.5f}".format(x)) else: self.lbCrossHairX.SetLabel("x={:10.3e}".format(x)) if abs(y)<1000 and abs(y)>1e-4: self.lbCrossHairY.SetLabel("y={:10.5f}".format(y)) else: self.lbCrossHairY.SetLabel("y={:10.3e}".format(y)) def removeTools(self,event=None,Layout=True): try: # Python3 self.toolSizer.Clear(delete_windows=True) # Delete Windows except: # Python2 if hasattr(self,'toolPanel'): self.toolSizer.Remove(self.toolPanel) self.toolPanel.Destroy() del self.toolPanel self.toolSizer.Clear() # Delete Windows if Layout: self.plotsizer.Layout() def showTool(self,toolName=''): self.removeTools(Layout=False) # TODO dictionary if toolName=='LogDec': self.toolPanel=LogDecToolPanel(self) elif toolName=='Mask': self.toolPanel=MaskToolPanel(self) elif toolName=='FASTRadialAverage': self.toolPanel=RadialToolPanel(self) else: raise Exception('Unknown tool {}'.format(toolName)) self.toolSizer.Add(self.toolPanel, 0, wx.EXPAND|wx.ALL, 5) self.plotsizer.Layout() def setPD_PDF(self,d,c): # ---PDF n=len(d.y) if d.yIsString: if n>100: Warn(self,'Dataset has string format and is too large to display') self.pltTypePanel.cbRegular.SetValue(True) return else: vc = c.value_counts().sort_index() d.x = vc.keys().tolist() d.y = vc/n # TODO counts/PDF option d.yIsString=False d.xIsString=True elif d.yIsDate: Warn(self,'Cannot plot PDF of dates') self.pltTypePanel.cbRegular.SetValue(True) return else: nBins=self.pdfPanel.scBins.GetValue() #min(int(n/10),50) if nBins>=n: nBins=n self.pdfPanel.scBins.SetValue(nBins) d.y, d.x = np.histogram(d.y[~np.isnan(d.y)], bins=nBins) dx = d.x[1] - d.x[0] d.x = d.x[:-1] + dx/2 d.y = d.y / (n*dx) # TODO counts /PDF option d.sx = d.sy; d.sy = 'PDF('+no_unit(d.sy)+')' iu = inverse_unit(d.sy) if len(iu)>0: d.sy += ' ['+ iu +']' def setPD_MinMax(self,d): if self.mmxPanel.cbyMinMax.IsChecked(): if d.yIsString: Warn(self,'Cannot compute min-max for strings') self.mmxPanel.cbyMinMax.SetValue(False) #self.pltTypePanel.cbRegular.SetValue(True) return mi= np.nanmin(d.y) mx= np.nanmax(d.y) if mi == mx: d.y=d.y*0 else: d.y = (d.y-mi)/(mx-mi) if self.mmxPanel.cbxMinMax.IsChecked(): if d.xIsString: Warn(self,'Cannot compute min-max for strings') self.mmxPanel.cbxMinMax.SetValue(False) #self.pltTypePanel.cbRegular.SetValue(True) return mi= np.nanmin(d.x) mx= np.nanmax(d.x) if mi == mx: d.x=d.x*0 else: d.x = (d.x-mi)/(mx-mi) def setPD_FFT(self,d): if d.yIsString or d.yIsDate: Warn(self,'Cannot plot FFT of dates or strings') self.pltTypePanel.cbRegular.SetValue(True) elif d.xIsString: Warn(self,'Cannot plot FFT if x axis is string') self.pltTypePanel.cbRegular.SetValue(True) else: output_type = self.spcPanel.cbType.GetStringSelection() averaging = self.spcPanel.cbAveraging.GetStringSelection() averaging_window = self.spcPanel.cbAveragingMethod.GetStringSelection() bDetrend = self.spcPanel.cbDetrend.IsChecked() nExp = self.spcPanel.scP2.GetValue() dt=None if d.xIsDate: dt = getDt(d.x) # --- Computing fft - x is freq, y is Amplitude d.x, d.y, Info = fft_wrap(d.x, d.y, dt=dt, output_type=output_type,averaging=averaging,averaging_window=averaging_window,detrend=bDetrend,nExp=nExp) # --- Setting plot options d.Info=Info d.xIsDate=False d.sy= 'FFT('+no_unit(d.sy)+')' if unit(d.sx)=='s': d.sx= 'Frequency [Hz]' else: d.sx= '' if hasattr(Info,'nExp') and Info.nExp!=nExp: self.spcPanel.scP2.SetValue(Info.nExp) self.spcPanel.updateP2(Info.nExp) def getPlotData(self,plotType): ID,SameCol=self.selPanel.getPlotDataSelection() del self.plotData self.plotData=[] tabs=self.selPanel.tabList.getTabs() # TODO for i,idx in enumerate(ID): d=PlotData(); d.id = i d.it = idx[0] d.ix = idx[1] d.iy = idx[2] d.sx = idx[3] d.sy = idx[4] d.syl = '' d.st = idx[5] d.filename = tabs[d.it].filename d.tabname = tabs[d.it].active_name d.SameCol = SameCol d.x,d.xIsString,d.xIsDate,_ = tabs[d.it].getColumn(d.ix) d.y,d.yIsString,d.yIsDate,c = tabs[d.it].getColumn(d.iy) n=len(d.y) d.needChineseFont = has_chinese_char(d.sy) or has_chinese_char(d.sx) # Stats of the raw data #d.x0Min = xMin(d) #d.x0Max = xMax(d) d.y0Min = yMin(d) d.y0Max = yMax(d) d.y0Std = yStd(d) d.y0Mean = yMean(d) d.n0 = (n,'{:d}'.format(n)) # Possible change of data if plotType=='MinMax': self.setPD_MinMax(d) elif plotType=='PDF': self.setPD_PDF(d,c) elif plotType=='FFT': self.setPD_FFT(d) self.plotData.append(d) def PD_Compare(self,mode): # --- Comparison PD=self.plotData sComp = self.cmpPanel.rbType.GetStringSelection() def getError(y,yref,method): if len(y)!=len(yref): raise NotImplementedError('Cannot compare signals of different lengths') if sComp=='Relative': if np.mean(np.abs(yref))<1e-7: Error=(y-yRef)/(yRef+1)*100 else: Error=(y-yRef)/yRef*100 elif sComp=='|Relative|': if np.mean(np.abs(yref))<1e-7: Error=abs((y-yRef)/(yRef+1))*100 else: Error=abs((y-yRef)/yRef)*100 elif sComp=='Ratio': if np.mean(np.abs(yref))<1e-7: Error=(y+1)/(yRef+1) else: Error=y/yRef elif sComp=='Absolute': Error=y-yRef else: raise Exception('Something wrong '+sComp) return Error def getErrorLabel(ylab=''): if len(ylab)>0: ylab=no_unit(ylab) ylab='in '+ylab+' ' if sComp=='Relative': return 'Relative error '+ylab+'[%]'; elif sComp=='|Relative|': return 'Abs. relative error '+ylab+'[%]'; if sComp=='Ratio': return 'Ratio '+ylab.replace('in','of')+'[-]'; elif sComp=='Absolute': usy = unique([pd.sy for pd in PD]) yunits= unique([unit(sy) for sy in usy]) if len(yunits)==1 and len(yunits[0])>0: return 'Absolute error '+ylab+'['+yunits[0]+']' else: return 'Absolute error '+ylab; elif sComp=='Y-Y': return PD[0].sy xlabelAll=PD[0].sx if any([pd.yIsString for pd in PD]): Warn(self,'Cannot compare strings') self.pltTypePanel.cbRegular.SetValue(True) return if any([pd.yIsDate for pd in PD]): Warn(self,'Cannot compare dates with other values') self.pltTypePanel.cbRegular.SetValue(True) return if mode=='nTabs_1Col': ylabelAll=getErrorLabel(PD[1].sy) usy = unique([pd.sy for pd in PD]) #print('Compare - different tabs - 1 col') st = [pd.st for pd in PD] if len(usy)==1: SS=usy[0] + ', '+ ' wrt. '.join(st[::-1]) if sComp=='Y-Y': xlabelAll=PD[0].st+', '+PD[0].sy ylabelAll=PD[1].st+', '+PD[1].sy else: SS=' wrt. '.join(usy[::-1]) if sComp=='Y-Y': xlabelAll=PD[0].sy ylabelAll=PD[1].sy xRef = PD[0].x yRef = PD[0].y PD[1].syl=SS y=np.interp(xRef,PD[1].x,PD[1].y) if sComp=='Y-Y': PD[1].x=yRef PD[1].y=y else: Error = getError(y,yRef,sComp) PD[1].x=xRef PD[1].y=Error PD[1].sx=xlabelAll PD[1].sy=ylabelAll self.plotData=[PD[1]] elif mode=='1Tab_nCols': # --- Compare one table - different columns #print('One Tab, different columns') ylabelAll=getErrorLabel() xRef = PD[0].x yRef = PD[0].y pdRef=PD[0] for pd in PD[1:]: if sComp=='Y-Y': pd.syl = no_unit(pd.sy)+' wrt. '+no_unit(pdRef.sy) pd.x = yRef pd.sx = PD[0].sy else: pd.syl = no_unit(pd.sy)+' wrt. '+no_unit(pdRef.sy) pd.sx = xlabelAll pd.sy = ylabelAll Error = getError(pd.y,yRef,sComp) pd.x=xRef pd.y=Error self.plotData=PD[1:] elif mode =='nTabs_SameCols': # --- Compare different tables, same column #print('Several Tabs, same columns') uiy=unique([pd.iy for pd in PD]) uit=unique([pd.it for pd in PD]) self.plotData=[] for iy in uiy: PD_SameCol=[pd for pd in PD if pd.iy==iy] xRef = PD_SameCol[0].x yRef = PD_SameCol[0].y ylabelAll=getErrorLabel(PD_SameCol[0].sy) for pd in PD_SameCol[1:]: if pd.xIsString: if len(xRef)==len(pd.x): pass # fine able to interpolate else: Error(self,'X values have different length and are strings, cannot interpolate string. Use `Index` for x instead.') else: pd.y=np.interp(xRef,pd.x,pd.y) if sComp=='Y-Y': pd.x=yRef pd.sx=PD_SameCol[0].st+', '+PD_SameCol[0].sy if len(PD_SameCol)==1: pd.sy =pd.st+', '+pd.sy else: pd.syl= pd.st else: if len(uit)<=2: pd.syl = pd.st+' wrt. '+PD_SameCol[0].st+', '+pd.sy else: pd.syl = pd.st+'|'+pd.sy pd.sx = xlabelAll pd.sy = ylabelAll Error = getError(pd.y,yRef,sComp) pd.x=xRef pd.y=Error self.plotData.append(pd) def plot_all(self): self.multiCursors=[] axes=self.fig.axes bScatter=self.cbScatter.IsChecked() PD=self.plotData needChineseFont = any([pd.needChineseFont for pd in PD]) if needChineseFont and self.specialFont is not None: font_options = {'fontproperties': self.specialFont} font_options_legd = {'prop': self.specialFont} else: font_options = {} font_options_legd = {} bAllNeg=True for ax in axes: # Plot data vDate=[PD[i].yIsDate for i in ax.iPD] if any(vDate) and len(vDate)>1: Error(self,'Cannot plot date and other value on the same axis') return #Keep me - tight axis, attempt to optimize #try: # xMin=np.min([PD[i].x0Min[0] for i in ax.iPD]) # xMax=np.max([PD[i].x0Max[0] for i in ax.iPD]) # ax.set_xlim(xMin,xMax) # ax.autoscale(False) #except: # pass #try: # yMin=np.min([PD[i].y0Min[0] for i in ax.iPD]) # yMax=np.max([PD[i].y0Max[0] for i in ax.iPD]) # ax.set_ylim(yMin,yMax) # ax.autoscale(False) #except: # pass for ipd in ax.iPD: pd=PD[ipd] if bScatter or len(pd.x)==1: sty='o' else: sty='-' ax.plot(pd.x,pd.y,sty,label=pd.syl,markersize=1) try: bAllNeg=bAllNeg and all(pd.y<=0) except: pass # Dates # Log Axes if self.cbLogX.IsChecked(): ax.set_xscale("log", nonposx='clip') if self.cbLogY.IsChecked(): if bAllNeg: pass else: ax.set_yscale("log", nonposy='clip') # XLIM - TODO FFT ONLY NASTY if self.pltTypePanel.cbFFT.GetValue(): try: xlim=float(self.spcPanel.tMaxFreq.GetLineText(0)) if xlim>0: ax.set_xlim([0,xlim]) pd=PD[ax.iPD[0]] I=pd.x<xlim ymin = np.min([np.min(PD[ipd].y[I]) for ipd in ax.iPD]) ax.set_ylim(bottom=ymin/2) except: pass # Special Grids if self.pltTypePanel.cbCompare.GetValue(): if self.cmpPanel.rbType.GetStringSelection()=='Y-Y': xmin,xmax=ax.get_xlim() ax.plot([xmin,xmax],[xmin,xmax],'k--',linewidth=0.5) # Labels axes[-1].set_xlabel(PD[axes[-1].iPD[0]].sx, **font_options) for ax in axes: usy = unique([PD[i].sy for i in ax.iPD]) if len(usy)<=3: ax.set_ylabel(' and '.join(usy), **font_options) # consider legend else: ax.set_ylabel('') # Legend #print('sy :',[pd.sy for pd in PD]) #print('syl:',[pd.syl for pd in PD]) usyP0 = unique([PD[i].syl for i in axes[0].iPD]) if self.pltTypePanel.cbCompare.GetValue(): for ax in axes: ax.legend(fancybox=False, loc=1, **font_options_legd) elif len(usyP0)>1: #axes[0].legend(fancybox=False, framealpha=1, loc=1, shadow=None) axes[0].legend(fancybox=False, loc=1, **font_options_legd) elif len(axes)>1 and len(axes)==len(PD): # Special case when we have subplots and all plots have the same label usy = unique([pd.sy for pd in PD]) if len(usy)==1: for ax in axes: ax.legend(fancybox=False, loc=1, **font_options_legd) # --- Cursors for each individual plot # NOTE: cursors needs to be stored in the object! #for ax in self.fig.axes: # self.cursors.append(MyCursor(ax,horizOn=True, vertOn=False, useblit=True, color='gray', linewidth=0.5, linestyle=':')) # Vertical cusor for all, commonly bXHair = self.cbXHair.GetValue() self.multiCursors = MyMultiCursor(self.canvas, tuple(self.fig.axes), useblit=True, horizOn=bXHair, vertOn=bXHair, color='gray', linewidth=0.5, linestyle=':') def findPlotMode(self,PD): uTabs=unique([pd.it for pd in PD]) usy=unique([pd.sy for pd in PD]) uiy=unique([pd.iy for pd in PD]) if len(uTabs)<=0: raise Exception('No Table. Contact developer') elif len(uTabs)==1: mode='1Tab_nCols' else: if PD[0].SameCol: mode='nTabs_SameCols' else: mode='nTabs_1Col' return mode def findSubPlots(self,PD,mode): uTabs = unique([pd.it for pd in PD]) usy = unique([pd.sy for pd in PD]) bSubPlots = self.cbSub.IsChecked() bCompare = self.pltTypePanel.cbCompare.GetValue() # NOTE bCompare somehow always 1Tab_nCols nSubPlots=1 spreadBy='none' if mode=='1Tab_nCols': if bSubPlots: if bCompare: nSubPlots=len(PD) spreadBy='iy' else: if len(uTabs)==1: nSubPlots=len(PD) else: nSubPlots=len(usy) spreadBy='iy' elif mode=='nTabs_SameCols': if bSubPlots: if bCompare: print('>>>TODO ',mode,len(usy),len(uTabs)) else: if len(usy)==1: # Temporary hack until we have an option for spread by tabs or col nSubPlots=len(uTabs) spreadBy='it' else: nSubPlots=len(usy) spreadBy='iy' else: mode='nTabs_1Col' if bSubPlots: if bCompare: print('>>> TODO',mode,len(uTabs)) else: nSubPlots=len(uTabs) spreadBy='it' return nSubPlots,spreadBy def distributePlots(self,mode,nSubPlots,spreadBy): """ Assigns plot data to axes and axes to plot data """ axes=self.fig.axes # Link plot data to axes if nSubPlots==1 or spreadBy=='none': axes[0].iPD=[i for i in range(len(self.plotData))] else: for ax in axes: ax.iPD=[] PD=self.plotData uTabs=unique([pd.it for pd in PD]) uiy=unique([pd.iy for pd in PD]) if spreadBy=='iy': for ipd,pd in enumerate(PD): i=uiy.index(pd.iy) axes[i].iPD.append(ipd) elif spreadBy=='it': for ipd,pd in enumerate(PD): i=uTabs.index(pd.it) axes[i].iPD.append(ipd) else: raise Exception('Wrong spreadby value') def setLegendLabels(self,mode): """ Set labels for legend """ if mode=='1Tab_nCols': for pd in self.plotData: if self.pltTypePanel.cbMinMax.GetValue(): pd.syl = no_unit(pd.sy) else: pd.syl = pd.sy elif mode=='nTabs_SameCols': for pd in self.plotData: pd.syl=pd.st elif mode=='nTabs_1Col': usy=unique([pd.sy for pd in self.plotData]) if len(usy)==1: for pd in self.plotData: pd.syl=pd.st else: for pd in self.plotData: if self.pltTypePanel.cbMinMax.GetValue(): pd.syl=no_unit(pd.sy) else: pd.syl=pd.sy #pd.syl=pd.st + ' - '+pd.sy def empty(self): self.cleanPlot() def clean_memory(self): if hasattr(self,'plotData'): del self.plotData self.plotData=[] for ax in self.fig.axes: ax.iPD=[] self.fig.delaxes(ax) gc.collect() def clean_memory_plot(self): pass def cleanPlot(self): for ax in self.fig.axes: if hasattr(ax,'iPD'): del ax.iPD self.fig.delaxes(ax) gc.collect() self.fig.add_subplot(111) ax = self.fig.axes[0] ax.set_axis_off() #ax.plot(1,1) self.canvas.draw() gc.collect() def redraw(self): self._redraw() if self.infoPanel is not None: self.infoPanel.showStats(self.plotData,self.pltTypePanel.plotType()) def redraw_same_data(self): self._redraw_same_data() def _redraw_same_data(self): if len(self.plotData)==0: self.cleanPlot(); return mode=self.findPlotMode(self.plotData) nPlots,spreadBy=self.findSubPlots(self.plotData,mode) self.clean_memory_plot() self.set_subplots(nPlots) self.distributePlots(mode,nPlots,spreadBy) if not self.pltTypePanel.cbCompare.GetValue(): self.setLegendLabels(mode) self.plot_all() self.canvas.draw() def _redraw(self): self.clean_memory() self.getPlotData(self.pltTypePanel.plotType()) if len(self.plotData)==0: self.cleanPlot(); return mode=self.findPlotMode(self.plotData) if self.pltTypePanel.cbCompare.GetValue(): self.PD_Compare(mode) if len(self.plotData)==0: self.cleanPlot(); return self._redraw_same_data()
class AppForm(QMainWindow, QWidget): def __init__(self, parent=None): QMainWindow.__init__(self, parent) icon = QIcon("32959206.png") self.setWindowIcon(icon) self.setWindowTitle('Graphic3D') self.setup(self) self.create_main_frame() self.create_menu() def setup(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.setStyleSheet( "#MainWindow { border-image: url(bg.png) 0 0 0 0 stretch stretch; }" ) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") def create_menu(self): #self.statusBar() #self.setFocus() openfile = QAction(QIcon('icons/Blue_Flower.ico'), 'Open', self) openfile.setShortcut('Ctrl+O') openfile.setStatusTip('Open new file') openfile.triggered.connect(self.openfile) quitui = QAction(QIcon('icons/Blue_Flower.ico'), 'Quit', self) quitui.setShortcut('Ctrl+Q') quitui.setStatusTip('Quit') quitui.triggered.connect(self.close) saveplot = QAction(QIcon('icons/Blue_Flower.ico'), 'Save Plot', self) saveplot.setShortcut('Ctrl+S') saveplot.setStatusTip('Save Plot') saveplot.triggered.connect(self.save_plot) about = QAction(QIcon('icons/Blue_Flower.ico'), 'About', self) about.setShortcut('Ctrl+A') about.setStatusTip('About') about.triggered.connect(self.on_about) menubar = self.menuBar() file = menubar.addMenu('&File') file.addAction(openfile) file.addAction(saveplot) file.addAction(quitui) helpabout = menubar.addMenu('&Help') helpabout.addAction(about) def mainaxes(self): self.axes = self.fig.add_subplot(1, 2, 1, projection='3d') self.axes.set_alpha(0) self.axes.patch.set_alpha(0) self.axes.set_aspect('equal') self.axes.set_xlim3d(-1, 42) self.axes.set_ylim3d(-1, 42) self.axes.set_zlim3d(-1, 63) self.axes.set_xlabel('x-axis') self.axes.set_ylabel('y-axis') self.axes.set_zlabel('z-axis') xmajorLocator = MultipleLocator(5) ymajorLocator = MultipleLocator(5) zmajorLocator = MultipleLocator(5) self.axes.xaxis.set_major_locator(xmajorLocator) self.axes.yaxis.set_major_locator(ymajorLocator) self.axes.zaxis.set_major_locator(zmajorLocator) def create_main_frame(self): #self.main_frame = QWidget() self.dpi = 100 self.fig = Figure((15.0, 12.0), dpi=self.dpi) self.fig.set_facecolor('none') self.canvas = FigureCanvas(self.fig) #self.canvas.setParent(self.main_frame) self.canvas.setParent(self.centralwidget) self.canvas.setStyleSheet("background-color:transparent;") # Since we have only one plot, we can use add_axes # instead of add_subplot, but then the subplot # configuration tool in the navigation toolbar wouldn't # work. self.fig.subplots_adjust(left=0.03, bottom=0.08, right=0.95, top=0.95, wspace=0.2, hspace=0.2) self.mainaxes() xmajorLocator = MultipleLocator(5) ymajorLocator = MultipleLocator(5) xminorLocator = MultipleLocator(1) yminorLocator = MultipleLocator(1) self.axx = self.fig.add_subplot(243) self.axx.set_xlim(0, 41) self.axx.set_ylim(0, 62) self.axx.grid(color='k', linestyle='--', linewidth=0.5, which='minor') self.axx.xaxis.set_major_locator(xmajorLocator) self.axx.yaxis.set_major_locator(ymajorLocator) self.axx.xaxis.set_minor_locator(xminorLocator) self.axx.yaxis.set_minor_locator(yminorLocator) self.axx.set_title('Y-Z section', loc='center') #self.axx.set_aspect('equal') self.axy = self.fig.add_subplot(244) self.axy.set_xlim(0, 41) self.axy.set_ylim(0, 62) self.axy.grid(color='k', linestyle='--', linewidth=0.5, which='minor') self.axy.xaxis.set_major_locator(xmajorLocator) self.axy.yaxis.set_major_locator(ymajorLocator) self.axy.xaxis.set_minor_locator(xminorLocator) self.axy.yaxis.set_minor_locator(yminorLocator) self.axy.set_title('X-Z section', loc='center') #self.axy.set_aspect('equal') self.axz = self.fig.add_subplot(248) self.axz.set_xlim(0, 41) self.axz.set_ylim(0, 41) self.axz.grid(color='k', linestyle='--', linewidth=0.5, which='minor') xmajorLocator = MultipleLocator(5) ymajorLocator = MultipleLocator(5) xminorLocator = MultipleLocator(1) yminorLocator = MultipleLocator(1) self.axz.xaxis.set_major_locator(xmajorLocator) self.axz.yaxis.set_major_locator(ymajorLocator) self.axz.xaxis.set_minor_locator(xminorLocator) self.axz.yaxis.set_minor_locator(yminorLocator) self.axz.set_title('X-Y section', loc='center') #self.axz.set_aspect('equal') self.logo = self.fig.add_subplot(247) self.logo.set_aspect('equal') #self.logo.set_xlim(-100,300) #self.logo.set_ylim(250,-70) img = mpimg.imread('color.png') imgplot = self.logo.imshow(img) self.logo.set_axis_off() self.fig.canvas.mpl_connect('button_press_event', self.onpressx) self.fig.canvas.mpl_connect('button_press_event', self.onpressy) self.fig.canvas.mpl_connect('button_press_event', self.onpressz) font = QFont() font.setFamily('Comic Sans MS') font.setBold(True) #大小 font.setPointSize(10) font.setWeight(60) slider_labelcolor = QLabel('Show:') slider_labelcolor.setFont(font) #slider_labelcolor.setText("<font color=%s>%s</font>" %('#000000', "Show:")) self.comboboxcolor = QComboBox(self) colors = [ 'View All', 'vsave < 3', '3 < vsave < 4', '4 < vsave < 5', '5 < vsave < 6', '6 < vsave < 7', '8 < vsave' ] self.comboboxcolor.addItems(colors) #self.comboboxcolor.setMaxVisibleItems(5) self.comboboxcolor.setStyleSheet( "border: 1px solid gray;border-radius:3px;padding: 1px 18px 1px 3px;min-width: 5em;selection-background-color: darkgray;" ) self.comboboxcolor.setFont(font) self.comboboxcolor.activated.connect(self.onecolor) self.returnbtn = QPushButton() self.returnbtn.setFont(font) self.returnbtn.clicked.connect(self.zoom) self.returnbtn.setStyleSheet( 'QPushButton{border-image:url(return.png)}') self.zoombutton = QPushButton() self.zoombutton.setText('ZOOM') self.zoombutton.setFont(font) self.zoombutton.setStyleSheet( "color:white;background-color:black;border-radius:4px;min-width: 5em;" ) self.i = 0 self.zoombutton.clicked.connect(self.count) self.sliderfig = QSlider(Qt.Horizontal) self.sliderfig.setRange(0, 99) self.sliderfig.setStyleSheet( "QSlider::handle:horizontal { border-radius:3px;border-image:url(rb.png);}" ) self.sliderfig.valueChanged.connect(self.zoomin) self.labezoomin = QLabel(self) self.labezoomout = QLabel(self) self.pixmapin = QPixmap('zo_opt.png') self.labezoomin.setPixmap(self.pixmapin) self.pixmapout = QPixmap('zi_opt.png') self.labezoomout.setPixmap(self.pixmapout) textboxx_label = QLabel(' Y-Z section : ') self.textboxx = QLineEdit(self) self.textboxx.setText('0') textboxx_label.setFont(font) self.textboxx.setStyleSheet( "border: 1px solid gray;border-radius:4px;padding: 1px 18px 1px 3px;min-width: 3em;" ) textboxy_label = QLabel(' X-Z section : ') self.textboxy = QLineEdit(self) self.textboxy.setText('0') textboxy_label.setFont(font) self.textboxy.setStyleSheet( "border: 1px solid gray;border-radius:4px;padding: 1px 18px 1px 3px;min-width: 3em;" ) textboxz_label = QLabel(' X-Y section : ') self.textboxz = QLineEdit(self) self.textboxz.setText('0') textboxz_label.setFont(font) self.textboxz.setStyleSheet( "border: 1px solid gray;border-radius:4px;padding: 1px 18px 1px 3px;min-width: 3em;" ) self.drawbutton = QPushButton() self.drawbutton.setText('DRAW') self.drawbutton.setFont(font) self.drawbutton.setStyleSheet( "color:white;background-color:black;border-radius:4px;min-width: 5em;" ) self.drawbutton.clicked.connect(self.drawsection) hbox = QHBoxLayout() for w in [ self.zoombutton, self.returnbtn, self.labezoomin, self.sliderfig, self.labezoomout, slider_labelcolor, self.comboboxcolor, textboxx_label, self.textboxx, textboxy_label, self.textboxy, textboxz_label, self.textboxz, self.drawbutton ]: hbox.addWidget(w) hbox.setAlignment(w, Qt.AlignVCenter) vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(self.canvas) #self.main_frame.setLayout(vbox) #self.setCentralWidget(self.main_frame) self.setCentralWidget(self.centralwidget) self.centralwidget.setLayout(vbox) #self.setCentralWidget.setMouseTracking(True) def on_about(self): msg = """ * Choose .pvel file * Input the number which scale of the sections in three axis separately you want to display then push the 'DRAW' button to show the 2D sections * Use the slider to zoom in/out the 3D model of the .pvel file * You can display single layer in 3D model by using the combobox """ QMessageBox.about(self, "About Graphic3D", msg.strip()) def count(self): self.i += 1 if self.i % 2 == 1: self.zoombutton.setStyleSheet( "color:white;background-color:red;border-radius:4px;min-width: 5em;" ) self.zoomcenter() self.zoom() else: self.zoombutton.setStyleSheet( "color:white;background-color:black;border-radius:4px;min-width: 5em;" ) self.setMouseTracking(False) self.fig.delaxes(self.zoomin) self.mainaxes() self.on_draw() def zoomcenter(self): if self.i % 2 == 1: #self.fig.canvas.mpl_connect('button_press_event',self.onpress) self.fig.canvas.mpl_connect('button_release_event', self.onrelease) self.pressevent = None def onpressx(self, event): if event.inaxes != self.axx: return self.pressevent = None self.x = event.xdata self.y = event.ydata val = self.textboxx.text() v = int(val) x = int(self.x) y = int(self.y) print(v, x, y) msg = "You've clicked on a point : ( %s ," % v + " %s ," % x + " %s )\n" % y + "Value:%f " % self.data[ v, x, y] QMessageBox.information(self, "Click!", msg) def onpressy(self, event): if event.inaxes != self.axy: return self.pressevent = None self.x = event.xdata self.y = event.ydata val = self.textboxy.text() v = int(val) x = int(self.x) y = int(self.y) print(x, v, y) msg = "You've clicked on a point : ( %s ," % x + " %s ," % v + " %s )\n" % y + "Value:%f " % self.data[ x, v, y] QMessageBox.information(self, "Click!", msg) def onpressz(self, event): if event.inaxes != self.axz: return self.pressevent = None self.x = event.xdata self.y = event.ydata val = self.textboxz.text() v = int(val) x = int(self.x) y = int(self.y) print(x, y, v) msg = "You've clicked on a point : ( %s ," % x + " %s ," % y + " %s )\n" % v + "Value:%f " % self.data[ x, y, v] QMessageBox.information(self, "Click!", msg) def onrelease(self, event): self.pressevent = None self.x = event.xdata self.y = event.ydata print(self.x, self.y) def zoom(self): extent = self.axes.get_window_extent().transformed( self.fig.dpi_scale_trans.inverted()) self.fig.savefig('axeszoom.png', bbox_inches=extent.expanded(1.1, 1.2), dpi=200, transparent=True) self.fig.delaxes(self.axes) self.zoomin = self.fig.add_subplot(121) img = mpimg.imread('axeszoom.png') imgplot = self.zoomin.imshow(img) self.setMouseTracking(True) self.zoomin.set_xlim(150, 1650) self.zoomin.set_ylim(1750, 180) #self.zoomin.set_aspect('equal') self.zoomin.set_alpha(0) self.zoomin.patch.set_alpha(0) self.zoomin.set_axis_off() print('AA') def zoomin(self): print(self.sliderfig.value()) z = self.sliderfig.value() self.zoomin.set_xlim(self.x - (self.x - 150) * (100 - z) / 100, self.x + (1650 - self.x) * (100 - z) / 100) self.zoomin.set_ylim(self.y + (1750 - self.y) * (100 - z) / 100, self.y - (self.y - 180) * (100 - z) / 100) #self.zoomin.set_aspect('equal') print('aa') def save_plot(self): file_choices = "PNG (*.png)|*.png" path = QFileDialog.getSaveFileName(self, 'Save file', '', file_choices) extent = self.axes.get_window_extent().transformed( self.fig.dpi_scale_trans.inverted()) self.fig.savefig("3Dmodel.png", bbox_inches=extent.expanded(1.2, 1.2), dpi=200, transparent=True) extent = self.axx.get_window_extent().transformed( self.fig.dpi_scale_trans.inverted()) self.fig.savefig("YZ_section_%s.png" % self.textboxx.text(), bbox_inches=extent.expanded(1.2, 1.2), dpi=200, transparent=True) extent = self.axy.get_window_extent().transformed( self.fig.dpi_scale_trans.inverted()) self.fig.savefig("XZ_section_%s.png" % self.textboxy.text(), bbox_inches=extent.expanded(1.2, 1.2), dpi=200, transparent=True) extent = self.axz.get_window_extent().transformed( self.fig.dpi_scale_trans.inverted()) self.fig.savefig("XY_section_%s.png" % self.textboxz.text(), bbox_inches=extent.expanded(1.2, 1.2), dpi=200, transparent=True) if path: self.canvas.print_figure(path[0], dpi=self.dpi) self.statusBar().showMessage('Saved to %s' % path, 2000) @jit def openfile(self): filename, _ = QFileDialog.getOpenFileName(self, 'Open file', './') file = open(filename) print(filename) line = file.readline() self.test = [] while line: fline = float(line) if fline == 0: break else: self.test.append(fline) line = file.readline() self.data = np.zeros((41, 41, 62), dtype=np.float) self.color = np.zeros((41, 41, 62), dtype=np.int) i = 0 j = 0 k = 0 x = 0 while j < 41: k = 0 while k < 62: i = 0 while i < 41: self.data[i, j, k] = self.test[x] if self.test[x] < 3: self.color[i, j, k] = 0 elif self.test[x] > 3 and self.test[x] < 4: self.color[i, j, k] = 1 elif self.test[x] > 4 and self.test[x] < 5: self.color[i, j, k] = 2 elif self.test[x] > 5 and self.test[x] < 6: self.color[i, j, k] = 3 elif self.test[x] > 6 and self.test[x] < 7: self.color[i, j, k] = 4 elif self.test[x] > 7 and self.test[x] < 8: self.color[i, j, k] = 5 elif self.test[x] > 8: self.color[i, j, k] = 6 x = x + 1 i = i + 1 k = k + 1 j = j + 1 print(self.color[40, 40, 61]) print(self.test[104221]) self.on_draw() @jit def on_draw(self): b = 0 while b < 41: c = 0 while c < 62: self.edges = [[(0, 0 + b, 0 + c), (1, 0 + b, 0 + c), (1, 1 + b, 0 + c), (0, 1 + b, 0 + c)], [(1, 0 + b, 0 + c), (1, 1 + b, 0 + c), (1, 1 + b, 1 + c), (1, 0 + b, 1 + c)], [(0, 1 + b, 0 + c), (0, 1 + b, 1 + c), (1, 1 + b, 1 + c), (1, 1 + b, 0 + c)], [(0, 1 + b, 1 + c), (0, 1 + b, 0 + c), (0, 0 + b, 0 + c), (0, 0 + b, 1 + c)], [(0, 0 + b, 0 + c), (0, 0 + b, 1 + c), (1, 0 + b, 1 + c), (1, 0 + b, 0 + c)], [(0, 1 + b, 1 + c), (0, 0 + b, 1 + c), (1, 0 + b, 1 + c), (1, 1 + b, 1 + c)]] self.faces = Poly3DCollection(self.edges, color='k', linewidth=0.5, zorder=1) if self.color[0, b, c] == 0: self.faces.set_facecolor((1, 0, 0.1, 1)) elif self.color[0, b, c] == 1: self.faces.set_facecolor((1, 0.5, 0, 1)) elif self.color[0, b, c] == 2: self.faces.set_facecolor((1, 1, 0, 1)) elif self.color[0, b, c] == 3: self.faces.set_facecolor((0.5, 1, 0, 1)) elif self.color[0, b, c] == 4: self.faces.set_facecolor((0, 1, 1, 1)) elif self.color[0, b, c] == 5: self.faces.set_facecolor((0, 0, 1, 1)) elif self.color[0, b, c] == 6: self.faces.set_facecolor((0.5, 0.2, 0.9, 1)) self.axes.add_collection3d(self.faces) c = c + 1 b = b + 1 b = 0 while b < 41: c = 0 while c < 62: self.edges = [[(40, 0 + b, 0 + c), (41, 0 + b, 0 + c), (41, 1 + b, 0 + c), (40, 1 + b, 0 + c)], [(41, 0 + b, 0 + c), (41, 1 + b, 0 + c), (41, 1 + b, 1 + c), (41, 0 + b, 1 + c)], [(40, 1 + b, 0 + c), (40, 1 + b, 1 + c), (41, 1 + b, 1 + c), (41, 1 + b, 0 + c)], [(40, 1 + b, 1 + c), (40, 1 + b, 0 + c), (40, 0 + b, 0 + c), (40, 0 + b, 1 + c)], [(40, 0 + b, 0 + c), (40, 0 + b, 1 + c), (41, 0 + b, 1 + c), (41, 0 + b, 0 + c)], [(40, 1 + b, 1 + c), (40, 0 + b, 1 + c), (41, 0 + b, 1 + c), (41, 1 + b, 1 + c)]] self.faces = Poly3DCollection(self.edges, color='k', linewidth=0.5, zorder=1) if self.color[40, b, c] == 0: self.faces.set_facecolor((1, 0, 0.1, 1)) elif self.color[40, b, c] == 1: self.faces.set_facecolor((1, 0.5, 0, 1)) elif self.color[40, b, c] == 2: self.faces.set_facecolor((1, 1, 0, 1)) elif self.color[40, b, c] == 3: self.faces.set_facecolor((0.5, 1, 0, 1)) elif self.color[40, b, c] == 4: self.faces.set_facecolor((0, 1, 1, 1)) elif self.color[40, b, c] == 5: self.faces.set_facecolor((0, 0, 1, 1)) elif self.color[40, b, c] == 6: self.faces.set_facecolor((0.5, 0.2, 0.9, 1)) self.axes.add_collection3d(self.faces) c = c + 1 b = b + 1 a = 0 while a < 41: c = 0 while c < 62: self.edges = [[(0 + a, 40, 0 + c), (1 + a, 40, 0 + c), (1 + a, 41, 0 + c), (0 + a, 41, 0 + c)], [(1 + a, 40, 0 + c), (1 + a, 41, 0 + c), (1 + a, 41, 1 + c), (1 + a, 40, 1 + c)], [(0 + a, 41, 0 + c), (0 + a, 41, 1 + c), (1 + a, 41, 1 + c), (1 + a, 41, 0 + c)], [(0 + a, 41, 1 + c), (0 + a, 41, 0 + c), (0 + a, 40, 0 + c), (0 + a, 40, 1 + c)], [(0 + a, 40, 0 + c), (0 + a, 40, 1 + c), (1 + a, 40, 1 + c), (1 + a, 40, 0 + c)], [(0 + a, 41, 1 + c), (0 + a, 40, 1 + c), (1 + a, 40, 1 + c), (1 + a, 41, 1 + c)]] self.faces = Poly3DCollection(self.edges, color='k', linewidth=0.5, zorder=1) if self.color[a, 40, c] == 0: self.faces.set_facecolor((1, 0, 0.1, 1)) elif self.color[a, 40, c] == 1: self.faces.set_facecolor((1, 0.5, 0, 1)) elif self.color[a, 40, c] == 2: self.faces.set_facecolor((1, 1, 0, 1)) elif self.color[a, 40, c] == 3: self.faces.set_facecolor((0.5, 1, 0, 1)) elif self.color[a, 40, c] == 4: self.faces.set_facecolor((0, 1, 1, 1)) elif self.color[a, 40, c] == 5: self.faces.set_facecolor((0, 0, 1, 1)) elif self.color[a, 40, c] == 6: self.faces.set_facecolor((0.5, 0.2, 0.9, 1)) self.axes.add_collection3d(self.faces) c = c + 1 a = a + 1 a = 0 while a < 41: c = 0 while c < 62: self.edges = [[(0 + a, 0, 0 + c), (1 + a, 0, 0 + c), (1 + a, 1, 0 + c), (0 + a, 1, 0 + c)], [(1 + a, 0, 0 + c), (1 + a, 1, 0 + c), (1 + a, 1, 1 + c), (1 + a, 0, 1 + c)], [(0 + a, 1, 0 + c), (0 + a, 1, 1 + c), (1 + a, 1, 1 + c), (1 + a, 1, 0 + c)], [(0 + a, 1, 1 + c), (0 + a, 1, 0 + c), (0 + a, 0, 0 + c), (0 + a, 0, 1 + c)], [(0 + a, 0, 0 + c), (0 + a, 0, 1 + c), (1 + a, 0, 1 + c), (1 + a, 0, 0 + c)], [(0 + a, 1, 1 + c), (0 + a, 0, 1 + c), (1 + a, 0, 1 + c), (1 + a, 1, 1 + c)]] self.faces = Poly3DCollection(self.edges, color='k', linewidth=0.5, zorder=1) if self.color[a, 0, c] == 0: self.faces.set_facecolor((1, 0, 0.1, 1)) elif self.color[a, 0, c] == 1: self.faces.set_facecolor((1, 0.5, 0, 1)) elif self.color[a, 0, c] == 2: self.faces.set_facecolor((1, 1, 0, 1)) elif self.color[a, 0, c] == 3: self.faces.set_facecolor((0.5, 1, 0, 1)) elif self.color[a, 0, c] == 4: self.faces.set_facecolor((0, 1, 1, 1)) elif self.color[a, 0, c] == 5: self.faces.set_facecolor((0, 0, 1, 1)) elif self.color[a, 0, c] == 6: self.faces.set_facecolor((0.5, 0.2, 0.9, 1)) self.axes.add_collection3d(self.faces) c = c + 1 a = a + 1 a = 0 while a < 41: b = 0 while b < 41: self.edges = [[(0 + a, 0 + b, 0), (1 + a, 0 + b, 0), (1 + a, 1 + b, 0), (0 + a, 1 + b, 0)], [(1 + a, 0 + b, 0), (1 + a, 1 + b, 0), (1 + a, 1 + b, 1), (1 + a, 0 + b, 1)], [(0 + a, 1 + b, 0), (0 + a, 1 + b, 1), (1 + a, 1 + b, 1), (1 + a, 1 + b, 0)], [(0 + a, 1 + b, 1), (0 + a, 1 + b, 0), (0 + a, 0 + b, 0), (0 + a, 0 + b, 1)], [(0 + a, 0 + b, 0), (0 + a, 0 + b, 1), (1 + a, 0 + b, 1), (1 + a, 0 + b, 0)], [(0 + a, 1 + b, 1), (0 + a, 0 + b, 1), (1 + a, 0 + b, 1), (1 + a, 1 + b, 1)]] self.faces = Poly3DCollection(self.edges, color='k', linewidth=0.5, zorder=1) if self.color[a, b, 0] == 0: self.faces.set_facecolor((1, 0, 0.1, 1)) elif self.color[a, b, 0] == 1: self.faces.set_facecolor((1, 0.5, 0, 1)) elif self.color[a, b, 0] == 2: self.faces.set_facecolor((1, 1, 0, 1)) elif self.color[a, b, 0] == 3: self.faces.set_facecolor((0.5, 1, 0, 1)) elif self.color[a, b, 0] == 4: self.faces.set_facecolor((0, 1, 1, 1)) elif self.color[a, b, 0] == 5: self.faces.set_facecolor((0, 0, 1, 1)) elif self.color[a, b, 0] == 6: self.faces.set_facecolor((0.5, 0.2, 0.9, 1)) self.axes.add_collection3d(self.faces) b = b + 1 a = a + 1 a = 0 while a < 41: b = 0 while b < 41: self.edges = [[(0 + a, 0 + b, 61), (1 + a, 0 + b, 61), (1 + a, 1 + b, 61), (0 + a, 1 + b, 61)], [(1 + a, 0 + b, 61), (1 + a, 1 + b, 61), (1 + a, 1 + b, 62), (1 + a, 0 + b, 62)], [(0 + a, 1 + b, 61), (0 + a, 1 + b, 62), (1 + a, 1 + b, 62), (1 + a, 1 + b, 61)], [(0 + a, 1 + b, 62), (0 + a, 1 + b, 61), (0 + a, 0 + b, 61), (0 + a, 0 + b, 62)], [(0 + a, 0 + b, 61), (0 + a, 0 + b, 62), (1 + a, 0 + b, 62), (1 + a, 0 + b, 61)], [(0 + a, 1 + b, 62), (0 + a, 0 + b, 62), (1 + a, 0 + b, 62), (1 + a, 1 + b, 62)]] self.faces = Poly3DCollection(self.edges, color='k', linewidth=0.5, zorder=1) if self.color[a, b, 61] == 0: self.faces.set_facecolor((1, 0, 0.1, 1)) elif self.color[a, b, 61] == 1: self.faces.set_facecolor((1, 0.5, 0, 1)) elif self.color[a, b, 61] == 2: self.faces.set_facecolor((1, 1, 0, 1)) elif self.color[a, b, 61] == 3: self.faces.set_facecolor((0.5, 1, 0, 1)) elif self.color[a, b, 61] == 4: self.faces.set_facecolor((0, 1, 1, 1)) elif self.color[a, b, 61] == 5: self.faces.set_facecolor((0, 0, 1, 1)) elif self.color[a, b, 61] == 6: self.faces.set_facecolor((0.5, 0.2, 0.9, 1)) self.axes.add_collection3d(self.faces) b = b + 1 a = a + 1 @jit def coloronly(self, index, r, b, g, a): self.canvas.draw() self.axes.cla() self.axes.set_xlim3d(-1, 42) self.axes.set_ylim3d(-1, 42) self.axes.set_zlim3d(-1, 63) xmajorLocator = MultipleLocator(5) ymajorLocator = MultipleLocator(5) zmajorLocator = MultipleLocator(5) self.axes.xaxis.set_major_locator(xmajorLocator) self.axes.yaxis.set_major_locator(ymajorLocator) self.axes.zaxis.set_major_locator(zmajorLocator) self.axes.set_alpha(0) self.axes.patch.set_alpha(0) i = 0 while i < 41: j = 0 while j < 41: k = 0 while k < 62: if self.color[i, j, k] == index: print(self.color[i, j, k], index) self.edges = [[(0 + i, 0 + j, 0 + k), (1 + i, 0 + j, 0 + k), (1 + i, 1 + j, 0 + k), (0 + i, 1 + j, 0 + k)], [(1 + i, 0 + j, 0 + k), (1 + i, 1 + j, 0 + k), (1 + i, 1 + j, 1 + k), (1 + i, 0 + j, 1 + k)], [(0 + i, 1 + j, 0 + k), (0 + i, 1 + j, 1 + k), (1 + i, 1 + j, 1 + k), (1 + i, 1 + j, 0 + k)], [(0 + i, 1 + j, 1 + k), (0 + i, 1 + j, 0 + k), (0 + i, 0 + j, 0 + k), (0 + i, 0 + j, 1 + k)], [(0 + i, 0 + j, 0 + k), (0 + i, 0 + j, 1 + k), (1 + i, 0 + j, 1 + k), (1 + i, 0 + j, 0 + k)], [(0 + i, 1 + j, 1 + k), (0 + i, 0 + j, 1 + k), (1 + i, 0 + j, 1 + k), (1 + i, 1 + j, 1 + k)]] self.faces = Poly3DCollection(self.edges, color='k', linewidth=0.5, zorder=1) self.faces.set_facecolor((r, b, g, a)) self.axes.add_collection3d(self.faces) k = k + 1 j = j + 1 i = i + 1 print('finish', r, b, g, a) self.canvas.draw() def onecolor(self): r = 0 b = 0 g = 0 a = 0 index = self.comboboxcolor.currentIndex() print(index * index) if index == 0: self.on_draw() else: if index == 1: r = 1 b = 0 g = 0.1 a = 1 elif index == 2: r = 1 b = 0.5 g = 0 a = 1 elif index == 3: r = 1 b = 1 g = 0 a = 1 elif index == 4: r = 0.5 b = 1 g = 0 a = 1 elif index == 5: r = 0 b = 1 g = 1 a = 1 elif index == 6: r = 0 b = 0 g = 1 a = 1 elif index == 7: r = 0.5 b = 0.2 g = 0.9 a = 1 self.coloronly(index - 1, r, b, g, a) def drawsection(self): xsec = self.textboxx.text() ysec = self.textboxy.text() zsec = self.textboxz.text() #self.plot(xsec,ysec,zsec) self.showsection(xsec, ysec, zsec) def plot(self, a, b, c): #self.axes.cla() aa = float(a) bb = float(b) cc = float(c) line1 = self.axes.plot([aa, aa], [45, -1], [63, 63], '-', c='k', linewidth=3, zorder=20) line2 = self.axes.plot([aa, aa], [-1, -1], [63, -1], '-', c='k', linewidth=3, zorder=20) line3 = self.axes.plot([aa, aa], [45, 45], [63, -1], '-', c='k', linewidth=3, zorder=20) line4 = self.axes.plot([aa, aa], [-1, 45], [-1, -1], '-', c='k', linewidth=3, zorder=20) line5 = self.axes.plot([42, -1], [bb, bb], [63, 63], '-', c='k', linewidth=3, zorder=20) line6 = self.axes.plot([-1, -1], [bb, bb], [63, -1], '-', c='k', linewidth=3, zorder=20) line7 = self.axes.plot([42, 42], [bb, bb], [63, -1], '-', c='k', linewidth=3, zorder=20) line8 = self.axes.plot([-1, 42], [bb, bb], [-1, -1], '-', c='k', linewidth=3, zorder=20) line9 = self.axes.plot([42, 42], [42, -1], [cc, cc], '-', c='k', linewidth=3, zorder=20) line10 = self.axes.plot([42, -1], [-1, -1], [cc, cc], '-', c='k', linewidth=3, zorder=20) line11 = self.axes.plot([-1, 42], [42, 42], [cc, cc], '-', c='k', linewidth=3, zorder=20) line12 = self.axes.plot([-1, -1], [-1, 42], [cc, cc], '-', c='k', linewidth=3, zorder=20) self.canvas.draw() @jit def showsection(self, a, b, c): aa = int(a) bb = int(b) cc = int(c) j = 0 k = 0 while j < 41: k = 0 while k < 62: if self.data[aa, j, k] < 3: rectangle = mpatches.Rectangle((0 + j, 0 + k), 1, 1, color=(1, 0, 0.1, 1)) elif self.data[aa, j, k] > 3 and self.data[aa, j, k] < 4: rectangle = mpatches.Rectangle((0 + j, 0 + k), 1, 1, color=(1, 0.5, 0, 1)) elif self.data[aa, j, k] > 4 and self.data[aa, j, k] < 5: rectangle = mpatches.Rectangle((0 + j, 0 + k), 1, 1, color=(1, 1, 0, 1)) elif self.data[aa, j, k] > 5 and self.data[aa, j, k] < 6: rectangle = mpatches.Rectangle((0 + j, 0 + k), 1, 1, color=(0.5, 1, 0, 1)) elif self.data[aa, j, k] > 6 and self.data[aa, j, k] < 7: rectangle = mpatches.Rectangle((0 + j, 0 + k), 1, 1, color=(0, 1, 1, 1)) elif self.data[aa, j, k] > 7 and self.data[aa, j, k] < 8: rectangle = mpatches.Rectangle((0 + j, 0 + k), 1, 1, color=(0, 0, 1, 1)) elif self.data[aa, j, k] > 8: rectangle = mpatches.Rectangle((0 + j, 0 + k), 1, 1, color=(0.5, 0.2, 0.9, 1)) print(self.data[aa, j, k]) self.axx.add_patch(rectangle) k = k + 1 j = j + 1 self.canvas.draw() i = 0 k = 0 while i < 41: k = 0 while k < 62: if self.data[i, bb, k] < 3: rectangle = mpatches.Rectangle((0 + i, 0 + k), 1, 1, color=(1, 0, 0.1, 1)) elif self.data[i, bb, k] > 3 and self.data[i, bb, k] < 4: rectangle = mpatches.Rectangle((0 + i, 0 + k), 1, 1, color=(1, 0.5, 0, 1)) elif self.data[i, bb, k] > 4 and self.data[i, bb, k] < 5: rectangle = mpatches.Rectangle((0 + i, 0 + k), 1, 1, color=(1, 1, 0, 1)) elif self.data[i, bb, k] > 5 and self.data[i, bb, k] < 6: rectangle = mpatches.Rectangle((0 + i, 0 + k), 1, 1, color=(0.5, 1, 0, 1)) elif self.data[i, bb, k] > 6 and self.data[i, bb, k] < 7: rectangle = mpatches.Rectangle((0 + i, 0 + k), 1, 1, color=(0, 1, 1, 1)) elif self.data[i, bb, k] > 7 and self.data[i, bb, k] < 8: rectangle = mpatches.Rectangle((0 + i, 0 + k), 1, 1, color=(0, 0, 1, 1)) elif self.data[i, bb, k] > 8: rectangle = mpatches.Rectangle((0 + i, 0 + k), 1, 1, color=(0.5, 0.2, 0.9, 1)) print(self.data[i, bb, k]) self.axy.add_patch(rectangle) k = k + 1 i = i + 1 self.canvas.draw() i = 0 j = 0 while i < 41: j = 0 while j < 41: if self.data[i, j, cc] < 3: rectangle = mpatches.Rectangle((0 + i, 0 + j), 1, 1, color=(1, 0, 0.1, 1)) elif self.data[i, j, cc] > 3 and self.data[i, j, cc] < 4: rectangle = mpatches.Rectangle((0 + i, 0 + j), 1, 1, color=(1, 0.5, 0, 1)) elif self.data[i, j, cc] > 4 and self.data[i, j, cc] < 5: rectangle = mpatches.Rectangle((0 + i, 0 + j), 1, 1, color=(1, 1, 0, 1)) elif self.data[i, j, cc] > 5 and self.data[i, j, cc] < 6: rectangle = mpatches.Rectangle((0 + i, 0 + j), 1, 1, color=(0.5, 1, 0, 1)) elif self.data[i, j, cc] > 6 and self.data[i, j, cc] < 7: rectangle = mpatches.Rectangle((0 + i, 0 + j), 1, 1, color=(0, 1, 1, 1)) elif self.data[i, j, cc] > 7 and self.data[i, j, cc] < 8: rectangle = mpatches.Rectangle((0 + i, 0 + j), 1, 1, color=(0, 0, 1, 1)) elif self.data[i, j, cc] > 8: rectangle = mpatches.Rectangle( (0 + i, 0 + j), 1, 1, color=(0.5, 0.2, 0.9, 1), ) print(self.data[i, j, cc]) self.axz.add_patch(rectangle) j = j + 1 i = i + 1 self.canvas.draw()
class LPlotWidget(LWidget): def __init__(self, parent=None): super(LPlotWidget, self).__init__(parent) self.setName(WIDGET_NAME) self.buildUi() self.dataContainer = LMyDataContainer(self) self.actions = LMyActions(self.dataContainer,self) self.updateUi() @LInAndOut(DEBUG & WIDGETS) def buildUi(self): self.verticalLayout = QVBoxLayout(self) #width, height = (14, 4) #width, height = figaspect(2.) width = 1 height = 1 dpi = 72 self.figure = Figure(figsize=(width, height), dpi=dpi) # <-- figs created with same geometry! self.figure2 = Figure(figsize=(width, height), dpi=dpi) #self.figure = Figure(dpi=dpi) # <-- figs created with same geometry! #self.figure2 = Figure(dpi=dpi) #self.axe111 = self.figure2.add_axes((0,0,1,1),title="My Axe Title",xlabel='X',ylabel='Y') #self.axesSubplot_111 = self.figure.add_subplot(2,2,1) #print self.axesSubplot_111.get_position() #self.axesSubplot_111 = self.figure.add_subplot(2,2,2) #print self.axesSubplot_111.get_position() #self.axesSubplot_111 = self.figure.add_subplot(2,2,3) #self.axesSubplot_111.set_frame_on(False) #self.bbox = self.axesSubplot_111.get_position() #print self.bbox.__class__.__name__ #print self.axesSubplot_111.get_position() self.axesSubplot_111 = self.figure.add_subplot(2,2,4) self.axesSubplot_111.plot([1,0]) #print self.axesSubplot_111.get_position() #self.axesSubplot_111.set_position(self.bbox) #self.axesSubplot_111.set_position([0.54772727, 0.53636364, 0.9, 0.9 ]) self.axesSubplot_111 = self.figure2.add_subplot(2,2,2) # <-- creation in fig2 self.axesSubplot_111 = self.figure2.add_subplot(1,1,1) # <-- position in fig2 doesn't impact position in fig1 print self.axesSubplot_111.__class__.__name__ print self.axesSubplot_111.get_position() print self.axesSubplot_111.get_axes_locator() #self.bbox = self.axesSubplot_111.get_position() self.axesSubplot_111.grid(color='g', linestyle='-.', linewidth=1) self.axesSubplot_111.plot([0,1]) #Change to the figure #self.axesSubplot_111.set_figure(self.figure) #self.figure.add_axes(self.axesSubplot_111) x0 = 1.0 y0 = 1.0 xspan = 8.0 yspan = 8.0 pos = [x0,y0,xspan,yspan] self.addAxesSubplot(self.axesSubplot_111, position=pos) #self.axesSubplot_111.reset_position() #self.axesSubplot_111.set_position(pos=pos,which='both') #self.axesSubplot_111.set_position(self.bbox,which='both') # <-- as if the bbox where scalled differently self.figureCanvas = FigureCanvas(self.figure) # <-- figure required self.verticalLayout.addWidget(self.figureCanvas) #FigureCanvas.setSizePolicy(self.figureCanvas, QSizePolicy.Expanding, QSizePolicy.Expanding) #FigureCanvas.updateGeometry(self.figureCanvas) @LInAndOut(DEBUG & WIDGETS) def updateUi(self): self.figure.suptitle(self.dataContainer.figureTitle) #---------------------------------------------------------------------- # Interface (set) @LInAndOut(DEBUG & WIDGETS) def setOptions(self, options): super(LPlotWidget, self).setOptions(options) if options.verboseLevel is not None: self.setVerboseLevel(options.verboseLevel) if options.figureTitle is not None: self.setFigureTitle(options.figureTitle) self.updateUi() @LInAndOut(DEBUG & WIDGETS) def setVerboseLevel(self, level): self.dataContainer.verboseLevel = level #---------------------------------------------------------------------- # Interface (get) #---------------------------------------------------------------------- # QT SLOTS @LInAndOut(DEBUG & WIDGETS) def setFigureTitle(self, title): self.dataContainer.figureTitle = title @pyqtSlot() def clear(self): for a in self.figure.get_axes(): self.figure.delaxes(a) #self.axe111.clear() #self.figure.draw() self.figureCanvas.draw() @pyqtSlot() def snapshot(self, fileName = None): if fileName is None: caption = "%s - Save File" % self.name filter = "PNG Image (*.png);;All files (*.*)" fileName = QFileDialog.getSaveFileName(self.parent(), caption=caption,filter=filter ) fileName = "%s" % fileName if len(fileName) > 0: self.figure.savefig(fileName, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format=None, transparent=False, bbox_inches=None, pad_inches=0.1) @pyqtSlot() def addAxesSubplot(self, axesSubplot, position=None, bbox=None): axesSubplot.set_figure(self.figure) self.figure.add_axes(axesSubplot) if position is not None: axesSubplot.set_position(position) if bbox is not None: axesSubplot.set_position(bbox) @pyqtSlot() def addAxesSubplots(self, axesSubplots): for axesSubplot in axesSubplots: self.addSubplot(axesSubplot)
class App: def __init__(self,master): # create toplevel window frame = Frame(master) frame.grid(ipadx=10,ipady=10) try: sys.argv[1] except: self.datatype = None else: self.datatype = sys.argv[1].split('--')[1] self.wdir = os.getcwd() + '/' self.I = pp.Image() self.Tool = pp.Tools() self.lb1=Label(frame, text="Nstep").grid(row=0,column=0) self.enstep = Entry(frame,width=8) self.enstep.grid(row=0,column=1) self.enstep.insert(0, "0") self.LoadedNstep = StringVar() self.PresentTime = StringVar() self.myData = self.loaddata() self.varkeys = self.myData.get_varinfo(self.datatype)['allvars'] self.grid_dict= self.myData.grid() if self.grid_dict["n3"] != 1: self.Geom = '3D' elif self.grid_dict["n3"] == 1 and self.grid_dict["n2"] != 1: self.Geom = '2D' else: self.Geom = '1D' self.ldatabutton=Button(frame,text="Load data",command=self.loaddata) self.ldatabutton.grid(row=0,column=2) ############### MARK THE CUTS ################################# self.ex1 = Entry(frame,width=5) self.ex1.grid(row=2,column=0) self.ex1.insert(0, "x1") self.ex2 = Entry(frame,width=5) self.ex2.grid(row=2,column=1) self.ex2.insert(0, "x2") self.ex3 = Entry(frame,width=5) self.ex3.grid(row=2,column=2) self.ex3.insert(0, "x3") if self.Geom == '2D': self.ex3.config(state='disabled') if self.Geom == '1D': self.ex3.config(state='disabled') self.ex2.config(state='disabled') self.ex1.config(state='disabled') # place a graph somewhere here self.f = Figure(figsize=(7,7), dpi=100) self.a = self.f.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.f, master=root) self.canvas.show() self.canvas.get_tk_widget().grid(row=0,column=3,columnspan=10,rowspan=10,sticky=E) #self.toolbar = NavigationToolbar2TkAgg(self.canvas,tl) #self.toolbar.update() #self.canvas._tkcanvas.grid(row=60,column=15,sticky=E) self.v = StringVar() self.v.set("None") ################ VARIABLES TO PLOT ################################# for j in range(len(self.varkeys)): self.ldata = Radiobutton(frame,text=self.varkeys[j],variable=self.v,value=self.varkeys[j],command=self.getmyvar) self.ldata.grid(row=3+j,column=0,sticky=W) ################ SLICES CHOICE ################################# self.slvar = StringVar() self.slvar.set("Choose Slice") if self.Geom == '3D' : SliceList = ("Along x1","Along x2","Along x3","Along x1-x2","Along x2-x3","Along x3-x1") elif self.Geom == '2D' : SliceList = ("Along x1", "Along x2", "Along x1-x2") else: SliceList = () for j in range(len(SliceList)): self.sldata = Radiobutton(frame,text=SliceList[j],variable=self.slvar,value=SliceList[j],command=self.setslice) self.sldata.grid(row=3+j,column=1,sticky=W) ############### PLOT PROPERTIES ################################# self.logvar = IntVar() self.chkb = Checkbutton(frame,text="Log ",variable=self.logvar,onvalue=1,offvalue=0,command=self.logchkcall) self.chkb.grid(row=3,column=2,sticky=W)#(row=15,column=0,sticky=W) self.polarvar = IntVar() self.polchkb = Checkbutton(frame,text="Polar",variable=self.polarvar,onvalue=1,offvalue=0,command=self.polchkcall) self.polchkb.grid(row=4,column=2,sticky=W)#(row=15,column=1) if self.Geom == '1D': self.polchkb.config(state='disabled') self.polarvar.set(0) self.preaspect = IntVar() self.aspectb = Checkbutton(frame,text="Aspect",variable=self.preaspect,onvalue=1,offvalue=0,command=self.aspchkcall) self.aspectb.grid(row=5,column=2,sticky=W)#(row=15,column=2) if self.Geom == '1D': self.aspectb.config(state='disabled') ################ X and Y LABELS ################################# self.lb2=Label(frame,text="Labels").grid(row=22,column=0) self.xlb = Entry(frame,width=15) self.xlb.grid(row=22,column=1) self.xlb.insert(0, "xlabel") self.ylb = Entry(frame,width=15) self.ylb.grid(row=22,column=2) self.ylb.insert(0, "ylabel") ############### X and Y RANGE####################### self.lb2a=Label(frame,text="XRange").grid(row=24,column=0) self.lb2b=Label(frame,text="YRange").grid(row=26,column=0) self.lb2c=Label(frame,text="VarRange").grid(row=28,column=0) self.xrmin = Entry(frame,width=15) self.xrmin.grid(row=24,column=1) self.xrmin.insert(0,'') self.xrmax = Entry(frame,width=15) self.xrmax.grid(row=24,column=2) self.xrmax.insert(0,'') self.yrmin = Entry(frame,width=15) self.yrmin.grid(row=26,column=1) self.yrmin.insert(0,'') self.yrmax = Entry(frame,width=15) self.yrmax.grid(row=26,column=2) self.yrmax.insert(0,'') self.varmin = Entry(frame,width=15) self.varmin.grid(row=28,column=1) self.varmin.insert(0,'') self.varmax = Entry(frame,width=15) self.varmax.grid(row=28,column=2) self.varmax.insert(0,'') if self.Geom == '1D': self.yrmin.config(state='disabled') self.yrmax.config(state='disabled') ################ CONTOURS ################################# self.lb3=Label(frame,text="Contours").grid(row=16,column=0) self.contvar = IntVar() self.chkb = Checkbutton(frame,text="Contour",variable=self.contvar,onvalue=1,offvalue=0,command=self.contchkcall) self.chkb.grid(row=6,column=2,sticky=W)#(row=16,column=0,sticky=W) self.plcont = StringVar() self.contkeys = ["None"] if "bx1" in self.varkeys: for item in self.varkeys: self.contkeys.append(item) self.contkeys.append("x1*bx3") if "Ax3" in self.varkeys: self.contkeys.append("x1*Ax3") else: for item in self.varkeys: self.contkeys.append(item) self.plcont.set("None") self.contmenu = OptionMenu(frame, self.plcont,*self.contkeys) self.contmenu.grid(row=16,column=1) self.xlevb = Entry(frame,width=15) self.xlevb.grid(row=16,column=2,sticky=W) self.xlevb.insert(0, "Levels") self.xlevb.config(state='disabled') self.contmenu.config(state='disabled') if self.Geom == '1D': self.chkb.config(state = 'disabled') ################ ARROWS ################################# self.lb4=Label(frame,text="Arrows").grid(row=19,column=0) self.arrowvar = IntVar() self.arrowchkb = Checkbutton(frame,text="Arrows",variable=self.arrowvar,onvalue=1,offvalue=0,command=self.arrchkcall) self.arrowchkb.grid(row=7,column=2,sticky=W)#(row=16,column=0,sticky=W) self.arrspb = Entry(frame,width=15) self.arrspb.grid(row=19,column=2,sticky=W) self.arrspb.insert(0, "20") self.plarr = StringVar() self.arrkeys = ["None"] self.arrkeys.append("Vp") self.arrkeys.append("Vp_norm") if "bx1" in self.varkeys: self.arrkeys.append("Bp") self.arrkeys.append("Bp_norm") self.plarr.set("None") self.arrmenu = OptionMenu(frame,self.plarr,*self.arrkeys) self.arrmenu.grid(row=19,column=1) self.arrmenu.config(state='disabled') self.arrspb.config(state='disabled') if self.Geom == '1D': self.arrowchkb.config(state = 'disabled') ################ VARIOUS PLOTTING BUTTONS ################################# self.pltbutton=Button(frame,text="Plot",command=self.plotfinal) self.pltbutton.grid(row=36,column=0) if self.Geom == '1D': self.pltbutton.config(state='active') else: self.pltbutton.config(state='disabled') self.surfbutton=Button(frame,text="Surface",command=self.plotsurface) self.surfbutton.grid(row=36,column=1) self.surfbutton.config(state='disabled') #if self.Geom == '1D': # self.surfbutton.config(state='disabled') self.clrbutton=Button(frame,text="Clear",command=self.plotclear) self.clrbutton.grid(row=36,column=2) ################ INFORMATION ################################# self.lbinf0 = Label(frame,text="Information",font=("Times",12,"bold")) self.lbinf0.grid(row=47,column=0,sticky=W,columnspan=3) self.lbinf1a = Label(frame,text="Dir :",font=("Times",10,"bold")).grid(row=49,column=0,sticky=W,columnspan=3) self.lbinf1 = Label(frame,text=self.wdir).grid(row=50,column=0,sticky=W,columnspan=3) self.lbinf2a = Label(frame,text="Domain :",font=("Times",10,"bold")).grid(row=51,column=0,sticky=W,columnspan=3) self.lbinf2 = Label(frame,text="n1 x n2 x n3 = %d x %d x %d " % (self.grid_dict.get('n1'),self.grid_dict.get('n2'),self.grid_dict.get('n3'))).grid(row=52,column=0,sticky=W,columnspan=3) self.lbinf3a = Label(frame,text="Time Status",font=("Times",10,"bold")).grid(row=53,column=0,sticky=W,columnspan=3) self.lbinf4 = Label(frame,text="Nlast = %d"% (pp.nlast_info(datatype=self.datatype).get('nlast'))).grid(row=54,column=0,sticky=W,columnspan=3) self.lbinf5 = Label(frame,textvariable = self.LoadedNstep).grid(row=55,column=0,sticky=W,columnspan=3) self.lbinf6 = Label(frame,textvariable = self.PresentTime).grid(row=56,column=0,sticky=W,columnspan=3) ################ VARIOUS FUNCTIONS ################################# def loaddata(self): try: int(self.enstep.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the proper value of Nstep" else: mynstep=int(self.enstep.get()) self.D = pp.pload(mynstep,w_dir=self.wdir,datatype=self.datatype) self.LoadedNstep.set("Loaded Nstep = "+self.enstep.get()) self.PresentTime.set("Present Time = "+str(self.D.time_info(self.datatype)['time'])+" [cu]") return self.D def getmyvar(self): try: self.v.get() != "None" except KeyError: print "Specify the variable to plot" else: self.myvar=self.v.get() def logchkcall(self): self.logchk = self.logvar.get() def contchkcall(self): self.contchk = self.contvar.get() if self.contchk == 1: self.contmenu.config(state='normal') self.xlevb.config(state='normal') else: self.contmenu.config(state='disabled') self.xlevb.config(state='disabled') def arrchkcall(self): self.arrchk = self.arrowvar.get() if self.arrchk == 1: self.arrmenu.config(state='normal') self.arrspb.config(state='normal') else: self.arrmenu.config(state='disabled') self.arrspb.config(state='disabled') def aspchkcall(self): self.aspchk=self.preaspect.get() def polchkcall(self): self.polchk = self.polarvar.get() def setslice(self): self.slicename=self.slvar.get() if self.slicename == "Along x1" or self.slicename == "Along x2" or self.slicename == "Along x3": self.surfbutton.config(state='disabled') self.arrowchkb.config(state = 'disabled') self.arrowvar.set(0) self.chkb.config(state = 'disabled') self.contvar.set(0) self.pltbutton.config(state='active') self.polchkb.config(state='disabled') self.polarvar.set(0) else: self.pltbutton.config(state='disabled') self.arrowchkb.config(state = 'normal') self.chkb.config(state = 'normal') self.surfbutton.config(state='active') self.polchkb.config(state='normal') if self.slicename == "Along x2-x3": self.polchkb.config(state='disabled') self.polarvar.set(0) def plotclear(self): self.a.clear() if len(self.f.axes)>1: self.f.delaxes(self.f.axes[1]) self.f.subplots_adjust(right=0.90) self.canvas.show() def plotfinal(self): if self.getplotvar() == True: self.a.axis([self.getxaxisrange()[0],self.getxaxisrange()[1],self.getvarrange()[0],self.getvarrange()[1]]) self.a.plot(self.x,self.var) self.a.set_aspect('auto') self.a.set_xlabel(self.xlb.get()) self.a.set_ylabel(self.ylb.get()) self.canvas.show() def plotsurface(self): tdum = time.time() self.plotclear() if self.preaspect.get() == 1: self.a.set_aspect('equal') else: self.a.set_aspect('auto') if self.polarvar.get() == 1: if self.drawpolar() == True: self.a.axis([self.getxaxisrange()[0],self.getxaxisrange()[1],self.getyaxisrange()[0],self.getyaxisrange()[1]]) self.image = self.a.imshow(self.SphData[self.myvar], origin='lower',extent=self.extent, interpolation='nearest',cmap="jet", vmin=self.getvarrange()[0],vmax=self.getvarrange()[1]) self.f.colorbar(self.image) else: if self.getsurfvar() == True: self.a.axis([self.getxaxisrange()[0],self.getxaxisrange()[1],self.getyaxisrange()[0],self.getyaxisrange()[1]]) self.image=self.a.pcolormesh(self.x,self.y,self.var,cmap='jet',vmin=self.getvarrange()[0],vmax=self.getvarrange()[1]) self.f.colorbar(self.image) if self.contvar.get() == 1: try: self.plcont.get() != "None" except KeyError: print "Specify the variable for Contour" else: self.drawcontour() self.contlevlist=[] self.contlevstr = string.split(self.xlevb.get(),',') try: if self.contlevstr[0] == 'log': self.flevel = self.contlevstr[1] self.varcont = log10(self.varcont) else: self.flevel = self.contlevstr[0] float(self.flevel) self.contlevlist = [float(self.flevel)] except: self.contlevlist = 5 else: for j in range(1,len(self.contlevstr)): self.contlevlist.append(float(self.contlevstr[j])) self.cs1 = self.a.contour(self.xcont,self.ycont,self.varcont,self.contlevlist,colors="w") self.a.clabel(self.cs1,inline=True) if self.arrowvar.get() == 1: try: self.plarr.get() != "None" except KeyError: print "Specify the variable for plotting the arrow" else: self.drawarrow() self.a.quiver(self.xcong, self.ycong, self.xveccong, self.yveccong,color='w') self.a.set_xlabel(self.xlb.get()) self.a.set_ylabel(self.ylb.get()) self.canvas.show() def getvarrange(self): try: float(self.varmin.get()) except: if self.polarvar.get() != 1: self.varminval = min(self.var) else: self.varminval = min(self.SphData[self.myvar][self.isnotnan].flat)#self.minPl else: self.varminval = float(self.varmin.get()) try: float(self.varmax.get()) except: if self.polarvar.get() != 1: self.varmaxval = max(self.var) else: self.varmaxval = max(self.SphData[self.myvar][self.isnotnan].flat)#self.maxPl else: self.varmaxval = float(self.varmax.get()) return [self.varminval,self.varmaxval] def getxaxisrange(self): try: float(self.xrmin.get()) except: if self.polarvar.get() != 1: self.xminval = min(self.x) else: self.xminval = min(self.R.flat) else: self.xminval = float(self.xrmin.get()) try: float(self.xrmax.get()) except: if self.polarvar.get() != 1: self.xmaxval = max(self.x) else: self.xmaxval = max(self.R.flat) else: self.xmaxval = float(self.xrmax.get()) return [self.xminval,self.xmaxval] def getyaxisrange(self): try: float(self.yrmin.get()) except: if self.polarvar.get() != 1: self.yminval = min(self.y) else: self.yminval = min(self.Z.flat) else: self.yminval = float(self.yrmin.get()) try: float(self.yrmax.get()) except: if self.polarvar.get() != 1: self.ymaxval = max(self.y) else: self.ymaxval = max(self.Z.flat) else: self.ymaxval = float(self.yrmax.get()) return [self.yminval,self.ymaxval] def getplotvar(self): self.sucess = False if self.logvar.get() == 1: self.var = log10(self.D.__getattribute__(self.myvar)) else: self.var = self.D.__getattribute__(self.myvar) if self.Geom == '1D': self.x = self.D.x1 self.sucess = True else: if self.slicename == "Along x1": self.x = self.D.x1 if self.grid_dict["n3"] == 1: try: int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 cut" else: self.var = self.var[:,int(self.ex2.get())] self.sucess = True else: try: int(self.ex2.get().strip().split()[0]) int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 or x3 cut" else: self.var = self.var[:,int(self.ex2.get()),int(self.ex3.get())] self.sucess = True elif self.slicename == "Along x2": self.x = self.D.x2 if self.grid_dict["n3"] == 1: try: int(self.ex1.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 cut" else: self.var = self.var[int(self.ex1.get()),:] self.sucess = True else: try: int(self.ex1.get().strip().split()[0]) int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 or x3 cut" else: self.var = self.var[int(self.ex1.get()),:,int(self.ex3.get())] self.sucess = True else: self.x = self.D.x3 try: int(self.ex1.get().strip().split()[0]) int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 or x2 cut" else: self.var = self.var[int(self.ex1.get()),int(self.ex2.get()),:] self.sucess = True return self.sucess def getsurfvar(self): self.sucess = False if self.logvar.get() == 1: self.var = log10(self.D.__getattribute__(self.myvar)) else: self.var = self.D.__getattribute__(self.myvar) if self.slicename == "Along x1-x2": self.x = self.D.x1 self.y = self.D.x2 xmineed = (abs(self.x-self.getxaxisrange()[0])).argmin() xmaneed = (abs(self.x-self.getxaxisrange()[1])).argmin() ymineed = (abs(self.y-self.getyaxisrange()[0])).argmin() ymaneed = (abs(self.y-self.getyaxisrange()[1])).argmin() self.x = self.x[xmineed:xmaneed] self.y = self.y[ymineed:ymaneed] if self.grid_dict["n3"] == 1: self.var = self.var[xmineed:xmaneed,ymineed:ymaneed].T self.sucess = True else: try: int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x3 cut" else: self.var = self.var[xmineed:xmaneed,ymineed:ymaneed,int(self.ex3.get())].T self.sucess = True elif self.slicename == "Along x2-x3": self.x = self.D.x2 self.y = self.D.x3 xmineed = (abs(self.x-self.getxaxisrange()[0])).argmin() xmaneed = (abs(self.x-self.getxaxisrange()[1])).argmin() ymineed = (abs(self.y-self.getyaxisrange()[0])).argmin() ymaneed = (abs(self.y-self.getyaxisrange()[1])).argmin() self.x = self.x[xmineed:xmaneed] self.y = self.y[ymineed:ymaneed] try: int(self.ex1.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 cut" else: self.var = self.var[int(self.ex1.get()),xmineed:xmaneed,ymineed:ymaneed].T self.sucess = True else: self.x = self.D.x1 self.y = self.D.x3 xmineed = (abs(self.x-self.getxaxisrange()[0])).argmin() xmaneed = (abs(self.x-self.getxaxisrange()[1])).argmin() ymineed = (abs(self.y-self.getyaxisrange()[0])).argmin() ymaneed = (abs(self.y-self.getyaxisrange()[1])).argmin() self.x = self.x[xmineed:xmaneed] self.y = self.y[ymineed:ymaneed] try: int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 cut" else: self.var = self.var[xmineed:xmaneed,int(self.ex2.get()),ymineed:ymaneed].T self.sucess = True return self.sucess def drawpolar(self): self.sucess = False if self.slicename == "Along x1-x2": if self.grid_dict["n3"] == 1: self.R,self.Z,self.SphData = self.I.getSphData(self.D,w_dir=self.wdir,datatype=self.datatype, rphi=False) self.sucess = True else: try: int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x3 cut" else: self.R,self.Z,self.SphData = self.I.getSphData(self.D,w_dir=self.wdir,datatype=self.datatype, rphi=False,x3cut=int(self.ex3.get())) self.sucess = True if self.slicename == "Along x3-x1": try: int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 cut" else: self.R,self.Z,self.SphData = self.I.getSphData(self.D,w_dir=self.wdir,datatype=self.datatype, rphi=True, x2cut=int(self.ex2.get())) self.sucess = True if self.sucess == True: self.extent=(min(self.R.flat),max(self.R.flat),min(self.Z.flat),max(self.Z.flat)) self.dRR=max(self.R.flat)-min(self.R.flat) self.dZZ=max(self.Z.flat)-min(self.Z.flat) self.isnotnan=-isnan(self.SphData[self.myvar]) self.maxPl=max(self.SphData[self.myvar][self.isnotnan].flat) self.minPl=min(self.SphData[self.myvar][self.isnotnan].flat) self.normrange=False if self.minPl<0: self.normrange=True if self.maxPl>-self.minPl: self.minPl=-self.maxPl else: self.maxPl=-self.minPl if (self.normrange and self.myvar !='rho' and self.myvar !='prs'): self.SphData[self.myvar][-1][-1]=self.maxPl self.SphData[self.myvar][-1][-2]=self.minPl if self.logvar.get() == 1: self.SphData[self.myvar] = log10(self.SphData[self.myvar]) return self.sucess def drawcontour(self): if self.polarvar.get() != 1: if self.slicename == "Along x1-x2": self.xcont = self.D.x1 self.ycont = self.D.x2 self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T,self.D.x2.T) if self.grid_dict["n3"] == 1: if self.plcont.get() == 'x1*Ax3': self.varcont = self.Xmesh*(self.D.Ax3.T) elif self.plcont.get() == 'x1*bx3': self.varcont = self.Xmesh*(self.D.bx3.T) else: self.varcont = self.D.__getattribute__(self.plcont.get())[:,:].T else: if self.plcont.get() == 'x1*Ax3': self.varcont = self.Xmesh*(self.D.Ax3[:,:,int(self.ex3.get())].T) elif self.plcont.get() == 'x1*bx3': self.varcont = self.Xmesh*(self.D.bx3[:,:,int(self.ex3.get())].T) else: self.varcont = self.D.__getattribute__(self.plcont.get())[:,:,int(self.ex3.get())].T elif self.slicename == "Along x2-x3": self.xcont = self.D.x2 self.ycont = self.D.x3 self.varcont = self.D.__getattribute__(self.plcont.get())[int(self.ex1.get()),:,:].T else: self.xcont = self.D.x1 self.ycont = self.D.x3 self.varcont = self.D.__getattribute__(self.plcont.get())[:,int(self.ex2.get()),:].T else: self.xcont = self.R self.ycont = self.Z if self.plcont.get() == 'x1*Ax3': self.varcont = self.R*(self.SphData['Ax3']) elif self.plcont.get() == 'x1*bx3': self.varcont = self.R*(self.SphData['bx3']) else: if self.logvar.get() == 1 and self.plcont.get() == self.myvar: self.varcont = 10**(self.SphData[self.plcont.get()]) else: self.varcont = self.SphData[self.plcont.get()] def drawarrow(self): if self.polarvar.get() != 1: if self.slicename == "Along x1-x2": self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T,self.D.x2.T) self.xcong = self.Tool.congrid(self.Xmesh,2*(int(self.arrspb.get()),),method='linear') self.ycong = self.Tool.congrid(self.Ymesh,2*(int(self.arrspb.get()),),method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm': if self.grid_dict["n3"] == 1: self.vel1 = self.D.vx1[:,:].T self.vel2 = self.D.vx2[:,:].T else: self.vel1 = self.D.vx1[:,:,int(self.ex3.get())].T self.vel2 = self.D.vx2[:,:,int(self.ex3.get())].T self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm': if self.grid_dict["n3"] == 1: self.mag1 = self.D.bx1[:,:].T self.mag2 = self.D.bx2[:,:].T else: self.mag1 = self.D.bx1[:,:,int(self.ex3.get())].T self.mag2 = self.D.bx2[:,:,int(self.ex3.get())].T self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp elif self.slicename == "Along x2-x3": self.Xmesh, self.Ymesh = meshgrid(self.D.x2.T,self.D.x3.T) self.xcong = self.Tool.congrid(self.Xmesh,2*(int(self.arrspb.get()),),method='linear') self.ycong = self.Tool.congrid(self.Ymesh,2*(int(self.arrspb.get()),),method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm': self.vel1 = self.D.vx2[int(self.ex1.get()),:,:].T self.vel2 = self.D.vx3[int(self.ex1.get()),:,:].T self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm': self.mag1 = self.D.bx2[int(self.ex1.get()),:,:].T self.mag2 = self.D.bx3[int(self.ex1.get()),:,:].T self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp else: self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T,self.D.x3.T) self.xcong = self.Tool.congrid(self.Xmesh,2*(int(self.arrspb.get()),),method='linear') self.ycong = self.Tool.congrid(self.Ymesh,2*(int(self.arrspb.get()),),method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm': self.vel1 = self.D.vx1[:,int(self.ex2.get()),:].T self.vel2 = self.D.vx3[:,int(self.ex2.get()),:].T self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm': self.mag1 = self.D.bx1[:,int(self.ex2.get()),:].T self.mag2 = self.D.bx3[:,int(self.ex2.get()),:].T self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp else: self.xcong = self.Tool.congrid(self.R,2*(int(self.arrspb.get()),),method='linear') self.ycong = self.Tool.congrid(self.Z,2*(int(self.arrspb.get()),),method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm': if self.slicename == "Along x1-x2": self.vel1 = self.SphData['v1c'] self.vel2 = self.SphData['v2c'] else: self.vel1 = self.SphData['v1c'] self.vel2 = self.SphData['v3c'] self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm': if self.slicename == "Along x1-x2": self.mag1 = self.SphData['b1c'] self.mag2 = self.SphData['b2c'] else: self.mag1 = self.SphData['b1c'] self.mag2 = self.SphData['b3c'] self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear') self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong/self.normVp self.yveccong = self.yveccong/self.normVp def epssave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.eps') def pngsave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.png') def pdfsave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.pdf') def jpgsave(self): self.f.savefig(self.myvar+'_'+self.enstep.get()+'.jpg')
class MplGraphQt5Widget(QWidget): def __init__(self, parent=None): super(MplGraphQt5Widget, self).__init__(parent) self.width = 3 self.height = 3 self.dpi = 100 self._dataY = np.array([]) self._dataX = np.array([]) self._spCols = 1 self._spRows = 1 self.all_sp_axes = [] self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi) self.all_sp_axes.append(self.fig.add_subplot(self._spCols, self._spRows, 1)) self.fig.set_frameon(False) self.fig.set_tight_layout(True) self.canvas = Canvas(self.fig) self._navBarOn = False self.mpl_toolbar = NavigationToolbar(self.canvas, parent) self.mpl_toolbar.dynamic_update() self.canvas.mpl_connect('key_press_event', self.on_key_press) self.canvas.mpl_connect('button_press_event', self.on_button_press) self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move) self.canvas.setFocusPolicy(Qt.ClickFocus) self.canvas.setFocus() self.canvas.setParent(parent) self.canvas.clearMask() self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.canvas.updateGeometry() vbox = QVBoxLayout() vbox.addWidget(self.canvas) vbox.addWidget(self.mpl_toolbar) if not self._navBarOn: self.mpl_toolbar.hide() self.setLayout(vbox) def get_icon(name): """Return Matplotlib icon *name*""" return QIcon(osp.join(rcParams['datapath'], 'images', name)) key_pressed = pyqtSignal(object, name='keyPressed') def on_key_press(self, event): self.key_pressed.emit(event) key_press_handler(event, self.canvas, self.mpl_toolbar) button_pressed = pyqtSignal(object, name='buttonPressed') def on_button_press(self, event): self.button_pressed.emit(event) key_press_handler(event, self.canvas, self.mpl_toolbar) mouse_move = pyqtSignal(object, name='mouseMoved') def on_mouse_move(self, event): self.mouse_move.emit(event) key_press_handler(event, self.canvas, self.mpl_toolbar) def generateNewAxes(self): for ax in self.all_sp_axes: self.fig.delaxes(ax) self.all_sp_axes = [] numOfAxes = (self._spRows*self._spCols)+1 for i in np.arange(1,numOfAxes): self.all_sp_axes.append(self.fig.add_subplot(self._spRows, self._spCols, i)) self.canvas.setGeometry(100, 100, 300, 300) #Used to update the new number of axes self.canvas.updateGeometry() #This will bring the size of the canvas back to the original (defined by the vbox) spRowsChanged = pyqtSignal(int) def getspRows(self): return self._spRows @pyqtSlot(int) def setspRows(self, spRows): self._spRows = spRows self.generateNewAxes() self.spRowsChanged.emit(spRows) def resetspRows(self): self.setspRows(1) spRows = pyqtProperty(int, getspRows, setspRows, resetspRows) spColsChanged = pyqtSignal(int) def getspCols(self): return self._spCols @pyqtSlot(int) def setspCols(self, spCols): self._spCols = spCols self.generateNewAxes() self.spRowsChanged.emit(spCols) def resetspCols(self): self.setspCols(1) spCols = pyqtProperty(int, getspCols, setspCols, resetspCols) dataChanged = pyqtSignal(bool) def get_Y_data(self): return self._dataY @pyqtSlot(int) def set_Y_data(self, y_data): self._dataY = y_data self.dataChanged.emit(True) def plot(self, on_axes=0): if np.size(self._dataX) == 0: self.all_sp_axes[on_axes].plot(self._dataY) else: self.all_sp_axes[on_axes].plot(self._dataX, self._dataY) def getNavBarOn(self): return self._navBarOn def setNavBarOn(self, navBarOn): self._navBarOn = navBarOn if not navBarOn: self.mpl_toolbar.hide() else: self.mpl_toolbar.show() def resetNavBarOn(self): self._navBarOn = True navBarOn = pyqtProperty(bool, getNavBarOn, setNavBarOn, resetNavBarOn) @pyqtSlot(bool) def set_autoscale(self, autoscale): for axis in self.all_sp_axes: axis.set_autoscale(autoscale)
class Qt4MplCanvas(FigureCanvas): """ A customized Qt widget for matplotlib figure. It can be used to replace GraphicsView of QtGui """ def __init__(self, parent): """ Initialization """ # from mpl_toolkits.axes_grid1 import host_subplot # import mpl_toolkits.axisartist as AA # import matplotlib.pyplot as plt # Instantiating matplotlib Figure self.fig = Figure() self.fig.patch.set_facecolor('white') if True: self.axes = self.fig.add_subplot(111) # return: matplotlib.axes.AxesSubplot self.axes2 = None else: self.axes = self.fig.add_host_subplot(111) # Initialize parent class and set parent FigureCanvas.__init__(self, self.fig) self.setParent(parent) # Set size policy to be able to expanding and resizable with frame FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) # Variables to manage all lines/subplot self._lineDict = {} self._lineIndex = 0 # legend and color bar self._colorBar = None return def add_plot_1d(self, vec_x, vec_y, y_err=None, color=None, label="", x_label=None, y_label=None, marker=None, line_style=None, line_width=1): """ :param vec_x: numpy array X :param vec_y: numpy array Y :param y_err: :param color: :param label: :param x_label: :param y_label: :param marker: :param line_style: :param line_width: :return: new key """ # Check input if isinstance(vec_x, np.ndarray) is False or isinstance(vec_y, np.ndarray) is False: raise NotImplementedError('Input vec_x or vec_y for addPlot() must be numpy.array.') plot_error = y_err is not None if plot_error is True: if isinstance(y_err, np.ndarray) is False: raise NotImplementedError('Input y_err must be either None or numpy.array.') if len(vec_x) != len(vec_y): raise NotImplementedError('Input vec_x and vec_y must have same size.') if plot_error is True and len(y_err) != len(vec_x): raise NotImplementedError('Input vec_x, vec_y and y_error must have same size.') # Hold previous data self.axes.hold(True) # process inputs and defaults if color is None: color = (0,1,0,1) if marker is None: marker = 'o' if line_style is None: line_style = '-' # color must be RGBA (4-tuple) if plot_error is False: print "[DB] line_style = ", line_style, "line_width = ", line_width, "marker = ", marker, "color = ", color r = self.axes.plot(vec_x, vec_y, color=color, marker=marker, linestyle=line_style, label=label, linewidth=line_width) # return: list of matplotlib.lines.Line2D object else: r = self.axes.errorbar(vec_x, vec_y, yerr=y_err, color=color, marker=marker, linestyle=line_style, label=label, linewidth=line_width) self.axes.set_aspect('auto') # set x-axis and y-axis label if x_label is not None: self.axes.set_xlabel(x_label, fontsize=20) if y_label is not None: self.axes.set_ylabel(y_label, fontsize=20) # set/update legend self._setupLegend() # Register line_key = self._lineIndex if len(r) == 1: self._lineDict[line_key] = r[0] self._lineIndex += 1 else: print "Impoooooooooooooooosible! Return from plot is a %d-tuple. " % (len(r)) # Flush/commit self.draw() return line_key def add_1d_plot_right(self, x, y, color=None, label="", x_label=None, ylabel=None, marker=None, linestyle=None, linewidth=1): """ Add a line (1-d plot) at right axis """ if self.axes2 is None: self.axes2 = self.axes.twinx() # print self.par1, type(self.par1) # Hold previous data self.axes2.hold(True) # Default if color is None: color = (0, 1, 0, 1) if marker is None: marker = 'o' if linestyle is None: linestyle = '-' # Special default if len(label) == 0: label = 'right' color = 'red' # color must be RGBA (4-tuple) r = self.axes2.plot(x, y, color=color, marker=marker, linestyle=linestyle, label=label, linewidth=linewidth) # return: list of matplotlib.lines.Line2D object self.axes2.set_aspect('auto') # set x-axis and y-axis label if x_label is not None: self.axes2.set_xlabel(x_label, fontsize=20) if ylabel is not None: self.axes2.set_ylabel(ylabel, fontsize=20) # set/update legend self._setupLegend() # Register line_key = -1 if len(r) == 1: line_key = self._lineIndex self._lineDict[line_key] = r[0] self._lineIndex += 1 else: print "Impoooooooooooooooosible!" # Flush/commit self.draw() return line_key def addPlot2D(self, array2d, xmin, xmax, ymin, ymax, holdprev, yticklabels=None): """ Add a 2D plot Arguments: - yticklabels :: list of string for y ticks """ # Release the current image self.axes.hold(holdprev) # Do plot # y ticks will be shown on line 1, 4, 23, 24 and 30 # yticks = [1, 4, 23, 24, 30] # self.axes.set_yticks(yticks) # show image imgplot = self.axes.imshow(array2d, extent=[xmin,xmax,ymin,ymax], interpolation='none') # set y ticks as an option: if yticklabels is not None: # it will always label the first N ticks even image is zoomed in print "--------> [FixMe]: Set up the Y-axis ticks is erroreous" #self.axes.set_yticklabels(yticklabels) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) # Flush... self._flush() return def addImage(self, imagefilename): """ Add an image by file """ #import matplotlib.image as mpimg # set aspect to auto mode self.axes.set_aspect('auto') img = matplotlib.image.imread(str(imagefilename)) # lum_img = img[:,:,0] # FUTURE : refactor for image size, interpolation and origin imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) self._flush() return def clear_all_1d_plots(self): """ Remove all lines from the canvas """ for ikey in self._lineDict.keys(): plot = self._lineDict[ikey] if plot is None: continue if isinstance(plot, tuple) is False: try: self.axes.lines.remove(plot) except ValueError as e: print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % ( str(plot), len(self.axes.lines), str(e)) self._lineDict[ikey] = None else: # error bar plot[0].remove() for line in plot[1]: line.remove() for line in plot[2]: line.remove() self._lineDict[ikey] = None # ENDIF(plot) # ENDFOR self._setupLegend() self.draw() return def clear_canvas(self): """ Clear data including lines and image from canvas """ # clear the image for next operation self.axes.hold(False) # Clear all lines self.clear_all_1d_plots() # clear image self.axes.cla() # Try to clear the color bar if len(self.fig.axes) > 1: self.fig.delaxes(self.fig.axes[1]) self._colorBar = None # This clears the space claimed by color bar but destroys sub_plot too. self.fig.clear() # Re-create subplot self.axes = self.fig.add_subplot(111) # flush/commit self._flush() return def getLastPlotIndexKey(self): """ Get the index/key of the last added line """ return self._lineIndex-1 def getPlot(self): """ reture figure's axes to expose the matplotlib figure to PyQt client """ return self.axes def getXLimit(self): """ Get limit of Y-axis """ return self.axes.get_xlim() def getYLimit(self): """ Get limit of Y-axis """ return self.axes.get_ylim() def setXYLimit(self, xmin, xmax, ymin, ymax): """ """ # for X xlims = self.axes.get_xlim() xlims = list(xlims) if xmin is not None: xlims[0] = xmin if xmax is not None: xlims[1] = xmax self.axes.set_xlim(xlims) # for Y ylims = self.axes.get_ylim() ylims = list(ylims) if ymin is not None: ylims[0] = ymin if ymax is not None: ylims[1] = ymax self.axes.set_ylim(ylims) # try draw self.draw() return def remove_plot_1d(self, plot_key): """ Remove the line with its index as key :param plot_key: :return: """ # self._lineDict[ikey].remove() print 'Remove line... ', # Get all lines in list lines = self.axes.lines assert isinstance(lines, list) print 'Number of lines = %d, List: %s' % (len(lines), str(lines)) print 'Line to remove: key = %s, Line Dict has key = %s' % (str(plot_key), str(self._lineDict.has_key(plot_key))) if plot_key in self._lineDict: self.axes.lines.remove(self._lineDict[plot_key]) self._lineDict[plot_key] = None else: raise RuntimeError('Line with ID %s is not recorded.' % plot_key) # Draw self.draw() return def updateLine(self, ikey, vecx, vecy, linestyle=None, linecolor=None, marker=None, markercolor=None): """ """ line = self._lineDict[ikey] if vecx is not None and vecy is not None: line.set_xdata(vecx) line.set_ydata(vecy) if linecolor is not None: line.set_color(linecolor) if linestyle is not None: line.set_linestyle(linestyle) if marker is not None: line.set_marker(marker) if markercolor is not None: line.set_markerfacecolor(markercolor) oldlabel = line.get_label() line.set_label(oldlabel) self.axes.legend() # commit self.draw() return def getLineStyleList(self): """ """ return MplLineStyles def getLineMarkerList(self): """ """ return MplLineMarkers def getLineBasicColorList(self): """ """ return MplBasicColors def getDefaultColorMarkerComboList(self): """ Get a list of line/marker color and marker style combination as default to add more and more line to plot """ combolist = [] nummarkers = len(MplLineMarkers) numcolors = len(MplBasicColors) for i in xrange(nummarkers): marker = MplLineMarkers[i] for j in xrange(numcolors): color = MplBasicColors[j] combolist.append( (marker, color) ) # ENDFOR (j) # ENDFOR(i) return combolist def _flush(self): """ A dirty hack to flush the image """ w, h = self.get_width_height() self.resize(w+1,h) self.resize(w,h) return def _setupLegend(self, location='best'): """ Set up legend self.axes.legend() Handler is a Line2D object. Lable maps to the line object """ loclist = [ "best", "upper right", "upper left", "lower left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center"] # Check legend location valid or not if location not in loclist: location = 'best' handles, labels = self.axes.get_legend_handles_labels() self.axes.legend(handles, labels, loc=location) # print handles # print labels #self.axes.legend(self._myLegendHandlers, self._myLegentLabels) return
class FigureCanvas(FigureCanvasQTAgg): """ A customized Qt widget for matplotlib figure. It can be used to replace GraphicsView of QtGui """ def __init__(self, parent): self._driver = AddieDriver() # from mpl_toolkits.axes_grid1 import host_subplot # import mpl_toolkits.axisartist as AA # import matplotlib.pyplot as plt # Instantiating matplotlib Figure self.fig = Figure() self.fig.patch.set_facecolor('white') self.axes = self.fig.add_subplot(111, projection='mantid') self.fig.subplots_adjust(bottom=0.15) # Initialize parent class and set parent FigureCanvasQTAgg.__init__(self, self.fig) self.setParent(parent) # Set size policy to be able to expanding and resizable with frame FigureCanvasQTAgg.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) FigureCanvasQTAgg.updateGeometry(self) # Variables to manage all lines/subplot self._lineDict = {} self._lineIndex = 0 # legend and color bar self._colorBar = None self._isLegendOn = False self._legendFontSize = 10 @property def is_legend_on(self): """ check whether the legend is shown or hide """ return self._isLegendOn def add_arrow(self, start_x, start_y, stop_x, stop_y): """ 0, 0, 0.5, 0.5, head_width=0.05, head_length=0.1, fc='k', ec='k') :return: """ head_width = 0.05 head_length = 0.1 fc = 'k' ec = 'k' self.axes.arrrow(start_x, start_y, stop_x, stop_y, head_width, head_length, fc, ec) def add_plot_1d(self, wkspname, wkspindex, color=None, label="", x_label=None, y_label=None, marker=None, line_style=None, line_width=1, alpha=1., show_legend=True, plotError=False): # process inputs and defaults if color is None: color = (0, 1, 0, 1) if marker is None: marker = 'None' if line_style is None: line_style = '-' # color must be RGBA (4-tuple) wksp = self._driver.get_ws(wkspname) if plotError: r = self.axes.errorbar(wksp, wkspIndex=wkspindex, color=color, marker=marker, linestyle=line_style, label=label, linewidth=line_width, alpha=alpha, markersize=40) else: # return: list of matplotlib.lines.Line2D object r = self.axes.plot(wksp, wkspIndex=wkspindex, color=color, marker=marker, markersize=2, linestyle=line_style, label=label, linewidth=line_width, alpha=alpha,distribution=True) self.axes.set_aspect('auto') # set x-axis and y-axis label if x_label is not None: self.axes.set_xlabel(x_label, fontsize=20) if y_label is not None: self.axes.set_ylabel(y_label, fontsize=20) # set/update legend if show_legend: self._setup_legend() # Register line_key = self._lineIndex if len(r) == 1: self._lineDict[line_key] = r[0] self._lineIndex += 1 else: msg = 'Return from plot is a %d-tuple: %s.. \n' % (len(r), r) for i_r in range(len(r)): msg += 'r[%d] = %s\n' % (i_r, str(r[i_r])) raise NotImplementedError(msg) # Flush/commit self.draw() return line_key def addPlot2D(self, array2d, xmin, xmax, ymin, ymax, holdprev, yticklabels=None): """ Add a 2D plot Arguments: - yticklabels :: list of string for y ticks """ # Release the current image self.axes.hold(holdprev) # Do plot # y ticks will be shown on line 1, 4, 23, 24 and 30 # yticks = [1, 4, 23, 24, 30] # self.axes.set_yticks(yticks) # show image imgplot = self.axes.imshow(array2d, extent=[xmin, xmax, ymin, ymax], interpolation='none') # set y ticks as an option: if yticklabels is not None: # it will always label the first N ticks even image is zoomed in print("--------> [FixMe]: The way to set up the Y-axis ticks is wrong!") # self.axes.set_yticklabels(yticklabels) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) # Flush... self._flush() def add_contour_plot(self, vec_x, vec_y, matrix_z): # create mesh grid grid_x, grid_y = np.meshgrid(vec_x, vec_y) # check size assert grid_x.shape == matrix_z.shape, 'Size of X (%d) and Y (%d) must match size of Z (%s).' \ '' % (len(vec_x), len(vec_y), matrix_z.shape) # Release the current image self.axes.hold(False) # Do plot contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100) labels = [item.get_text() for item in self.axes.get_yticklabels()] print('[DB...BAT] Number of Y labels = ', len(labels), ', Number of Y = ', len(vec_y)) # TODO/ISSUE/55: how to make this part more powerful if len(labels) == 2*len(vec_y) - 1: new_labels = [''] * len(labels) for i in range(len(vec_y)): new_labels[i*2] = '%d' % int(vec_y[i]) self.axes.set_yticklabels(new_labels) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type contour_plot.set_cmap('spectral') self._colorBar = self.fig.colorbar(contour_plot) else: self._colorBar.update_bruteforce(contour_plot) # Flush... self._flush() def addImage(self, imagefilename): """ Add an image by file """ #import matplotlib.image as mpimg # set aspect to auto mode self.axes.set_aspect('auto') img = matplotlib.image.imread(str(imagefilename)) # lum_img = img[:,:,0] # FUTURE : refactor for image size, interpolation and origin imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) self._flush() def clear_all_1d_plots(self): """ Remove all lines from the canvas """ for ikey in list(self._lineDict.keys()): plot = self._lineDict[ikey] if plot is None: continue if isinstance(plot, tuple) is False: try: self.axes.lines.remove(plot) except ValueError as e: print("[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % ( str(plot), len(self.axes.lines), str(e))) del self._lineDict[ikey] else: # error bar plot[0].remove() for line in plot[1]: line.remove() for line in plot[2]: line.remove() del self._lineDict[ikey] # ENDIF(plot) # ENDFOR self._setup_legend() self.draw() def clear_canvas(self): """ Clear data including lines and image from canvas """ # clear the image for next operation self.axes.hold(False) # Clear all lines self.clear_all_1d_plots() # clear image self.axes.cla() # Try to clear the color bar if len(self.fig.axes) > 1: self.fig.delaxes(self.fig.axes[1]) self._colorBar = None # This clears the space claimed by color bar but destroys sub_plot too. self.fig.clear() # Re-create subplot self.axes = self.fig.add_subplot(111) self.fig.subplots_adjust(bottom=0.15) # flush/commit self._flush() def decrease_legend_font_size(self): """ reset the legend with the new font size Returns: """ # minimum legend font size is 2! return if it already uses the smallest font size. if self._legendFontSize <= 2: return self._legendFontSize -= 1 self._setup_legend() self.draw() def getLastPlotIndexKey(self): """ Get the index/key of the last added line """ return self._lineIndex-1 def getPlot(self): """ reture figure's axes to expose the matplotlib figure to PyQt client """ return self.axes def getXLimit(self): """ Get limit of Y-axis """ return self.axes.get_xlim() def getYLimit(self): """ Get limit of Y-axis """ return self.axes.get_ylim() def hide_legend(self): """ hide the legend if it is not None """ if self.axes.legend() is not None: # set visible to be False and re-draw self.axes.legend().set_visible(False) self.draw() self._isLegendOn = False def increase_legend_font_size(self): """ reset the legend with the new font size """ self._legendFontSize += 1 self._setup_legend() self.draw() def setXYLimit(self, xmin, xmax, ymin, ymax): # for X xlims = self.axes.get_xlim() xlims = list(xlims) if xmin is not None: xlims[0] = xmin if xmax is not None: xlims[1] = xmax self.axes.set_xlim(xlims) # for Y ylims = self.axes.get_ylim() ylims = list(ylims) if ymin is not None: ylims[0] = ymin if ymax is not None: ylims[1] = ymax self.axes.set_ylim(ylims) # try draw self.draw() def set_title(self, title, color): # TODO/NOW - doc & etc self.axes.set_title(title, loc='center', color=color) self.draw() def remove_plot_1d(self, plot_key): """ Remove the line with its index as key """ # Get all lines in list lines = self.axes.lines assert isinstance(lines, list), 'Lines must be list' if plot_key in self._lineDict: try: self.axes.lines.remove(self._lineDict[plot_key]) except ValueError as r_error: error_message = 'Unable to remove to 1D line %s (ID=%d) due to %s.' % (str(self._lineDict[plot_key]), plot_key, str(r_error)) raise RuntimeError(error_message) # remove the plot key from dictionary del self._lineDict[plot_key] else: raise RuntimeError('Line with ID %s is not recorded.' % plot_key) self._setup_legend() # Draw self.draw() def show_legend(self): """ show the legend if the legend is not None Returns: """ if self.axes.legend() is not None: # set visible to be True and re-draw # self.axes.legend().set_visible(True) self._setup_legend() self.draw() # set flag on self._isLegendOn = True def updateLine(self, ikey, wkspname=None, wkspindex=None, vecx=None, vecy=None, linestyle=None, linecolor=None, marker=None, markercolor=None): """ Update a plot line or a series plot line """ line = self._lineDict[ikey] if line is None: print('[ERROR] Line (key = %d) is None. Unable to update' % ikey) return if wkspname or (vecx and vecy): if wkspname: vecx, vecy, _ = self._driver.get_ws_data(wkspname, wkspindex) line.set_data(vecx, vecy) if linecolor is not None: line.set_color(linecolor) if linestyle is not None: line.set_linestyle(linestyle) if marker is not None: line.set_marker(marker) if markercolor is not None: line.set_markerfacecolor(markercolor) oldlabel = line.get_label() line.set_label(oldlabel) self._setup_legend() # commit self.draw() def get_data(self, line_id): """ Get vecX and vecY from line object in matplotlib :param line_id: :return: 2-tuple as vector X and vector Y """ # check if line_id not in self._lineDict: raise KeyError('Line ID %s does not exist.' % str(line_id)) # get line line = self._lineDict[line_id] if line is None: raise RuntimeError('Line ID %s has been removed.' % line_id) return line.get_xdata(), line.get_ydata() def getLineStyleList(self): return LINE_STYLES def getLineMarkerList(self): return LINE_MARKERS def getLineBasicColorList(self): return BASIC_COLORS def getDefaultColorMarkerComboList(self): """ Get a list of line/marker color and marker style combination as default to add more and more line to plot """ combo_list = list() num_markers = len(LINE_MARKERS) num_colors = len(BASIC_COLORS) for i in range(num_markers): marker = LINE_MARKERS[i] for j in range(num_colors): color = BASIC_COLORS[j] combo_list.append((marker, color)) # ENDFOR (j) # ENDFOR(i) return combo_list def _flush(self): """ A dirty hack to flush the image """ w, h = self.get_width_height() self.resize(w+1, h) self.resize(w, h) def _setup_legend(self, location='best'): """ Set up legend self.axes.legend(): Handler is a Line2D object. Lable maps to the line object """ allowed_location_list = [ "best", "upper right", "upper left", "lower left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center"] # Check legend location valid or not if location not in allowed_location_list: location = 'best' handles, labels = self.axes.get_legend_handles_labels() self.axes.legend(handles, labels, loc=location, fontsize=self._legendFontSize) self._isLegendOn = True
class Visualiser(Frame): def __init__(self, master, **kwargs): self.data = None self.pca_data = None self.clusters = None self.measurer = None self.color_conv = matplotlib.colors.ColorConverter() self.frame = Frame(master, **kwargs) self.frame.rowconfigure(0, weight=1) self.frame.columnconfigure(0, weight=1) self.figure_frame = Frame(self.frame) self.figure_frame.rowconfigure(0, weight=1) self.figure_frame.rowconfigure(1, weight=1) self.figure_frame.rowconfigure(2, weight=1) self.figure_frame.columnconfigure(0, weight=1) self.figure_frame.columnconfigure(1, weight=1) self.figure = Figure(figsize=(5,5), dpi=100) self.canvas = FigureCanvasTkAgg(self.figure, self.figure_frame) self.figure_subplot = self.figure.add_subplot("111") self.canvas.show() self.canvas.get_tk_widget().pack(fill=BOTH, expand=1) self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.figure_frame) self.toolbar.update() self.canvas._tkcanvas.pack(fill=BOTH, expand=1) self.figure_frame.grid(row=0, sticky=N+E+S+W) self.controls_frame = Frame(self.frame) self.show_points = IntVar() self.show_points.set(1) self.show_points_c = Checkbutton(self.controls_frame, text="Show Points", variable=self.show_points) self.show_points_c.grid(row=0, column=0, sticky=N+E+S+W) self.show_convex_hull = IntVar() self.show_convex_hull_c = Checkbutton(self.controls_frame, text="Show Convex Hull", variable=self.show_convex_hull) self.show_convex_hull_c.grid(row=0, column=1, sticky=N+E+S+W) self.show_centers = IntVar() self.show_centers_c = Checkbutton(self.controls_frame, text="Show Cluster Centers", variable=self.show_centers) self.show_centers_c.grid(row=0, column=2, sticky=N+E+S+W) self.show_ellipse = IntVar() self.show_ellipse_c = Checkbutton(self.controls_frame, text="Show Variance Ellipse", variable=self.show_ellipse) self.show_ellipse_c.grid(row=1, column=0, sticky=N+E+S+W) self.show_3D = IntVar() self.show_3D_c = Checkbutton(self.controls_frame, text="Show in 3D (If possible)", variable=self.show_3D) self.show_3D_c.grid(row=1, column=1, sticky=N+E+S+W) self.rerender_b = Button(self.controls_frame, text="Rerender visualisation", command=self.render) self.rerender_b.grid(row=2, columnspan=2, sticky=N+E+S+W) self.controls_frame.grid(row=1, sticky=N+E+S+W) def grid(self, **kwargs): self.frame.grid(**kwargs) def pack(self, **kwargs): self.frame.pack(**kwargs) def load_data(self, data, clusters): self.measurer = clustermeasures.ClusterMeasures() self.measurer.load_clustered_data(data, clusters) self.measurer.calculate_measures() self.data = self.measurer._data self.clusters = self.measurer._clusters self.pca_data = mlab.PCA(np.matrix(self.data)).Y self.colors = [self.color_conv.to_rgb((random.random(), random.random(), random.random())) for i in range(self.measurer._num_clusters)] def render(self): #Display the 2d PCA of the clustered data num_clusters = self.measurer._num_clusters clusters = [[] for i in range(num_clusters)] self.figure.delaxes(self.figure_subplot) ############ DISPLAY IN 3D ################ if self.show_3D.get(): self.figure_subplot = self.figure.add_subplot(111, projection='3d') self.figure_subplot.hold(True) color = 0 for cluster in self.measurer.pca_3d_clustered: if self.show_ellipse.get(): centroid = find_centroid(cluster) variance = np.var(cluster, 0) stddev = [math.sqrt(v) for v in variance] ## your ellispsoid and center in matrix form A = np.array([[stddev[0],0,0],[0,stddev[1],0],[0,0,stddev[2]]]) A = np.cov(np.matrix(cluster), rowvar=0) center = centroid #Two standard deviations of data N = 2; ## find the rotation matrix and radii of the axes U, s, rotation = linalg.svd(A) radii = N*np.sqrt(s) # now carry on with EOL's answer u = np.linspace(0.0, 2.0 * np.pi, 100) v = np.linspace(0.0, np.pi, 100) x = radii[0] * np.outer(np.cos(u), np.sin(v)) y = radii[1] * np.outer(np.sin(u), np.sin(v)) z = radii[2] * np.outer(np.ones_like(u), np.cos(v)) for i in range(len(x)): for j in range(len(x)): [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], rotation) + center self.figure_subplot.plot_wireframe(x, y, z, rstride=4, cstride=4, color=self.colors[color], alpha=0.5) if self.show_points.get(): self.figure_subplot.scatter([e[0] for e in cluster], [e[1] for e in cluster], [e[2] for e in cluster], c=self.colors[color], marker='o', alpha=.6) if self.show_centers.get(): center = find_centroid(cluster) self.figure_subplot.scatter(center[0], center[1], center[2], color=self.colors[color], marker='*',s=100) color += 1 ################## DISPLAY IN 2D ################### if not self.show_3D.get(): self.figure_subplot = self.figure.add_subplot("111") self.figure_subplot.hold(True) for i in range(num_clusters): cluster = self.measurer.pca_2d_clustered[i] color = self.colors[i] if self.show_points.get(): self.figure_subplot.scatter([e[0] for e in cluster], [e[1] for e in cluster], color=color, marker='o') if self.show_centers.get(): center = find_centroid(self.measurer.pca_2d_clustered[i]) self.figure_subplot.scatter(center[0], center[1], color=color, marker='*',s=100) #Plot the convex hull if self.show_convex_hull.get(): self.display_convex_hull(cluster, self.colors[i]) self.figure_subplot.hold(False) self.canvas.show() def display_convex_hull(self, cluster, color): cluster = np.matrix(cluster) try: hull = ConvexHull(cluster) except: return False for simplex in hull.simplices: self.figure_subplot.plot(cluster[simplex, 0], cluster[simplex, 1], color=color)
class Qt4Mpl2dCanvas(FigureCanvas): """ A customized Qt widget for matplotlib 2D image. It can be used to replace GraphicsView """ def __init__(self, parent): """ Initialization """ # Instantiating matplotlib Figure self.fig = Figure() self.fig.patch.set_facecolor('white') self.axes = self.fig.add_subplot( 111) # return: matplotlib.axes.AxesSubplot # Initialize parent class and set parent FigureCanvas.__init__(self, self.fig) self.setParent(parent) # Set size policy to be able to expanding and resizable with frame FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) # legend and color bar self._colorBar = None # Buffer of data self._currentArray2D = None # image management data structure self._currIndex = 0 self._imagePlotDict = dict() # image size self._xLimit = [0., 1.] self._yLimit = [0., 1.] return @property def array2d(self): """ get the matrix plot now :return: """ return self._currentArray2D def add_2d_plot(self, array2d, x_min, x_max, y_min, y_max, hold_prev, yticklabels=None): """ Add a 2D plot Requirements: (1) a valid 2-dimensional numpy.ndarray (2) x_min, x_max, y_min, y_max are of right order Guarantees: a 2D fill-plot is made :param array2d: :param x_min: :param x_max: :param y_min: :param y_max: :param hold_prev: hold previous image. If False, all 2D image and polygon patches will be removed :param yticklabels: list of string for y ticks :return: """ # Check assert isinstance( array2d, np.ndarray ), 'Input array2d must be a numpy array but not %s.' % str( type(array2d)) assert isinstance(x_min, int) and isinstance(x_max, int) and x_min < x_max, \ 'x_min = %s (of type %s) should be less than x_max = %s (of type %s).' \ '' % (str(x_min), str(type(x_min)), str(x_max), str(type(x_max))) assert isinstance(y_min, int) and isinstance(y_max, int) and y_min < y_max # Release the current image self.axes.hold(hold_prev) # show image img_plot = self.axes.imshow(array2d, extent=[x_min, x_max, y_min, y_max], interpolation='none') self._currentArray2D = array2d # set y ticks as an option: if yticklabels is not None: # it will always label the first N ticks even image is zoomed in # FUTURE-VZ : The way to set up the Y-axis ticks is wrong!" # self.axes.set_yticklabels(yticklabels) print( '[Warning] The method to set up the Y-axis ticks to 2D image is wrong!' ) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type img_plot.set_cmap('spectral') self._colorBar = self.fig.colorbar(img_plot) else: self._colorBar.update_bruteforce(img_plot) # Flush... self._flush() # Add the image management self._currIndex += 1 self._imagePlotDict[self._currIndex] = img_plot return self._currIndex def add_patch(self, patch): """ add an artist patch such as polygon :param patch: :return: """ self.axes.add_artist(patch) # Flush... self._flush() return def addImage(self, imagefilename): """ Add an image by file """ # set aspect to auto mode self.axes.set_aspect('auto') img = matplotlib.image.imread(str(imagefilename)) # lum_img = img[:,:,0] # FUTURE : refactor for image size, interpolation and origin imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) self._flush() return def clear_canvas(self): """ Clear data including lines and image from canvas """ # clear the image for next operation self.axes.hold(False) # clear 2D image self.axes.cla() # Try to clear the color bar if len(self.fig.axes) > 1: self.fig.delaxes(self.fig.axes[1]) self._colorBar = None # This clears the space claimed by color bar but destroys sub_plot too. self.fig.clear() # Re-create subplot self.axes = self.fig.add_subplot(111) # END-FOR # flush/commit self._flush() return def plot_polygon(self, vertex_array, fill=False, color='w'): """ Plot a new polygon :param vertex_array: :param fill: :param color: :return: """ # check requirements assert isinstance(vertex_array, np.ndarray) assert isinstance(fill, bool) assert isinstance(color, str) # plot polygon p = plt.Polygon(vertex_array, fill=fill, color=color) self.axes.add_artist(p) # Flush... self._flush() return p @property def x_min(self): """ x minimum :return: """ return self._xLimit[0] @property def x_max(self): """ maximum x :return: """ return self._xLimit[1] @property def y_min(self): """ minimum y :return: """ return self._yLimit[0] @property def y_max(self): """ maximum y :return: """ return self._yLimit[1] def _flush(self): """ A dirty hack to flush the image """ w, h = self.get_width_height() self.resize(w + 1, h) self.resize(w, h) return
class GraphPanel(wx.Panel): def __init__(self,parent,ctrl): wx.Panel.__init__(self,parent) self.SetBackgroundColour('#FFFFFF') self.SetSizeWH(500,600) self.ctrlPanel = ctrl self.initGraph() wx.EVT_PAINT(self, self.OnPaint) def initGraph(self): self.trial = 1 self.sbs = {} self.sbs['Lever'] = ScatterBrain('Lever','#3399FF','s') self.sbs['Mark'] = ScatterBrain('Mark','#000000','x') for i in range(0,8): name = 'aTaste%d'%i self.sbs[name] = ScatterBrain(name,Ferret.TasteColors[i],'o') name2 = 'mTaste%d'%i self.sbs[name2] = ScatterBrain(name2,Ferret.TasteColors[i],'o',False) self.figure = Figure(dpi=100,figsize=(5,5.8)) self.axes = self.figure.add_subplot(111) self.axes.axis([0,X.trialDuration,0,1.5]) self.axes.set_xlabel('time (s)') for i in X.intervalList: if isinstance(i, Intervals.WaitInt): continue color = Ferret.iColors[i.type] if isinstance(i, Intervals.ToneInt): color = Ferret.freq2color(i.freq) self.axes.axvspan(i.startTime,i.startTime+i.duration,facecolor=color,alpha=0.5,lw=0.0, zorder=0) LText = FontProperties() LText.set_size("small") self.axes.legend((self.sbs['Lever'].getPlot(self.axes),self.sbs['Mark'].getPlot(self.axes), self.sbs['aTaste1'].getPlot(self.axes),self.sbs['mTaste1'].getPlot(self.axes)), ("Lever Press","Time Marked", "Reward Given","Manual Reward"), prop=LText, fancybox=True, bbox_to_anchor=(0., 1.02, 1., .102), loc=1, ncol=2, mode="expand", borderaxespad=0) self.canvas = FigureCanvas(self, -1, self.figure) def clearGraph(self): self.figure.delaxes(self.axes) self.initGraph() self.Refresh() def addPoint(self,t,pcat): if pcat<8: self.sbs['aTaste%d'%pcat].addPoint(t,self.trial) elif pcat<16: self.sbs['mTaste%d'%(pcat-8)].addPoint(t,self.trial) elif pcat==30: self.sbs['Lever'].addPoint(t,self.trial) elif pcat==31: self.sbs['Mark'].addPoint(t,self.trial) def newTrial(self): self.trial+=1 self.axes.set_ylim(top=(self.trial+0.5)) def OnPaint(self, event): for k,v in self.sbs.items(): v.getPlot(self.axes) self.canvas.draw() event.Skip() def OnSetFocus(self, event): self.color = 'yellow' self.Refresh() def OnKillFocus(self, event): self.color = '#b3b3b3' self.Refresh() def saveGraph(self,filename="graph.png"): self.figure.savefig(filename)
class MyGui: def __init__(self): self.window = Tk() self.window.protocol("WM_DELETE_WINDOW", self.on_closing) self.xvals = [] self.yvals = [] """ but = Button(self.window, text = "Start", font = "Calibri 20", width = 6, height = 1) but.grid(row = 3, column = 3) """ # Frame1 self.frame1 = Frame(self.window) self.frame1.grid(row=0, column=0) lab = Label(self.frame1, text="File Header:", font="calibri 20", width=10, height=1, anchor="e") lab.grid(row=0, column=0, sticky="E", pady=15) self.headerentry = ScrolledText(self.frame1, height=3, width=20) self.headerentry.grid(row=0, column=1, sticky="E") lab = Label(self.frame1, text="File Path:", font="calibri 20", width=10, height=1, anchor="e") lab.grid(row=1, column=0) buttonpath = Button(self.frame1, text="Browse", command=self.browse_button, font="calibri 20", width=11, height=1, anchor="center") buttonpath.grid(row=1, column=1, sticky="w", pady=(0, 5)) # Frame1 End # Frame3 widthtime = 3 self.frame3 = Frame(self.window) self.frame3.grid(row=1, column=0) lab = Label(self.frame3, text="Duration:", font="calibri 20", width=8, height=1) lab.grid(row=1, column=0, sticky="e", padx=(0, 20)) self.dayE = Entry(self.frame3, width=widthtime) self.dayE.grid(row=0, column=2, padx=(5, 18)) lab = Label(self.frame3, text="Days:", font="calibri 15") lab.grid(row=0, column=1, sticky="e") self.hourE = Entry(self.frame3, width=widthtime) self.hourE.grid(row=1, column=2, padx=(5, 18)) lab = Label(self.frame3, text="Hours:", font="calibri 15") lab.grid(row=1, column=1, sticky="e") self.minutesE = Entry(self.frame3, width=widthtime) self.minutesE.grid(row=2, column=2, padx=(5, 18)) lab = Label(self.frame3, text="Minutes:", font="calibri 15") lab.grid(row=2, column=1, sticky="e") lab = Label(self.frame3, text="Interval:", font="calibri 20") lab.grid(row=3, column=0, padx=(0, 20)) lab = Label(self.frame3, text="Seconds:", font="calibri 15") lab.grid(row=3, column=1, sticky="e") self.entryT = Entry(self.frame3, width=widthtime) self.entryT.grid(row=3, column=2, padx=(5, 18)) # Frame3 End # Frame5 Start self.frame5 = Frame(self.window) self.frame5.grid(row=3, column=0) lab = Label(self.frame5, text="DMM:", font="calibri 20") lab.grid(row=0, column=0, sticky="e", padx=10) but = Button(self.frame5, text="Ping", command=self.ping, font="calibri 12", pady=2) but.grid(row=0, column=3, padx=10) but = Button(self.frame5, text="R", command=self.ping, font="calibri 12", pady=2) but.grid(row=0, column=4, padx=10) self.dropdowncom(self.frame5) # self.batterystat = Progressbar(self.frame5, orient=HORIZONTAL, length=100, mode="determinate") # self.batterystat.grid(row=1, column=0, columnspan=2) # Frame5 End # Frame7 self.frame7 = Frame(self.window) self.frame7.grid(column=1, row=3) self.batlabel = Label(self.frame7, text="Battery: n/a %", font="calibri 15") self.batlabel.grid(row=0, column=1, padx=20) but = Button(self.frame7, text="Start", command=self.startmeas, font="calibri 15") but.grid(row=0, column=2, padx=(10, 0)) self.percentlab = Label(self.frame7, text="Progress: 0%", font="calibri 15") self.percentlab.grid(row=0, column=0, padx=(0, 10)) # Frame Graph self.frame8 = Frame(self.window) self.frame8.grid(row=0, column=1, rowspan=2) self.fig = Figure(figsize=(5, 4), dpi=100) self.suba = self.fig.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame8) self.canvas.draw() self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1) # Frame Graph End def dropdowncom(self, frame): find_com = serial.tools.list_ports COM = find_com.comports() self.COM_LIST = [] for x in COM: self.COM_LIST.append(x[0]) if self.COM_LIST == []: self.COM_LIST.append("COM0") self.dmmcom = StringVar(self.window) self.dmmcom.set(self.COM_LIST[0]) self.DMM = OptionMenu(frame, self.dmmcom, *self.COM_LIST) self.DMM.grid(column=1, row=0, sticky="e") self.DMM.config(width=5, height=1, highlightthickness=0, font="Calibri 14") def updatecoms(self): print("update") find_com = serial.tools.list_ports COM = find_com.comports() self.COM_LIST = [] for x in COM: self.COM_LIST.append(x[0]) if self.COM_LIST == []: self.COM_LIST.append("COM0") self.dmmcom.set('') self.DMM['menu'].delete(0, 'end') new_choices = self.COM_LIST for choice in new_choices: self.DMM['menu'].add_command(label=choice, command=tkinter._setit(self.dmmcom, choice)) self.dmmcom.set(self.COM_LIST[0]) def updatecoms(self): print("update") find_com = serial.tools.list_ports COM = find_com.comports() self.COM_LIST = [] for x in COM: self.COM_LIST.append(x[0]) if self.COM_LIST == []: self.COM_LIST.append("COM0") self.dmmcom.set('') self.DMM['menu'].delete(0, 'end') new_choices = self.COM_LIST for choice in new_choices: self.DMM['menu'].add_command(label=choice, command=tkinter._setit(self.dmmcom, choice)) self.dmmcom.set(self.COM_LIST[0]) def start(self): self.window.mainloop() def browse_button(self): print("Browse") self.filename = filedialog.askdirectory() print(self.filename) def ping(self): self.dmm = Connection() self.dmm.initialize(self.dmmcom.get()) self.dmm.finddevice() self.batlabel["text"] = "Battery: " + str(self.dmm.getbattery()) + "%" self.dmm.kill() def gettime(self): try: d = int(self.dayE.get()) except: d = 0 try: h = int(self.hourE.get()) except: h = 0 try: m = float(self.minutesE.get()) except: m = 0 try: timeb = float(self.entryT.get()) except: timeb = 3 self.time = d * 24 * 60 * 60 + h * 60 * 60 + m * 60 self.timebet = timeb def startmeas(self): self.suba.clear() print("clear") self.gettime() numberofmeas = self.time / self.timebet numberofmeas = int(numberofmeas) print(numberofmeas) time = 0 path = self.filename + "/measurement.txt" file = open(path, "w") file.write(self.headerentry.get('1.0', END) + "\n") file.write("Meassurement[n]; Time[s]; Value; Unit \n") file.close() com = self.dmmcom.get() self.dmm.initialize(com) unitdmm = self.dmm.getsetup()[0] self.xvals = [] self.yvals = [] for x in range(numberofmeas): self.dmm.initialize(com) value = self.dmm.getValue() self.dmm.kill() file = open(path, "a") print(x, time) linewr = ("%d;%.3f;%.6f;%s \n" % (x, time, value, unitdmm)) self.xvals.append(time) self.yvals.append(value) print(linewr) file.write(linewr) file.close() self.fig.delaxes(self.suba) self.suba = self.fig.add_subplot(111) #xvals = self.xvals[-20:] #yvals = self.yvals[-20:] xvals = self.xvals yvals = self.yvals self.suba.plot(xvals, yvals, color="blue") self.canvas.draw() percent = (x / numberofmeas) * 100 self.percentlab["text"] = ("Progress: %.2f" % percent) # Showing percentage in Gui self.sleep(self.timebet) time = time + self.timebet file.close() def rgraph(self): self.fig = Figure(figsize=(5, 4), dpi=100) self.suba = self.fig.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame8) self.canvas.draw() self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1) def sleep(self, x): duration = 0 start = time.perf_counter() print("sleep") while duration <= x: time.sleep(0.005) self.window.update() duration = time.perf_counter() - start def on_closing(self): if messagebox.askokcancel("Quit", "Do you want to quit?\n some meassurement will be lost\n and the programm will stop meassuring"): self.window.destroy()
class App: def __init__(self, master): # create toplevel window frame = Frame(master) frame.grid(ipadx=10, ipady=10) self.wdir = os.getcwd() + '/' self.I = pp.Image() self.Tool = pp.Tools() self.lb1 = Label(frame, text="Nstep").grid(row=0, column=0) self.enstep = Entry(frame, width=8) self.enstep.grid(row=0, column=1) self.enstep.insert(0, "0") self.LoadedNstep = StringVar() self.PresentTime = StringVar() self.myData = self.loaddata() self.varkeys = self.myData.get_varinfo()['allvars'] self.grid_dict = self.myData.grid() if self.grid_dict["n3"] != 1: self.Geom = '3D' elif self.grid_dict["n3"] == 1 and self.grid_dict["n2"] != 1: self.Geom = '2D' else: self.Geom = '1D' self.ldatabutton = Button(frame, text="Load data", command=self.loaddata) self.ldatabutton.grid(row=0, column=2) ############### MARK THE CUTS ################################# self.ex1 = Entry(frame, width=5) self.ex1.grid(row=2, column=0) self.ex1.insert(0, "x1") self.ex2 = Entry(frame, width=5) self.ex2.grid(row=2, column=1) self.ex2.insert(0, "x2") self.ex3 = Entry(frame, width=5) self.ex3.grid(row=2, column=2) self.ex3.insert(0, "x3") if self.Geom == '2D': self.ex3.config(state='disabled') if self.Geom == '1D': self.ex3.config(state='disabled') self.ex2.config(state='disabled') self.ex1.config(state='disabled') # place a graph somewhere here self.f = Figure(figsize=(7, 7), dpi=100) self.a = self.f.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.f, master=root) self.canvas.show() self.canvas.get_tk_widget().grid(row=0, column=3, columnspan=10, rowspan=10, sticky=E) #self.toolbar = NavigationToolbar2TkAgg(self.canvas,tl) #self.toolbar.update() #self.canvas._tkcanvas.grid(row=60,column=15,sticky=E) self.v = StringVar() self.v.set("None") ################ VARIABLES TO PLOT ################################# for j in range(len(self.varkeys)): self.ldata = Radiobutton(frame, text=self.varkeys[j], variable=self.v, value=self.varkeys[j], command=self.getmyvar) self.ldata.grid(row=3 + j, column=0, sticky=W) ################ SLICES CHOICE ################################# self.slvar = StringVar() self.slvar.set("Choose Slice") if self.Geom == '3D': SliceList = ("Along x1", "Along x2", "Along x3", "Along x1-x2", "Along x2-x3", "Along x3-x1") elif self.Geom == '2D': SliceList = ("Along x1", "Along x2", "Along x1-x2") else: SliceList = () for j in range(len(SliceList)): self.sldata = Radiobutton(frame, text=SliceList[j], variable=self.slvar, value=SliceList[j], command=self.setslice) self.sldata.grid(row=3 + j, column=1, sticky=W) ############### PLOT PROPERTIES ################################# self.logvar = IntVar() self.chkb = Checkbutton(frame, text="Log ", variable=self.logvar, onvalue=1, offvalue=0, command=self.logchkcall) self.chkb.grid(row=3, column=2, sticky=W) #(row=15,column=0,sticky=W) self.polarvar = IntVar() self.polchkb = Checkbutton(frame, text="Polar", variable=self.polarvar, onvalue=1, offvalue=0, command=self.polchkcall) self.polchkb.grid(row=4, column=2, sticky=W) #(row=15,column=1) if self.Geom == '1D': self.polchkb.config(state='disabled') self.polarvar.set(0) self.preaspect = IntVar() self.aspectb = Checkbutton(frame, text="Aspect", variable=self.preaspect, onvalue=1, offvalue=0, command=self.aspchkcall) self.aspectb.grid(row=5, column=2, sticky=W) #(row=15,column=2) if self.Geom == '1D': self.aspectb.config(state='disabled') ################ X and Y LABELS ################################# self.lb2 = Label(frame, text="Labels").grid(row=22, column=0) self.xlb = Entry(frame, width=15) self.xlb.grid(row=22, column=1) self.xlb.insert(0, "xlabel") self.ylb = Entry(frame, width=15) self.ylb.grid(row=22, column=2) self.ylb.insert(0, "ylabel") ############### X and Y RANGE####################### self.lb2a = Label(frame, text="XRange").grid(row=24, column=0) self.lb2b = Label(frame, text="YRange").grid(row=26, column=0) self.lb2c = Label(frame, text="VarRange").grid(row=28, column=0) self.xrmin = Entry(frame, width=15) self.xrmin.grid(row=24, column=1) self.xrmin.insert(0, '') self.xrmax = Entry(frame, width=15) self.xrmax.grid(row=24, column=2) self.xrmax.insert(0, '') self.yrmin = Entry(frame, width=15) self.yrmin.grid(row=26, column=1) self.yrmin.insert(0, '') self.yrmax = Entry(frame, width=15) self.yrmax.grid(row=26, column=2) self.yrmax.insert(0, '') self.varmin = Entry(frame, width=15) self.varmin.grid(row=28, column=1) self.varmin.insert(0, '') self.varmax = Entry(frame, width=15) self.varmax.grid(row=28, column=2) self.varmax.insert(0, '') if self.Geom == '1D': self.yrmin.config(state='disabled') self.yrmax.config(state='disabled') ################ CONTOURS ################################# self.lb3 = Label(frame, text="Contours").grid(row=16, column=0) self.contvar = IntVar() self.chkb = Checkbutton(frame, text="Contour", variable=self.contvar, onvalue=1, offvalue=0, command=self.contchkcall) self.chkb.grid(row=6, column=2, sticky=W) #(row=16,column=0,sticky=W) self.plcont = StringVar() self.contkeys = ["None"] if "b1" in self.varkeys: for item in self.varkeys: self.contkeys.append(item) self.contkeys.append("x1*b3") self.contkeys.append("x1*A3") else: for item in self.varkeys: self.contkeys.append(item) self.plcont.set("None") self.contmenu = OptionMenu(frame, self.plcont, *self.contkeys) self.contmenu.grid(row=16, column=1) self.xlevb = Entry(frame, width=15) self.xlevb.grid(row=16, column=2, sticky=W) self.xlevb.insert(0, "Levels") self.xlevb.config(state='disabled') self.contmenu.config(state='disabled') if self.Geom == '1D': self.chkb.config(state='disabled') ################ ARROWS ################################# self.lb4 = Label(frame, text="Arrows").grid(row=19, column=0) self.arrowvar = IntVar() self.arrowchkb = Checkbutton(frame, text="Arrows", variable=self.arrowvar, onvalue=1, offvalue=0, command=self.arrchkcall) self.arrowchkb.grid(row=7, column=2, sticky=W) #(row=16,column=0,sticky=W) self.arrspb = Entry(frame, width=15) self.arrspb.grid(row=19, column=2, sticky=W) self.arrspb.insert(0, "20") self.plarr = StringVar() self.arrkeys = ["None"] self.arrkeys.append("Vp") self.arrkeys.append("Vp_norm") if "b1" in self.varkeys: self.arrkeys.append("Bp") self.arrkeys.append("Bp_norm") self.plarr.set("None") self.arrmenu = OptionMenu(frame, self.plarr, *self.arrkeys) self.arrmenu.grid(row=19, column=1) self.arrmenu.config(state='disabled') self.arrspb.config(state='disabled') if self.Geom == '1D': self.arrowchkb.config(state='disabled') ################ VARIOUS PLOTTING BUTTONS ################################# self.pltbutton = Button(frame, text="Plot", command=self.plotfinal) self.pltbutton.grid(row=36, column=0) if self.Geom == '1D': self.pltbutton.config(state='active') else: self.pltbutton.config(state='disabled') self.surfbutton = Button(frame, text="Surface", command=self.plotsurface) self.surfbutton.grid(row=36, column=1) self.surfbutton.config(state='disabled') #if self.Geom == '1D': # self.surfbutton.config(state='disabled') self.clrbutton = Button(frame, text="Clear", command=self.plotclear) self.clrbutton.grid(row=36, column=2) ################ INFORMATION ################################# self.lbinf0 = Label(frame, text="Information", font=("Times", 12, "bold")) self.lbinf0.grid(row=47, column=0, sticky=W, columnspan=3) self.lbinf1a = Label(frame, text="Dir :", font=("Times", 10, "bold")).grid(row=49, column=0, sticky=W, columnspan=3) self.lbinf1 = Label(frame, text=self.wdir).grid(row=50, column=0, sticky=W, columnspan=3) self.lbinf2a = Label(frame, text="Domain :", font=("Times", 10, "bold")).grid(row=51, column=0, sticky=W, columnspan=3) self.lbinf2 = Label( frame, text="n1 x n2 x n3 = %d x %d x %d " % (self.grid_dict.get('n1'), self.grid_dict.get('n2'), self.grid_dict.get('n3'))).grid(row=52, column=0, sticky=W, columnspan=3) self.lbinf3a = Label(frame, text="Time Status", font=("Times", 10, "bold")).grid(row=53, column=0, sticky=W, columnspan=3) self.lbinf4 = Label(frame, text="Nlast = %d" % (pp.nlast_info().get('nlast'))).grid(row=54, column=0, sticky=W, columnspan=3) self.lbinf5 = Label(frame, textvariable=self.LoadedNstep).grid(row=55, column=0, sticky=W, columnspan=3) self.lbinf6 = Label(frame, textvariable=self.PresentTime).grid(row=56, column=0, sticky=W, columnspan=3) ################ VARIOUS FUNCTIONS ################################# def loaddata(self): try: int(self.enstep.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the proper value of Nstep" else: mynstep = int(self.enstep.get()) self.D = pp.pload(mynstep, w_dir=self.wdir) self.LoadedNstep.set("Loaded Nstep = " + self.enstep.get()) self.PresentTime.set("Present Time = " + str(self.D.time_info()['time']) + " [cu]") return self.D def getmyvar(self): try: self.v.get() != "None" except KeyError: print "Specify the variable to plot" else: self.myvar = self.v.get() def logchkcall(self): self.logchk = self.logvar.get() def contchkcall(self): self.contchk = self.contvar.get() if self.contchk == 1: self.contmenu.config(state='normal') self.xlevb.config(state='normal') else: self.contmenu.config(state='disabled') self.xlevb.config(state='disabled') def arrchkcall(self): self.arrchk = self.arrowvar.get() if self.arrchk == 1: self.arrmenu.config(state='normal') self.arrspb.config(state='normal') else: self.arrmenu.config(state='disabled') self.arrspb.config(state='disabled') def aspchkcall(self): self.aspchk = self.preaspect.get() def polchkcall(self): self.polchk = self.polarvar.get() def setslice(self): self.slicename = self.slvar.get() if self.slicename == "Along x1" or self.slicename == "Along x2" or self.slicename == "Along x3": self.surfbutton.config(state='disabled') self.arrowchkb.config(state='disabled') self.arrowvar.set(0) self.chkb.config(state='disabled') self.contvar.set(0) self.pltbutton.config(state='active') self.polchkb.config(state='disabled') self.polarvar.set(0) else: self.pltbutton.config(state='disabled') self.arrowchkb.config(state='normal') self.chkb.config(state='normal') self.surfbutton.config(state='active') self.polchkb.config(state='normal') if self.slicename == "Along x2-x3": self.polchkb.config(state='disabled') self.polarvar.set(0) def plotclear(self): self.a.clear() if len(self.f.axes) > 1: self.f.delaxes(self.f.axes[1]) self.f.subplots_adjust(right=0.90) self.canvas.show() def plotfinal(self): if self.getplotvar() == True: self.a.axis([ self.getxaxisrange()[0], self.getxaxisrange()[1], self.getvarrange()[0], self.getvarrange()[1] ]) self.a.plot(self.x, self.var) self.a.set_aspect('auto') self.a.set_xlabel(self.xlb.get()) self.a.set_ylabel(self.ylb.get()) self.canvas.show() def plotsurface(self): tdum = time.time() self.plotclear() if self.preaspect.get() == 1: self.a.set_aspect('equal') else: self.a.set_aspect('auto') if self.polarvar.get() == 1: if self.drawpolar() == True: self.a.axis([ self.getxaxisrange()[0], self.getxaxisrange()[1], self.getyaxisrange()[0], self.getyaxisrange()[1] ]) self.image = self.a.imshow(self.SphData[self.myvar], origin='lower', extent=self.extent, interpolation='nearest', cmap="jet", vmin=self.getvarrange()[0], vmax=self.getvarrange()[1]) self.f.colorbar(self.image) else: if self.getsurfvar() == True: self.a.axis([ self.getxaxisrange()[0], self.getxaxisrange()[1], self.getyaxisrange()[0], self.getyaxisrange()[1] ]) self.image = self.a.pcolormesh(self.x, self.y, self.var, cmap='jet', vmin=self.getvarrange()[0], vmax=self.getvarrange()[1]) self.f.colorbar(self.image) if self.contvar.get() == 1: try: self.plcont.get() != "None" except KeyError: print "Specify the variable for Contour" else: self.drawcontour() self.contlevlist = [] self.contlevstr = string.split(self.xlevb.get(), ',') try: if self.contlevstr[0] == 'log': self.flevel = self.contlevstr[1] self.varcont = log10(self.varcont) else: self.flevel = self.contlevstr[0] float(self.flevel) self.contlevlist = [float(self.flevel)] except: self.contlevlist = 5 else: for j in range(1, len(self.contlevstr)): self.contlevlist.append(float(self.contlevstr[j])) self.cs1 = self.a.contour(self.xcont, self.ycont, self.varcont, self.contlevlist, colors="w") self.a.clabel(self.cs1, inline=True) if self.arrowvar.get() == 1: try: self.plarr.get() != "None" except KeyError: print "Specify the variable for plotting the arrow" else: self.drawarrow() self.a.quiver(self.xcong, self.ycong, self.xveccong, self.yveccong, color='w') self.a.set_xlabel(self.xlb.get()) self.a.set_ylabel(self.ylb.get()) self.canvas.show() print time.time() - tdum def getvarrange(self): try: float(self.varmin.get()) except: if self.polarvar.get() != 1: self.varminval = min(self.var) else: self.varminval = min( self.SphData[self.myvar][self.isnotnan].flat) #self.minPl else: self.varminval = float(self.varmin.get()) try: float(self.varmax.get()) except: if self.polarvar.get() != 1: self.varmaxval = max(self.var) else: self.varmaxval = max( self.SphData[self.myvar][self.isnotnan].flat) #self.maxPl else: self.varmaxval = float(self.varmax.get()) return [self.varminval, self.varmaxval] def getxaxisrange(self): try: float(self.xrmin.get()) except: if self.polarvar.get() != 1: self.xminval = min(self.x) else: self.xminval = min(self.R.flat) else: self.xminval = float(self.xrmin.get()) try: float(self.xrmax.get()) except: if self.polarvar.get() != 1: self.xmaxval = max(self.x) else: self.xmaxval = max(self.R.flat) else: self.xmaxval = float(self.xrmax.get()) return [self.xminval, self.xmaxval] def getyaxisrange(self): try: float(self.yrmin.get()) except: if self.polarvar.get() != 1: self.yminval = min(self.y) else: self.yminval = min(self.Z.flat) else: self.yminval = float(self.yrmin.get()) try: float(self.yrmax.get()) except: if self.polarvar.get() != 1: self.ymaxval = max(self.y) else: self.ymaxval = max(self.Z.flat) else: self.ymaxval = float(self.yrmax.get()) return [self.yminval, self.ymaxval] def getplotvar(self): self.sucess = False if self.logvar.get() == 1: self.var = log10(self.D.__getattribute__(self.myvar)) else: self.var = self.D.__getattribute__(self.myvar) if self.Geom == '1D': self.x = self.D.x1 self.sucess = True else: if self.slicename == "Along x1": self.x = self.D.x1 if self.grid_dict["n3"] == 1: try: int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 cut" else: self.var = self.var[:, int(self.ex2.get())] self.sucess = True else: try: int(self.ex2.get().strip().split()[0]) int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 or x3 cut" else: self.var = self.var[:, int(self.ex2.get()), int(self.ex3.get())] self.sucess = True elif self.slicename == "Along x2": self.x = self.D.x2 if self.grid_dict["n3"] == 1: try: int(self.ex1.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 cut" else: self.var = self.var[int(self.ex1.get()), :] self.sucess = True else: try: int(self.ex1.get().strip().split()[0]) int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 or x3 cut" else: self.var = self.var[int(self.ex1.get()), :, int(self.ex3.get())] self.sucess = True else: self.x = self.D.x3 try: int(self.ex1.get().strip().split()[0]) int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 or x2 cut" else: self.var = self.var[int(self.ex1.get()), int(self.ex2.get()), :] self.sucess = True return self.sucess def getsurfvar(self): self.sucess = False if self.logvar.get() == 1: self.var = log10(self.D.__getattribute__(self.myvar)) else: self.var = self.D.__getattribute__(self.myvar) if self.slicename == "Along x1-x2": self.x = self.D.x1 self.y = self.D.x2 if self.grid_dict["n3"] == 1: self.var = self.var[:, :].T self.sucess = True else: try: int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x3 cut" else: self.var = self.var[:, :, int(self.ex3.get())].T self.sucess = True elif self.slicename == "Along x2-x3": self.x = self.D.x2 self.y = self.D.x3 try: int(self.ex1.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x1 cut" else: self.var = self.var[int(self.ex1.get()), :, :].T self.sucess = True else: self.x = self.D.x1 self.y = self.D.x3 try: int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 cut" else: self.var = self.var[:, int(self.ex2.get()), :].T self.sucess = True return self.sucess def drawpolar(self): self.sucess = False if self.slicename == "Along x1-x2": if self.grid_dict["n3"] == 1: self.R, self.Z, self.SphData = self.I.getSphData( self.D, w_dir=self.wdir, rphi=False) self.sucess = True else: try: int(self.ex3.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x3 cut" else: self.R, self.Z, self.SphData = self.I.getSphData( self.D, w_dir=self.wdir, rphi=False, x3cut=int(self.ex3.get())) self.sucess = True if self.slicename == "Along x3-x1": try: int(self.ex2.get().strip().split()[0]) except (ValueError, IndexError): print "Specify the value of x2 cut" else: self.R, self.Z, self.SphData = self.I.getSphData( self.D, w_dir=self.wdir, rphi=True, x2cut=int(self.ex2.get())) self.sucess = True if self.sucess == True: self.extent = (min(self.R.flat), max(self.R.flat), min(self.Z.flat), max(self.Z.flat)) self.dRR = max(self.R.flat) - min(self.R.flat) self.dZZ = max(self.Z.flat) - min(self.Z.flat) self.isnotnan = -isnan(self.SphData[self.myvar]) self.maxPl = max(self.SphData[self.myvar][self.isnotnan].flat) self.minPl = min(self.SphData[self.myvar][self.isnotnan].flat) self.normrange = False if self.minPl < 0: self.normrange = True if self.maxPl > -self.minPl: self.minPl = -self.maxPl else: self.maxPl = -self.minPl if (self.normrange and self.myvar != 'rho' and self.myvar != 'pr'): self.SphData[self.myvar][-1][-1] = self.maxPl self.SphData[self.myvar][-1][-2] = self.minPl if self.logvar.get() == 1: self.SphData[self.myvar] = log10(self.SphData[self.myvar]) return self.sucess def drawcontour(self): if self.polarvar.get() != 1: if self.slicename == "Along x1-x2": self.xcont = self.D.x1 self.ycont = self.D.x2 self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T, self.D.x2.T) if self.grid_dict["n3"] == 1: if self.plcont.get() == 'x1*A3': self.varcont = self.Xmesh * (self.D.A3.T) elif self.plcont.get() == 'x1*b3': self.varcont = self.Xmesh * (self.D.b3.T) else: self.varcont = self.D.__getattribute__( self.plcont.get())[:, :].T else: if self.plcont.get() == 'x1*A3': self.varcont = self.Xmesh * ( self.D.A3[:, :, int(self.ex3.get())].T) elif self.plcont.get() == 'x1*b3': self.varcont = self.Xmesh * ( self.D.b3[:, :, int(self.ex3.get())].T) else: self.varcont = self.D.__getattribute__( self.plcont.get())[:, :, int(self.ex3.get())].T elif self.slicename == "Along x2-x3": self.xcont = self.D.x2 self.ycont = self.D.x3 self.varcont = self.D.__getattribute__( self.plcont.get())[int(self.ex1.get()), :, :].T else: self.xcont = self.D.x1 self.ycont = self.D.x3 self.varcont = self.D.__getattribute__( self.plcont.get())[:, int(self.ex2.get()), :].T else: self.xcont = self.R self.ycont = self.Z if self.plcont.get() == 'x1*A3': self.varcont = self.R * (self.SphData['A3']) elif self.plcont.get() == 'x1*b3': self.varcont = self.R * (self.SphData['b3']) else: if self.logvar.get() == 1 and self.plcont.get() == self.myvar: self.varcont = 10**(self.SphData[self.plcont.get()]) else: self.varcont = self.SphData[self.plcont.get()] def drawarrow(self): if self.polarvar.get() != 1: if self.slicename == "Along x1-x2": self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T, self.D.x2.T) self.xcong = self.Tool.congrid(self.Xmesh, 2 * (int(self.arrspb.get()), ), method='linear') self.ycong = self.Tool.congrid(self.Ymesh, 2 * (int(self.arrspb.get()), ), method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm': if self.grid_dict["n3"] == 1: self.vel1 = self.D.v1[:, :].T self.vel2 = self.D.v2[:, :].T else: self.vel1 = self.D.v1[:, :, int(self.ex3.get())].T self.vel2 = self.D.v2[:, :, int(self.ex3.get())].T self.xveccong = self.Tool.congrid( self.vel1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid( self.vel2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm': if self.grid_dict["n3"] == 1: self.mag1 = self.D.b1[:, :].T self.mag2 = self.D.b2[:, :].T else: self.mag1 = self.D.b1[:, :, int(self.ex3.get())].T self.mag2 = self.D.b2[:, :, int(self.ex3.get())].T self.xveccong = self.Tool.congrid( self.mag1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid( self.mag2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp elif self.slicename == "Along x2-x3": self.Xmesh, self.Ymesh = meshgrid(self.D.x2.T, self.D.x3.T) self.xcong = self.Tool.congrid(self.Xmesh, 2 * (int(self.arrspb.get()), ), method='linear') self.ycong = self.Tool.congrid(self.Ymesh, 2 * (int(self.arrspb.get()), ), method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm': self.vel1 = self.D.v2[int(self.ex1.get()), :, :].T self.vel2 = self.D.v3[int(self.ex1.get()), :, :].T self.xveccong = self.Tool.congrid( self.vel1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid( self.vel2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm': self.mag1 = self.D.b2[int(self.ex1.get()), :, :].T self.mag2 = self.D.b3[int(self.ex1.get()), :, :].T self.xveccong = self.Tool.congrid( self.mag1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid( self.mag2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp else: self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T, self.D.x3.T) self.xcong = self.Tool.congrid(self.Xmesh, 2 * (int(self.arrspb.get()), ), method='linear') self.ycong = self.Tool.congrid(self.Ymesh, 2 * (int(self.arrspb.get()), ), method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm': self.vel1 = self.D.v1[:, int(self.ex2.get()), :].T self.vel2 = self.D.v3[:, int(self.ex2.get()), :].T self.xveccong = self.Tool.congrid( self.vel1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid( self.vel2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm': self.mag1 = self.D.b1[:, int(self.ex2.get()), :].T self.mag2 = self.D.b3[:, int(self.ex2.get()), :].T self.xveccong = self.Tool.congrid( self.mag1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid( self.mag2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp else: self.xcong = self.Tool.congrid(self.R, 2 * (int(self.arrspb.get()), ), method='linear') self.ycong = self.Tool.congrid(self.Z, 2 * (int(self.arrspb.get()), ), method='linear') if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm': if self.slicename == "Along x1-x2": self.vel1 = self.SphData['v1c'] self.vel2 = self.SphData['v2c'] else: self.vel1 = self.SphData['v1c'] self.vel2 = self.SphData['v3c'] self.xveccong = self.Tool.congrid(self.vel1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid(self.vel2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Vp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm': if self.slicename == "Along x1-x2": self.mag1 = self.SphData['b1c'] self.mag2 = self.SphData['b2c'] else: self.mag1 = self.SphData['b1c'] self.mag2 = self.SphData['b3c'] self.xveccong = self.Tool.congrid(self.mag1, 2 * (int(self.arrspb.get()), ), method='linear') self.yveccong = self.Tool.congrid(self.mag2, 2 * (int(self.arrspb.get()), ), method='linear') self.normVp = sqrt(self.xveccong**2 + self.yveccong**2) if self.plarr.get() == 'Bp_norm': self.xveccong = self.xveccong / self.normVp self.yveccong = self.yveccong / self.normVp def epssave(self): self.f.savefig(self.myvar + '_' + self.enstep.get() + '.eps') def pngsave(self): self.f.savefig(self.myvar + '_' + self.enstep.get() + '.png') def pdfsave(self): self.f.savefig(self.myvar + '_' + self.enstep.get() + '.pdf') def jpgsave(self): self.f.savefig(self.myvar + '_' + self.enstep.get() + '.jpg')
def plot_on_map(self, param='Speed (OBD)', detail=1, cmap='hot'): """@deprecated Plots a trace parameter on a map.""" lats, lngs = self.df['Latitude'], self.df['Longitude'] # plot longitude vs latitude using speed as color track_bounds = Pin(np.min(lats), np.min(lngs)), Pin(np.max(lats), np.max(lngs)) track_center = Pin(np.median(lats), np.median(lngs)) fig = Figure() # create new figure outside pyplot # A canvas must be manually attached to the figure (pyplot would automatically # do it). This is done by instantiating the canvas with the figure as # argument. FigureCanvas(fig) ax = fig.add_subplot(111) # ax.set_aspect('equal') # plot the trace as latitude, longitude scatter with 'param' as color colors = self.df[param] # .values self.df.plot(kind='scatter', x='Longitude', y='Latitude', ax=ax, c=colors, cmap=cmap) # delete the colorbar created by dataframe.plot if len(fig.axes) > 1: fig.delaxes(fig.axes[-1]) # delete the last one # save limits and use them to get a map xlim = ax.get_xlim() ylim = ax.get_ylim() width = np.ptp(xlim) height = np.ptp(ylim) self.aspect = height / width # fig.set_dpi(100) screen_width = 15. size = (screen_width, screen_width * self.aspect) fig.set_size_inches(size) # make lat, lng pins for bounds to get_bounded_map # get a map matching the bounds of the plot sw = Pin(ylim[0], xlim[0]) ne = Pin(ylim[1], xlim[1]) bounds = (sw, ne) mapfield = Mapfield(bounds=bounds, detail=detail) mapimage = mapfield.image ext = *xlim, *ylim # left, right, bottom, top ax.imshow(mapimage, zorder=0, extent=ext, aspect='auto', interpolation='bicubic') # plt.axis('off') return fig
class NumberTracing(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent, *args, **kwargs) self.parent = parent #Variables for ROIframe self.varX1 = tk.StringVar() self.varY1 = tk.StringVar() self.varX2 = tk.StringVar() self.varY2 = tk.StringVar() self.varX1.set("0") self.varY1.set("0") self.varX2.set("0") self.varY2.set("0") #Variables for the tesseract loop self.values = [] self.times = [] self.running = False self.idle = tk.DoubleVar() self.idle.set(1.0) self.i = 0 self.memory = numpy.nan self.latestDiff = 0. self.shortMem = [] #Frames self.left = tk.Frame(self.parent, borderwidth=1, relief="solid") self.right = tk.Frame(self.parent, borderwidth=1, relief="solid") self.righttop = tk.Frame(self.right, borderwidth=1, relief="solid") self.rightmiddle = tk.Frame(self.right, borderwidth=1, relief="solid") self.rightbottom = tk.Frame(self.right, borderwidth=1, relief="solid") #Labels self.delimiterL = tk.Label(self.rightmiddle, text="Delimiter:") self.idleL = tk.Label(self.rightmiddle, text="Time delay:") #Buttons ROIb = tk.Button(self.righttop, text="Define ROI", command=lambda: self.start_klickYourROI(None)) saveROIb = tk.Button(self.righttop, text="Save ROI", command=lambda: self.start_saveROI(None)) loadROIb = tk.Button(self.righttop, text="Load ROI", command=lambda: self.start_loadROI(None)) runb = tk.Button(self.rightmiddle, text="Start", bg="LightBlue1", command=lambda: self.start_run(None)) stopb = tk.Button(self.rightmiddle, text="Stop", bg="orange2", command=lambda: self.start_stop(None)) clearb = tk.Button(self.rightmiddle, text="Clear", command=lambda: self.start_clear(None)) lastminb = tk.Button(self.rightmiddle, text="Last Minute", command=lambda: self.start_lastminute(None)) saveb = tk.Button(self.rightmiddle, text="Save Graph", command=lambda: self.start_savegraph(None)) #Entry fields self.delimiterE = tk.Entry(master=self.rightmiddle) self.idleE = tk.Entry(master=self.rightmiddle) #Figures self.fig = Figure(figsize=(2, 1)) self.canvas = FigureCanvasTkAgg(self.fig, master=self.rightbottom) self.figleft = Figure(figsize=(6, 2)) self.canvasleft = FigureCanvasTkAgg(self.figleft, master=self.left) #Opening image image = cv2.imread("dogwithfish.jpg") image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) self.subfleft = self.figleft.add_subplot(111) self.subfleft.axis('off') self.subfleft.imshow(image) #Checkboxes self.difference = tk.IntVar() self.totalordifferenceCB = tk.Checkbutton(self.rightmiddle, text="Difference?", variable=self.difference) #Packing it all self.left.pack(side="left", expand=True, fill="both") self.right.pack(side="right", expand=True, fill="both") self.righttop.pack(side="top", expand=True, fill="both") self.rightbottom.pack(side="bottom", expand=True, fill="both") self.rightmiddle.pack(side="bottom", expand=True, fill="both") self.canvas.get_tk_widget().pack(fill="both", expand=True) self.canvasleft.get_tk_widget().pack(fill="both", expand=True) ROIb.pack(fill=tk.X, padx=2, pady=2) saveROIb.pack(fill=tk.X, padx=2, pady=2) loadROIb.pack(fill=tk.X, padx=2, pady=2) self.delimiterL.pack(fill=tk.X, padx=2, pady=2) self.delimiterE.pack(fill=tk.X, padx=2, pady=2) self.idleL.pack(fill=tk.X, padx=2, pady=2) self.idleE.pack(fill=tk.X, padx=2, pady=2) runb.pack(fill=tk.X, padx=2, pady=2) stopb.pack(fill=tk.X, padx=2, pady=2) clearb.pack(fill=tk.X, padx=2, pady=2) lastminb.pack(fill=tk.X, padx=2, pady=2) self.totalordifferenceCB.pack(fill=tk.X, padx=2, pady=2) saveb.pack(fill=tk.X, padx=2, pady=2) #Functions def queryMousePosition(self): pt = POINT() windll.user32.GetCursorPos(byref(pt)) return pt.x, pt.y #Button Functions def klickYourROI(self): klicksdone = 0 state_left = win32api.GetKeyState(0x01) print("Klick upper left!") while klicksdone < 1: a = win32api.GetKeyState(0x01) if a != state_left: # Button state changed state_left = a if a < 0: print(' ') else: #print('Left Button Released1') x1, y1 = self.queryMousePosition() klicksdone = 1 print("Klick lower right!") while klicksdone < 2: a = win32api.GetKeyState(0x01) if a != state_left: # Button state changed state_left = a if a < 0: print(' ') else: #print('Left Button Released2') x2, y2 = self.queryMousePosition() klicksdone = 2 self.varX1.set(str(x1)) self.varY1.set(str(y1)) self.varX2.set(str(x2)) self.varY2.set(str(y2)) self.parent.update_idletasks() print(x1, y1, x2, y2) return 0 def start_klickYourROI(self, event): global ROI_thread ROI_thread = threading.Thread(target=self.klickYourROI) ROI_thread.deamon = True ROI_thread.start() def saveROI(self): with open("ROI.txt", "w") as ROIfile: ROIfile.write("{}\n{}\n{}\n{}".format(self.varX1.get(), self.varY1.get(), self.varX2.get(), self.varY2.get())) def start_saveROI(self, event): self.saveROI() def loadROI(self): with open("ROI.txt", "r") as ROIfile: data = ROIfile.read().splitlines() self.varX1.set(data[0]) self.varY1.set(data[1]) self.varX2.set(data[2]) self.varY2.set(data[3]) image = PIL.ImageGrab.grab(bbox=(int(self.varX1.get()), int(self.varY1.get()), int(self.varX2.get()), int(self.varY2.get()))) subf = self.fig.add_subplot(111) subf.clear() subf.axis('off') subf.imshow(image) self.canvas.draw() def start_loadROI(self, event): self.loadROI() def stop(self): self.running = False print("Stopped!") def start_stop(self, event): self.stop() def run(self): print("Running!") T = float(self.idleE.get()) print(T) splitting = True delimiter = self.delimiterE.get() if delimiter == "": splitting = False print(delimiter) if self.difference.get() == 1: mode = "Difference" else: mode = "Total" #while self.running == True: startt = time.time() image = PIL.ImageGrab.grab(bbox=(int(self.varX1.get()), int(self.varY1.get()), int(self.varX2.get()), int(self.varY2.get()))) subf = self.fig.add_subplot(111) subf.clear() subf.axis('off') subf.imshow(image) self.canvas.draw() opencvImage = cv2.cvtColor(numpy.array(image), cv2.COLOR_BGR2GRAY) #use tesseract to read the numbers from the chosen frame results = tes.image_to_string(opencvImage) results = mergeInCaseOfSplitted(results) results = results.replace(" ", "") if splitting == True: try: splitresults = results.split( delimiter ) #Split the string at the commata and match together number = "" for j in range(len(splitresults)): number += splitresults[j] print(splitresults, number, self.i) number = float(number) except: #Problem with the splitting print("Result is not float!") number = numpy.nan else: print(results) try: number = float(results) print(number) except: number = numpy.nan print("Result is not float!") #Append Values to arrays and check for potential problems self.times.append(int(self.i) * T) if mode == "Difference": print("Mode is Difference!") try: if self.i < 2: #for the first number there is no earlier number, so set to NaN self.shortMem.append(number) self.values.append(numpy.nan) self.memory = numpy.nan if self.i == 1: self.latestDiff = self.shortMem[1] - self.shortMem[0] else: if number - self.memory < 0.0001: #adjust for display and screenshot not synched (python too fast) self.values.append(self.latestDiff) else: self.latestDiff = number - self.memory #if everything is fine just add the difference between current and last self.values.append(self.latestDiff) except Exception as e: #add NaN if anything goes wrong self.values.append(numpy.nan) print(e) try: self.memory = number except: self.memory = numpy.nan print("Memory = {}".format(self.memory)) if mode == "Total": print("Mode is Total!") try: if self.i < 1: #for the first number there is no earlier number, so set to NaN self.values.append(numpy.nan) else: self.values.append(number) except: #add NaN if anything goes wrong self.values.append(numpy.nan) self.figleft.delaxes(self.subfleft) self.subfleft = self.figleft.add_subplot(111) self.subfleft.clear() self.subfleft.set_title("Behaviour of Variable") self.subfleft.set_xlabel("Time [s]") self.subfleft.set_ylabel("Value") self.subfleft.plot(numpy.array(self.times), numpy.array(self.values)) self.subfleft.grid() self.canvasleft.draw() endt = time.time() diff = endt - startt print(diff) print(T) print(threading.active_count()) try: time.sleep(T - diff) except Exception as e: print(e) print("Issue with time delay.") self.i += 1 if self.running == True: self.after(1, self.run) def start_run(self, event): self.running = True self.run() def clear(self): self.times = [] self.values = [] self.i = 0 subfleft = self.figleft.add_subplot(111) subfleft.clear() def start_clear(self, event): self.clear() def lastminute(self): #Calculate how many indicees have to be cut off to get one minute: #Number of indicees is 60 seconds devided by the repetition rate T indicees = int(60. / float(self.idleE.get())) self.times = self.times[-1 * indicees:-1] self.values = self.values[-1 * indicees:-1] def start_lastminute(self, event): self.lastminute() def savegraph(self): f = open('countsOverTime.txt', 'w') for j in range(len(self.values)): f.write(str(self.times[j]) + '\t' + str(self.values[j]) + '\n') f.close() def start_savegraph(self, event): self.savegraph()
class TimelineFrame(wx.Frame): """The main frame of the application""" def __init__(self, parent): wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=_("GRASS GIS Timeline Tool")) tgis.init(True) self.datasets = [] self.timeData = {} self._layout() self.temporalType = None self.unit = None # We create a database interface here to speedup the GUI self.dbif = tgis.SQLDatabaseInterfaceConnection() self.dbif.connect() self.Bind(wx.EVT_CLOSE, self.OnClose) def OnClose(self, event): """Close the database interface and stop the messenger and C-interface subprocesses. """ if self.dbif.connected is True: self.dbif.close() tgis.stop_subprocesses() self.Destroy() def _layout(self): """Creates the main panel with all the controls on it: * mpl canvas * mpl navigation toolbar * Control panel for interaction """ self.panel = wx.Panel(self) # Create the mpl Figure and FigCanvas objects. # 5x4 inches, 100 dots-per-inch # # color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND) self.fig = Figure((5.0, 4.0), facecolor=(1, 1, 1)) self.canvas = FigCanvas(self.panel, wx.ID_ANY, self.fig) # axes are initialized later self.axes2d = None self.axes3d = None # Create the navigation toolbar, tied to the canvas # self.toolbar = NavigationToolbar(self.canvas) # # Layout # self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND) self.vbox.Add(self.toolbar, 0, wx.EXPAND) self.vbox.AddSpacer(10) gridSizer = wx.GridBagSizer(hgap=5, vgap=5) self.datasetSelect = gselect.Select(parent=self.panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE, type='stds', multiple=True) self.drawButton = Button(self.panel, id=wx.ID_ANY, label=_("Draw")) self.drawButton.Bind(wx.EVT_BUTTON, self.OnRedraw) self.helpButton = Button(self.panel, id=wx.ID_ANY, label=_("Help")) self.helpButton.Bind(wx.EVT_BUTTON, self.OnHelp) self.view3dCheck = wx.CheckBox( self.panel, id=wx.ID_ANY, label=_("3D plot of spatio-temporal extents")) self.view3dCheck.Bind(wx.EVT_CHECKBOX, self.OnRedraw) if not check_version(1, 0, 0): self.view3dCheck.SetLabel( _("3D plot of spatio-temporal extents " "(matplotlib >= 1.0.0)")) self.view3dCheck.Disable() gridSizer.Add(StaticText(self.panel, id=wx.ID_ANY, label=_("Select space time dataset(s):")), pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) gridSizer.Add(self.datasetSelect, pos=(1, 0), flag=wx.EXPAND) gridSizer.Add(self.drawButton, pos=(1, 1), flag=wx.EXPAND) gridSizer.Add(self.helpButton, pos=(1, 2), flag=wx.EXPAND) gridSizer.Add(self.view3dCheck, pos=(2, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) self.vbox.Add(gridSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=10) self.panel.SetSizer(self.vbox) self.vbox.Fit(self) def _getData(self, timeseries): """Load data and read properties""" self.timeData = {} mode = None unit = None for series in timeseries: name = series[0] + '@' + series[1] etype = series[2] sp = tgis.dataset_factory(etype, name) if not sp.is_in_db(dbif=self.dbif): GError( self, message=_("Dataset <%s> not found in temporal database") % (name)) return sp.select(dbif=self.dbif) self.timeData[name] = {} self.timeData[name]['elementType'] = series[2] self.timeData[name]['temporalType'] = sp.get_temporal_type( ) # abs/rel if mode is None: mode = self.timeData[name]['temporalType'] elif self.timeData[name]['temporalType'] != mode: GError(parent=self, message=_( "Datasets have different temporal type " "(absolute x relative), which is not allowed.")) return # check topology maps = sp.get_registered_maps_as_objects(dbif=self.dbif) self.timeData[name]['validTopology'] = sp.check_temporal_topology( maps=maps, dbif=self.dbif) self.timeData[name]['temporalMapType'] = sp.get_map_time( ) # point/interval self.timeData[name]['unit'] = None # only with relative if self.timeData[name]['temporalType'] == 'relative': start, end, self.timeData[name]['unit'] = sp.get_relative_time( ) if unit is None: unit = self.timeData[name]['unit'] elif self.timeData[name]['unit'] != unit: GError( self, _("Datasets have different time unit which is not allowed." )) return self.timeData[name]['start_datetime'] = [] # self.timeData[name]['start_plot'] = [] self.timeData[name]['end_datetime'] = [] # self.timeData[name]['end_plot'] = [] self.timeData[name]['names'] = [] self.timeData[name]['north'] = [] self.timeData[name]['south'] = [] self.timeData[name]['west'] = [] self.timeData[name]['east'] = [] columns = ','.join([ 'name', 'start_time', 'end_time', 'north', 'south', 'west', 'east' ]) rows = sp.get_registered_maps(columns=columns, where=None, order='start_time', dbif=self.dbif) if not rows: GError(parent=self, message=_("Dataset <{name}> is empty").format( name=series[0] + '@' + series[1])) return for row in rows: mapName, start, end, north, south, west, east = row self.timeData[name]['start_datetime'].append(start) self.timeData[name]['end_datetime'].append(end) self.timeData[name]['names'].append(mapName) self.timeData[name]['north'].append(north) self.timeData[name]['south'].append(south) self.timeData[name]['west'].append(west) self.timeData[name]['east'].append(east) self.temporalType = mode self.unit = unit def _draw3dFigure(self): """Draws 3d view (spatio-temporal extents). Only for matplotlib versions >= 1.0.0. Earlier versions cannot draw time ticks and alpha and it has a slightly different API. """ self.axes3d.clear() self.axes3d.grid(False) # self.axes3d.grid(True) if self.temporalType == 'absolute': convert = mdates.date2num else: convert = lambda x: x colors = cycle(COLORS) plots = [] for name in self.datasets: name = name[0] + '@' + name[1] startZ = convert(self.timeData[name]['start_datetime']) mapType = self.timeData[name]['temporalMapType'] if mapType == 'interval': dZ = convert(self.timeData[name]['end_datetime']) - startZ else: dZ = [0] * len(startZ) startX = self.timeData[name]['west'] dX = self.timeData[name]['east'] - np.array(startX) startY = self.timeData[name]['south'] dY = self.timeData[name]['north'] - np.array(startY) color = next(colors) plots.append( self.axes3d.bar3d(startX, startY, startZ, dX, dY, dZ, color=color, alpha=ALPHA)) params = grass.read_command('g.proj', flags='g') params = grass.parse_key_val(params) if 'unit' in params: self.axes3d.set_xlabel(_("X [%s]") % params['unit']) self.axes3d.set_ylabel(_("Y [%s]") % params['unit']) else: self.axes3d.set_xlabel(_("X")) self.axes3d.set_ylabel(_("Y")) if self.temporalType == 'absolute': if check_version(1, 1, 0): self.axes3d.zaxis_date() self.axes3d.set_zlabel(_('Time')) self.axes3d.mouse_init() self.canvas.draw() def _draw2dFigure(self): """Draws 2D plot (temporal extents)""" self.axes2d.clear() self.axes2d.grid(True) if self.temporalType == 'absolute': convert = mdates.date2num else: convert = lambda x: x colors = cycle(COLORS) yticksNames = [] yticksPos = [] plots = [] lookUp = LookUp(self.timeData) for i, name in enumerate(self.datasets): # just name; with mapset it would be long yticksNames.append(name[0]) name = name[0] + '@' + name[1] yticksPos.append(i) barData = [] pointData = [] mapType = self.timeData[name]['temporalMapType'] start = convert(self.timeData[name]['start_datetime']) # TODO: mixed if mapType == 'interval': end = convert(self.timeData[name]['end_datetime']) lookUpData = list(zip(start, end)) duration = end - np.array(start) barData = list(zip(start, duration)) lookUp.AddDataset(type_='bar', yrange=(i - 0.1, i + 0.1), xranges=lookUpData, datasetName=name) else: # self.timeData[name]['end_plot'] = None pointData = start lookUp.AddDataset(type_='point', yrange=i, xranges=pointData, datasetName=name) color = next(colors) if mapType == 'interval': plots.append( self.axes2d.broken_barh(xranges=barData, yrange=(i - 0.1, 0.2), facecolors=color, edgecolor='black', alpha=ALPHA)) else: plots.append( self.axes2d.plot(pointData, [i] * len(pointData), marker='o', linestyle='None', color=color)[0]) if self.temporalType == 'absolute': self.axes2d.xaxis_date() self.fig.autofmt_xdate() # self.axes2d.set_xlabel(_("Time")) else: self.axes2d.set_xlabel(_("Time [%s]") % self.unit) self.axes2d.set_yticks(yticksPos) self.axes2d.set_yticklabels(yticksNames) self.axes2d.set_ylim(min(yticksPos) - 1, max(yticksPos) + 1) # adjust xlim xlim = self.axes2d.get_xlim() padding = ceil((xlim[1] - xlim[0]) / 20.) self.axes2d.set_xlim(xlim[0] - padding, xlim[1] + padding) self.axes2d.set_axisbelow(True) self.canvas.draw() DataCursor(plots, lookUp, InfoFormat) def OnRedraw(self, event): """Required redrawing.""" datasets = self.datasetSelect.GetValue().strip() if not datasets: return datasets = datasets.split(',') try: datasets = self._checkDatasets(datasets) if not datasets: return except GException as e: GError(parent=self, message=unicode(e), showTraceback=False) return self.datasets = datasets self._redraw() def _redraw(self): """Readraw data. Decides if to draw also 3D and adjusts layout if needed. """ self._getData(self.datasets) # axes3d are physically removed if not self.axes2d: self.axes2d = self.fig.add_subplot(1, 1, 1) self._draw2dFigure() if check_version(1, 0, 0): if self.view3dCheck.IsChecked(): self.axes2d.change_geometry(2, 1, 1) if not self.axes3d: # do not remove this import - unused but it is required for # 3D from mpl_toolkits.mplot3d import Axes3D # pylint: disable=W0611 self.axes3d = self.fig.add_subplot(2, 1, 2, projection='3d') self.axes3d.set_visible(True) self._draw3dFigure() else: if self.axes3d: self.fig.delaxes(self.axes3d) self.axes3d = None self.axes2d.change_geometry(1, 1, 1) self.canvas.draw() def _checkDatasets(self, datasets): """Checks and validates datasets. Reports also type of dataset (e.g. 'strds'). :return: (mapName, mapset, type) """ validated = [] tDict = tgis.tlist_grouped('stds', group_type=True, dbif=self.dbif) # nested list with '(map, mapset, etype)' items allDatasets = [[[(map, mapset, etype) for map in maps] for etype, maps in six.iteritems(etypesDict)] for mapset, etypesDict in six.iteritems(tDict)] # flatten this list if allDatasets: allDatasets = reduce(lambda x, y: x + y, reduce(lambda x, y: x + y, allDatasets)) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() allDatasets = [ i for i in sorted(allDatasets, key=lambda l: mapsets.index(l[1])) ] for dataset in datasets: errorMsg = _("Space time dataset <%s> not found.") % dataset if dataset.find("@") >= 0: nameShort, mapset = dataset.split('@', 1) indices = [ n for n, (mapName, mapsetName, etype) in enumerate(allDatasets) if nameShort == mapName and mapsetName == mapset ] else: indices = [ n for n, (mapName, mapset, etype) in enumerate(allDatasets) if dataset == mapName ] if len(indices) == 0: raise GException(errorMsg) elif len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, message=_("Please specify the space time dataset <%s>." % dataset), caption=_("Ambiguous dataset name"), choices=[("%(map)s@%(mapset)s: %(etype)s" % { 'map': allDatasets[i][0], 'mapset': allDatasets[i][1], 'etype': allDatasets[i][2] }) for i in indices], style=wx.CHOICEDLG_STYLE | wx.OK) if dlg.ShowModal() == wx.ID_OK: index = dlg.GetSelection() validated.append(allDatasets[indices[index]]) else: continue else: validated.append(allDatasets[indices[0]]) return validated def OnHelp(self, event): RunCommand('g.manual', quiet=True, entry='g.gui.timeline') # interface def SetDatasets(self, datasets): """Set data""" if not datasets: return try: datasets = self._checkDatasets(datasets) if not datasets: return except GException as e: GError(parent=self, message=unicode(e), showTraceback=False) return self.datasets = datasets self.datasetSelect.SetValue(','.join( map(lambda x: x[0] + '@' + x[1], datasets))) self._redraw() def Show3D(self, show): """Show also 3D if possible""" if check_version(1, 0, 0): self.view3dCheck.SetValue(show)
class PltWidget(tk.Frame): def __init__(self, parent): # inheritance tk.Frame.__init__(self, parent) self.parent = parent # figure init self.fig = Figure(figsize=FIG_SIZE) self.ax = self.fig.gca() # a tk.DrawingArea self.canvas = FigureCanvasTkAgg(self.fig, master=self) self.canvas.draw() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) toolbar = NavigationToolbar2Tk(self.canvas, self) toolbar.update() toolbar.pack(side=tk.BOTTOM) toolbar.home() # toggle refo/tria button dep_btn = tk.Button(master=self, text='refo/tria toggle', width=BTN_W, command=self.toggle_dep_type) dep_btn.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) # toggle 2D/3D button dim_btn = tk.Button(master=self, text='2D/3D toggle', width=BTN_W, command=self.toggle_dim_type) dim_btn.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1) # default toggle settings self.dep_type = False self.dim_type = True def refresh(self): ''' update window ''' self.ax.clear() if self.dim_type: if self.dep_type: self.ax = self.parent.obj.plt_tria(self.ax) else: self.ax = self.parent.obj.plt_refo(self.ax) else: amin = self.parent.obj.dx if self.dep_type else self.parent.obj.a self.ax = self.parent.obj.plt_3d(self.ax, amin=amin, dep_type=self.dep_type) self.canvas.draw() @staticmethod def xor(a, b): return bool(a) != bool(b) def toggle_dep_type(self): self.dep_type = self.xor(self.dep_type, 1) self.refresh() def toggle_dim_type(self): self.dim_type = self.xor(self.dim_type, 1) self.change_dim_type() self.refresh() def change_dim_type(self): self.fig.delaxes(self.ax) if self.dim_type: self.fig.set_size_inches(FIG_SIZE, forward=True) self.ax = self.fig.gca() else: self.ax = Axes3D(self.fig) self.parent.obj.plt_3d_init(self.fig, self.ax)
class MplCanvas(FigureCanvasQTAgg, customthreads.StoppableThread): def __init__(self, xlim=None, ylim=None, channel=1, x_range=None, parent=None, post_process=None, width=5, height=4, dpi=100, *args, **kwargs): customthreads.StoppableThread.__init__(self, *args, **kwargs) self.lock = Lock() self.in_queue = queue.Queue() self.xlim = xlim self.ylim = ylim self.x_range = x_range if(self.x_range is None): self.x_range = range(self.xlim[0], self.xlim[1]) self.fig = Figure(figsize=(width, height), dpi=dpi) FigureCanvasQTAgg.__init__(self, self.fig) FigureCanvasQTAgg.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) FigureCanvasQTAgg.updateGeometry(self) self.axes_list = [] self.setParent(parent) self.set_channel(channel) self.post_process = post_process if(self.post_process is None): self.post_process = lambda data: data def set_channel(self, channel): self.lock.acquire() self.channel = channel '''clear subplots''' if(self.axes_list is not []): for ax in self.axes_list: self.fig.delaxes(ax) self.axes_list = [] for i in range(1, self.channel+1): self.axes_list.append(self.fig.add_subplot(self.channel, 1, i)) self.axes_list[i-1].hold(False) self.lock.release() def run(self): print(self.x_range) while(self.is_stopped() is False): try: data = self.in_queue.get_nowait() split_data = ast.split_channel(data, self.channel) p_split_data = [self.post_process(sd) for sd in split_data] self.lock.acquire() for i in range(self.channel): self.axes_list[i].plot(self.x_range, p_split_data[i], 'b') self.axes_list[i].set_xlim(self.xlim) self.axes_list[i].set_ylim(self.ylim) self.draw() self.lock.release() except queue.Empty: pass
class TransformEditor(QtGui.QMainWindow): """GUI to edit transformations. .. warning:: Note that this module requires PyQt4. Parameters ---------- transform_manager : TransformManager All nodes that are reachable from the base frame will be editable frame : string Name of the base frame xlim : tuple, optional (-1, 1) Lower and upper limit for the x position. Defines the range of the plot and the range of the slider. ylim : tuple, optional (-1, 1) Lower and upper limit for the y position. Defines the range of the plot and the range of the slider. zlim : tuple, optional (-1, 1) Lower and upper limit for the z position. Defines the range of the plot and the range of the slider. s : float, optional (default: 1) Scaling of the axis and angle that will be drawn figsize : tuple of integers, optional (default: (10, 10)) Width, height in inches. dpi : integer, optional (default: 100) Resolution of the figure. parent : QtGui.QWidget, optional (default: None) Parent widget. Attributes ---------- transform_manager : TransformManager Result, all frames are expressed in the base frame """ def __init__(self, transform_manager, base_frame, xlim=(-1.0, 1.0), ylim=(-1.0, 1.0), zlim=(-1.0, 1.0), s=1.0, figsize=(10, 10), dpi=100, window_size=(500, 600), parent=None): self.app = QtGui.QApplication(sys.argv) super(TransformEditor, self).__init__(parent) self.transform_manager = self._init_transform_manager( transform_manager, base_frame) self.base_frame = base_frame self.xlim = xlim self.ylim = ylim self.zlim = zlim self.s = s self.figsize = figsize self.dpi = dpi self.window_size = window_size self.setWindowTitle("Transformation Editor") self.axis = None self._create_main_frame() self._on_node_changed([ node for node in self.transform_manager.nodes if node != self.base_frame ][0]) def _init_transform_manager(self, transform_manager, frame): """Transform all nodes into the reference frame.""" tm = TransformManager() if frame not in transform_manager.nodes: raise KeyError("Unknown frame '%s'" % frame) for node in transform_manager.nodes: try: node2frame = transform_manager.get_transform(node, frame) tm.add_transform(node, frame, node2frame) except KeyError: pass # Frame is not connected to the reference frame return tm def _create_main_frame(self): """Create main frame and layout.""" self.main_frame = QtGui.QWidget() self.frame_editor = PositionEulerEditor(self.base_frame, self.xlim, self.ylim, self.zlim) self.connect(self.frame_editor, QtCore.SIGNAL("frameChanged()"), self._on_update) frame_selection = self._create_frame_selector() plot = self._create_plot() vbox = QtGui.QVBoxLayout() vbox.addWidget(self.frame_editor) vbox.addWidget(frame_selection) vbox.addWidget(plot) main_layout = QtGui.QHBoxLayout() main_layout.addLayout(vbox) self.main_frame.setLayout(main_layout) self.setCentralWidget(self.main_frame) self.setGeometry(0, 0, *self.window_size) def _create_frame_selector(self): frame_selection = QtGui.QComboBox() for node in self.transform_manager.nodes: if node != self.base_frame: frame_selection.addItem(node) self.connect(frame_selection, QtCore.SIGNAL("activated(const QString&)"), self._on_node_changed) return frame_selection def _create_plot(self): plot = QtGui.QWidget() canvas_group = QtGui.QGridLayout() self.fig = Figure(self.figsize, dpi=self.dpi) self.fig.subplots_adjust(left=0, right=1, bottom=0, top=1) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.main_frame) canvas_group.addWidget(self.canvas, 1, 0) mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame) canvas_group.addWidget(mpl_toolbar, 2, 0) plot.setLayout(canvas_group) return plot def _on_node_changed(self, node): """Slot: manipulatable node changed.""" self.node = str(node) A2B = self.transform_manager.get_transform(self.node, self.base_frame) self.frame_editor.set_frame(A2B) self._plot() def _on_update(self): """Slot: transformation changed.""" self.transform_manager.add_transform(self.node, self.base_frame, self.frame_editor.A2B) self._plot() def _plot(self): """Draw plot.""" if self.axis is None: elev, azim = 30, 60 else: elev, azim = self.axis.elev, self.axis.azim self.fig.delaxes(self.axis) self.axis = self.fig.add_subplot(111, projection="3d") self.axis.view_init(elev, azim) self.axis.set_xlim(self.xlim) self.axis.set_ylim(self.ylim) self.axis.set_zlim(self.zlim) p = self.transform_manager.get_transform(self.node, self.base_frame)[:3, 3] self.axis.scatter(p[0], p[1], p[2], s=100) self.transform_manager.plot_frames_in(self.base_frame, ax=self.axis, s=self.s) self.canvas.draw() def show(self): """Start GUI.""" super(TransformEditor, self).show() self.app.exec_()
class MatplotlibWidget(FigureCanvas): """ Class handling 1D, 2D, 3D data and displaying them in a canvas as 1D curve graphs, 2D images or multiple 2D images. """ MASK_HIDDEN = 0 MASK_SHOWN = 1 MASK_ONLY = 2 def __init__(self, graphMode=None, parent=None, name=None, width=5, height=4, dpi=100, bgColor=None, valueRange=None, maskLabels=None): """ Create matplotlib 'front-end' widget which can render 1D,2D,3D data as 1D or 2D graphs and handle masks. """ if debug : print '**xndarrayViewRenderer.__init__ ...' self.parent = parent if graphMode: self.graphMode = graphMode else: self.graphMode = viewModes.MODE_2D self.fwidth = width self.fheight = height self.dpi = dpi # Will define the range of the colormap associated to values: if debug: print 'valueRange :', valueRange #valueRange = [0.001, 0.2] #noise var #valueRange = [0.001, 0.5] #noise ARp #valueRange = [0, 11] if valueRange is not None: self.norm = Normalize(valueRange[0], valueRange[1]+_N.abs(valueRange[1])*.01, clip=True) self.backgroundValue = valueRange[0] - 100 else: self.norm = None self.backgroundValue = 0 #? # Define the range of the colormap associated to the mask: # will be used to draw contours of mask self.maskCm = None self.maskLabels = maskLabels if debug: print '######### maskLabels :', maskLabels if maskLabels is not None: _N.random.seed(1) # ensure we get always the same random colors #TODO: put the random seed back in the same state as before!!! rndm = _N.random.rand(len(maskLabels),3) # black: #fixed = _N.zeros((len(maskLabels),3)) + _N.array([0.,0.,0.]) # green: #fixed = _N.zeros((len(maskLabels),3)) + _N.array([0.,1.,0.]) #white: fixed = _N.zeros((len(maskLabels),3)) + _N.array([1.,1.,1.]) # Create uniform colormaps for every mask label # self.maskCm = dict(zip(maskLabels, # [ListedColormap([ tuple(r) ]) for r in rndm])) self.maskCm = dict(zip(maskLabels, [ListedColormap([tuple(r)]) for r in fixed])) self.displayMaskFlag = self.MASK_HIDDEN # Set the color of the widget background if self.parent: bgc = parent.backgroundBrush().color() #bgcolor = float(bgc.red())/255.0, float(bgc.green())/255.0, \ # float(bgc.blue())/255.0 bgcolor = "#%02X%02X%02X" % (bgc.red(), bgc.green(), bgc.blue()) else: bgcolor = 'w' # Create the matplotlib figure: self.fig = Figure(figsize=(width, height), dpi=dpi, facecolor=bgcolor, edgecolor=bgcolor) # Size of the grid of plots: self.subplotsH = 0 self.subplotsW = 0 self.axes = None self.showAxesFlag = True self.showAxesLabels = True # Init the parent Canvas: FigureCanvas.__init__(self, self.fig) # Some QT size stuffs self.reparent(parent, QPoint(0, 0)) FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) # Color bar related stuffs: self.showColorBar = False self.colorBars = None # color associated to position where mask=0 : self.bgColor = 'w'#QColor('white') if bgColor==None else bgColor # Default colormap (~rainbow) : black-blue-green-yellow-red self.colorMapString = '0;0;0.5;0.0;0.75;1.0;1.;1.0#' \ '0;0;0.5;1;0.75;1;1;0.#' \ '0;0;0.25;1;0.5;0;1;0.' self.setColorMapFromString(self.colorMapString) self.update() # Signal stuffs: #self.mpl_connect('button_release_event', self.onRelease) self.mpl_connect('motion_notify_event', self.onMove) self.mpl_connect('button_press_event', self.onClick) def setBackgroundColor(self, color): if type(color) == QColor: self.bgColor = tuple([c/255. for c in color.getRgb()]) else: self.bgColor = color # assume letter code/ hex color string / ... # anything supported by matplotlib.colors #TODO maybe do some checks ? if debug:print 'setting over/under color ', self.bgColor self.colorMap.set_under(color=self.bgColor) self.colorMap.set_over(color=self.bgColor) def sizeHint(self): w = self.fig.get_figwidth() h = self.fig.get_figheight() return QSize(w, h) def getColorMapString(self): return self.colorMapString def setColorMapFromString(self, scm): if debug : print 'MatplotlibWidget.setColorMapFromString' scm = str(scm) if debug : print ' recieved scm:', scm # Make sure we do not have any negative values : subResult = re.subn('(\+[0-9]+(\.\d*)?)','0.',scm) if debug and subResult[1] > 0: print ' !!! found negative values !!!' sys.exit(1) scm = subResult[0] self.colorMapString = scm if debug : print ' negative filtered scm :', scm self.colorMap = cmstring_to_mpl_cmap(scm) # Set colors corresponding to [minval-1 , minval] to background color: self.setBackgroundColor(self.bgColor) def setGraphMode(self, m): if self.graphMode == m: return if debug: print 'xndarrayViewRenderer.setGraphMode:',m self.graphMode = m self.computeFigure() def minimumSizeHint(self): return QSize(100, 100) def setMaskDisplay(self, flag): if self.displayMaskFlag == flag: return self.displayMaskFlag = flag self.resetGraph() self.refreshFigure() def toggleColorbar(self): if debug: print "MatplotlibWidget toggleColorbar..." self.showColorBar = not self.showColorBar if debug: print ' showColorBar = %s' %(['On','Off'][self.showColorBar]) #if not self.showColorBar: self.resetGraph() #self.resetGraph() self.refreshFigure() #self.draw() def hideAxes(self): if not self.showAxesFlag: return self.showAxesFlag = False for ax in self.axes: ax.set_axis_off() self.adjustSubplots() self.draw() def showAxes(self): if self.showAxesFlag: return self.showAxesFlag = True for ax in self.axes: ax.set_axis_on() self.adjustSubplots() self.draw() def toggleAxesLabels(self): self.showAxesLabels = not self.showAxesLabels for a in self.axes: self.plotAxesLabels(a) self.adjustSubplots() self.draw() def setMaskLabel(self, label): if debug: print "MatplotlibWidget setMaskLabel ..." self.maskLabel = label self._applyMask() self.resetGraph() self.refreshFigure() def _applyMask(self): if debug: print "MatplotlibWidget applyMask ..." self.maskedValues = self.values.copy() self.maskedErrors = None if self.errors==None else self.errors.copy() if self.mask != None: if debug: print 'self.maskLabel:', self.maskLabel if self.maskLabel != 0: m = (self.mask != self.maskLabel) else: m = (self.mask == 0) #print 'm :', m if debug: print 'backgroundValue :', self.backgroundValue self.maskedValues[m] = self.backgroundValue if self.errors != None: self.maskedErrors[m] = 0 def updateData(self, cub, mask=None, maskLabel=0, maskName='mask', otherSlices=None): if debug: print "MatplotlibWidget update data ..." print "Got cuboid:" print cub.descrip() if mask is not None: print 'Got mask:', mask.shape print mask # Retrieve data and make everything be 3D-shaped: deltaDims = 3-cub.get_ndims() targetSh = cub.data.shape + (1,) * deltaDims self.domainNames = cub.axes_names + [None] * deltaDims self.domainValues = [cub.axes_domains[a] for a in cub.axes_names] + \ [None] * deltaDims self.values = cub.data.reshape(targetSh) self.mask = None if mask==None else mask.reshape(targetSh) self.maskName = maskName #self.errors = None if cub.errors==None else cub.errors.reshape(targetSh) self.errors = None self.valueLabel = cub.value_label self.maskLabel = maskLabel self.otherSlices = otherSlices self._applyMask() if debug: print 'MatplotlibWidget.update: got view:' print '**Domains:' for i in xrange(len(self.domainNames)): if self.domainNames[i]!=None: if _N.isreal(self.domainNames[i][0]) : print '%s : [%d %d]' %(self.domainNames[i], self.domainValues[i].min(), self.domainValues[i].max()) else: print '%s : [%s ... %s]' %(self.domainNames[i], self.domainValues[i][0], self.domainValues[i][-1]) if debug: print 'self.maskedValues:', self.maskedValues.shape print self.maskedValues[:,:,0] #print 'self.values :', self.values.shape if self.errors != None: print 'self.errors:', self.maskedErrors.shape self.emit(PYSIGNAL('valuesChanged'),(self.getShortDataDescription(),)) self.computeFigure() def getShortDataDescription(self): if self.mask!=None: if self.maskLabel > 0: v = self.values[self.mask == self.maskLabel] else: v = self.values[self.mask != 0] else: v = self.maskedValues if v.size > 0: descr = '%1.3g(%1.3g)[%1.3g,%1.3g]' %(v.mean(),v.std(), v.min(),v.max()) else: descr = '' return descr def resetGraph(self): if debug : print 'MatplotlibWidget.resetGraph ...' if self.colorBars != None: if debug: print 'self.colorbars :', self.colorBars for cb in self.colorBars: self.fig.delaxes(cb.ax) self.colorBars = None if self.graphMode == viewModes.MODE_HIST: if self.axes: for a in self.axes: self.fig.delaxes(a) ax = self.fig.add_subplot(111) ax.zValue = 0 self.axes = [ax] #self.axes.clear() self.axes[0].hold(False) else: nbZVal = self.values.shape[2] if debug: print 'nbZVal :', nbZVal h = round(nbZVal**.5) w = _N.ceil(nbZVal/h) if 1 or (h != self.subplotsH or w != self.subplotsW): if self.axes: for a in self.axes: self.fig.delaxes(a) self.subplotsW = w self.subplotsH = h self.axes = [] if debug: print 'add subplots : w=%d, h=%d' %(w,h) for i in xrange(1,nbZVal+1): #if debug: print ' add(%d, %d, %d)' %(h,w,i) ax = self.fig.add_subplot(h,w,i) ax.zValue = i-1 self.axes.append(ax) self.adjustSubplots() def adjustSubplots(self): if debug: print "adjustSubplots ..." if self.graphMode == viewModes.MODE_HIST: self.fig.subplots_adjust(left=0.2, right=.95, bottom=0.2, top=.9, hspace=0., wspace=0.) return if self.values.shape[2] == 1: if not self.showAxesFlag: self.fig.subplots_adjust(left=0.2, right=.8, bottom=0.2, top=.8, hspace=0.05, wspace=0.05) elif not self.showAxesLabels: if self.graphMode == viewModes.MODE_2D: self.fig.subplots_adjust(left=0.05, right=.95, bottom=0.01, top=.95, hspace=0., wspace=0.) else: self.fig.subplots_adjust(left=0.2, right=.95, bottom=0.1, top=.95, hspace=0., wspace=0.) else: self.fig.subplots_adjust(left=0.1, right=.95, bottom=0.1, top=.9, hspace=0.05, wspace=0.05) else: if not self.showAxesFlag: self.fig.subplots_adjust(left=0., right=1., bottom=0., top=1., hspace=0.05, wspace=0.05) elif not self.showAxesLabels: self.fig.subplots_adjust(left=0.1, right=.9, bottom=0.2, top=.9, hspace=0.7, wspace=0.3) else: self.fig.subplots_adjust(left=0.1, right=.9, bottom=0.1, top=.9, hspace=0.01, wspace=0.7) def showMask(self, splot, mask): if mask != None: nr, nc = mask.shape extent = [-0.5, nc-0.5, -0.5, nr-0.5] if self.displayMaskFlag == self.MASK_SHOWN: labels = _N.unique(mask) for il, lab in enumerate(labels): if lab != 0: if self.maskCm!=None : cm = self.maskCm[lab] else : cm = get_cmap('binary') splot.contour((mask==lab).astype(int), 1, cmap=cm, linewidths=2., extent=extent,alpha=.7) #cmap=cm, linewidths=1.5, extent=extent,alpha=.7) if self.displayMaskFlag == self.MASK_ONLY: if self.maskLabel == 0: labels = _N.unique(mask) for il, lab in enumerate(labels): if lab != 0: if self.maskCm != None: cm = self.maskCm[lab] else: cm = get_cmap('binary') ml = (mask==lab).astype(int) print 'contouf of mask label %d -> %d pos' \ %(lab, ml.sum()) splot.contourf(ml, 1, cmap=cm, linewidths=1., extent=extent) elif (mask==self.maskLabel).sum() > 0: if self.maskCm != None: cm = self.maskCm[_N.where(mask==self.maskLabel)[0]] else: cm = get_cmap('binary') ax.contourf((mask==self.maskLabel).astype(int), 1, cmap=cm, linewidths=1.5, extent=extent) def plot1D(self): if debug: print 'MatplotlibWidget.computeFigure: MODE_1D' di2 = 0 nbins = 100. d1 = self.domainValues[1] d0 = self.domainValues[0] plotPDF = False if d0[0] == 'mean' and len(d0)>1 and d0[1] == 'var': plotPDF = True if (self.values[1,:] < 10.).all(): xMin = (self.values[0,:] - 6*self.values[1,:]**.5).min() xMax = (self.values[0,:] + 6*self.values[1,:]**.5).max() else: xMin = (self.values[0,:] - 10*self.values[1,:]**.5).min() xMax = (self.values[0,:] + 10*self.values[1,:]**.5).max() bins = _N.arange(xMin, xMax, (xMax-xMin)/nbins) x = d0 if _N.isreal(d0[0]) else _N.arange(len(d0)) me = self.maskedErrors.max() if self.errors!=None else 0 yMax = self.maskedValues.max()+me yMin = self.maskedValues.min()-me if 1 or self.errors !=None : dy = (yMax-yMin)*0.05 dx = (x.max()-x.min())*0.05 else: dx,dy = 0,0 for ax in self.axes: ax.hold(True) #ax.set_axis_off() vSlice = self.maskedValues[:,:,di2] if self.errors != None: errSlice = self.maskedErrors[:,:,di2] for di1 in xrange(self.values.shape[1]): if plotPDF: plotNormPDF(ax, bins, vSlice[0,di1], vSlice[1,di1]) else: print 'di1:',di1 print 'domainValues:', self.domainValues if self.domainValues[1] is not None: val = str(self.domainNames[1]) + ' = ' + \ str(self.domainValues[1][di1]) else: val = 'nothing' ax.plot(x, vSlice[:,di1], picker=ValuePicker(val)) #ax.plot(vSlice[:,di1], picker=ValuePicker(val)) if not _N.isreal(d0[0]): setTickLabels(self.axes[0].xaxis, d0) if self.errors != None and not _N.allclose(errSlice[:,di1],0.) : ax.errorbar(x, vSlice[:,di1], errSlice[:,di1], fmt=None) if not plotPDF: ax.set_xlim(x.min()-dx, x.max()+dx) ax.set_ylim(yMin-dy, yMax+dy) elif ax.get_ylim()[1] > 1.0: ax.set_ylim(0, 1.) if not self.showAxesFlag: ax.set_axis_off() self.plotAxesLabels(ax) #ax.set_title(self.domainNames[2]+' ' \ # +str(self.domainValues[2][di2])) di2 += 1 def plotAxesLabels(self, axis): if not self.showAxesLabels: axis.set_xlabel('') axis.set_ylabel('') return if self.graphMode == viewModes.MODE_1D: axis.set_xlabel(self.domainNames[0]) axis.set_ylabel(self.valueLabel) elif self.graphMode == viewModes.MODE_2D: axis.set_ylabel(self.domainNames[0]) if self.domainValues[1] != None: axis.set_xlabel(self.domainNames[1]) else: #MODE_HIST axis.set_xlabel(self.valueLabel) axis.set_ylabel('density') def plot2D(self): if debug: print 'MatplotlibWidget.computeFigure: MODE_2D' di2 = 0 self.colorBars = [] for ax in self.axes: ax.hold(True) if self.mask != None: self.showMask(ax, self.mask[:,:,di2]) #print 'maskedValues:', self.maskedValues.min(), self.maskedValues.max() if not hasattr(ax, 'matshow'): # matplotlib version < 0.9: ms = _matshow(ax, self.maskedValues[:,:,di2], cmap=self.colorMap, norm=self.norm) else: ms = ax.matshow(self.maskedValues[:,:,di2], cmap=self.colorMap, norm=self.norm) if self.showColorBar and len(self.axes)<2: if debug: print ' plot colorbar ...' self.colorBars.append(self.fig.colorbar(ms)) if not self.showAxesFlag: ax.set_axis_off() else: setTickLabels(ax.yaxis, self.domainValues[0]) if self.domainValues[1] != None: setTickLabels(ax.xaxis, self.domainValues[1]) self.plotAxesLabels(ax) #ax.set_title(self.domainNames[2]+' ' \ # +str(self.domainValues[2][di2])) di2 += 1 def plotHist(self): if debug: print 'MatplotlibWidget.computeFigure: MODE_HIST' v = self.values if 0 and self.mask != None: if debug: print 'self.mask:', _N.unique(self.mask) if self.maskLabel > 0: #if debug: print 'self.values[self.mask == %d] :' %self.maskLabel #if debug: print self.values[self.mask == self.maskLabel] vs = [self.values[self.mask == self.maskLabel]] else: #if debug: print 'self.values[self.mask != 0] :' #if debug: print self.values[self.mask != 0] vs = [self.values[self.mask == ml] for ml in self.maskLabels if ml!=0] else: vs = [self.values] bins = 30 #bins = _N.arange(0,1.,0.05) normed = True colors = ['b','r','g'] n,bins = _N.histogram(self.values, bins=bins, normed=normed) for iv, v in enumerate(vs): if v.size > 0: fColor = colors[iv] alpha = 0.5 if iv > 0 else 1. self.axes[0].hold(True) n,b,p = self.axes[0].hist(v, bins=bins, normed=normed, fc=fColor, alpha=alpha) #if type(bins) == int : # bins = b else: print "Nothing in histogram" self.plotAxesLabels(self.axes[0]) def computeFigure(self): if debug: print 'MatplotlibWidget.computeFigure: ...' # Reset subplots adjustment: #self.fig.subplots_adjust(left=0.15, right=.9, bottom=0.2, top=.8, # hspace=0.1, wspace=0.1) self.resetGraph() self.refreshFigure() def refreshFigure(self): if debug : print 'MatplotlibWidget.refreshFigure ...' if self.graphMode == viewModes.MODE_1D: self.plot1D() elif self.graphMode == viewModes.MODE_2D: self.plot2D() elif self.graphMode == viewModes.MODE_HIST: self.plotHist() if debug: print 'fig:', self.fig.get_figwidth(), self.fig.get_figheight() self.draw() def save(self, fn): if debug : print 'MatplotlibWidget: self.fig.savefig ...' self.fig.savefig(fn) def printVal(self, v): if not _N.isreal(v): # assume string return v #else assume number elif int(v) == v: #integer return '%d' %v else: # float return '%1.3g' %v def onClick(self, event): if debug: print 'mpl press event !' if not event.inaxes: return i = round(event.ydata) j = round(event.xdata) if hasattr(event.inaxes, 'zValue'): #if self.graphMode == viewModes.MODE_2D: k = event.inaxes.zValue else: k = -1 if debug: print 'click on :', (i,j,k) print 'self.values.shape :', self.values.shape if self.otherSlices is not None: pos = self.otherSlices.copy() else: pos = {} if self.graphMode == viewModes.MODE_2D: if i<self.values.shape[0] and j<self.values.shape[1]: for n in xrange(3): if debug: print 'self.domainNames[n]:', self.domainNames[n] if self.domainNames[n] != None: dv = self.domainValues[n][[i,j,k][n]] pos[self.domainNames[n]] = dv if self.mask is not None: pos[self.maskName] = self.mask[i,j,k] pos[self.valueLabel] = self.values[i,j,k] if debug: print '-> ', pos print "emitting positionClicked ..." self.emit(PYSIGNAL("positionClicked"), (pos.keys(), pos.values()) ) def onMove(self, event): if event.inaxes and hasattr(event.inaxes, 'zValue'): #print 'zVal:', event.inaxes.zValue k = event.inaxes.zValue i = round(event.ydata) j = round(event.xdata) #print 'xdata : %f, ydata : %f' %(event.xdata, event.ydata) #print 'i:%d, j:%d, k:%d' %(i,j,k) if self.graphMode == viewModes.MODE_2D: if i >=self.values.shape[0] or j>=self.values.shape[1]: msg = '' else: if self.mask==None or (self.mask[i,j,k] != 0 and \ (self.maskLabel==0 or \ self.mask[i,j,k]==self.maskLabel)): msg = '%s: %1.3g' %(self.valueLabel, self.values[i,j,k]) else: msg = 'background' if self.mask != None: msg += ', %s:%d' %(self.maskName, self.mask[i,j,k]) if msg != '': for n in xrange(3): if self.domainNames[n] is not None: dv = self.domainValues[n][[i,j,k][n]] msg += ', %s: %s' \ %(self.domainNames[n], self.printVal(dv)) if self.errors != None: msg += ', error: %1.3g' %(self.errors[i,j,k]) elif self.graphMode == viewModes.MODE_1D: msg = '%s: %1.3g, %s: %1.3g' %(self.domainNames[0],event.xdata, self.valueLabel,event.ydata) elif self.graphMode == viewModes.MODE_HIST: msg = '%s: %1.3g, %s: %1.3g' %(self.valueLabel,event.xdata, 'freq',event.ydata) else: msg = '' self.emit(PYSIGNAL('pointerInfoChanged'), (msg,)) def onRelease(self, event): if debug:print event.name if event.inaxes: self.matData = _N.random.randn(10,10) self.ai.set_data(self.matData)
class frame_plot(frame): instancias = [] instancia_selecionada = None # funcões de geters e sets def get_lines_axes(self, index): if (isinstance(index, int)): subplot = self.subplots[0] else: subplot = index return subplot.lines def get_lines_lengenda(self, index): if (isinstance(index, int)): subplot = self.subplots[index] else: subplot = index return subplot.legend().get_lines() def get_visible_lines(self, index): try: array_linhas_visiveis = [] if (isinstance(index, int)): subplot = self.subplots[0] else: subplot = index for linha in subplot.lines: if (linha.get_visible()): array_linhas_visiveis.append(linha) return array_linhas_visiveis except Exception as e: print(str(e)) def get_serie_line2d(self, line2d): try: linha = [] for subplot in self.figura.axes: for linha_legenda, linha_serie in zip( self.legendas[subplot].get_lines(), subplot.lines): if (line2d == linha_legenda): linha = 'linha legenda', self.processamento.get_time_serie( linha_serie) if (line2d == linha_serie): linha = 'linha grafico', self.processamento.get_time_serie( linha_serie) if (len(linha) > 0): return linha[1], linha[0] else: raise ValueError( "Não foi possivel encontra a serie selecionada") except ValueError as e: print(str(e)) except Exception as e: print(str(e)) def get_subplot(self, index, copy=False): self.subplots = self.figura.axes if (copy == False): return self.figura.axes[index], len(self.subplots) else: return self.subplots[:][index], len(self.subplots) def get_subplot_line2d(self, line_2d): try: cont = 0 for subplot in self.figura.axes: for linha in subplot.lines: if (linha == line_2d): return subplot, cont cont = cont + 1 except Exception as e: print(str(e)) def __init__(self, janela, container, botao_aba, **kwargs): frame.__init__(self, janela, 'frame_plot', container) frame_plot.add_instancia(self) self.kwargs = kwargs self.processamento = processamento(self) self.current_plot = "" self.botao_aba = botao_aba #raise frame def raise_frame(self): try: self.tkraise() frame_plot.set_current_instancia(self) except Exception as e: print(str(e)) #funcões de criacao def criar_figura(self, valor): try: self.figura = Figure(figsize=(5, 5), dpi=100) self.figura.subplots_adjust(bottom=0.09, top=0.95, left=0.05, right=0.96) self.canvas = FigureCanvasTkAgg(figure=self.figura, master=self) self.figura.canvas = self.canvas self.canvas.draw() self.canvas.get_tk_widget().pack(side=tk.RIGHT, fill=tk.BOTH, expand=1) self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) toolbar = NavigationToolbar2Tk(self.canvas, self) toolbar.update() self.grid(row=0, column=0, sticky=tk.NSEW) self.pick_event = self.figura.canvas.mpl_connect( 'pick_event', self.on_pick) self.click_event = self.figura.canvas.mpl_connect( 'button_press_event', self.on_click) except Exception as e: print(str(e)) #funcões subplot def add_subplot(self, column=1): self.size_subplots = len(self.figura.axes) self.figura.add_subplot(self.size_subplots + 1, column, self.size_subplots + 1) self.subplots = self.figura.axes def excluir_subplot(self, index): if (isinstance(index, int)): self.figura.delaxes(self.subplots[index]) self.size_subplots = len(self.figura.axes) self.subplots = self.figura.axes if (len(self.subplots) > 0): self.selecionar_subplot(0) else: self.figura.delaxes(index) self.size_subplots = len(self.figura.axes) self.subplots = self.figura.axes if (len(self.subplots) > 0): self.selecionar_subplot(0) def verificar_subplots(self): if (len(self.figura.axes) == 0): self.legendas = {} self.add_subplot(1) self.selecionar_subplot(0) def selecionar_subplot(self, index): try: if (isinstance(index, int)): self.subplot_selecionado = self.subplots[index] else: self.subplot_selecionado = index for subplot in self.figura.axes: if (subplot == self.subplot_selecionado): subplot.set_facecolor(SUBPLOT_SELECT_COLOR) else: subplot.set_facecolor(SUBPLOT_NOT_SELECT_COLOR) except Exception as e: print(str(e)) # funcões de atualização def update_legenda(self, *args, **kwargs): try: for subplot in self.figura.axes: handles, labels = subplot.get_legend_handles_labels() self.legendas[subplot] = subplot.legend(handles, labels) if (self.legendas[subplot] != None): for linha in self.legendas[subplot].get_lines(): linha.set_picker(5) except Exception as e: print(str(e)) def update_escala(self, visible_only=True): try: for subplot in self.figura.axes: if (len(self.get_visible_lines(subplot)) > 0): subplot.relim(visible_only=visible_only) subplot.autoscale_view(True, True, True) else: subplot.relim(visible_only=visible_only) subplot.autoscale_view(False, False, False) except Exception as e: print(str(e)) def update_subplots(self): for subplot in self.figura.axes: if (len(subplot.lines) == 0 and self.current_plot == "Normal"): self.excluir_subplot(subplot) quant_subplots = len(self.figura.axes) cont_subplot = 1 for subplot in self.figura.axes: subplot.change_geometry(quant_subplots, 1, cont_subplot) cont_subplot += 1 def update_canvas(self, *args, **kwargs): self.canvas.draw() def update_screen(self): try: self.update_subplots() self.update_escala(self.subplot_selecionado) self.update_legenda() self.update_canvas() except Exception as e: print(str(e)) # funcões de plotagem def plot_normal(self, data_x, data_y, x_label, y_label, index_axes=-1, plot_date=True, **kwargs): try: if (self.current_plot != "Normal"): self.figura.clear() self.verificar_subplots() if (isinstance(index_axes, int)): if (index_axes == -1): subplot = self.subplot_selecionado elif (index_axes >= 0): subplot = self.figura.axes[index_axes] else: subplot = index_axes if (plot_date): subplot.xaxis.set_major_formatter( mdates.DateFormatter('%d/%m/%Y')) line_2d, = subplot.plot(data_x, data_y, **kwargs) self.subplot_selecionado.set_xlabel(x_label) self.subplot_selecionado.set_ylabel(y_label) self.current_plot = "Normal" line_2d.set_picker(5) return line_2d, subplot except Exception as e: print(str(e)) def box_plot(self, data, **kwargs): try: if (self.current_plot != "Boxplot"): self.figura.clear() self.verificar_subplots() self.subplot_selecionado.boxplot(data, **kwargs) self.current_plot = "Boxplot" except Exception as e: print(str(e)) def plot_bar(self, array_valores, array_text): pass def plot_scatter(self, data_x, data_y, **kwargs): if (self.current_plot != "Scatter"): self.figura.clear() self.verificar_subplots() self.subplot_selecionado.plot(data_x, data_y, 'o', **kwargs) self.current_plot = "Scatter" def plot_histograma(self, array_valores, quantidade_classes, normed=False, **kwargs): try: if (self.current_plot != "Histogram"): self.figura.clear() self.verificar_subplots() self.subplot_selecionado.hist(array_valores, quantidade_classes, normed=normed, **kwargs) self.update_canvas() self.current_plot = "Histogram" except Exception as e: print(str(e)) def plot_autocorrelacao(self, data_y, titulo="Autocorrelação", tipo_plot="pacf", lags=None, alpha=0.05, **kwargs): if (self.current_plot != "Autocorrelação"): self.figura.clear() self.verificar_subplots() if (tipo_plot == "pacf"): sm.graphics.tsa.plot_pacf(data_y, ax=self.subplot_selecionado, title=titulo, lags=lags, alpha=alpha, **kwargs) elif (tipo_plot == "acf"): sm.graphics.tsa.plot_acf(data_y, ax=self.subplot_selecionado, title=titulo, lags=lags, alpha=alpha, **kwargs) self.current_plot = "Autocorrelação" def fill_area(self, data_x, y, z, index_subplot=None, **kwargs): if (self.current_plot != "Normal"): self.figura.clear() if (isinstance(index_subplot, int)): if (index_subplot == None): subplot = self.subplot_selecionado elif (index_subplot >= 0): subplot = self.figura.axes[index_subplot] else: subplot = index_subplot figura = subplot.fill_between(data_x, y, z, **kwargs) self.current_plot = "Normal" return figura, subplot #funcões eventos def on_motion(self, event): try: pass except Exception as e: print(str(e)) def on_figure_enter(self, event): try: pass except Exception as e: print(str(e)) def on_figure_leave(self, event): try: pass except Exception as e: print(str(e)) def on_axes_enter(self, event): try: pass except Exception as e: print(str(e)) def on_axes_leave(self, event): try: pass except Exception as e: print(str(e)) def on_click(self, event): try: self.canvas.get_tk_widget().focus_force() subplot = event.inaxes if (subplot != None and subplot != self.subplot_selecionado and not self.click_pick_event): self.selecionar_subplot(subplot) self.update_canvas() self.click_pick_event = False except Exception as e: print(str(e)) def on_pick(self, event): try: self.click_pick_event = True objeto = event.artist evento_mouse = event.mouseevent key = evento_mouse.key serie, tipo_linha = self.get_serie_line2d(objeto) if (tipo_linha == 'linha grafico'): if (key == None): self.processamento.processamento_plot.selecionar_serie( serie, True, True) elif (key == 'alt'): self.processamento.processamento_plot.selecionar_serie( serie, True, False) if (tipo_linha == 'linha legenda'): if (evento_mouse.button == 1): self.processamento.processamento_plot.selecionar_serie( serie, True, True) if (evento_mouse.button == 2): self.processamento.processamento_plot.selecionar_serie( serie, True, True) if (evento_mouse.button == 3): dirt = self.janela.get_mouse_position() self.criar_menu_opcoes(serie, dirt["x"], dirt["y"]) except Exception as e: print(str(e)) def on_key_press(self, event): try: print(event.key) except Exception as e: print(str(e)) def on_key_release(self, event): try: pass except Exception as e: print(str(e)) # função criacão menu opções def criar_menu_mover_plot(self, serie, menu_opcoes): try: def mover_novo_subplot(): self.add_subplot(1) self.selecionar_subplot(-1) self.processamento.processamento_plot.move_plot_serie( serie, index_subplot=-1) menu_mover_plot = tk.Menu(menu_opcoes, tearoff=0) menu_opcoes.add_cascade(label="Mover para", menu=menu_mover_plot) cont = 0 for subplot in self.subplots: if (subplot != serie.subplot): menu_mover_plot.add_command( label="Subplot " + str(cont + 1), command=lambda index_subplot=cont: self.processamento. processamento_plot.move_plot_serie( serie, index_subplot=index_subplot)) cont = cont + 1 menu_mover_plot.add_command(label="Novo subplot", command=lambda: mover_novo_subplot()) except Exception as e: print(str(e)) def criar_menu_opcoes(self, serie, mouse_x, mouse_y): try: menu_opcoes = tk.Menu(self, tearoff=0) menu_opcoes.add_command( label="Excluir", command=lambda: self.processamento.processamento_plot. excluir_plot_serie(serie, True)) menu_opcoes.add_command( label="Esconder/Mostrar", command=lambda: self.processamento.processamento_plot. mudar_visibilidade_plot_serie(serie, True)) self.criar_menu_mover_plot(serie, menu_opcoes) menu_opcoes.post(mouse_x, mouse_y) except Exception as e: print(str(e)) # metodos classe @classmethod def add_instancia(cls, instancia): cls.instancias.append(instancia) @classmethod def remove_instancia(cls, instancia): cls.instancias.remove(instancia) @classmethod def get_instances(cls): return cls.instancias @classmethod def get_current_instacia(cls): return cls.instancia_selecionada @classmethod def set_current_instancia(cls, instancia): cls.current_instancia = instancia
class Qt4Mpl2DCanvas(FigureCanvas): """ A customized Qt widget for matplotlib figure. It can be used to replace GraphicsView of QtGui """ def __init__(self, parent): """ Initialization """ # Instantiating matplotlib Figure self.fig = Figure() self.fig.patch.set_facecolor('white') # initialization super(Qt4Mpl2DCanvas, self).__init__(self.fig) # set up axis/subplot (111) only for 2D self.axes = self.fig.add_subplot( 111, polar=False) # return: matplotlib.axes.AxesSubplot # plot management self._scatterPlot = None self._imagePlot = None # Initialize parent class and set parent FigureCanvas.__init__(self, self.fig) self.setParent(parent) # Set size policy to be able to expanding and resizable with frame FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) # Variables to manage all lines/subplot self._lineDict = {} self._lineIndex = 0 # legend and color bar self._colorBar = None self._isLegendOn = False self._legendFontSize = 8 return def update_image(self, array2d): """ @return: """ self._imagePlot.set_data(array2d) self._flush() return def has_plot(self, plot_type): if plot_type == 'image' and self._imagePlot is not None: return True return False @property def is_legend_on(self): """ check whether the legend is shown or hide Returns: boolean """ return self._isLegendOn def add_arrow(self, start_x, start_y, stop_x, stop_y): """ Example: (0, 0, 0.5, 0.5, head_width=0.05, head_length=0.1, fc='k', ec='k') @param start_x: @param start_y: @param stop_x: @param stop_y: @return: """ head_width = 0.05 head_length = 0.1 fc = 'k' ec = 'k' arrow = self.axes.arrrow(start_x, start_y, stop_x, stop_y, head_width, head_length, fc, ec) return arrow def add_contour_plot(self, vec_x, vec_y, matrix_z): """ add a contour plot Example: reduced data: vec_x: d-values, vec_y: run numbers, matrix_z, matrix for intensities :param vec_x: a list of a vector for X axis :param vec_y: a list of a vector for Y axis :param matrix_z: :return: """ # check input # TODO - labor assert isinstance(vec_x, list) or isinstance(vec_x, np.ndarray), 'blabla' assert isinstance(vec_y, list) or isinstance(vec_y, np.ndarray), 'blabla' assert isinstance(matrix_z, np.ndarray), 'blabla' # create mesh grid grid_x, grid_y = np.meshgrid(vec_x, vec_y) # # print '[DB...BAT] Grid X and Grid Y size: ', grid_x.shape, grid_y.shape # check size assert grid_x.shape == matrix_z.shape, 'Size of X (%d) and Y (%d) must match size of Z (%s).' \ '' % (len(vec_x), len(vec_y), matrix_z.shape) # # Release the current image # self.axes.hold(False) # Do plot: resolution on Z axis (color bar is set to 100) self.axes.clear() contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100) labels = [item.get_text() for item in self.axes.get_yticklabels()] # Set the Y-axis ticks # TODO/ISSUE/NOW: how to make this part more flexible if len(labels) == 2 * len(vec_y) - 1: new_labels = [''] * len(labels) for i in range(len(vec_y)): new_labels[i * 2] = '%d' % int(vec_y[i]) self.axes.set_yticklabels(new_labels) # END-IF # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type contour_plot.set_cmap('spectral') self._colorBar = self.fig.colorbar(contour_plot) else: self._colorBar.update_bruteforce(contour_plot) # Flush... self._flush() def add_image_plot(self, array2d, xmin, xmax, ymin, ymax, yticklabels=None): """ @param array2d: @param xmin: @param xmax: @param ymin: @param ymax: @param holdprev: @param yticklabels: list of string for y ticks @return: """ # check assert isinstance(array2d, np.ndarray), 'blabla' assert len(array2d.shape) == 2, 'blabla' # show image self._imagePlot = self.axes.imshow(array2d, extent=[xmin, xmax, ymin, ymax], interpolation='none') print(self._imagePlot, type(self._imagePlot)) # set y ticks as an option: if yticklabels is not None: # it will always label the first N ticks even image is zoomed in print("[FIXME]: The way to set up the Y-axis ticks is wrong!") self.axes.set_yticklabels(yticklabels) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # set up color bar # # Set color bar. plt.colorbar() does not work! # if self._colorBar is None: # # set color map type # imgplot.set_cmap('spectral') # self._colorBar = self.fig.colorbar(imgplot) # else: # self._colorBar.update_bruteforce(imgplot) # Flush... self._flush() return def add_image_file(self, imagefilename): """Add an image by file """ # set aspect to auto mode self.axes.set_aspect('auto') img = matplotlib.image.imread(str(imagefilename)) # lum_img = img[:,:,0] # FUTURE : refactor for image size, interpolation and origin imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) self._flush() return def add_scatter_plot(self, array2d): """ add scatter plot @param array2d: @return: """ # check! # TODO - 20180801 - Make it work assert isinstance(array2d, np.ndarray), 'blabla' if array2d.shape[1] < 3: raise RuntimeError('blabla3') if False: array2d = np.ndarray(shape=(100, 3), dtype='float') array2d[0][0] = 0 array2d[0][1] = 0 array2d[0][2] = 1 import random for index in range(1, 98): x = random.randint(1, 255) y = random.randint(1, 255) z = random.randint(1, 20000) array2d[index][0] = float(x) array2d[index][1] = float(y) array2d[index][2] = float(z) array2d[99][0] = 255 array2d[99][1] = 255 array2d[99][2] = 1 self._scatterPlot = self.axes.scatter(array2d[:, 0], array2d[:, 1], s=80, c=array2d[:, 2], marker='s') return def clear_canvas(self): """ Clear data including lines and image from canvas """ # clear the image for next operation # self.axes.hold(False) # clear image self.axes.cla() # Try to clear the color bar if len(self.fig.axes) > 1: self.fig.delaxes(self.fig.axes[1]) self._colorBar = None # This clears the space claimed by color bar but destroys sub_plot too. self.fig.clear() # Re-create subplot self.axes = self.fig.add_subplot(111) self.fig.subplots_adjust(bottom=0.15) # flush/commit self._flush() return def decrease_legend_font_size(self): """ reset the legend with the new font size Returns: """ # minimum legend font size is 2! return if it already uses the smallest font size. if self._legendFontSize <= 2: return self._legendFontSize -= 1 self._setup_legend(font_size=self._legendFontSize) self.draw() return def getLastPlotIndexKey(self): """ Get the index/key of the last added line """ return self._lineIndex - 1 def getPlot(self): """ reture figure's axes to expose the matplotlib figure to PyQt client """ return self.axes def getXLimit(self): """ Get limit of Y-axis """ return self.axes.get_xlim() def getYLimit(self): """ Get limit of Y-axis """ return self.axes.get_ylim() def hide_legend(self): """ hide the legend if it is not None Returns: """ if self.axes.legend() is not None: # set visible to be False and re-draw self.axes.legend().set_visible(False) self.draw() self._isLegendOn = False return def increase_legend_font_size(self): """ reset the legend with the new font size Returns: """ self._legendFontSize += 1 self._setup_legend(font_size=self._legendFontSize) self.draw() return def setXYLimit(self, xmin, xmax, ymin, ymax): """ """ # for X xlims = self.axes.get_xlim() xlims = list(xlims) if xmin is not None: xlims[0] = xmin if xmax is not None: xlims[1] = xmax self.axes.set_xlim(xlims) # for Y ylims = self.axes.get_ylim() ylims = list(ylims) if ymin is not None: ylims[0] = ymin if ymax is not None: ylims[1] = ymax self.axes.set_ylim(ylims) # try draw self.draw() return def set_title(self, title, color): """ set the tile to an axis :param title: :param color :return: """ # check input assert isinstance(title, str), 'Title must be a string but not a {0}.'.format( type(title)) assert isinstance(color, str), 'Color must be a string but not a {0}.'.format( type(color)) self.setWindowTitle(title) self.draw() return def show_legend(self): """ show the legend if the legend is not None Returns: """ if self.axes.legend() is not None: # set visible to be True and re-draw # self.axes.legend().set_visible(True) self._setup_legend(font_size=self._legendFontSize) self.draw() # set flag on self._isLegendOn = True return def _flush(self): """ A dirty hack to flush the image """ w, h = self.get_width_height() self.resize(w + 1, h) self.resize(w, h) return def _setup_legend(self, location='best', font_size=10): """ Set up legend self.axes.legend(): Handler is a Line2D object. Lable maps to the line object Args: location: font_size: Returns: """ allowed_location_list = [ "best", "upper right", "upper left", "lower left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center" ] # Check legend location valid or not if location not in allowed_location_list: location = 'best' handles, labels = self.axes.get_legend_handles_labels() self.axes.legend(handles, labels, loc=location, fontsize=font_size) self._isLegendOn = True return
class ProjectAnalysisPage: def __init__(self, proj_info): self.project = proj_info self.project_name = None # StringVar() self.sample_file = None self.sample_file_name = None self.sample_analysis_file = None self.f1 = None self.a1 = None self.canvas1 = None self.f2 = None self.a2 = None self.canvas2 = None self.f3 = None self.a3 = None self.canvas3 = None def create_gui(self, master): analysisFrame = Frame(master) analysisFrame.pack(fill="both") self.sample_file_subframe(analysisFrame) self.analysis_plots_subframe(analysisFrame) return analysisFrame def get_sample_file(self): dir_path = filedialog.askopenfilename(title="Select Sample File") if dir_path: self.sample_file.set(dir_path) print("filename: ", os.path.split(dir_path)[-1]) self.sample_file_name.set(os.path.split(dir_path)[-1]) proj_name = self.sample_file_name.get()[:-4] self.sample_analysis_file.set("".join(os.path.split(dir_path)[:-1]) + "/" + proj_name + ".sa") print("sample_analysis_file: ", self.sample_analysis_file.get()) def sample_file_subframe(self, master): self.sample_file = StringVar() self.sample_file_name = StringVar() self.sample_analysis_file = StringVar() self.sample_file.set(self.project.sample_dir.get()) file_frame = LabelFrame(master, text="Sample File") file_frame.pack(fill="both", padx=10) # file_frame.grid(row=0, column=0) dialog_frame = Frame(master) dialog_frame.pack(fill='both', side='top') file_name_frame = Frame(master) file_name_frame.pack(side='top') sample_file_label = Label(dialog_frame, text="Choose sample file: ") sample_file_label.pack(anchor='w', side='left', padx=5, pady=5) sample_file_entry = Entry(dialog_frame, textvariable=self.sample_file) sample_file_entry.pack(anchor='e', expand=1, fill='x', side='left') button1 = Button(dialog_frame, text="...", command=self.get_sample_file) button1.pack(anchor='e', side='left', padx=10, pady=5) file_name_label = Label(file_name_frame, text="Sample file name: ") file_name_label.pack( side='left', padx=15, pady=15) file_name = Label(file_name_frame, textvariable=self.sample_file_name) file_name.pack( side='left', padx=15, pady=15) def analysis_plots_subframe(self, master): plotter_frame = LabelFrame(master, text="Analysis Plots") plotter_frame.pack(fill="both") button1 = Button(plotter_frame, text="Print Plot", command=self.print_plots) button1.pack(anchor='n', side='top', padx=10, pady=5) plots_frame = Frame(plotter_frame) plots_frame.pack(fill="both", expand=True) plot1_frame = Frame(plots_frame) # plot1_frame.pack(fill="both", expand=True, anchor='e', side='top') plot1_frame.grid(row=0, column=0, sticky="nw") plot2_frame = Frame(plots_frame) plot2_frame.grid(row=0, column=1, sticky="ne") # plot2_frame.pack(fill="both", expand=True, anchor='w', side='top') # initialize plot1 self.f1 = Figure(figsize=(4, 4), dpi=100) self.a1 = self.f1.add_subplot(111) self.a1.plot([1, 2, 3, 4, 5, 6, 7, 8], [5, 6, 1, 3, 8, 9, 3, 5], 'g') self.canvas1 = FigureCanvasTkAgg(self.f1, plot1_frame) tkagg.NavigationToolbar2TkAgg(self.canvas1, plot1_frame) self.canvas1.show() self.canvas1.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True) # initialize plot2 self.f2 = Figure(figsize=(4, 4), dpi=100) self.a2 = self.f2.add_subplot(111) self.a2.plot([1, 2, 4, 5, 8, 6, 7, 8], [5, 6, 1, 3, 8, 9, 3, 5], 'b') self.canvas2 = FigureCanvasTkAgg(self.f2, plot2_frame) tkagg.NavigationToolbar2TkAgg(self.canvas2, plot2_frame) self.canvas2.show() self.canvas2.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True) def print_plots(self): print("yess") p = SampleParser() print("sample_file.get(): ", self.sample_file.get()) sample_file = self.sample_file.get() analysis_file = self.sample_analysis_file.get() print("analysis file: ", analysis_file) plot_list = p.parse_sample_file(sample_file, analysis_file) print("plot_list: ", plot_list) print("lkjsadflkj") if len(plot_list[0]) > 0 : self.f1.delaxes(self.a1) self.a1 = self.f1.gca(projection='3d') self.a1.plot_trisurf(plot_list[0], plot_list[1], plot_list[2], cmap='viridis', edgecolor='none') self.canvas1.show() self.canvas1.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True) self.f2.delaxes(self.a2) self.a2 = self.f2.gca(projection='3d') self.a2.plot_trisurf(plot_list[0], plot_list[1], plot_list[3], cmap='viridis', edgecolor='none') self.canvas2.show() self.canvas2.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)
class PlotFrame(wx.Frame): help_msg=""" Menus for Import...import project settings file Export...export figure (png, jpg) to file Print Setup...setup size of figure for printing Print Preview...preview printer page Print...send figure to a system printer Exit...end application Basic-2D...View basic 2D representation of data Advanced-2D...View 2D representation (with span selection control) Advanced-3D...View 3D representation of data View-Grid...Toggle grid View-Legend...Toggle legend View-Fill...Toggle fill representation of data (only for 2D) where 'figure' means an image of the matplotlib canvas In addition, "Ctrl-C" is bound to copy-figure-to-clipboard """ about_msg=""" Option_price_visualisation v0.1 29-Aug-2013 Nathan Floor, [email protected] """ def __init__(self): wx.Frame.__init__(self, None, -1, "Visualise Option Prices and Greeks", size=(300, 500)) self.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent) # intialise variables when start program self.viewLegend = False self.viewGrid = True self.viewFill = False self.reInitialiseData() # build interface self.Build_Menus() self.Build_Panel() self.statusbar = self.CreateStatusBar() self.Plot_Data() self.SetSize(size=(900, 550)) def reInitialiseData(self): self.fileReader = csvReader.Reader() self.current_view = 0 self.time = numpy.arange(0, 31, 1) self.indmin = 0 self.indmax = 31 self.strike_price = 0 # initialise data arrays self.option_price = [] self.stock_price = [] self.delta = [] self.gamma = [] self.vega = [] self.theta = [] self.rho = [] self.risidual = [] # initialise secondary data sets self.option_price_fill = [] self.time_span_fill = [] self.delta_fill = [] self.gamma_fill = [] self.vega_fill = [] self.theta_fill = [] self.rho_fill = [] # initialise bump values self.stock_bump = 0 self.time_bump = 0 self.rate_bump = 0 self.volitile_bump = 0 # on span-selection of graph def onselect(self, xmin, xmax): # initialise data sets option_price = [] delta = [] gamma = [] theta = [] rho = [] vega = [] maxYLimlist = [] minYLimlist = [] # identify the indices of new data set based on selection self.indmin = int(xmin) #self.indmax = numpy.searchsorted(t, (xmin, xmax)) self.indmax = min(len(self.time)-1, int(xmax)+1) self.time_span_fill = self.time[self.indmin:self.indmax] if len(self.option_price) > 0: option_price = numpy.array(map(float, self.option_price[self.stock_bump])) self.option_price_fill = option_price[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.option_price_fill)) minYLimlist.append(min(self.option_price_fill)) if not self.viewFill: self.line1.set_data(self.time_span_fill, self.option_price_fill) if len(self.delta) > 0: delta = numpy.array(map(float, self.delta[self.stock_bump])) self.delta_fill = delta[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.delta_fill)) minYLimlist.append(min(self.delta_fill)) if not self.viewFill: self.line2.set_data(self.time_span_fill, self.delta_fill) if len(self.gamma) > 0: gamma = numpy.array(map(float, self.gamma[self.stock_bump])) self.gamma_fill = gamma[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.gamma_fill)) minYLimlist.append(min(self.gamma_fill)) if not self.viewFill: self.line3.set_data(self.time_span_fill, self.gamma_fill) if len(self.theta) > 0: theta = numpy.array(map(float, self.theta[self.time_bump])) self.theta_fill = theta[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.theta_fill)) minYLimlist.append(min(self.theta_fill)) if not self.viewFill: self.line4.set_data(self.time_span_fill, self.theta_fill) if len(self.rho) > 0: rho = numpy.array(map(float, self.rho[self.rate_bump])) self.rho_fill = rho[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.rho_fill)) minYLimlist.append(min(self.rho_fill)) if not self.viewFill: self.line5.set_data(self.time_span_fill, self.rho_fill) if len(self.vega) > 0: vega = numpy.array(map(float, self.vega[self.volitile_bump])) self.vega_fill = vega[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.vega_fill)) minYLimlist.append(min(self.vega_fill)) if not self.viewFill: self.line6.set_data(self.time_span_fill, self.vega_fill) if len(self.risidual) > 0: risidual = numpy.array(map(float, self.risidual[self.stock_bump])) self.risidual_fill = risidual[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.risidual_fill)) minYLimlist.append(min(self.risidual_fill)) if not self.viewFill: self.line7.set_data(self.time_span_fill, self.risidual_fill) if len(maxYLimlist) > 0: maxYLim = max(maxYLimlist) else: maxYLim = 1 if len(minYLimlist) > 0: minYLim = min(minYLimlist) else: minYLim = 0 self.axes2.set_xlim(self.time_span_fill[0]-1, self.time_span_fill[-1]+1) self.axes2.set_ylim(minYLim, maxYLim) if not self.viewFill: self.canvas.draw() else: self.Plot_Data() def Build_Panel(self): self.panel = wx.Panel(self) # Create Figure and canvas objects self.fig = Figure((6.0, 4.0)) self.canvas = FigCanvas(self.panel, -1, self.fig) self.axes = self.fig.add_subplot(111) # setup slider-widgets for controlling GUI self.sliderPanel = wx.Panel(self.panel) self.stockSlider_label = wx.StaticText(self.sliderPanel, -1, "Stock Price: ") self.stockSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS) # self.stockSlider.SetTickFreq(9, 1) self.rateSlider_label = wx.StaticText(self.sliderPanel, -1, "Interest Rate: ") self.rateSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS) self.rateSlider.SetTickFreq(1, 1) self.timeStepSlider_label = wx.StaticText(self.sliderPanel, -1, "Time Step: ") self.timeStepSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS) self.timeStepSlider.SetTickFreq(1, 1) self.Bind(wx.EVT_SLIDER, self.onStockSlider, self.stockSlider) self.Bind(wx.EVT_SLIDER, self.onRateSlider, self.rateSlider) self.Bind(wx.EVT_SLIDER, self.ontimeStepSlider, self.timeStepSlider) # setup options-widgets for controlling graphs self.callRadio = wx.RadioButton(self.panel, label="Call options", pos=(10, 10)) self.putRadio = wx.RadioButton(self.panel, label="Put options", pos=(10, 30)) self.callRadio.SetValue(True) self.spaceKeeper = wx.StaticText(self.panel, -1, '') self.optionPriceCheck = wx.CheckBox(self.panel, label="view Option Price", pos=(20, 20)) self.deltaCheck = wx.CheckBox(self.panel, label="show Delta", pos=(20, 20)) self.gammaCheck = wx.CheckBox(self.panel, label="show Gamma", pos=(20, 20)) self.rhoCheck = wx.CheckBox(self.panel, label="show Rho", pos=(20, 20)) self.thetaCheck = wx.CheckBox(self.panel, label="show Theta", pos=(20, 20)) self.fillCheck = wx.CheckBox(self.panel, label="show fill feature", pos=(20, 20)) self.risidualCheck = wx.CheckBox(self.panel, label="Show Residual", pos=(20, 20)) self.differenceCheck = wx.CheckBox(self.panel, label="Show Difference", pos=(20, 20)) self.effectCheck = wx.CheckBox(self.panel, label="Show Greek's effect on option price", pos=(20, 20)) self.effectCheck.SetValue(True) self.Bind(wx.EVT_RADIOBUTTON, self.onCallRadio, self.callRadio) self.Bind(wx.EVT_RADIOBUTTON, self.onPutRadio, self.putRadio) self.Bind(wx.EVT_CHECKBOX, self.onOptionPrice, self.optionPriceCheck) self.Bind(wx.EVT_CHECKBOX, self.onDelta, self.deltaCheck) self.Bind(wx.EVT_CHECKBOX, self.onGamma, self.gammaCheck) self.Bind(wx.EVT_CHECKBOX, self.onRho, self.rhoCheck) self.Bind(wx.EVT_CHECKBOX, self.onTheta, self.thetaCheck) self.Bind(wx.EVT_CHECKBOX, self.onRisidual, self.risidualCheck) self.Bind(wx.EVT_CHECKBOX, self.onDifferenceCheck, self.differenceCheck) self.Bind(wx.EVT_CHECKBOX, self.onShowEffects, self.effectCheck) self.Bind(wx.EVT_CHECKBOX, self.onShowFillEffect, self.fillCheck) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas) #################### # Layout with sizers #################### flags = wx.ALIGN_LEFT | wx.ALL | wx.ALIGN_CENTER_VERTICAL self.sizer = wx.BoxSizer(wx.VERTICAL) self.hboxMainBlock = wx.BoxSizer(wx.HORIZONTAL) self.vboxOptions = wx.BoxSizer(wx.VERTICAL) self.hboxSliders = wx.BoxSizer(wx.HORIZONTAL) self.flexiGridSizer = wx.FlexGridSizer(4, 2, 3, 10) # adds border around sliders to group related widgets self.vboxOptions.AddSpacer(10) self.sliderStaticBox = wx.StaticBox(self.sliderPanel, -1, 'Bump Sliders') self.sliderBorder = wx.StaticBoxSizer(self.sliderStaticBox, orient=wx.VERTICAL) self.flexiGridSizer.AddMany([(self.stockSlider_label), (self.stockSlider, 1, wx.ALL), (self.rateSlider_label), (self.rateSlider, 1, wx.EXPAND), (self.timeStepSlider_label), (self.timeStepSlider, 1, wx.EXPAND)]) self.sliderBorder.Add(self.flexiGridSizer, 1, wx.ALL, 5) self.sliderPanel.SetSizer(self.sliderBorder) self.vboxOptions.Add(self.sliderPanel, 0, flag=wx.ALIGN_LEFT|wx.ALL) # add border for type of option price self.optionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Option Price Type'), orient=wx.VERTICAL) self.flexiOptions = wx.FlexGridSizer(3, 1, 3, 10) self.flexiOptions.AddMany([(self.callRadio, 1, wx.EXPAND), (self.putRadio, 1, wx.EXPAND), (self.optionPriceCheck, 1, wx.EXPAND)]) self.optionsBorder.Add(self.flexiOptions, 1, wx.ALL, 5) self.vboxOptions.Add(self.optionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW) # add border for greeks self.greekOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Greek effect Options'), orient=wx.VERTICAL) self.flexiOptions2 = wx.FlexGridSizer(6, 1, 3, 10) self.flexiOptions2.AddMany([(self.deltaCheck, 1, wx.EXPAND), (self.gammaCheck, 1, wx.EXPAND), (self.rhoCheck, 1, wx.EXPAND), (self.thetaCheck, 1, wx.EXPAND), (self.risidualCheck, 1, wx.EXPAND)]) self.greekOptionsBorder.Add(self.flexiOptions2, 1, wx.ALL, 5) self.vboxOptions.Add(self.greekOptionsBorder, 1, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW) #self.vboxOptions.AddSpacer(5) # add border for other checkable options self.otherOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Extra Options'), orient=wx.VERTICAL) self.flexiOptions3 = wx.FlexGridSizer(3, 1, 3, 10) self.flexiOptions3.AddMany([(self.fillCheck, 1, wx.EXPAND), (self.differenceCheck, 1, wx.EXPAND), (self.effectCheck, 1, wx.EXPAND)]) self.otherOptionsBorder.Add(self.flexiOptions3, 1, wx.ALL, 5) self.vboxOptions.Add(self.otherOptionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW) self.vboxOptions.AddSpacer(5) self.hboxMainBlock.Add(self.vboxOptions, 0, flag=flags) self.hboxMainBlock.Add(self.canvas, 1, flag=wx.ALIGN_RIGHT|wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) self.sizer.Add(self.hboxMainBlock, 1, wx.ALL|wx.EXPAND) self.sizer.Add(self.toolbar, 0, wx.ALL|wx.ALIGN_RIGHT) self.sizer.AddSpacer(1) self.canvas.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent) self.Bind(wx.EVT_CLOSE, self.onExit) self.panel.SetSizer(self.sizer) self.sizer.Fit(self) self.Center() def Build_Menus(self): """ build menus """ MENU_EXIT = wx.NewId() MENU_OPEN = wx.NewId() MENU_SAVE = wx.NewId() MENU_PRINT = wx.NewId() MENU_PSETUP = wx.NewId() MENU_PREVIEW =wx.NewId() MENU_CLIPB =wx.NewId() MENU_VIEW_GRID = wx.NewId() MENU_HELP =wx.NewId() MENU_BASIC = wx.NewId() MENU_ADVANCE = wx.NewId() MENU_LEGEND = wx.NewId() MENU_3D = wx.NewId() MENU_ABOUT = wx.NewId() menuBar = wx.MenuBar() f0 = wx.Menu() importItem = wx.MenuItem(f0, MENU_OPEN, "&Import\tCtrl+I") f0.AppendItem(importItem) f0.Append(MENU_SAVE, "&Export", "Save Image of Plot") f0.AppendSeparator() printMenu = wx.Menu() printMenu.Append(MENU_PSETUP, "Page Setup...", "Printer Setup") printMenu.Append(MENU_PREVIEW,"Print Preview...", "Print Preview") printItem = wx.MenuItem(printMenu, MENU_PRINT, "Print\tCtrl+P") printMenu.AppendItem(printItem) f0.AppendMenu(-1, '&Print', printMenu) f0.AppendSeparator() exitItem = wx.MenuItem(f0, MENU_EXIT, 'E&xit\tCtrl+Q') f0.AppendItem(exitItem) menuBar.Append(f0, "&File") f1 = wx.Menu() f1.Append(MENU_BASIC, '&Basic', "Basic View(2D)") f1.Append(MENU_ADVANCE, '&Advanced-2D', "Advanced View(2D)") f1.Append(MENU_3D, 'A&dvanced-3D', "Advanced View(3D)") optionsMenu = wx.Menu() viewGridItem = wx.MenuItem(optionsMenu, MENU_VIEW_GRID, 'View &Grid\tCtrl+G') optionsMenu.AppendItem(viewGridItem) viewLegendItem = wx.MenuItem(optionsMenu, MENU_LEGEND, 'View &Legend\tCtrl+L') optionsMenu.AppendItem(viewLegendItem) f1.AppendMenu(-1, "&Options", optionsMenu) menuBar.Append(f1, "&View") f2 = wx.Menu() f2.Append(MENU_HELP, "Quick &Reference", "Quick Reference") f2.Append(MENU_ABOUT, "&About", "About this interface") menuBar.Append(f2, "&Help") self.SetMenuBar(menuBar) self.Bind(wx.EVT_MENU, self.onImport, id=MENU_OPEN) self.Bind(wx.EVT_MENU, self.onPrint, id=MENU_PRINT) self.Bind(wx.EVT_MENU, self.onPrinterSetup, id=MENU_PSETUP) self.Bind(wx.EVT_MENU, self.onPrinterPreview, id=MENU_PREVIEW) self.Bind(wx.EVT_MENU, self.onClipboard, id=MENU_CLIPB) self.Bind(wx.EVT_MENU, self.onExport, id=MENU_SAVE) self.Bind(wx.EVT_MENU, self.onExit , id=MENU_EXIT) self.Bind(wx.EVT_MENU, self.onViewGrid, id=MENU_VIEW_GRID) self.Bind(wx.EVT_MENU, self.onViewLegend, id=MENU_LEGEND) self.Bind(wx.EVT_MENU, self.onHelp, id=MENU_HELP) self.Bind(wx.EVT_MENU, self.onAbout, id=MENU_ABOUT) self.Bind(wx.EVT_MENU, self.onBasicView, id=MENU_BASIC) self.Bind(wx.EVT_MENU, self.onAdvancedView, id=MENU_ADVANCE) self.Bind(wx.EVT_MENU, self.onAdvanced3DView, id=MENU_3D) """ Menu event methods """ def onViewLegend(self, event=None): if self.viewLegend: self.viewLegend = False self.Plot_Data() else: self.viewLegend = True # use proxy artist plot_op = Line2D([], [], linewidth=3, color="black") plot_delta = Line2D([], [], linewidth=3, color="royalblue") plot_gamma = Line2D([], [], linewidth=3, color="cyan") plot_theta = Line2D([], [], linewidth=3, color="green") plot_rho = Line2D([], [], linewidth=3, color="darkorange") plot_risidual = Line2D([], [], linewidth=3, color="purple") # Shink current axis by 15% box = self.axes.get_position() self.axes.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis self.axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'], loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) if self.current_view == 1: box = self.axes2.get_position() self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) self.canvas.draw() def onBasicView(self, event=None): self.current_view = 0 # show sliders panel self.sliderPanel.Enable() self.toolbar.Enable() self.fillCheck.Enable() self.panel.Layout() self.Plot_Data() def onAdvancedView(self, event=None): self.current_view = 1 # show sliders panel self.sliderPanel.Enable() self.toolbar.Enable() self.fillCheck.Enable() self.panel.Layout() self.Plot_Data() def onAdvanced3DView(self, event=None): self.current_view = 2 # hide slider panel since will not be used self.sliderPanel.Disable() self.toolbar.Disable() self.fillCheck.Disable() self.panel.Layout() self.Plot_Data() def onPrinterSetup(self,event=None): self.canvas.Printer_Setup(event=event) def onPrinterPreview(self,event=None): self.canvas.Printer_Preview(event=event) def onPrint(self,event=None): self.canvas.Printer_Print(event=event) def onClipboard(self,event=None): self.canvas.Copy_to_Clipboard(event=event) def onKeyEvent(self,event=None): """ capture and act upon keystroke events """ if event == None: return key = event.GetKeyCode() if (key < wx.WXK_SPACE or key > 255): return if (event.ControlDown() and chr(key)=='C'): # Ctrl-C self.onClipboard(event=event) if (event.ControlDown() and chr(key)=='P'): # Ctrl-P self.onPrinterPreview(event=event) def onHelp(self, event=None): dlg = wx.MessageDialog(self, self.help_msg, "Quick Reference", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onAbout(self, event=None): dlg = wx.MessageDialog(self, self.about_msg, "About", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onViewGrid(self, event=None): if self.viewGrid: self.viewGrid = False else: self.viewGrid = True for a in self.fig.axes: a.grid(self.viewGrid) self.canvas.draw() def onExport(self,event=None): """ save figure image to file""" file_choices = "PNG (*.png)|*.png|" \ "JPEG (*.jpg)|*.jpg|" \ "BMP (*.bmp)|*.bmp" thisdir = os.getcwd() dlg = wx.FileDialog(self, message='Save Plot Figure as...', defaultDir = thisdir, defaultFile='plot.png', wildcard=file_choices, style=wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path,dpi=300) if (path.find(thisdir) == 0): path = path[len(thisdir)+1:] print('Saved plot to %s' % path) def onImport(self, event=None): """ Import csv file of option prices and greeks """ file_choices = "SETTINGS (*.settings)|*.settings" thisdir = ''.join(os.getcwd()+'/data') # import output file dlg = wx.FileDialog(self, message='Import option prices and greeks (Outputs)', defaultDir = thisdir, defaultFile='data.settings', wildcard=file_choices, style=wx.OPEN) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() projectDir = path.rsplit('/', 1)[0] #projectDir = path.rsplit('\\', 1)[0] self.reInitialiseData() # this also involves reading in all the data self.number_bumps = self.fileReader.loadSettingsFile(path, projectDir, self.statusbar) print('Opened settings file at %s' % path) else: dlg = wx.MessageDialog(self, "Failed to import the correct settings file.", "Complication", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return # populate data self.strike_price = self.fileReader.getStrikePrice() self.stock_price = self.fileReader.getStockPrice() self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), self.vegaCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked()) self.onBasicView() def onExit(self,event=None): dlg = wx.MessageDialog(None, 'Are you sure to exit?', 'Confirm', wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION) ret = dlg.ShowModal() if ret == wx.ID_YES: self.Destroy() """ GUI event methods """ def onShowFillEffect(self, event=None): if self.fillCheck.IsChecked(): if self.differenceCheck.IsChecked(): self.differenceCheck.SetValue(False) # reload and replot data self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.viewFill = True else: self.viewFill = False self.Plot_Data() def onCallRadio(self, event=None): self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onPutRadio(self, event=None): self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onOptionPrice(self, event=None): self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.Plot_Data() def onDelta(self, event=None): self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onGamma(self, event=None): self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onRho(self, event=None): self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onTheta(self, event=None): self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onVega(self, event=None): self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onRisidual(self, event=None): self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # print(self.risidual) self.Plot_Data() def onShowEffects(self, event=None): if not self.effectCheck.IsChecked(): warning_msg = """ This setting will plot the value of the greeks, but not terms of the option price. This means that the greek graphs will no-longer be comparable. You will still be able to plot the greeks against each other though. Do you want to continue? """ dlg = wx.MessageDialog(self, warning_msg, "Take Note", wx.YES_NO | wx.ICON_INFORMATION) ret = dlg.ShowModal() if ret == wx.ID_NO: dlg.Destroy() self.effectCheck.SetValue(True) return dlg.Destroy() self.differenceCheck.Disable() self.fillCheck.Disable() self.optionPriceCheck.SetValue(False) self.onOptionPrice() self.optionPriceCheck.Disable() else: self.differenceCheck.Enable() self.optionPriceCheck.Enable() if self.current_view != 2: self.fillCheck.Enable() # reload and replot data self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onDifferenceCheck(self, event=None): if self.fillCheck.IsChecked(): self.fillCheck.SetValue(False) self.viewFill = False # reload and replot data self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onStockSlider(self, event=None): self.statusbar.SetStatusText("Stock price bump: "+str(self.stockSlider.GetValue())) self.stock_bump = self.stockSlider.GetValue()-1 self.Plot_Data() def onRateSlider(self, event=None): self.statusbar.SetStatusText("Interest Rate bump: "+str(self.rateSlider.GetValue())) self.rate_bump = self.rateSlider.GetValue()-1 self.Plot_Data() def onVolatilSlider(self, event=None): self.statusbar.SetStatusText("Volatility bump: "+str(self.volatilSlider.GetValue())) self.volitile_bump = self.volatilSlider.GetValue()-1 self.Plot_Data() def ontimeStepSlider(self, event=None): self.statusbar.SetStatusText("Time step bump: "+str(self.timeStepSlider.GetValue())) self.time_bump = self.timeStepSlider.GetValue()-1 self.Plot_Data() self.Plot_Data() """ Graph plotting methods """ def clearPlots(self): """ Clear all graphs and plots for next draw """ for a in self.fig.axes: self.fig.delaxes(a) def Plotter_2D_general(self, axes): # plot option price graph temp_option_price = [] if len(self.option_price) > 0: temp_option_price = numpy.array(map(float, self.option_price[self.stock_bump])) if len(self.option_price) > 0: axes.plot(self.time, self.option_price[self.stock_bump], color='black') # stagger plot effects of greeks temp_delta = [] temp_gamma = [] temp_theta = [] temp_rho = [] temp_risidual = [] if len(self.delta) > 0: temp_delta = numpy.array(self.delta[self.stock_bump]) if len(self.gamma) > 0: temp_gamma = numpy.array(self.gamma[self.stock_bump]) if len(self.rho) > 0: temp_rho = numpy.array(self.rho[self.rate_bump]) if len(self.theta) > 0: temp_theta = numpy.array(self.theta[self.time_bump]) if len(self.risidual) > 0: temp_risidual = numpy.array(self.risidual[self.stock_bump]) if not self.differenceCheck.IsChecked() and len(temp_option_price) > 0: for t in self.time: greeks_below = [] greeks_above = [] # above/below option price if t < 30: # sort arrays if len(temp_delta) > 0: if temp_delta[t+1] > temp_option_price[t+1]: greeks_above.append([temp_delta[t:t+2], 'delta']) else: greeks_below.append([temp_delta[t:t+2], 'delta']) if len(temp_gamma) > 0: if temp_gamma[t+1] > temp_option_price[t+1]: greeks_above.append([temp_gamma[t:t+2], 'gamma']) else: greeks_below.append([temp_gamma[t:t+2], 'gamma']) if len(temp_theta) > 0: if temp_theta[t+1] > temp_option_price[t+1]: greeks_above.append([temp_theta[t:t+2], 'theta']) else: greeks_below.append([temp_theta[t:t+2], 'theta']) if len(temp_rho) > 0: if temp_rho[t+1] > temp_option_price[t+1]: greeks_above.append([temp_rho[t:t+2], 'rho']) else: greeks_below.append([temp_rho[t:t+2], 'rho']) if len(temp_risidual) > 0: if temp_risidual[t+1] > temp_option_price[t+1]: greeks_above.append([temp_risidual[t:t+2], 'risidual']) else: greeks_below.append([temp_risidual[t:t+2], 'risidual']) temp_time = numpy.arange(t, t+2, 1) greeks_above = sorted(greeks_above, key=lambda tup: tup[0][1]) greeks_below = sorted(greeks_below, key=lambda tup: tup[0][1], reverse=True) # PLOT stagger greek effects temp_time = numpy.arange(t, t+2, 1) temp1 = numpy.array(temp_option_price[t:t+2]) # print(t, greeks_below, greeks_above) for g in greeks_above: # print(t) temp2 = numpy.array([temp_option_price[t], g[0][1]]) if self.viewFill and len(self.option_price) > 0: if g[1] == 'delta': axes.fill_between(temp_time, temp2, temp1, color='blue') if g[1] == 'gamma': axes.fill_between(temp_time, temp2, temp1, color='cyan') if g[1] == 'theta': axes.fill_between(temp_time, temp2, temp1, color='green') if g[1] == 'rho': axes.fill_between(temp_time, temp2, temp1, color='darkorange') if g[1] == 'risidual': axes.fill_between(temp_time, temp2, temp1, color='purple') if g[1] == 'delta': axes.plot(temp_time, temp2, label="Delta", color='blue') if g[1] == 'gamma': axes.plot(temp_time, temp2, label="Gamma", color='cyan') if g[1] == 'theta': axes.plot(temp_time, temp2, label="Theta", color='green') if g[1] == 'rho': axes.plot(temp_time, temp2, label="Rho", color='darkorange') if g[1] == 'risidual': axes.plot(temp_time, temp2, label="risidual", color='purple') temp1 = temp2 temp1 = numpy.array(temp_option_price[t:t+2]) for g in greeks_below: temp2 = numpy.array([temp_option_price[t], g[0][1]]) if self.viewFill and len(self.option_price) > 0: if g[1] == 'delta': axes.fill_between(temp_time, temp2, temp1, color='blue') if g[1] == 'gamma': axes.fill_between(temp_time, temp2, temp1, color='cyan') if g[1] == 'theta': axes.fill_between(temp_time, temp2, temp1, color='green') if g[1] == 'rho': axes.fill_between(temp_time, temp2, temp1, color='darkorange') if g[1] == 'risidual': axes.fill_between(temp_time, temp2, temp1, color='purple') if g[1] == 'delta': axes.plot(temp_time, temp2, label="Delta", color='blue') if g[1] == 'gamma': axes.plot(temp_time, temp2, label="Gamma", color='cyan') if g[1] == 'theta': axes.plot(temp_time, temp2, label="Theta", color='green') if g[1] == 'rho': axes.plot(temp_time, temp2, label="Rho", color='darkorange') if g[1] == 'risidual': axes.plot(temp_time, temp2, label="risidual", color='purple') temp1 = temp2 else: # plot difference between greeks and option price if len(self.delta) > 0: axes.plot(self.delta[self.stock_bump], color='blue') if len(self.gamma) > 0: axes.plot(self.gamma[self.stock_bump], color='cyan') # if len(self.vega) > 0: # axes.plot(self.vega[self.volitile_bump], label="Vega", color='yellow') if len(self.theta) > 0: axes.plot(self.time, self.theta[self.time_bump], color='green') if len(self.rho) > 0: axes.plot(self.time, self.rho[self.rate_bump], color='darkorange') if len(self.risidual) > 0: axes.plot(self.time, self.risidual[self.stock_bump], color='purple') if self.viewLegend: # use proxy artist plot_op = Line2D([], [], linewidth=3, color="black") plot_delta = Line2D([], [], linewidth=3, color="royalblue") plot_gamma = Line2D([], [], linewidth=3, color="cyan") plot_theta = Line2D([], [], linewidth=3, color="green") plot_rho = Line2D([], [], linewidth=3, color="darkorange") plot_risidual = Line2D([], [], linewidth=3, color="purple") # Shink current axis by 15% box = axes.get_position() axes.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'], loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) def Plot_Data(self): if self.current_view == 1: self.Plot_Data_advanced() elif self.current_view == 2: self.Plot_Data_3D() elif self.current_view == 0: """ Basic 2D graph plotter """ self.clearPlots() self.axes = self.fig.add_subplot(111) # can use add_axes, but then nav-toolbar would not work self.axes.set_xlim(0, 30) self.axes.grid(self.viewGrid) self.Plotter_2D_general(self.axes) # set caption and axes labels self.axes.set_xlabel('Time (Daily)') if self.effectCheck.IsChecked(): self.axes.set_ylabel('Price (Rands)') if hasattr(self, 'title'): self.title.set_text('Option Prices and breakdown of the effects of Greeks') else: self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks') else: self.axes.set_ylabel('Greek Value') if hasattr(self, 'title'): self.title.set_text('Raw Greek values not in terms of option price') else: self.title = self.fig.suptitle('Greek values not in terms of option price') self.canvas.draw() def Plot_Data_advanced(self): """ Advanced 2D plotter """ self.clearPlots() self.axes2 = self.fig.add_subplot(212) self.axes = self.fig.add_subplot(211, sharex=self.axes2) self.axes.set_xlim(0, 30) self.axes.grid(self.viewGrid) self.axes2.grid(self.viewGrid) self.Plotter_2D_general(self.axes) # plot strike price and stock price curve if self.strike_price > 0: self.axes2.plot([0, 30], [self.strike_price, self.strike_price], label="Strike Price", color='red') # plot stock price curve temp_stock_price = numpy.array(self.stock_price) if len(temp_stock_price) > 0: self.axes2.plot(self.time, temp_stock_price, label="Stock Price", color='blue') # set limits for x and y axes # self.axes2.set_xlim(self.time_span_fill[0], self.time_span_fill[-1]) # self.axes2.set_ylim(min(p, key=float), max(p, key=float)) # set caption and axes labels self.axes2.set_xlabel('Time (Daily)') self.axes2.set_ylabel('Price (Rands)') if self.effectCheck.IsChecked(): self.axes.set_ylabel('Price (Rands)') if hasattr(self, 'title'): self.title.set_text('Option Prices and breakdown of the effects of Greeks') else: self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks') else: self.axes.set_ylabel('Greek Value') if hasattr(self, 'title'): self.title.set_text('Raw Greek values not in terms of option price') else: self.title = self.fig.suptitle('Greek values not in terms of option price') # set useblit True on gtkagg for enhanced performance # self.span = SpanSelector(self.axes, self.onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) if self.viewLegend: # Shink current axis by 15% box = self.axes2.get_position() self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) self.canvas.draw() def Plot_Data_3D(self): """ Advanced 3D plotter """ # plot graphs self.clearPlots() self.axes = self.fig.add_subplot(111, projection='3d') # can use add_axes, but then nav-toolbar would not work self.axes.grid(self.viewGrid) b = numpy.arange(0, 9, 1) X2D, Y2D = numpy.meshgrid(self.time, b) Z2D = None # plot option price surface if len(self.option_price) > 0: Z2D = [[float(string) for string in inner] for inner in self.option_price] surf = self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, cmap=cm.afmhot, zorder=0.5) #cm.coolwarm, cm.winter, cm.autumn cbar = self.fig.colorbar(surf, shrink=0.5, aspect=5) cbar.set_label('Option Price', rotation=90) ### TODO - mayavi ### # X2D, Y2D = numpy.mgrid[self.time, b] # print(X2D) # s = mlab.surf(Z2D) # mlab.show() # plot greek surfaces if len(self.delta) > 0: Z2D = [[float(string) for string in inner] for inner in self.delta] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='blue') if len(self.gamma) > 0: Z2D = [[float(string) for string in inner] for inner in self.gamma] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='cyan') if len(self.theta) > 0: Z2D = [[float(string) for string in inner] for inner in self.theta] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='green') if len(self.rho) > 0: Z2D = [[float(string) for string in inner] for inner in self.rho] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='orange') # if len(self.vega) > 0: # Z2D = [[float(string) for string in inner] for inner in self.vega] # self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, # antialiased=False, alpha=0.75, color='aqua') if len(self.risidual) > 0: Z2D = [[float(string) for string in inner] for inner in self.risidual] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='rosybrown') if Z2D != None: # cset1 = self.axes.contourf(X2D, Y2D, Z2D, zdir='z', offset=300, cmap=cm.afmhot) self.axes.contourf(X2D, Y2D, Z2D, zdir='x', offset=0, cmap=cm.coolwarm) self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=-0.3, cmap=cm.winter) # cset = self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=10, cmap=cm.afmhot) # cbar = self.fig.colorbar(cset1, shrink=0.7, aspect=3) # cbar = self.fig.colorbar(cset2, shrink=0.7, aspect=3) # cbar = self.fig.colorbar(cset3, shrink=0.5, aspect=5) # cbar.set_label('Option Proce', rotation=90) # set captions and axis labels self.axes.set_xlabel('Time (Days)') self.axes.set_xlim(0, 35) self.axes.set_ylabel('Bump Size') #~ self.axes.set_ylim(-3, 8) # self.axes.set_zlabel('Price (Rands)') # ~ self.axes.set_zlim(-100, 100) if self.effectCheck.IsChecked(): if self.differenceCheck.IsChecked(): self.axes.set_zlabel('Greek Value') else: self.axes.set_zlabel('Price (Rands)') if hasattr(self, 'title'): self.title.set_text('Option Prices and breakdown of the effects of Greeks') else: self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks') else: self.axes.set_zlabel('Greek Value') if hasattr(self, 'title'): self.title.set_text('Raw Greek values not in terms of option price') else: self.title = self.fig.suptitle('Greek values not in terms of option price') self.canvas.draw()
class Spectra(ttk.Frame): def __init__(self, parent): super().__init__(parent) self.parent = parent self.grid(column=0, row=0, sticky='nwse') tk.Grid.columnconfigure(self, 1, weight=1) tk.Grid.rowconfigure(self, 8, weight=1) # Spectra name s_name_frame = ttk.LabelFrame(self, text="Spectra type:") s_name_frame.grid(column=0, row=0) self.s_name = tk.StringVar() self.s_name_radio = {} names = 'IR UV Raman VCD ECD ROA'.split(' ') values = 'ir uv raman vcd ecd roa'.split(' ') positions = [(c, r) for c in range(2) for r in range(3)] for n, v, (c, r) in zip(names, values, positions): b = ttk.Radiobutton(s_name_frame, text=n, variable=self.s_name, value=v, command=lambda v=v: self.spectra_chosen(v)) b.configure(state='disabled') b.grid(column=c, row=r, sticky='w', padx=5) self.s_name_radio[v] = b # Settings sett = ttk.LabelFrame(self, text="Settings:") sett.grid(column=0, row=1, sticky='we') tk.Grid.columnconfigure(sett, (1, 2), weight=1) ttk.Label(sett, text='Fitting').grid(column=0, row=0) fit = tk.StringVar() self.fitting = ttk.Combobox(sett, textvariable=fit, state='disabled', width=13) self.fitting.bind('<<ComboboxSelected>>', self.live_preview_callback) self.fitting.var = fit self.fitting.grid(column=1, row=0, columnspan=2, sticky='e') self.fitting['values'] = ('lorentzian', 'gaussian') guicom.WgtStateChanger.bars.append(self.fitting) for no, name in enumerate( 'Start Stop Step Width Offset Scaling'.split(' ')): ttk.Label(sett, text=name).grid(column=0, row=no + 1) var = tk.StringVar() entry = ttk.Entry(sett, textvariable=var, width=10, state='disabled', validate='key', validatecommand=self.parent.validate_entry) entry.bind('<FocusOut>', lambda e, var=var: (self.parent.entry_out_validation(var), self.live_preview_callback())) setattr(self, name.lower(), entry) entry.var = var entry.grid(column=1, row=no + 1, sticky='e') unit = tk.StringVar() unit.set('-') entry.unit = unit label = ttk.Label(sett, textvariable=unit) label.grid(column=2, row=no + 1, sticky='e') guicom.WgtStateChanger.bars.append(entry) # Calculation Mode self.mode = tk.StringVar() self.single_radio = ttk.Radiobutton(self, text='Single file', variable=self.mode, value='single', state='disabled', command=self.mode_chosen) self.single_radio.grid(column=0, row=2, sticky='w') self.average_radio = ttk.Radiobutton(self, text='Average by energy', variable=self.mode, value='average', state='disabled', command=self.mode_chosen) self.average_radio.grid(column=0, row=3, sticky='w') self.stack_radio = ttk.Radiobutton(self, text='Stack by overview', variable=self.mode, value='stack', state='disabled', command=self.mode_chosen) self.stack_radio.grid(column=0, row=4, sticky='w') self.single = tk.StringVar() self.single.set('Choose conformer...') self.single_box = ttk.Combobox(self, textvariable=self.single, state='disabled') self.single_box.bind( '<<ComboboxSelected>>', lambda event: self.live_preview_callback(event, mode='single')) # self.single_box.grid(column=0, row=3) self.single_box['values'] = () self.average = tk.StringVar() self.average.set('Choose energy...') self.average_box = ttk.Combobox(self, textvariable=self.average, state='disabled') self.average_box.bind( '<<ComboboxSelected>>', lambda event: self.live_preview_callback(event, mode='average')) # self.average_box.grid(column=0, row=5) average_names = 'Thermal Enthalpy Gibbs SCF Zero-Point'.split(' ') self.average_box['values'] = average_names average_keys = 'ten ent gib scf zpe'.split(' ') self.average_ref = {k: v for k, v in zip(average_names, average_keys)} self.stack = tk.StringVar() self.stack.set('Choose colour...') self.stack_box = ttk.Combobox(self, textvariable=self.stack, state='disabled') self.stack_box.bind('<<ComboboxSelected>>', self.change_colour) # self.stack_box.grid(column=0, row=7) self.stack_box['values'] = ('Blues Reds Greens spring summer autumn ' 'winter copper ocean rainbow ' 'nipy_spectral gist_ncar'.split(' ')) guicom.WgtStateChanger.bars.extend([ self.single_radio, self.single_box, self.stack_radio, self.stack_box ]) guicom.WgtStateChanger.both.extend( [self.average_radio, self.average_box]) self.boxes = dict(single=self.single_box, average=self.average_box, stack=self.stack_box) self.current_box = None # Live preview # Recalculate frame = ttk.Frame(self) frame.grid(column=0, row=8, sticky='n') var = tk.BooleanVar() var.set(False) self.reverse_ax = ttk.Checkbutton(frame, variable=var, text='Reverse x-axis', state='disabled', command=self.live_preview_callback) self.reverse_ax.grid(column=0, row=0, sticky='w') self.reverse_ax.var = var var = tk.BooleanVar() var.set(True) self.show_bars = ttk.Checkbutton(frame, variable=var, text='Show bars', state='disabled', command=self.live_preview_callback) self.show_bars.grid(column=0, row=1, sticky='w') self.show_bars.var = var self.show_bars.previous_value = True var = tk.BooleanVar() var.set(False) self.show_exp = ttk.Checkbutton(frame, variable=var, text='Experimental', state='disabled', command=self.live_preview_callback) self.show_exp.grid(column=0, row=2, sticky='w') self.show_exp.var = var self.load_exp = ttk.Button( frame, text='Load...', state='disabled', command=lambda: (self.load_exp_command(), self.live_preview_callback())) self.load_exp.grid(column=1, row=2) var = tk.BooleanVar() var.set(True) self.live_prev = ttk.Checkbutton(frame, variable=var, text='Live preview', state='disabled') self.live_prev.grid(column=0, row=3, sticky='w') self.live_prev.var = var # previously labeled 'Recalculate' self.recalc_b = ttk.Button(frame, text='Redraw', state='disabled', command=self.recalculate_command) self.recalc_b.grid(column=1, row=3) guicom.WgtStateChanger.bars.extend([self.live_prev, self.recalc_b]) # Spectrum spectra_view = ttk.LabelFrame(self, text='Spectra view') spectra_view.grid(column=1, row=0, rowspan=10, sticky='nwse') tk.Grid.columnconfigure(spectra_view, 0, weight=1) tk.Grid.rowconfigure(spectra_view, 0, weight=1) self.figure = Figure() # ensure proper plot resizing self.bind('<Configure>', lambda event: self.figure.tight_layout()) self.canvas = FigureCanvasTkAgg(self.figure, master=spectra_view) # self.canvas.draw() self.canvas.get_tk_widget().grid(column=0, row=0, sticky='nwse') self.tslr_ax = None self.bars_ax = None self.exp_ax = None self.last_used_settings = { name: { 'offset': 0, 'scaling': 1, 'show_bars': True, 'show_exp': False, 'reverse_ax': name not in ('uv', 'ecd') } for name in self.s_name_radio } self._exp_spc = {k: None for k in self.s_name_radio.keys()} # TO DO: # add save/save img buttons @property def exp_spc(self): return self._exp_spc[self.s_name.get()] @exp_spc.setter def exp_spc(self, value): self._exp_spc[self.s_name.get()] = value def load_exp_command(self): filename = askopenfilename( parent=self, title='Select spectrum file.', filetypes=[ ("text files", "*.txt"), ("xy files", "*.xy"), # ("spc files", "*.spc"), # spc not supported yet ("all files", "*.*") ]) if filename: try: spc = self.parent.tslr.soxhlet.load_spectrum(filename) self.exp_spc = spc except ValueError: logger.warning( "Experimental spectrum couldn't be loaded. " "Please check if format of your file is supported" " or if file is not corrupted.") else: return def mode_chosen(self, event=None): mode = self.mode.get() if self.current_box is not None: self.current_box.grid_forget() self.current_box = self.boxes[mode] self.current_box.grid(column=0, row=5) if mode == 'single': self.show_bars.config(state='normal') self.show_bars.var.set(self.show_bars.previous_value) else: self.show_bars.config(state='disabled') self.show_bars.previous_value = self.show_bars.var.get() self.show_bars.var.set(False) self.live_preview_callback() def spectra_chosen(self, event=None): tslr = self.parent.tslr self.visualize_settings() bar = tesliper.gw.default_spectra_bars[self.s_name.get()] self.single_box['values'] = [ k for k, v in tslr.molecules.items() if bar in v ] self.reverse_ax.config(state='normal') self.load_exp.config(state='normal') self.show_exp.config(state='normal') if self.mode.get(): self.live_preview_callback() else: self.single_radio.invoke() def visualize_settings(self): spectra_name = self.s_name.get() spectra_type = tesliper.gw.Bars.spectra_type_ref[spectra_name] tslr = self.parent.tslr last_used = self.last_used_settings[spectra_name] settings = tslr.parameters[spectra_type].copy() settings.update(last_used) for name, sett in settings.items(): if name == 'fitting': try: self.fitting.var.set(settings['fitting'].__name__) except AttributeError: self.fitting.var.set(settings['fitting']) else: entry = getattr(self, name) entry.var.set(sett) try: entry.unit.set( tesliper.gw.Spectra._units[spectra_name][name]) except AttributeError: logger.debug(f"Pass on {name}") except KeyError: if name == 'offset': entry.unit.set( tesliper.gw.Spectra._units[spectra_name]['start']) elif name == 'scaling': pass else: raise ValueError(f'Invalid setting name: {name}') def live_preview_callback(self, event=None, mode=False): # TO DO: separate things, that don't need recalculation # TO DO: show/hide bars/experimental plots when checkbox clicked # TO DO: rewrite this function with sense spectra_name = self.s_name.get() mode_con = self.mode.get() == mode if mode else True settings_con = spectra_name not in self.last_used_settings or \ self.current_settings != self.last_used_settings[spectra_name] core = any([not self.tslr_ax, mode_con, settings_con]) if all([core, self.live_prev.var.get(), self.mode.get()]): # self.mode.get() unnecessary because included in mode_con? self.recalculate_command() def new_plot(self): if self.tslr_ax: self.figure.delaxes(self.tslr_ax) self.tslr_ax = None if self.bars_ax: self.figure.delaxes(self.bars_ax) self.bars_ax = None if self.exp_ax: self.figure.delaxes(self.exp_ax) self.exp_ax = None def align_axes(self, axes, values): """Align zeros of the axes, zooming them out by same ratio""" # based on https://stackoverflow.com/a/46901839 if not len(values) == len(axes): raise ValueError( f"Number of values ({len(values)}) different than number of" f"axes ({len(axes)}).") extrema = [[min(v), max(v)] for v in values] # upper and lower limits lowers, uppers = zip(*extrema) all_positive = min(lowers) > 0 all_negative = max(uppers) < 0 # reset for divide by zero issues lowers = [1 if math.isclose(l, 0.0) else l for l in lowers] uppers = [-1 if math.isclose(u, 0.0) else u for u in uppers] # pick "most centered" axis res = [abs(u + l) for l, u in zip(lowers, uppers)] min_index = res.index(min(res)) # scale positive or negative part multiplier1 = -abs(uppers[min_index] / lowers[min_index]) multiplier2 = -abs(lowers[min_index] / uppers[min_index]) lower_lims, upper_lims = [], [] for i, (low, up) in enumerate(extrema): # scale positive or negative part based on which induces valid if i != min_index: lower_change = up * multiplier2 upper_change = low * multiplier1 if upper_change < up: lower_lims.append(lower_change) upper_lims.append(up) else: lower_lims.append(low) upper_lims.append(upper_change) else: lower_lims.append(low) upper_lims.append(up) # bump by 10% for a margin if all_positive: lower_lims = [0 for _ in range(len(lower_lims))] if all_negative: upper_lims = [0 for _ in range(len(upper_lims))] diff = [abs(u - l) for l, u in zip(lower_lims, upper_lims)] margin = [x * .05 for x in diff] lower_lims = [lim - m for lim, m in zip(lower_lims, margin)] upper_lims = [lim + m for lim, m in zip(upper_lims, margin)] # set axes limits [ ax.set_ylim(low, up) for ax, low, up in zip(axes, lower_lims, upper_lims) ] def show_spectra(self, spc, bars=None, colour=None, width=0.5, stack=False): # TO DO: correct spectra drawing when offset used spc.offset = float(self.offset.var.get()) spc.scaling = float(self.scaling.var.get()) self.new_plot() self.tslr_ax = tslr_ax = self.figure.add_subplot(111) tslr_ax.set_xlabel(spc.units['x']) tslr_ax.set_ylabel(spc.units['y']) tslr_ax.hline = tslr_ax.axhline(color='lightgray', lw=width) if stack: col = cm.get_cmap(colour) no = len(spc.y) x = spc.x for num, y_ in enumerate(spc.y): tslr_ax.plot(x, y_, lw=width, color=col(num / no)) else: tslr_ax.plot(spc.x, spc.y, lw=width, color='k') values = [spc.y] axes = [tslr_ax] if self.show_bars.var.get() and bars is not None: self.bars_ax = bars_ax = tslr_ax.twinx() freqs = bars.wavelengths[0] if spc.genre in ('uv', 'ecd') \ else bars.frequencies[0] freqs = freqs + spc.offset # show only bars within range requested in calculations blade = (freqs >= min(spc.x)) & (freqs <= max(spc.x)) markerline, stemlines, baseline = bars_ax.stem( freqs[blade], bars.values[0][blade], linefmt='b-', markerfmt=' ', basefmt=' ') for line in stemlines: line.set_linewidth(width) bars_ax.set_ylabel(bars.units) bars_ax.tick_params(axis='y', colors='b') values.append(bars.values[0]) axes.append(bars_ax) if self.show_exp.var.get() and self.exp_spc is not None: maxes = [max(self.exp_spc[1]), max(spc.y)] if min(maxes) / max(maxes) > 0.4: # if both will fit fine in one plot tslr_ax.plot(*self.exp_spc, lw=width, color='r') values[0] = maxes + [min(self.exp_spc[1]), min(spc.y)] else: self.exp_ax = exp_ax = tslr_ax.twinx() exp_ax.plot(*self.exp_spc, lw=width, color='r') exp_ax.spines["left"].set_position(("axes", -0.1)) exp_ax.spines["left"].set_visible(True) exp_ax.yaxis.set_ticks_position('left') exp_ax.tick_params(axis='y', colors='r') tslr_ax.yaxis.set_label_coords(-0.17, 0.5) # tslr_ax.tick_params(axis='y', colors='navy') values.append(self.exp_spc[1]) axes.append(exp_ax) self.align_axes(axes, values) if self.reverse_ax.var.get(): tslr_ax.invert_xaxis() self.figure.tight_layout() self.canvas.draw() def average_draw(self, spectra_name, option): # TO DO: ensure same conformers are taken into account self._calculate_spectra(spectra_name, option, 'average') queue_ = self.parent.thread.queue self._show_spectra(queue_) def single_draw(self, spectra_name, option): self._calculate_spectra(spectra_name, option, 'single') bar_name = tesliper.gw.default_spectra_bars[spectra_name] with self.parent.tslr.molecules.trimmed_to([option]): bars = self.parent.tslr[bar_name] queue_ = self.parent.thread.queue self._show_spectra(queue_, bars=bars) def stack_draw(self, spectra_name, option): # TO DO: color of line depending on population self._calculate_spectra(spectra_name, option, 'stack') if self.tslr_ax: self.figure.delaxes(self.tslr_ax) self.tslr_ax = self.figure.add_subplot(111) queue_ = self.parent.thread.queue self._show_spectra(queue_, colour=option, stack=True) def change_colour(self, event=None): if not self.tslr_ax or self.mode.get() != 'stack': return colour = self.stack.get() col = cm.get_cmap(colour) self.tslr_ax.hline.remove() lines = self.tslr_ax.get_lines() no = len(lines) for num, line in enumerate(lines): line.set_color(col(num / no)) self.tslr_ax.hline = self.tslr_ax.axhline(color='lightgray', lw=0.5) self.canvas.draw() def _show_spectra(self, queue_, bars=None, colour=None, width=0.5, stack=False): try: spc = queue_.get(0) # data put to queue by self._calculate_spectra self.show_spectra(spc, bars=bars, colour=colour, width=width, stack=stack) except queue.Empty: self.after(20, self._show_spectra, queue_, bars, colour, width, stack) @guicom.Feedback("Calculating...") def _calculate_spectra(self, spectra_name, option, mode): tslr = self.parent.tslr if mode == 'single': spc = tslr.calculate_single_spectrum(spectra_name=spectra_name, conformer=option, **self.calculation_params) else: spc = tslr.calculate_spectra( spectra_name, **self.calculation_params)[ spectra_name] # tslr.calculate_spectra returns dictionary if mode == 'average': en_name = self.average_ref[option] spc = tslr.get_averaged_spectrum(spectra_name, en_name) return spc @property def calculation_params(self): d = { k: v for k, v in self.current_settings.items() if k in 'start stop step width fitting'.split(' ') } return d @property def current_settings(self): try: settings = { key: float(getattr(self, key).get()) for key in 'start stop step width offset scaling'.split(' ') } settings.update({ key: getattr(self, key).var.get() for key in 'reverse_ax show_bars show_exp'.split(' ') }) fit = self.fitting.get() settings['fitting'] = getattr(tesliper.dw, fit) except ValueError: return {} return settings def recalculate_command(self): spectra_name = self.s_name.get() if not spectra_name: logger.debug('spectra_name not specified.') return self.last_used_settings[spectra_name] = self.current_settings.copy() mode = self.mode.get() # get value of self.single, self.average or self.stack respectively option = getattr(self, mode).get() if option.startswith('Choose '): return logger.debug("Recalculating!") self.new_plot() # call self.single_draw, self.average_draw or self.stack_draw # respectively drawers = { 'single': self.single_draw, 'average': self.average_draw, 'stack': self.stack_draw } spectra_drawer = drawers[mode] spectra_drawer(spectra_name, option)
class PlotView(QtWidgets.QWidget): subplotRemovedSignal = QtCore.Signal(object) plotCloseSignal = QtCore.Signal() def __init__(self): super(PlotView, self).__init__() self.plots = OrderedDict({}) self.errors_list = set() self.plot_storage = {} # stores lines and info to create lines self.current_grid = None self.gridspecs = { 1: gridspec.GridSpec(1, 1), 2: gridspec.GridSpec(1, 2), 3: gridspec.GridSpec(3, 1), 4: gridspec.GridSpec(2, 2) } self.figure = Figure() self.figure.set_facecolor("none") self.canvas = FigureCanvas(self.figure) self.plot_selector = QtWidgets.QComboBox() self._update_plot_selector() self.plot_selector.currentIndexChanged[str].connect(self._set_bounds) button_layout = QtWidgets.QHBoxLayout() self.x_axis_changer = AxisChangerPresenter(AxisChangerView("X")) self.x_axis_changer.on_upper_bound_changed(self._update_x_axis_upper) self.x_axis_changer.on_lower_bound_changed(self._update_x_axis_lower) self.y_axis_changer = AxisChangerPresenter(AxisChangerView("Y")) self.y_axis_changer.on_upper_bound_changed(self._update_y_axis_upper) self.y_axis_changer.on_lower_bound_changed(self._update_y_axis_lower) self.errors = QtWidgets.QCheckBox("Errors") self.errors.stateChanged.connect(self._errors_changed) button_layout.addWidget(self.plot_selector) button_layout.addWidget(self.x_axis_changer.view) button_layout.addWidget(self.y_axis_changer.view) button_layout.addWidget(self.errors) grid = QtWidgets.QGridLayout() self.toolbar = myToolbar(self.canvas, self) self.toolbar.update() grid.addWidget(self.toolbar, 0, 0) grid.addWidget(self.canvas, 1, 0) grid.addLayout(button_layout, 2, 0) self.setLayout(grid) def setAddConnection(self, slot): self.toolbar.setAddConnection(slot) def setRmConnection(self, slot): self.toolbar.setRmConnection(slot) def _redo_layout(func): """ Simple decorator (@_redo_layout) to call tight_layout() on plots and to redraw the canvas. (https://www.python.org/dev/peps/pep-0318/) """ def wraps(self, *args, **kwargs): output = func(self, *args, **kwargs) if len(self.plots): self.figure.tight_layout() self.canvas.draw() return output return wraps def _silent_checkbox_check(self, state): """ Checks a checkbox without emitting a checked event. """ self.errors.blockSignals(True) self.errors.setChecked(state) self.errors.blockSignals(False) def _set_plot_bounds(self, name, plot): """ Sets AxisChanger bounds to the given plot bounds and updates the plot-specific error checkbox. """ self.x_axis_changer.set_bounds(plot.get_xlim()) self.y_axis_changer.set_bounds(plot.get_ylim()) self._silent_checkbox_check(name in self.errors_list) def _set_bounds(self, new_plot): """ Sets AxisChanger bounds if a new plot is added, or removes the AxisChanger fields if a plot is removed. """ new_plot = str(new_plot) if new_plot and new_plot != "All": plot = self.get_subplot(new_plot) self._set_plot_bounds(new_plot, plot) elif not new_plot: self.x_axis_changer.clear_bounds() self.y_axis_changer.clear_bounds() def _get_current_plot_name(self): """ Returns the 'current' plot name based on the dropdown selector. """ return str(self.plot_selector.currentText()) def _get_current_plots(self): """ Returns a list of the current plot, or all plots if 'All' is selected. """ name = self._get_current_plot_name() return self.plots.values() if name == "All" else [ self.get_subplot(name)] @_redo_layout def _update_x_axis(self, bound): """ Updates the plot's x limits with the specified bound. """ try: for plot in self._get_current_plots(): plot.set_xlim(**bound) except KeyError: return def _update_x_axis_lower(self, bound): """ Updates the lower x axis limit. """ self._update_x_axis({"left": bound}) def _update_x_axis_upper(self, bound): """ Updates the upper x axis limit. """ self._update_x_axis({"right": bound}) @_redo_layout def _update_y_axis(self, bound): """ Updates the plot's y limits with the specified bound. """ try: for plot in self._get_current_plots(): plot.set_ylim(**bound) except KeyError: return def _update_y_axis_lower(self, bound): """ Updates the lower y axis limit. """ self._update_y_axis({"bottom": bound}) def _update_y_axis_upper(self, bound): """ Updates the upper y axis limit. """ self._update_y_axis({"top": bound}) def _modify_errors_list(self, name, state): """ Adds/Removes a plot name to the errors set depending on the 'state' bool. """ if state: self.errors_list.add(name) else: try: self.errors_list.remove(name) except KeyError: return def _change_plot_errors(self, name, plot, state): """ Removes the previous plot and redraws with/without errors depending on the state. """ self._modify_errors_list(name, state) # get a copy of all the workspaces workspaces = copy(self.plot_storage[name].ws) # get the limits before replotting, so they appear unchanged. x, y = plot.get_xlim(), plot.get_ylim() # clear out the old container self.plot_storage[name].delete() for workspace in workspaces: self.plot(name, workspace) plot.set_xlim(x) plot.set_ylim(y) self._set_bounds(name) # set AxisChanger bounds again. @_redo_layout def _errors_changed(self, state): """ Replots subplots with errors depending on the current selection. """ current_name = self._get_current_plot_name() if current_name == "All": for name, plot in iteritems(self.plots): self._change_plot_errors(name, plot, state) else: self._change_plot_errors( current_name, self.get_subplot(current_name), state) def _set_positions(self, positions): """ Moves all subplots based on a gridspec change. """ for plot, pos in zip(self.plots.values(), positions): grid_pos = self.current_grid[pos[0], pos[1]] plot.set_position( grid_pos.get_position( self.figure)) # sets plot position, magic? # required because tight_layout() is used. plot.set_subplotspec(grid_pos) @_redo_layout def _update_gridspec(self, new_plots, last=None): """ Updates the gridspec; adds a 'last' subplot if one is supplied. """ if new_plots: self.current_grid = self.gridspecs[new_plots] positions = putils.get_layout(new_plots) self._set_positions(positions) if last is not None: # label is necessary to fix # https://github.com/matplotlib/matplotlib/issues/4786 pos = self.current_grid[positions[-1][0], positions[-1][1]] self.plots[last] = self.figure.add_subplot(pos, label=last) self.plots[last].set_subplotspec(pos) self._update_plot_selector() def _update_plot_selector(self): """ Updates plot selector (dropdown). """ self.plot_selector.clear() self.plot_selector.addItem("All") self.plot_selector.addItems(list(self.plots.keys())) @_redo_layout def plot(self, name, workspace): """ Plots a workspace to a subplot (with errors, if necessary). """ if name in self.errors_list: self.plot_workspace_errors(name, workspace) else: self.plot_workspace(name, workspace) self._set_bounds(name) def _add_plotted_line(self, name, label, lines, workspace): """ Appends plotted lines to the related subplot list. """ self.plot_storage[name].addLine(label, lines, workspace) def plot_workspace_errors(self, name, workspace): """ Plots a workspace with errors, and appends caps/bars to the subplot list. """ subplot = self.get_subplot(name) line, cap_lines, bar_lines = plots.plotfunctions.errorbar( subplot, workspace, specNum=1) # make a tmp plot to get auto generated legend name tmp, = plots.plotfunctions.plot(subplot, workspace, specNum=1) label = tmp.get_label() # remove the tmp line tmp.remove() del tmp # collect results all_lines = [line] all_lines.extend(cap_lines) all_lines.extend(bar_lines) self._add_plotted_line(name, label, all_lines, workspace) def plot_workspace(self, name, workspace): """ Plots a workspace normally. """ subplot = self.get_subplot(name) line, = plots.plotfunctions.plot(subplot, workspace, specNum=1) self._add_plotted_line(name, line.get_label(), [line], workspace) def get_subplot(self, name): """ Returns the subplot corresponding to a given name """ return self.plots[name] def get_subplots(self): """ Returns all subplots. """ return self.plots def add_subplot(self, name): """ will raise KeyError if: plots exceed 4 """ self._update_gridspec(len(self.plots) + 1, last=name) self.plot_storage[name] = subPlot(name) return self.get_subplot(name) def remove_subplot(self, name): """ will raise KeyError if: 'name' isn't a plot; there are no plots """ self.figure.delaxes(self.get_subplot(name)) del self.plots[name] del self.plot_storage[name] self._update_gridspec(len(self.plots)) self.subplotRemovedSignal.emit(name) def removeLine(self, subplot, label): self.plot_storage[subplot].removeLine(label) @_redo_layout def add_moveable_vline(self, plot_name, x_value, y_minx, y_max, **kwargs): pass @_redo_layout def add_moveable_hline(self, plot_name, y_value, x_min, x_max, **kwargs): pass def closeEvent(self, event): self.plotCloseSignal.emit() def plotCloseConnection(self, slot): self.plotCloseSignal.connect(slot) @property def subplot_names(self): return self.plot_storage.keys() def line_labels(self, subplot): return self.plot_storage[subplot].lines.keys()
class Interact(QtGui.QMainWindow): def __init__(self, data, app, title=None, sortkey=None, axisequal=False, parent=None, **kwargs): self.app = app QtGui.QMainWindow.__init__(self, parent) if title is not None: self.setWindowTitle(title) else: self.setWindowTitle(', '.join(d[1] for d in data)) if sortkey is not None: self.sortkey = sortkey else: self.sortkey = kwargs.get('key', lambda x: x.lower()) self.grid = QtGui.QGridLayout() self.frame = QtGui.QWidget() self.dpi = 100 self.fig = Figure(tight_layout=True) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.frame) self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus) self.canvas.mpl_connect('key_press_event', self.canvas_key_press) self.axes = self.fig.add_subplot(111) self.axes2 = self.axes.twinx() self.fig.delaxes(self.axes2) self.xlim = None self.ylim = None self.xlogscale = 'linear' self.ylogscale = 'linear' self.axisequal = axisequal self.margins = 0 self.mpl_toolbar = NavigationToolbar(self.canvas, self.frame) self.pickers = None self.vbox = QtGui.QVBoxLayout() self.vbox.addWidget(self.mpl_toolbar) self.props_editor = PropertyEditor(self) self.datas = [] for d in data: self.add_data(*d) self.vbox.addLayout(self.grid) self.set_layout() def set_layout(self): self.vbox.addWidget(self.canvas) self.frame.setLayout(self.vbox) self.setCentralWidget(self.frame) for data in self.datas: self.setTabOrder(data.menu, data.scale_box) self.setTabOrder(data.scale_box, data.xmenu) self.setTabOrder(data.xmenu, data.xscale_box) if len(self.datas) >= 2: for d1, d2 in zip(self.datas[:-1], self.datas[1:]): self.setTabOrder(d1.menu, d2.menu) self.draw() def add_data(self, obj, name, kwargs=None): kwargs = kwargs or {} kwargs['name'] = kwargs.get('name', name) or 'data' self.datas.append(DataObj(self, obj, **kwargs)) data = self.datas[-1] self.row = self.grid.rowCount() self.column = 0 def axisequal(): self.axisequal = not self.axisequal self.draw() def add_widget(w, axis=None): self.grid.addWidget(w, self.row, self.column) data.widgets.append(w) self.connect(w, SIGNAL('duplicate()'), data.duplicate) self.connect(w, SIGNAL('remove()'), data.remove) self.connect(w, SIGNAL('closed()'), data.close) self.connect(w, SIGNAL('axisequal()'), axisequal) self.connect(w, SIGNAL('relabel()'), data.change_label) self.connect(w, SIGNAL('edit_props()'), data.edit_props) self.connect(w, SIGNAL('sync()'), data.sync) self.connect(w, SIGNAL('twin()'), data.toggle_twin) self.connect(w, SIGNAL('xlim()'), self.set_xlim) self.connect(w, SIGNAL('ylim()'), self.set_ylim) if axis: self.connect(w, SIGNAL('sync_axis()'), lambda axes=[axis]: data.sync(axes)) self.column += 1 add_widget(data.label) add_widget(data.menu, 'y') add_widget(data.scale_label) add_widget(data.scale_box, 'y') add_widget(data.xlabel) add_widget(data.xmenu, 'x') add_widget(data.xscale_label) add_widget(data.xscale_box, 'x') def warn(self, message): self.warnings = [message] self.draw_warnings() self.canvas.draw() def remove_data(self, data): if len(self.datas) < 2: return self.warn("Can't delete last row") index = self.datas.index(data) self.datas.pop(index) for widget in data.widgets: self.grid.removeWidget(widget) widget.deleteLater() if self.props_editor.dataobj is data: self.props_editor.close() self.set_layout() self.draw() self.datas[index - 1].menu.setFocus() self.datas[index - 1].menu.lineEdit().selectAll() def get_scale(self, textbox, completer): completer.close_popup() text = text_type(textbox.text()) try: return eval(text, CONSTANTS.copy()) except Exception as e: self.warnings.append('Error setting scale: ' + text_type(e)) return 1.0 def get_key(self, menu): key = text_type(menu.itemText(menu.currentIndex())) text = text_type(menu.lineEdit().text()) if key != text: self.warnings.append( 'Plotted key (%s) does not match typed key (%s)' % (key, text)) return key @staticmethod def cla(axes): tight, xmargin, ymargin = axes._tight, axes._xmargin, axes._ymargin axes.clear() axes._tight, axes._xmargin, axes._ymargin = tight, xmargin, ymargin def clear_pickers(self): if self.pickers is not None: [p.disable() for p in self.pickers] self.pickers = None def plot(self, axes, data, xname, xscale, yname, yscale, i, label): if xname in data.obj: x = data.obj[xname][..., i] * xscale y = data.obj[yname][..., i] * yscale def plot(y): if xname in data.obj: return axes.plot(x, y, label=label) else: return axes.plot(y, label=label) try: lines = plot(y) except ValueError: lines = plot(y.T) if isinstance(i, slice): i = 0 for line in lines: if hasattr(data, 'cdata'): line.set_color(data.cmap(data.norm(data.cdata[i]))) self.handles[(label,)] = line elif 'color' not in data.props and 'linestyle' not in data.props: style, color = next(self.styles) line.set_color(color) line.set_linestyle(style) self.handles[(label, color, style)] = line elif 'color' not in data.props: line.set_color(color_cycle[i % len(color_cycle)]) self.handles[ (label, line.get_color(), data.props['linestyle'])] = line else: self.handles[ (label, data.props.get('color', line.get_color()), data.props.get('linestyle', line.get_linestyle()))] = line for key, value in data.props.items(): getattr(line, 'set_' + key, lambda _: None)(value) return len(lines) def draw(self): self.mpl_toolbar.home = self.draw twin = any(d.twin for d in self.datas) self.clear_pickers() self.fig.clear() self.axes = self.fig.add_subplot(111) color_data = next((d for d in self.datas if hasattr(d, 'cdata')), None) if color_data and not twin: self.mappable = mpl.cm.ScalarMappable(norm=color_data.norm, cmap=color_data.cmap) self.mappable.set_array(color_data.cdata) self.colorbar = self.fig.colorbar( self.mappable, ax=self.axes, fraction=0.1, pad=0.02) elif twin: self.axes2 = self.axes.twinx() for ax in self.axes, self.axes2: ax._tight = bool(self.margins) if self.margins: ax.margins(self.margins) xlabel = [] ylabel = [] xlabel2 = [] ylabel2 = [] self.warnings = [] self.handles = OrderedDict() self.styles = cycle(product(linestyle_cycle, color_cycle)) for d in self.datas: if d.twin: axes, x, y = self.axes2, xlabel2, ylabel2 else: axes, x, y = self.axes, xlabel, ylabel scale = self.get_scale(d.scale_box, d.scale_compl) xscale = self.get_scale(d.xscale_box, d.xscale_compl) text = self.get_key(d.menu) xtext = self.get_key(d.xmenu) args = axes, d, xtext, xscale, text, scale if isiterable(d.labels): for i, label in enumerate(d.labels): self.plot(*args + (i, label)) else: n = self.plot(*args + (slice(None), d.labels)) if n > 1: d.labels = ['%s %d' % (d.labels, i) for i in range(n)] return self.draw() axes.set_xlabel('') if xtext: x.append(xtext + ' (' + d.name + ')') y.append(text + ' (' + d.name + ')') self.axes.set_xlabel('\n'.join(xlabel)) self.axes.set_ylabel('\n'.join(ylabel)) self.draw_warnings() self.axes2.set_xlabel('\n'.join(xlabel2)) self.axes2.set_ylabel('\n'.join(ylabel2)) self.axes.set_xlim(self.xlim) self.axes.set_ylim(self.ylim) self.axes.set_xscale(self.xlogscale) self.axes.set_yscale(self.ylogscale) for ax in self.axes, self.axes2: ax.set_aspect('equal' if self.axisequal else 'auto', 'box-forced') legend = self.axes.legend(self.handles.values(), [k[0] for k in self.handles.keys()]) legend.draggable(True) self.pickers = [picker(ax) for ax in [self.axes, self.axes2]] self.canvas.draw() def draw_warnings(self): self.axes.text(0.05, 0.05, '\n'.join(self.warnings), transform=self.axes.transAxes, color='red') def canvas_key_press(self, event): key_press_handler(event, self.canvas, self.mpl_toolbar) if event.key == 'ctrl+q': self._close() elif event.key in mpl.rcParams['keymap.home']: self.xlim = self.ylim = None self.draw() elif event.key == 'ctrl+x': self.set_xlim(draw=False) elif event.key == 'ctrl+y': self.set_ylim(draw=False) elif event.key == 'ctrl+l': self.draw() self.xlogscale = self.axes.get_xscale() self.ylogscale = self.axes.get_yscale() def edit_parameters(self): xlim = self.axes.get_xlim() ylim = self.axes.get_ylim() self.mpl_toolbar.edit_parameters() if xlim != self.axes.get_xlim(): self.xlim = self.axes.get_xlim() if ylim != self.axes.get_ylim(): self.ylim = self.axes.get_ylim() self.xlogscale = self.axes.get_xscale() self.ylogscale = self.axes.get_yscale() def _margins(self): self.margins = 0 if self.margins else 0.05 self.draw() def _options(self): self.edit_parameters() def _close(self): self.app.references.discard(self) self.window().close() def _input_lim(self, axis, default): default = text_type(default) if re.match(r'^\(.*\)$', default) or re.match(r'^\[.*\]$', default): default = default[1:-1] text, ok = QtGui.QInputDialog.getText( self, 'Set axis limits', '{} limits:'.format(axis), QtGui.QLineEdit.Normal, default) if ok: try: return eval(text_type(text), CONSTANTS.copy()) except Exception: return None else: return None def set_xlim(self, draw=True): self.xlim = self._input_lim( 'x', self.xlim or self.axes.get_xlim()) if draw: self.draw() def set_ylim(self, draw=True): self.ylim = self._input_lim( 'y', self.ylim or self.axes.get_ylim()) if draw: self.draw() control_actions = { QtCore.Qt.Key_M: _margins, QtCore.Qt.Key_O: _options, QtCore.Qt.Key_Q: _close, } @staticmethod def data_dict(d): kwargs = OrderedDict(( ('name', d.name), ('xname', text_type(d.xmenu.lineEdit().text())), ('xscale', text_type(d.xscale_box.text())), ('yname', text_type(d.menu.lineEdit().text())), ('yscale', text_type(d.scale_box.text())), ('props', d.props), ('labels', d.labels), )) for key in 'xscale', 'yscale': try: kwargs[key] = ast.literal_eval(kwargs[key]) except ValueError: pass else: if float(kwargs[key]) == 1.0: del kwargs[key] if not kwargs['props']: del kwargs['props'] return kwargs def data_dicts(self): return "\n".join(text_type(self.dict_repr(self.data_dict(d))) for d in self.datas) @classmethod def dict_repr(cls, d, top=True): if isinstance(d, dict): return ('{}' if top else 'dict({})').format(', '.join( ['{}={}'.format(k, cls.dict_repr(v, False)) for k, v in d.items()])) elif isinstance(d, string_types): return repr(str(d)) return repr(d) def event(self, event): if (event.type() == QtCore.QEvent.KeyPress and event.modifiers() & CONTROL_MODIFIER and event.key() in self.control_actions): self.control_actions[event.key()](self) return True # Create duplicate of entire GUI with Ctrl+Shift+N elif (event.type() == QtCore.QEvent.KeyPress and event.modifiers() & CONTROL_MODIFIER and event.modifiers() & QtCore.Qt.ShiftModifier and event.key() == QtCore.Qt.Key_N): create(*[[d.obj, d.name, self.data_dict(d)] for d in self.datas]) return True # Print dictionaries of keys and scales for all data with Ctrl+Shift+P elif (event.type() == QtCore.QEvent.KeyPress and event.modifiers() & CONTROL_MODIFIER and event.modifiers() & QtCore.Qt.ShiftModifier and event.key() == QtCore.Qt.Key_P): print(self.data_dicts()) sys.stdout.flush() return True return super(Interact, self).event(event)
class LabRADPlotWidget2(Qt.QWidget): def __init__(self, parent, cxn=None, path=[], dataset=None, toolbar=True, timer=None, settings={}): """ A Qt widget that plots a labrad dataset, using Matplotlib. """ # run qwidget init Qt.QWidget.__init__(self, parent) # create the qt basics self.figure = Figure() self.canvas = FigureCanvas(self.figure) self.canvas.setSizePolicy(Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Expanding) if toolbar: self.toolbar = NavigationToolbar(self.canvas, None) else: self.toolbar = None self.layout = Qt.QVBoxLayout() self.layout.addWidget(self.canvas) if self.toolbar: self.layout.addWidget(self.toolbar) self.setLayout(self.layout) self.groupBoxLayout = Qt.QHBoxLayout() self.layout.addLayout(self.groupBoxLayout) self.makeOptionsBox() self.groupBoxes = [] self.settings = settings # matplotlib variables self.rebuildPlot = False self.subplots = [] self.lines = [] # labrad variables self.path = path self.dataset = dataset # start the labrad connection if cxn is None: import labrad cxnDef = labrad.connectAsync(name=labrad.util.getNodeName() + ' Plot Widget') cxnDef.addCallback(self.setCxn) self.cxn = None else: self.setCxn(cxn) # give us a timer if timer is None: self.updateTimer = Qt.QTimer() self.updateTimer.timeout.connect(self.timerFunc) self.waitingOnLabrad=True self.updateTimer.start(UPDATE_PERIOD * 1000) else: self.updateTimer = timer self.updateTimer.timeout.connect(self.timerFunc) self.waitinOnLabrad=True def makeOptionsBox(self): vl = Qt.QVBoxLayout() self.rescaleCB = Qt.QCheckBox("Autoscale Y-Axis") self.rescaleCB.setChecked(True) vl.addWidget(self.rescaleCB) self.rescaleXCB = Qt.QCheckBox("Autoscale X-Axis") self.rescaleXCB.setChecked(True) vl.addWidget(self.rescaleXCB) l = Qt.QLabel("Minutes to Display") self.minutesToDisplayEdit = Qt.QLineEdit() hl = Qt.QHBoxLayout() hl.addWidget(l); hl.addWidget(self.minutesToDisplayEdit); vl.addLayout(hl) self.tempUnitsCB = Qt.QCheckBox("Temperature in F") self.tempUnitsCB.setChecked(False) vl.addWidget(self.tempUnitsCB) self.hideUncheckedCB = Qt.QCheckBox("Hide unchecked") self.hideUncheckedCB.setChecked(False) self.hideUncheckedCB.toggled.connect(self.hideUncheckedCallback) vl.addWidget(self.hideUncheckedCB) optGB = Qt.QGroupBox("Options") optGB.setCheckable(False) optGB.setLayout(vl) optGB.setSizePolicy(Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Fixed) self.groupBoxLayout.addWidget(optGB, 0, QtCore.Qt.AlignTop) def hideUncheckedCallback(self, toggled): if toggled: for cb in self.checkBoxes: if not cb.isChecked(): cb.setVisible(False) else: for cb in self.checkBoxes: cb.setVisible(True) def setCxn(self, cxn): self.cxn = cxn if self.dataset: self.loadDataset() self.waitingOnLabrad=False def setDataset(self, path=[], dataset=None): if path: self.path = path if dataset: self.dataset = dataset self.loadDataset() def getDataset(self): return self.dataset def loadDataset(self): p = self.cxn.data_vault.packet() p.cd(self.path) p.dir() d = p.send() d.addCallback(self.loadDatasetCallback) def loadDatasetCallback(self, response): dsList = response.dir[1] if type(self.dataset) == str and not self.dataset in dsList: for ds in dsList: if self.dataset in ds: self.dataset = ds break else: # note this else is for the for loop, not the if statement self.dataset = None print "Dataset %s not found!" % self.dataset p = self.cxn.data_vault.packet() p.open(self.dataset) p.send() self.rebuildPlot = True def timerFunc(self): if self.waitingOnLabrad: return if not self.dataset: return p = self.cxn.data_vault.packet() if self.rebuildPlot: p.variables() p.get(1000) d = p.send() d.addCallback(self.datavaultCallback) def datavaultCallback(self, response): if self.rebuildPlot and 'variables' not in response.settings: return elif self.rebuildPlot: for plot in self.subplots: self.figure.delaxes(plot) self.plots = [] self.lines = [] # list of legends self.plotLegends = list(set([x[0] for x in response.variables[1]])) # dict of lists of labels, where plotLabels[legend] = [list of labels for this legend] self.plotLabels = dict(zip(self.plotLegends, [[] for i in range(len(self.plotLegends))])) # dict of lists of units, as above self.plotUnits = dict(zip(self.plotLegends, [[] for i in range(len(self.plotLegends))])) # dict of lists of indices self.plotIndices = dict(zip(self.plotLegends, [[] for i in range(len(self.plotLegends))])) i = 0 for legend, label, unit in response.variables[1]: i += 1 self.plotLabels[legend].append(label) self.plotUnits[legend].append(unit) self.plotIndices[legend].append(i) # list of plots for i in range(len(self.plotLegends)): if i == 0: self.plots.append(self.figure.add_subplot(len(self.plotLegends), 1, i)) else: self.plots.append(self.figure.add_subplot(len(self.plotLegends), 1, i, sharex=self.plots[0])) self.plots[i].set_ylabel(self.plotLegends[i]) plt.setp(self.plots[i].get_xticklabels(), visible=False) self.plotData = response.get if 'xAxisIsTime' in self.settings.keys() and self.settings['xAxisIsTime']: self.plotT0 = self.plotData[0,0] self.plotData[:,0] -= self.plotT0 self.plotData[:,0] /= 60.0 self.xlabel = "Time [min] since %s" % time.strftime('%Y-%b-%d %H:%M', time.localtime(self.plotT0)) else: self.xlabel = '%s [%s]' % response.variables[0][0] # create the lines for i in range(1, self.plotData.shape[1]): plotNum = self.plotLegends.index(response.variables[1][i-1][0]) self.lines.append(self.plots[plotNum].add_line(mp.lines.Line2D(self.plotData[:,0], self.plotData[:,i], label='%s [%s]' % response.variables[1][i-1][1:], color = COLORS[(i-1) % len(COLORS)], marker='o', linestyle='-'))) for plot in self.plots: #plot.legend(prop={'size': 'x-small'}, loc='upper left') plot.autoscale() self.plots[-1].set_xlabel(self.xlabel) self.buildGroupBoxes() self.canvas.draw() self.rebuildPlot = False self.applySettings() else: newdata = response.get if newdata.shape[1] == 0: return if 'xAxisIsTime' in self.settings.keys() and self.settings['xAxisIsTime']: newdata[:,0] -= self.plotT0 newdata[:,0] /= 60.0 self.plotData = np.append(self.plotData, newdata, axis=0) # trim down to appropriate size if self.plotData.shape[0] > MAX_POINTS: self.plotData = self.plotData[(self.plotData.shape[0] - MAX_POINTS):, :] for i in range(1, newdata.shape[1]): line = self.lines[i-1] if self.tempUnitsCB.isChecked() and '[K]' in line.get_label(): line.set_data(self.plotData[:,0], (self.plotData[:,i]-273.15)*1.8 + 32) elif self.tempUnitsCB.isChecked() and '[C]' in line.get_label(): line.set_data(self.plotData[:,0], self.plotData[:,i]*1.8 + 32) else: line.set_data(self.plotData[:,0], self.plotData[:,i]) self.scalePlots() self.canvas.draw() def scalePlots(self): ''' scale the plots to show all the data. only use visible lines. account for absolute limits in settings. ''' for plot, legend in zip(self.plots, self.plotLegends): # determine x max and min xmax, xmin = max(self.plotData[:,0]), min(self.plotData[:,0]) if 'xlimits' in self.settings.keys(): for leg, amin, amax in self.settings['xlimits']: if legend in leg: xmax = min(xmax, amax) xmin = max(xmin, amin) break try: m = float(str(self.minutesToDisplayEdit.text())) if m > 0: xmin = max(xmin, xmax-m) except ValueError: pass # determine y max and min plotIndices = [x for x in self.plotIndices[legend] if self.lines[x-1].get_visible()] if not plotIndices: continue xinds = np.where(np.logical_and(self.plotData[:,0] >= xmin, self.plotData[:,0] <= xmax))[0] ymax, ymin = self.plotData[:,plotIndices][xinds].max(), self.plotData[:,plotIndices][xinds].min() #ymax, ymin = self.plotData[:,plotIndices].max(), self.plotData[:,plotIndices].min() yr = ymax-ymin ymax += yr*0.1 ymin -= yr*0.1 if 'ylimits' in self.settings.keys(): for leg, amin, amax in self.settings['ylimits']: if legend in leg: ymax = min(ymax, amax) ymin = max(ymin, amin) break if self.rescaleXCB.isChecked(): plot.set_xlim(xmax=xmax, xmin=xmin) if self.rescaleCB.isChecked(): plot.set_ylim(ymax=ymax, ymin=ymin) def applySettings(self): ''' apply the plot settings in the settings dict. things like which plots are visible, axis limits, etc.''' if 'activeLines' in self.settings.keys(): for cb in self.checkBoxes: cb.setChecked(False) for al in self.settings['activeLines']: for cb in self.checkBoxes: if al.strip() == str(cb.text()).strip(): cb.setChecked(True) if 'activePlots' in self.settings.keys(): for ap in self.settings['activePlots']: for gb in self.groupBoxes: if ap in str(gb.title()): gb.setChecked(True) else: gb.setChecked(False) gb.leaveEvent(None) self.groupBoxCallback() self.hideUncheckedCB.setChecked(True) self.hideUncheckedCallback(True) #if 'ylimits' in self.settings.keys(): #for name, lim in ylimits: def buildGroupBoxes(self): while True: it = self.groupBoxLayout.takeAt(1) if not it: break self.groupBoxLayout.removeItem(it) self.groupBoxes = [] self.checkBoxes = [] self.checkBoxesToLines = {} for legend in self.plotLegends: vl = Qt.QVBoxLayout() if len(self.plotLabels[legend]) == 1: gb = Qt.QGroupBox("%s (%s)" % (legend, self.plotLabels[legend][0])) else: gb = Qt.QGroupBox(legend) for label in self.plotLabels[legend]: l = self.lines[self.plotIndices[legend][self.plotLabels[legend].index(label)] - 1] cb = Qt.QCheckBox(label) cb.setStyleSheet('QCheckBox {color: %s; font-weight: bold}' % l.get_color()) cb.setChecked(True) cb.toggled.connect(self.checkBoxCallback) vl.addWidget(cb) self.checkBoxes.append(cb) self.checkBoxesToLines[cb] = l gb.setCheckable(True) gb.setChecked(True) gb.setLayout(vl) gb.setSizePolicy(Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Fixed) gb.clicked.connect(self.groupBoxCallback) self.groupBoxes.append(gb) self.groupBoxLayout.addWidget(gb, 0, QtCore.Qt.AlignTop) gb.leaveEvent(None) self.groupBoxLayout.addStretch() def checkBoxCallback(self): for cb in self.checkBoxes: self.checkBoxesToLines[cb].set_visible(cb.isChecked()) self.scalePlots() self.canvas.draw() def groupBoxCallback(self): # count up number of active graphs numActive = 0 for gb in self.groupBoxes: if gb.isChecked(): numActive += 1 # activate/deactivate i = 0 for gb, plot in zip(self.groupBoxes, self.plots): if gb.isChecked(): i+=1 plot.set_visible(True) plot.change_geometry(numActive, 1, i) if i == numActive: plt.setp(plot.get_xticklabels(), visible=True) plot.set_xlabel(self.xlabel) else: plt.setp(plot.get_xticklabels(), visible=False) plot.set_xlabel('') else: plot.set_visible(False) self.canvas.draw()
class PyAbel: #(tk.Tk): def __init__(self, parent): self.parent = parent self.initialize() def initialize(self): self.fn = None self.old_fn = None self.old_method = None self.old_fi = None self.AIM = None self.rmx = (368, 393) # matplotlib figure self.f = Figure(figsize=(2, 4)) self.gs = gridspec.GridSpec(2, 2, width_ratios=[1, 2]) self.gs.update(wspace=0.2, hspace=0.5) self.plt = [] self.plt.append(self.f.add_subplot(self.gs[0])) self.plt.append(self.f.add_subplot(self.gs[1])) self.plt.append(self.f.add_subplot(self.gs[2], sharex=self.plt[0], sharey=self.plt[0])) self.plt.append(self.f.add_subplot(self.gs[3])) for i in [0, 2]: self.plt[i].set_adjustable('box-forced') # hide until have data for i in range(4): self.plt[i].axis("off") # tkinter # set default font size for buttons self.font = tkFont.Font(size=11) self.fontB = tkFont.Font(size=12, weight='bold') #frames top (buttons), text, matplotlib (canvas) self.main_container = tk.Frame(self.parent, height=10, width=100) self.main_container.pack(side="top", fill="both", expand=True) self.button_frame = tk.Frame(self.main_container) #self.info_frame = tk.Frame(self.main_container) self.matplotlib_frame = tk.Frame(self.main_container) self.button_frame.pack(side="top", fill="x", expand=True) #self.info_frame.pack(side="top", fill="x", expand=True) self.matplotlib_frame.pack(side="top", fill="both", expand=True) self._menus() self._button_area() self._plot_canvas() self._text_info_box() def _button_frame(self): self.button_frame = tk.Frame(self.main_container) self.button_frame.pack(side="top", fill="x", expand=True) self._menus() def _menus(self): # menus with callback ---------------- # duplicates the button interface self.menubar = tk.Menu(self.parent) self.transform_method = tk.IntVar() # File - menu self.filemenu = tk.Menu(self.menubar, tearoff=0) self.filemenu.add_command(label="Load image file", command=self._loadimage) self.filemenu.add_separator() self.filemenu.add_command(label="Exit", command=self._quit) self.menubar.add_cascade(label="File", menu=self.filemenu) # Process - menu self.processmenu = tk.Menu(self.menubar, tearoff=0) self.processmenu.add_command(label="Center image", command=self._center) self.submenu=tk.Menu(self.processmenu) for method in Abel_methods: self.submenu.add_radiobutton(label=method, var=self.transform_method, val=Abel_methods.index(method), command=self._transform) self.processmenu.add_cascade(label="Inverse Abel transform", menu=self.submenu, underline=0) self.processmenu.add_command(label="Speed distribution", command=self._speed) self.processmenu.add_command(label="Angular distribution", command=self._anisotropy) self.angmenu=tk.Menu(self.processmenu) self.menubar.add_cascade(label="Processing", menu=self.processmenu) # view - menu self.viewmenu = tk.Menu(self.menubar, tearoff=0) self.viewmenu.add_command(label="Raw image", command=self._display) self.viewmenu.add_command(label="Inverse Abel transformed image", command=self._transform) self.viewmenu.add_command(label="view buttons", command=self._on_buttons) self.menubar.add_cascade(label="View", menu=self.viewmenu) def _button_area(self): # grid layout # make expandable for col in range(5): self.button_frame.columnconfigure(col, weight=1) self.button_frame.rowconfigure(col, weight=1) # column 0 --------- # load image file button self.load = tk.Button(master=self.button_frame, text="load image", font=self.fontB, command=self._loadimage) self.load.grid(row=0, column=0, sticky=tk.W, padx=(5, 10), pady=(5, 0)) self.sample_image = ttk.Combobox(master=self.button_frame, font=self.font, values=["from file", "from transform", "sample dribinski", "sample Ominus"], width=14, height=4) self.sample_image.current(0) self.sample_image.grid(row=1, column=0, padx=(5, 10)) # quit self.quit = tk.Button(master=self.button_frame, text="quit", font=self.fontB, command=self._quit) self.quit.grid(row=3, column=0, sticky=tk.W, padx=(5, 10), pady=(0, 5)) # column 1 ----------- # center image self.center = tk.Button(master=self.button_frame, text="center image", anchor=tk.W, font=self.fontB, command=self._center) self.center.grid(row=0, column=1, padx=(0, 20), pady=(5, 0)) self.center_method = ttk.Combobox(master=self.button_frame, font=self.font, values=["com", "slice", "gaussian", "image_center"], width=10, height=4) self.center_method.current(1) self.center_method.grid(row=1, column=1, padx=(0, 20)) # column 2 ----------- # Abel transform image self.recond = tk.Button(master=self.button_frame, text="Abel transform image", font=self.fontB, command=self._transform) self.recond.grid(row=0, column=2, padx=(0, 10), pady=(5, 0)) self.transform = ttk.Combobox(master=self.button_frame, values=Abel_methods, font=self.font, width=10, height=len(Abel_methods)) self.transform.current(2) self.transform.grid(row=1, column=2, padx=(0, 20)) self.direction = ttk.Combobox(master=self.button_frame, values=["inverse", "forward"], font=self.font, width=8, height=2) self.direction.current(0) self.direction.grid(row=2, column=2, padx=(0, 20)) # column 3 ----------- # speed button self.speed = tk.Button(master=self.button_frame, text="speed", font=self.fontB, command=self._speed) self.speed.grid(row=0, column=5, padx=20, pady=(5, 0)) self.speedclr = tk.Button(master=self.button_frame, text="clear plot", font=self.font, command=self._speed_clr) self.speedclr.grid(row=1, column=5, padx=20) # column 4 ----------- # anisotropy button self.aniso = tk.Button(master=self.button_frame, text="anisotropy", font=self.fontB, command=self._anisotropy) self.aniso.grid(row=0, column=6, pady=(5, 0)) self.subframe = tk.Frame(self.button_frame) self.subframe.grid(row=1, column=6) self.rmin = tk.Entry(master=self.subframe, text='rmin', width=3, font=self.font) self.rmin.grid(row=0, column=0) self.rmin.delete(0, tk.END) self.rmin.insert(0, self.rmx[0]) self.lbl = tk.Label(master=self.subframe, text="to", font=self.font) self.lbl.grid(row=0, column=1) self.rmax = tk.Entry(master=self.subframe, text='rmax', width=3, font=self.font) self.rmax.grid(row=0, column=2) self.rmax.delete(0, tk.END) self.rmax.insert(0, self.rmx[1]) # turn off button interface self.hide_buttons = tk.Button(master=self.button_frame, text="hide buttons", font=self.fontB, command=self._hide_buttons) self.hide_buttons.grid(row=3, column=6, sticky=tk.E, pady=(0, 20)) def _text_info_box(self): # text info box --------------------- self.text = ScrolledText(master=self.button_frame, height=4, fg="mediumblue", bd=1, relief=tk.SUNKEN) self.text.insert(tk.END, "Work in progress, some features may" " be incomplete\n\n") self.text.insert(tk.END, "To start load an image data file using" " 'load image' button (or file menu)\n") self.text.insert(tk.END, "e.g. data/O2-ANU1024.txt.bz2\n") self.text.grid(row=3, column=1, columnspan=3, padx=5) def _plot_canvas(self): # matplotlib canvas -------------------------- self.canvas = FigureCanvasTkAgg(self.f, master=self.matplotlib_frame) #self.cid = self.canvas.mpl_connect('button_press_event', self._onclick) self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.parent) self.toolbar.update() self.canvas._tkcanvas.pack(anchor=tk.W, side=tk.TOP, fill=tk.BOTH, expand=1) def _onclick(self,event): print('button={:d}, x={:f}, y={:f}, xdata={:f}, ydata={:f}'.format( event.button, event.x, event.y, event.xdata, event.ydata)) # call back functions ----------------------- def _display(self): if self.fn is None: self._loadimage() # display image self.plt[0].imshow(self.IM, vmin=0) #rows, cols = self.IM.shape #r2 = rows/2 #c2 = cols/2 #self.a.plot((r2, r2), (0, cols), 'r--', lw=0.1) #self.a.plot((0, rows), (c2, c2),'r--', lw=0.1) #self.f.colorbar(self.a.get_children()[2], ax=self.f.gca()) self.plt[0].set_title("raw image", fontsize=10) self.canvas.show() def _loadimage(self): if self.fn is not None: # clear old plot for i in range(4): self._clr_plt(i) self.plt[i].axis("off") self.fn = self.sample_image.get() # update what is occurring text box self.text.insert(tk.END, "\nloading image file {:s}".format(self.fn)) self.text.see(tk.END) self.canvas.show() if self.fn == "from file": self.fn = askopenfilename() # read image file if ".txt" in self.fn: self.IM = np.loadtxt(self.fn) else: self.IM = imread(self.fn) elif self.fn == "from transform": self.IM = self.AIM self.AIM = None for i in range(1,4): self._clr_plt(i) self.plt[i].axis("off") self.direction.current(0) else: self.fn = self.fn.split(' ')[-1] self.IM = abel.tools.analytical.sample_image(n=1001, name=self.fn) self.direction.current(1) # raw images require 'forward' transform self.text.insert(tk.END,"\nsample image: (1) Abel transform 'forward', ") self.text.insert(tk.END," (2) load 'from transform', ") self.text.insert(tk.END," (3) Abel transform 'inverse', ") self.text.insert(tk.END," (4) Speed") self.text.see(tk.END) # if even size image, make odd if self.IM.shape[0] % 2 == 0: self.IM = shift(self.IM, (-0.5, -0.5))[:-1,:-1] self.old_method = None self.AIM = None self.action = "file" self.rmin.delete(0, tk.END) self.rmin.insert(0, self.rmx[0]) self.rmax.delete(0, tk.END) self.rmax.insert(0, self.rmx[1]) # show the image self._display() def _center(self): self.action = "center" center_method = self.center_method.get() # update information text box self.text.insert(tk.END, "\ncentering image using {:s}".\ format(center_method)) self.canvas.show() # center image via chosen method self.IM = abel.tools.center.center_image(self.IM, method=center_method, odd_size=True) self.text.insert(tk.END, "\ncenter offset = {:}".format(self.offset)) self.text.see(tk.END) self._display() def _transform(self): #self.method = Abel_methods[self.transform_method.get()] self.method = self.transform.get() self.fi = self.direction.get() if self.method != self.old_method or self.fi != self.old_fi: # Abel transform of whole image self.text.insert(tk.END,"\n{:s} {:s} Abel transform:".\ format(self.method, self.fi)) if "basex" in self.method: self.text.insert(tk.END, "\nbasex: first time calculation of the basis" " functions may take a while ...") if "onion" in self.method: self.text.insert(tk.END,"\nonion_peeling: method is in early " "testing and may not produce reliable results") if "direct" in self.method: self.text.insert(tk.END,"\ndirect: calculation is slowed if Cython" " unavailable ...") self.canvas.show() self.AIM = abel.transform(self.IM, method=self.method, direction=self.fi, symmetry_axis=None)['transform'] self.rmin.delete(0, tk.END) self.rmin.insert(0, self.rmx[0]) self.rmax.delete(0, tk.END) self.rmax.insert(0, self.rmx[1]) if self.old_method != self.method or self.fi != self.old_fi or\ self.action not in ["speed", "anisotropy"]: self.plt[2].set_title(self.method+" {:s} Abel transform".format(self.fi), fontsize=10) self.plt[2].imshow(self.AIM, vmin=0, vmax=self.AIM.max()/5.0) #self.f.colorbar(self.c.get_children()[2], ax=self.f.gca()) #self.text.insert(tk.END, "{:s} inverse Abel transformed image".format(self.method)) self.text.see(tk.END) self.old_method = self.method self.old_fi = self.fi self.canvas.show() def _speed(self): self.action = "speed" # inverse Abel transform self._transform() # update text box in case something breaks self.text.insert(tk.END, "\nspeed distribution") self.text.see(tk.END) self.canvas.show() # speed distribution self.radial, self.speed_dist = abel.tools.vmi.angular_integration(self.AIM) self.plt[1].axis("on") self.plt[1].plot(self.radial, self.speed_dist/self.speed_dist[10:].max(), label=self.method) self.plt[1].axis(xmax=500, ymin=-0.05) self.plt[1].set_xlabel("radius (pixels)", fontsize=9) self.plt[1].set_ylabel("normalized intensity") self.plt[1].set_title("radial speed distribution", fontsize=12) self.plt[1].legend(fontsize=9) self.action = None self.canvas.show() def _speed_clr(self): self._clr_plt(1) def _clr_plt(self, i): self.f.delaxes(self.plt[i]) self.plt[i] = self.f.add_subplot(self.gs[i]) self.canvas.show() def _anisotropy(self): def P2(x): # 2nd order Legendre polynomial return (3*x*x-1)/2 def PAD(theta, beta, amp): return amp*(1 + beta*P2(np.cos(theta))) self.action = "anisotropy" self._transform() # radial range over which to follow the intensity variation with angle self.rmx = (int(self.rmin.get()), int(self.rmax.get())) self.text.insert(tk.END,"\nanisotropy parameter pixel range {:} to {:}: "\ .format(*self.rmx)) self.canvas.show() # inverse Abel transform self._transform() # intensity vs angle self.intensity, self.theta = abel.tools.vmi.\ calculate_angular_distributions(self.AIM,\ radial_ranges=[self.rmx,]) # fit to P2(cos theta) self.beta, self.amp = abel.tools.vmi.anisotropy_parameter(self.theta, self.intensity[0]) self.text.insert(tk.END," beta = {:g}+-{:g}".format(*self.beta)) self._clr_plt(3) self.plt[3].axis("on") self.plt[3].plot(self.theta, self.intensity[0], 'r-') self.plt[3].plot(self.theta, PAD(self.theta, self.beta[0], self.amp[0]), 'b-', lw=2) self.plt[3].annotate("$\\beta({:d},{:d})={:.2g}\pm{:.2g}$".format(*self.rmx+self.beta), (-np.pi/2,-2)) self.plt[3].set_title("anisotropy", fontsize=12) self.plt[3].set_xlabel("angle", fontsize=9) self.plt[3].set_ylabel("intensity") self.action = None self.canvas.show() def _hide_buttons(self): self.button_frame.destroy() def _on_buttons(self): self._button_frame() def _quit(self): self.parent.quit() # stops mainloop self.parent.destroy() # this is necessary on Windows to prevent
class TimelineFrame(wx.Frame): """The main frame of the application""" def __init__(self, parent): wx.Frame.__init__( self, parent, id=wx.ID_ANY, title=_("GRASS GIS Timeline Tool")) tgis.init(True) self.datasets = [] self.timeData = {} self._layout() self.temporalType = None self.unit = None # We create a database interface here to speedup the GUI self.dbif = tgis.SQLDatabaseInterfaceConnection() self.dbif.connect() def __del__(self): """Close the database interface and stop the messenger and C-interface subprocesses. """ if self.dbif.connected is True: self.dbif.close() tgis.stop_subprocesses() def _layout(self): """Creates the main panel with all the controls on it: * mpl canvas * mpl navigation toolbar * Control panel for interaction """ self.panel = wx.Panel(self) # Create the mpl Figure and FigCanvas objects. # 5x4 inches, 100 dots-per-inch # # color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND) self.fig = Figure((5.0, 4.0), facecolor=(1, 1, 1)) self.canvas = FigCanvas(self.panel, wx.ID_ANY, self.fig) # axes are initialized later self.axes2d = None self.axes3d = None # Create the navigation toolbar, tied to the canvas # self.toolbar = NavigationToolbar(self.canvas) # # Layout # self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND) self.vbox.Add(self.toolbar, 0, wx.EXPAND) self.vbox.AddSpacer(10) gridSizer = wx.GridBagSizer(hgap=5, vgap=5) self.datasetSelect = gselect.Select(parent=self.panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE, type='stds', multiple=True) self.drawButton = wx.Button(self.panel, id=wx.ID_ANY, label=_("Draw")) self.drawButton.Bind(wx.EVT_BUTTON, self.OnRedraw) self.helpButton = wx.Button(self.panel, id=wx.ID_ANY, label=_("Help")) self.helpButton.Bind(wx.EVT_BUTTON, self.OnHelp) self.view3dCheck = wx.CheckBox( self.panel, id=wx.ID_ANY, label=_("3D plot of spatio-temporal extents")) self.view3dCheck.Bind(wx.EVT_CHECKBOX, self.OnRedraw) if not check_version(1, 0, 0): self.view3dCheck.SetLabel(_("3D plot of spatio-temporal extents " "(matplotlib >= 1.0.0)")) self.view3dCheck.Disable() gridSizer.Add(wx.StaticText(self.panel, id=wx.ID_ANY, label=_("Select space time dataset(s):")), pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) gridSizer.Add(self.datasetSelect, pos=(1, 0), flag=wx.EXPAND) gridSizer.Add(self.drawButton, pos=(1, 1), flag=wx.EXPAND) gridSizer.Add(self.helpButton, pos=(1, 2), flag=wx.EXPAND) gridSizer.Add( self.view3dCheck, pos=(2, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL) self.vbox.Add( gridSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=10) self.panel.SetSizer(self.vbox) self.vbox.Fit(self) def _getData(self, timeseries): """Load data and read properties""" self.timeData = {} mode = None unit = None for series in timeseries: name = series[0] + '@' + series[1] etype = series[2] sp = tgis.dataset_factory(etype, name) if not sp.is_in_db(dbif=self.dbif): GError( self, message=_("Dataset <%s> not found in temporal database") % (name)) return sp.select(dbif=self.dbif) self.timeData[name] = {} self.timeData[name]['elementType'] = series[2] self.timeData[name][ 'temporalType'] = sp.get_temporal_type() # abs/rel if mode is None: mode = self.timeData[name]['temporalType'] elif self.timeData[name]['temporalType'] != mode: GError( parent=self, message=_( "Datasets have different temporal type " "(absolute x relative), which is not allowed.")) return # check topology maps = sp.get_registered_maps_as_objects(dbif=self.dbif) self.timeData[name]['validTopology'] = sp.check_temporal_topology( maps=maps, dbif=self.dbif) self.timeData[name][ 'temporalMapType'] = sp.get_map_time() # point/interval self.timeData[name]['unit'] = None # only with relative if self.timeData[name]['temporalType'] == 'relative': start, end, self.timeData[name][ 'unit'] = sp.get_relative_time() if unit is None: unit = self.timeData[name]['unit'] elif self.timeData[name]['unit'] != unit: GError( self, _("Datasets have different time unit which is not allowed.")) return self.timeData[name]['start_datetime'] = [] # self.timeData[name]['start_plot'] = [] self.timeData[name]['end_datetime'] = [] # self.timeData[name]['end_plot'] = [] self.timeData[name]['names'] = [] self.timeData[name]['north'] = [] self.timeData[name]['south'] = [] self.timeData[name]['west'] = [] self.timeData[name]['east'] = [] columns = ','.join(['name', 'start_time', 'end_time', 'north', 'south', 'west', 'east']) rows = sp.get_registered_maps(columns=columns, where=None, order='start_time', dbif=self.dbif) if not rows: GError( parent=self, message=_("Dataset <{name}> is empty").format( name=series[0] + '@' + series[1])) return for row in rows: mapName, start, end, north, south, west, east = row self.timeData[name]['start_datetime'].append(start) self.timeData[name]['end_datetime'].append(end) self.timeData[name]['names'].append(mapName) self.timeData[name]['north'].append(north) self.timeData[name]['south'].append(south) self.timeData[name]['west'].append(west) self.timeData[name]['east'].append(east) self.temporalType = mode self.unit = unit def _draw3dFigure(self): """Draws 3d view (spatio-temporal extents). Only for matplotlib versions >= 1.0.0. Earlier versions cannot draw time ticks and alpha and it has a slightly different API. """ self.axes3d.clear() self.axes3d.grid(False) # self.axes3d.grid(True) if self.temporalType == 'absolute': convert = mdates.date2num else: convert = lambda x: x colors = cycle(COLORS) plots = [] for name in self.datasets: name = name[0] + '@' + name[1] startZ = convert(self.timeData[name]['start_datetime']) mapType = self.timeData[name]['temporalMapType'] if mapType == 'interval': dZ = convert(self.timeData[name]['end_datetime']) - startZ else: dZ = [0] * len(startZ) startX = self.timeData[name]['west'] dX = self.timeData[name]['east'] - np.array(startX) startY = self.timeData[name]['south'] dY = self.timeData[name]['north'] - np.array(startY) color = colors.next() plots.append(self.axes3d.bar3d(startX, startY, startZ, dX, dY, dZ, color=color, alpha=ALPHA)) params = grass.read_command('g.proj', flags='g') params = grass.parse_key_val(params) if 'unit' in params: self.axes3d.set_xlabel(_("X [%s]") % params['unit']) self.axes3d.set_ylabel(_("Y [%s]") % params['unit']) else: self.axes3d.set_xlabel(_("X")) self.axes3d.set_ylabel(_("Y")) if self.temporalType == 'absolute': if check_version(1, 1, 0): self.axes3d.zaxis_date() self.axes3d.set_zlabel(_('Time')) self.axes3d.mouse_init() self.canvas.draw() def _draw2dFigure(self): """Draws 2D plot (temporal extents)""" self.axes2d.clear() self.axes2d.grid(True) if self.temporalType == 'absolute': convert = mdates.date2num else: convert = lambda x: x colors = cycle(COLORS) yticksNames = [] yticksPos = [] plots = [] lookUp = LookUp(self.timeData) for i, name in enumerate(self.datasets): # just name; with mapset it would be long yticksNames.append(name[0]) name = name[0] + '@' + name[1] yticksPos.append(i) barData = [] pointData = [] mapType = self.timeData[name]['temporalMapType'] start = convert(self.timeData[name]['start_datetime']) # TODO: mixed if mapType == 'interval': end = convert(self.timeData[name]['end_datetime']) lookUpData = zip(start, end) duration = end - np.array(start) barData = zip(start, duration) lookUp.AddDataset(type_='bar', yrange=(i - 0.1, i + 0.1), xranges=lookUpData, datasetName=name) else: # self.timeData[name]['end_plot'] = None pointData = start lookUp.AddDataset( type_='point', yrange=i, xranges=pointData, datasetName=name) color = colors.next() if mapType == 'interval': plots.append( self.axes2d.broken_barh( xranges=barData, yrange=( i - 0.1, 0.2), facecolors=color, alpha=ALPHA)) else: plots.append( self.axes2d.plot( pointData, [i] * len(pointData), marker='o', linestyle='None', color=color)[0]) if self.temporalType == 'absolute': self.axes2d.xaxis_date() self.fig.autofmt_xdate() # self.axes2d.set_xlabel(_("Time")) else: self.axes2d.set_xlabel(_("Time [%s]") % self.unit) self.axes2d.set_yticks(yticksPos) self.axes2d.set_yticklabels(yticksNames) self.axes2d.set_ylim(min(yticksPos) - 1, max(yticksPos) + 1) # adjust xlim xlim = self.axes2d.get_xlim() padding = ceil((xlim[1] - xlim[0]) / 20.) self.axes2d.set_xlim(xlim[0] - padding, xlim[1] + padding) self.canvas.draw() DataCursor(plots, lookUp, InfoFormat) def OnRedraw(self, event): """Required redrawing.""" datasets = self.datasetSelect.GetValue().strip() if not datasets: return datasets = datasets.split(',') try: datasets = self._checkDatasets(datasets) if not datasets: return except GException as e: GError(parent=self, message=unicode(e), showTraceback=False) return self.datasets = datasets self._redraw() def _redraw(self): """Readraw data. Decides if to draw also 3D and adjusts layout if needed. """ self._getData(self.datasets) # axes3d are physically removed if not self.axes2d: self.axes2d = self.fig.add_subplot(1, 1, 1) self._draw2dFigure() if check_version(1, 0, 0): if self.view3dCheck.IsChecked(): self.axes2d.change_geometry(2, 1, 1) if not self.axes3d: # do not remove this import - unused but it is required for # 3D from mpl_toolkits.mplot3d import Axes3D # pylint: disable=W0611 self.axes3d = self.fig.add_subplot( 2, 1, 2, projection='3d') self.axes3d.set_visible(True) self._draw3dFigure() else: if self.axes3d: self.fig.delaxes(self.axes3d) self.axes3d = None self.axes2d.change_geometry(1, 1, 1) self.canvas.draw() def _checkDatasets(self, datasets): """Checks and validates datasets. Reports also type of dataset (e.g. 'strds'). :return: (mapName, mapset, type) """ validated = [] tDict = tgis.tlist_grouped('stds', group_type=True, dbif=self.dbif) # nested list with '(map, mapset, etype)' items allDatasets = [[[(map, mapset, etype) for map in maps] for etype, maps in etypesDict.iteritems()] for mapset, etypesDict in tDict.iteritems()] # flatten this list if allDatasets: allDatasets = reduce( lambda x, y: x + y, reduce( lambda x, y: x + y, allDatasets)) mapsets = tgis.get_tgis_c_library_interface().available_mapsets() allDatasets = [ i for i in sorted( allDatasets, key=lambda l: mapsets.index(l[1]))] for dataset in datasets: errorMsg = _("Space time dataset <%s> not found.") % dataset if dataset.find("@") >= 0: nameShort, mapset = dataset.split('@', 1) indices = [n for n, (mapName, mapsetName, etype) in enumerate( allDatasets) if nameShort == mapName and mapsetName == mapset] else: indices = [n for n, (mapName, mapset, etype) in enumerate( allDatasets) if dataset == mapName] if len(indices) == 0: raise GException(errorMsg) elif len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, message=_( "Please specify the space time dataset <%s>." % dataset), caption=_("Ambiguous dataset name"), choices=[("%(map)s@%(mapset)s: %(etype)s" % {'map': allDatasets[i][0], 'mapset': allDatasets[i][1], 'etype': allDatasets[i][2]}) for i in indices], style=wx.CHOICEDLG_STYLE | wx.OK) if dlg.ShowModal() == wx.ID_OK: index = dlg.GetSelection() validated.append(allDatasets[indices[index]]) else: continue else: validated.append(allDatasets[indices[0]]) return validated def OnHelp(self, event): RunCommand('g.manual', quiet=True, entry='g.gui.timeline') # interface def SetDatasets(self, datasets): """Set data""" if not datasets: return try: datasets = self._checkDatasets(datasets) if not datasets: return except GException as e: GError(parent=self, message=unicode(e), showTraceback=False) return self.datasets = datasets self.datasetSelect.SetValue( ','.join(map(lambda x: x[0] + '@' + x[1], datasets))) self._redraw() def Show3D(self, show): """Show also 3D if possible""" if check_version(1, 0, 0): self.view3dCheck.SetValue(show)
class MainFrame(wx.Frame): """Contains the main GUI and button boxes""" def __init__(self, parent, config, video, shuffle, Dataframe, scorer, savelabeled): # Settting the GUI size and panels design displays = (wx.Display(i) for i in range(wx.Display.GetCount()) ) # Gets the number of displays screenSizes = [ display.GetGeometry().GetSize() for display in displays ] # Gets the size of each display index = 0 # For display 1. screenWidth = screenSizes[index][0] screenHeight = screenSizes[index][1] self.gui_size = (screenWidth * 0.7, screenHeight * 0.85) wx.Frame.__init__( self, parent, id=wx.ID_ANY, title='DeepLabCut2.0 - Manual Outlier Frame Extraction', size=wx.Size(self.gui_size), pos=wx.DefaultPosition, style=wx.RESIZE_BORDER | wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL) self.statusbar = self.CreateStatusBar() self.statusbar.SetStatusText("") self.SetSizeHints( wx.Size(self.gui_size) ) # This sets the minimum size of the GUI. It can scale now! ################################################################################################################################################### # Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting! topSplitter = wx.SplitterWindow(self) self.image_panel = ImagePanel(topSplitter, config, video, shuffle, Dataframe, self.gui_size) self.widget_panel = WidgetPanel(topSplitter) topSplitter.SplitHorizontally(self.image_panel, self.widget_panel, sashPosition=self.gui_size[1] * 0.83) #0.9 topSplitter.SetSashGravity(1) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(topSplitter, 1, wx.EXPAND) self.SetSizer(sizer) ################################################################################################################################################### # Add Buttons to the WidgetPanel and bind them to their respective functions. widgetsizer = wx.WrapSizer(orient=wx.HORIZONTAL) self.load_button_sizer = wx.BoxSizer(wx.VERTICAL) self.help_button_sizer = wx.BoxSizer(wx.VERTICAL) self.help = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Help") self.help_button_sizer.Add(self.help, 1, wx.ALL, 15) # widgetsizer.Add(self.help , 1, wx.ALL, 15) self.help.Bind(wx.EVT_BUTTON, self.helpButton) widgetsizer.Add(self.help_button_sizer, 1, wx.ALL, 0) self.grab = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Grab Frames") widgetsizer.Add(self.grab, 1, wx.ALL, 15) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.grab.Enable(True) widgetsizer.AddStretchSpacer(5) self.slider = wx.Slider(self.widget_panel, id=wx.ID_ANY, value=0, minValue=0, maxValue=1, size=(200, -1), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS) widgetsizer.Add(self.slider, 1, wx.ALL, 5) self.slider.Bind(wx.EVT_SLIDER, self.OnSliderScroll) widgetsizer.AddStretchSpacer(5) self.start_frames_sizer = wx.BoxSizer(wx.VERTICAL) self.end_frames_sizer = wx.BoxSizer(wx.VERTICAL) self.start_frames_sizer.AddSpacer(15) # self.startFrame = wx.SpinCtrl(self.widget_panel, value='0', size=(100, -1), min=0, max=120) self.startFrame = wx.SpinCtrl(self.widget_panel, value='0', size=(100, -1)) #,style=wx.SP_VERTICAL) self.startFrame.Enable(False) self.start_frames_sizer.Add(self.startFrame, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) start_text = wx.StaticText(self.widget_panel, label='Start Frame Index') self.start_frames_sizer.Add(start_text, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) self.checkBox = wx.CheckBox(self.widget_panel, id=wx.ID_ANY, label='Range of frames') self.checkBox.Bind(wx.EVT_CHECKBOX, self.activate_frame_range) self.start_frames_sizer.Add(self.checkBox, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) # self.end_frames_sizer.AddSpacer(15) self.endFrame = wx.SpinCtrl(self.widget_panel, value='1', size=(160, -1)) #, min=1, max=120) self.endFrame.Enable(False) self.end_frames_sizer.Add(self.endFrame, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) end_text = wx.StaticText(self.widget_panel, label='Number of Frames') self.end_frames_sizer.Add(end_text, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) self.updateFrame = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Update") self.end_frames_sizer.Add(self.updateFrame, 1, wx.EXPAND | wx.ALIGN_LEFT, 15) self.updateFrame.Bind(wx.EVT_BUTTON, self.updateSlider) self.updateFrame.Enable(False) widgetsizer.Add(self.start_frames_sizer, 1, wx.ALL, 0) widgetsizer.AddStretchSpacer(5) widgetsizer.Add(self.end_frames_sizer, 1, wx.ALL, 0) widgetsizer.AddStretchSpacer(15) self.quit = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Quit") widgetsizer.Add(self.quit, 1, wx.ALL, 15) self.quit.Bind(wx.EVT_BUTTON, self.quitButton) self.quit.Enable(True) self.widget_panel.SetSizer(widgetsizer) self.widget_panel.SetSizerAndFit(widgetsizer) # Variables initialization self.numberFrames = 0 self.currFrame = 0 self.figure = Figure() self.axes = self.figure.add_subplot(111) self.drs = [] self.extract_range_frame = False self.firstFrame = 0 # self.cropping = False # Read confing file self.cfg = auxiliaryfunctions.read_config(config) self.Task = self.cfg['Task'] self.start = self.cfg['start'] self.stop = self.cfg['stop'] self.date = self.cfg['date'] self.trainFraction = self.cfg['TrainingFraction'] self.trainFraction = self.trainFraction[0] self.videos = self.cfg['video_sets'].keys() self.bodyparts = self.cfg['bodyparts'] self.colormap = plt.get_cmap(self.cfg['colormap']) self.colormap = self.colormap.reversed() self.markerSize = self.cfg['dotsize'] self.alpha = self.cfg['alphavalue'] self.iterationindex = self.cfg['iteration'] self.cropping = self.cfg['cropping'] self.video_names = [Path(i).stem for i in self.videos] self.config_path = Path(config) self.video_source = Path(video).resolve() self.shuffle = shuffle self.Dataframe = Dataframe self.scorer = scorer self.savelabeled = savelabeled # Read the video file self.vid = cv2.VideoCapture(str(self.video_source)) self.videoPath = os.path.dirname(self.video_source) self.filename = Path(self.video_source).name self.numberFrames = int(self.vid.get(cv2.CAP_PROP_FRAME_COUNT)) self.strwidth = int(np.ceil(np.log10(self.numberFrames))) # Set the values of slider and range of frames self.startFrame.SetMax(self.numberFrames - 1) self.slider.SetMax(self.numberFrames - 1) self.endFrame.SetMax(self.numberFrames - 1) self.startFrame.Bind(wx.EVT_SPINCTRL, self.updateSlider) #wx.EVT_SPIN # Set the status bar self.statusbar.SetStatusText('Working on video: {}'.format( os.path.split(str(self.video_source))[-1])) # Adding the video file to the config file. if not (str(self.video_source.stem) in self.video_names): add.add_new_videos(self.config_path, [self.video_source]) self.filename = Path(self.video_source).name self.update() self.plot_labels() self.widget_panel.Layout() def quitButton(self, event): """ Quits the GUI """ self.statusbar.SetStatusText("") dlg = wx.MessageDialog(None, "Are you sure?", "Quit!", wx.YES_NO | wx.ICON_WARNING) result = dlg.ShowModal() if result == wx.ID_YES: print("Quitting for now!") self.Destroy() def updateSlider(self, event): self.slider.SetValue(self.startFrame.GetValue()) self.startFrame.SetValue(self.slider.GetValue()) self.axes.clear() self.figure.delaxes(self.figure.axes[1]) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.currFrame = (self.slider.GetValue()) self.update() self.plot_labels() def activate_frame_range(self, event): """ Activates the frame range boxes """ self.checkSlider = event.GetEventObject() if self.checkSlider.GetValue() == True: self.extract_range_frame = True self.startFrame.Enable(True) self.startFrame.SetValue(self.slider.GetValue()) self.endFrame.Enable(True) self.updateFrame.Enable(True) self.grab.Enable(False) else: self.extract_range_frame = False self.startFrame.Enable(False) self.endFrame.Enable(False) self.updateFrame.Enable(False) self.grab.Enable(True) def line_select_callback(self, eclick, erelease): 'eclick and erelease are the press and release events' self.new_x1, self.new_y1 = eclick.xdata, eclick.ydata self.new_x2, self.new_y2 = erelease.xdata, erelease.ydata def OnSliderScroll(self, event): """ Slider to scroll through the video """ self.axes.clear() self.figure.delaxes(self.figure.axes[1]) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.currFrame = (self.slider.GetValue()) self.startFrame.SetValue(self.currFrame) self.update() self.plot_labels() def update(self): """ Updates the image with the current slider index """ self.grab.Enable(True) self.grab.Bind(wx.EVT_BUTTON, self.grabFrame) self.figure, self.axes, self.canvas = self.image_panel.getfigure() self.vid.set(1, self.currFrame) ret, frame = self.vid.read() frame = img_as_ubyte(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) if ret: if self.cropping: self.coords = (self.cfg['x1'], self.cfg['x2'], self.cfg['y1'], self.cfg['y2']) frame = frame[int(self.coords[2]):int(self.coords[3]), int(self.coords[0]):int(self.coords[1]), :] else: self.coords = None self.ax = self.axes.imshow(frame, cmap=self.colormap) self.axes.set_title( str( str(self.currFrame) + "/" + str(self.numberFrames - 1) + " " + self.filename)) self.figure.canvas.draw() else: print("Invalid frame") def chooseFrame(self): ret, frame = self.vid.read() frame = img_as_ubyte(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) if self.cropping: self.coords = (self.cfg['x1'], self.cfg['x2'], self.cfg['y1'], self.cfg['y2']) frame = frame[int(self.coords[2]):int(self.coords[3]), int(self.coords[0]):int(self.coords[1]), :] else: self.coords = None fname = Path(self.filename) output_path = self.config_path.parents[0] / 'labeled-data' / fname.stem self.machinefile = os.path.join( str(output_path), 'machinelabels-iter' + str(self.iterationindex) + '.h5') name = str(fname.stem) DF = self.Dataframe.ix[[self.currFrame]] DF.index = [ os.path.join('labeled-data', name, "img" + str(index).zfill(self.strwidth) + ".png") for index in DF.index ] img_name = str(output_path) + '/img' + str(self.currFrame).zfill( int(np.ceil(np.log10(self.numberFrames)))) + '.png' labeled_img_name = str(output_path) + '/img' + str( self.currFrame).zfill(int(np.ceil(np.log10( self.numberFrames)))) + 'labeled.png' # Check for it output path and a machine label file exist if output_path.exists() and Path(self.machinefile).is_file(): cv2.imwrite(img_name, frame) if self.savelabeled: self.figure.savefig(labeled_img_name, bbox_inches='tight') Data = pd.read_hdf(self.machinefile, 'df_with_missing') DataCombined = pd.concat([Data, DF]) DataCombined = DataCombined[~DataCombined.index.duplicated( keep='first')] DataCombined.to_hdf(self.machinefile, key='df_with_missing', mode='w') DataCombined.to_csv( os.path.join(str(output_path), 'machinelabels.csv')) # If machine label file does not exist then create one elif output_path.exists() and not (Path(self.machinefile).is_file()): if self.savelabeled: self.figure.savefig(labeled_img_name, bbox_inches='tight') cv2.imwrite(img_name, frame) DF.to_hdf(self.machinefile, key='df_with_missing', mode='w') DF.to_csv(os.path.join(str(output_path), "machinelabels.csv")) else: print( "%s path not found. Please make sure that the video was added to the config file using the function 'deeplabcut.add_new_videos'.Quitting for now!" % output_path) self.Destroy() def grabFrame(self, event): """ Extracts the frame and saves in the current directory """ if self.extract_range_frame == True: num_frames_extract = self.endFrame.GetValue() for i in range(self.currFrame, self.currFrame + num_frames_extract): self.currFrame = i self.vid.set(1, self.currFrame) self.chooseFrame() else: self.vid.set(1, self.currFrame) self.chooseFrame() def plot_labels(self): """ Plots the labels of the analyzed video """ self.vid.set(1, self.currFrame) ret, frame = self.vid.read() self.norm, self.colorIndex = self.image_panel.getColorIndices( frame, self.bodyparts) if ret: frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) divider = make_axes_locatable(self.axes) cax = divider.append_axes("right", size="5%", pad=0.05) cbar = self.figure.colorbar(self.ax, cax=cax, spacing='proportional', ticks=self.colorIndex) cbar.set_ticklabels(self.bodyparts) for bpindex, bp in enumerate(self.bodyparts): color = self.colormap(self.norm(self.colorIndex[bpindex])) self.points = [ self.Dataframe[self.scorer][bp]['x'].values[ self.currFrame], self.Dataframe[self.scorer][bp] ['y'].values[self.currFrame], 1.0 ] circle = [ patches.Circle((self.points[0], self.points[1]), radius=self.markerSize, fc=color, alpha=self.alpha) ] self.axes.add_patch(circle[0]) self.figure.canvas.draw() def helpButton(self, event): """ Opens Instructions """ wx.MessageBox( "1. Use the checkbox 'Crop?' at the bottom left if you need to crop the frame. In this case use the left mouse button to draw a box corresponding to the region of interest. Click the 'Set cropping parameters' button to add the video with the chosen crop parameters to the config file.\n\n2. Use the slider to select a frame in the entire video. \n\n3. Click Grab Frames button to save the specific frame.\n\n4. In events where you need to extract a range frames, then use the checkbox 'Range of frames' to select the starting frame index and the number of frames to extract. \n Click the update button to see the frame. Click Grab Frames to select the range of frames. \n Click OK to continue", 'Instructions to use!', wx.OK | wx.ICON_INFORMATION)
class PlotFrame(Frame): def __init__(self, master): Frame.__init__(self, master) self.figure = Figure(dpi=100) self.canvas = FigureCanvasTkAgg(self.figure,master=self) self.canvas.show() self.widget = self.canvas.get_tk_widget() self.widget.pack(side=TOP, expand=1, fill=BOTH) self.__plots = {} self.reset() self.bind("<Configure>", self._configure) self.config(background='red') self._scaledict = {} self._panmode = False self._xzoommode = False self._panstate = None self._padding = {} self._boundaries_changed = {} self.canvas.mpl_connect('button_press_event', self._button_pressed) self.canvas.mpl_connect('button_release_event', self._button_released) self.canvas.mpl_connect('motion_notify_event', self._motion) self.canvas.mpl_connect('scroll_event', self._scroll) def _scroll(self, event): if not event.inaxes: return for a in event.inaxes.get_children(): z = 0 if type(a) == YAxis and not self._xzoommode: self._scaledict[event.inaxes][1] = False z = 1 if (event.step > 0) else -1 elif type(a) == XAxis and self._xzoommode: self._scaledict[event.inaxes][0] = False z = 1 if (event.step > 0) else -1 if z != 0: a.zoom(z) self._boundaries_changed[event.inaxes] = True self._padding[event.inaxes] = [0, 0, 0, 0] def _button_pressed(self, event): if event.dblclick or not event.inaxes: if event.inaxes: self._panmode = False self._xzoommode = False self._panstate = None self._scaledict[event.inaxes] = [True, True] self._padding[event.inaxes] = [0, 0, 0, 0] self._boundaries_changed[event.inaxes] = False event.inaxes.set_ylim(auto=True) event.inaxes.set_xlim(auto=True) self.update() return self._panstate = [event.inaxes, event.x, event.y, 0, 0] if event.button == 1: self._panmode = True else: self._xzoommode = True def _button_released(self, event): self._xzoommode = False self._panmode = False self._panstate = None def _motion(self, event): if not self._panmode: return panx = False pany = False ps = self._panstate ps[3] += event.x - ps[1] ps[4] += event.y - ps[2] dx = ps[3] dy = ps[4] if abs(dx) > 5 and abs(dx) > abs(dy): panx = True elif abs(dy) > 5 and abs(dy) > abs(dx): pany = True for a in ps[0].get_children(): p = 0 if type(a) == YAxis and pany: self._scaledict[ps[0]][1] = False p = 1 if (dy < 0) else -1 elif type(a) == XAxis and panx: self._scaledict[ps[0]][0] = False p = 1 if (dx < 0) else -1 if p != 0: ps[3] = 0 ps[4] = 0 a.pan(p) self._boundaries_changed[ps[0]] = True self._padding[event.inaxes] = [0, 0, 0, 0] ps[1] = event.x ps[2] = event.y self._panstate = ps def update(self): for p in self.figure.axes: p.relim() p.autoscale_view(True, self._scaledict[p][0], self._scaledict[p][1]) xi = p.get_xaxis().get_data_interval() yi = p.get_yaxis().get_data_interval() if self._boundaries_changed[p]: if not self._padding[p][0] and not self._scaledict[p][0]: self._padding[p][0] = p.get_xlim()[0] - xi[0] if not self._padding[p][1] and not self._scaledict[p][0]: self._padding[p][1] = p.get_xlim()[1] - xi[1] if not self._padding[p][2] and not self._scaledict[p][1]: self._padding[p][2] = p.get_ylim()[0] - yi[0] if not self._padding[p][3] and not self._scaledict[p][1]: self._padding[p][3] = p.get_ylim()[1] - yi[1] if self._padding[p][0] < 0: p.set_xlim(left=xi[0] + self._padding[p][0]) if self._padding[p][1] > 0: p.set_xlim(right=xi[1] + self._padding[p][1]) if self._padding[p][2] < 0: p.set_ylim(bottom=yi[0] + self._padding[p][2]) if self._padding[p][3] > 0: p.set_ylim(top=yi[1] + self._padding[p][3]) self.canvas.draw() def _configure(self, *args): width = self.winfo_width() height = self.winfo_height() w = width / 100.0 h = height / 100.0 self.figure.set_size_inches(w, h) def add_graph(self, graph, xdata=[], ydata=[]): if not graph.position in self.__plots: plt = self.figure.add_subplot(int(graph.position)) plt.set_autoscale_on(True) self.__plots[graph.position] = plt plt.grid() self._scaledict[plt] = [True, True] self._padding[plt] = [0, 0, 0, 0] self._boundaries_changed[plt] = False graph.line, = self.__plots[graph.position].plot(xdata,ydata, graph.cfg) self.update_legends() def update_legends(self): lines = {} ids = {} for g in Graph.graphs.values(): if not lines.has_key(g.position) or not ids.has_key(g.position): lines[g.position] = [] ids[g.position] = [] ids[g.position].append(g.identifier) lines[g.position].append(g.line) for p in lines.keys(): if self.__plots.has_key(p): self.__plots[p].legend(lines[p], ids[p], 'upper left') def delete_graph(self, graph): graph.line.remove() for p in self.__plots.keys(): if len(self.__plots[p].lines) == 0: self.figure.delaxes(self.__plots[p]) del self.__plots[p] def update_graph(self, graph): xd = graph.line.get_xdata() yd = graph.line.get_ydata() self.delete_graph(graph) self.add_graph(graph) def clear_graph(self, graph): graph.line.remove() self.add_graph(graph, [], []) def reset(self): for p in self.figure.axes: self.figure.delaxes(p) self._scaledict = {} self.__plots = {} self._padding = {} self._boundaries_changed = {} self.figure.clf()
class DOYPlot(FigureCanvas): def __str__(self): return "Stacked Day of Year Plot" def __init__(self, parent=None): ### Setup datasets # Actual data self.x = np.zeros(0) self.year = np.zeros(0) self.y = np.zeros(0) # Modeled fitted data self.mx = np.zeros(0) self.mx_year = np.zeros(0) self.my = np.zeros(0) # Location of pixel plotted self.px = None self.py = None # Store colorbar so we know to delete self.cbar = None # Store range of data self.yr_range = (0, 1) # Setup plots self.setup_plots() self.plot() def setup_plots(self): self.fig = Figure() self.axes = self.fig.add_subplot(111) FigureCanvas.__init__(self, self.fig) self.setAutoFillBackground(False) self.axes.set_ylim([0, 10000]) self.fig.tight_layout() def update_plot(self): """ Fetches new information and then calls plot """ self.px, self.py = tsm.ts.get_px(), tsm.ts.get_py() if self.px is not None and self.py is not None: # Add + 1 so we index on 1,1 instead of 0,0 (as in ENVI/MATLAB) self.px, self.py = self.px + 1, self.py + 1 self.x = np.array([int(d.strftime('%j')) for d in tsm.ts.dates]) self.year = np.array([d.year for d in tsm.ts.dates]) self.y = tsm.ts.get_data(setting.plot['mask'])[setting.plot['band'], :] if setting.plot['fit'] is True and tsm.ts.result is not None: if len(tsm.ts.result) > 0: self.mx, self.my = tsm.ts.get_prediction(setting.plot['band']) else: self.mx, self.my = (np.zeros(0), np.zeros(0)) self.mx_year = [] for _mx in self.mx: self.mx_year.append(np.array([d.year for d in _mx])) if setting.plot['break'] is True and tsm.ts.result is not None: if len(tsm.ts.result) > 1: self.bx, self.by = tsm.ts.get_breaks(setting.plot['band']) else: self.bx, self.by = (np.zeros(0), np.zeros(0)) self.plot() def plot(self): """ Matplotlib plot of time series stacked by DOY """ self.axes.clear() title = 'Time series - row: {r} col: {c}'.format( r=str(self.py), c=str(self.px)) self.axes.set_title(title) self.axes.set_xlabel('Day of Year') if tsm.ts is None: self.axes.set_ylabel('Band') else: self.axes.set_ylabel(tsm.ts.band_names[setting.plot['band']]) self.axes.grid(True) self.axes.set_ylim([setting.plot['min'][setting.plot['band']], setting.plot['max'][setting.plot['band']]]) self.axes.set_xlim(0, 366) if setting.plot['xmin'] is not None \ and setting.plot['xmax'] is not None: # Find array indexes for year range self.yr_range = np.arange( np.where(self.year >= setting.plot['xmin'])[0][0], np.where(self.year <= setting.plot['xmax'])[0][-1]) else: self.yr_range = np.arange(0, self.year.shape[0]) # Specify the year min and max yr_min = 0 yr_max = 1 if len(self.year) > 0: yr_min = self.year.min() yr_max = self.year.max() # Setup colormap and mapper cmap = mpl.cm.get_cmap('jet') norm = mpl.colors.Normalize(vmin=yr_min, vmax=yr_max) mapper = mpl.cm.ScalarMappable(norm=norm, cmap=cmap) # Plot sp = self.axes.scatter(self.x[self.yr_range], self.y[self.yr_range], cmap=cmap, c=self.year[self.yr_range], norm=norm, marker='o', edgecolors='none', s=25, picker=setting.plot['picker_tol']) # Only put colorbar if we have data if tsm.ts is not None: # Setup layout to add space # http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#axesdivider divider = mpl_grid.make_axes_locatable(self.axes) cax = divider.append_axes('right', size='5%', pad=0.05) # Reset colorbar so it doesn't overwrite itself... if self.cbar is not None: self.fig.delaxes(self.fig.axes[1]) self.fig.subplots_adjust(right=0.90) self.cbar = self.fig.colorbar(sp, cax=cax) if setting.plot['fit'] is True: med_year = [] fit_plt = [] # Find median year and plot that result for n, _yr in enumerate(self.mx_year): # Make sure _yr is not empty array if len(_yr) == 0: continue # Determine median year med = int(np.median(_yr)) # Make sure median year is in our current x-axis if setting.plot['xmin'] > med or setting.plot['xmax'] < med: continue med_year.append(med) # Determine line color col = mapper.to_rgba(med) # Get index from mx predicted data for median year fit_range = np.arange( np.where(_yr == med)[0][0], np.where(_yr == med)[0][-1]) # Recreate as DOY mx_doy = np.array([int(d.strftime('%j')) for d in self.mx[n][fit_range]]) # Plot seg, = self.axes.plot(mx_doy, self.my[n][fit_range], color=col, linewidth=2) fit_plt.append(seg) if len(med_year) > 0: self.axes.legend(fit_plt, ['Fit {n}: {y}'.format(n=n + 1, y=y) for n, y in enumerate(med_year)]) # Redraw self.fig.tight_layout() self.fig.canvas.draw() def save_plot(self): """ Save the matplotlib figure """ ### Parse options from settings fname = setting.save_plot['fname'] fformat = setting.save_plot['format'] facecolor = setting.save_plot['facecolor'] edgecolor = setting.save_plot['edgecolor'] transparent = setting.save_plot['transparent'] ### Format the output path directory = os.path.split(fname)[0] # Check for file extension if '.' not in os.path.split(fname)[1]: filename = '{f}.{e}'.format(f=os.path.split(fname)[1], e=fformat) # Add in directory if none if directory == '': directory = '.' # If directory does not exist, return False if not os.path.exists(directory): return False # Join and save filename = os.path.join(directory, filename) self.fig.savefig(filename, format=fformat, facecolor=facecolor, edgecolor=edgecolor, transparent=transparent) return True def disconnect(self): pass
class GraphPanel(wx.Panel): def __init__(self,parent,ctrl): wx.Panel.__init__(self,parent) self.SetBackgroundColour('#FFFFFF') self.ctrlPanel = ctrl self.initGraph() wx.EVT_PAINT(self, self.OnPaint) def initGraph(self): self.x0 = [] self.y0 = [] self.x1 = [] self.y1 = [] self.x2 = [] self.y2 = [] self.trial = 1 self.figure = Figure(dpi=100,figsize=(5,8)) self.axes = self.figure.add_subplot(111) self.axes.axis([0,self.ctrlPanel.experimentDuration,1,0]) self.axes.set_xlabel('time (s)') bluepts = self.axes.scatter(self.x0, self.y0, c='b',s=10,lw=0.0) redpts = self.axes.scatter(self.x1,self.y1, c='r',s=10,lw=0.0) purpts = self.axes.scatter(self.x2,self.y2,c='m',s=10,lw=0.0) startAt = self.ctrlPanel.iti endAt = startAt+self.ctrlPanel.toneDuration tone = self.axes.axvspan(startAt,endAt,facecolor='g',alpha=0.5,lw=0.0) startAt = endAt endAt = startAt+self.ctrlPanel.wait wait = self.axes.axvspan(startAt,endAt,facecolor='#aeaeae',alpha=0.5,lw=0.0) startAt = endAt endAt = startAt + self.ctrlPanel.rewardInterval reward = self.axes.axvspan(startAt,endAt,facecolor='#FFCCCC',alpha=0.5,lw=0.0) LText = FontProperties() LText.set_size("small") self.axes.legend((bluepts,redpts,purpts,tone,wait,reward), ("Lever Press","Rewarded Press","Manual Reward","Tone Duration","Wait Interval","Reward Interval"), prop=LText, fancybox=True, bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0) self.canvas = FigureCanvas(self, -1, self.figure) def clearGraph(self): self.figure.delaxes(self.axes) self.initGraph() self.Refresh() def addPoint(self,t,pcat): if pcat==1: self.x1.append(t) self.y1.append(self.trial) self.trial+=1 self.axes.set_ylim(bottom=self.trial) elif pcat==2: self.x2.append(t) self.y2.append(self.trial) self.trial+=1 self.axes.set_ylim(bottom=self.trial) else: self.x0.append(t) self.y0.append(self.trial) def OnPaint(self, event): self.bluepts = self.axes.scatter(self.x0, self.y0, c='b',s=10,lw=0.0) self.redpts = self.axes.scatter(self.x1,self.y1, c='r',s=10,lw=0.0) self.purpts = self.axes.scatter(self.x2,self.y2,c='m',s=10,lw=0.0) self.canvas.draw() event.Skip() def OnSetFocus(self, event): #self.color = '#0099f7' self.color = 'yellow' self.Refresh() def OnKillFocus(self, event): self.color = '#b3b3b3' self.Refresh()
class Window(QtGui.QApplication): """This class holds/is the main windows of the GUI""" EXIT_CODE_REBOOT = -666 def __init__(self, sys_argv): """Inits/ Builds the GUI""" super(Window, self).__init__(sys_argv) #----------------------------Setting path to resources folder----------------------------# current_path = os.path.realpath(__file__) current_path = current_path.split("\\") pathToProgramm = current_path[:-2 or None] self.path = "" for s in pathToProgramm: self.path += s + "\\" #----------------------------Validator for float inputs----------------------------# regexp_onlyDoubles = QtCore.QRegExp('^([-+]?\d*\.\d+|\d+)$') self.validator = QtGui.QRegExpValidator(regexp_onlyDoubles) #----------------------------Variablen----------------------------# self.potenzialnummer = 2 self.potenzialList = [] self.currentPotenzial = 1 self.wasFullyConnectedBeforeUndo = [] self.potencial = 0 self.controler = controler.Controler() #----------------------------Init Main Window----------------------------# cssFile = "../resources/css-gui.txt" css = "" with open(cssFile, "r") as fh: css += (fh.read()) screen_resolution = self.desktop().screenGeometry() width, height = screen_resolution.width(), screen_resolution.height() self.main_window = QtGui.QMainWindow() self.main_window.setWindowTitle('ECS - Electronical Circuit Simulator') self.main_window.showMaximized() #Set Icon self.setAppIcon() # set the layout containerMain = QtGui.QWidget() containerMain.setObjectName("containerMain") containerMain.setStyleSheet(css) self.main_window.setStyleSheet(css) mainLayout = QtGui.QVBoxLayout(containerMain) containerGraph = QtGui.QWidget() containerGraph.setObjectName("containerGraph") containerGraph.setFixedWidth(width * 0.965) graphLayout = QtGui.QVBoxLayout(containerGraph) containerCircuit = QtGui.QWidget() containerCircuit.setObjectName("containerCircuit") containerCircuit.setFixedWidth(width * 0.7) containerCircuit.setFixedHeight(height * 0.4) circuitLayout = QtGui.QVBoxLayout(containerCircuit) containerInput = QtGui.QWidget() containerInput.setObjectName("containerInput") containerInput.setFixedWidth(width * 0.25) containerInput.setFixedHeight(height * 0.4) inputLayout = QtGui.QVBoxLayout(containerInput) containerUpperLayout = QtGui.QWidget() upperLayout = QtGui.QHBoxLayout(containerUpperLayout) containerLowerLayout = QtGui.QWidget() lowerLayout = QtGui.QHBoxLayout(containerLowerLayout) containerLowerLayout.setFixedHeight(height * 0.4) #----------------------------Main-Menue------------------------------# self.setMenu() self.createDropDowns() #----------------------------Graph-Layout----------------------------# self.figure = Figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, containerGraph) self.buttonPlotPotenzial = QtGui.QPushButton('Plot Potenzial ') self.buttonPlotPotenzial.clicked.connect(self.plot2) self.buttonPlotPotenzial.hide() self.buttonPlotPotenzial.setFixedSize(120, 20) graphInputLayout = QtGui.QHBoxLayout() graphInputLayout.addWidget(self.potenzialDropDown) graphInputLayout.addWidget(self.buttonPlotPotenzial) graphInputWidget = QtGui.QWidget() graphInputWidget.setLayout(graphInputLayout) graphInputWidget.setFixedSize(350, 30) graphLayout.addWidget(self.toolbar) graphLayout.addWidget(graphInputWidget) graphLayout.addWidget(self.canvas) #----------------------------Circuit-Layout----------------------------# self.createCircuitFigure() circuitLayout.setContentsMargins(20, 20, 20, 20) circuitLayout.addWidget(self.scrollArea) #----------------------------Input-Layout----------------------------# inputNameLayout = QtGui.QHBoxLayout() self.createFunctionDropwDowns() self.componentNameInputLabel = QtGui.QLabel("Name des Bauteils") self.componentNameInput = QtGui.QLineEdit() self.componentNameInput.setObjectName("") self.componentNameInput.setText("") inputNameLayout.addWidget(self.componentNameInputLabel) inputNameLayout.addWidget(self.componentNameInput) inputComponentLayout = QtGui.QHBoxLayout() inputComponentLayout.addWidget(self.componentDropwDown) inputComponentLayout.addWidget(self.potenzialDropDownFrom) inputComponentLayout.addWidget(self.potenzialDropDownTo) inputComponentLayout2 = QtGui.QHBoxLayout() self.directionLabel = QtGui.QLabel("Direction") inputComponentLayout2.addWidget(self.directionLabel) inputComponentLayout2.addWidget(self.directionDropwDown) inputComponentLayout3 = QtGui.QHBoxLayout() self.componentValueLabel = QtGui.QLabel("Start-Value of Component") self.componentValueLabel.hide() self.componentValueInput = QtGui.QLineEdit() self.componentValueInput.setObjectName("") self.componentValueInput.setText("0.0") self.componentValueInput.hide() self.componentValueInput.setValidator(self.validator) #self.componentValueInput.textEdited.connect(self.on_valueInputChanged) inputComponentLayout3.addWidget(self.componentValueLabel) inputComponentLayout3.addWidget(self.componentValueInput) inputComponentLayout3.addWidget(self.function_c_DropwDown) inputComponentLayout3.addWidget(self.function_i_DropwDown) inputComponentLayout3.addWidget(self.function_r_DropwDown) inputComponentLayout3.addWidget(self.function_v_DropwDown) inputComponentLayout3.addWidget(self.function_l_DropwDown) buttonAddComponent = QtGui.QPushButton('Add Component') buttonAddComponent.clicked.connect(self.addComponentToCircuit) buttonUndo = QtGui.QPushButton('Simulate') buttonUndo.clicked.connect(self.enterPotencialValues) inputLayout.addLayout(inputNameLayout) inputLayout.addLayout(inputComponentLayout) inputLayout.addLayout(inputComponentLayout2) inputLayout.addLayout(inputComponentLayout3) inputLayout.addWidget(buttonAddComponent) inputLayout.addWidget(buttonUndo) inputLayout.setContentsMargins(50, 50, 50, 50) #----------------------------Main-Layout----------------------------# upperLayout.addWidget(containerInput) upperLayout.addWidget(containerCircuit) lowerLayout.addWidget(containerGraph) mainLayout.addWidget(containerUpperLayout) mainLayout.addWidget(containerLowerLayout) self.main_window.setCentralWidget(containerMain) self.createNewCircuit() def setAppIcon(self): """This function loads and sets the application icon""" app_icon = QtGui.QIcon() app_icon.addFile("..\\resources\\favicon.ico") app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(16, 16)) app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(24, 24)) app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(32, 32)) app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(48, 48)) app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(256, 256)) self.setWindowIcon(QtGui.QIcon("..\\resources\\favicon.ico")) self.main_window.setWindowIcon(app_icon) def setMenu(self): """This function create the Window-Menue""" self.statusbar = self.main_window.statusBar() mainMenu = self.main_window.menuBar() fileMenu = mainMenu.addMenu("&File") editMenu = mainMenu.addMenu("&Edit") createNewAction = QtGui.QAction("New", self.main_window) createNewAction.setShortcut("Ctrl+N") createNewAction.setStatusTip("Create a new Circuit") createNewAction.triggered.connect(self.createNewCircuit) exitAction = QtGui.QAction("Exit", self.main_window) exitAction.setShortcut("Ctrl+Q") exitAction.setStatusTip("Leave the Applikation") exitAction.triggered.connect(self.closeApplication) saveAction = QtGui.QAction("Save", self.main_window) saveAction.setShortcut("Ctrl+S") saveAction.setStatusTip("Save the Applikation") saveAction.triggered.connect(self.save) loadAction = QtGui.QAction("Load", self.main_window) loadAction.setShortcut("Ctrl+O") loadAction.setStatusTip("Load the Applikation") loadAction.triggered.connect(self.load) undoAction = QtGui.QAction("Undo", self.main_window) undoAction.setShortcut("Ctrl+Z") undoAction.setStatusTip("Undo the last Action") undoAction.triggered.connect(self.undo) fileMenu.addAction(createNewAction) fileMenu.addAction(saveAction) fileMenu.addAction(loadAction) fileMenu.addAction(exitAction) editMenu.addAction(undoAction) mainMenu.setObjectName("mainMenu") mainMenu.setStyleSheet( "#mainMenu{padding: 3px; border-bottom: 2px solid #0F9BA8; background-color:white}" ) def createFunctionDropwDowns(self): """This function creates the Drop-Downs for Function selection based ond the funcitonLib""" all_functions = inspect.getmembers(functionLib, inspect.isfunction) self.c_functions = [] self.i_functions = [] self.r_functions = [] self.v_functions = [] self.l_functions = [] for functionTupel in all_functions: if "c_" in functionTupel[0]: self.c_functions.append(functionTupel) elif "i_" in functionTupel[0]: self.i_functions.append(functionTupel) elif "r_" in functionTupel[0]: self.r_functions.append(functionTupel) elif "v_" in functionTupel[0]: self.v_functions.append(functionTupel) elif "l_" in functionTupel[0]: self.l_functions.append(functionTupel) self.function_c_DropwDown = QtGui.QComboBox() self.function_c_DropwDown.addItem("Choose Function") self.function_i_DropwDown = QtGui.QComboBox() self.function_i_DropwDownNew = QtGui.QComboBox() self.function_i_DropwDown.addItem("Choose Function") self.function_i_DropwDownNew.addItem("Choose Function") self.function_r_DropwDown = QtGui.QComboBox() self.function_r_DropwDown.addItem("Choose Function") self.function_v_DropwDown = QtGui.QComboBox() self.function_v_DropwDownNew = QtGui.QComboBox() self.function_v_DropwDown.addItem("Choose Function") self.function_v_DropwDownNew.addItem("Choose Function") self.function_l_DropwDown = QtGui.QComboBox() self.function_l_DropwDown.addItem("Choose Function") for functionTupel in self.c_functions: self.function_c_DropwDown.addItem(functionTupel[0]) for functionTupel in self.i_functions: self.function_i_DropwDown.addItem(functionTupel[0]) self.function_i_DropwDownNew.addItem(functionTupel[0]) for functionTupel in self.r_functions: self.function_r_DropwDown.addItem(functionTupel[0]) for functionTupel in self.v_functions: self.function_v_DropwDown.addItem(functionTupel[0]) self.function_v_DropwDownNew.addItem(functionTupel[0]) for functionTupel in self.l_functions: self.function_l_DropwDown.addItem(functionTupel[0]) self.function_c_DropwDown.hide() self.function_i_DropwDown.hide() #self.function_r_DropwDown.hide() self.function_v_DropwDown.hide() self.function_l_DropwDown.hide() def createCircuitFigure(self): """This function creates the visiual representation of the circuit""" self.circuitFigure = Figure() self.circuitCanvas = FigureCanvas(self.circuitFigure) self.image = QtGui.QLabel() self.image.setGeometry(50, 40, 250, 250) self.image.setObjectName("imageCircuit") self.scrollArea = QtGui.QScrollArea() self.scrollArea.setWidget(self.image) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollCircuit") def createDropDowns(self): """This function creates multile Drop-Downs for the GUI. Mostly used for the input of components""" self.componentDropwDown = QtGui.QComboBox() self.componentDropwDown.addItem("Resistor") self.componentDropwDown.addItem("Coil") self.componentDropwDown.addItem("Capacitator") self.componentDropwDown.addItem("V-Source") self.componentDropwDown.addItem("I-Source") self.componentDropwDown.currentIndexChanged.connect( self.on_ComponentChanged) self.potenzialDropDownFrom = QtGui.QComboBox() self.potenzialDropDownFrom.addItem("---Potencial From---") self.potenzialDropDownFrom.addItem("E-Last") self.potenzialDropDownFrom.addItem("E-Masse") self.potenzialDropDownFrom.setAutoCompletion(True) self.potenzialDropDownTo = QtGui.QComboBox() self.potenzialDropDownTo.addItem("---Potencial To---") self.potenzialDropDownTo.addItem("E-Last") self.potenzialDropDownTo.addItem("E-Masse") self.potenzialDropDownFrom.setAutoCompletion(True) self.directionDropwDown = QtGui.QComboBox() self.directionDropwDown.addItem("left") self.directionDropwDown.addItem("right") self.directionDropwDown.addItem("up") self.directionDropwDown.addItem("down") self.potenzialDropDown = QtGui.QComboBox() self.potenzialDropDown.setFixedSize(200, 20) self.potenzialDropDown.hide() self.potenzialDropDown.currentIndexChanged.connect( self.onPotencialChanged) def onPotencialChanged(self): """Sets the choosen potencial for plotting graph when Potencial-Drop-Down changed""" self.potencial = self.potenzialDropDown.currentIndex() def createNewCircuit(self): """This function handels the initial creating dialog for creating a new circuit""" all_functions = inspect.getmembers(functionLib, inspect.isfunction) print(all_functions) self.i_functions = [] self.v_functions = [] for functionTupel in all_functions: if "i_" in functionTupel[0]: self.i_functions.append(functionTupel) elif "v_" in functionTupel[0]: self.v_functions.append(functionTupel) self.function_i_DropwDownNew = QtGui.QComboBox() self.function_i_DropwDownNew.addItem("Choose Function") self.function_v_DropwDownNew = QtGui.QComboBox() self.function_v_DropwDownNew.addItem("Choose Function") for functionTupel in self.i_functions: self.function_i_DropwDownNew.addItem(functionTupel[0]) for functionTupel in self.v_functions: self.function_v_DropwDownNew.addItem(functionTupel[0]) self.function_v_DropwDownNew.hide() self.function_i_DropwDownNew.show() self.initParametersDialog = QtGui.QDialog() layout = QtGui.QFormLayout() startLabel = QtGui.QLabel("Choose a start Circuit") self.choosen = 0 self.beginningCircuit = QtGui.QComboBox() self.beginningCircuit.addItem("Start with a I-Source") self.beginningCircuit.addItem("Start with a V-Source") self.beginningCircuit.currentIndexChanged.connect( self.onNewDropChanged) okButton = QtGui.QPushButton("Create New Circuit") okButton.clicked.connect(self.setStartingValues) layout.addRow(startLabel, self.beginningCircuit) layout.addWidget(self.function_v_DropwDownNew) layout.addWidget(self.function_i_DropwDownNew) layout.addRow(okButton) self.initParametersDialog.setLayout(layout) self.initParametersDialog.setWindowTitle("Create a new Circuit") self.initParametersDialog.exec() self.controler = controler.Controler() self.controler.createCircuit(self.choosen, self.function) self.potenzialDropDownFrom.clear() self.potenzialDropDownFrom.addItem("---Ausgangspotenzial---") self.potenzialDropDownFrom.addItem("E-Last") self.potenzialDropDownFrom.addItem("E-Masse") self.potenzialDropDownTo.clear() self.potenzialDropDownTo.addItem("---Eingangspotenzial---") self.potenzialDropDownTo.addItem("E-Last") self.potenzialDropDownTo.addItem("E-Masse") self.updateGraph() def setStartingValues(self): """Sets function when function-drop-downs changed. It has influence on the function for the starting element""" if self.choosen == 0: self.function = self.function_i_DropwDownNew.currentText() else: self.function = self.function_v_DropwDownNew.currentText() self.initParametersDialog.close() def onNewDropChanged(self): """Sets choosen when beginningCircuit - drop-down changed. It determins if the starting element is a voltage or a power-source""" self.choosen = self.beginningCircuit.currentIndex() if self.choosen == 1: self.function_v_DropwDownNew.show() self.function_i_DropwDownNew.hide() else: self.function_i_DropwDownNew.show() self.function_v_DropwDownNew.hide() def save(self): """Saves the current project / current simulation without the simulation data""" objectsToSave = [ self.controler, [ self.potenzialDropDownFrom.itemText(i) for i in range(self.potenzialDropDownFrom.count()) ], [ self.potenzialDropDownTo.itemText(i) for i in range(self.potenzialDropDownTo.count()) ] ] pathFileName = QtGui.QFileDialog.getSaveFileName( None, 'Load ECS-Project', self.path + '\\saved-circuits', 'pickle(*.pickle)') with open(pathFileName, 'wb') as handle: pickle.dump(objectsToSave, handle, protocol=pickle.HIGHEST_PROTOCOL) messagebox = timedMessage.TimerMessageBox("Information", "File successfully saved", 3, self.main_window) messagebox.exec_() self.statusbar.showMessage("File successfully saved", 5000) def load(self): """This function handels the loading of a circuit""" self.potenzialDropDown.hide() self.buttonPlotPotenzial.hide() pathFileName = QtGui.QFileDialog.getOpenFileName( None, 'Load ECS-Project', self.path + '\\saved-circuits', 'pickle(*.pickle)') with open(pathFileName, 'rb') as handle: loadedObjects = pickle.load(handle) messagebox = timedMessage.TimerMessageBox("Informaion", "File successfully loaded", 2, self.main_window) messagebox.exec_() self.statusbar.showMessage("File successfully loaded", 5000) self.controler = loadedObjects[0] self.controler.drawCircuit() self.updateGraph() self.potenzialDropDownFrom.clear() self.potenzialDropDownTo.clear() self.potenzialDropDownFrom.addItems(loadedObjects[1]) self.potenzialDropDownTo.addItems(loadedObjects[2]) def closeApplication(self): """Closes the GUI""" self.quit() def undo(self): """Undo the last modification to the circuit""" haveToRemove = self.controler.undoAddComponent() if haveToRemove: self.potenzialDropDownFrom.removeItem( self.potenzialDropDownFrom.count() - 1) self.potenzialDropDownTo.removeItem( self.potenzialDropDownTo.count() - 1) self.updateGraph() """def on_valueInputChanged(self): self.componentValueDropDown.setCurrentIndex(0)""" def on_valueDropDownChanged(self): """Resets the written component value""" self.componentValueInput.setText("") def on_ComponentChanged(self): """Makes certain input-field visible and hide others if the user selectets a different component""" self.function_c_DropwDown.hide() self.function_i_DropwDown.hide() self.function_r_DropwDown.hide() self.function_v_DropwDown.hide() self.function_l_DropwDown.hide() self.componentValueInput.hide() self.componentValueLabel.hide() if self.componentDropwDown.currentText() == "Coil": self.componentValueInput.setText("0.0") self.componentValueInput.show() self.componentValueLabel.show() self.function_l_DropwDown.show() elif self.componentDropwDown.currentText() == "Resistor": self.function_r_DropwDown.show() elif self.componentDropwDown.currentText() == "Capacitator": self.function_c_DropwDown.show() elif self.componentDropwDown.currentText() == "V-Source": self.function_v_DropwDown.show() elif self.componentDropwDown.currentText() == "I-Source": self.function_i_DropwDown.show() #else: #self.componentValueInput.hide() #self.componentValueLabel.hide() def addComponentToCircuit(self): """Handels the adding of a new component to the circuit""" component = (str(self.componentDropwDown.currentText())) function = "0" if component == "Capacitator": function = self.function_c_DropwDown.currentText() if component == "I-Source": function = self.function_i_DropwDown.currentText() if component == "Resistor": function = self.function_r_DropwDown.currentText() if component == "V-Source": function = self.function_v_DropwDown.currentText() if component == "Coil": function = self.function_l_DropwDown.currentText() direction = (str(self.directionDropwDown.currentText())) name = (str(self.componentNameInput.text())) elabel = self.controler.addComponent( component, direction, name, self.potenzialDropDownFrom.currentIndex(), self.potenzialDropDownTo.currentIndex(), self.componentValueInput.text(), function) if len(elabel) > 0: self.potenzialDropDownFrom.addItem(elabel) self.potenzialDropDownTo.addItem(elabel) self.potenzialDropDownFrom.setCurrentIndex(0) self.potenzialDropDownTo.setCurrentIndex(0) self.componentValueInput.setText("0.0") self.componentValueInput.hide() self.componentValueLabel.hide() self.updateGraph() def updateGraph(self): """Updates the current visual representation of the circuit""" self.pixmap = QtGui.QPixmap("..\\resources\\ergebnis.png") self.image.setPixmap(self.pixmap) def simulate(self): """Collects all nessesary inputs to the start the simulation and starts it""" self.potenzialDropDown.clear() for x in range(len(self.list_potencialInputs)): self.controler.addPotencialValue( "E" + str(x), self.list_potencialInputs[x].text()) self.controler.setTValues(float(self.list_timeInputs[0].text()), float(self.list_timeInputs[1].text())) self.potenzialParameters.close() try: self.controler.writeNetList("Schaltung.txt") self.controler.simulate("Schaltung.txt") qt = QtGui.QMessageBox() qt.setIcon(QtGui.QMessageBox.Information) qt.setWindowTitle("Info") qt.setText("Simulation was successfull!") qt.exec() except: qt = QtGui.QMessageBox() qt.setIcon(QtGui.QMessageBox.Critical) qt.setWindowTitle("An Error Occured") qt.setText( "The circuit could not be simulated \nThe circuit might not be valid" ) qt.exec() for potencial in range(len(self.potenzialDropDownFrom) - 2): self.potenzialDropDown.addItem("Potencial " + str(potencial + 1)) self.potenzialDropDown.show() self.buttonPlotPotenzial.show() def enterPotencialValues(self): """Creates the input fields for the starting values of the simulation""" self.potenzialParameters = QtGui.QDialog() layout = QtGui.QFormLayout() label_t = QtGui.QLabel("Please insert the time to simulate") t_input = QtGui.QLineEdit() t_input.setObjectName("") t_input.setText("1.0") t_input.setValidator(self.validator) label_t_steps = QtGui.QLabel( "Please insert the steps you want to split the time") t_steps_input = QtGui.QLineEdit() t_steps_input.setObjectName("") t_steps_input.setText("1.0") t_steps_input.setValidator(self.validator) layout.addRow(label_t, t_input) layout.addRow(label_t_steps, t_steps_input) self.list_timeInputs = [t_input, t_steps_input] label_infoPotencial = QtGui.QLabel( "Please insert start-value (float) for the potencials") self.list_potencialInputs = [] for potencial in range(len(self.potenzialDropDownFrom) - 2): inputPotencialLayout = QtGui.QHBoxLayout() potencialValueLabel = QtGui.QLabel("Value of Potencial:" + str(potencial)) potencialValueInput = QtGui.QLineEdit() potencialValueInput.setObjectName("") potencialValueInput.setText("1.0") potencialValueInput.setValidator(self.validator) inputPotencialLayout.addWidget(potencialValueLabel) inputPotencialLayout.addWidget(potencialValueInput) layout.addRow(inputPotencialLayout) self.list_potencialInputs.append(potencialValueInput) button_startSimulation = QtGui.QPushButton("Start Simulation") button_startSimulation.clicked.connect(self.simulate) layout.addRow(button_startSimulation) self.potenzialParameters.setLayout(layout) self.potenzialParameters.setWindowTitle("Potencial Values") self.potenzialParameters.exec() def plot2(self): """Plots the simulated data for a choosen potencial""" x = [] y = [] data = self.controler.getSolutionData() for entry in data: x.append(entry[0][0][self.potencial]) y.append(entry[1]) ax = self.figure.add_subplot(111) ax.clear() ax.set_xlabel("Time") ax.set_ylabel("Potencial Value") ax.plot(y, x) self.figure.tight_layout() self.canvas.draw() self.figure.delaxes(ax)
class Qt4Mpl2dCanvas(FigureCanvas): """ A customized Qt widget for matplotlib 2D image. It can be used to replace GraphicsView """ def __init__(self, parent): """ Initialization """ # Instantiating matplotlib Figure self.fig = Figure() self.fig.patch.set_facecolor('white') self.axes = self.fig.add_subplot(111) # return: matplotlib.axes.AxesSubplot # Initialize parent class and set parent FigureCanvas.__init__(self, self.fig) self.setParent(parent) # Set size policy to be able to expanding and resizable with frame FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) # legend and color bar self._colorBar = None # Buffer of data self._currentArray2D = None # image management data structure self._currIndex = 0 self._imagePlotDict = dict() # image size self._xLimit = [0., 1.] self._yLimit = [0., 1.] return @property def array2d(self): """ get the matrix plot now :return: """ return self._currentArray2D def add_2d_plot(self, array2d, x_min, x_max, y_min, y_max, hold_prev, yticklabels=None): """ Add a 2D plot Requirements: (1) a valid 2-dimensional numpy.ndarray (2) x_min, x_max, y_min, y_max are of right order Guarantees: a 2D fill-plot is made :param array2d: :param x_min: :param x_max: :param y_min: :param y_max: :param hold_prev: hold previous image. If False, all 2D image and polygon patches will be removed :param yticklabels: list of string for y ticks :return: """ # Check assert isinstance(array2d, np.ndarray), 'Input array2d must be a numpy array but not %s.' % str(type(array2d)) assert isinstance(x_min, int) and isinstance(x_max, int) and x_min < x_max, \ 'x_min = %s (of type %s) should be less than x_max = %s (of type %s).' \ '' % (str(x_min), str(type(x_min)), str(x_max), str(type(x_max))) assert isinstance(y_min, int) and isinstance(y_max, int) and y_min < y_max # Release the current image self.axes.hold(hold_prev) # show image img_plot = self.axes.imshow(array2d, extent=[x_min, x_max, y_min, y_max], interpolation='none') self._currentArray2D = array2d # set y ticks as an option: if yticklabels is not None: # it will always label the first N ticks even image is zoomed in # FUTURE-VZ : The way to set up the Y-axis ticks is wrong!" # self.axes.set_yticklabels(yticklabels) print('[Warning] The method to set up the Y-axis ticks to 2D image is wrong!') # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type img_plot.set_cmap('spectral') self._colorBar = self.fig.colorbar(img_plot) else: self._colorBar.update_bruteforce(img_plot) # Flush... self._flush() # Add the image management self._currIndex += 1 self._imagePlotDict[self._currIndex] = img_plot return self._currIndex def add_patch(self, patch): """ add an artist patch such as polygon :param patch: :return: """ self.axes.add_artist(patch) # Flush... self._flush() return def addImage(self, imagefilename): """ Add an image by file """ # set aspect to auto mode self.axes.set_aspect('auto') img = matplotlib.image.imread(str(imagefilename)) # lum_img = img[:,:,0] # FUTURE : refactor for image size, interpolation and origin imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) self._flush() return def clear_canvas(self): """ Clear data including lines and image from canvas """ # clear the image for next operation self.axes.hold(False) # clear 2D image self.axes.cla() # Try to clear the color bar if len(self.fig.axes) > 1: self.fig.delaxes(self.fig.axes[1]) self._colorBar = None # This clears the space claimed by color bar but destroys sub_plot too. self.fig.clear() # Re-create subplot self.axes = self.fig.add_subplot(111) # END-FOR # flush/commit self._flush() return def plot_polygon(self, vertex_array, fill=False, color='w'): """ Plot a new polygon :param vertex_array: :param fill: :param color: :return: """ # check requirements assert isinstance(vertex_array, np.ndarray) assert isinstance(fill, bool) assert isinstance(color, str) # plot polygon p = plt.Polygon(vertex_array, fill=fill, color=color) self.axes.add_artist(p) # Flush... self._flush() return p @property def x_min(self): """ x minimum :return: """ return self._xLimit[0] @property def x_max(self): """ maximum x :return: """ return self._xLimit[1] @property def y_min(self): """ minimum y :return: """ return self._yLimit[0] @property def y_max(self): """ maximum y :return: """ return self._yLimit[1] def _flush(self): """ A dirty hack to flush the image """ w, h = self.get_width_height() self.resize(w+1, h) self.resize(w, h) return
class FigureCanvas(FigureCanvasQTAgg): """ A customized Qt widget for matplotlib figure. It can be used to replace GraphicsView of QtGui """ def __init__(self, parent): self._driver = AddieDriver() # from mpl_toolkits.axes_grid1 import host_subplot # import mpl_toolkits.axisartist as AA # import matplotlib.pyplot as plt # Instantiating matplotlib Figure self.fig = Figure() self.fig.patch.set_facecolor('white') self.axes = self.fig.add_subplot(111, projection='mantid') self.fig.subplots_adjust(bottom=0.15) # Initialize parent class and set parent FigureCanvasQTAgg.__init__(self, self.fig) self.setParent(parent) # Set size policy to be able to expanding and resizable with frame FigureCanvasQTAgg.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) FigureCanvasQTAgg.updateGeometry(self) # Variables to manage all lines/subplot self._lineDict = {} self._lineIndex = 0 # legend and color bar self._colorBar = None self._isLegendOn = False self._legendFontSize = 10 @property def is_legend_on(self): """ check whether the legend is shown or hide """ return self._isLegendOn def add_arrow(self, start_x, start_y, stop_x, stop_y): """ 0, 0, 0.5, 0.5, head_width=0.05, head_length=0.1, fc='k', ec='k') :return: """ head_width = 0.05 head_length = 0.1 fc = 'k' ec = 'k' self.axes.arrrow(start_x, start_y, stop_x, stop_y, head_width, head_length, fc, ec) def add_plot_1d(self, wkspname, wkspindex, color=None, label="", x_label=None, y_label=None, marker=None, line_style=None, line_width=1, alpha=1., show_legend=True, plotError=False): # process inputs and defaults if color is None: color = (0, 1, 0, 1) if marker is None: marker = 'None' if line_style is None: line_style = '-' # color must be RGBA (4-tuple) wksp = addie.utilities.workspaces.get_ws(wkspname) if plotError: r = self.axes.errorbar(wksp, wkspIndex=wkspindex, color=color, marker=marker, linestyle=line_style, label=label, linewidth=line_width, alpha=alpha, markersize=40) else: # return: list of matplotlib.lines.Line2D object r = self.axes.plot(wksp, wkspIndex=wkspindex, color=color, marker=marker, markersize=2, linestyle=line_style, label=label, linewidth=line_width, alpha=alpha, distribution=True) self.axes.set_aspect('auto') # set x-axis and y-axis label if x_label is not None: self.axes.set_xlabel(x_label, fontsize=20) if y_label is not None: self.axes.set_ylabel(y_label, fontsize=20) # set/update legend if show_legend: self._setup_legend() # Register line_key = self._lineIndex if len(r) == 1: self._lineDict[line_key] = r[0] self._lineIndex += 1 else: msg = 'Return from plot is a %d-tuple: %s.. \n' % (len(r), r) for i_r in range(len(r)): msg += 'r[%d] = %s\n' % (i_r, str(r[i_r])) raise NotImplementedError(msg) # Flush/commit self.draw() return line_key def addPlot2D(self, array2d, xmin, xmax, ymin, ymax, holdprev, yticklabels=None): """ Add a 2D plot Arguments: - yticklabels :: list of string for y ticks """ # Release the current image self.axes.hold(holdprev) # Do plot # y ticks will be shown on line 1, 4, 23, 24 and 30 # yticks = [1, 4, 23, 24, 30] # self.axes.set_yticks(yticks) # show image imgplot = self.axes.imshow(array2d, extent=[xmin, xmax, ymin, ymax], interpolation='none') # set y ticks as an option: if yticklabels is not None: # it will always label the first N ticks even image is zoomed in print( "--------> [FixMe]: The way to set up the Y-axis ticks is wrong!" ) # self.axes.set_yticklabels(yticklabels) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) # Flush... self._flush() def add_contour_plot(self, vec_x, vec_y, matrix_z): # create mesh grid grid_x, grid_y = np.meshgrid(vec_x, vec_y) # check size assert grid_x.shape == matrix_z.shape, 'Size of X (%d) and Y (%d) must match size of Z (%s).' \ '' % (len(vec_x), len(vec_y), matrix_z.shape) # Release the current image self.axes.hold(False) # Do plot contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100) labels = [item.get_text() for item in self.axes.get_yticklabels()] print('[DB...BAT] Number of Y labels = ', len(labels), ', Number of Y = ', len(vec_y)) # TODO/ISSUE/55: how to make this part more powerful if len(labels) == 2 * len(vec_y) - 1: new_labels = [''] * len(labels) for i in range(len(vec_y)): new_labels[i * 2] = '%d' % int(vec_y[i]) self.axes.set_yticklabels(new_labels) # explicitly set aspect ratio of the image self.axes.set_aspect('auto') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type contour_plot.set_cmap('spectral') self._colorBar = self.fig.colorbar(contour_plot) else: self._colorBar.update_bruteforce(contour_plot) # Flush... self._flush() def addImage(self, imagefilename): """ Add an image by file """ #import matplotlib.image as mpimg # set aspect to auto mode self.axes.set_aspect('auto') img = matplotlib.image.imread(str(imagefilename)) # lum_img = img[:,:,0] # FUTURE : refactor for image size, interpolation and origin imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') # Set color bar. plt.colorbar() does not work! if self._colorBar is None: # set color map type imgplot.set_cmap('spectral') self._colorBar = self.fig.colorbar(imgplot) else: self._colorBar.update_bruteforce(imgplot) self._flush() def clear_all_1d_plots(self): """ Remove all lines from the canvas """ for ikey in list(self._lineDict.keys()): plot = self._lineDict[ikey] if plot is None: continue if isinstance(plot, tuple) is False: try: self.axes.lines.remove(plot) except ValueError as e: print( "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (str(plot), len(self.axes.lines), str(e))) del self._lineDict[ikey] else: # error bar plot[0].remove() for line in plot[1]: line.remove() for line in plot[2]: line.remove() del self._lineDict[ikey] # ENDIF(plot) # ENDFOR self._setup_legend() self.draw() def clear_canvas(self): """ Clear data including lines and image from canvas """ # clear the image for next operation self.axes.hold(False) # Clear all lines self.clear_all_1d_plots() # clear image self.axes.cla() # Try to clear the color bar if len(self.fig.axes) > 1: self.fig.delaxes(self.fig.axes[1]) self._colorBar = None # This clears the space claimed by color bar but destroys sub_plot # too. self.fig.clear() # Re-create subplot self.axes = self.fig.add_subplot(111) self.fig.subplots_adjust(bottom=0.15) # flush/commit self._flush() def decrease_legend_font_size(self): """ reset the legend with the new font size Returns: """ # minimum legend font size is 2! return if it already uses the smallest # font size. if self._legendFontSize <= 2: return self._legendFontSize -= 1 self._setup_legend() self.draw() def getLastPlotIndexKey(self): """ Get the index/key of the last added line """ return self._lineIndex - 1 def getPlot(self): """ reture figure's axes to expose the matplotlib figure to PyQt client """ return self.axes def getXLimit(self): """ Get limit of Y-axis """ return self.axes.get_xlim() def getYLimit(self): """ Get limit of Y-axis """ return self.axes.get_ylim() def hide_legend(self): """ hide the legend if it is not None """ if self.axes.legend() is not None: # set visible to be False and re-draw self.axes.legend().set_visible(False) self.draw() self._isLegendOn = False def increase_legend_font_size(self): """ reset the legend with the new font size """ self._legendFontSize += 1 self._setup_legend() self.draw() def setXYLimit(self, xmin, xmax, ymin, ymax): # for X xlims = self.axes.get_xlim() xlims = list(xlims) if xmin is not None: xlims[0] = xmin if xmax is not None: xlims[1] = xmax self.axes.set_xlim(xlims) # for Y ylims = self.axes.get_ylim() ylims = list(ylims) if ymin is not None: ylims[0] = ymin if ymax is not None: ylims[1] = ymax self.axes.set_ylim(ylims) # try draw self.draw() def set_title(self, title, color): # TODO/NOW - doc & etc self.axes.set_title(title, loc='center', color=color) self.draw() def remove_plot_1d(self, plot_key): """ Remove the line with its index as key """ # Get all lines in list lines = self.axes.lines assert isinstance(lines, list), 'Lines must be list' if plot_key in self._lineDict: try: self.axes.lines.remove(self._lineDict[plot_key]) except ValueError as r_error: error_message = 'Unable to remove to 1D line %s (ID=%d) due to %s.' % ( str(self._lineDict[plot_key]), plot_key, str(r_error)) raise RuntimeError(error_message) # remove the plot key from dictionary del self._lineDict[plot_key] else: raise RuntimeError('Line with ID %s is not recorded.' % plot_key) self._setup_legend() # Draw self.draw() def show_legend(self): """ show the legend if the legend is not None Returns: """ if self.axes.legend() is not None: # set visible to be True and re-draw # self.axes.legend().set_visible(True) self._setup_legend() self.draw() # set flag on self._isLegendOn = True def updateLine(self, ikey=-1, wkspname=None, wkspindex=None, vecx=None, vecy=None, linestyle=None, linecolor=None, marker=None, markercolor=None): """ Update a plot line or a series plot line """ line = self._lineDict[ikey] if line is None: print('[ERROR] Line (key = %d) is None. Unable to update' % ikey) return if wkspname or (vecx and vecy): if wkspname: vecx, vecy, _ = addie.utilities.workspaces.get_ws_data( wkspname, wkspindex) line.set_data(vecx, vecy) if linecolor is not None: line.set_color(linecolor) if linestyle is not None: line.set_linestyle(linestyle) if marker is not None: line.set_marker(marker) if markercolor is not None: line.set_markerfacecolor(markercolor) oldlabel = line.get_label() line.set_label(oldlabel) self._setup_legend() # commit self.draw() def get_data(self, line_id): """ Get vecX and vecY from line object in matplotlib :param line_id: :return: 2-tuple as vector X and vector Y """ # check if line_id not in self._lineDict: raise KeyError('Line ID %s does not exist.' % str(line_id)) # get line line = self._lineDict[line_id] if line is None: raise RuntimeError('Line ID %s has been removed.' % line_id) return line.get_xdata(), line.get_ydata() def getLineStyleList(self): return LINE_STYLES def getLineMarkerList(self): return LINE_MARKERS def getLineBasicColorList(self): return BASIC_COLORS def getDefaultColorMarkerComboList(self): """ Get a list of line/marker color and marker style combination as default to add more and more line to plot """ combo_list = list() num_markers = len(LINE_MARKERS) num_colors = len(BASIC_COLORS) for i in range(num_markers): marker = LINE_MARKERS[i] for j in range(num_colors): color = BASIC_COLORS[j] combo_list.append((marker, color)) # ENDFOR (j) # ENDFOR(i) return combo_list def _flush(self): """ A dirty hack to flush the image """ w, h = self.get_width_height() self.resize(w + 1, h) self.resize(w, h) def _setup_legend(self, location='best'): """ Set up legend self.axes.legend(): Handler is a Line2D object. Lable maps to the line object """ allowed_location_list = [ "best", "upper right", "upper left", "lower left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center" ] # Check legend location valid or not if location not in allowed_location_list: location = 'best' handles, labels = self.axes.get_legend_handles_labels() self.axes.legend(handles, labels, loc=location, fontsize=self._legendFontSize) self._isLegendOn = True