class CanvasFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, "CanvasFrame", size=(550, 350)) color = wx.Colour("WHITE") self.SetBackgroundColour(color) self.figure = Figure() self.axes = self.figure.add_subplot(111) t = arange(0.0, 3.0, 0.01) s = sin(2 * pi * t) self.axes.plot(t, s) self.canvas = FigureCanvas(self, -1, self.figure) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizerAndFit(self.sizer) self.add_toolbar() def add_toolbar(self): self.toolbar = NavigationToolbar2Wx(self.canvas) self.toolbar.Realize() if wx.Platform == "__WXMAC__": self.SetToolBar(self.toolbar) else: tw, th = self.toolbar.GetSize() fw, fh = self.canvas.GetSize() self.toolbar.SetSize(wx.Size(fw, th)) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) self.toolbar.update() def OnPaint(self, event): self.canvas.draw()
class PlotPanel(wx.Panel): """ A panel on which is drawn the map with wanted data. """ def __init__(self, parent, size : tuple, dataset : nc.Dataset, map_options : dict, presets : dict, tb_option : bool = True): super(PlotPanel, self).__init__(parent=parent, id=wx.ID_ANY, size=size) self.parent = parent self.dataset = dataset self.map_options = map_options self.presets = presets self.figure = MplFig(figsize=(10.8, 6)) self.figure.set_facecolor('xkcd:grey') self.axes = self.figure.add_subplot(111) self.canvas = FigureCanvas(self, -1, self.figure) self.main_sizer = wx.BoxSizer(wx.VERTICAL) self.main_sizer.Add(self.canvas, 0, wx.EXPAND) self.toolbar = None if tb_option: self.add_toolbar() self.main_sizer.Add(self.toolbar, 0, wx.EXPAND | wx.LEFT, 20) self.toolbar.update() self.SetSizer(self.main_sizer) def draw(self): """ Draw the data and the map. """ # Create figure fig = Figure(figure=self.figure, ax=self.axes, dataset=self.dataset, map_options=self.map_options, presets=self.presets) fig.plot_data() self.figure.tight_layout() self.figure.canvas.draw() def add_toolbar(self): """ Add a toolbar to the Canvas. """ self.toolbar = NavigationToolbar2Wx(self.canvas) self.toolbar.Realize() tw, th = self.toolbar.GetSize() cw, ch = self.canvas.GetSize() self.toolbar.SetSize(wx.Size(cw, ch))
class ring_pattern(wx.Frame): def __init__(self, parent): wx.Frame.__init__(self, parent, -1, "Ring Figure - " + parent.filename, size=(550, 400)) self.parent = parent iconFile = os.path.join(parent.parent.iconspath, "diff_profiler_ico.ico") icon1 = wx.Icon(iconFile, wx.BITMAP_TYPE_ICO) self.SetIcon(icon1) self.mpl_old = self.parent.mpl_old self.background_sub = self.parent.background_sub self.prosim = self.parent.prosim self.plot_sim = self.parent.plot_sim self.ring_patt = [] self.back_patt = [] self.dirname = self.parent.dirname self.statbar = self.CreateStatusBar( ) # A Statusbar in the bottom of the window self.statbar.SetFieldsCount(2) self.statbar.SetStatusText("None", 1) # Setting up the menu. filemenu is a local variable at this stage. figmenu = wx.Menu() # use ID_ for future easy reference - much better than "48", "404" etc # The & character indicates the short cut key self.Save_evt = figmenu.Append( wx.NewId(), "&Save Figure", "Save the figure as vestor or highres image") self.BGSub_evt = figmenu.AppendCheckItem( wx.NewId(), "&Background Subtract", "Subtract the profile fitted background from the pattern image") self.ProSim_evt = figmenu.AppendCheckItem( wx.NewId(), "&Profile Simulation", "Show the ring pattern from a profile simulation") self.PeakSim_evt = figmenu.AppendCheckItem( wx.NewId(), "Peak &Simulation", "Show a peak simulation as rings") if self.parent.background_sub: self.BGSub_evt.Check(True) else: self.BGSub_evt.Enable(False) if self.parent.prosim: self.ProSim_evt.Check(True) else: self.ProSim_evt.Enable(False) if self.parent.plot_sim: self.PeakSim_evt.Check(True) else: self.PeakSim_evt.Enable(False) # Creating the menubar. menuBar = wx.MenuBar() menuBar.Append(figmenu, "&Figure") # Adding the "patternmenu" to the MenuBar self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content. # Note - previous line stores the whole of the menu into the current object self.SetBackgroundColour(wx.Colour("WHITE")) self.figure = Figure(figsize=(8, 8), dpi=76) self.axes = self.figure.add_axes([0, 0, 1, 1], yticks=[], xticks=[], frame_on=False) # self.canvas = FigureCanvas(self, -1, self.figure) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) # Capture the paint message self.Bind(wx.EVT_PAINT, self.OnPaint) self.toolbar = MyNavigationToolbar2(self, self.canvas, True) self.toolbar.Realize() tw, th = self.toolbar.GetSize() fw, fh = self.canvas.GetSize() self.toolbar.SetSize(wx.Size(fw, th)) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() # Define the code to be run when a menu option is selected if self.mpl_old: self.Bind(wx.EVT_MENU, self.toolbar.save, self.Save_evt) self.Bind(wx.EVT_MENU, self.toolbar.save_figure, self.Save_evt) self.Bind(wx.EVT_MENU, self.OnBGSub, self.BGSub_evt) self.Bind(wx.EVT_MENU, self.OnProSim, self.ProSim_evt) self.Bind(wx.EVT_MENU, self.OnPeakSim, self.PeakSim_evt) self.SetSizer(self.sizer) self.Fit() self.ring_plot() def OnBGSub(self, event): #self.id = event.GetId() if self.BGSub_evt.IsChecked(): self.background_sub = 1 else: self.background_sub = 0 self.ring_plot() def OnProSim(self, event): #self.id = event.GetId() if self.ProSim_evt.IsChecked(): self.prosim = 1 else: self.prosim = 0 self.ring_plot() def OnPeakSim(self, event): #self.id = event.GetId() if self.PeakSim_evt.IsChecked(): self.plot_sim = 1 else: self.plot_sim = 0 self.axes.cla() self.ring_plot() def OnPaint(self, event): self.canvas.draw() event.Skip() def ring_plot(self): #rc('font', size=16) if self.parent.latex: rc('text', usetex=True) rc('font', family='serif') else: rc('text', usetex=False) rc('font', family='sans-serif') rc('mathtext', fontset='custom') self.origin = [round(self.parent.C[1]), round(self.parent.C[0])] #self.pattern_open_crop = self.parent.pattern_open[origin[0]-(self.parent.boxs-6):origin[0]+(self.parent.boxs-3),origin[1]-(self.parent.boxs-6):origin[1]+(self.parent.boxs-3)] self.pattern_open_crop = self.parent.pattern_open[ int(self.origin[0] - (self.parent.boxs)):int(self.origin[0] + (self.parent.boxs)), int(self.origin[1] - (self.parent.boxs)):int(self.origin[1] + (self.parent.boxs))] if self.background_sub == 1: self.do_background_sub() self.axes.imshow( self.pattern_open_crop, cmap='gray', interpolation='bicubic', extent=(-self.parent.drdf.max(), self.parent.drdf.max(), -self.parent.drdf.max(), self.parent.drdf.max())) if self.prosim == 1: self.do_prosim() if self.plot_sim == 1: self.do_plot_sim() #self.axes.plot(0,0,'+') #self.axes.axis('equal') self.axes.set_xlim(-self.parent.limit, self.parent.limit) self.axes.set_ylim(-self.parent.limit, self.parent.limit) #self.axes.xaxis.set_ticks_position('bottom') #self.axes.yaxis.set_ticks_position('left') self.axes.figure.canvas.draw() def do_background_sub(self): if self.back_patt == []: self.back_patt = make_profile_rings( self.parent.background - self.parent.background.min(), self.parent.drdf, self.origin, self.parent.boxs, True) #figure() #imshow(self.back_patt, cmap = 'gray') #show() print(self.pattern_open_crop.shape, self.back_patt.shape, self.origin) print(self.parent.rdf.max(), self.back_patt.max(), self.pattern_open_crop.max(), self.parent.rdf_max) middle_x = self.back_patt.shape[1] / 2 self.back_patt = self.back_patt * self.parent.rdf_max #figure() #plot(self.back_patt[:,middle_x]) #plot(self.pattern_open_crop[:,middle_x]) #line = self.pattern_open_crop[:,middle_x] - self.back_patt[:,middle_x] #plot(line) #line[line < 0] = 0 #plot(line) self.pattern_open_crop = self.pattern_open_crop.astype(np.float32) self.pattern_open_crop -= self.back_patt #plot(self.pattern_open_crop[:,middle_x]) self.pattern_open_crop[self.pattern_open_crop < 0] = 0 #plot(self.pattern_open_crop[:,middle_x]) #show() print(self.pattern_open_crop.min(), self.pattern_open_crop.max()) def do_plot_sim(self): sim_name = [] marks = [] color = ['#42D151', '#2AA298', '#E7E73C'] marker = ['o', '^', 's'] print(len(self.parent.simulations)) #, self.srdfb if len(self.parent.simulations) >= 3: sim_len_i = 3 else: sim_len_i = len(self.parent.simulations) print(sim_len_i) #,self.srdfb[sim_len_i[0]],self.sdrdfb[sim_len_i[0]] for col_index, simulation in enumerate( self.parent.simulations[-sim_len_i:]): sim_color = simulation.sim_color if simulation.sim_color else color[ col_index] sim_name += [simulation.sim_label] sim = simulation.srdf sim_norm = sim / float(max(sim)) #print(sim, max(sim[1:]), min(sim[1:]), sim_norm) marks += [ self.axes.plot(0, 0, '-', color=sim_color, zorder=-10)[0] ] rect = patches.Rectangle((-self.parent.limit, -self.parent.limit), self.parent.limit, self.parent.limit, facecolor="none", edgecolor="none") self.axes.add_patch(rect) if not simulation.peak_index_labels: for radius in simulation.sdrdf: #print(radius) circ_mark = patches.Circle((0, 0), radius, fill=0, color=sim_color, linewidth=2, alpha=.7) self.axes.add_patch(circ_mark) circ_mark.set_clip_path(rect) self.axes.set_autoscale_on(False) #sim_index = nonzero(self.srdfb[i]!=0) else: j = 0 for i, label in enumerate(simulation.peak_index_labels[::-1]): #print(label) if label: circ_mark = patches.Circle((0, 0), simulation.sdrdf[::-1][i], fill=0, color=sim_color, linewidth=2, alpha=.7) self.axes.add_patch(circ_mark) circ_mark.set_clip_path(rect) self.axes.set_autoscale_on(False) if label.find('-') == -1: label = r'(' + label + ')' else: label = r'$\mathsf{(' + label.replace( '-', r'\bar ') + ')}$' #print(label) bbox_props = dict(boxstyle="round", fc=sim_color, ec="0.5", alpha=1, lw=1.5) arrowprops = dict( arrowstyle="wedge,tail_width=1.", fc=sim_color, ec="0.5", alpha=.7, patchA=None, patchB=circ_mark, relpos=(0.5, 0.5), ) an = self.axes.annotate(label, xy=(0, 0), xytext=(.1 + col_index / 10.0, .1 + j / 15.0), textcoords='axes fraction', ha="center", va="center", size=20, rotation=0, zorder=90 - col_index, picker=True, bbox=bbox_props, arrowprops=arrowprops) an.draggable() j += 1 print(sim_name, marks) leg = self.axes.legend(marks, sim_name, loc='upper left', shadow=0, fancybox=True, numpoints=1, prop={'size': 16}) frame = leg.get_frame() frame.set_alpha(0.7) for handle in leg.legendHandles: handle.set_linewidth(3.0) def do_prosim(self): if self.ring_patt == []: self.ring_patt = make_profile_rings(self.parent.prosim_int, self.parent.prosim_inv_d, self.origin, self.parent.boxs) self.axes.imshow(self.ring_patt[:, :self.ring_patt.shape[1] // 2], cmap='gray', origin='lower', interpolation='bicubic', extent=(-self.parent.prosim_inv_d.max(), 0, -self.parent.prosim_inv_d.max(), self.parent.prosim_inv_d.max())) print(self.parent.prosim_inv_d.max())
class PanelGraph(wx.Panel): def __init__(self, panel, notify, settings, status, remoteControl): self.panel = panel self.notify = notify self.plot = None self.settings = settings self.status = status self.remoteControl = remoteControl self.spectrum = None self.isLimited = None self.limit = None self.extent = None self.annotate = None self.isDrawing = False self.toolTip = wx.ToolTip('') self.mouseSelect = None self.mouseZoom = None self.measureTable = None self.background = None self.selectStart = None self.selectEnd = None self.menuClearSelect = [] self.measure = None self.show = None self.doDraw = False wx.Panel.__init__(self, panel) self.figure = matplotlib.figure.Figure(facecolor='white') self.figure.set_size_inches(0, 0) self.canvas = FigureCanvas(self, -1, self.figure) self.canvas.SetToolTip(self.toolTip) self.measureTable = PanelMeasure(self, settings) self.toolbar = NavigationToolbar(self.canvas, self, settings, self.__hide_overlay) self.toolbar.Realize() vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(self.canvas, 1, wx.EXPAND) vbox.Add(self.measureTable, 0, wx.EXPAND) vbox.Add(self.toolbar, 0, wx.EXPAND) self.SetSizer(vbox) vbox.Fit(self) self.create_plot() self.canvas.mpl_connect('button_press_event', self.__on_press) self.canvas.mpl_connect('figure_enter_event', self.__on_enter) self.canvas.mpl_connect('axes_leave_event', self.__on_leave) self.canvas.mpl_connect('motion_notify_event', self.__on_motion) self.canvas.mpl_connect('draw_event', self.__on_draw) self.canvas.mpl_connect('idle_event', self.__on_idle) self.Bind(wx.EVT_SIZE, self.__on_size) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.__on_timer, self.timer) def __set_fonts(self): axes = self.plot.get_axes() if axes is not None: axes.xaxis.label.set_size('small') axes.yaxis.label.set_size('small') if self.settings.display == Display.SURFACE: axes.zaxis.label.set_size('small') axes.tick_params(axis='both', which='major', labelsize='small') axes = self.plot.get_axes_bar() if axes is not None: axes.tick_params(axis='both', which='major', labelsize='small') def __enable_menu(self, state): for menu in self.menuClearSelect: menu.Enable(state) def __on_press(self, event): if self.settings.clickTune and matplotlib.__version__ >= '1.2' and event.dblclick: frequency = int(event.xdata * 1e6) self.remoteControl.tune(frequency) elif isinstance(self.plot, PlotterPreview): self.plot.to_front() def __on_enter(self, _event): self.toolTip.Enable(False) def __on_leave(self, _event): self.toolTip.Enable(True) self.status.set_info('', level=None) def __on_motion(self, event): axes = self.plot.get_axes() axesBar = self.plot.get_axes_bar() xpos = event.xdata ypos = event.ydata text = "" if (xpos is None or ypos is None or self.spectrum is None or event.inaxes is None): spectrum = None elif event.inaxes == axesBar: spectrum = None level = self.plot.get_bar().norm.inverse(ypos) text = "{}".format(format_precision(self.settings, level=level)) elif self.settings.display == Display.PLOT: timeStamp = max(self.spectrum) spectrum = self.spectrum[timeStamp] elif self.settings.display == Display.SPECT: timeStamp = num2epoch(ypos) if timeStamp in self.spectrum: spectrum = self.spectrum[timeStamp] else: nearest = min(self.spectrum.keys(), key=lambda k: abs(k - timeStamp)) spectrum = self.spectrum[nearest] elif self.settings.display == Display.SURFACE: spectrum = None coords = axes.format_coord(event.xdata, event.ydata) match = re.match('x=([-|0-9|\.]+).*y=([0-9|\:]+).*z=([-|0-9|\.]+)', coords) if match is not None and match.lastindex == 3: freq = float(match.group(1)) level = float(match.group(3)) text = "{}, {}".format( *format_precision(self.settings, freq, level)) else: spectrum = None if spectrum is not None and len(spectrum) > 0: x = min(spectrum.keys(), key=lambda freq: abs(freq - xpos)) if min(spectrum.keys(), key=float) <= xpos <= max(spectrum.keys(), key=float): y = spectrum[x] text = "{}, {}".format(*format_precision(self.settings, x, y)) else: text = format_precision(self.settings, xpos) markers = find_artists(self.figure, 'peak') markers.extend(find_artists(self.figure, 'peakThres')) hit = False for marker in markers: if isinstance(marker, Line2D): location = marker.get_path().vertices[0] markX, markY = axes.transData.transform(location) dist = abs(math.hypot(event.x - markX, event.y - markY)) if dist <= 5: if self.settings.display == Display.PLOT: tip = "{}, {}".format(*format_precision( self.settings, location[0], location[1])) else: tip = "{}".format( format_precision(self.settings, location[0])) self.toolTip.SetTip(tip) hit = True break self.toolTip.Enable(hit) self.status.set_info(text, level=None) def __on_size(self, event): ppi = wx.ScreenDC().GetPPI() size = [float(v) for v in self.canvas.GetSize()] width = size[0] / ppi[0] height = size[1] / ppi[1] self.figure.set_figwidth(width) self.figure.set_figheight(height) self.figure.set_dpi(ppi[0]) event.Skip() def __on_draw(self, _event): axes = self.plot.get_axes() if axes is not None: self.background = self.canvas.copy_from_bbox(axes.bbox) self.__draw_overlay() def __on_idle(self, _event): if self.doDraw and self.plot.get_plot_thread() is None: self.__hide_overlay() self.doDraw = False if os.name == 'nt': threading.Thread(target=self.__draw_canvas, name='Draw').start() else: self.__draw_canvas() def __on_timer(self, _event): self.timer.Stop() self.set_plot(None, None, None, None, self.annotate) def __draw_canvas(self): try: self.isDrawing = True self.canvas.draw() except wx.PyDeadObjectError: pass self.isDrawing = False wx.CallAfter(self.status.set_busy, False) def __draw_overlay(self): if self.background is not None: self.canvas.restore_region(self.background) self.__draw_select() self.draw_measure() axes = self.plot.get_axes() if axes is not None: self.canvas.blit(axes.bbox) def __draw_select(self): if self.selectStart is not None and self.selectEnd is not None: self.mouseSelect.draw(self.selectStart, self.selectEnd) def __hide_overlay(self): if self.plot is not None: self.plot.hide_measure() self.__hide_select() def __hide_select(self): if self.mouseSelect is not None: self.mouseSelect.hide() def create_plot(self): if self.plot is not None: self.plot.close() self.toolbar.set_auto(True) if self.settings.display == Display.PLOT: self.plot = Plotter(self.notify, self.figure, self.settings) elif self.settings.display == Display.SPECT: self.plot = Spectrogram(self.notify, self.figure, self.settings) elif self.settings.display == Display.SURFACE: self.plot = Plotter3d(self.notify, self.figure, self.settings) elif self.settings.display == Display.STATUS: self.plot = PlotterStatus(self.notify, self.figure, self.settings) elif self.settings.display == Display.TIMELINE: self.plot = PlotterTime(self.notify, self.figure, self.settings) elif self.settings.display == Display.PREVIEW: self.plot = PlotterPreview(self.notify, self.figure, self.settings) self.plot.set_window(self) self.__set_fonts() self.toolbar.set_plot(self.plot) self.toolbar.set_type(self.settings.display) self.measureTable.set_type(self.settings.display) self.set_plot_title() self.figure.subplots_adjust(top=0.85) self.redraw_plot() self.plot.scale_plot(True) self.mouseZoom = MouseZoom(self.toolbar, plot=self.plot, callbackHide=self.__hide_overlay) self.mouseSelect = MouseSelect(self.plot, self.on_select, self.on_selected) self.measureTable.show(self.settings.showMeasure) self.panel.SetFocus() def on_select(self): self.hide_measure() def on_selected(self, start, end): self.__enable_menu(True) self.selectStart = start self.selectEnd = end self.measureTable.set_selected(self.spectrum, start, end) def add_menu_clear_select(self, menu): self.menuClearSelect.append(menu) menu.Enable(False) def draw(self): self.doDraw = True def show_measure_table(self, show): self.measureTable.show(show) self.Layout() def set_plot(self, spectrum, isLimited, limit, extent, annotate=False): if spectrum is not None and extent is not None: if isLimited is not None and limit is not None: self.spectrum = copy.copy(spectrum) self.extent = extent self.annotate = annotate self.isLimited = isLimited self.limit = limit if self.plot.get_plot_thread() is None and not self.isDrawing: self.timer.Stop() self.measureTable.set_selected(self.spectrum, self.selectStart, self.selectEnd) if isLimited: self.spectrum = reduce_points(spectrum, limit) self.status.set_busy(True) self.plot.set_plot(self.spectrum, self.extent, annotate) if self.settings.display == Display.PREVIEW: self.status.set_busy(False) else: self.timer.Start(200, oneShot=True) def set_plot_title(self): if len(self.settings.devicesRtl) > 0: gain = self.settings.devicesRtl[self.settings.indexRtl].gain else: gain = 0 self.plot.set_title("Frequency Spectrogram\n{} - {} MHz," " gain = {}dB".format(self.settings.start, self.settings.stop, gain)) def redraw_plot(self): if self.spectrum is not None: self.set_plot(self.spectrum, self.settings.pointsLimit, self.settings.pointsMax, self.extent, self.settings.annotate) def set_grid(self, on): self.plot.set_grid(on) def set_selected(self, start, end): self.selectStart = start self.selectEnd = end self.__draw_select() def hide_toolbar(self, hide): self.toolbar.Show(not hide) def hide_measure(self): if self.plot is not None: self.plot.hide_measure() def draw_measure(self): if self.measure is not None and self.measure.is_valid(): self.plot.draw_measure(self.measure, self.show) def update_measure(self, measure=None, show=None): if not measure and not show: self.measureTable.update_measure() else: self.measure = measure self.show = show self.__draw_overlay() def get_figure(self): return self.figure def get_axes(self): return self.plot.get_axes() def get_canvas(self): return self.canvas def get_toolbar(self): return self.toolbar def get_mouse_select(self): return self.mouseSelect def scale_plot(self, force=False): self.plot.scale_plot(force) def clear_plots(self): self.plot.clear_plots() self.spectrum = None self.doDraw = True def clear_selection(self): self.measure = None self.measureTable.clear_measurement() self.selectStart = None self.selectEnd = None self.mouseSelect.clear() self.__enable_menu(False) def close(self): self.plot.close() close_modeless()
class Panel_Plotting_Helper(wx.Panel): def __init__(self, parent): w, h = parent.GetSize() wx.Panel.__init__(self, parent=parent, size=(w, 0.7 * h), style=wx.SUNKEN_BORDER) self.parent = parent self.legends = [] self.legendpos = [0.5, 1] self.fig = Figure( figsize=(12, 6), dpi=90) # create a figure size 8x6 inches, 80 dots per inches self.splts = [] self.canvas = FigureCanvasWxAgg(self, -1, self.fig) self.toolbar = Toolbar(self.canvas) # matplotlib toolbar # additional toolbar status_txt = wx.StaticText(self.toolbar, label=' Status on hover: ', pos=(230, 7), \ size=(100, 17)) self.status = wx.TextCtrl(self.toolbar, pos=(330,4), size=(300, 22), \ style=wx.TE_READONLY) self.toolbar.Realize() self.figw, self.figh = self.fig.get_window_extent( ).width, self.fig.get_window_extent().height sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.toolbar, 0, wx.GROW) sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(sizer) self.box_width_fraction = 1.0 self.box_height_fraction = 0.9 self.lines = [] self.lined = dict() self.draggableList = ['Text', 'Legend'] # print(self.toolbar.GetBackgroundColour()) self.fig.canvas.mpl_connect('resize_event', self.squeeze_legend) self.fig.canvas.mpl_connect('pick_event', self.on_pick) self.fig.canvas.mpl_connect('motion_notify_event', self.on_motion) self.fig.canvas.mpl_connect('figure_leave_event', self.on_leave) def plot_J(self, J, theta, format, r, count): index = count % 3 + 3 self.splts[index].plot(np.arange(len(J)), J, color=format['color'], linewidth=format['linewidth'], linestyle=format['linestyle'], label=format['label'], picker=True) self.splts[index].set_xlabel("Number of Iteration", fontsize=FONT_SIZE) self.splts[index].set_ylabel("Cost value", fontsize=FONT_SIZE) self.set_ticks(self.splts[index], np.arange(len(J)), J) comment = r + ': [\n' for t in theta: comment += ' ' + str(t) + '\n' comment += ']' props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) annotate = self.splts[index].annotate(comment, xy=(len(J)-1, J[len(J)-1]), xytext=(len(J)/2, (J[0]+J[len(J)-1])/2), \ arrowprops=dict(facecolor='black', shrink=0.05), bbox=props, fontsize=FONT_SIZE, picker=True) annotate.draggable(True) def plot_data_gradient_descent(self, X, y, format): print("Plotting data ...") for i in range(int(round(len(self.splts) / 2))): self.plot_data(self.splts[i], X, y, format) self.update_canvas() def plot_data_normal_equation(self, X, y, format): print("Plotting data ...") for i in range(int(round((len(self.splts) + 1) / 2))): self.plot_data(self.splts[i], X, y, format) self.update_canvas() def plot_data(self, splt, X, y, format): line, = splt.plot(X, y, 'ro', color=format['color'], label=format['label'], picker=True) self.set_ticks(splt, X, y) self.lines.append(line) splt.set_xlabel("X1", fontsize=FONT_SIZE) splt.set_ylabel("Y", fontsize=FONT_SIZE) def set_ticks(self, splt, X, y): xticks = self.make_ticks(X) yticks = self.make_ticks(y) splt.set_xticks(xticks) splt.set_yticks(yticks) for tick in splt.get_xticklabels(): tick.set_rotation(45) tick.set_fontsize(FONT_SIZE) for tick in splt.get_yticklabels(): tick.set_rotation(45) tick.set_fontsize(FONT_SIZE) def plot_all_gradient_descent(self, object): print( "Plotting Linear-Regression (Gradient Descent) and J-Convergence ..." ) count = 0 for r in object: c = self.random_color() self.splts[count].plot(object[r]['data']['x'], object[r]['data']['y'], color=c, linestyle="-", label="Linear Regression (alpha=" + r + ")", picker=True) self.set_ticks(self.splts[count], object[r]['data']['x'], object[r]['data']['y']) self.plot_J( object[r]['J_history'], object[r]['theta'], { "color": c, "linewidth": 5, "linestyle": "-", "label": "Convergence of J" }, r, count) count += 1 self.show_legend() self.update_canvas() def plot_all_normal_equation(self, object): print("Plotting Linear-Regression (Normal Equation) ...") count = 0 for r in object: c = self.random_color() line, = self.splts[count].plot( object[r]['data']['x'], object[r]['data']['y'], color=c, linestyle="-", label="Linear Regression (Normal Equation)", picker=True) self.lines.append(line) self.set_ticks(self.splts[count], object[r]['data']['x'], object[r]['data']['y']) comment = 'Theta: [\n' for t in object[r]['theta']: comment += ' ' + str(t[0]) + '\n' comment += ']' # place a text box in upper left in axes coords props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) annotate = self.splts[count].annotate(comment, xy=(min(object[r]['data']['x']), max(object[r]['data']['y'])), \ xytext=(min(object[r]['data']['x']), max(object[r]['data']['y'])), bbox=props, fontsize=FONT_SIZE, picker=True) annotate.draggable(True) count += 1 self.show_legend() self.update_canvas() def show_legend(self): self.legends = [] for i in range(len(self.splts)): splt = self.splts[i] # Shrink current axis by 20% box = splt.get_position() splt.set_position([box.x0, box.y0, box.width * self.box_width_fraction, \ box.height * self.box_height_fraction]) # Now add the legend with some customizations. legend = splt.legend(loc='upper center', ncol=1, fancybox=True, shadow=True) legend.set_bbox_to_anchor((self.legendpos[0], \ self.legendpos[1] + legend.get_window_extent().height/self.figh + 0.25)) legend.figure.canvas.mpl_connect('pick_event', self.on_pick) legend.draggable(True) # lined = dict() # for legline, origline in zip(legend.get_lines(), self.lines): # legline.set_picker(5) # 5 pts tolerance # self.lined[legline] = origline self.legends.append(legend) if legend: # The frame is matplotlib.patches.Rectangle instance surrounding the legend. frame = legend.get_frame() frame.set_facecolor('0.90') # Set the fontsize for label in legend.get_texts(): label.set_fontsize(FONT_SIZE) for label in legend.get_lines(): label.set_linewidth(0.75) # the legend line width else: pass def make_ticks(self, data): minn = np.min(data) maxx = np.max(data) return np.arange(minn, maxx, int((maxx - minn) / 3)) def squeeze_legend(self, evt): new_height = self.fig.get_window_extent().height self.box_height_fraction = new_height / self.figh self.figh = new_height new_width = self.fig.get_window_extent().width self.box_width_fraction = new_width / self.figw self.figw = new_width self.show_legend() self.update_canvas() def on_pick(self, evt): if isinstance(evt.artist, Text): # box_points = evt.artist.get_position() global TEXT_DRAGGABLE TEXT_DRAGGABLE = not TEXT_DRAGGABLE evt.artist.draggable(TEXT_DRAGGABLE) elif isinstance(evt.artist, Line2D): # box_points = evt.artist.get_clip_box() pass elif isinstance(evt.artist, Legend): # box_points = evt.artist.get_clip_box() global LEGEND_DRAGGABLE LEGEND_DRAGGABLE = not LEGEND_DRAGGABLE evt.artist.draggable(LEGEND_DRAGGABLE) else: print(evt.artist) pass # print("You've clicked on a bar with coords:\n %r, %r" % (box_points , evt.artist)) self.update_canvas() def on_motion(self, mouseevt): w, h = self.canvas.GetSize() if mouseevt.x in range(0, int(w + 1)) and mouseevt.y in range( 0, int(h + 1)): self.status.SetValue('Click on %r for dragging On/Off' % self.draggableList) else: pass def on_leave(self, mouseevt): self.status.SetValue('') def make_figure(self, type): self.fig.clf() if type == 'gd': gs = GridSpec(2, 3) gs.update(hspace=0.7, wspace=0.8) self.splts = [ self.fig.add_subplot(gs[int(i / 3), int(i % 3)]) for i in range(2 * 3) ] # grid nxn elif type == 'ne': gs = GridSpec(1, 1) gs.update(hspace=0.7, wspace=0.8) self.splts = [ self.fig.add_subplot(gs[int(i / 3), int(i % 3)]) for i in range(1 * 1) ] # grid nxn else: pass def random_color(self): rgbl = [0, random.random(), random.random()] return tuple(rgbl) def update_canvas(self): self.fig.canvas.draw() self.canvas.Refresh() self.toolbar.update()
class diffaction_int(wx.Frame): def __init__(self, filename=None): self.fullpath = fullpath self.iconspath = resource_path('icons') self.mpl_old = mpl_old im = Image.open(os.path.join(self.iconspath, 'diff_profile_text.png')) im = im.convert('L') x_str = im.tobytes('raw', im.mode, 0, 1) self.pattern = np.fromstring(x_str, np.uint8) self.pattern.shape = im.size[1], im.size[0] self.pattern_open = np.array([]) self.size = self.pattern.shape self.camlen = 100 self.accv = 200 self.imgcal = 244 #self.img_con = 0.05 #self.img_con16 = 0.0001 self.img_con = Param(1, minimum=0.01, maximum=1.9) self.img_contrast = (self.pattern.min(), self.pattern.max()) accvm = self.accv * 1000 self.wavelen = con.h / (np.sqrt(2 * con.m_e * con.e * accvm)) * 1 / ( np.sqrt(1 + (con.e * accvm) / (2 * con.m_e * con.c**2))) self.pixel_size = self.PixelSize() print(self.pixel_size) wx.Frame.__init__(self, None, -1, 'Diffraction Ring Profiler', size=(550, 350)) self.Bind(wx.EVT_CLOSE, self.OnExit) iconFile = os.path.join(self.iconspath, "diff_profiler_ico.ico") icon1 = wx.Icon(iconFile, wx.BITMAP_TYPE_ICO) self.SetIcon(icon1) # dirname is an APPLICATION variable that we're choosing to store # in with the frame - it's the parent directory for any file we # choose to edit in this frame self.dirname = self.fullpath self.statbar = self.CreateStatusBar( ) # A Statusbar in the bottom of the window self.statbar.SetFieldsCount(2) self.statbar.SetStatusText("None", 1) # Setting up the menu. filemenu is a local variable at this stage. patternmenu = wx.Menu() # use ID_ for future easy reference - much better that "48", "404" etc # The & character indicates the short cut key patternmenu.Append(ID_OPEN, "&Open", " Open a file to edit") patternmenu.AppendSeparator() patternmenu.Append(ID_EXIT, "E&xit", " Terminate the program") # Setting up the menu. filemenu is a local variable at this stage. editmenu = wx.Menu() # use ID_ for future easy reference - much better that "48", "404" etc # The & character indicates the short cut key editmenu.Append(ID_UNDO, "&Undo", " Remove last point or circle") # Setting up the menu. filemenu is a local variable at this stage. toolsmenu = wx.Menu() # use ID_ for future easy reference - much better that "48", "404" etc # The & character indicates the short cut key toolsmenu.Append( ID_CAL, "&Calibrate Pixel Size", " Calibrate pixel size using marked rings and known d-spacing") toolsmenu.Append( ID_PREF, "Ca&lculate Pixel Size", " Calculate pixel size using image resolution and cameralength") toolsmenu.AppendSeparator() toolsmenu.Append(ID_PIX, "&Dead Pixel Fix", " Remove dead and hot pixels from the pattern") #toolsmenu.Append(ID_MARK, "&Mark Rings"," Mark diffraction rings to find the pattern center") toolsmenu.Append(ID_INT, "&Profile", " Extract profiles from the diffraction pattern") # Setting up the menu. filemenu is a local variable at this stage. helpmenu = wx.Menu() # use ID_ for future easy reference - much better that "48", "404" etc # The & character indicates the short cut key helpmenu.Append(ID_ABOUT, "&About", " Information about this program") # Creating the menubar. menuBar = wx.MenuBar() menuBar.Append(patternmenu, "&Pattern") # Adding the "patternmenu" to the MenuBar menuBar.Append(editmenu, "&Edit") menuBar.Append(toolsmenu, "&Tools") # Adding the "patternmenu" to the MenuBar menuBar.Append(helpmenu, "&Help") # Adding the "patternmenu" to the MenuBar self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content. # Note - previous line stores the whole of the menu into the current object self.SetBackgroundColour(wx.Colour("WHITE")) self.figure = Figure(figsize=(8, 8), dpi=76) self.figure.patch.set_facecolor('#F2F1F0') self.axes = self.figure.add_subplot(111) self.axes.set_aspect(1) self.figure.tight_layout() #log_pattern = log(1+a*self.pattern)#/log(1+a*self.pattern).max()*255 self.img = self.axes.imshow(self.pattern, cmap='gray', aspect='equal', interpolation='bicubic') #axi.set_xlim(0, size[1]) #axi.set_ylim(0, size[0]) #canvas = axi.figure.canvas self.axes.set_autoscale_on(False) self.canvas = FigureCanvas(self, -1, self.figure) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) # Capture the paint message wx.EvtHandler.Bind(self, wx.EVT_PAINT, self.OnPaint) self.toolbar = MyNavigationToolbar(self, self.canvas, True, self.OnUndo) self.toolbar.Realize() tw, th = self.toolbar.GetSize() fw, fh = self.canvas.GetSize() self.toolbar.SetSize(wx.Size(fw, th)) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() self.img_conSliderGroup = SliderGroup(self, label='Image gamma:', param=self.img_con) self.sizer.Add(self.img_conSliderGroup.panel, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=0) # Define the code to be run when a menu option is selected self.Bind(wx.EVT_MENU, self.OnAbout, id=ID_ABOUT) self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT) self.Bind(wx.EVT_MENU, self.OnOpen, id=ID_OPEN) #self.Bind(wx.EVT_MENU, self.toolbar._on_markrings, id=ID_MARK) self.Bind(wx.EVT_MENU, self.toolbar._on_integrate, id=ID_INT) self.Bind(wx.EVT_MENU, self.OnUndo, id=ID_UNDO) self.Bind(wx.EVT_MENU, self.OnPref, id=ID_PREF) self.Bind(wx.EVT_MENU, self.OnCal, id=ID_CAL) self.Bind(wx.EVT_MENU, self.OnPix, id=ID_PIX) self.SetSizer(self.sizer) self.Fit() if filename: print(filename[0]) self.dirname, self.filename = os.path.split( os.path.abspath(filename[0])) self.openimage() def PixelSize(self): return 1 / (((self.imgcal / 2.54) * 100) * self.wavelen * (float(self.camlen) / 100)) #computes 1/m per pixel #1/(2*sin(.5*(arctan((arange(B)*Dd)/((float(camlen) / 100)*((imgcal / 2.54) * 100))))))/(wavelen * 10**10) def OnPaint(self, event): self.canvas.draw() event.Skip() def UpdateStatusbar(self): self.statbar.SetStatusText( "CamL: {0} cm | AccV: {1} kV | Res: {2:0.4f} 1/Å".format( self.camlen, self.accv, self.pixel_size * 10**-10), 0) def OnAbout(self, e): info = wx.adv.AboutDialogInfo() info.Name = "Diffraction Ring Profiler" info.Version = "1.2" info.Copyright = "(C) 2011 Brian Olsen" info.Description = "This program is for extracting intensity\n profiles from diffraction ring patterns\n" info.WebSite = ("http://code.google.com/p/diffraction-ring-profiler/", "Diffraction Ring Profiler Website") info.Developers = ["Brian Olsen"] # change the wx.ClientDC to use self.panel instead of self info.License = 'Licensed under GPL 3.0 \n http://www.gnu.org/licenses/gpl.html' # Then we call wx.AboutBox giving it that info object wx.adv.AboutBox(info) # self.aboutme = wx.MessageDialog( self, "This program is for extracting intensity\n" # " profiles from diffraction ring patterns\n\n" "Diffraction Ring Profiler 1.2\n\n" # "(c) Brian Olsen, Licensed under GPL 3.0\n\n" "http://code.google.com/p/diffraction-ring-profiler/", # "About Diffraction Ring Profiler", wx.OK) # self.aboutme.ShowModal() # Shows it # widget / frame defined earlier so it can come up fast when needed def OnExit(self, e): # A modal with an "are you sure" check - we don't want to exit # unless the user confirms the selection in this case ;-) self.doiexit = wx.MessageDialog(self, "Do you want to quit?\n", "Warning", wx.YES_NO) igot = self.doiexit.ShowModal() # Shows it self.doiexit.Destroy() if igot == wx.ID_YES: self.Destroy() # Closes out this simple application def OnOpen(self, e): # In this case, the dialog is created within the method because # the directory name, etc, may be changed during the running of the # application. In theory, you could create one earlier, store it in # your frame object and change it when it was called to reflect # current parameters / values dlg = wx.FileDialog( self, "Choose a diffraction image", self.dirname, "", "Image Files|*.tif;*.TIF;*.tiff;*.TIFF;*.jpg;*.JPG;*.png;*.PNG;*.bmp;*.BMP;*.dm3;*.DM3|All Files|*.*", wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: self.filename = dlg.GetFilename() self.dirname = dlg.GetDirectory() self.openimage() print(self.dirname) dlg.Destroy() def openimage(self): self.toolbar.circles = [] self.toolbar.point3 = np.array([]) self.canvas.mpl_disconnect(self.toolbar.cid) name, ext = os.path.splitext(self.filename) print(self.dirname, name, ext, os.path.join(self.dirname, self.filename)) if ext == '.dm3' or ext == '.DM3': dm3f = dm3.DM3(os.path.join(self.dirname, self.filename)) print(dm3f.info, dm3f.pxsize) self.pattern_open = dm3f.imagedata - dm3f.imagedata.min() #self.pattern_open = array(self.pattern_open) self.pattern_open.shape #print9self.pattern_open[[182],[1336]]) a = self.img_con.value self.img_contrast = (dm3f.contrastlimits[0] - dm3f.imagedata.min(), dm3f.contrastlimits[1] - dm3f.imagedata.min()) print(dm3f.info['mag'], dm3f.info['hv']) self.accv = int(float(dm3f.info['hv']) / 1000.0) if dm3f.info['mode'] == b'DIFFRACTION': self.camlen = int(float(dm3f.info['mag']) / 10.0) print(self.camlen, self.accv) if dm3f.pxsize[0]: if dm3f.pxsize[1] == b'1/nm': self.pixel_size = dm3f.pxsize[0] * 10**9 print('.dm3 set pixel_size:', self.pixel_size) elif dm3f.pxsize[1] == b'1/A': self.pixel_size = dm3f.pxsize[0] * 10**10 print('.dm3 set pixel_size:', self.pixel_size) elif dm3f.pxsize[1] == b'1/m': self.pixel_size = dm3f.pxsize[0] print('.dm3 set pixel_size:', self.pixel_size) else: self.pixel_size = self.PixelSize() print( 'No units in calibration. Using calculated pixel_size:', self.pixel_size) elif dm3f.pxsize[0] == 1: self.pixel_size = self.PixelSize() print( 'Calibration of 1. Likely unset. Using calculated pixel_size:', self.pixel_size) else: self.pixel_size = self.PixelSize() print( 'Calibration of 0. Likely unset. Using calculated pixel_size:', self.pixel_size) else: im = Image.open(os.path.join(self.dirname, self.filename)) Image._initialized = 2 print(im.mode) #im.show() if im.mode == 'L': # return MxN luminance array print('luminance') x_str = im.tobytes('raw', im.mode, 0, 1) self.pattern_open = np.fromstring(x_str, np.uint8) self.pattern_open.shape = im.size[1], im.size[0] elif im.mode == 'I;16': # return MxN luminance array print('I;16') x_str = im.tobytes('raw', im.mode, 0, 1) self.pattern_open = np.fromstring(x_str, np.uint16) self.pattern_open.shape = im.size[1], im.size[0] elif im.mode == 'I;16B': # return MxN luminance array print('I;16') x_str = im.tobytes('raw', im.mode, 0, 1) self.pattern_open = np.fromstring(x_str, '>u2') self.pattern_open.shape = im.size[1], im.size[0] else: # return MxN luminance array print('convert') try: im = im.convert('L') x_str = im.tobytes('raw', im.mode, 0, 1) self.pattern_open = np.fromstring(x_str, np.uint8) self.pattern_open.shape = im.size[1], im.size[0] except ValueError: dlg.Destroy() error_file = 'Image file must be grayscale.' print(error_file) error_int_dlg = Error(self, -1, 'Error', error_file) error_int_dlg.Show(True) error_int_dlg.Centre() self.axes.clear() self.axes.imshow(self.pattern, cmap='gray', aspect='equal', origin='upper') self.canvas.draw() self.pattern_open = np.array([]) self.SetTitle("Diffraction Ring Profiler") return self.img_contrast = (self.pattern_open.min(), self.pattern_open.max()) #log_pattern = log(1+0.001*self.pattern_open)#/log(1+a*pattern).max()*255 self.size = self.pattern_open.shape print('shape: ', self.size) self.axes.clear() self.img = self.axes.imshow(self.pattern_open, cmap='gray', aspect='equal', origin='upper', vmin=self.img_contrast[0], vmax=self.img_contrast[1]) self.axes.xaxis.set_ticks_position('bottom') self.axes.yaxis.set_ticks_position('left') self.canvas.draw() self.SetTitle("Diffraction Ring Profiler - " + self.filename) self.UpdateStatusbar() self.img_con.set(1) def OnUndo(self, e): # Undo last point or circle print(self.toolbar.point3.size) print(self.axes.lines) print(self.toolbar.hist) undo = self.toolbar.hist[-1] if undo == 'start': print('back to start') elif undo == 'circ': self.toolbar.circles.pop(-1) for circle in self.toolbar.circles: print(circle.radius) self.axes.patches.pop(-1) self.axes.texts.pop(-1) del self.axes.lines[-4:] del self.toolbar.hist[-4:] print(self.toolbar.hist) self.canvas.draw() elif undo == 'point3' and self.toolbar.point3.size == 2: self.toolbar.point3 = np.array([]) print(self.toolbar.point3) self.axes.lines.pop(-1) self.canvas.draw() del self.toolbar.hist[-1:] elif undo == 'point3': self.toolbar.point3 = self.toolbar.point3[:-1, :] print(self.toolbar.point3) self.axes.lines.pop(-1) self.canvas.draw() del self.toolbar.hist[-1:] elif undo == 'line': self.axes.patches.pop(-1) self.axes.texts.pop(-1) del self.axes.lines[-2:] del self.toolbar.hist[-3:] print(self.toolbar.hist) self.canvas.draw() elif undo == 'point2': self.toolbar.point2 = np.array([]) print(self.toolbar.point2) self.axes.lines.pop(-1) self.canvas.draw() del self.toolbar.hist[-1:] else: print('undo error') def OnPix(self, e): std_cutoff = 80 filter_size = 3 self.pattern_open, num_filter, pattern_diff = self.filter_outliers( self.pattern_open, filter_size, std_cutoff) self.img.set_data(self.pattern_open) self.canvas.draw() print(num_filter) #figure() #imshow(pattern_diff, cmap='gray') #show() def filter_outliers(self, pattern, filter_size, std_cutoff): pattern[np.nonzero(pattern > 1e9)] = 0 pattern_filter = median_filter(pattern, size=filter_size) pattern_diff = pattern - pattern_filter pattern_index = np.nonzero( np.logical_or( -np.std(pattern_diff) * std_cutoff + pattern_diff.mean() > pattern_diff, pattern_diff > np.std(pattern_diff) * std_cutoff + pattern_diff.mean())) print(pattern_index) if pattern[pattern_index].any(): pattern_final = np.copy(pattern) print(pattern_final[pattern_index]) num_filter = len(pattern_final[pattern_index]) print(num_filter) pattern_final[pattern_index] = pattern_filter[pattern_index] pattern_diff_final = pattern - pattern_final print(np.nonzero(pattern > pattern.max() * .8), pattern.max(), pattern_filter.max(), np.median(pattern_diff_final), (pattern_diff_final).max()) else: pattern_final = np.copy(pattern) num_filter = 0 return pattern_final, num_filter, pattern_diff def OnPref(self, e): dlg = Pref(self, -1, 'Calculate Pixel Size') dlg.Show(True) dlg.Centre() def OnCal(self, e): dlg = Cal(self, -1, 'Calibrate Pixel Size') dlg.Show(True) dlg.Centre()
class G3Plot(wx.Frame): """ G3Plot creates a frame with a toolbar that holds a G-3 graph (2D y vs. x plot). The graph allows multiple plots from multicolumn data 'x, y1, y2, ...' given at successive x-values, given in one or more files. Wildcard file names are accepted. """ def __init__(self, files, verbose=False, title='(x,y) data', formt='k', xlabel='X', ylabel='Y', ymin=-0.1, ymax=0.05, xmin=0.0, xmax=1.0, pos=(50, 60), size=(640, 500)): wx.Frame.__init__(self, None, -1, "G3 Plot", pos, size) # self.SetBackgroundColour(wx.NamedColor("WHITE")) self.panel = None self.dpi = None self.fig = None self.canvas = None self.axes = None self.toolbar = None # Just in case we need to have these values stored self.verbose = verbose self.title = title self.formt = formt self.xlabel = xlabel self.ylabel = ylabel self.ymin = ymin self.ymax = ymax self.xmin = xmin self.xmax = xmax if self.verbose: print('xmin, xmax, ymin, ymax: ', self.xmin, self.xmax, self.ymin, self.ymax) self.subplot = [] # Give the figure size in inches, and rez self.figure = Figure(figsize=(6.4, 4.8), dpi=100) # Wait to create the subplot when AddSubplot() is called # self.axes = self.figure.add_subplot(1,1,1) # self.axes.set_title(self.title) # self.axes.set_xlabel(self.xlabel) # self.axes.set_ylabel(self.ylabel) self.PlotFiles(files) # create axes and plot all the data self.canvas = FigureCanvas(self, -1, self.figure) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) # Capture the paint message # wx.EVT_PAINT(self, self.OnPaint) self.toolbar = MyNavigationToolbar(self.canvas, True) self.toolbar.Realize() if wx.Platform == '__WXMAC__': # Mac platform (OSX 10.3, MacPython) does not seem to cope with # having a toolbar in a sizer. This work-around gets the buttons # back, but at the expense of having the toolbar at the top self.SetToolBar(self.toolbar) else: # On Windows platform, default window size is incorrect, so set # toolbar width to figure width. tw, th = self.toolbar.GetSize() fw, fh = self.canvas.GetSize() # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version. # As noted above, doesn't work for Mac. self.toolbar.SetSize(wx.Size(fw, th)) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() self.SetSizer(self.sizer) self.Fit() #---------------------------------------------------------------------- def PlotFiles(self, file_list): """ Loops through all files and makes a call to _PlotFile to plot each data set to the canvas. """ self.plot_data = [] if self.verbose: print("Processing %d files." % len(file_list)) for f in file_list: this_file = os.path.abspath(f) if os.path.isfile(this_file): try: self._PlotFile(this_file) except Exception as e: sys.exit("Error plotting files: %s" % e) else: print("File Error: '%s' is not found." % this_file) #---------------------------------------------------------------------- def _PlotFile(self, f): """ Parses the data in file f and plots all data columns """ # Will end up being a list of lists. First item # of the list will be the time step, all following # items will be output data at each time step. plot_data = None if self.verbose: print("Plotting file: %s" % f) this_file = os.path.abspath(f) if os.path.isfile(this_file): num_items = None fdata = open(this_file, 'r') for line in fdata.readlines(): data = line.split() if plot_data is None: num_items = len(data) plot_data = [[] for i in range(num_items)] for indx, d in enumerate(data): if indx < num_items: try: plot_data[indx].append(d) except IndexError as e: print("Error processing data line for index %d" % indx) # Now we plot all of the data we collected. t = plot_data[0] for indx, x in enumerate(plot_data[1:]): if self.verbose: num_plots = len(plot_data[1:]) print("\tPlotting data set %d of %d" % (indx + 1, num_plots)) xa = np.asarray(t, dtype=float) ya = np.asarray(x, dtype=float) self._AddSubplot(xa, ya) else: print("File Error: '%s' is not found." % this_file) #---------------------------------------------------------------------- def _AddSubplot(self, t, x): """ Create a subplot if one doesn't exist, and plot the (t, x) data. For historical reasons the x-axis variable is called 't' and the y-axis variable 'x'. This should be changed! The add_subplot method of a Figure creates an Axes instance (111) == (1,1,1) --> row 1, col 1, Figure 1 """ if self.axes is None: self.axes = self.figure.add_subplot(1, 1, 1) # This is where Axes attributes are set self.axes.set_title(self.title) self.axes.set_xlabel(self.xlabel) self.axes.set_ylabel(self.ylabel) if self.xmin is None or self.xmax is None: self.axes.set_autoscalex_on(True) else: self.axes.set_autoscalex_on(False) self.axes.axis(xmin=self.xmin, xmax=self.xmax) if self.ymin is None or self.ymax is None: self.axes.set_autoscaley_on(True) else: self.axes.set_autoscaley_on(False) self.axes.axis(ymin=self.ymin, ymax=self.ymax) # With the new, or an exising Axes instance, plot the data if self.formt is None: self.axes.plot(t, x) else: self.axes.plot(t, x, self.formt) #---------------------------------------------------------------------- def OnPaint(self, event): self.canvas.draw() event.Skip()
class PlotPanel(wx.Panel): """The PlotPanel has a Figure and a Canvas. OnSize events simply set a flag, and the actual resizing of the figure is triggered by an Idle event.""" def __init__(self, parent, color=None, dpi=None, **kwargs): from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg from matplotlib.figure import Figure self.parent = parent # initialize Panel if 'id' not in kwargs.keys(): kwargs['id'] = wx.ID_ANY if 'style' not in kwargs.keys(): kwargs['style'] = wx.NO_FULL_REPAINT_ON_RESIZE wx.Panel.__init__(self, parent, **kwargs) # initialize matplotlib stuff self.figure = Figure(None, dpi) self.canvas = FigureCanvasWxAgg(self, -1, self.figure) self.SetColor(color) self._SetSize() #self.draw() self._resizeflag = False self.Bind(wx.EVT_IDLE, self._onIdle) self.Bind(wx.EVT_SIZE, self._onSize) def SetColor(self, rgbtuple=None): """Set figure and canvas colours to be the same.""" if rgbtuple is None: rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() clr = [c / 255. for c in rgbtuple] self.figure.set_facecolor(clr) self.figure.set_edgecolor(clr) self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple)) def _onSize(self, event): self._resizeflag = True #print 'Resizing Plot' #self._SetSize() def _onIdle(self, evt): if self._resizeflag: self._resizeflag = False self._SetSize() def _SetSize(self): pixels = tuple(self.GetClientSize()) if not tuple(self.canvas.GetSize()) == pixels: self.SetSize(pixels) self.canvas.SetSize(pixels) self.figure.set_size_inches( float(pixels[0]) / self.figure.get_dpi(), float(pixels[1]) / self.figure.get_dpi()) try: if self.IsShown(): self.draw() except: pass def draw(self): pass # abstract, to be overridden by child classes
class Spectrogram(StandardMonitorPage): """Main class for a page that generates real-time spectrogram plots of EEG. """ def __init__(self, *args, **kwargs): """Construct a new Spectrogram page. Args: *args, **kwargs: Arguments to pass to the Page base class. """ self.initConfig() # initialize Page base class StandardMonitorPage.__init__(self, name='Spectrogram', configPanelClass=ConfigPanel, *args, **kwargs) self.initCanvas() self.initLayout() def initConfig(self): self.filter = True # use raw or filtered signal self.chanIndex = 0 # index of channel to show self.width = 5.0 # width of window to use for computing PSD self.decimationFactor = 1 # decimation factor, e.g., 2 will decimate to half sampRate self.interpolation = 'none' self.normScale = 'log' self.scale = -2 self.method = 'Wavelet' self.setRefreshDelay(200) self.waveletConfig = util.Holder(nFreq=100, span=10) self.fourierConfig = util.Holder() def initCanvas(self): """Initialize a new matplotlib canvas, figure and axis. """ self.plotPanel = wx.Panel(self) self.plotPanel.SetBackgroundColour('white') plotSizer = wx.BoxSizer(orient=wx.VERTICAL) self.plotPanel.SetSizer(plotSizer) self.fig = plt.Figure(facecolor='white') #self.canvas = FigureCanvas(parent=self, id=wx.ID_ANY, figure=self.fig) self.canvas = FigureCanvas(parent=self.plotPanel, id=wx.ID_ANY, figure=self.fig) self.ax = self.fig.add_subplot(1, 1, 1) self.ax.set_xlabel('Time (s)') self.ax.set_ylabel('Frequency (Hz)') self.cbAx = self.fig.add_axes([0.91, 0.05, 0.03, 0.93]) #self.fig.subplots_adjust(hspace=0.0, wspace=0.0, # left=0.035, right=0.92, top=0.98, bottom=0.05) self.adjustMargins() self.firstPlot() self.lastSize = (0, 0) self.needsResizePlot = True self.canvas.Bind(wx.EVT_SIZE, self.resizePlot) self.canvas.Bind(wx.EVT_IDLE, self.idleResizePlot) ##self.plotToolbar = widgets.PyPlotNavbar(self.canvas) ##plotSizer.Add(self.plotToolbar, proportion=0, flag=wx.EXPAND) plotSizer.Add(self.canvas, proportion=1, flag=wx.EXPAND) #self.plotToolbar.Hide() def initLayout(self): self.initStandardLayout() plotPaneAuiInfo = aui.AuiPaneInfo().Name('canvas').Caption( 'Spectrogram').CenterPane() #self.auiManager.AddPane(self.canvas, plotPaneAuiInfo) self.auiManager.AddPane(self.plotPanel, plotPaneAuiInfo) self.auiManager.Update() self.canvas.Hide() def afterUpdateSource(self): self.configPanel.updateChannels() def afterStart(self): # make sure canvas is visible self.canvas.Show() self.plotPanel.Layout() # trigger initial plot update self.needsFirstPlot = True def getCap(self): cap = self.src.getEEGSecs(self.width, filter=self.filter, copy=False) if self.decimationFactor > 1: cap.decimate(self.decimationFactor) return cap def getSpectrum(self, cap): # configurable XXX - idfah data = cap.data[:, self.chanIndex] * sig.windows.tukey( cap.data.shape[0]) # tukey or hann? XXX - idfah freqs, powers, phases = self.cwt.apply(data) # configurable XXX - idfah powers = np.clip(powers, 1.0e-10, np.inf) return freqs, powers def firstPlot(self, event=None): cap = self.getCap() self.cwt = sig.CWT(sampRate=cap.getSampRate(), freqs=self.waveletConfig.nFreq, span=self.waveletConfig.span) if self.isRunning(): freqs, powers = self.getSpectrum(cap) else: freqs = np.arange(1, self.src.getSampRate() // 2 + 1) powers = np.zeros((128, 10, 1)) powers[0, 0, 0] = 1.0 self.ax.cla() self.cbAx.cla() self.ax.set_xlabel('Time (s)') self.ax.set_ylabel('Frequency (Hz)') self.wimg = self.ax.imshow(powers[:, :, 0].T, interpolation=self.interpolation, origin='lower', aspect='auto', norm=self.getNorm(), extent=self.getExtent(cap, freqs), cmap=plt.cm.get_cmap('jet'), animated=True) self.cbar = self.fig.colorbar(self.wimg, cax=self.cbAx) self.cbar.set_label(r'Power Density ($V^2 / Hz$)') #self.updateNorm(powers) self.canvas.draw() #self.background = self.canvas.copy_from_bbox(self.fig.bbox) self.background = self.canvas.copy_from_bbox(self.ax.bbox) self.needsFirstPlot = False def adjustMargins(self): self.fig.subplots_adjust(hspace=0.0, wspace=0.0, left=0.045, right=0.90, top=0.98, bottom=0.07) def resizePlot(self, event): # prevents handling extra resize events, hack XXX - idfah size = self.canvas.GetSize() if self.lastSize == size: return else: self.lastSize = size # this is all a hack to do resizing on idle when page is not running # should this be a custom FigureCanvas derived widget? XXX - idfah if self.isRunning(): # when running, just do event.Skip() this will # call canvas._onSize since it is second handler self.needsResizePlot = False event.Skip() else: # flag to resize on next idle event self.needsResizePlot = True def idleResizePlot(self, event): # if not running and flagged for resize if not self.isRunning() and self.needsResizePlot: ##self.adjustMargins() self.needsResizePlot = False # call canvas resize method manually # hack alert, we just pass None as event # since it's not used anyway self.canvas._onSize(None) def getExtent(self, cap, freqs): return (0.0, cap.getNObs() / float(cap.getSampRate()), np.min(freqs), np.max(freqs)) def getNorm(self): mx = 10**self.scale if self.normScale == 'linear': mn = 0.0 norm = pltLinNorm(mn, mx) elif self.normScale == 'log': mn = 1e-10 norm = pltLogNorm(mn, mx) else: raise RuntimeError('Invalid norm %s.' % norm) return norm def updatePlot(self, event=None): """Draw the spectrogram plot. """ if self.needsFirstPlot: self.firstPlot() else: cap = self.getCap() freqs, powers = self.getSpectrum(cap) #self.updateNorm(powers) self.canvas.restore_region(self.background) self.wimg.set_array(powers[:, :, 0].T) self.wimg.set_extent(self.getExtent(cap, freqs)) self.ax.draw_artist(self.wimg) ##self.cbAx.draw_artist(self.cbar.patch) ##self.cbAx.draw_artist(self.cbar.solids) #self.cbar.draw_all() #self.canvas.blit(self.cbAx.bbox) #self.canvas.blit(self.fig.bbox) self.canvas.blit(self.ax.bbox) # for debugging, redraws everything ##self.canvas.draw() def captureImage(self, event=None): ## Parts borrowed from backends_wx.py from matplotlib # Fetch the required filename and file type. filetypes, exts, filter_index = self.canvas._get_imagesave_wildcards() default_file = self.canvas.get_default_filename() dlg = wx.FileDialog(self, "Save to file", "", default_file, filetypes, wx.SAVE | wx.OVERWRITE_PROMPT) dlg.SetFilterIndex(filter_index) if dlg.ShowModal() == wx.ID_OK: dirname = dlg.GetDirectory() filename = dlg.GetFilename() format = exts[dlg.GetFilterIndex()] basename, ext = os.path.splitext(filename) if ext.startswith('.'): ext = ext[1:] if ext in ('svg', 'pdf', 'ps', 'eps', 'png') and format != ext: #looks like they forgot to set the image type drop #down, going with the extension. format = ext self.canvas.print_figure(os.path.join(dirname, filename), format=format)
class FIRBandpassConfigPanel(FilterConfigPanel): def __init__(self, *args, **kwargs): FilterConfigPanel.__init__(self, *args, **kwargs) # options go in top-level sizer self.initOptions() # other stuff split horizontally by bottomSizer self.bottomSizer = wx.BoxSizer(wx.HORIZONTAL) self.initSliders() self.initResponse() self.sizer.Add(self.bottomSizer, proportion=1, flag=wx.EXPAND) self.initLayout() def initOptions(self): optionsSizer = wx.BoxSizer(wx.HORIZONTAL) self.filtTypeComboBox = wx.ComboBox(self, choices=list(self.flt.filtMap.keys()), value=self.flt.filtType, style=wx.CB_DROPDOWN) self.Bind(wx.EVT_COMBOBOX, self.setFiltType, self.filtTypeComboBox) optionsSizer.Add(self.filtTypeComboBox, proportion=1, flag=wx.LEFT | wx.TOP | wx.RIGHT | wx.ALIGN_CENTER, border=20) self.sizer.Add(optionsSizer, proportion=0)#, flag=wx.EXPAND) def setFiltType(self, event): filtType = self.filtTypeComboBox.GetValue() if filtType not in self.flt.filtMap.keys(): raise RuntimeError('Invalid filter type: %s.' % str(filtType)) self.flt.filtType = filtType self.updateResponse() def initSliders(self): sliderSizer = wx.BoxSizer(wx.HORIZONTAL) lowFreqControlBox = widgets.ControlBox(self, label='lowFreq', orient=wx.VERTICAL) self.lowFreqText = wx.StaticText(self, label='%6.2f(Hz)' % self.flt.lowFreq) lowFreqTextSizer = wx.BoxSizer(orient=wx.VERTICAL) lowFreqTextSizer.Add(self.lowFreqText, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL) self.lowFreqSlider = wx.Slider(self, style=wx.SL_VERTICAL | wx.SL_INVERSE, minValue=0, maxValue=int(self.flt.nyquist*4), value=int(self.flt.lowFreq*4)) self.Bind(wx.EVT_SLIDER, self.setLowFreq, self.lowFreqSlider) lowFreqControlBox.Add(lowFreqTextSizer, proportion=0, flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=8) lowFreqControlBox.Add(self.lowFreqSlider, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=25) sliderSizer.Add(lowFreqControlBox, proportion=1, flag=wx.ALL | wx.EXPAND, border=10) highFreqControlBox = widgets.ControlBox(self, label='highFreq', orient=wx.VERTICAL) self.highFreqText = wx.StaticText(self, label='%6.2f(Hz)' % self.flt.highFreq) highFreqTextSizer = wx.BoxSizer(orient=wx.VERTICAL) highFreqTextSizer.Add(self.highFreqText, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL) self.highFreqSlider = wx.Slider(self, style=wx.SL_VERTICAL | wx.SL_INVERSE, minValue=0, maxValue=int(self.flt.nyquist*4), value=int(self.flt.highFreq*4)) self.Bind(wx.EVT_SLIDER, self.setHighFreq, self.highFreqSlider) highFreqControlBox.Add(highFreqTextSizer, proportion=0, flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=8) highFreqControlBox.Add(self.highFreqSlider, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=25) sliderSizer.Add(highFreqControlBox, proportion=1, flag=wx.ALL | wx.EXPAND, border=10) orderControlBox = widgets.ControlBox(self, label='Order', orient=wx.VERTICAL) self.orderText = wx.StaticText(self, label='%2d' % self.flt.order) orderTextSizer = wx.BoxSizer(orient=wx.VERTICAL) orderTextSizer.Add(self.orderText, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL) self.orderSlider = wx.Slider(self, style=wx.SL_VERTICAL | wx.SL_INVERSE, minValue=2, maxValue=50, value=self.flt.order // 2) self.Bind(wx.EVT_SLIDER, self.setOrder, self.orderSlider) orderControlBox.Add(orderTextSizer, proportion=0, flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=8) orderControlBox.Add(self.orderSlider, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=25) sliderSizer.Add(orderControlBox, proportion=1, flag=wx.ALL | wx.EXPAND, border=10) self.bottomSizer.Add(sliderSizer, proportion=1, flag=wx.EXPAND) def setLowFreq(self, event): self.flt.lowFreq = self.lowFreqSlider.GetValue() / 4.0 self.lowFreqText.SetLabel('%6.2f(Hz)' % self.flt.lowFreq) self.updateResponse() def setHighFreq(self, event): self.flt.highFreq = self.highFreqSlider.GetValue() / 4.0 self.highFreqText.SetLabel('%6.2f(Hz)' % self.flt.highFreq) self.updateResponse() def setOrder(self, event): self.flt.order = self.orderSlider.GetValue() * 2 self.orderText.SetLabel('%2d' % self.flt.order) self.updateResponse() def initResponse(self): self.freqResponseFig = plt.Figure() self.freqResponseCanvas = FigureCanvas(parent=self, id=wx.ID_ANY, figure=self.freqResponseFig) self.freqResponseAx = self.freqResponseFig.add_subplot(1,1,1) #self.freqResponseFig.tight_layout() self.phaseResponseFig = plt.Figure() self.phaseResponseCanvas = FigureCanvas(parent=self, id=wx.ID_ANY, figure=self.phaseResponseFig) self.phaseResponseAx = self.phaseResponseFig.add_subplot(1,1,1) #self.freqResponseFig.tight_layout() responseSizer = wx.BoxSizer(wx.VERTICAL) freqResponseControlBox = widgets.ControlBox(self, label='Frequency Response', orient=wx.VERTICAL) freqResponseControlBox.Add(self.freqResponseCanvas, proportion=1, flag=wx.ALL | wx.EXPAND, border=8) responseSizer.Add(freqResponseControlBox, proportion=1, flag=wx.TOP | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=10) phaseResponseControlBox = widgets.ControlBox(self, label='Phase Response', orient=wx.VERTICAL) phaseResponseControlBox.Add(self.phaseResponseCanvas, proportion=1, flag=wx.ALL | wx.EXPAND, border=8) responseSizer.Add(phaseResponseControlBox, proportion=1, flag=wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=10) self.bottomSizer.Add(responseSizer, proportion=1, flag=wx.EXPAND) self.freqResponseCanvas.SetMinSize((0,0)) self.phaseResponseCanvas.SetMinSize((0,0)) # could we prevent resize when panel is not visible? XXX - idfah self.freqResponseLastSize = (0,0) self.freqResponseCanvas.Bind(wx.EVT_SIZE, self.freqResponseResize) self.phaseResponseLastSize = (0,0) self.phaseResponseCanvas.Bind(wx.EVT_SIZE, self.phaseResponseResize) self.updateResponse() def freqResponseResize(self, event): # prevents handling extra resize events, hack XXX - idfah size = self.freqResponseCanvas.GetSize() if self.freqResponseLastSize == size: return self.freqResponseLastSize = size event.Skip() def phaseResponseResize(self, event): # prevents handling extra resize events, hack XXX - idfah size = self.phaseResponseCanvas.GetSize() if self.phaseResponseLastSize == size: return self.phaseResponseLastSize = size event.Skip() def updateResponse(self): self.flt.updateFilter() self.freqResponseAx.cla() self.flt.bp.plotFreqResponse(ax=self.freqResponseAx, linewidth=2) self.freqResponseAx.autoscale(tight=True) self.freqResponseAx.legend(prop={'size': 12}) self.freqResponseCanvas.draw() self.phaseResponseAx.cla() self.flt.bp.plotPhaseResponse(ax=self.phaseResponseAx, linewidth=2) self.phaseResponseAx.legend(prop={'size': 12}) self.phaseResponseAx.autoscale(tight=True) self.phaseResponseCanvas.draw()
class PanelGraph(wx.Panel): def __init__(self, panel, notify, settings, callbackMotion, remoteControl): self.panel = panel self.notify = notify self.plot = None self.settings = settings self.remoteControl = remoteControl self.spectrum = None self.isLimited = None self.limit = None self.extent = None self.annotate = None self.mouseSelect = None self.mouseZoom = None self.measureTable = None self.background = None self.selectStart = None self.selectEnd = None self.menuClearSelect = [] self.measure = None self.show = None self.doDraw = False wx.Panel.__init__(self, panel) self.figure = matplotlib.figure.Figure(facecolor='white') self.canvas = FigureCanvas(self, -1, self.figure) self.measureTable = PanelMeasure(self, settings) self.toolbar = NavigationToolbar(self.canvas, self, settings, self.__hide_overlay) self.toolbar.Realize() vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(self.canvas, 1, wx.EXPAND) vbox.Add(self.measureTable, 0, wx.EXPAND) vbox.Add(self.toolbar, 0, wx.EXPAND) self.SetSizer(vbox) vbox.Fit(self) self.create_plot() self.canvas.mpl_connect('button_press_event', self.__on_press) self.canvas.mpl_connect('motion_notify_event', callbackMotion) self.canvas.mpl_connect('draw_event', self.__on_draw) self.canvas.mpl_connect('idle_event', self.__on_idle) self.Bind(wx.EVT_SIZE, self.__on_size) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.__on_timer, self.timer) def __set_fonts(self): axes = self.plot.get_axes() if axes is not None: axes.xaxis.label.set_size('small') axes.yaxis.label.set_size('small') if self.settings.display == Display.SURFACE: axes.zaxis.label.set_size('small') axes.tick_params(axis='both', which='major', labelsize='small') axes = self.plot.get_axes_bar() if axes is not None: axes.tick_params(axis='both', which='major', labelsize='small') def __enable_menu(self, state): for menu in self.menuClearSelect: menu.Enable(state) def __on_press(self, event): if self.settings.clickTune and matplotlib.__version__ >= '1.2' and event.dblclick: frequency = int(event.xdata * 1e6) self.remoteControl.tune(frequency) def __on_size(self, event): ppi = wx.ScreenDC().GetPPI() size = [float(v) for v in self.canvas.GetSize()] width = size[0] / ppi[0] height = size[1] / ppi[1] self.figure.set_figwidth(width) self.figure.set_figheight(height) self.figure.set_dpi(ppi[0]) event.Skip() def __on_draw(self, _event): axes = self.plot.get_axes() if axes is not None: self.background = self.canvas.copy_from_bbox(axes.bbox) self.__draw_overlay() def __on_idle(self, _event): if self.doDraw and self.plot.get_plot_thread() is None: self.__hide_overlay() self.canvas.draw() self.doDraw = False def __on_timer(self, _event): self.timer.Stop() self.set_plot(None, None, None, None, self.annotate) def __draw_overlay(self): if self.background is not None: self.canvas.restore_region(self.background) self.__draw_select() self.draw_measure() axes = self.plot.get_axes() if axes is None: self.canvas.draw() else: self.canvas.blit(axes.bbox) def __draw_select(self): if self.selectStart is not None and self.selectEnd is not None: self.mouseSelect.draw(self.selectStart, self.selectEnd) def __hide_overlay(self): if self.plot is not None: self.plot.hide_measure() self.__hide_select() def __hide_select(self): if self.mouseSelect is not None: self.mouseSelect.hide() def create_plot(self): if self.plot is not None: self.plot.close() self.toolbar.set_auto(True) if self.settings.display == Display.PLOT: self.plot = Plotter(self.notify, self.figure, self.settings) elif self.settings.display == Display.SPECT: self.plot = Spectrogram(self.notify, self.figure, self.settings) elif self.settings.display == Display.SURFACE: self.plot = Plotter3d(self.notify, self.figure, self.settings) elif self.settings.display == Display.STATUS: self.plot = PlotterStatus(self.notify, self.figure, self.settings) else: self.plot = PlotterTime(self.notify, self.figure, self.settings) self.__set_fonts() self.toolbar.set_plot(self.plot) self.toolbar.set_type(self.settings.display) self.measureTable.set_type(self.settings.display) self.set_plot_title() self.figure.subplots_adjust(top=0.85) self.redraw_plot() self.plot.scale_plot(True) self.mouseZoom = MouseZoom(self.toolbar, plot=self.plot, callbackHide=self.__hide_overlay) self.mouseSelect = MouseSelect(self.plot, self.on_select, self.on_selected) self.measureTable.show(self.settings.showMeasure) self.panel.SetFocus() def on_select(self): self.hide_measure() def on_selected(self, start, end): self.__enable_menu(True) self.selectStart = start self.selectEnd = end self.measureTable.set_selected(self.spectrum, start, end) def add_menu_clear_select(self, menu): self.menuClearSelect.append(menu) menu.Enable(False) def draw(self): self.doDraw = True def show_measure_table(self, show): self.measureTable.show(show) self.Layout() def set_plot(self, spectrum, isLimited, limit, extent, annotate=False): if spectrum is not None and extent is not None: if isLimited is not None and limit is not None: self.spectrum = copy.copy(spectrum) self.extent = extent self.annotate = annotate self.isLimited = isLimited self.limit = limit if self.plot.get_plot_thread() is None: self.timer.Stop() self.measureTable.set_selected(self.spectrum, self.selectStart, self.selectEnd) if isLimited: spectrum = reduce_points(spectrum, limit) self.plot.set_plot(self.spectrum, self.extent, annotate) else: self.timer.Start(200, oneShot=True) def set_plot_title(self): if len(self.settings.devicesRtl) > 0: gain = self.settings.devicesRtl[self.settings.indexRtl].gain else: gain = 0 self.plot.set_title("Frequency Spectrogram\n{} - {} MHz," " gain = {}dB".format(self.settings.start, self.settings.stop, gain)) def redraw_plot(self): if self.spectrum is not None: self.set_plot(self.spectrum, self.settings.pointsLimit, self.settings.pointsMax, self.extent, self.settings.annotate) def set_grid(self, on): self.plot.set_grid(on) def hide_measure(self): if self.plot is not None: self.plot.hide_measure() def draw_measure(self): if self.measure is not None and self.measure.is_valid(): self.plot.draw_measure(self.measure, self.show) def update_measure(self, measure=None, show=None): if not measure and not show: self.measureTable.update_measure() else: self.measure = measure self.show = show self.__draw_overlay() def get_figure(self): return self.figure def get_axes(self): return self.plot.get_axes() def get_canvas(self): return self.canvas def get_toolbar(self): return self.toolbar def scale_plot(self, force=False): self.plot.scale_plot(force) def clear_plots(self): self.plot.clear_plots() self.spectrum = None self.doDraw = True def clear_selection(self): self.measure = None self.measureTable.clear_measurement() self.selectStart = None self.selectEnd = None self.mouseSelect.clear() self.__enable_menu(False) def close(self): close_modeless()
class PlotWin(wx.Frame): def __init__(self,parent): self.parent=parent self.listeners = {} self.makeFrame() self.initMenu() self.initPopUpMenu() def makeFrame(self): global canvas #@@@@ # Got this trick for a two stage creation from # http://wiki.wxpython.org/index.cgi/TwoStageCreation pre = wx.PreFrame() self.res = XmlResource(homepath+"/plotwin.xrc") self.res.LoadOnFrame(pre,self.parent,"plotwin") self.PostCreate(pre) self.SetBackgroundColour(wx.NamedColor("WHITE")) self.Show() self.figure = Figure() self.axes = [self.figure.add_subplot(111)] self.canvas = FigureCanvas(self, -1, self.figure) canvas = self.canvas #@@@@ self.sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.sizer) self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.Fit() self.addToolbar() def initMenu(self): self.menubar = XRCCTRL(self, "menubar") bindings = ( ("file_exit", self.onFileExit), ("layout_subplots", self.onLayout), ("help_about", self.onHelpAbout)) for id,fun in bindings: wx.EVT_MENU(self, XRCID(id),fun) def initPopUpMenu(self): filetraceMenu=wx.Menu() filetraceMenu.Append(ID_TRACE_NEW_LINE, "New line plot...") filetraceMenu.Append(ID_TRACE_ADD_LINE, "Add line plot...") filetraceMenu.Append(ID_TRACE_NEW_BAR, "New bar plot...") filelistenerMenu=wx.Menu() filelistenerMenu.Append(ID_LISTENER_NEW_LINE, "New line plot...") filelistenerMenu.Append(ID_LISTENER_NEW_BAR, "New bar plot...") self.popup = wx.Menu() self.popup.AppendMenu(ID_PLOT_TRACE, "Plot file trace", filetraceMenu) self.popup.AppendMenu(ID_PLOT_LISTENER, "Plot from listener", filelistenerMenu) self.popup.AppendSeparator() self.popup.Append(ID_CLEAR_PLOT, "Clear plot") self.popup.Append(ID_PLOT_PARAMETERS, "Plot parameters...") self.Bind(wx.EVT_MENU, self.onClearPlot, id=ID_CLEAR_PLOT) self.Bind(wx.EVT_MENU, self.onPlotParameters, id=ID_PLOT_PARAMETERS) self.Bind(wx.EVT_MENU, self.onTraceLine, id=ID_TRACE_NEW_LINE) self.Bind(wx.EVT_MENU, self.onTraceLine, id=ID_TRACE_ADD_LINE) self.Bind(wx.EVT_MENU, self.onTraceNewBar, id=ID_TRACE_NEW_BAR) self.Bind(wx.EVT_MENU, self.onListenerNewLine, id=ID_LISTENER_NEW_LINE) self.Bind(wx.EVT_MENU, self.onListenerNewBar, id=ID_LISTENER_NEW_BAR) def addToolbar(self): self.toolbar = NavigationToolbar2Wx(self.canvas) self.toolbar.Realize() if wx.Platform == '__WXMAC__': # Mac platform (OSX 10.3, MacPython) does not seem to cope with # having a toolbar in a sizer. This work-around gets the buttons # back, but at the expense of having the toolbar at the top self.SetToolBar(self.toolbar) else: # On Windows platform, default window size is incorrect, so set # toolbar width to figure width. tw, th = self.toolbar.GetSizeTuple() fw, fh = self.canvas.GetSizeTuple() # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version. # As noted above, doesn't work for Mac. self.toolbar.SetSize(wx.Size(fw, th)) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) # update the axes menu on the toolbar self.toolbar.update() self.canvas.mpl_connect("button_press_event", self.onButtonPress) # --------------------------------------------------------------------- def onFileExit(self,evt): pass def onLayout(self,evt): dlg=self.res.LoadDialog(self, "layoutDlg") wx.EVT_BUTTON(dlg,XRCID("button_OK"), lambda evt: dlg.EndModal(wx.ID_OK)) wx.EVT_BUTTON(dlg,XRCID("button_Cancel"), lambda evt: dlg.EndModal(wx.ID_CANCEL)) ret = dlg.ShowModal() if ret == wx.ID_OK: self.numRows = XRCCTRL(dlg, "rowSpin").GetValue() self.numCols = XRCCTRL(dlg, "colSpin").GetValue() self.newLayout() dlg.Destroy() def onButtonPress(self,evt): if not evt.inaxes: return if evt.button==wx.MOUSE_BTN_RIGHT and not self.toolbar._active: self.currentAxis = evt.inaxes x=evt.x y=self.canvas.GetSize().GetHeight()-evt.y self.PopupMenu(self.popup, wx.Point(x,y)) def onTraceLine(self,evt): traceFile = self.openTraceFile() if not traceFile: return if evt.GetId() == ID_TRACE_NEW_LINE: self.currentAxis.clear() xvec=[] yvec=[] for line in traceFile: x,y=line.split() xvec.append(float(x)) yvec.append(float(y)) traceFile.close() self.currentAxis.plot(xvec,yvec) def onTraceNewBar(self,evt): traceFile = self.openTraceFile() if not traceFile: return data = {} for line in traceFile: # Lines have the format: time item1;item2;item3 # where the items have the format: xvalue,yvalue t,line = line.split(' ',1) line = line.strip() if line: items=line.split(';') for item in items: x,y=item.split(',') data[int(x)]=float(y) traceFile.close() xvec=data.keys() yvec=data.values() self.currentAxis.bar(xvec,yvec) self.currentAxis.set_title("Trace: %s"%os.path.basename(traceFile.name)) def onListenerNewLine(self,evt): result = self.newLineListenerDlg() if not result: return traceID,updateFreq,visiblePoints,keepInvisiblePoints = result if not traceID or not updateFreq or visiblePoints < 0: return self.onClearPlot(None) self.listeners[traceID] = LineListener( traceID, self.currentAxis, 1.0/updateFreq, visiblePoints, keepInvisiblePoints) def onListenerNewBar(self,evt): result = self.newBarListenerDlg() if not result: return traceID,updateFreq = result if not traceID or not updateFreq: return self.onClearPlot(None) self.listeners[traceID] = BarListener( traceID, self.currentAxis, 1.0/updateFreq) def onClearPlot(self,evt): self.currentAxis.clear() for traceID,listener in self.listeners.items(): if listener.axis == self.currentAxis: listener.unregister() del self.listeners[traceID] def onPlotParameters(self,evt): pass def onHelpAbout(self,evt): pass def OnPaint(self, evt): self.canvas.draw() def simReloaded(self): """Called by the simulation controller when the simulation is reloaded. Reregister all listeners, since they have been unregistered. """ for listener in self.listeners.values(): listener.reregister() # -------------------------------------------------------------------- def newLayout(self): self.figure.clear() self.axes = [] layoutCode = self.numRows*100 + self.numCols*10 for row in range(self.numRows): for col in range(self.numCols): plotnum = row*self.numCols + col + 1 axis=self.figure.add_subplot(layoutCode+plotnum) self.axes.append(axis) self.canvas.draw() for listener in self.listeners.values(): listener.unregister() self.listeners={} def openTraceFile(self): dlg = wx.FileDialog( self, message="Choose a trace file", defaultDir=os.getcwd(), defaultFile="", wildcard="All files (*.*)|*.*", style=wx.OPEN | wx.CHANGE_DIR) if dlg.ShowModal() != wx.ID_OK: return None filename = os.path.abspath(dlg.GetPaths()[0]) try: traceFile=file(filename) except IOError,message: dlg = wx.MessageDialog(self, str(message), 'File open error', wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return None return traceFile