class CanvasFrameMap(wx.Frame): def __init__(self, ): wx.Frame.__init__(self, None, -1, 'Activity Map', size=(750, 750)) self.SetBackgroundColour(wx.NamedColor("BLACK")) self.figure = Figure(figsize=(5, 5)) self.axes = self.figure.add_subplot(111) duder = array(rangevecReorg) duder.shape = 80, 80 self.axes.imshow(duder, origin='upper', cmap=cm.hot, extent=(0, 80, 0, 80)) self.axes.set_xlabel(str(FileString[0])) self.axes.set_ylabel('y') self.figure_canvas = FigureCanvas(self, -1, self.figure) # Note that event is a MplEvent self.figure_canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar) self.figure_canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.figure_canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self.sizer) self.Fit() self.statusBar = wx.StatusBar(self, -1) self.statusBar.SetFieldsCount(1) self.SetStatusBar(self.statusBar) self.toolbar = NavigationToolbar2Wx(self.figure_canvas) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) self.toolbar.Show() def ChangeCursor(self, event): self.figure_canvas.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE)) def UpdateStatusBar(self, event): if event.inaxes: x, y = event.xdata, event.ydata self.statusBar.SetStatusText( ("x= " + str(int(x)) + " y=" + str(int(y))), 0)
class CanvasFrame(wx.Frame): def __init__(self, ): wx.Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350)) self.SetBackgroundColour(wx.NamedColour("WHITE")) 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.axes.set_xlabel('t') self.axes.set_ylabel('sin(t)') self.figure_canvas = FigureCanvas(self, -1, self.figure) # Note that event is a MplEvent self.figure_canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar) self.figure_canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.figure_canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self.sizer) self.Fit() self.statusBar = wx.StatusBar(self, -1) self.statusBar.SetFieldsCount(1) self.SetStatusBar(self.statusBar) self.toolbar = NavigationToolbar2Wx(self.figure_canvas) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) self.toolbar.Show() def ChangeCursor(self, event): self.figure_canvas.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE)) def UpdateStatusBar(self, event): if event.inaxes: x, y = event.xdata, event.ydata self.statusBar.SetStatusText(( "x= " + str(x) + " y=" +str(y) ), 0)
class CanvasFrame(wx.Frame): def __init__(self, ): super().__init__(None, -1, 'CanvasFrame', size=(550, 350)) self.figure = Figure() self.axes = self.figure.add_subplot() t = np.arange(0.0, 3.0, 0.01) s = np.sin(2 * np.pi * t) self.axes.plot(t, s) self.axes.set_xlabel('t') self.axes.set_ylabel('sin(t)') self.figure_canvas = FigureCanvas(self, -1, self.figure) # Note that event is a MplEvent self.figure_canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar) self.figure_canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.figure_canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self.sizer) self.Fit() self.statusBar = wx.StatusBar(self, -1) self.SetStatusBar(self.statusBar) self.toolbar = NavigationToolbar2Wx(self.figure_canvas) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) self.toolbar.Show() def ChangeCursor(self, event): self.figure_canvas.SetCursor(wx.Cursor(wx.CURSOR_BULLSEYE)) def UpdateStatusBar(self, event): if event.inaxes: self.statusBar.SetStatusText("x={} y={}".format( event.xdata, event.ydata))
class PVWindow(wx.Frame): #########################Init Funcions############################# def __init__(self,parent=None,dpi=100,geoid=Geodesic.WGS84,fontsize=8): """Constructor""" #call init of super class default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP wx.Frame.__init__(self, parent, title="Phase Viewer %s"%parent.__version__,style=default_style, size=(400*2,300*2)) self.Bind(wx.EVT_CLOSE, self.on_close_main) self.parent=parent self.dpi = dpi self.geoid = geoid self.fontsize = fontsize self.mouse_left_down = False self.panel = wx.Panel(self,-1,size=(400*2,300*2)) #Populate UI and Menu self.init_UI() self.create_menu() self.configure() self.update() def init_UI(self): spacing = 10 #-----------------------------------------Make SideBar-----------------------------------------------------# side_bar_sizer = wx.BoxSizer(wx.VERTICAL) #####-------------------------------------Make FilterBox---------------------------------------------------# filter_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Filter Options"), wx.VERTICAL) highlow_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Highcut/Lowcut"), wx.HORIZONTAL) order_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Order"), wx.HORIZONTAL) text_input_sizer = wx.BoxSizer(wx.HORIZONTAL) null_filter = lambda x,y,z,fs,order: x self.filters = {"None":null_filter,"Butterworth Bandpass":sk.butter_bandpass_filter,"Butterworth Lowpass":sk.butter_lowpass_filter} list_filters = ["None","Butterworth Bandpass","Butterworth Lowpass"] self.filter_type_box = wx.ComboBox(self.panel, id=wx.ID_ANY,size=(200, 25), value=list_filters[0], choices=list_filters, style=wx.CB_DROPDOWN|wx.TE_READONLY) self.Bind(wx.EVT_COMBOBOX, self.on_select_filter,self.filter_type_box) self.lowcut_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25)) self.highcut_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25)) self.order_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25)) order_sizer.Add(self.order_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing) highlow_sizer.AddMany([(self.lowcut_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (self.highcut_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)]) text_input_sizer.AddMany([(highlow_sizer, 2, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (order_sizer, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)]) filter_sizer.AddMany([(self.filter_type_box, 1, wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (text_input_sizer, 1, wx.ALIGN_CENTER|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing)]) #####-------------------------------------Make BoundsBox---------------------------------------------------# bounds_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Bounds"), wx.HORIZONTAL) bounds_diff_sizer = wx.BoxSizer(wx.HORIZONTAL) self.low_bound_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25)) self.high_bound_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25)) self.aero_diff_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25)) bounds_sizer.AddMany([(self.low_bound_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (self.high_bound_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)]) bounds_diff_sizer.AddMany([(bounds_sizer, 2, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (self.aero_diff_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)]) #####-------------------------------------Make UpdateBtn---------------------------------------------------# self.update_button = wx.Button(self.panel, id=wx.ID_ANY, label='Update',size=(200,50)) self.Bind(wx.EVT_BUTTON, self.on_update_button, self.update_button) #-------------------------------------Make Figures---------------------------------------------------------# self.power_fig = Figure((3, 3), dpi=self.dpi) self.power_canvas = FigCanvas(self.panel, -1, self.power_fig) self.power_toolbar = NavigationToolbar(self.power_canvas) # psk.remove_axis_lines_and_ticks(self.ax) self.power_toolbar.Hide() self.power_plot_setting = "Zoom" self.power_toolbar.zoom() self.power_canvas.Bind(wx.EVT_MIDDLE_DOWN,self.on_middle_click_power_plot) self.fig = Figure((4, 3), dpi=self.dpi) self.canvas = FigCanvas(self.panel, -1, self.fig) self.toolbar = NavigationToolbar(self.canvas) # psk.remove_axis_lines_and_ticks(self.ax) self.toolbar.Hide() self.plot_setting = "Zoom" self.toolbar.zoom() self.canvas.Bind(wx.EVT_MIDDLE_DOWN,self.on_middle_click_plot) self.canvas.Bind(wx.EVT_MOTION,self.on_move_mouse_plot) self.canvas.Bind(wx.EVT_LEFT_DOWN, self.on_left_click_down) self.canvas.Bind(wx.EVT_LEFT_UP, self.on_left_click_up) # self.canvas.Bind(wx.EVT_RIGHT_DCLICK, self.on_select_dright_click) #----------------------------------Build UI and Fit--------------------------------------------------------# side_bar_sizer.AddMany([(filter_sizer, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (bounds_diff_sizer, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (self.update_button, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (self.power_canvas, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)]) outer_sizer = wx.BoxSizer(wx.HORIZONTAL) outer_sizer.AddMany([#(grd_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND|wx.LEFT|wx.RIGHT,spacing), (side_bar_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND), (self.canvas,10,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND)]) self.panel.SetSizerAndFit(outer_sizer) def create_menu(self): """ Generates Menu """ self.menubar = wx.MenuBar() #----------------- # File Menu #----------------- menu_file = wx.Menu() menu_file.AppendSeparator() m_exit = menu_file.Append(-1, "&Exit\tCtrl-Q", "Exit") self.Bind(wx.EVT_MENU, self.on_close_main, m_exit) #----------------- self.menubar.Append(menu_file, "&File") self.SetMenuBar(self.menubar) def configure(self): self.lowcut_box.SetValue("%.2f"%0.01) self.highcut_box.SetValue("%.2f"%0.1) self.order_box.SetValue("%d"%3) self.low_bound_box.SetValue("%.2f"%(-50.0)) self.high_bound_box.SetValue("%.2f"%50.0) self.aero_diff_box.SetValue("%.1f"%0.0) #########################Update UI Funcions############################# def update(self): self.fig.clear() #clear self.power_fig.clear() self.draw_figures() #draw self.canvas.draw() #rerender self.power_canvas.draw() def on_close_main(self,event): self.parent.pv_open=False self.Destroy() ###################Button and Dropdown Functions######################### # def on_change_grd_btn(self,event): # dlg = wx.FileDialog( # self, message="Choose Grid File", # defaultDir=self.parent.WD, # defaultFile="", # wildcard="Grid Files (*.grd,*.nc,*.ncf)|*.grd;*.nc;*.ncf|All Files (*.*)|*.*", # style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST # ) # if dlg.ShowModal() == wx.ID_OK: # self.grd_file = dlg.GetPath() # self.grd_path.SetValue(self.grd_file) # self.update() # dlg.Destroy() # else: dlg.Destroy() def on_select_filter(self,event): self.update() def on_update_button(self,event): self.update() ###########################Figure Funcions############################### def on_middle_click_plot(self,event): if event.LeftIsDown() or event.ButtonDClick(): event.Skip(); return elif self.plot_setting == "Zoom": self.plot_setting = "Pan" self.toolbar.pan('off') elif self.plot_setting == "Pan": self.plot_setting = "Pick" self.toolbar.pan('off') myCursor= wx.StockCursor(wx.CURSOR_IBEAM) self.canvas.SetCursor(myCursor) elif self.plot_setting == "Pick": self.plot_setting = "Zoom" self.toolbar.zoom() event.Skip() def on_middle_click_power_plot(self,event): if event.LeftIsDown() or event.ButtonDClick(): event.Skip(); return elif self.power_plot_setting == "Zoom": self.power_plot_setting = "Pan" self.power_toolbar.pan('off') elif self.power_plot_setting == "Pan": self.power_plot_setting = "Zoom" self.power_toolbar.zoom() event.Skip() def on_move_mouse_plot(self,event): pos=event.GetPosition() width, height = self.canvas.get_width_height() pos = [pos[0],height-pos[1]] pos = self.ax0.transData.inverted().transform(pos) # self.annotate_point(pos,xy=(1-0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,va='top',ha='right') self.plot_tracer_point(pos[0],linestyle='--',color='red',alpha=.5) self.canvas.draw() event.Skip() def on_left_click_down(self,event): if self.plot_setting!="Pick": event.Skip(); return pos=event.GetPosition() width, height = self.canvas.get_width_height() pos = [pos[0],height-pos[1]] pos = self.ax0.transData.inverted().transform(pos) self.tmp_new_bounds = [pos[0],None] self.mouse_left_down = True event.Skip() def on_left_click_up(self,event): if self.plot_setting!="Pick": event.Skip(); return pos=event.GetPosition() width, height = self.canvas.get_width_height() pos = [pos[0],height-pos[1]] pos = self.ax0.transData.inverted().transform(pos) self.tmp_new_bounds[1] = pos[0] self.mouse_left_down = False if abs(self.tmp_new_bounds[1]-self.tmp_new_bounds[0])>0: self.low_bound_box.SetValue("%.1f"%float(min(self.tmp_new_bounds))) self.high_bound_box.SetValue("%.1f"%float(max(self.tmp_new_bounds))) self.update() event.Skip() ##########################Additional Plotting and Backend Functions################ def on_parent_select_track(self): self.update() def plot_tracer_point(self,x,**kwargs): try: for tracer in self.tracers: tracer.remove() except (AttributeError,ValueError) as e: pass self.tracers = [] self.tracers.append(self.ax0.axvline(x,**kwargs)) self.tracers.append(self.ax1.axvline(x,**kwargs)) self.tracers.append(self.ax2.axvline(x,**kwargs)) if self.mouse_left_down: myCursor= wx.StockCursor(wx.CURSOR_IBEAM) self.canvas.SetCursor(myCursor) self.tracers.append(self.ax0.axvspan(min([self.tmp_new_bounds[0],x]),max([self.tmp_new_bounds[0],x]),color="yellow",alpha=.4)) self.tracers.append(self.ax1.axvspan(min([self.tmp_new_bounds[0],x]),max([self.tmp_new_bounds[0],x]),color="yellow",alpha=.4)) self.tracers.append(self.ax2.axvspan(min([self.tmp_new_bounds[0],x]),max([self.tmp_new_bounds[0],x]),color="yellow",alpha=.4)) def draw_figures(self): ####################################################Get Values dsk_row = self.parent.dsk_row track = self.parent.track ddis = float(self.parent.samp_dis_box.GetValue()) if ddis==0: self.parent.user_warning("Synthetic is required for comparision of phase, start by initalilzing a synthetic"); return synth_dis = self.parent.dis_synth synth_mag = self.parent.synth filter_type = self.filter_type_box.GetValue() lowcut = float(self.lowcut_box.GetValue()) highcut = float(self.highcut_box.GetValue()) order = int(self.order_box.GetValue()) left_bound = float(self.low_bound_box.GetValue()) right_bound = float(self.high_bound_box.GetValue()) aero_diff = float(self.aero_diff_box.GetValue()) left_idx = np.argmin(np.abs(synth_dis-left_bound)) right_idx = np.argmin(np.abs(synth_dis-right_bound)) left_idx,right_idx = min([left_idx,right_idx]),max([left_idx,right_idx]) bin_range,bin_num = (-180,180),120 ###################################################Filter Data data_path = os.path.join(dsk_row["data_dir"],dsk_row["comp_name"]) data_df = utl.open_mag_file(data_path) projected_distances = utl.calc_projected_distance(dsk_row['inter_lon'],dsk_row['inter_lat'],data_df['lon'].tolist(),data_df['lat'].tolist(),(180+dsk_row['strike'])%360) shifted_mag = sk.phase_shift_data(data_df["mag"],dsk_row["phase_shift"]) if np.any(np.diff(projected_distances["dist"])<0): itshifted_mag = np.interp(-synth_dis,-projected_distances["dist"],shifted_mag) else: itshifted_mag = np.interp(synth_dis,projected_distances["dist"],shifted_mag) fitshifted_mag = self.filters[filter_type](itshifted_mag,lowcut,highcut,fs=1/ddis,order=order) ###################################################Actual Plotting outer = gridspec.GridSpec(4, 1) ###################################################Axis 0: Magnetic profiles self.ax0 = self.fig.add_subplot(outer[0]) if self.parent.show_other_comp: #Handle Other Aeromag Component if dsk_row["track_type"]=="aero": if "Ed.lp" in track: other_track = track.replace("Ed.lp","Vd.lp") total_track = track.replace("Ed.lp","Td.lp") other_phase = dsk_row["phase_shift"]-90 elif "Hd.lp" in track: other_track = track.replace("Hd.lp","Vd.lp") total_track = track.replace("Hd.lp","Td.lp") other_phase = dsk_row["phase_shift"]-90 elif "Vd.lp" in track: other_track = track.replace("Vd.lp","Ed.lp") total_track = track.replace("Vd.lp","Td.lp") if other_track not in self.parent.deskew_df["comp_name"].tolist(): other_track = track.replace("Vd.lp","Hd.lp") other_phase = dsk_row["phase_shift"]+90 else: self.parent.user_warning("Improperly named component files should have either Ed.lp, Hd.lp, or Vd.lp got: %s"%track); return oth_row = self.parent.deskew_df[self.parent.deskew_df["comp_name"]==other_track].iloc[0] oth_data_path = os.path.join(oth_row["data_dir"],oth_row["comp_name"]) tot_data_path = os.path.join(oth_row["data_dir"],total_track) #Should be in same place oth_data_df = utl.open_mag_file(oth_data_path) oth_shifted_mag = sk.phase_shift_data(oth_data_df["mag"],other_phase) if np.any(np.diff(projected_distances["dist"])<0): oth_itshifted_mag = np.interp(-synth_dis,-projected_distances["dist"],oth_shifted_mag) else: oth_itshifted_mag = np.interp(synth_dis,projected_distances["dist"],oth_data_df) oth_fitshifted_mag = self.filters[filter_type](oth_itshifted_mag,lowcut,highcut,fs=1/ddis,order=order) if filter_type=="None": psk.plot_skewness_data(oth_row,other_phase,self.ax0,xlims=[None,None],color='darkgreen',zorder=2,picker=True,alpha=.7,return_objects=True,flip=True) else: self.ax0.plot(synth_dis,oth_fitshifted_mag,color="#299C29",zorder=3,alpha=.6) tot_data_df = utl.open_mag_file(tot_data_path) if np.any(np.diff(projected_distances["dist"])<0): tot_imag = np.interp(-synth_dis,-projected_distances["dist"],tot_data_df["mag"]) else: tot_imag = np.interp(synth_dis,projected_distances["dist"],tot_data_df["mag"]) tot_fimag = self.filters[filter_type](tot_imag,lowcut,highcut,fs=1/ddis,order=order) if filter_type=="None": psk.plot_skewness_data(dsk_row,dsk_row["phase_shift"],self.ax0,xlims=[None,None],zorder=3,picker=True,return_objects=True,flip=True) else: self.ax0.plot(synth_dis,fitshifted_mag,color="#7F7D7D",zorder=3,alpha=.6) self.ax0.plot(self.parent.dis_synth,self.parent.synth,'r-',alpha=.4,zorder=1) self.ax0.set_ylabel("Magnetic Profiles") # self.ax0.get_xaxis().set_ticklabels([]) ###################################################Axis 1/2: Phase Angles and Differences self.ax1 = self.fig.add_subplot(outer[1], sharex=self.ax0) self.ax2 = self.fig.add_subplot(outer[2], sharex=self.ax0) ###################################################Calculate: Phase Differences trimmed_dis = synth_dis[left_idx:right_idx] trimmed_synth = synth_mag[left_idx:right_idx] trimmed_fitshifted_mag = fitshifted_mag[left_idx:right_idx] al_data = np.angle(hilbert(fitshifted_mag),deg=False)[left_idx:right_idx] al_synth = np.angle(hilbert(np.real(synth_mag)),deg=False)[left_idx:right_idx] data_synth_diff = phase_diff_func(al_synth,al_data) if self.parent.show_other_comp and dsk_row["track_type"]=="aero": trimmed_oth_fitshifted_mag = oth_fitshifted_mag[left_idx:right_idx] al_oth = np.angle(hilbert(oth_fitshifted_mag),deg=False)[left_idx:right_idx] oth_synth_diff = phase_diff_func(al_synth,al_oth) oth_data_diff = phase_diff_func(al_oth,al_data) if abs(aero_diff) > 0: idx = ma.array(np.abs(oth_data_diff)<aero_diff) self.ax1.plot((trimmed_dis[~idx]),(np.rad2deg(al_oth[~idx])),color="darkgreen",linestyle=":") self.ax2.plot((trimmed_dis[~idx]),(oth_synth_diff[~idx]),color="tab:pink",alpha=.8,linestyle=":") self.ax2.plot((trimmed_dis[~idx]),(oth_data_diff[~idx]),color="tab:grey",alpha=.8,linestyle=":") self.ax1.plot((trimmed_dis[~idx]),(np.rad2deg(al_data[~idx])),color="k",linestyle=":") self.ax1.plot((trimmed_dis[~idx]),(np.rad2deg(al_synth[~idx])),color="r",linestyle=":") self.ax2.plot((trimmed_dis[~idx]),(data_synth_diff[~idx]),color="tab:red",alpha=.8,linestyle=":") # import pdb; pdb.set_trace() # not_trimmed_dis = (trimmed_dis[~idx]) # not_trimmed_dis[np.diff(~idx,prepend=[0])] = ma.masked # not_al_data = (al_data[~idx]) # not_al_data[np.diff(~idx)] = ma.masked # not_al_synth = (al_synth[~idx]) # not_al_synth[np.diff(~idx)] = ma.masked # not_al_oth = (al_oth[~idx]) # not_al_oth[np.diff(~idx)] = ma.masked # not_data_synth_diff = (data_synth_diff[~idx]) # not_data_synth_diff[np.diff(~idx)] = ma.masked # not_oth_synth_diff = (oth_synth_diff[~idx]) # not_oth_synth_diff[np.diff(~idx)] = ma.masked # not_oth_data_diff = (oth_data_diff[~idx]) # not_oth_data_diff[np.diff(~idx)] = ma.masked trimmed_dis = (trimmed_dis[idx]) al_data = (al_data[idx]) al_synth = (al_synth[idx]) al_oth = (al_oth[idx]) data_synth_diff = (data_synth_diff[idx]) oth_synth_diff = (oth_synth_diff[idx]) oth_data_diff = (oth_data_diff[idx]) self.ax1.plot(trimmed_dis,np.rad2deg(al_oth),color="darkgreen") self.ax2.plot(trimmed_dis,oth_synth_diff,color="tab:pink",alpha=.8) self.ax2.plot(trimmed_dis,oth_data_diff,color="tab:grey",alpha=.8) self.ax1.plot(trimmed_dis,np.rad2deg(al_data),color="k") self.ax1.plot(trimmed_dis,np.rad2deg(al_synth),color="r") self.ax2.plot(trimmed_dis,data_synth_diff,color="tab:red",alpha=.8) # self.ax2.get_xaxis.set_ticklabels self.ax0.set_xlim(*self.parent.ax.get_xlim()) self.ax0.set_ylim(*self.parent.ax.get_ylim()) self.ax1.set_ylabel("Phase Angles") self.ax2.set_ylabel("Phase Differences") ###################################################Axis 2.1: Power Spectrum # inner = gridspec.GridSpecFromSubplotSpec(1, 2, subplot_spec=outer[2])#, hspace=0.) # self.ax2 = self.fig.add_subplot(inner[0]) ###################################################Axis 2.2: Phase Statistics self.ax3 = self.fig.add_subplot(outer[3]) if self.parent.show_other_comp and dsk_row["track_type"]=="aero": self.ax3.hist(oth_synth_diff,range=bin_range,bins=bin_num,color="tab:pink",alpha=.5,zorder=2) self.ax3.hist(oth_data_diff,range=bin_range,bins=bin_num,color="tab:grey",alpha=.5,zorder=1) self.ax3.hist(data_synth_diff,range=bin_range,bins=bin_num,color="tab:red",alpha=.5,zorder=3) self.ax3.axvline(np.median(data_synth_diff),color="k",alpha=.5,zorder=5,linestyle=":") self.ax3.axvline(np.mean(data_synth_diff),color="k",alpha=.5,zorder=5) self.ax3.axvspan(np.mean(data_synth_diff)-np.std(data_synth_diff),np.mean(data_synth_diff)+np.std(data_synth_diff),color="tab:grey",alpha=.3,zorder=0) self.ax3.annotate(r"$\theta_{mean}$ = $%.1f^\circ \pm %.1f^\circ$"%(np.mean(data_synth_diff),np.std(data_synth_diff)) + "\n" + r"$\theta_{median}$ = %.1f$^\circ$"%np.median(data_synth_diff),xy=(0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,va='top',ha='left') self.ax3.set_ylabel(r"$\Delta \theta$ Count") self.fig.suptitle("%s\n%s\n"%(dsk_row["sz_name"],track)) ###################################################Power Figure N = (right_idx-left_idx) #Length of signal in distance domain NW = 3 #following Parker and O'brien '97 and HJ-Gordon '03 we use a time-bandwith product of 6 (Nw is half) Ns = 5 #Number of points to use in running average smoothing #Handle Distance Domain # import pdb; pdb.set_trace() Sk_complex, weights, eigenvalues=pmtm(itshifted_mag[left_idx:right_idx], NW=NW, NFFT=N, show=False) Sk = np.abs(Sk_complex)**2 smoothed_tshifted_freq = (np.mean(Sk * np.transpose(weights), axis=0) * ddis)[N//2:][::-1] # smoothed_tshifted_freq = np.convolve(smoothed_tshifted_freq, np.ones((Ns,))/Ns, mode='same') #10 point running average smoothing tdata_freqs = np.linspace(0.0, 1.0/(2.0*ddis), N-N//2) #0 to Nyquest self.power_ax = self.power_fig.add_subplot(111) if self.parent.show_other_comp and dsk_row["track_type"]=="aero": Sk_complex, weights, eigenvalues=pmtm(oth_itshifted_mag[left_idx:right_idx], NW=NW, NFFT=N, show=False) Sk = np.abs(Sk_complex)**2 oth_smoothed_tshifted_freq = (np.mean(Sk * np.transpose(weights), axis=0) * ddis)[N//2:][::-1] # oth_smoothed_tshifted_freq = np.convolve(oth_smoothed_tshifted_freq, np.ones((Ns,))/Ns, mode='same') #10 point running average smoothing self.power_ax.semilogy(tdata_freqs, oth_smoothed_tshifted_freq, color="darkgreen") # self.power_ax.semilogy(tdata_freqs, oth_smoothed_tshifted_freq+smoothed_tshifted_freq, color="grey") Sk_complex, weights, eigenvalues=pmtm(tot_imag[left_idx:right_idx], NW=NW, NFFT=N, show=False) Sk = np.abs(Sk_complex)**2 tot_smoothed_tshifted_freq = (np.mean(Sk * np.transpose(weights), axis=0) * ddis)[N//2:][::-1] # tot_smoothed_tshifted_freq = np.convolve(tot_smoothed_tshifted_freq, np.ones((Ns,))/Ns, mode='same') #10 point running average smoothing self.power_ax.semilogy(tdata_freqs, tot_smoothed_tshifted_freq, color="tab:orange") #Old Numpy Method # synth_freqs = np.fft.fftfreq(len(synth_dis[left_idx:right_idx]),ddis) # tdata_freqs = np.fft.fftfreq(len(shifted_mag[left_idx:right_idx]),ddis) # tshifted_freq = np.fft.fft(shifted_mag[left_idx:right_idx]) # fitshifted_freq = np.fft.fft(fitshifted_mag[left_idx:right_idx]) # tsynth_freq = np.fft.fft(synth_mag[left_idx:right_idx]) self.power_ax.semilogy(tdata_freqs, smoothed_tshifted_freq, color="k",zorder=100) # self.power_ax.semilogy(tdata_freqs, np.abs(tshifted_freq), color="k") # self.power_ax.plot(synth_freqs, np.abs(fitshifted_freq), color="#7F7D7D") # self.power_ax.plot(synth_freqs, np.abs(tsynth_freq), color="r") self.power_ax.set_xlim(0.0,0.4) self.power_ax.set_ylim(1e-1,1e6)
class LeftGraphBottom(wx.Panel): def __init__(self, parent, statusbar): wx.Panel.__init__(self, parent) self.statusbar = statusbar """ An polygon editor. Key-bindings 't' toggle vertex markers on and off. When vertex markers are on, you can move them, delete them 'd' delete the vertex under point 'i' insert a vertex at point. You must be within epsilon of the line connecting two existing vertices """ self.fig = Figure((4.0, 3.0)) self.canvas = FigCanvas(self, -1, self.fig) self.ax = self.fig.add_subplot(111) """ subplots_adjust(bottom=0.14): permet d'ajuster la taille du canevas en prenant en compte la legende sinon la legende est rognee""" self.fig.subplots_adjust(bottom=0.20) self.ax.set_ylabel("DW", fontdict=font) self.ax.set_xlabel("Depth ($\AA$)", fontdict=font) self.toolbar = NavigationToolbar(self.canvas) self.toolbar.Hide() self.fig.patch.set_facecolor(colorBackgroundGraph) self._ind = None # the active vert self.poly = [] self.line = [] self.showverts = True self.epsilon = 5 # max pixel distance to count as a vertex hit self.new_coord = {'indice': 0, 'x': 0, 'y': 0} self.modelpv = False xs = [-1] ys = [-1] poly = Polygon(list(zip(xs, ys)), ls='solid', fill=False, closed=False, animated=True) self.ax.set_xlim([0, 1]) self.ax.set_ylim([0, 1]) self.c_dw = "" self.l_dw = "" self.canvas.mpl_connect('draw_event', self.draw_callback) self.canvas.mpl_connect('button_press_event', self.button_press_callback) self.canvas.mpl_connect('button_release_event', self.button_release_callback) self.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback) self.canvas.mpl_connect('scroll_event', self.scroll_callback) self.canvas.mpl_connect('motion_notify_event', self.on_update_coordinate) mastersizer = wx.BoxSizer(wx.VERTICAL) mastersizer.Add(self.canvas, 1, wx.ALL | wx.EXPAND) mastersizer.Add(self.toolbar, 0, wx.ALL) pub.subscribe(self.draw_c, pubsub_draw_graph) pub.subscribe(self.OnDrawGraph, pubsub_Draw_DW) pub.subscribe(self.scale_manual, pubsub_Update_Scale_DW) pub.subscribe(self.on_color, pubsub_Graph_change_color_style) self.on_color() self.draw_c(poly, xs, ys) self.SetSizer(mastersizer) self.Fit() def on_color(self): a = P4Rm() self.c_dw = a.DefaultDict['c_dw'] self.l_dw = a.DefaultDict['l_dw'] self.c_bkg = a.DefaultDict['c_graph_background'] def OnDrawGraph(self, b=None): a = P4Rm() self.modelpv = a.modelPv self.ax.clear() if a.AllDataDict['damaged_depth'] == 0: self.ax.text(0.5, 0.5, "No Damage", size=30, rotation=0., ha="center", va="center", bbox=dict( boxstyle="round", ec='red', fc=self.c_dw, )) x_dwp = [-1] y_dwp = [-1] xs = [-1] ys = [-1] self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_xlim([0, 1]) self.ax.set_ylim([0, 1]) else: if b != 2: x_dwp = a.ParamDict['x_dwp'] y_dwp = a.ParamDict['DW_shifted'] xs = deepcopy(a.ParamDict['depth']) ys = deepcopy(a.ParamDict['DW_i']) P4Rm.DragDrop_DW_x = x_dwp P4Rm.DragDrop_DW_y = y_dwp ymin = min(ys) - min(ys) * 10 / 100 ymax = max(ys) + max(ys) * 10 / 100 self.ax.set_ylim([ymin, ymax]) if a.ParamDict['x_dwp'] != "": self.ax.set_xlim( [a.ParamDict['depth'][-1], a.ParamDict['depth'][0]]) elif b == 2: x_dwp = [-1] y_dwp = [-1] xs = [-1] ys = [-1] self.ax.set_xlim([0, 1]) self.ax.set_ylim([0, 1]) poly = Polygon(list(zip(x_dwp, y_dwp)), lw=0, ls='solid', color=self.c_dw, fill=False, closed=False, animated=True) if self.modelpv is True: P4Rm.ParamDict['dwp_pv_backup'] = a.ParamDict['dwp'] self.draw_c(poly, xs, ys) def draw_c(self, data, x, y): self.ax.plot(x, y, color=self.c_dw, lw=2., ls='solid') self.ax.set_ylabel("DW", fontdict=font) self.ax.set_xlabel("Depth ($\AA$)", fontdict=font) if LooseVersion(matplotlib_vers) < LooseVersion("2.0.0"): self.ax.set_axis_bgcolor(self.c_bkg) else: self.ax.set_facecolor(self.c_bkg) self.poly = data xs, ys = zip(*self.poly.xy) self.line = Line2D(xs, ys, lw=0, ls='solid', color=self.c_dw, marker='.', ms=32, markerfacecolor=self.c_dw, markeredgecolor='k', mew=1.0) self.ax.add_line(self.line) self.ax.add_patch(self.poly) self.canvas.SetCursor(Cursor(wx.CURSOR_HAND)) self.canvas.draw() def draw_callback(self, event): self.background = self.canvas.copy_from_bbox(self.ax.bbox) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.blit(self.ax.bbox) def get_ind_under_point(self, event): 'get the index of the vertex under point if within epsilon tolerance' # display coords xy = np.asarray(self.poly.xy) xyt = self.poly.get_transform().transform(xy) xt, yt = xyt[:, 0], xyt[:, 1] d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2) indseq = np.nonzero(np.equal(d, np.amin(d)))[0] ind = indseq[0] if d[ind] >= self.epsilon: ind = None return ind def button_press_callback(self, event): 'whenever a mouse button is pressed' a = P4Rm() val = a.xrd_graph_loaded if self.canvas.HasCapture(): self.canvas.ReleaseMouse() if not self.showverts: return if event.inaxes is None: return if event.button != 1: return if val == 1: self._ind = self.get_ind_under_point(event) self.new_coord['indice'] = self._ind def button_release_callback(self, event): 'whenever a mouse button is released' a = P4Rm() val = a.xrd_graph_loaded if self.canvas.HasCapture(): self.canvas.ReleaseMouse() else: if not self.showverts: return if event.button != 1: return if self.new_coord['indice'] is not None and val == 1: a = P4Rm() temp_1 = self.new_coord['y'] temp_2 = self.new_coord['x'] P4Rm.DragDrop_DW_y[self.new_coord['indice']] = temp_1 P4Rm.DragDrop_DW_x[self.new_coord['indice']] = temp_2 if a.AllDataDict['model'] == 0: temp = self.new_coord['y'] P4Rm.DragDrop_DW_y[self.new_coord['indice']] = temp temp = [ dw * scale for dw, scale in zip( a.DragDrop_DW_y, a.ParamDict['scale_dw']) ] temp = [float(format(value, '.8f')) for value in temp] temp2 = np.concatenate([temp, [a.ParamDict['dw_out']]]) P4Rm.ParamDict['dwp'] = deepcopy(temp2) P4Rm.ParamDictbackup['dwp'] = deepcopy(temp2) elif a.AllDataDict['model'] == 1: temp = self.new_coord['y'] P4Rm.DragDrop_DW_y[self.new_coord['indice']] = temp temp = [ dw * scale for dw, scale in zip( a.DragDrop_DW_y, a.ParamDict['scale_dw']) ] temp = [float(format(value, '.8f')) for value in temp] temp2 = np.concatenate([[a.ParamDict['dw_out'][0]], temp, [a.ParamDict['dw_out'][1]]]) P4Rm.ParamDict['dwp'] = deepcopy(temp2) P4Rm.ParamDictbackup['dwp'] = deepcopy(temp2) elif a.AllDataDict['model'] == 2: t_temp = a.ParamDict['depth'] + a.ParamDict['z'] t = t_temp[0] dwp_temp = range(7) dwp_temp[0] = a.DragDrop_DW_y[0] dwp_temp[1] = 1 - a.DragDrop_DW_x[0] / t dwp_temp[2] = 2 * (-1 + a.ParamDict['dwp'][1] + a.DragDrop_DW_x[1] / t) dwp_temp[3] = 2 * (1 - a.ParamDict['dwp'][1] - 1 * a.DragDrop_DW_x[2] / t) dwp_temp[4] = a.ParamDict['dwp'][4] dwp_temp[5] = a.ParamDict['dwp'][5] dwp_temp[6] = a.DragDrop_DW_y[3] P4Rm.ParamDict['dwp'] = deepcopy(dwp_temp) P4Rm.ParamDictbackup['dwp'] = deepcopy(dwp_temp) P4Rm.ParamDict['dwp_pv'] = deepcopy(dwp_temp) pub.sendMessage(pubsub_Update_Fit_Live) self._ind = None def scroll_callback(self, event): if not event.inaxes: return a = P4Rm() if event.key == 'u' and event.button == 'up': temp = a.ParamDict['DW_multiplication'] + 0.01 P4Rm.ParamDict['DW_multiplication'] = temp elif event.key == 'u' and event.button == 'down': temp = a.ParamDict['DW_multiplication'] - 0.01 P4Rm.ParamDict['DW_multiplication'] = temp P4Rm.ParamDict['dwp'] = multiply(a.ParamDictbackup['dwp'], a.ParamDict['DW_multiplication']) pub.sendMessage(pubsub_Re_Read_field_paramters_panel, event=event) def scale_manual(self, event, val=None): a = P4Rm() if val is not None: P4Rm.ParamDict['DW_multiplication'] = val P4Rm.ParamDict['dwp'] = multiply(a.ParamDict['dwp'], a.ParamDict['DW_multiplication']) pub.sendMessage(pubsub_Re_Read_field_paramters_panel, event=event) def motion_notify_callback(self, event): 'on mouse movement' a = P4Rm() if a.AllDataDict['damaged_depth'] == 0: return if not self.showverts: return if self._ind is None: return if event.inaxes is None: return if event.button != 1: return if self.modelpv is True: if self._ind == 0: y = event.ydata x = event.xdata elif self._ind == 1 or self._ind == 2: y = a.DragDrop_DW_y[self.new_coord['indice']] x = event.xdata else: x = a.DragDrop_DW_x[self.new_coord['indice']] y = event.ydata else: y = event.ydata x = a.DragDrop_DW_x[self.new_coord['indice']] self.new_coord['x'] = x self.new_coord['y'] = y self.poly.xy[self._ind] = x, y self.line.set_data(zip(*self.poly.xy)) self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) self.canvas.blit(self.ax.bbox) def on_update_coordinate(self, event): if event.inaxes is None: self.statusbar.SetStatusText(u"", 1) self.statusbar.SetStatusText(u"", 2) else: a = P4Rm() if not a.AllDataDict['damaged_depth'] == 0: x, y = event.xdata, event.ydata xfloat = round(float(x), 2) yfloat = round(float(y), 2) self.statusbar.SetStatusText(u"x = " + str(xfloat), 1) self.statusbar.SetStatusText(u"y = " + str(yfloat), 2) xy = np.asarray(self.poly.xy) xyt = self.poly.get_transform().transform(xy) xt, yt = xyt[:, 0], xyt[:, 1] d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2) indseq = np.nonzero(np.equal(d, np.amin(d)))[0] ind = indseq[0] if d[ind] >= self.epsilon: self.canvas.SetCursor(Cursor(wx.CURSOR_ARROW)) elif d[ind] <= self.epsilon: self.canvas.SetCursor(Cursor(wx.CURSOR_HAND))
class PlotPanel(BasePanel): """ MatPlotlib 2D plot as a wx.Panel, suitable for embedding in any wx.Frame. This does provide a right-click popup menu for configuration, zooming, saving an image of the figure, and Ctrl-C for copy-image-to-clipboard. For more features, see PlotFrame, which embeds a PlotPanel and also provides, a Menu, StatusBar, and Printing support. """ def __init__(self, parent, size=(700, 450), dpi=150, axisbg=None, facecolor=None, fontsize=9, trace_color_callback=None, output_title='plot', with_data_process=True, theme=None, **kws): self.trace_color_callback = trace_color_callback BasePanel.__init__(self, parent, output_title=output_title, **kws) self.conf = PlotConfig(panel=self, theme=theme, with_data_process=with_data_process) self.data_range = {} self.win_config = None self.cursor_callback = None self.lasso_callback = None self.cursor_mode = 'zoom' self.parent = parent self.figsize = (size[0] * 1.0 / dpi, size[1] * 1.0 / dpi) self.dpi = dpi self.conf.facecolor = ifnotNone(axisbg, self.conf.facecolor) self.conf.facecolor = ifnotNone(facecolor, self.conf.facecolor) # axesmargins : margins in px left/top/right/bottom self.axesmargins = (30, 30, 30, 30) self.BuildPanel() self.conf.user_limits = {} # [None, None, None, None] self.data_range = {} self.conf.zoom_lims = [] self.conf.axes_traces = {} def plot(self, xdata, ydata, side='left', title=None, xlabel=None, ylabel=None, y2label=None, use_dates=False, **kws): """ create a new plot of x/y data, clearing any existing plot on the panel """ allaxes = self.fig.get_axes() if len(allaxes) > 1: for ax in allaxes[1:]: if ax in self.data_range: self.data_range.pop(ax) self.fig.delaxes(ax) self.data_range = {} self.conf.zoom_lims = [] self.conf.axes_traces = {} self.clear() axes = self.axes if side == 'right': axes = self.get_right_axes() self.conf.reset_lines() self.conf.yscale = 'linear' self.conf.user_limits[axes] = [None, None, None, None] if xlabel is not None: self.set_xlabel(xlabel, delay_draw=True) if ylabel is not None: self.set_ylabel(ylabel, delay_draw=True) if y2label is not None: self.set_y2label(y2label, delay_draw=True) if title is not None: self.set_title(title, delay_draw=True) self.use_datas = ifnotNone(use_dates, self.use_dates) return self.oplot(xdata, ydata, side=side, **kws) def oplot(self, xdata, ydata, side='left', label=None, xlabel=None, ylabel=None, y2label=None, title=None, dy=None, ylog_scale=None, xlog_scale=None, grid=None, xmin=None, xmax=None, ymin=None, ymax=None, color=None, style=None, drawstyle=None, linewidth=2, marker=None, markersize=None, refresh=True, show_legend=None, legend_loc='best', legend_on=True, delay_draw=False, bgcolor=None, framecolor=None, gridcolor=None, labelfontsize=None, titlefontsize=None, legendfontsize=None, fullbox=None, axes_style=None, zorder=None, viewpad=None, theme=None, **kws): """ basic plot method, adding to an existing display """ self.cursor_mode = 'zoom' conf = self.conf conf.plot_type = 'lineplot' axes = self.axes if theme is not None: conf.set_theme(theme=theme) if side == 'right': axes = self.get_right_axes() # set y scale to log/linear if ylog_scale is not None: conf.yscale = {False: 'linear', True: 'log'}[ylog_scale] if xlog_scale is not None: conf.xscale = {False: 'linear', True: 'log'}[xlog_scale] axes.xaxis.set_major_formatter(FuncFormatter(self.xformatter)) if self.use_dates: xdata = [datetime.fromtimestamp(i) for i in xdata] xdata = dates.date2num(xdata) # axes.xaxis.set_major_locator(dates.AutoDateLocator()) linewidth = ifNone(linewidth, 2) conf.viewpad = ifnotNone(viewpad, conf.viewpad) if xlabel is not None: self.set_xlabel(xlabel, delay_draw=delay_draw) if ylabel is not None: self.set_ylabel(ylabel, delay_draw=delay_draw) if y2label is not None: self.set_y2label(y2label, delay_draw=delay_draw) if title is not None: self.set_title(title, delay_draw=delay_draw) if show_legend is not None: conf.set_legend_location(legend_loc, legend_on) conf.show_legend = show_legend conf.show_grid = ifnotNone(grid, conf.show_grid) # set data range for this trace # datarange = [min(xdata), max(xdata), min(ydata), max(ydata)] if axes not in conf.user_limits: conf.user_limits[axes] = [None, None, None, None] conf.user_limits[axes][0] = ifnotNone(xmin, conf.user_limits[axes][0]) conf.user_limits[axes][1] = ifnotNone(xmax, conf.user_limits[axes][1]) conf.user_limits[axes][2] = ifnotNone(ymin, conf.user_limits[axes][2]) conf.user_limits[axes][3] = ifnotNone(ymax, conf.user_limits[axes][3]) if axes == self.axes: axes.yaxis.set_major_formatter(FuncFormatter(self.yformatter)) else: axes.yaxis.set_major_formatter(FuncFormatter(self.y2formatter)) zorder = ifNone(zorder, 5 * (conf.ntrace + 1)) if axes not in conf.axes_traces: conf.axes_traces[axes] = [] conf.axes_traces[axes].append(conf.ntrace) conf.gridcolor = ifnotNone(gridcolor, conf.gridcolor) conf.facecolor = ifnotNone(bgcolor, conf.facecolor) if framecolor is not None: self.canvas.figure.set_facecolor(framecolor) conf.set_trace_zorder(zorder, delay_draw=True) if color: conf.set_trace_color(color, delay_draw=True) if style: conf.set_trace_style(style, delay_draw=True) if marker: conf.set_trace_marker(marker, delay_draw=True) if linewidth is not None: conf.set_trace_linewidth(linewidth, delay_draw=True) if markersize is not None: conf.set_trace_markersize(markersize, delay_draw=True) if drawstyle is not None: conf.set_trace_drawstyle(drawstyle, delay_draw=True) if dy is None: _lines = axes.plot(xdata, ydata, drawstyle=drawstyle, zorder=zorder) else: _lines = axes.errorbar(xdata, ydata, yerr=dy, zorder=zorder) if axes not in conf.data_save: conf.data_save[axes] = [] conf.data_save[axes].append((xdata, ydata)) if conf.show_grid and axes == self.axes: # I'm sure there's a better way... for i in axes.get_xgridlines() + axes.get_ygridlines(): i.set_color(conf.gridcolor) i.set_zorder(-100) axes.grid(True) else: axes.grid(False) if (self.conf.xscale == 'log' or self.conf.yscale == 'log'): self.set_logscale(xscale=self.conf.xscale, yscale=self.conf.yscale, delay_draw=delay_draw) if label is None: label = 'trace %i' % (conf.ntrace + 1) conf.set_trace_label(label, delay_draw=True) needs_relabel = False if labelfontsize is not None: conf.labelfont.set_size(labelfontsize) needs_relabel = True if titlefontsize is not None: conf.titlefont.set_size(titlefontsize) needs_relabel = True if legendfontsize is not None: conf.legendfont.set_size(legendfontsize) needs_relabel = True if conf.ntrace < len(conf.lines): conf.lines[conf.ntrace] = _lines else: conf.init_trace(conf.ntrace, 'black', 'solid') conf.lines.append(_lines) # now set plot limits: if not delay_draw: self.set_viewlimits() if refresh: conf.refresh_trace(conf.ntrace) needs_relabel = True if conf.show_legend and not delay_draw: conf.draw_legend() if needs_relabel and not delay_draw: conf.relabel() # axes style ('box' or 'open') conf.axes_style = 'box' if fullbox is not None and not fullbox: conf.axes_style = 'open' if axes_style in ('open', 'box', 'bottom'): conf.axes_style = axes_style conf.set_axes_style(delay_draw=delay_draw) if not delay_draw: self.draw() self.canvas.Refresh() conf.ntrace = conf.ntrace + 1 # print("# oplot done") return _lines def plot_many(self, datalist, side='left', title=None, xlabel=None, ylabel=None, **kws): """ plot many traces at once, taking a list of (x, y) pairs """ def unpack_tracedata(tdat, **kws): if (isinstance(tdat, dict) and 'xdata' in tdat and 'ydata' in tdat): xdata = tdat.pop('xdata') ydata = tdat.pop('ydata') out = kws out.update(tdat) elif isinstance(tdat, (list, tuple)): out = kws xdata = tdat[0] ydata = tdat[1] return (xdata, ydata, out) opts = dict(side=side, title=title, xlabel=xlabel, ylabel=ylabel, delay_draw=True) opts.update(kws) x0, y0, opts = unpack_tracedata(datalist[0], **opts) self.plot(x0, y0, **opts) for dat in datalist[1:]: x, y, opts = unpack_tracedata(dat, delay_draw=True) self.oplot(x, y, **opts) conf = self.conf if conf.show_legend: conf.draw_legend() conf.relabel() self.draw() self.canvas.Refresh() def add_text(self, text, x, y, side='left', size=None, rotation=None, ha='left', va='center', family=None, **kws): """add text at supplied x, y position """ axes = self.axes if side == 'right': axes = self.get_right_axes() dynamic_size = False if size is None: size = self.conf.legendfont.get_size() dynamic_size = True t = axes.text(x, y, text, ha=ha, va=va, size=size, rotation=rotation, family=family, **kws) self.conf.added_texts.append((dynamic_size, t)) self.draw() def add_arrow(self, x1, y1, x2, y2, side='left', shape='full', color='black', width=0.01, head_width=0.03, overhang=0, **kws): """add arrow supplied x, y position""" dx, dy = x2 - x1, y2 - y1 axes = self.axes if side == 'right': axes = self.get_right_axes() axes.arrow(x1, y1, dx, dy, shape=shape, length_includes_head=True, fc=color, edgecolor=color, width=width, head_width=head_width, overhang=overhang, **kws) self.draw() def scatterplot(self, xdata, ydata, label=None, size=10, color=None, edgecolor=None, selectcolor=None, selectedge=None, xlabel=None, ylabel=None, y2label=None, xmin=None, xmax=None, ymin=None, ymax=None, viewpad=None, title=None, grid=None, callback=None, **kw): if xlabel is not None: self.set_xlabel(xlabel) if ylabel is not None: self.set_ylabel(ylabel) if y2label is not None: self.set_y2label(y2label) if title is not None: self.set_title(title) if grid is not None: self.conf.show_grid = grid if callback is not None: self.lasso_callback = callback self.conf.plot_type = 'scatter' self.cursor_mode = 'lasso' if color is not None: self.conf.scatter_normalcolor = color if edgecolor is not None: self.conf.scatter_normaledge = edgecolor if selectcolor is not None: self.conf.scatter_selectcolor = selectcolor if selectedge is not None: self.conf.scatter_selectedge = selectedge if viewpad is not None: conf.viewpad = viewpad axes = self.axes self.conf.user_limits[axes] = [xmin, xmax, ymin, ymax] self.conf.axes_traces = {axes: [0]} self.conf.set_trace_label('scatterplot') # self.conf.set_trace_datarange((min(xdata), max(xdata), # min(ydata), max(ydata))) self.conf.scatter_xdata = xdata self.conf.scatter_ydata = ydata self.axes.scatter(xdata, ydata, c=self.conf.scatter_normalcolor, edgecolors=self.conf.scatter_normaledge) if self.conf.show_grid: for i in axes.get_xgridlines() + axes.get_ygridlines(): i.set_color(self.conf.gridcolor) i.set_zorder(-30) axes.grid(True) else: axes.grid(False) xrange = max(xdata) - min(xdata) yrange = max(ydata) - min(ydata) xmin = min(xdata) - xrange / 25.0 xmax = max(xdata) + xrange / 25.0 ymin = min(ydata) - yrange / 25.0 ymax = max(ydata) + yrange / 25.0 axes.set_xlim((xmin, xmax), emit=True) axes.set_ylim((ymin, ymax), emit=True) self.set_viewlimits() self.draw() def lassoHandler(self, vertices): conf = self.conf if self.conf.plot_type == 'scatter': xd, yd = conf.scatter_xdata, conf.scatter_ydata sdat = list(zip(xd, yd)) oldmask = conf.scatter_mask try: self.axes.scatter(xd[where(oldmask)], yd[where(oldmask)], s=conf.scatter_size, c=conf.scatter_normalcolor, edgecolors=conf.scatter_normaledge) except IndexError: self.axes.scatter(xd, yd, s=conf.scatter_size, c=conf.scatter_normalcolor, edgecolors=conf.scatter_normaledge) mask = conf.scatter_mask = inside_poly(vertices, sdat) pts = nonzero(mask)[0] self.axes.scatter(xd[where(mask)], yd[where(mask)], s=conf.scatter_size, c=conf.scatter_selectcolor, edgecolors=conf.scatter_selectedge) else: xdata = self.axes.lines[0].get_xdata() ydata = self.axes.lines[0].get_ydata() sdat = [(x, y) for x, y in zip(xdata, ydata)] mask = inside_poly(vertices, sdat) pts = nonzero(mask)[0] self.lasso = None self.draw() # self.canvas.draw_idle() if (self.lasso_callback is not None and hasattr(self.lasso_callback, '__call__')): self.lasso_callback(data=sdat, selected=pts, mask=mask) def set_xylims(self, limits, axes=None, side='left'): "set user-defined limits and apply them" if axes is None: axes = self.axes if side == 'right': axes = self.get_right_axes() self.conf.user_limits[axes] = list(limits) self.unzoom_all() def set_viewlimits(self): """updates xy limits of a plot based on current data, user defined limits, and any zoom level """ self.conf.set_viewlimits() def get_viewlimits(self, axes=None): if axes is None: axes = self.axes xmin, xmax = axes.get_xlim() ymin, ymax = axes.get_ylim() return (xmin, xmax, ymin, ymax) def clear(self): """ clear plot """ for ax in self.fig.get_axes(): ax.cla() self.conf.ntrace = 0 self.conf.xlabel = '' self.conf.ylabel = '' self.conf.y2label = '' self.conf.title = '' self.conf.data_save = {} def reset_config(self): """reset configuration to defaults.""" self.conf.set_defaults() def unzoom(self, event=None, **kws): """ zoom out 1 level, or to full data range """ self.conf.unzoom(full=False) def unzoom_all(self, event=None): """ zoom out full data range """ self.conf.unzoom(full=True) def process_data(self, event=None, expr=None): if expr in self.conf.data_expressions: self.conf.data_expr = expr self.conf.process_data() self.draw() if expr is None: expr = '' if self.conf.data_deriv: if expr is None: expr = 'y' expr = "deriv(%s)" % expr self.write_message("plotting %s" % expr, panel=0) def toggle_deriv(self, evt=None, value=None): "toggle derivative of data" if value is None: self.conf.data_deriv = not self.conf.data_deriv expr = self.conf.data_expr or '' if self.conf.data_deriv: expr = "deriv(%s)" % expr self.write_message("plotting %s" % expr, panel=0) self.conf.process_data() def set_logscale(self, event=None, xscale='linear', yscale='linear', delay_draw=False): "set log or linear scale for x, y axis" self.conf.set_logscale(xscale=xscale, yscale=yscale, delay_draw=delay_draw) def toggle_legend(self, evt=None, show=None): "toggle legend display" if show is None: show = not self.conf.show_legend self.conf.show_legend = show self.conf.draw_legend() def toggle_grid(self, evt=None, show=None): "toggle grid display" if show is None: show = not self.conf.show_grid self.conf.enable_grid(show) def configure(self, event=None): """show configuration frame""" if self.win_config is not None: try: self.win_config.Raise() except: self.win_config = None if self.win_config is None: self.win_config = PlotConfigFrame( parent=self, config=self.conf, trace_color_callback=self.trace_color_callback) self.win_config.Raise() #### ## create GUI #### def BuildPanel(self): """ builds basic GUI panel and popup menu""" self.fig = Figure(self.figsize, dpi=self.dpi) # 1 axes for now self.gridspec = GridSpec(1, 1) self.axes = self.fig.add_subplot(self.gridspec[0], facecolor=self.conf.facecolor) self.canvas = FigureCanvas(self, -1, self.fig) self.printer.canvas = self.canvas self.set_bg(self.conf.framecolor) self.conf.canvas = self.canvas self.canvas.SetCursor(wxCursor(wx.CURSOR_CROSS)) self.canvas.mpl_connect("pick_event", self.__onPickEvent) # overwrite ScalarFormatter from ticker.py here: self.axes.xaxis.set_major_formatter(FuncFormatter(self.xformatter)) self.axes.yaxis.set_major_formatter(FuncFormatter(self.yformatter)) # This way of adding to sizer allows resizing sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.canvas, 2, wx.LEFT | wx.TOP | wx.BOTTOM | wx.EXPAND, 0) self.SetAutoLayout(True) self.autoset_margins() self.SetSizer(sizer) self.Fit() canvas_draw = self.canvas.draw def draw(*args, **kws): self.autoset_margins() canvas_draw(*args, **kws) self.canvas.draw = draw self.addCanvasEvents() def _updateCanvasDraw(self): """ Overload of the draw function that update axes position before each draw""" fn = self.canvas.draw def draw2(*a, **k): self._updateGridSpec() return fn(*a, **k) self.canvas.draw = draw2 def get_default_margins(self): """get default margins""" trans = self.fig.transFigure.inverted().transform # Static margins l, t, r, b = self.axesmargins (l, b), (r, t) = trans(((l, b), (r, t))) # Extent dl, dt, dr, db = 0, 0, 0, 0 for i, ax in enumerate(self.fig.get_axes()): (x0, y0), (x1, y1) = ax.get_position().get_points() try: (ox0, oy0), (ox1, oy1) = ax.get_tightbbox( self.canvas.get_renderer()).get_points() (ox0, oy0), (ox1, oy1) = trans(((ox0, oy0), (ox1, oy1))) dl = min(0.2, max(dl, (x0 - ox0))) dt = min(0.2, max(dt, (oy1 - y1))) dr = min(0.2, max(dr, (ox1 - x1))) db = min(0.2, max(db, (y0 - oy0))) except: pass return (l + dl, t + dt, r + dr, b + db) def autoset_margins(self): """auto-set margins left, bottom, right, top according to the specified margins (in pixels) and axes extent (taking into account labels, title, axis) """ if not self.conf.auto_margins: return # coordinates in px -> [0,1] in figure coordinates trans = self.fig.transFigure.inverted().transform # Static margins if not self.use_dates: self.conf.margins = l, t, r, b = self.get_default_margins() self.gridspec.update(left=l, top=1 - t, right=1 - r, bottom=b) # Axes positions update for ax in self.fig.get_axes(): try: ax.update_params() except ValueError: pass ax.set_position(ax.figbox) def draw(self): self.canvas.draw() def update_line(self, trace, xdata, ydata, side='left', draw=False, update_limits=True): """ update a single trace, for faster redraw """ x = self.conf.get_mpl_line(trace) x.set_data(xdata, ydata) # datarange = [xdata.min(), xdata.max(), ydata.min(), ydata.max()] # self.conf.set_trace_datarange(datarange, trace=trace) axes = self.axes if side == 'right': axes = self.get_right_axes() if update_limits: self.set_viewlimits() if draw: self.draw() def get_figure(self): return self.fig def __onPickEvent(self, event=None): """pick events""" legline = event.artist trace = self.conf.legend_map.get(legline, None) visible = True if trace is not None and self.conf.hidewith_legend: line, legline, legtext = trace visible = not line.get_visible() line.set_visible(visible) if visible: legline.set_zorder(10.00) legline.set_alpha(1.00) legtext.set_zorder(10.00) legtext.set_alpha(1.00) else: legline.set_alpha(0.50) legtext.set_alpha(0.50) #### ## GUI events #### def report_leftdown(self, event=None): if event is None: return ex, ey = event.x, event.y msg = '' try: x, y = self.axes.transData.inverted().transform((ex, ey)) except: x, y = event.xdata, event.ydata if x is not None and y is not None: msg = ("X,Y= %s, %s" % (self._xfmt, self._yfmt)) % (x, y) if len(self.fig.get_axes()) > 1: ax2 = self.fig.get_axes()[1] try: x2, y2 = ax2.transData.inverted().transform((ex, ey)) msg = "X,Y,Y2= %s, %s, %s" % (self._xfmt, self._yfmt, self._y2fmt) % (x, y, y2) except: pass nsbar = getattr(self, 'nstatusbar', 1) self.write_message(msg, panel=max(0, nsbar - 2)) if (self.cursor_callback is not None and hasattr(self.cursor_callback, '__call__')): self.cursor_callback(x=event.xdata, y=event.ydata)
class MegaPlotWindow(PlotWindow): """Specialized four-panel PlotWindow for displaying A, B, and C scans of a three-dimensional dataset""" def __init__(self, parent, data_file): self.parent = parent self.data_file = data_file self.controller = MegaPlotWindowController(self, data_file) module_logger.info("Successfully initialized MegaPlotWindow.") self.load_data() @property def axes(self): """Returns a tuple of all the view's axes""" return (self.ascan_axes, self.hbscan_axes, self.vbscan_axes, self.cscan_axes) def init_ui(self): """Creates the PlotWindow UI""" parent_x, parent_y = self.parent.GetPositionTuple() parent_w, parent_h = self.parent.GetSize() self.SetPosition((parent_x + parent_w + ui_defaults.widget_margin, ui_defaults.widget_margin)) self.main_panel = wx.Panel(self) self.main_panel_sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL) # Controls for specifying (x,y,z) position in 3D dataset self.ctrl_panel = wx.Panel(self.main_panel) self.ctrl_sizer = wx.BoxSizer(wx.HORIZONTAL) info_lbl = wx.StaticText(self.ctrl_panel, wx.ID_ANY, u"Coordinates In Data:", wx.DefaultPosition, wx.DefaultSize) self.ctrl_sizer.Add(info_lbl, ui_defaults.lbl_pct, ui_defaults.lblsizer_flags, ui_defaults.widget_margin) xpos_lbl = wx.StaticText(self.ctrl_panel, wx.ID_ANY, u"X Position", wx.DefaultPosition, wx.DefaultSize) self.ctrl_sizer.Add(xpos_lbl, ui_defaults.lbl_pct, ui_defaults.lblsizer_flags, ui_defaults.widget_margin) self.xpos_sc = wx.SpinCtrl(self.ctrl_panel, wx.ID_ANY, value="", min=0, max=self.controller.data.shape[1] - 1) self.Bind(wx.EVT_SPINCTRL, self.controller.on_xy_change, self.xpos_sc) self.ctrl_sizer.Add(self.xpos_sc, ui_defaults.ctrl_pct, ui_defaults.sizer_flags, ui_defaults.widget_margin) ypos_lbl = wx.StaticText(self.ctrl_panel, wx.ID_ANY, u"Y Position", wx.DefaultPosition, wx.DefaultSize) self.ctrl_sizer.Add(ypos_lbl, ui_defaults.lbl_pct, ui_defaults.lblsizer_flags, ui_defaults.widget_margin) self.ypos_sc = wx.SpinCtrl(self.ctrl_panel, wx.ID_ANY, value="", min=0, max=self.controller.data.shape[0] - 1) self.Bind(wx.EVT_SPINCTRL, self.controller.on_xy_change, self.ypos_sc) self.ctrl_sizer.Add(self.ypos_sc, ui_defaults.ctrl_pct, ui_defaults.sizer_flags, ui_defaults.widget_margin) self.slice_cb = wx.CheckBox(self.ctrl_panel, wx.ID_ANY, "Plot Z Index As C Scan", style=wx.ALIGN_RIGHT) self.slice_cb.SetToolTipString( u"Use the specified index in Z as the C Scan plot data") self.slice_cb.SetValue(True) self.ctrl_sizer.Add(self.slice_cb, ui_defaults.lbl_pct, ui_defaults.sizer_flags, ui_defaults.widget_margin) self.slice_sc = wx.SpinCtrl(self.ctrl_panel, wx.ID_ANY, value="", min=0, max=self.controller.data.shape[2] - 1) self.Bind(wx.EVT_SPINCTRL, self.controller.on_sliceidx_change, self.slice_sc) slice_lbl = wx.StaticText(self.ctrl_panel, wx.ID_ANY, u"Slice Index", wx.DefaultPosition, wx.DefaultSize) self.ctrl_sizer.Add(slice_lbl, ui_defaults.lbl_pct, ui_defaults.lblsizer_flags, ui_defaults.widget_margin) self.ctrl_sizer.Add(self.slice_sc, ui_defaults.ctrl_pct, ui_defaults.sizer_flags, ui_defaults.widget_margin) self.ctrl_panel.SetSizerAndFit(self.ctrl_sizer) self.main_panel_sizer.Add(self.ctrl_panel, ui_defaults.lbl_pct, ui_defaults.sizer_flags, ui_defaults.widget_margin) self.figure = Figure() self.canvas = FigureCanvas(self.main_panel, wx.ID_ANY, self.figure) self.ascan_axes = self.figure.add_subplot(221) self.vbscan_axes = self.figure.add_subplot(222) self.hbscan_axes = self.figure.add_subplot(223) self.cscan_axes = self.figure.add_subplot(224) self.cscan_cursor = Cursor(self.cscan_axes, useblit=True, color="#4F6581", alpha=0.5) self.figure.canvas.mpl_connect("button_press_event", self.controller.on_click) self.main_panel_sizer.Add(self.canvas, 1, ui_defaults.sizer_flags, 0) self.navtools_cb = wx.CheckBox(self.main_panel, wx.ID_ANY, "Use Plot Navigation Tools") self.navtools_cb.SetValue(self.controller.get_navtools_config()) self.navtools_cb.SetToolTipString("Check to use pan/zoom tools") self.Bind(wx.EVT_CHECKBOX, self.controller.on_check_navtools, self.navtools_cb) self.main_panel_sizer.Add(self.navtools_cb, ui_defaults.lbl_pct, ui_defaults.sizer_flags, ui_defaults.widget_margin) self.add_toolbar() self.SetIcon(self.parent.GetIcon()) self.main_panel.SetSizerAndFit(self.main_panel_sizer) self.sizer.Add(self.main_panel, 1, ui_defaults.sizer_flags, 0) self.SetSizerAndFit(self.sizer) def add_toolbar(self): """Creates the matplotlib toolbar (zoom, pan/scroll, etc.) for the plot""" self.toolbar = NavigationToolbar2Wx(self.canvas) self.toolbar.Realize() if wx.Platform == '__WXMAC__': self.SetToolBar(self.toolbar) else: tw, th = self.toolbar.GetSizeTuple() fw, fh = self.canvas.GetSizeTuple() self.toolbar.SetSize(wx.Size(fw, th)) self.main_panel_sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND, 0) self.toolbar.update() self.toggle_toolbar() def toggle_toolbar(self): """Enables / disables the navigation toolbar and sets cursors accordingly.""" if self.navtools_enabled(): self.canvas.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) else: self.canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS)) self.toolbar.Enable(self.navtools_enabled()) self.controller.set_navtools_config(self.navtools_enabled()) def init_plot_menu(self): """Creates the Plot menu""" self.plot_mnu = wx.Menu() self.labels_mnu = wx.Menu() # Titles and Labels plottitle_mnui = wx.MenuItem(self.labels_mnu, wx.ID_ANY, text="Set Plot Title", help="Set Plot Title") self.Bind(wx.EVT_MENU, self.controller.on_set_plottitle, id=plottitle_mnui.GetId()) self.labels_mnu.AppendItem(plottitle_mnui) xlbl_mnui = wx.MenuItem(self.labels_mnu, wx.ID_ANY, text="Set X Axis Label", help="Set X Axis Label") self.Bind(wx.EVT_MENU, self.controller.on_set_xlabel, id=xlbl_mnui.GetId()) self.labels_mnu.AppendItem(xlbl_mnui) ylbl_mnui = wx.MenuItem(self.labels_mnu, wx.ID_ANY, text="Set Y Axis Label", help="Set Y Axis Label") self.Bind(wx.EVT_MENU, self.controller.on_set_ylabel, id=ylbl_mnui.GetId()) self.labels_mnu.AppendItem(ylbl_mnui) cbarlbl_mnui = wx.MenuItem(self.labels_mnu, wx.ID_ANY, text='Set Colorbar Label', help='Set Colorbar Label') self.Bind(wx.EVT_MENU, self.controller.on_set_cbarlbl, id=cbarlbl_mnui.GetId()) self.labels_mnu.AppendItem(cbarlbl_mnui) self.plot_mnu.AppendMenu(wx.ID_ANY, "Title And Labels", self.labels_mnu) self.colormaps_mnu = wx.Menu() # Colormaps self.preview_cmaps_mnui = wx.MenuItem( self.colormaps_mnu, wx.ID_ANY, text='Preview Colormaps', help='Preview available colormaps') self.Bind(wx.EVT_MENU, self.controller.on_preview_cmaps, id=self.preview_cmaps_mnui.GetId()) self.colormaps_mnu.AppendItem(self.preview_cmaps_mnui) self.select_cmap_mnui = wx.MenuItem(self.colormaps_mnu, wx.ID_ANY, text='Select Colormap...', help='Selects colormap') self.Bind(wx.EVT_MENU, self.controller.on_select_cmap, id=self.select_cmap_mnui.GetId()) self.colormaps_mnu.AppendItem(self.select_cmap_mnui) self.create_cmap_mnui = wx.MenuItem(self.colormaps_mnu, wx.ID_ANY, text='Create Colormap...', help='Create or edit a colormap') self.colormaps_mnu.AppendItem(self.create_cmap_mnui) self.Bind(wx.EVT_MENU, self.controller.on_create_cmap, id=self.create_cmap_mnui.GetId()) self.plot_mnu.AppendMenu(wx.ID_ANY, "Colormaps", self.colormaps_mnu) self.show_colorbar_mnui = wx.MenuItem( self.plot_mnu, wx.ID_ANY, text="Show Colorbar", help="Show color scale in image plot", kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, self.controller.on_toggle_colorbar, id=self.show_colorbar_mnui.GetId()) self.plot_mnu.AppendItem(self.show_colorbar_mnui) self.show_colorbar_mnui.Check(self.controller.get_colorbar_config()) self.plot_conventional_bscans_mnui = wx.MenuItem( self.plot_mnu, wx.ID_ANY, text="Plot Conventional B-scans", help="Plot conventional 2D B-scans", kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, self.controller.on_change_bscans, id=self.plot_conventional_bscans_mnui.GetId()) self.plot_mnu.AppendItem(self.plot_conventional_bscans_mnui) self.plot_conventional_bscans_mnui.Check( self.controller.conventional_bscans) gridtoggle_mnui = wx.MenuItem(self.plot_mnu, wx.ID_ANY, text="Toggle Grid", help="Turns grid on or off") self.plot_mnu.AppendItem(gridtoggle_mnui) self.Bind(wx.EVT_MENU, self.controller.on_toggle_grid, id=gridtoggle_mnui.GetId()) self.menubar.Append(self.plot_mnu, "&Plot") def init_specific_ops_menu(self): """Creates any plot-specific Operations menu items""" self.setcscan_mnui = wx.MenuItem( self.ops_mnu, wx.ID_ANY, text="Define C Scan", help="Specify function to generate C Scan") self.Bind(wx.EVT_MENU, self.controller.on_define_cscan, id=self.setcscan_mnui.GetId()) self.ops_mnu.AppendItem(self.setcscan_mnui) self.rect_mnu = wx.Menu() # Rectification operations self.fullrect_mnui = wx.MenuItem(self.rect_mnu, wx.ID_ANY, text="Full", help="Full Rectification") self.Bind(wx.EVT_MENU, self.controller.on_rectify, id=self.fullrect_mnui.GetId()) self.rect_mnu.AppendItem(self.fullrect_mnui) self.ops_mnu.AppendMenu(wx.ID_ANY, 'Rectify', self.rect_mnu) self.gate_mnu = wx.Menu() # Gates operations for gate in self.controller.gates: gate_name = self.controller.gates[gate][0] gate_desc = "Applies a {0} gate function to the data".format( gate_name) gate_mnui = wx.MenuItem(self.gate_mnu, id=gate, text=gate_name, help=gate_desc) self.gate_mnu.AppendItem(gate_mnui) self.Bind(wx.EVT_MENU, self.controller.on_apply_gate, id=gate_mnui.GetId()) self.ops_mnu.AppendMenu(wx.ID_ANY, 'Gates', self.gate_mnu) def navtools_enabled(self): """Returns True if plot navigation bar is enabled""" return self.navtools_cb.IsChecked() @property def plot_conventional_bscans(self): """True if the Bscan plots should be conventional 2D imgplots vs. the original Megaplot 1D""" return self.plot_conventional_bscans_mnui.IsChecked() @plot_conventional_bscans.setter def plot_conventional_bscans(self, on=True): """Sets the use of conventional Bscans or the original 1D Megaplot Bscans""" self.plot_conventional_bscans_mnui.Check(on) @property def plot_linear_bscans(self): """True if the Bscan plots should be the original 1D Megaplot plots""" return not self.plot_conventional_bscans
class InterpretationEditorFrame(wx.Frame): #########################Init Funcions############################# def __init__(self,parent): """Constructor""" #set parent and resolution self.parent = parent self.GUI_RESOLUTION=self.parent.GUI_RESOLUTION #call init of super class default_style = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.NO_FULL_REPAINT_ON_RESIZE | wx.WS_EX_CONTEXTHELP | wx.FRAME_EX_CONTEXTHELP wx.Frame.__init__(self, self.parent, title="Interpretation Editor version:%s"%CURRENT_VERSION,style=default_style, size=(675*self.GUI_RESOLUTION,425*self.GUI_RESOLUTION)) self.Bind(wx.EVT_CLOSE, self.on_close_edit_window) #setup wx help provider class to give help messages provider = wx.SimpleHelpProvider() wx.HelpProvider.Set(provider) self.helper = wx.ContextHelp(doNow=False) #make the Panel self.panel = wx.Panel(self,-1,size=(700*self.GUI_RESOLUTION,450*self.GUI_RESOLUTION)) #set icon self.SetIcon(self.parent.icon) # icon = wx.Icon() # icon_path = os.path.join(IMG_DIRECTORY, 'PmagPy.ico') # if os.path.exists(icon_path): # icon.CopyFromBitmap(wx.Bitmap(icon_path), wx.BITMAP_TYPE_ANY) # self.SetIcon(icon) self.specimens_list=self.parent.specimens self.current_fit_index = None self.search_query = "" self.font_type = self.parent.font_type #build UI and menu self.init_UI() self.create_menu() #update with stuff self.on_select_level_name(None) def init_UI(self): """ Builds User Interface for the interpretation Editor """ #set fonts FONT_WEIGHT=1 if sys.platform.startswith('win'): FONT_WEIGHT=-1 font1 = wx.Font(9+FONT_WEIGHT, wx.SWISS, wx.NORMAL, wx.NORMAL, False, self.font_type) font2 = wx.Font(12+FONT_WEIGHT, wx.SWISS, wx.NORMAL, wx.NORMAL, False, self.font_type) #if you're on mac do some funny stuff to make it look okay is_mac = False if sys.platform.startswith("darwin"): is_mac = True self.search_bar = wx.SearchCtrl(self.panel, size=(350*self.GUI_RESOLUTION,25) ,style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB | wx.TE_NOHIDESEL) self.Bind(wx.EVT_TEXT_ENTER, self.on_enter_search_bar,self.search_bar) self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.on_enter_search_bar,self.search_bar) self.search_bar.SetHelpText(dieh.search_help) # self.Bind(wx.EVT_TEXT, self.on_complete_search_bar,self.search_bar) #build logger self.logger = wx.ListCtrl(self.panel, -1, size=(100*self.GUI_RESOLUTION,475*self.GUI_RESOLUTION),style=wx.LC_REPORT) self.logger.SetFont(font1) self.logger.InsertColumn(0, 'specimen',width=75*self.GUI_RESOLUTION) self.logger.InsertColumn(1, 'fit name',width=65*self.GUI_RESOLUTION) self.logger.InsertColumn(2, 'max',width=55*self.GUI_RESOLUTION) self.logger.InsertColumn(3, 'min',width=55*self.GUI_RESOLUTION) self.logger.InsertColumn(4, 'n',width=25*self.GUI_RESOLUTION) self.logger.InsertColumn(5, 'fit type',width=60*self.GUI_RESOLUTION) self.logger.InsertColumn(6, 'dec',width=45*self.GUI_RESOLUTION) self.logger.InsertColumn(7, 'inc',width=45*self.GUI_RESOLUTION) self.logger.InsertColumn(8, 'mad',width=45*self.GUI_RESOLUTION) self.logger.InsertColumn(9, 'dang',width=45*self.GUI_RESOLUTION) self.logger.InsertColumn(10, 'a95',width=45*self.GUI_RESOLUTION) self.logger.InsertColumn(11, 'K',width=45*self.GUI_RESOLUTION) self.logger.InsertColumn(12, 'R',width=45*self.GUI_RESOLUTION) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnClick_listctrl, self.logger) self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK,self.OnRightClickListctrl,self.logger) self.logger.SetHelpText(dieh.logger_help) #set fit attributes boxsizers self.display_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "display options"), wx.HORIZONTAL) self.name_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "fit name/color"), wx.VERTICAL) self.bounds_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "fit bounds"), wx.VERTICAL) self.buttons_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY), wx.VERTICAL) #logger display selection box UPPER_LEVEL = self.parent.level_box.GetValue() if UPPER_LEVEL=='sample': name_choices = self.parent.samples if UPPER_LEVEL=='site': name_choices = self.parent.sites if UPPER_LEVEL=='location': name_choices = self.parent.locations if UPPER_LEVEL=='study': name_choices = ['this study'] self.level_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=UPPER_LEVEL, choices=['sample','site','location','study'], style=wx.CB_DROPDOWN|wx.TE_READONLY) self.Bind(wx.EVT_COMBOBOX, self.on_select_high_level,self.level_box) self.level_box.SetHelpText(dieh.level_box_help) self.level_names = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=self.parent.level_names.GetValue(), choices=name_choices, style=wx.CB_DROPDOWN|wx.TE_READONLY) self.Bind(wx.EVT_COMBOBOX, self.on_select_level_name,self.level_names) self.level_names.SetHelpText(dieh.level_names_help) #mean type and plot display boxes self.mean_type_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=self.parent.mean_type_box.GetValue(), choices=['Fisher','Fisher by polarity','None'], style=wx.CB_DROPDOWN|wx.TE_READONLY, name="high_type") self.Bind(wx.EVT_COMBOBOX, self.on_select_mean_type_box,self.mean_type_box) self.mean_type_box.SetHelpText(dieh.mean_type_help) self.mean_fit_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value=self.parent.mean_fit, choices=(['None','All'] + self.parent.fit_list), style=wx.CB_DROPDOWN|wx.TE_READONLY, name="high_type") self.Bind(wx.EVT_COMBOBOX, self.on_select_mean_fit_box,self.mean_fit_box) self.mean_fit_box.SetHelpText(dieh.mean_fit_help) #show box if UPPER_LEVEL == "study" or UPPER_LEVEL == "location": show_box_choices = ['specimens','samples','sites'] if UPPER_LEVEL == "site": show_box_choices = ['specimens','samples'] if UPPER_LEVEL == "sample": show_box_choices = ['specimens'] self.show_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), value='specimens', choices=show_box_choices, style=wx.CB_DROPDOWN|wx.TE_READONLY,name="high_elements") self.Bind(wx.EVT_COMBOBOX, self.on_select_show_box,self.show_box) self.show_box.SetHelpText(dieh.show_help) #coordinates box self.coordinates_box = wx.ComboBox(self.panel, -1, size=(110*self.GUI_RESOLUTION, 25), choices=self.parent.coordinate_list, value=self.parent.coordinates_box.GetValue(), style=wx.CB_DROPDOWN|wx.TE_READONLY, name="coordinates") self.Bind(wx.EVT_COMBOBOX, self.on_select_coordinates,self.coordinates_box) self.coordinates_box.SetHelpText(dieh.coordinates_box_help) #bounds select boxes self.tmin_box = wx.ComboBox(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), choices=[''] + self.parent.T_list, style=wx.CB_DROPDOWN|wx.TE_READONLY, name="lower bound") self.tmin_box.SetHelpText(dieh.tmin_box_help) self.tmax_box = wx.ComboBox(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), choices=[''] + self.parent.T_list, style=wx.CB_DROPDOWN|wx.TE_READONLY, name="upper bound") self.tmax_box.SetHelpText(dieh.tmax_box_help) #color box self.color_dict = self.parent.color_dict self.color_box = wx.ComboBox(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), choices=[''] + sorted(self.color_dict.keys()), style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER, name="color") self.Bind(wx.EVT_TEXT_ENTER, self.add_new_color, self.color_box) self.color_box.SetHelpText(dieh.color_box_help) #name box self.name_box = wx.TextCtrl(self.panel, -1, size=(80*self.GUI_RESOLUTION, 25), name="name") self.name_box.SetHelpText(dieh.name_box_help) #more mac stuff h_size_buttons,button_spacing = 25,5.5 if is_mac: h_size_buttons,button_spacing = 18,0. #buttons self.add_all_button = wx.Button(self.panel, id=-1, label='add new fit to all specimens',size=(160*self.GUI_RESOLUTION,h_size_buttons)) self.add_all_button.SetFont(font1) self.Bind(wx.EVT_BUTTON, self.add_fit_to_all, self.add_all_button) self.add_all_button.SetHelpText(dieh.add_all_help) self.add_fit_button = wx.Button(self.panel, id=-1, label='add fit to highlighted specimens',size=(160*self.GUI_RESOLUTION,h_size_buttons)) self.add_fit_button.SetFont(font1) self.Bind(wx.EVT_BUTTON, self.add_highlighted_fits, self.add_fit_button) self.add_fit_button.SetHelpText(dieh.add_fit_btn_help) self.delete_fit_button = wx.Button(self.panel, id=-1, label='delete highlighted fits',size=(160*self.GUI_RESOLUTION,h_size_buttons)) self.delete_fit_button.SetFont(font1) self.Bind(wx.EVT_BUTTON, self.delete_highlighted_fits, self.delete_fit_button) self.delete_fit_button.SetHelpText(dieh.delete_fit_btn_help) self.apply_changes_button = wx.Button(self.panel, id=-1, label='apply changes to highlighted fits',size=(160*self.GUI_RESOLUTION,h_size_buttons)) self.apply_changes_button.SetFont(font1) self.Bind(wx.EVT_BUTTON, self.apply_changes, self.apply_changes_button) self.apply_changes_button.SetHelpText(dieh.apply_changes_help) #windows display_window_0 = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION) display_window_1 = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION) display_window_2 = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION) name_window = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION) bounds_window = wx.GridSizer(2, 1, 10*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION) buttons1_window = wx.GridSizer(4, 1, 5*self.GUI_RESOLUTION, 19*self.GUI_RESOLUTION) display_window_0.AddMany( [(self.coordinates_box, wx.ALIGN_LEFT), (self.show_box, wx.ALIGN_LEFT)] ) display_window_1.AddMany( [(self.level_box, wx.ALIGN_LEFT), (self.level_names, wx.ALIGN_LEFT)] ) display_window_2.AddMany( [(self.mean_type_box, wx.ALIGN_LEFT), (self.mean_fit_box, wx.ALIGN_LEFT)] ) name_window.AddMany( [(self.name_box, wx.ALIGN_LEFT), (self.color_box, wx.ALIGN_LEFT)] ) bounds_window.AddMany( [(self.tmin_box, wx.ALIGN_LEFT), (self.tmax_box, wx.ALIGN_LEFT)] ) buttons1_window.AddMany( [(self.add_fit_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0), (self.add_all_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0), (self.delete_fit_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0), (self.apply_changes_button, wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, 0)]) self.display_sizer.Add(display_window_0, 1, wx.TOP|wx.EXPAND, 8) self.display_sizer.Add(display_window_1, 1, wx.TOP | wx.LEFT|wx.EXPAND, 8) self.display_sizer.Add(display_window_2, 1, wx.TOP | wx.LEFT|wx.EXPAND, 8) self.name_sizer.Add(name_window, 1, wx.TOP, 5.5) self.bounds_sizer.Add(bounds_window, 1, wx.TOP, 5.5) self.buttons_sizer.Add(buttons1_window, 1, wx.TOP, 0) #duplicate high levels plot self.fig = Figure((2.5*self.GUI_RESOLUTION, 2.5*self.GUI_RESOLUTION), dpi=100) self.canvas = FigCanvas(self.panel, -1, self.fig, ) self.toolbar = NavigationToolbar(self.canvas) self.toolbar.Hide() self.toolbar.zoom() self.high_EA_setting = "Zoom" self.canvas.Bind(wx.EVT_LEFT_DCLICK,self.on_equalarea_high_select) self.canvas.Bind(wx.EVT_MOTION,self.on_change_high_mouse_cursor) self.canvas.Bind(wx.EVT_MIDDLE_DOWN,self.home_high_equalarea) self.canvas.Bind(wx.EVT_RIGHT_DOWN,self.pan_zoom_high_equalarea) self.canvas.SetHelpText(dieh.eqarea_help) self.eqarea = self.fig.add_subplot(111) draw_net(self.eqarea) #Higher Level Statistics Box self.stats_sizer = wx.StaticBoxSizer( wx.StaticBox( self.panel, wx.ID_ANY,"mean statistics" ), wx.VERTICAL) for parameter in ['mean_type','dec','inc','alpha95','K','R','n_lines','n_planes']: COMMAND="self.%s_window=wx.TextCtrl(self.panel,style=wx.TE_CENTER|wx.TE_READONLY,size=(100*self.GUI_RESOLUTION,25))"%parameter exec(COMMAND) COMMAND="self.%s_window.SetBackgroundColour(wx.WHITE)"%parameter exec(COMMAND) COMMAND="self.%s_window.SetFont(font2)"%parameter exec(COMMAND) COMMAND="self.%s_outer_window = wx.GridSizer(1,2,5*self.GUI_RESOLUTION,15*self.GUI_RESOLUTION)"%parameter exec(COMMAND) COMMAND="""self.%s_outer_window.AddMany([ (wx.StaticText(self.panel,label='%s',style=wx.TE_CENTER),wx.EXPAND), (self.%s_window, wx.EXPAND)])"""%(parameter,parameter,parameter) exec(COMMAND) COMMAND="self.stats_sizer.Add(self.%s_outer_window, 1, wx.ALIGN_LEFT|wx.EXPAND, 0)"%parameter exec(COMMAND) self.switch_stats_button = wx.SpinButton(self.panel, id=wx.ID_ANY, style=wx.SP_HORIZONTAL|wx.SP_ARROW_KEYS|wx.SP_WRAP, name="change stats") self.Bind(wx.EVT_SPIN, self.on_select_stats_button,self.switch_stats_button) self.switch_stats_button.SetHelpText(dieh.switch_stats_btn_help) #construct panel hbox0 = wx.BoxSizer(wx.HORIZONTAL) hbox0.Add(self.name_sizer,flag=wx.ALIGN_TOP|wx.EXPAND,border=8) hbox0.Add(self.bounds_sizer,flag=wx.ALIGN_TOP|wx.EXPAND,border=8) vbox0 = wx.BoxSizer(wx.VERTICAL) vbox0.Add(hbox0,flag=wx.ALIGN_TOP,border=8) vbox0.Add(self.buttons_sizer,flag=wx.ALIGN_TOP,border=8) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox1.Add(vbox0,flag=wx.ALIGN_TOP,border=8) hbox1.Add(self.stats_sizer,flag=wx.ALIGN_TOP,border=8) hbox1.Add(self.switch_stats_button,flag=wx.ALIGN_TOP|wx.EXPAND,border=8) vbox1 = wx.BoxSizer(wx.VERTICAL) vbox1.Add(self.display_sizer,flag=wx.ALIGN_TOP,border=8) vbox1.Add(hbox1,flag=wx.ALIGN_TOP,border=8) vbox1.Add(self.canvas,proportion=1,flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,border=8) vbox2 = wx.BoxSizer(wx.VERTICAL) vbox2.Add(self.search_bar,proportion=.5,flag=wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.EXPAND, border=8) vbox2.Add(self.logger,proportion=1,flag=wx.ALIGN_LEFT|wx.EXPAND,border=8) hbox2 = wx.BoxSizer(wx.HORIZONTAL) hbox2.Add(vbox2,proportion=1,flag=wx.ALIGN_LEFT|wx.EXPAND) hbox2.Add(vbox1,flag=wx.ALIGN_TOP|wx.EXPAND) self.panel.SetSizerAndFit(hbox2) hbox2.Fit(self) def create_menu(self): menubar = wx.MenuBar() #-------------------------------------------------------------------- menu_file = wx.Menu() m_change_WD = menu_file.Append(-1, "Change Working Directory\tCtrl-W","") self.Bind(wx.EVT_MENU, self.parent.on_menu_change_working_directory, m_change_WD) m_make_MagIC_results_tables = menu_file.Append(-1, "&Save MagIC pmag tables\tCtrl-Shift-S", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_make_MagIC_results_tables, m_make_MagIC_results_tables) submenu_save_plots = wx.Menu() m_save_high_level = submenu_save_plots.Append(-1, "&Save high level plot", "") self.Bind(wx.EVT_MENU, self.parent.on_save_high_level, m_save_high_level,"Eq") m_new_sub_plots = menu_file.AppendSubMenu(submenu_save_plots, "&Save plot") menu_file.AppendSeparator() m_exit = menu_file.Append(-1, "E&xit\tCtrl-Q", "Exit") self.Bind(wx.EVT_MENU, self.on_close_edit_window, m_exit) #-------------------------------------------------------------------- menu_Analysis = wx.Menu() submenu_criteria = wx.Menu() m_change_criteria_file = submenu_criteria.Append(-1, "&Change acceptance criteria", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_change_criteria, m_change_criteria_file) m_import_criteria_file = submenu_criteria.Append(-1, "&Import criteria file", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_criteria_file, m_import_criteria_file) m_new_sub = menu_Analysis.AppendSubMenu(submenu_criteria, "Acceptance criteria") m_import_LSQ = menu_Analysis.Append(-1, "&Import Interpretations from LSQ file\tCtrl-L", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_read_from_LSQ, m_import_LSQ) m_previous_interpretation = menu_Analysis.Append(-1, "&Import previous interpretations from a redo file\tCtrl-R", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_previous_interpretation, m_previous_interpretation) m_save_interpretation = menu_Analysis.Append(-1, "&Save current interpretations to a redo file\tCtrl-S", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_save_interpretation, m_save_interpretation) #-------------------------------------------------------------------- menu_Tools = wx.Menu() m_view_VGP = menu_Tools.Append(-1, "&View VGPs\tCtrl-Shift-V", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_view_vgps, m_view_VGP) #-------------------------------------------------------------------- menu_Help = wx.Menu() m_help = menu_Help.Append(-1, "&Usage and Tips\tCtrl-H", "") self.Bind(wx.EVT_MENU, self.on_menu_help, m_help) m_cookbook = menu_Help.Append(-1, "&PmagPy Cookbook\tCtrl-Shift-W", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_cookbook, m_cookbook) m_docs = menu_Help.Append(-1, "&Open Docs\tCtrl-Shift-H", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_docs, m_docs) m_git = menu_Help.Append(-1, "&Github Page\tCtrl-Shift-G", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_git, m_git) m_debug = menu_Help.Append(-1, "&Open Debugger\tCtrl-Shift-D", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_debug, m_debug) #-------------------------------------------------------------------- menu_edit = wx.Menu() m_new = menu_edit.Append(-1, "&New interpretation\tCtrl-N", "") self.Bind(wx.EVT_MENU, self.parent.on_btn_add_fit, m_new) m_delete = menu_edit.Append(-1, "&Delete interpretation\tCtrl-D", "") self.Bind(wx.EVT_MENU, self.parent.on_btn_delete_fit, m_delete) m_next_interp = menu_edit.Append(-1, "&Next interpretation\tCtrl-Up", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_next_interp, m_next_interp) m_previous_interp = menu_edit.Append(-1, "&Previous interpretation\tCtrl-Down", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_prev_interp, m_previous_interp) m_next_specimen = menu_edit.Append(-1, "&Next Specimen\tCtrl-Right", "") self.Bind(wx.EVT_MENU, self.parent.on_next_button, m_next_specimen) m_previous_specimen = menu_edit.Append(-1, "&Previous Specimen\tCtrl-Left", "") self.Bind(wx.EVT_MENU, self.parent.on_prev_button, m_previous_specimen) menu_coordinates = wx.Menu() m_speci = menu_coordinates.Append(-1, "&Specimen Coordinates\tCtrl-P", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_change_speci_coord, m_speci) if "geographic" in self.parent.coordinate_list: m_geo = menu_coordinates.Append(-1, "&Geographic Coordinates\tCtrl-G", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_change_geo_coord, m_geo) if "tilt-corrected" in self.parent.coordinate_list: m_tilt = menu_coordinates.Append(-1, "&Tilt-Corrected Coordinates\tCtrl-T", "") self.Bind(wx.EVT_MENU, self.parent.on_menu_change_tilt_coord, m_tilt) m_coords = menu_edit.AppendSubMenu(menu_coordinates, "&Coordinate Systems") #-------------------------------------------------------------------- #self.menubar.Append(menu_preferences, "& Preferences") menubar.Append(menu_file, "&File") menubar.Append(menu_edit, "&Edit") menubar.Append(menu_Analysis, "&Analysis") menubar.Append(menu_Tools, "&Tools") menubar.Append(menu_Help, "&Help") self.SetMenuBar(menubar) ################################Logger Functions################################## def update_editor(self): """ updates the logger and plot on the interpretation editor window """ self.fit_list = [] self.search_choices = [] for specimen in self.specimens_list: if specimen not in self.parent.pmag_results_data['specimens']: continue self.fit_list += [(fit,specimen) for fit in self.parent.pmag_results_data['specimens'][specimen]] self.logger.DeleteAllItems() offset = 0 for i in range(len(self.fit_list)): i -= offset v = self.update_logger_entry(i) if v == "s": offset += 1 def update_logger_entry(self,i): """ helper function that given a index in this objects fit_list parameter inserts a entry at that index @param: i -> index in fit_list to find the (specimen_name,fit object) tup that determines all the data for this logger entry. """ if i < len(self.fit_list): tup = self.fit_list[i] elif i < self.logger.GetItemCount(): self.logger.DeleteItem(i) return else: return coordinate_system = self.parent.COORDINATE_SYSTEM fit = tup[0] pars = fit.get(coordinate_system) fmin,fmax,n,ftype,dec,inc,mad,dang,a95,sk,sr2 = "","","","","","","","","","","" specimen = tup[1] if coordinate_system=='geographic': block_key = 'zijdblock_geo' elif coordinate_system=='tilt-corrected': block_key = 'zijdblock_tilt' else: block_key = 'zijdblock' name = fit.name if pars == {} and self.parent.Data[specimen][block_key] != []: fit.put(specimen, coordinate_system, self.parent.get_PCA_parameters(specimen,fit,fit.tmin,fit.tmax,coordinate_system,fit.PCA_type)) pars = fit.get(coordinate_system) if self.parent.Data[specimen][block_key]==[]: spars = fit.get('specimen') fmin = fit.tmin fmax = fit.tmax if 'specimen_n' in list(spars.keys()): n = str(spars['specimen_n']) else: n = 'No Data' if 'calculation_type' in list(spars.keys()): ftype = spars['calculation_type'] else: ftype = 'No Data' dec = 'No Data' inc = 'No Data' mad = 'No Data' dang = 'No Data' a95 = 'No Data' sk = 'No Data' sr2 = 'No Data' else: if 'measurement_step_min' in list(pars.keys()): fmin = str(fit.tmin) else: fmin = "N/A" if 'measurement_step_max' in list(pars.keys()): fmax = str(fit.tmax) else: fmax = "N/A" if 'specimen_n' in list(pars.keys()): n = str(pars['specimen_n']) else: n = "N/A" if 'calculation_type' in list(pars.keys()): ftype = pars['calculation_type'] else: ftype = "N/A" if 'specimen_dec' in list(pars.keys()): dec = "%.1f"%pars['specimen_dec'] else: dec = "N/A" if 'specimen_inc' in list(pars.keys()): inc = "%.1f"%pars['specimen_inc'] else: inc = "N/A" if 'specimen_mad' in list(pars.keys()): mad = "%.1f"%pars['specimen_mad'] else: mad = "N/A" if 'specimen_dang' in list(pars.keys()): dang = "%.1f"%pars['specimen_dang'] else: dang = "N/A" if 'specimen_alpha95' in list(pars.keys()): a95 = "%.1f"%pars['specimen_alpha95'] else: a95 = "N/A" if 'specimen_k' in list(pars.keys()): sk = "%.1f"%pars['specimen_k'] else: sk = "N/A" if 'specimen_r' in list(pars.keys()): sr2 = "%.1f"%pars['specimen_r'] else: sr2 = "N/A" if self.search_query != "": entry = (specimen+name+fmin+fmax+n+ftype+dec+inc+mad+dang+a95+sk+sr2).replace(" ","").lower() if self.search_query not in entry: self.fit_list.pop(i) if i < self.logger.GetItemCount(): self.logger.DeleteItem(i) return "s" for e in (specimen,name,fmin,fmax,n,ftype,dec,inc,mad,dang,a95,sk,sr2): if e not in self.search_choices: self.search_choices.append(e) if i < self.logger.GetItemCount(): self.logger.DeleteItem(i) self.logger.InsertItem(i, str(specimen)) self.logger.SetItem(i, 1, name) self.logger.SetItem(i, 2, fmin) self.logger.SetItem(i, 3, fmax) self.logger.SetItem(i, 4, n) self.logger.SetItem(i, 5, ftype) self.logger.SetItem(i, 6, dec) self.logger.SetItem(i, 7, inc) self.logger.SetItem(i, 8, mad) self.logger.SetItem(i, 9, dang) self.logger.SetItem(i, 10, a95) self.logger.SetItem(i, 11, sk) self.logger.SetItem(i, 12, sr2) self.logger.SetItemBackgroundColour(i,"WHITE") a,b = False,False if fit in self.parent.bad_fits: self.logger.SetItemBackgroundColour(i,"red") b = True if self.parent.current_fit == fit: self.logger.SetItemBackgroundColour(i,"LIGHT BLUE") self.logger_focus(i) self.current_fit_index = i a = True if a and b: self.logger.SetItemBackgroundColour(i,"red") def update_current_fit_data(self): """ updates the current_fit of the parent Zeq_GUI entry in the case of it's data being changed """ if self.current_fit_index: self.update_logger_entry(self.current_fit_index) def change_selected(self,new_fit): """ updates passed in fit or index as current fit for the editor (does not affect parent), if no parameters are passed in it sets first fit as current @param: new_fit -> fit object to highlight as selected """ if len(self.fit_list)==0: return if self.search_query and self.parent.current_fit not in [x[0] for x in self.fit_list]: return if self.current_fit_index == None: if not self.parent.current_fit: return for i,(fit,specimen) in enumerate(self.fit_list): if fit == self.parent.current_fit: self.current_fit_index = i break i = 0 if isinstance(new_fit, Fit): for i, (fit,speci) in enumerate(self.fit_list): if fit == new_fit: break elif type(new_fit) is int: i = new_fit elif new_fit != None: print(('cannot select fit of type: ' + str(type(new_fit)))) if self.current_fit_index != None and \ len(self.fit_list) > 0 and \ self.fit_list[self.current_fit_index][0] in self.parent.bad_fits: self.logger.SetItemBackgroundColour(self.current_fit_index,"") else: self.logger.SetItemBackgroundColour(self.current_fit_index,"WHITE") self.current_fit_index = i if self.fit_list[self.current_fit_index][0] in self.parent.bad_fits: self.logger.SetItemBackgroundColour(self.current_fit_index,"red") else: self.logger.SetItemBackgroundColour(self.current_fit_index,"LIGHT BLUE") def logger_focus(self,i,focus_shift=16): """ focuses the logger on an index 12 entries below i @param: i -> index to focus on """ if self.logger.GetItemCount()-1 > i+focus_shift: i += focus_shift else: i = self.logger.GetItemCount()-1 self.logger.Focus(i) def OnClick_listctrl(self, event): """ Edits the logger and the Zeq_GUI parent object to select the fit that was newly selected by a double click @param: event -> wx.ListCtrlEvent that triggered this function """ i = event.GetIndex() if self.parent.current_fit == self.fit_list[i][0]: return self.parent.initialize_CART_rot(self.fit_list[i][1]) si = self.parent.specimens.index(self.fit_list[i][1]) self.parent.specimens_box.SetSelection(si) self.parent.select_specimen(self.fit_list[i][1]) self.change_selected(i) fi = 0 while (self.parent.s == self.fit_list[i][1] and i >= 0): i,fi = (i-1,fi+1) self.parent.update_fit_box() self.parent.fit_box.SetSelection(fi-1) self.parent.update_selection() def OnRightClickListctrl(self, event): """ Edits the logger and the Zeq_GUI parent object so that the selected interpretation is now marked as bad @param: event -> wx.ListCtrlEvent that triggered this function """ i = event.GetIndex() fit,spec = self.fit_list[i][0],self.fit_list[i][1] if fit in self.parent.bad_fits: if not self.parent.mark_fit_good(fit,spec=spec): return if i == self.current_fit_index: self.logger.SetItemBackgroundColour(i,"LIGHT BLUE") else: self.logger.SetItemBackgroundColour(i,"WHITE") else: if not self.parent.mark_fit_bad(fit): return if i == self.current_fit_index: self.logger.SetItemBackgroundColour(i,"red") else: self.logger.SetItemBackgroundColour(i,"red") self.parent.calculate_high_levels_data() self.parent.plot_high_levels_data() self.logger_focus(i) ##################################Search Bar Functions############################### def on_enter_search_bar(self,event): self.search_query = self.search_bar.GetValue().replace(" ","").lower() self.update_editor() # def on_complete_search_bar(self,event): # self.search_bar.AutoComplete(self.search_choices) ###################################ComboBox Functions################################ def update_bounds_boxes(self,B_list): self.tmin_box.SetItems(B_list) self.tmax_box.SetItems(B_list) def add_new_color(self,event): new_color = self.color_box.GetValue() if ':' in new_color: color_list = new_color.split(':') color_name = color_list[0] if len(color_list[1])==7 and color_list[1].startswith('#'): for c in color_list[1][1:]: if ord(c) < 48 or ord(c) > 70: self.parent.user_warning('invalid hex color must be of form #0F0F0F');return color_val = color_list[1] elif '(' in color_list[1] and ')' in color_list[1]: color_val = list(map(eval, tuple(color_list[1].strip('( )').split(',')))) for val in color_val: if val > 1 or val < 0: self.parent.user_warning("invalid RGB sequence"); return else: self.parent.user_warning("colors must be given as a valid hex color or rgb tuple"); return else: self.parent.user_warning("New colors must be passed in as $colorname:$colorval where $colorval is a valid hex color or rgb tuple"); return self.color_dict[color_name] = color_val #clear old box self.color_box.Clear() #update fit box self.color_box.SetItems([''] + sorted(self.color_dict.keys())) def on_select_coordinates(self,event): self.parent.coordinates_box.SetStringSelection(self.coordinates_box.GetStringSelection()) self.parent.onSelect_coordinates(event) def on_select_show_box(self,event): """ Changes the type of mean shown on the high levels mean plot so that single dots represent one of whatever the value of this box is. @param: event -> the wx.COMBOBOXEVENT that triggered this function """ self.parent.UPPER_LEVEL_SHOW=self.show_box.GetValue() self.parent.calculate_high_levels_data() self.parent.plot_high_levels_data() def on_select_high_level(self,event,called_by_parent=False): """ alters the possible entries in level_names combobox to give the user selections for which specimen interpretations to display in the logger @param: event -> the wx.COMBOBOXEVENT that triggered this function """ UPPER_LEVEL=self.level_box.GetValue() if UPPER_LEVEL=='sample': self.level_names.SetItems(self.parent.samples) self.level_names.SetStringSelection(self.parent.Data_hierarchy['sample_of_specimen'][self.parent.s]) if UPPER_LEVEL=='site': self.level_names.SetItems(self.parent.sites) self.level_names.SetStringSelection(self.parent.Data_hierarchy['site_of_specimen'][self.parent.s]) if UPPER_LEVEL=='location': self.level_names.SetItems(self.parent.locations) self.level_names.SetStringSelection(self.parent.Data_hierarchy['location_of_specimen'][self.parent.s]) if UPPER_LEVEL=='study': self.level_names.SetItems(['this study']) self.level_names.SetStringSelection('this study') if not called_by_parent: self.parent.level_box.SetStringSelection(UPPER_LEVEL) self.parent.onSelect_high_level(event,True) self.on_select_level_name(event) def on_select_level_name(self,event,called_by_parent=False): """ change this objects specimens_list to control which specimen interpretatoins are displayed in this objects logger @param: event -> the wx.ComboBoxEvent that triggered this function """ high_level_name=str(self.level_names.GetValue()) if self.level_box.GetValue()=='sample': self.specimens_list=self.parent.Data_hierarchy['samples'][high_level_name]['specimens'] elif self.level_box.GetValue()=='site': self.specimens_list=self.parent.Data_hierarchy['sites'][high_level_name]['specimens'] elif self.level_box.GetValue()=='location': self.specimens_list=self.parent.Data_hierarchy['locations'][high_level_name]['specimens'] elif self.level_box.GetValue()=='study': self.specimens_list=self.parent.Data_hierarchy['study']['this study']['specimens'] if not called_by_parent: self.parent.level_names.SetStringSelection(high_level_name) self.parent.onSelect_level_name(event,True) self.specimens_list.sort(key=spec_key_func) self.update_editor() def on_select_mean_type_box(self, event): """ set parent Zeq_GUI to reflect change in this box and change the @param: event -> the wx.ComboBoxEvent that triggered this function """ new_mean_type = self.mean_type_box.GetValue() if new_mean_type == "None": self.parent.clear_high_level_pars() self.parent.mean_type_box.SetStringSelection(new_mean_type) self.parent.onSelect_mean_type_box(event) def on_select_mean_fit_box(self, event): """ set parent Zeq_GUI to reflect the change in this box then replot the high level means plot @param: event -> the wx.COMBOBOXEVENT that triggered this function """ new_mean_fit = self.mean_fit_box.GetValue() self.parent.mean_fit_box.SetStringSelection(new_mean_fit) self.parent.onSelect_mean_fit_box(event) ###################################Button Functions################################## def on_select_stats_button(self,event): """ """ i = self.switch_stats_button.GetValue() self.parent.switch_stats_button.SetValue(i) self.parent.update_high_level_stats() def add_highlighted_fits(self, evnet): """ adds a new interpretation to each specimen highlighted in logger if multiple interpretations are highlighted of the same specimen only one new interpretation is added @param: event -> the wx.ButtonEvent that triggered this function """ specimens = [] next_i = self.logger.GetNextSelected(-1) if next_i == -1: return while next_i != -1: fit,specimen = self.fit_list[next_i] if specimen in specimens: next_i = self.logger.GetNextSelected(next_i) continue else: specimens.append(specimen) next_i = self.logger.GetNextSelected(next_i) for specimen in specimens: self.add_fit_to_specimen(specimen) self.update_editor() self.parent.update_selection() def add_fit_to_all(self,event): for specimen in self.parent.specimens: self.add_fit_to_specimen(specimen) self.update_editor() self.parent.update_selection() def add_fit_to_specimen(self,specimen): if specimen not in self.parent.pmag_results_data['specimens']: self.parent.pmag_results_data['specimens'][specimen] = [] new_name = self.name_box.GetLineText(0) new_color = self.color_box.GetValue() new_tmin = self.tmin_box.GetValue() new_tmax = self.tmax_box.GetValue() if not new_name: next_fit = str(len(self.parent.pmag_results_data['specimens'][specimen]) + 1) while ("Fit " + next_fit) in [x.name for x in self.parent.pmag_results_data['specimens'][specimen]]: next_fit = str(int(next_fit) + 1) new_name = ("Fit " + next_fit) if not new_color: next_fit = str(len(self.parent.pmag_results_data['specimens'][specimen]) + 1) new_color = self.parent.colors[(int(next_fit)-1) % len(self.parent.colors)] else: new_color = self.color_dict[new_color] if not new_tmin: new_tmin = None if not new_tmax: new_tmax = None if new_name in [x.name for x in self.parent.pmag_results_data['specimens'][specimen]]: print(('-E- interpretation called ' + new_name + ' already exsists for specimen ' + specimen)) return self.parent.add_fit(specimen, new_name, new_tmin, new_tmax, color=new_color,suppress_warnings=True) def delete_highlighted_fits(self, event): """ iterates through all highlighted fits in the logger of this object and removes them from the logger and the Zeq_GUI parent object @param: event -> the wx.ButtonEvent that triggered this function """ next_i = -1 deleted_items = [] while True: next_i = self.logger.GetNextSelected(next_i) if next_i == -1: break deleted_items.append(next_i) deleted_items.sort(reverse=True) for item in deleted_items: self.delete_entry(index=item) self.parent.update_selection() def delete_entry(self, fit = None, index = None): """ deletes the single item from the logger of this object that corrisponds to either the passed in fit or index. Note this function mutaits the logger of this object if deleting more than one entry be sure to pass items to delete in from highest index to lowest or else odd things can happen. @param: fit -> Fit object to delete from this objects logger @param: index -> integer index of the entry to delete from this objects logger """ if type(index) == int and not fit: fit,specimen = self.fit_list[index] if fit and type(index) == int: for i, (f,s) in enumerate(self.fit_list): if fit == f: index,specimen = i,s break if index == self.current_fit_index: self.current_fit_index = None if fit not in self.parent.pmag_results_data['specimens'][specimen]: print(("cannot remove item (entry #: " + str(index) + ") as it doesn't exist, this is a dumb bug contact devs")) self.logger.DeleteItem(index) return self.parent.pmag_results_data['specimens'][specimen].remove(fit) del self.fit_list[index] self.logger.DeleteItem(index) def apply_changes(self, event): """ applies the changes in the various attribute boxes of this object to all highlighted fit objects in the logger, these changes are reflected both in this object and in the Zeq_GUI parent object. @param: event -> the wx.ButtonEvent that triggered this function """ new_name = self.name_box.GetLineText(0) new_color = self.color_box.GetValue() new_tmin = self.tmin_box.GetValue() new_tmax = self.tmax_box.GetValue() next_i = -1 changed_i = [] while True: next_i = self.logger.GetNextSelected(next_i) if next_i == -1: break specimen = self.fit_list[next_i][1] fit = self.fit_list[next_i][0] if new_name: if new_name not in [x.name for x in self.parent.pmag_results_data['specimens'][specimen]]: fit.name = new_name if new_color: fit.color = self.color_dict[new_color] #testing not_both = True if new_tmin and new_tmax: if fit == self.parent.current_fit: self.parent.tmin_box.SetStringSelection(new_tmin) self.parent.tmax_box.SetStringSelection(new_tmax) fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,new_tmin,new_tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type)) not_both = False if new_tmin and not_both: if fit == self.parent.current_fit: self.parent.tmin_box.SetStringSelection(new_tmin) fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,new_tmin,fit.tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type)) if new_tmax and not_both: if fit == self.parent.current_fit: self.parent.tmax_box.SetStringSelection(new_tmax) fit.put(specimen,self.parent.COORDINATE_SYSTEM, self.parent.get_PCA_parameters(specimen,fit,fit.tmin,new_tmax,self.parent.COORDINATE_SYSTEM,fit.PCA_type)) changed_i.append(next_i) offset = 0 for i in changed_i: i -= offset v = self.update_logger_entry(i) if v == "s": offset += 1 self.parent.update_selection() ###################################Canvas Functions################################## def scatter(self,*args,**kwargs): # args_corrected = self.eqarea.transAxes.transform(vstack(args).T) # x,y = args_corrected.T return self.eqarea.scatter(*args,**kwargs) def plot(self,*args,**kwargs): # args_corrected = self.eqarea.transAxes.transform(vstack(args).T) # x,y = args_corrected.T return self.eqarea.plot(*args,**kwargs) def write(self,text): return self.eqarea.text(-1.2,1.15,text,{'family':self.font_type, 'fontsize':10*self.GUI_RESOLUTION, 'style':'normal','va':'center', 'ha':'left' }) def draw_net(self): draw_net(self.eqarea) def draw(self): self.toolbar.home() self.eqarea.set_xlim(-1., 1.) self.eqarea.set_ylim(-1., 1.) self.eqarea.axes.set_aspect('equal') self.eqarea.axis('off') self.canvas.draw() def pan_zoom_high_equalarea(self,event): """ Uses the toolbar for the canvas to change the function from zoom to pan or pan to zoom @param: event -> the wx.MouseEvent that triggered this funciton """ if event.LeftIsDown() or event.ButtonDClick(): return elif self.high_EA_setting == "Zoom": self.high_EA_setting = "Pan" try: self.toolbar.pan('off') except TypeError: pass elif self.high_EA_setting == "Pan": self.high_EA_setting = "Zoom" try: self.toolbar.zoom() except TypeError: pass else: self.high_EA_setting = "Zoom" try: self.toolbar.zoom() except TypeError: pass def home_high_equalarea(self,event): """ returns high equal area to it's original position @param: event -> the wx.MouseEvent that triggered the call of this function @alters: toolbar setting """ self.toolbar.home() def on_change_high_mouse_cursor(self,event): """ If mouse is over data point making it selectable change the shape of the cursor @param: event -> the wx Mouseevent for that click """ if self.show_box.GetValue() != "specimens": return if not self.parent.high_EA_xdata or not self.parent.high_EA_ydata: return pos=event.GetPosition() width, height = self.canvas.get_width_height() pos[1] = height - pos[1] xpick_data,ypick_data = pos xdata_org = self.parent.high_EA_xdata ydata_org = self.parent.high_EA_ydata data_corrected = self.eqarea.transData.transform(vstack([xdata_org,ydata_org]).T) xdata,ydata = data_corrected.T xdata = list(map(float,xdata)) ydata = list(map(float,ydata)) e = 4e0 if self.high_EA_setting == "Zoom": self.canvas.SetCursor(wx.Cursor(wx.CURSOR_CROSS)) else: self.canvas.SetCursor(wx.Cursor(wx.CURSOR_ARROW)) for i,(x,y) in enumerate(zip(xdata,ydata)): if 0 < sqrt((x-xpick_data)**2. + (y-ypick_data)**2.) < e: self.canvas.SetCursor(wx.Cursor(wx.CURSOR_HAND)) break event.Skip() def on_equalarea_high_select(self,event): self.parent.on_equalarea_high_select(event,fig = self.eqarea, canvas = self.canvas) ###############################Menu Functions###################################### def on_menu_help(self,event): """ Toggles the GUI's help mode which allows user to click on any part of the dialog and get help @param: event -> wx.MenuEvent that triggers this function """ self.helper.BeginContextHelp(None) ###############################Window Functions###################################### def on_close_edit_window(self, event): """ the function that is triggered on the close of the interpretation editor window @param: event -> wx.WindowEvent that triggered this function """ self.parent.ie_open = False self.Destroy()
class main_gui(wx.Frame): '''Setting up the placement and ''' def __init__(self, parent, file_path): if args.debug: print('main_gui.__init__') self.args = args self.initialize_controls(parent) self.box_sizer.Add(self.panel1, 0, wx.EXPAND) ## Initialize GUI plot self.figure = Figure() self.canvas = FigureCanvas(self, -1, self.figure) self.box_sizer.Add(self.canvas, 1, wx.EXPAND) ## Default rectangle variable self.pressed = False ## Initialize bottom text bar self.box_sizer.Add(self.status_bar, 0, border=0, flag=0) self.status_bar.SetStatusText('Ready', 0) rect = self.status_bar.GetFieldRect(0) ## Set up names self.video_file = file_path ## Create a dialog box at the beginning if the video path is not a real file if self.args.video_file == None: openFileDialog = wx.FileDialog(self, "Open Video file", "", "", "Video files (*.*)|*.*", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) ## Closing program if Browse box is closed if openFileDialog.ShowModal() == wx.ID_CANCEL: print( '\nExiting Program. Must select a video from box or enter path into command line\n' ) raise SystemExit ## Setting video name from dialog box selection self.video_file = openFileDialog.GetPath() ## Passing individual inputs from GUI to a list self.update_names() self.input_names = [ 'x', 'y', 'w', 'h', 'check_frame', 'blank_0', 'blank_n', 'crop_0', 'crop_n', 'threshold', 'diameter', 'minmass', 'maxsize', 'ecc_low', 'ecc_high', 'vials', 'window', 'pixel_to_cm', 'frame_rate', 'vial_id_vars', 'outlier_TB', 'outlier_LR', 'naming_convention', 'path_project', 'file_suffix', 'convert_to_cm_sec', 'trim_outliers' ] self.parameter_names = [ 'self.input_' + item for item in self.input_names ] self.input_values = [ ## int self.input_x, self.input_y, self.input_w, self.input_h, self.input_check_frame, self.input_blank_0, self.input_blank_n, self.input_crop_0, self.input_crop_n, self.input_threshold, self.input_diameter, self.input_minmass, self.input_maxsize, self.input_ecc_low, self.input_ecc_high, self.input_vials, self.input_window, self.input_pixel_to_cm, self.input_frame_rate, self.input_vial_id_vars, self.input_outlier_TB, self.input_outlier_LR, ## str self.input_naming_convention, self.input_path_project, self.input_file_suffix, ## bool self.input_convert_to_cm_sec, self.input_checkBox_trim_outliers ] ## Enable all buttons button_list = [ 'browse_video', 'reload_video', 'test_parameters', 'store_parameters' ] for button in button_list: exec('self.button_' + button + '.Enable(True)') ## Load video self.load_video() self.status_bar.SetStatusText("Ready...", 0) if args.debug: print('End of init') return def update_variables(self): '''Updates the detection variables''' if args.debug: print('main_gui.update_variables') variables = [] ## Including integers for item, jtem in zip(self.input_names[:22], self.input_values[:22]): # print('int',item,jtem) phrase = str(item + '=' + jtem.GetValue()) if args.debug: print(' ' + phrase) variables.append(phrase) ## Including strings - type I for item, jtem in zip(self.input_names[22:24], self.input_values[22:24]): # print('str-I',item,jtem) phrase = str(item + '="' + jtem.GetValue() + '"') if args.debug: print(' ' + phrase) variables.append(phrase) ## Including strings - type II for item, jtem in zip(self.input_names[24:25], self.input_values[24:25]): # print('str-II',item,jtem) phrase = str(item + '="' + str(jtem) + '"') if args.debug: print(phrase) variables.append(phrase) ## Including booleans for item, jtem in zip(self.input_names[25:], self.input_values[25:]): # print('bool',item,jtem) phrase = str(item + '=%s' % str(jtem.GetValue())) if args.debug: print(' ' + phrase) variables.append(phrase) return variables def load_video(self): '''Function for loading the video when the respective button is pressed''' if args.debug: print('main_gui.load_video') ## Set up self.status_bar.SetStatusText("Loading video", 0) self.figure.clear() self.axes = [ self.figure.add_subplot(111), ] ## Confirm file is a path, or folder has specified suffix status = self.check_specified_video() if status: print("Loading:", self.video_file) self.update_names() for item in self.input_values[:4]: item.SetEditable(True) item.Enable(True) self.checkBox_fixed_ROI.Enable(True) self.input_convert_to_cm_sec.Enable(True) ## Busy cursor while the detector object is called and initialized wx.BeginBusyCursor() try: vars = self.update_variables() self.detector = detector(self.video_file, gui=True, variables=vars) self.axes[0].imshow(self.detector.image_stack[0]) self.figure.canvas.draw() finally: wx.EndBusyCursor() ## Setting mechanism for drawing the ROI rectangle self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) self.canvas.mpl_connect('button_press_event', self.draw_rectangle) self.canvas.mpl_connect('button_release_event', self.on_release) self.canvas.mpl_connect('motion_notify_event', self.on_motion) self.rect = Rectangle((0, 0), 1, 1, fill=False, ec='r') self.axes[0].add_patch(self.rect) ## Auto-set GUI parameters from the video self.input_blank_0.SetValue('0') self.input_blank_n.SetValue(str(self.detector.n_frames)) self.input_crop_0.SetValue('0') self.input_crop_n.SetValue(str(self.detector.n_frames)) self.input_check_frame.SetValue('0') self.input_ecc_low.SetValue('0') self.input_ecc_high.SetValue('1') self.input_ecc_high.SetValue('1') self.input_path_project.SetValue(self.folder) self.input_naming_convention.SetValue(self.name) self.input_vial_id_vars.SetValue( str(len(self.input_naming_convention.GetValue().split('_')))) ## Display the 0th and frame corresponding with (most likely) t = 2 seconds try: self.input_frame_rate = int(self.input_frame_rate.GetValue()) except: pass if self.detector.n_frames < self.input_frame_rate * 2: self.input_check_frame.SetValue(str(self.detector.n_frames)) ## Try to make the local linear regression window size 2 seconds, but if not then 35% of the frames in the video if self.detector.n_frames < self.input_frame_rate * 2: self.input_window.SetValue( str(int(len(self.detector.image_stack) * .35))) else: self.input_window.SetValue(str(int(self.input_frame_rate) * 2)) ## Enable Test parameter button if disabled from prior testing self.button_test_parameters.Enable(True) self.x0, self.y0 = 0, 0 self.x1, self.y1 = self.detector.width, self.detector.height ## Display the first frame of the video in the GUI self.update_ROIdisp() self.canvas.draw() else: return def update_names(self): '''Updates the names of variables within the program. Generally variables set for naming files.''' if args.debug: print('main_gui.update_names') self.status_bar.SetStatusText("Updating file names...", 0) self.text_video_path.SetLabelText(self.video_file) self.folder, self.name = os.path.split(self.video_file) self.name, self.input_file_suffix = self.name.split('.') ## Naming files to be generated self.name_noext = os.path.join(self.folder, self.name) self.path_data = self.name_noext + '.raw.csv' self.path_filter = self.name_noext + '.filter.csv' self.path_plot = self.name_noext + '.diag.png' self.path_slope = self.name_noext + '.slopes.csv' if args.debug: print('name:', self.name_noext, "+ file suffixes") ## Set path_project default to the folder of the selected video file if self.input_path_project == '': self.input_path_project = self.folder return def check_specified_video(self): if args.debug: print('main_gui.check_specified_video') self.status_bar.SetStatusText("Checking specified video...", 0) ## Check file path and update names if os.path.isfile(self.video_file): self.button_reload_video.Enable(True) self.button_test_parameters.Enable(True) self.update_names() self.input_file_suffix = '.' + self.video_file.split( '/')[-1].split('.')[-1] return True else: self.video_file = "No or invalid file entered. Please change the file path" self.button_browse_video.Enable(True) return False ## Commands for drawing the ROI rectangle def ChangeCursor(self, event): '''Change cursor into crosshair type when enter the plot area''' self.canvas.SetCursor(wx.Cursor(wx.CURSOR_CROSS)) return def draw_rectangle(self, event): '''Draw ROI rectangle''' self.status_bar.SetStatusText( "Draw rectangle from upper-left to lower-right", 0) self.pressed = True if self.checkBox_fixed_ROI.Enabled: try: self.x0 = int(event.xdata) self.y0 = int(event.ydata) ## If the fixed_ROI box is checked, handle values differently if self.checkBox_fixed_ROI.GetValue(): self.x1 = self.x0 + int(eval(self.input_w.GetValue())) self.y1 = self.y0 + int(eval(self.input_h.GetValue())) self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.rect.set_xy((self.x0, self.y0)) self.canvas.draw() ## Set the values in the GUI and program to drawn rectangle self.input_x.SetValue(str(self.x0)) self.input_y.SetValue(str(self.y0)) self.input_h.SetValue(str(self.rect.get_height())) self.input_w.SetValue(str(self.rect.get_width())) except: pass return def on_release(self, event): '''When mouse is on plot and button is released, redraw ROI rectangle, update ROI values''' self.status_bar.SetStatusText("Specify the detector parameters...", 0) self.pressed = False if self.checkBox_fixed_ROI.Enabled: if self.checkBox_fixed_ROI.GetValue(): pass else: self.redraw_rect(event) self.update_ROIdisp() return def on_motion(self, event): '''If the mouse is on plot and if the mouse button is pressed, redraw ROI rectangle''' if self.pressed & self.checkBox_fixed_ROI.Enabled & ( not self.checkBox_fixed_ROI.GetValue()): # Redraw the rectangle self.redraw_rect(event) self.update_ROIdisp() return def redraw_rect(self, event): '''Draw the ROI rectangle overlay''' try: x1 = int(event.xdata) y1 = int(event.ydata) if any([self.x1 != x1, self.y1 != y1]): self.x1 = x1 self.y1 = y1 self.rect.set_xy((self.x0, self.y0)) self.rect.set_width(self.x1 - self.x0) self.rect.set_height(self.y1 - self.y0) self.canvas.draw() else: pass except: pass return def update_ROIdisp(self): '''Updates the ROI coordinates as the rectangle is drawn.''' self.input_x.SetValue(str(self.x0)) self.input_y.SetValue(str(self.y0)) self.input_h.SetValue(str(int(self.y1) - int(self.y0))) self.input_w.SetValue(str(int(self.x1) - int(self.x0))) return def OnButton_testParButton(self, event): '''Tests the entered parameters when the `Test parameters` button is pressed''' if args.debug: print('main_gui.OnButton_testParButton') self.status_bar.SetStatusText("Testing parameters...", 0) #Prep the parameters variables = self.update_variables() self.checkBox_fixed_ROI.Enable(False) ## Set up figure for plots self.figure.clear() self.axes = [ self.figure.add_subplot(231), self.figure.add_subplot(232), self.figure.add_subplot(233), self.figure.add_subplot(234), self.figure.add_subplot(235), self.figure.add_subplot(236) ] ## Busy cursor while the main function runs wx.BeginBusyCursor() try: variables = variables + ['debug=' + str(args.debug)] self.detector.parameter_testing(variables, self.axes) finally: wx.EndBusyCursor() ## Renders plots in the GUI self.figure.tight_layout() self.figure.canvas.draw() # Enable buttons and print statements once parameter testing is complete self.button_reload_video.Enable(True) self.button_store_parameters.Enable(True) if args.debug: print('Parameter testing complete') self.status_bar.SetStatusText( "Refine detector parameters by reloading the video, or finish optimization by pressing 'Save configuration'", 0) return def OnButton_strParButton(self, event): '''Runs the 'save_parameter' function for creating the configuration file''' if args.debug: print('main_gui.OnButton_strParButton') self.save_parameter() self.button_store_parameters.SetBackgroundColour( wx.Colour(241, 241, 241)) def set_config_file(self): '''Set path for the project folder''' if args.debug: print('main_gui.OnButton_strParButton') ## Figure out where to save configuration file if os.path.isdir(self.input_path_project): if not self.input_path_project.endswith('/'): self.input_path_project = self.input_path_project + '/' self.path_parameters = self.input_path_project + self.name + '.cfg' else: self.path_parameters = self.path_noext + '.cfg' return self.path_parameters def save_parameter(self): if args.debug: print('main_gui.save_parameter') ''' Save parameters as python list. New parameter sets appended to the config file. Each parameter sets come with a comment line, contain the datetime of analysis ''' variables = self.update_variables() try: self.input_path_project = self.input_path_project.GetValue() except: pass self.path_parameters = self.set_config_file() ## Printing output to configuration file print('Saving parameters to:', self.path_parameters) with open(self.path_parameters, 'w') as f: print('## FreeClimber ##', file=f) f.close() now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with open(self.path_parameters, 'a') as f: print('## Generated from file: ' + self.video_file, file=f) print('## @ ' + now, file=f) print('##', file=f) print('## Analysis parameters:', file=f) for item in variables: print(item, file=f) f.close() print("Configuration settings saved") return def OnButton_Browse(self, event): if args.debug: print('main_gui.OnButton_Browse') openFileDialog = wx.FileDialog(self, "Open Video file", "", "", "Video files (*.*)|*.*", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if openFileDialog.ShowModal() == wx.ID_CANCEL: pass else: self.video_file = openFileDialog.GetPath() self.update_names() self.load_video() self.figure.clear() return def OnButton_LoadVideo(self, event): '''Calls function to load the video when the `reload` button is pressed''' if args.debug: print('main_gui.OnButton_LoadVideo') self.load_video() return def initialize_sizers(self): '''Initializes the GUI window orientation''' if args.debug: print('main_gui.initialize_sizers') # Generated method, do not edit self.box_sizer = wx.BoxSizer(orient=wx.VERTICAL) self.SetSizer(self.box_sizer) return def initialize_controls(self, prnt): '''Initializes the GUI controls, for which there are many''' if args.debug: print('main_gui.initialize_controls') # Generated method, do not edit wx.Frame.__init__(self, id=wxID_text_title, name='', parent=prnt, pos=wx.Point(100, 30), size=wx.Size(950, 759), style=wx.DEFAULT_FRAME_STYLE, title='FreeClimber') self.SetClientSize(wx.Size(950, 737)) ###### ## Inputs for ROI Rectangle self.panel1 = wx.Panel(id=wxID_panel_1, name='panel1', parent=self, pos=wx.Point(0, 0), size=wx.Size(950, 231), style=wx.TAB_TRAVERSAL) ## Step 1 boxes self.text_step_1a = wx.StaticText(id=wxID_text_step_1a, label=u'Step 1a: Specify a video', name='text_step_1a', parent=self.panel1, pos=wx.Point(col1, 10), size=wx.Size(box_dimensions), style=wx.ALIGN_CENTER) ## Browse self.button_browse_video = wx.Button(id=wxID_browse_video, label=u'Browse...', name=u'button_browse_video', parent=self.panel1, pos=wx.Point(col1, 30), size=wx.Size(box_dimensions), style=0) self.button_browse_video.Bind(wx.EVT_BUTTON, self.OnButton_Browse, id=wxID_browse_video) self.text_step_1b = wx.StaticText(id=wxID_text_step_1b, label=u'Step 1b: Define options', name='text_step_1b', parent=self.panel1, pos=wx.Point(col1, 65), size=wx.Size(box_dimensions), style=wx.ALIGN_CENTER) ## Pixel to cm self.text_pixel_to_cm = wx.StaticText( id=wxID_text_pixel_to_cm, label=u"Pixels / cm:", name='text_pixel_to_cm', parent=self.panel1, pos=wx.Point(col1, 85), size=wx.Size(medium_box_dimensions), style=0) self.input_pixel_to_cm = wx.TextCtrl( id=wxID_input_pixel_to_cm, name=u'input_pixel_to_cm', parent=self.panel1, pos=wx.Point(col1 + 95, 85), size=wx.Size(medium_box_dimensions), style=0, value=u"1") ## Frame Rate self.text_frame_rate = wx.StaticText(id=wxID_frame_rate, label=u'Frames / sec:', name='text_frame_rate', parent=self.panel1, pos=wx.Point(col1, 115), size=wx.Size(box_dimensions), style=0) self.input_frame_rate = wx.TextCtrl( id=wxID_frame_rate, name=u'input_frame_rate', parent=self.panel1, pos=wx.Point(col1 + 95, 115), size=wx.Size(medium_box_dimensions), style=0, value='25') ## Check box to convert final slope to cm self.input_convert_to_cm_sec = wx.CheckBox( id=wxID_input_convert_to_cm_sec, label=u'Convert to cm / sec', name=u'input_convert_to_cm_sec', parent=self.panel1, pos=wx.Point(col1, 145), size=wx.Size(250, 22), style=0) ## Step 2 boxes self.text_step_2 = wx.StaticText(id=wxID_text_step_2, label=u'Step 2: Select ROI', name='text_step_2', parent=self.panel1, pos=wx.Point(col2, 10), size=wx.Size(box_dimensions), style=wx.ALIGN_LEFT) ## X self.text_x = wx.StaticText(id=wxID_text_x, label=u'x-pos.', name='text_x', parent=self.panel1, pos=wx.Point(col2, 30), size=wx.Size(medium_box_dimensions), style=wx.ALIGN_LEFT) self.input_x = wx.TextCtrl(id=wxID_input_x, name=u'input_x', parent=self.panel1, style=0, value=u'0', pos=wx.Point(col2 + 55, 30), size=wx.Size(medium_box_dimensions)) ## Y self.text_y = wx.StaticText(id=wxID_text_y, label=u'y-pos.', name='text_y', parent=self.panel1, pos=wx.Point(col2, 55), size=wx.Size(medium_box_dimensions), style=wx.ALIGN_LEFT) self.input_y = wx.TextCtrl(id=wxID_input_y, name=u'input_y', parent=self.panel1, pos=wx.Point(col2 + 55, 55), size=wx.Size(medium_box_dimensions), style=0, value=u'0') ## Width self.text_w = wx.StaticText(id=wxID_text_w, label=u'Width:', name='text_w', parent=self.panel1, pos=wx.Point(col2, 80), size=wx.Size(medium_box_dimensions), style=wx.ALIGN_LEFT) self.input_w = wx.TextCtrl(id=wxID_input_w, name=u'input_w', parent=self.panel1, pos=wx.Point(col2 + 55, 80), size=wx.Size(medium_box_dimensions), style=0, value=u'0') ## Height self.text_h = wx.StaticText(id=wxID_text_h, label=u'Height:', name='text_h', parent=self.panel1, pos=wx.Point(col2, 105), size=wx.Size(medium_box_dimensions), style=wx.ALIGN_LEFT) self.input_h = wx.TextCtrl(id=wxID_input_h, name=u'input_h', parent=self.panel1, pos=wx.Point(col2 + 55, 105), size=wx.Size(medium_box_dimensions), style=0, value=u'0') ## ROI rectangle stays same dimensions but can be redrawn. Not critical to keep self.checkBox_fixed_ROI = wx.CheckBox(id=wxID_check_box_ROI, label=u'Fixed ROI Size?', name=u'checkBox_fixed_ROI', parent=self.panel1, pos=wx.Point(col2, 145), size=wx.Size(250, 22), style=0) self.checkBox_fixed_ROI.SetValue(False) ###### ## Detection parameters self.text_step_3 = wx.StaticText( id=wxID_text_step_3, label=u'Step 3: Specify spot parameters', name='text_step_3', parent=self.panel1, pos=wx.Point(col3, 10), size=wx.Size(100, 22), style=wx.ALIGN_LEFT) ## Expected spot diameter self.text_diameter = wx.StaticText(id=wxID_text_diameter, label=u'Diameter:', name='text_diameter', parent=self.panel1, pos=wx.Point(col3, 30), size=wx.Size(medium_box_dimensions), style=0) self.input_diameter = wx.TextCtrl(id=wxID_input_diameter, name=u'input_diameter', parent=self.panel1, pos=wx.Point(col3 + 100, 30), size=wx.Size(medium_box_dimensions), style=0, value=u'7') ## Maximum spot diameter self.text_maxsize = wx.StaticText(id=wxID_text_maxsize, label=u'MaxDiameter:', name='text_maxsize', parent=self.panel1, pos=wx.Point(col3, 55), size=wx.Size(medium_box_dimensions), style=0) self.input_maxsize = wx.TextCtrl(id=wxID_input_maxsize, name=u'input_maxsize', parent=self.panel1, pos=wx.Point(col3 + 100, 55), size=wx.Size(medium_box_dimensions), style=0, value=u'11') ## Minimum spot 'mass' self.text_minmass = wx.StaticText(id=wxID_text_minmass, label=u'MinMass:', name='text_minmass', parent=self.panel1, pos=wx.Point(col3, 80), size=wx.Size(medium_box_dimensions), style=0) self.input_minmass = wx.TextCtrl(id=wxID_input_minmass, name=u'input_minmass', parent=self.panel1, pos=wx.Point(col3 + 100, 80), size=wx.Size(medium_box_dimensions), style=0, value=u'100') ## Spot threshold self.text_threshold = wx.StaticText( id=wxID_text_threshold, label=u'Threshold:', name='text_threshold', parent=self.panel1, pos=wx.Point(col3, 105), size=wx.Size(medium_box_dimensions), style=0) self.input_threshold = wx.TextCtrl(id=wxID_input_threshold, name=u'input_threshold', parent=self.panel1, pos=wx.Point(col3 + 100, 105), size=wx.Size(medium_box_dimensions), style=0, value=u'"auto"') ## Eccentricity range self.text_ecc = wx.StaticText(id=wxID_text_ecc, label=u'Ecc/circularity:', name='text_ecc', parent=self.panel1, pos=wx.Point(col3, 130), size=wx.Size(medium_box_dimensions), style=0) self.input_ecc_low = wx.TextCtrl(id=wxID_input_ecc_low, name=u'input_ecc_low', parent=self.panel1, pos=wx.Point(col3 + 100, 130), size=wx.Size(small_box_dimensions), style=0, value=u'0') self.input_ecc_high = wx.TextCtrl(id=wxID_input_ecc_high, name=u'input_ecc_high', parent=self.panel1, pos=wx.Point(col3 + 140, 130), size=wx.Size(small_box_dimensions), style=0, value=u'0') #### Step 4 arguments ## Check frames self.text_step_4 = wx.StaticText( id=wxID_text_step_4, label=u'Step 4: Additional parameters', name='text_step_4', parent=self.panel1, pos=wx.Point(col4, 10), size=wx.Size(100, 22), style=wx.ALIGN_LEFT) ## Background frames self.text_background_frames = wx.StaticText( id=wxID_text_background_frames, label=u'Background frames:', name='text_background_frames', parent=self.panel1, pos=wx.Point(col4, 30), size=wx.Size(medium_box_dimensions), style=0) self.input_blank_0 = wx.TextCtrl(id=wxID_input_blank_0, name=u'input_blank_0', parent=self.panel1, pos=wx.Point(col4 + 130, 30), size=wx.Size(small_box_dimensions), style=0, value=u'0') self.input_blank_n = wx.TextCtrl(id=wxID_input_blank_n, name=u'input_blank_n', parent=self.panel1, pos=wx.Point(col4 + 170, 30), size=wx.Size(small_box_dimensions), style=0, value=u'0') ## crop frames self.text_crop_frames = wx.StaticText( id=wxID_text_crop_frames, label=u'Crop frames:', name='text_crop_frames', parent=self.panel1, pos=wx.Point(col4, 55), size=wx.Size(medium_box_dimensions), style=0) self.input_crop_0 = wx.TextCtrl(id=wxID_input_crop_0, name=u'input_crop_0', parent=self.panel1, pos=wx.Point(col4 + 130, 55), size=wx.Size(small_box_dimensions), style=0, value=u'0') self.input_crop_n = wx.TextCtrl(id=wxID_input_crop_n, name=u'input_crop_n', parent=self.panel1, pos=wx.Point(col4 + 170, 55), size=wx.Size(small_box_dimensions), style=0, value=u'0') ## Check frames self.text_check_frames = wx.StaticText(id=wxID_text_check_frames, label=u'Check frame:', name='text_check_frames', parent=self.panel1, pos=wx.Point(col4, 80), size=wx.Size(115, 17), style=0) self.input_check_frame = wx.TextCtrl( id=wxID_input_check_frame, name=u'input_check_frame', parent=self.panel1, pos=wx.Point(col4 + 130, 80), size=wx.Size(small_box_dimensions), style=0, value=u'0') ## Vials self.text_vials = wx.StaticText(id=wxID_text_vials, label=u'Number of vials:', name='text_vials', parent=self.panel1, pos=wx.Point(col4, 105), size=wx.Size(133, 22), style=0) self.input_vials = wx.TextCtrl(id=wxID_input_vials, name=u'input_vials', parent=self.panel1, pos=wx.Point(col4 + 130, 105), size=wx.Size(small_box_dimensions), style=0, value=u'1') ## Window size self.text_window = wx.StaticText(id=wxID_text_window, label=u'Window size:', name='text_window', parent=self.panel1, pos=wx.Point(col4, 130), size=wx.Size(133, 22), style=0) self.input_window = wx.TextCtrl(id=wxID_input_window, name=u'input_window', parent=self.panel1, pos=wx.Point(col4 + 130, 130), size=wx.Size(small_box_dimensions), style=0, value='1') ## Edge trim self.input_checkBox_trim_outliers = wx.CheckBox( id=wxID_check_box_outlier, label=u'Trim outliers? (TB LR)', name=u'checkBox_outlier', parent=self.panel1, pos=wx.Point(col4, 155), size=wx.Size(250, 22), style=0) self.input_checkBox_trim_outliers.SetValue(False) self.input_outlier_TB = wx.TextCtrl(id=wxID_outlier_TB, name=u'input_outlier_TB', parent=self.panel1, pos=wx.Point(col4 + 130, 155), size=wx.Size(small_box_dimensions), style=0, value=u'1') self.input_outlier_LR = wx.TextCtrl(id=wxID_outlier_LR, name=u'input_outlier_LR', parent=self.panel1, pos=wx.Point(col4 + 170, 155), size=wx.Size(small_box_dimensions), style=0, value=u'3') self.text_step_5 = wx.StaticText(id=wxID_text_step_5, label=u'Step 5: Naming parameters', name='text_step_5', parent=self.panel1, pos=wx.Point(col5, 10), size=wx.Size(100, 22), style=wx.ALIGN_LEFT) ## Naming convention self.text_naming_convention = wx.StaticText( id=wxID_text_naming_convention, label=u"Naming pattern:", name='text_naming_convention', parent=self.panel1, pos=wx.Point(col5, 30), size=wx.Size(medium_box_dimensions), style=0) self.input_naming_convention = wx.TextCtrl( id=wxID_input_naming_convention, name=u'input_naming_convention', parent=self.panel1, pos=wx.Point(col5, 50), size=wx.Size(large_box_dimensions), style=0, value='') ## Variables self.text_vial_id_vars = wx.StaticText(id=wxID_text_vial_id_vars, label=u'Vial_ID variables:', name='text_vial_id_vars', parent=self.panel1, pos=wx.Point(col5, 80), size=wx.Size(133, 22), style=0) self.input_vial_id_vars = wx.TextCtrl( id=wxID_input_vial_id_vars, name=u'input_vial_id_vars', parent=self.panel1, pos=wx.Point(col5 + 130, 80), size=wx.Size(small_box_dimensions), style=0, value=u'2') self.text_path_project = wx.StaticText( id=wxID_text_path_project, label=u"Project path:", name='text_path_project', parent=self.panel1, pos=wx.Point(col4 - 45, 180), size=wx.Size(medium_box_dimensions), style=0) self.input_path_project = wx.TextCtrl(id=wxID_input_path_project, name=u'input_path_project', parent=self.panel1, pos=wx.Point(col4 + 40, 180), size=wx.Size(350, 22), style=0, value='') ## Bottom panels self.text_video_path = wx.StaticText(id=wxID_video_path, label='Video Path', name='text_video_path', parent=self.panel1, pos=wx.Point(10, 205), size=wx.Size(930, 22), style=0) self.text_video_path.SetBackgroundColour(wx.Colour(241, 241, 241)) self.button_test_parameters = wx.Button(id=wxID_test_parameters, label=u'Test parameters', name=u'button_test_parameters', parent=self.panel1, pos=wx.Point(col1, 180), size=wx.Size(140, 22), style=wx.ALIGN_CENTER) self.button_test_parameters.Bind(wx.EVT_BUTTON, self.OnButton_testParButton, id=wxID_test_parameters) self.button_reload_video = wx.Button(id=wxID_reload_video, label=u'Reload video', name=u'button_reload_video', parent=self.panel1, pos=wx.Point(col1 + 160 * 1, 180), size=wx.Size(140, 22), style=wx.ALIGN_CENTER) self.button_reload_video.Bind(wx.EVT_BUTTON, self.OnButton_LoadVideo, id=wxID_reload_video) self.button_store_parameters = wx.Button( id=wxID_store_parameters, label=u'Save configuration', name=u'button_store_parameters', parent=self.panel1, pos=wx.Point(col1 + 160 * 2, 180), size=wx.Size(140, 22), style=wx.ALIGN_CENTER) self.button_store_parameters.Bind(wx.EVT_BUTTON, self.OnButton_strParButton, id=wxID_store_parameters) ## Text box at the bottom self.status_bar = wx.StatusBar(id=wxID_status_bar, name='status_bar', parent=self, style=0) self.initialize_sizers() return
class CanvasPanel(wx.Panel): """ plot frame based on the Generic Frame class""" def __init__(self, parent, figure, *args, **kargs): wx.Panel.__init__(self, parent) # initialize the external data source figure.set_dpi(150) sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(sizer) self.figurecavas = FigureCanvas(self, -1, figure) sizer.Add(self.figurecavas, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL) self.figurecavas.mpl_connect('pick_event', self.OnPick) self.figurecavas.mpl_connect('button_press_event', self.OnButtonPress) self.figurecavas.mpl_connect('motion_notify_event', self.UpdateStatusBar) self.figurecavas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) self.figurecavas.mpl_connect('key_press_event', self.OnKeyPressed) # add interactive curve pick function # setup the tool bar self.toolbar = MyNavigationToolbar(self.figurecavas, True) self.toolbar.Realize() sizer.Add(self.toolbar, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL) self.text_x = wx.TextCtrl(self, wx.NewId(), "Value X:", size=(100, -1)) self.text_y = wx.TextCtrl(self, wx.NewId(), "Value Y:", size=(100, -1)) sizer.Add( self.text_x, 0, wx.TOP | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL) sizer.Add( self.text_y, 0, wx.TOP | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL) self.sizerinuse = sizer # bind resize event wx.EVT_SIZE(self, self.OnSize) # show the frame self.Show() def OnPick(self, event): print 'picked' def OnButtonPress(self, event): ''' button press event''' pass def OnKeyPressed(self, event): #print 'keypressed' pass def ResizeCanvas(self): pass ''' size = self.Parent.GetClientSize() self.figurecavas.resize(size[0],size[1]) self.figurecavas.draw() print self.figurecavas.Size print self.Size print self.Parent.Size ''' def OnSize(self, event): event.Skip() #wx.CallAfter(self.ResizeCanvas) def FigureUpdate(self, newfigure=None): if newfigure != None: newfigure.set_dpi(150) #self.figurecavas.figure.clear() self.figurecavas.figure = newfigure #FigureCanvas(self, -1, newfigure) self.figurecavas.draw() self.figurecavas.Update() self.Update() self.Refresh() def ChangeCursor(self, event): """ change the cursor within the canvas""" self.figurecavas.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE)) def UpdateStatusBar(self, event): """ update the statue bar for point position""" if event.inaxes: x, y = event.xdata, event.ydata self.text_x.SetValue(str(x)) self.text_y.SetValue(str(y)) #self.statusBar.SetStatusText(( "x= " + str(x) + # " y=" +str(y) ), # 0) def set_limits(self, limits): """ Set limits for the x and y axes, Operation based on current ax """ ax1 = self.figurecavas.figure.axes[0] if limits != None: if limits[0] != None and limits[0] != 'None': ax1.set_xlim(xmin=float(limits[0])) if limits[1] != None and limits[1] != 'None': ax1.set_xlim(xmax=float(limits[1])) if limits[2] != None and limits[2] != 'None': ax1.set_ylim(ymin=float(limits[2])) if limits[3] != None and limits[3] != 'None': ax1.set_ylim(ymax=float(limits[3])) return ax1 def set_labels(self, label): """ Set labels for the x and y axes """ ax = self.figurecavas.figure.axes[0] ax.set_xlabel(label[0]) ax.set_ylabel(label[1])
class Plotter(wx.Frame): def __init__(self, parent, ID, title): wx.Frame.__init__(self, parent, ID, title, wx.DefaultPosition, wx.Size(600, 600)) self.initGui() self.initMenu() self.Centre() self.Show() self.graphs = [] self.currentGraph = {} def initGui(self): # Create main panel panel = wx.Panel(self) panel.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) # Set sizers sizer0 = wx.BoxSizer(wx.VERTICAL) panel.SetSizer(sizer0) # Set gui elements sizer1 = wx.BoxSizer(wx.HORIZONTAL) loadData = wx.Button(panel, label='Load Graphs') loadData.Bind(wx.EVT_BUTTON, self.OnLoad) sizer1.Add(loadData, flag=wx.ALIGN_CENTER_VERTICAL) sizer1.Add((20, -1)) sizer1.Add(wx.StaticText(panel, label='Current Graph'), flag=wx.ALIGN_CENTER_VERTICAL) sizer1.Add((4, -1)) self.graphsList = wx.ComboBox(panel, choices=[], size=[300, 24], style=wx.CB_READONLY) self.graphsList.Bind(wx.EVT_COMBOBOX, self.OnSelectGraph) sizer1.Add(self.graphsList, proportion=1) sizer0.Add(sizer1, flag=wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.TOP | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=20) # Matplotlib item panelcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() facecolor = [channel / float(255) for channel in panelcolour] self.figure = Figure(figsize=(-1, -1), dpi=80, facecolor=facecolor, linewidth=1.0) self.figure.subplots_adjust(left=0.08, bottom=0.08, right=0.98, top=0.98) self.canvas = FigCanvas(panel, -1, self.figure) self.axes = self.figure.add_subplot(111) self.axes.set_xlabel('X-Axis') self.axes.set_ylabel('Y-Axis') self.axes.set_xlim(0.0, 1.0) self.axes.set_ylim(0.0, 1.0) matplotlib.rcParams.update({'font.size': 12}) self.axes.grid(False) sizer0.Add(self.canvas, 1, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=20) self.toolbar = NavigationToolbar(self.canvas) sizer0.Add(self.toolbar, 0, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.LEFT | wx.RIGHT, border=20) sizer0.Add((-1, 20)) self.statusBar = wx.StatusBar(self, -1) self.statusBar.SetFieldsCount(1) self.SetStatusBar(self.statusBar) self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar) self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) # Redefine close event self.Bind(wx.EVT_CLOSE, self.OnClose) def initMenu(self): menubar = wx.MenuBar() # File menu fileMenu = wx.Menu() openItem = wx.MenuItem(fileMenu, 11, '&Open\tCtrl+O') self.Bind(wx.EVT_MENU, self.OnOpen, id=11) saveItem = wx.MenuItem(fileMenu, 12, '&Save\tCtrl+S') self.Bind(wx.EVT_MENU, self.OnSave, id=12) exitItem = wx.MenuItem(fileMenu, 13, '&Exit\tAlt+F4') self.Bind(wx.EVT_MENU, self.OnClose, id=13) fileMenu.AppendItem(openItem) fileMenu.AppendItem(saveItem) fileMenu.AppendSeparator() fileMenu.AppendItem(exitItem) # Edit menu editMenu = wx.Menu() loadItem = wx.MenuItem(editMenu, 21, '&Load data') self.Bind(wx.EVT_MENU, self.OnLoad, id=21) clearItem = wx.MenuItem(editMenu, 22, '&Clear memory') self.Bind(wx.EVT_MENU, self.OnClear, id=22) editMenu.AppendItem(loadItem) editMenu.AppendItem(clearItem) # Help menu helpMenu = wx.Menu() aboutItem = wx.MenuItem(helpMenu, 31, '&About\tCtrl+A') #self.Bind(wx.EVT_MENU, self.OnAbout, id=31) helpItem = wx.MenuItem(helpMenu, 32, '&Help\tF1') #self.Bind(wx.EVT_MENU, self.OnHelp, id=32) helpMenu.AppendItem(aboutItem) helpMenu.AppendSeparator() helpMenu.AppendItem(helpItem) menubar.Append(fileMenu, '&File') menubar.Append(editMenu, '&Edit') menubar.Append(helpMenu, '&Help') self.SetMenuBar(menubar) def ChangeCursor(self, event): self.canvas.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE)) def UpdateStatusBar(self, event): if event.inaxes: x, y = event.xdata, event.ydata self.statusBar.SetStatusText( ("x = " + str(numpy.rint(x)) + "; y = " + str(numpy.rint(y))), 0) def OnLoad(self, event): # Load a dictionary with plots self.graphs = [] self.graphs.extend(stored.plots) # Update a list of graphs #self.graphsList.Enable() self.graphsList.Clear() for graph in self.graphs: self.graphsList.Append(graph['Title']) event.Skip() def OnClear(self, event): # Clear a dictionary with plots self.graphs = [] self.graphsList.Clear() event.Skip() def OnOpen(self, event): dlg = wx.FileDialog(self, message="Choose a file", defaultDir=os.getcwd(), defaultFile="", wildcard="*.dat", style=wx.OPEN | wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() dataFile = open(path, 'r') # Read data file # ... dlg.Destroy() def OnSave(self, event): if (bool(self.graphs) == True) and (bool(self.currentGraph) == True): dialog = wx.FileDialog(None, message="Save data as ...", defaultDir=os.getcwd(), defaultFile="", wildcard="*.dat", style=wx.SAVE | wx.OVERWRITE_PROMPT) if dialog.ShowModal() == wx.ID_OK: path = dialog.GetPath() # Create a file dataFile = open(path, 'w') # Fill in the content of a data file title = 'Title: ' + self.currentGraph['Title'] + '\n' type = 'Type: ' + self.currentGraph['Type'] + '\n' xTitle = 'xTitle: ' + self.currentGraph['xTitle'] + '\n' yTitle = 'yTitle: ' + self.currentGraph['yTitle'] + '\n' axesTitles = '{0:>10s}'.format('x') + '{0:>10s}'.format( 'y') + '{0:>10s}'.format('z') + '\n' dataFile.write(title) dataFile.write(type) dataFile.write(xTitle) dataFile.write(yTitle) dataFile.write(axesTitles) # Write x,y,z to a data file graphType = self.currentGraph['Type'] print(self.currentGraph['xData']) #print self.currentGraph['xData'].shape[0], self.currentGraph['yData'].shape[0], self.currentGraph['zData'].shape dim = self.currentGraph['xData'].shape[0] if (graphType == 'DistanceMap'): for i in range(dim): x = self.currentGraph['xData'][i] dataFile.write('{0:10.2f}'.format(x)) y = self.currentGraph['yData'][i] dataFile.write('{0:10.2f}'.format(y)) for j in range(dim): z = self.currentGraph['zData'][i][j] dataFile.write('{0:10.2f}'.format(z)) dataFile.write('\n') if (graphType == 'DifferenceMap'): pass if (graphType == 'DistancePlot'): pass if (graphType == 'AccessibilityPlot'): pass dataFile.close() dialog.Destroy() def OnClose(self, event): stored.mtsslplot = 0 self.Destroy() def OnSelectGraph(self, event): # Read on the selected graph title = self.graphsList.GetStringSelection() for graph in self.graphs: if (graph['Title'] == title): self.currentGraph = graph # Plot the selected graph self.plotGraph() event.Skip() def plotGraph(self): #print "Selecting graph" self.refreshFigure() # Read on the type of a graph graphType = self.currentGraph['Type'] if (graphType == 'DistanceMap'): self.plotDistanceMap() if (graphType == 'DifferenceMap'): self.plotDifferenceMap() if (graphType == 'DistancePlot'): self.plotDistancePlot() if (graphType == 'AccessibilityPlot'): self.plotAccessibilityPlot() if (graphType == 'DistanceDistribution'): #print "plotting distribution" self.plotDistanceDistribution() def refreshFigure(self): self.figure.clear() self.axes = self.figure.add_subplot(111) self.axes.set_xlabel('X-Axis') self.axes.set_ylabel('Y-Axis') self.axes.set_xlim(0.0, 1.0) self.axes.set_ylim(0.0, 1.0) matplotlib.rcParams.update({'font.size': 12}) def plotDistanceMap(self): # Read on x,y,z x = self.currentGraph['xData'] - 0.5 * numpy.ones( len(self.currentGraph['xData'])) y = self.currentGraph['yData'] - 0.5 * numpy.ones( len(self.currentGraph['yData'])) X, Y = numpy.meshgrid(x, y) Z = self.currentGraph['zData'] # Define colormap cmap = colors.ListedColormap(['blue', 'green', 'orange', 'red']) cmap.set_under('white') cmap.set_over('white') bounds = [1, 15, 50, 80, 100] norm = colors.BoundaryNorm(bounds, cmap.N) # Draw surface plot img = self.axes.pcolor(X, Y, Z, cmap=cmap, norm=norm) self.axes.set_xlim(x.min(), x.max()) self.axes.set_ylim(y.min(), y.max()) self.axes.set_xlabel(self.currentGraph['xTitle']) self.axes.set_ylabel(self.currentGraph['yTitle']) # Cosmetics #matplotlib.rcParams.update({'font.size': 12}) xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) self.axes.xaxis.set_minor_locator(xminorLocator) self.axes.yaxis.set_minor_locator(yminorLocator) self.axes.tick_params(direction='out', length=6, width=1) self.axes.tick_params(which='minor', direction='out', length=3, width=1) self.axes.xaxis.labelpad = 15 self.axes.yaxis.labelpad = 15 # Draw colorbar colorbar = self.figure.colorbar(img, boundaries=[0, 1, 15, 50, 80, 100], spacing='proportional', ticks=[15, 50, 80, 100], extend='both') colorbar.ax.set_xlabel('Angstrom') colorbar.ax.xaxis.set_label_position('top') colorbar.ax.xaxis.labelpad = 20 self.figure.tight_layout() self.canvas.draw() def plotDifferenceMap(self): # Read on x,y,z x = self.currentGraph['xData'] - 0.5 * numpy.ones( len(self.currentGraph['xData'])) y = self.currentGraph['yData'] - 0.5 * numpy.ones( len(self.currentGraph['yData'])) X, Y = numpy.meshgrid(x, y) Z = self.currentGraph['zData'] # Draw surface plot img = self.axes.pcolor(X, Y, Z, cmap='jet', vmin=0.0, vmax=numpy.amax(Z)) self.axes.set_xlim(x.min(), x.max()) self.axes.set_ylim(y.min(), y.max()) self.axes.set_xlabel(self.currentGraph['xTitle']) self.axes.set_ylabel(self.currentGraph['yTitle']) # Cosmetics #matplotlib.rcParams.update({'font.size': 18}) xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) self.axes.xaxis.set_minor_locator(xminorLocator) self.axes.yaxis.set_minor_locator(yminorLocator) self.axes.tick_params(direction='out', length=6, width=1) self.axes.tick_params(which='minor', direction='out', length=3, width=1) self.axes.xaxis.labelpad = 15 self.axes.yaxis.labelpad = 15 # Draw colorbar colorbar = self.figure.colorbar(img) colorbar.ax.set_xlabel('Angstrom') colorbar.ax.xaxis.set_label_position('top') colorbar.ax.xaxis.labelpad = 20 self.figure.tight_layout() self.canvas.draw() def plotDistancePlot(self): # Read on x,y x = self.currentGraph['xData'] y = self.currentGraph['yData'] # Remove data points with distances <= 0 index = numpy.zeros(1) for i in range(0, y.shape[0]): if (y[i] <= 0): index = numpy.append(index, i) index = numpy.delete(index, 0) Y = numpy.delete(y, index) X = numpy.delete(x, index) # Plot graph self.axes.plot(X, Y, linestyle='solid', linewidth=0.5, color='black', marker='o', markerfacecolor='white', markeredgecolor='black', markersize=6, markeredgewidth=1) Xmin = 0 Xmax = X.max() + 1 Ymin = 0 Ymax = Y.max() * 1.05 self.axes.set_xlim(Xmin, Xmax) self.axes.set_ylim(Ymin, Ymax) self.axes.set_xlabel(self.currentGraph['xTitle']) self.axes.set_ylabel(self.currentGraph['yTitle']) # Color the distance ranges self.axes.fill_between([Xmin, Xmax], 15, Ymin, color='blue', alpha=0.4) self.axes.fill_between([Xmin, Xmax], 50, 15, color='green', alpha=0.4) self.axes.fill_between([Xmin, Xmax], 80, 50, color='orange', alpha=0.4) self.axes.fill_between([Xmin, Xmax], Ymax, 80, color='red', alpha=0.4) # Cosmetics #matplotlib.rcParams.update({'font.size': 18}) xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) self.axes.xaxis.set_minor_locator(xminorLocator) self.axes.yaxis.set_minor_locator(yminorLocator) self.axes.tick_params(direction='out', length=6, width=1) self.axes.tick_params(which='minor', direction='out', length=3, width=1) self.axes.xaxis.labelpad = 15 self.axes.yaxis.labelpad = 15 self.figure.tight_layout() self.canvas.draw() def plotDistanceDistribution(self): # Read on x,y x = self.currentGraph['xData'] y = self.currentGraph['yData'] # Remove data points with distances <= 0 index = numpy.zeros(1) for i in range(0, y.shape[0]): if (y[i] <= 0): index = numpy.append(index, i) index = numpy.delete(index, 0) Y = numpy.delete(y, index) X = numpy.delete(x, index) # Plot graph self.axes.plot( X, Y, linestyle='solid', linewidth=0.5, color='red', #marker='.', markerfacecolor='white', markeredgecolor='black', markersize=6, markeredgewidth=1) Xmin = 0 Xmax = X.max() + 1 Ymin = 0 Ymax = Y.max() * 1.05 self.axes.set_xlim(Xmin, Xmax) self.axes.set_ylim(Ymin, Ymax) self.axes.set_xlabel(self.currentGraph['xTitle']) self.axes.set_ylabel(self.currentGraph['yTitle']) # Color the distance ranges #self.axes.fill_between([Xmin, Xmax], 15, Ymin, color='blue', alpha=0.4) #self.axes.fill_between([Xmin, Xmax], 50, 15, color='green', alpha=0.4) #self.axes.fill_between([Xmin, Xmax], 80, 50, color='orange', alpha=0.4) #self.axes.fill_between([Xmin, Xmax], Ymax, 80, color='red', alpha=0.4) # Cosmetics #matplotlib.rcParams.update({'font.size': 18}) xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) self.axes.xaxis.set_minor_locator(xminorLocator) self.axes.yaxis.set_minor_locator(yminorLocator) self.axes.tick_params(direction='out', length=6, width=1) self.axes.tick_params(which='minor', direction='out', length=3, width=1) self.axes.xaxis.labelpad = 15 self.axes.yaxis.labelpad = 15 self.figure.tight_layout() self.canvas.draw() def plotAccessibilityPlot(self): # Read on x,y x = self.currentGraph['xData'] y = self.currentGraph['yData'] X = x Y = y # Plot graph self.axes.plot(X, Y, linestyle='solid', linewidth=0.5, color='red', marker='.', markerfacecolor='white', markeredgecolor='black', markersize=6, markeredgewidth=1) Xmin = 0 Xmax = X.max() + 1 Ymin = 0 Ymax = Y.max() * 1.05 self.axes.set_xlim(Xmin, Xmax) self.axes.set_ylim(Ymin, Ymax) self.axes.set_xlabel(self.currentGraph['xTitle']) self.axes.set_ylabel(self.currentGraph['yTitle']) # Cosmetics #self.figure.set_size_inches(30,3) #matplotlib.rcParams.update({'font.size': 18}) xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) self.axes.xaxis.set_minor_locator(xminorLocator) self.axes.yaxis.set_minor_locator(yminorLocator) self.axes.tick_params(direction='out', length=6, width=1) self.axes.tick_params(which='minor', direction='out', length=3, width=1) self.axes.xaxis.labelpad = 15 self.axes.yaxis.labelpad = 15 self.figure.tight_layout() self.canvas.draw()
class PlotPanel(BasePanel): """ MatPlotlib 2D plot as a wx.Panel, suitable for embedding in any wx.Frame. This does provide a right-click popup menu for configuration, zooming, saving an image of the figure, and Ctrl-C for copy-image-to-clipboard. For more features, see PlotFrame, which embeds a PlotPanel and also provides, a Menu, StatusBar, and Printing support. """ def __init__(self, parent, size=(700, 450), dpi=150, axisbg=None, facecolor=None, fontsize=9, trace_color_callback=None, output_title='plot', with_data_process=True, **kws): self.trace_color_callback = trace_color_callback matplotlib.rc('axes', axisbelow=True) matplotlib.rc('lines', linewidth=2) matplotlib.rc('xtick', labelsize=fontsize, color='k') matplotlib.rc('ytick', labelsize=fontsize, color='k') matplotlib.rc('legend', fontsize=fontsize) matplotlib.rc('grid', linewidth=0.5, linestyle='-') BasePanel.__init__(self, parent, output_title=output_title, **kws) self.conf = PlotConfig(panel=self, with_data_process=with_data_process) self.data_range = {} self.win_config = None self.cursor_callback = None self.lasso_callback = None self.cursor_mode = 'zoom' self.parent = parent self.figsize = (size[0] * 1.0 / dpi, size[1] * 1.0 / dpi) self.dpi = dpi if facecolor is not None: self.conf.bgcolor = facecolor if axisbg is not None: self.conf.bgcolor = axisbg # axesmargins : margins in px left/top/right/bottom self.axesmargins = (30, 30, 30, 30) self.BuildPanel() self.conf.user_limits = {} # [None, None, None, None] self.data_range = {} self.conf.zoom_lims = [] self.conf.axes_traces = {} def plot(self, xdata, ydata, side='left', title=None, xlabel=None, ylabel=None, y2label=None, use_dates=False, **kws): """ plot (that is, create a new plot: clear, then oplot) """ allaxes = self.fig.get_axes() if len(allaxes) > 1: for ax in allaxes[1:]: if ax in self.data_range: self.data_range.pop(ax) self.fig.delaxes(ax) self.data_range = {} self.conf.zoom_lims = [] self.conf.axes_traces = {} self.clear() axes = self.axes if side == 'right': axes = self.get_right_axes() self.conf.ntrace = 0 self.conf.yscale = 'linear' self.conf.user_limits[axes] = [None, None, None, None] if xlabel is not None: self.set_xlabel(xlabel) if ylabel is not None: self.set_ylabel(ylabel) if y2label is not None: self.set_y2label(y2label) if title is not None: self.set_title(title) if use_dates is not None: self.use_dates = use_dates return self.oplot(xdata, ydata, side=side, **kws) def oplot(self, xdata, ydata, side='left', label=None, xlabel=None, ylabel=None, y2label=None, title=None, dy=None, ylog_scale=None, xlog_scale=None, grid=None, xmin=None, xmax=None, ymin=None, ymax=None, color=None, style=None, drawstyle=None, linewidth=2, marker=None, markersize=None, refresh=True, show_legend=None, legend_loc='best', legend_on=True, delay_draw=False, bgcolor=None, framecolor=None, gridcolor=None, labelfontsize=None, legendfontsize=None, fullbox=None, axes_style=None, zorder=None, **kws): """ basic plot method, overplotting any existing plot """ self.cursor_mode = 'zoom' conf = self.conf conf.plot_type = 'lineplot' axes = self.axes if side == 'right': axes = self.get_right_axes() # set y scale to log/linear if ylog_scale is not None: conf.yscale = {False: 'linear', True: 'log'}[ylog_scale] if xlog_scale is not None: conf.xscale = {False: 'linear', True: 'log'}[xlog_scale] axes.xaxis.set_major_formatter(FuncFormatter(self.xformatter)) if self.use_dates: xdata = [datetime.fromtimestamp(i) for i in xdata] xdata = dates.date2num(xdata) # axes.xaxis.set_major_locator(dates.AutoDateLocator()) if linewidth is None: linewidth = 2 if xlabel is not None: self.set_xlabel(xlabel) if ylabel is not None: self.set_ylabel(ylabel) if y2label is not None: self.set_y2label(y2label) if title is not None: self.set_title(title) if show_legend is not None: conf.set_legend_location(legend_loc, legend_on) conf.show_legend = show_legend if grid is not None: conf.show_grid = grid # set data range for this trace datarange = [min(xdata), max(xdata), min(ydata), max(ydata)] if axes not in conf.user_limits: conf.user_limits[axes] = [None, None, None, None] if xmin is not None: conf.user_limits[axes][0] = xmin if xmax is not None: conf.user_limits[axes][1] = xmax if ymin is not None: conf.user_limits[axes][2] = ymin if ymax is not None: conf.user_limits[axes][3] = ymax if axes == self.axes: axes.yaxis.set_major_formatter(FuncFormatter(self.yformatter)) else: axes.yaxis.set_major_formatter(FuncFormatter(self.y2formatter)) n = conf.ntrace if zorder is None: zorder = 5 * (n + 1) if axes not in conf.axes_traces: conf.axes_traces[axes] = [] conf.axes_traces[axes].append(n) if bgcolor is not None: conf.bgcolor = bgcolor axes.set_axis_bgcolor(bgcolor) if framecolor is not None: self.canvas.figure.set_facecolor(framecolor) conf.set_trace_zorder(zorder, delay_draw=True) if color: conf.set_trace_color(color, delay_draw=True) if style: conf.set_trace_style(style, delay_draw=True) if marker: conf.set_trace_marker(marker, delay_draw=True) if linewidth is not None: conf.set_trace_linewidth(linewidth, delay_draw=True) if markersize is not None: conf.set_trace_markersize(markersize, delay_draw=True) if drawstyle is not None: conf.set_trace_drawstyle(drawstyle, delay_draw=True) if gridcolor is not None: conf.gridcolor = gridcolor if dy is None: _lines = axes.plot(xdata, ydata, drawstyle=drawstyle, zorder=zorder) else: _lines = axes.errorbar(xdata, ydata, yerr=dy, zorder=zorder) if axes not in conf.data_save: conf.data_save[axes] = [] conf.data_save[axes].append((xdata, ydata)) if conf.show_grid and axes == self.axes: # I'm sure there's a better way... for i in axes.get_xgridlines() + axes.get_ygridlines(): i.set_color(conf.gridcolor) i.set_zorder(-100) axes.grid(True) else: axes.grid(False) if (self.conf.xscale == 'log' or self.conf.yscale == 'log'): self.set_logscale(xscale=self.conf.xscale, yscale=self.conf.yscale) if label is None: label = 'trace %i' % (conf.ntrace + 1) conf.set_trace_label(label, delay_draw=True) conf.set_trace_datarange(datarange) needs_relabel = False if labelfontsize is not None: conf.labelfont.set_size(labelfontsize) needs_relabel = True if legendfontsize is not None: conf.legendfont.set_size(legendfontsize) needs_relabel = True if n < len(conf.lines): conf.lines[n] = _lines else: conf._init_trace(n, 'black', 'solid') conf.lines.append(_lines) # now set plot limits: self.set_viewlimits() if refresh: conf.refresh_trace(conf.ntrace) needs_relabel = True if conf.show_legend and not delay_draw: conf.draw_legend() if needs_relabel and not delay_draw: conf.relabel() # axes style ('box' or 'open') conf.axes_style = 'box' if fullbox is not None and not fullbox: conf.axes_style = 'open' if axes_style in ('open', 'box', 'bottom'): conf.axes_style = axes_style conf.set_axes_style(delay_draw=delay_draw) if not delay_draw: self.draw() self.canvas.Refresh() conf.ntrace = conf.ntrace + 1 return _lines def plot_many(self, datalist, side='left', title=None, xlabel=None, ylabel=None, **kws): """ plot many traces at once, taking a list of (x, y) pairs """ def unpack_tracedata(tdat, **kws): if (isinstance(tdat, dict) and 'xdata' in tdat and 'ydata' in tdat): xdata = tdat.pop('xdata') ydata = tdat.pop('ydata') out = kws out.update(tdat) elif isinstance(tdat, (list, tuple)): out = kws xdata = tdat[0] ydata = tdat[1] return (xdata, ydata, out) opts = dict(side=side, title=title, xlabel=xlabel, ylabel=ylabel, delay_draw=True) opts.update(kws) x0, y0, opts = unpack_tracedata(datalist[0], **opts) self.plot(x0, y0, **opts) for dat in datalist[1:]: x, y, opts = unpack_tracedata(dat, delay_draw=True) self.oplot(x, y, **opts) conf = self.conf if conf.show_legend: conf.draw_legend() conf.relabel() self.draw() self.canvas.Refresh() def add_text(self, text, x, y, side='left', size=None, rotation=None, ha='left', va='center', family=None, **kws): """add text at supplied x, y position""" axes = self.axes if side == 'right': axes = self.get_right_axes() dynamic_size = False if size is None: size = self.conf.legendfont.get_size() dynamic_size = True t = axes.text(x, y, text, ha=ha, va=va, size=size, rotation=rotation, family=family, **kws) self.conf.added_texts.append((dynamic_size, t)) self.draw() def add_arrow(self, x1, y1, x2, y2, side='left', shape='full', color='black', width=0.01, head_width=0.03, overhang=0, **kws): """add arrow supplied x, y position""" dx, dy = x2 - x1, y2 - y1 axes = self.axes if side == 'right': axes = self.get_right_axes() axes.arrow(x1, y1, dx, dy, shape=shape, length_includes_head=True, fc=color, edgecolor=color, width=width, head_width=head_width, overhang=overhang, **kws) self.draw() def scatterplot(self, xdata, ydata, label=None, size=10, color=None, edgecolor=None, selectcolor=None, selectedge=None, xlabel=None, ylabel=None, y2label=None, xmin=None, xmax=None, ymin=None, ymax=None, title=None, grid=None, callback=None, **kw): if xlabel is not None: self.set_xlabel(xlabel) if ylabel is not None: self.set_ylabel(ylabel) if y2label is not None: self.set_y2label(y2label) if title is not None: self.set_title(title) if grid is not None: self.conf.show_grid = grid if callback is not None: self.lasso_callback = callback self.conf.plot_type = 'scatter' self.cursor_mode = 'lasso' if color is not None: self.conf.scatter_normalcolor = color if edgecolor is not None: self.conf.scatter_normaledge = edgecolor if selectcolor is not None: self.conf.scatter_selectcolor = selectcolor if selectedge is not None: self.conf.scatter_selectedge = selectedge axes = self.axes self.conf.user_limits[axes] = (xmin, xmax, ymin, ymax) self.conf.axes_traces = {axes: [0]} self.conf.set_trace_label('scatterplot') self.conf.set_trace_datarange( (min(xdata), max(xdata), min(ydata), max(ydata))) fcols = [to_rgba(self.conf.scatter_normalcolor) for x in xdata] ecols = [self.conf.scatter_normaledge] * len(xdata) self.conf.scatter_data = [(x, y) for x, y in zip(xdata, ydata)] self.conf.scatter_size = size self.conf.scatter_coll = CircleCollection( sizes=(size, ), facecolors=fcols, edgecolors=ecols, offsets=self.conf.scatter_data, transOffset=self.axes.transData) self.axes.add_collection(self.conf.scatter_coll) if self.conf.show_grid: for i in axes.get_xgridlines() + axes.get_ygridlines(): i.set_color(self.conf.gridcolor) i.set_zorder(-30) axes.grid(True) else: axes.grid(False) self.set_viewlimits() self.draw() def lassoHandler(self, vertices): conf = self.conf if self.conf.plot_type == 'scatter': fcols = conf.scatter_coll.get_facecolors() ecols = conf.scatter_coll.get_edgecolors() sdat = conf.scatter_data mask = inside_poly(vertices, sdat) pts = nonzero(mask)[0] self.conf.scatter_mask = mask for i in range(len(sdat)): if i in pts: ecols[i] = to_rgba(conf.scatter_selectedge) fcols[i] = to_rgba(conf.scatter_selectcolor) fcols[i][3] = 0.3 ecols[i][3] = 0.8 else: fcols[i] = to_rgba(conf.scatter_normalcolor) ecols[i] = to_rgba(conf.scatter_normaledge) else: xdata = self.axes.lines[0].get_xdata() ydata = self.axes.lines[0].get_ydata() sdat = [(x, y) for x, y in zip(xdata, ydata)] mask = inside_poly(vertices, sdat) # print mask pts = nonzero(mask)[0] self.lasso = None self.draw() # self.canvas.draw_idle() if (self.lasso_callback is not None and hasattr(self.lasso_callback, '__call__')): self.lasso_callback(data=sdat, selected=pts, mask=mask) def set_xylims(self, limits, axes=None, side='left'): "set user-defined limits and apply them" if axes is None: axes = self.axes if side == 'right': axes = self.get_right_axes() self.conf.user_limits[axes] = limits self.unzoom_all() def set_viewlimits(self): """updates xy limits of a plot based on current data, user defined limits, and any zoom level """ self.conf.set_viewlimits() def get_viewlimits(self, axes=None): if axes is None: axes = self.axes xmin, xmax = axes.get_xlim() ymin, ymax = axes.get_ylim() return (xmin, xmax, ymin, ymax) def clear(self): """ clear plot """ for ax in self.fig.get_axes(): ax.cla() self.conf.ntrace = 0 self.conf.xlabel = '' self.conf.ylabel = '' self.conf.y2label = '' self.conf.title = '' self.conf.data_save = {} def reset_config(self): """reset configuration to defaults.""" self.conf.set_defaults() def unzoom(self, event=None, **kws): """ zoom out 1 level, or to full data range """ self.conf.unzoom(full=False) def unzoom_all(self, event=None): """ zoom out full data range """ self.conf.unzoom(full=True) def process_data(self, event=None, expr=None): if expr in self.conf.data_expressions: self.conf.data_expr = expr self.conf.process_data() self.draw() if expr is None: expr = '' if self.conf.data_deriv: if expr is None: expr = 'y' expr = "deriv(%s)" % expr self.write_message("plotting %s" % expr, panel=0) def toggle_deriv(self, evt=None, value=None): "toggle derivative of data" if value is None: self.conf.data_deriv = not self.conf.data_deriv expr = self.conf.data_expr or '' if self.conf.data_deriv: expr = "deriv(%s)" % expr self.write_message("plotting %s" % expr, panel=0) self.conf.process_data() def set_logscale(self, event=None, xscale='linear', yscale='linear'): "set log or linear scale for x, y axis" self.conf.set_logscale(xscale=xscale, yscale=yscale) def toggle_legend(self, evt=None, show=None): "toggle legend display" if show is None: show = not self.conf.show_legend self.conf.show_legend = show self.conf.draw_legend() def toggle_grid(self, evt=None, show=None): "toggle grid display" if show is None: show = not self.conf.show_grid self.conf.enable_grid(show) def configure(self, event=None): """show configuration frame""" if self.win_config is not None: try: self.win_config.Raise() except: self.win_config = None if self.win_config is None: self.win_config = PlotConfigFrame( parent=self, config=self.conf, trace_color_callback=self.trace_color_callback) self.win_config.Raise() #### ## create GUI #### def BuildPanel(self): """ builds basic GUI panel and popup menu""" self.fig = Figure(self.figsize, dpi=self.dpi) # 1 axes for now self.gridspec = GridSpec(1, 1) kwargs = {'facecolor': self.conf.bgcolor} if matplotlib.__version__ < "2.0": kwargs = {'axisbg': self.conf.bgcolor} self.axes = self.fig.add_subplot(self.gridspec[0], **kwargs) self.canvas = FigureCanvas(self, -1, self.fig) self.printer.canvas = self.canvas self.set_bg(self.conf.framecolor) self.conf.canvas = self.canvas self.canvas.SetCursor(wxCursor(wx.CURSOR_CROSS)) self.canvas.mpl_connect("pick_event", self.__onPickEvent) # overwrite ScalarFormatter from ticker.py here: self.axes.xaxis.set_major_formatter(FuncFormatter(self.xformatter)) self.axes.yaxis.set_major_formatter(FuncFormatter(self.yformatter)) # This way of adding to sizer allows resizing sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.canvas, 2, wx.LEFT | wx.TOP | wx.BOTTOM | wx.EXPAND, 0) self.SetAutoLayout(True) self.autoset_margins() self.SetSizer(sizer) self.Fit() canvas_draw = self.canvas.draw def draw(*args, **kws): self.autoset_margins() canvas_draw(*args, **kws) self.canvas.draw = draw self.addCanvasEvents() def _updateCanvasDraw(self): """ Overload of the draw function that update axes position before each draw""" fn = self.canvas.draw def draw2(*a, **k): self._updateGridSpec() return fn(*a, **k) self.canvas.draw = draw2 def get_default_margins(self): """get default margins""" trans = self.fig.transFigure.inverted().transform # Static margins l, t, r, b = self.axesmargins (l, b), (r, t) = trans(((l, b), (r, t))) # Extent dl, dt, dr, db = 0, 0, 0, 0 for i, ax in enumerate(self.fig.get_axes()): (x0, y0), (x1, y1) = ax.get_position().get_points() try: (ox0, oy0), (ox1, oy1) = ax.get_tightbbox( self.canvas.get_renderer()).get_points() (ox0, oy0), (ox1, oy1) = trans(((ox0, oy0), (ox1, oy1))) dl = max(dl, (x0 - ox0)) dt = max(dt, (oy1 - y1)) dr = max(dr, (ox1 - x1)) db = max(db, (y0 - oy0)) except: pass # print(" > %.3f %.3f %.3f %.3f " % (dl, dt, dr, db)) return (l + dl, t + dt, r + dr, b + db) def autoset_margins(self): """auto-set margins left, bottom, right, top according to the specified margins (in pixels) and axes extent (taking into account labels, title, axis) """ if not self.conf.auto_margins: return # coordinates in px -> [0,1] in figure coordinates trans = self.fig.transFigure.inverted().transform # Static margins if not self.use_dates: self.conf.margins = l, t, r, b = self.get_default_margins() self.gridspec.update(left=l, top=1 - t, right=1 - r, bottom=b) # Axes positions update for ax in self.fig.get_axes(): try: ax.update_params() except ValueError: pass ax.set_position(ax.figbox) def draw(self): self.canvas.draw() def update_line(self, trace, xdata, ydata, side='left', draw=False, update_limits=True): """ update a single trace, for faster redraw """ x = self.conf.get_mpl_line(trace) x.set_data(xdata, ydata) datarange = [xdata.min(), xdata.max(), ydata.min(), ydata.max()] self.conf.set_trace_datarange(datarange, trace=trace) axes = self.axes if side == 'right': axes = self.get_right_axes() if update_limits: self.set_viewlimits() if draw: self.draw() def get_figure(self): return self.fig def __onPickEvent(self, event=None): """pick events""" legline = event.artist trace = self.conf.legend_map.get(legline, None) visible = True if trace is not None and self.conf.hidewith_legend: line, legline, legtext = trace visible = not line.get_visible() line.set_visible(visible) if visible: legline.set_zorder(10.00) legline.set_alpha(1.00) legtext.set_zorder(10.00) legtext.set_alpha(1.00) else: legline.set_alpha(0.50) legtext.set_alpha(0.50) def onExport(self, event=None, **kws): ofile = '' title = 'unknown plot' if self.conf.title is not None: title = ofile = self.conf.title.strip() if len(ofile) > 64: ofile = ofile[:63].strip() if len(ofile) < 1: ofile = 'plot' for c in ' .:";|/\\(){}[]\'&^%*$+=-?!@#': ofile = ofile.replace(c, '_') while '__' in ofile: ofile = ofile.replace('__', '_') ofile = ofile + '.dat' dlg = wx.FileDialog(self, message='Export Map Data to ASCII...', defaultDir=os.getcwd(), defaultFile=ofile, style=wx.FD_SAVE | wx.FD_CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: self.writeASCIIFile(dlg.GetPath(), title=title) def writeASCIIFile(self, fname, title='unknown plot'): buff = ["# X,Y Data for %s" % title, "#------------", "# X Y"] lines = self.axes.get_lines() x0 = lines[0].get_xaxis() y0 = lines[0].get_yaxis() lab0 = lines[0].get_label().strip() if len(lab0) < 1: lab0 = 'Y' buff.append("# X %s" % lab0) outa = [x0, y0] npts = len(x0) if len(lines) > 1: for ix, line in enumerate(lines[1:]): lab = ['# ', ' ', line.get_label().strip()] x = line.get_xdata() y = line.get_ydata() npts = max(npts, len(y)) if not all(x == x0): lab0[1] = ' X%i ' % (ix + 2) out.append(x) out.append(line.get_ydata()) fout = open(fname, 'w') fout.write("%s\n" % "\n".join(buff)) fout.close() orig_dir = os.path.abspath(os.curdir) thisdir = os.getcwd() file_choices = "DAT (*.dat)|*.dat|ALL FILES (*.*)|*.*" dlg = wx.FileDialog(self, message='Export Plot Data to ASCII...', defaultDir=thisdir, defaultFile=ofile, wildcard=file_choices, style=wx.FD_SAVE | wx.FD_CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: self.writeASCIIFile(dlg.GetPath(), title=title) os.chdir(orig_dir) def writeASCIIFile(self, fname, title='unknown plot'): "save plot data to external file" buff = ["# Plot Data for %s" % title, "#------"] out = [] labs = [] itrace = 0 for ax in self.fig.get_axes(): for line in ax.lines: itrace += 1 x = line.get_xdata() y = line.get_ydata() ylab = line.get_label() if len(ylab) < 1: ylab = ' Y%i' % itrace if len(ylab) < 4: ylab = ' %s%s' % (' ' * 4, lab) for c in ' .:";|/\\(){}[]\'&^%*$+=-?!@#': ylab = ylab.replace(c, '_') pad = max(1, 13 - len(ylab)) lab = ' X%i %s%s ' % (itrace, ' ' * pad, ylab) out.extend([x, y]) labs.append(lab) buff.append('# %s ' % (' '.join(labs))) npts = [len(a) for a in out] for i in range(max(npts)): oline = [] for a in out: d = nan if i < len(a): d = a[i] oline.append(gformat(d)) buff.append(' '.join(oline)) if itrace > 0: fout = open(fname, 'w') fout.write("%s\n" % "\n".join(buff)) fout.close() self.write_message("Exported data to '%s'" % fname, panel=0) #### ## GUI events #### def report_leftdown(self, event=None): if event is None: return ex, ey = event.x, event.y msg = '' try: x, y = self.axes.transData.inverted().transform((ex, ey)) except: x, y = event.xdata, event.ydata if x is not None and y is not None: msg = ("X,Y= %s, %s" % (self._xfmt, self._yfmt)) % (x, y) if len(self.fig.get_axes()) > 1: ax2 = self.fig.get_axes()[1] try: x2, y2 = ax2.transData.inverted().transform((ex, ey)) msg = "X,Y,Y2= %s, %s, %s" % (self._xfmt, self._yfmt, self._y2fmt) % (x, y, y2) except: pass nsbar = getattr(self, 'nstatusbar', 1) self.write_message(msg, panel=max(0, nsbar - 2)) if (self.cursor_callback is not None and hasattr(self.cursor_callback, '__call__')): self.cursor_callback(x=event.xdata, y=event.ydata)
class ShowTifInPath(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) self.fig = plt.figure() self.canvas = FigCanvas(self, -1, self.fig) self.lastFileName = '' self.filesPath = '' self.bindKeyShortcuts() self.createMenuAndToolbar() def bindKeyShortcuts(self): self.canvas.Bind(wx.EVT_KEY_DOWN, self.OnDwnKeyPress) self.canvas.Bind(wx.EVT_KEY_UP, self.OnUpKeyPress) self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) # Create an accelerator table myKeyId_1 = wx.NewId() myKeyId_2 = wx.NewId() self.Bind(wx.EVT_MENU, self.onCtrlShiftF1, id=myKeyId_1) self.Bind(wx.EVT_MENU, self.onShiftAltY, id=myKeyId_2) accel_tbl = wx.AcceleratorTable([ (wx.ACCEL_SHIFT | wx.ACCEL_CTRL, wx.WXK_F1, myKeyId_1), (wx.ACCEL_SHIFT | wx.ACCEL_ALT, ord('Y'), myKeyId_2) ]) self.SetAcceleratorTable(accel_tbl) def onCtrlShiftF1(self, event): """ https://www.blog.pythonlibrary.org/2010/12/02/wxpython-keyboard-shortcuts-accelerators/ """ print "You pressed CTRL+SHIFT+F1" def onShiftAltY(self, event): """ https://www.blog.pythonlibrary.org/2010/12/02/wxpython-keyboard-shortcuts-accelerators/ """ print "You pressed ALT+SHIFT+Y" def createMenuAndToolbar(self): ''' ref: https://www.blog.pythonlibrary.org/2008/07/02/wxpython-working-with-menus-toolbars-and-accelerators/ ''' """ Create the menu bar. """ menuBar = wx.MenuBar() fileMenu = wx.Menu() fileMenu.AppendSeparator() exitMenuItem = fileMenu.Append(wx.NewId(), "&Exit\tAlt+F4", "Exit the application") self.Bind(wx.EVT_MENU, self.OnExit, exitMenuItem) menuBar.Append(fileMenu, "&File") # exitMenuItem.Enable(False) # menuBar.EnableTop(0, False) self.GetParent().SetMenuBar(menuBar) # add it to Frame object """ Create a toolbar. """ self.toolbar = self.GetParent().CreateToolBar() self.toolbar.SetToolBitmapSize((16, 16)) # sets icon size # Use wx.ArtProvider for default icons open_ico = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, (16, 16)) if 'phoenix' in wx.PlatformInfo: openTool = self.toolbar.AddTool(wx.ID_ANY, "Open", open_ico, "Select file to load") else: openTool = self.toolbar.AddSimpleTool(wx.ID_ANY, open_ico, "Open", "Select file to load") # self.Bind(wx.EVT_MENU, self.onSave, saveTool) # Use wx.ArtProvider for default icons save_ico = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, (16, 16)) saveTool = self.toolbar.AddTool(wx.ID_ANY, "Save", save_ico, "Saves the Current Worksheet") # self.Bind(wx.EVT_MENU, self.onSave, saveTool) self.toolbar.AddSeparator() print_ico = wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR, (16, 16)) printTool = self.toolbar.AddTool(wx.ID_ANY, "Print", print_ico, "Sends Timesheet to Default Printer") # self.Bind(wx.EVT_MENU, self.onPrint, printTool) # delete_ico = wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR, (16, 16)) # deleteTool = self.toolbar.AddSimpleTool(wx.ID_ANY, delete_ico, "Delete", "Delete contents of cell") # # self.Bind(wx.EVT_MENU, self.onDelete, deleteTool) # # undo_ico = wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR, (16, 16)) # self.undoTool = self.toolbar.AddSimpleTool(wx.ID_UNDO, undo_ico, "Undo", "") # self.toolbar.EnableTool(wx.ID_UNDO, False) # # self.Bind(wx.EVT_TOOL, self.onUndo, self.undoTool) # # redo_ico = wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_TOOLBAR, (16, 16)) # self.redoTool = self.toolbar.AddSimpleTool(wx.ID_REDO, redo_ico, "Redo", "") # self.toolbar.EnableTool(wx.ID_REDO, False) # # self.Bind(wx.EVT_TOOL, self.onRedo, self.redoTool) # This basically shows the toolbar self.toolbar.Realize() def OnExit(self): # SystemExit() self.Close() def ChangeCursor(self, event): self.canvas.SetCursor(wx.Cursor(wx.CURSOR_BULLSEYE)) def updateTif(self, tifFullName): img = mpimg.imread(tifFullName) self.imgplot.set_data(img) self.canvas.draw() # self.vbox.Fit(self) #bad for getting correct resize self.canvas.Refresh() return self.imgplot def showTif(self, tifFullName): img = mpimg.imread(tifFullName) self.imgplot = plt.imshow(img) self.cBar = plt.colorbar() self.toolbar = NavigationToolbar(self.canvas) # plt.axis('off') self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.vbox.Add(self.toolbar, 0, wx.EXPAND) self.SetSizer(self.vbox) self.vbox.Fit(self) return self.imgplot, self.cBar def OnDwnKeyPress(self, event): pass # print "dwnKey" def OnUpKeyPress(self, event): print "onUpKey" pressedKey = event.GetKeyCode() if (pressedKey == wx.WXK_LEFT) | (pressedKey == wx.WXK_DOWN): print "left / down key" #currentIndex % len(relevant items) filesList = list(panel.filesInfo) if (filesList[3] > 0): filesList[3] = (filesList[3]) - 1 else: filesList[3] = len(filesList[2]) - 1 panel.filesInfo = tuple(filesList) newFileName = panel.filesInfo[2][filesList[3]] panel.updateTif(newFileName) elif (pressedKey == wx.WXK_RIGHT) | (pressedKey == wx.WXK_UP): print "right / up key" #currentIndex % len(relevant items) filesList = list(panel.filesInfo) if (filesList[3] < (len(filesList[2]) - 1)): filesList[3] = (filesList[3]) + 1 else: filesList[3] = 0 panel.filesInfo = tuple(filesList) newFileName = panel.filesInfo[2][filesList[3]] panel.updateTif(newFileName) elif (pressedKey == wx.WXK_NUMPAD_ADD): print "+ key" elif (pressedKey == wx.WXK_NUMPAD_SUBTRACT): print "- key" else: print pressedKey return pressedKey
class Plotter(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent=parent) self.initGui() self.Centre() self.Show() self.graphsToPlot = [] self.currentGraph = {} #listen to messages from checklistbox pub.subscribe(self.__onItemChecked, 'item.checked') #the list of plots changed def __onItemChecked(self, data): self.graphsToPlot = [] for key, value in data.iteritems(): self.graphsToPlot.append(value) self.plotGraphs() def initGui(self): # Create main panel panel = self panel.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) # Set sizers sizer0 = wx.BoxSizer(wx.VERTICAL) panel.SetSizer(sizer0) # Matplotlib item panelcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() facecolor = [channel / float(255) for channel in panelcolour] self.figure = plt.figure( figsize=(-1, -1), dpi=80, facecolor=facecolor, linewidth=1.0 ) #Figure(figsize=(-1, -1), dpi=80, facecolor=facecolor, linewidth=1.0) self.figure.subplots_adjust(left=0.08, bottom=0.08, right=0.98, top=0.98) self.canvas = FigCanvas(panel, -1, self.figure) self.mainAxes = plt.subplot2grid((1, 1), (0, 0)) self.mainAxes.set_xlabel('X-Axis') self.mainAxes.set_ylabel('Y-Axis') self.mainAxes.set_xlim(0.0, 1.0) self.mainAxes.set_ylim(0.0, 1.0) matplotlib.rcParams.update({'font.size': 12}) self.mainAxes.grid(False) sizer0.Add(self.canvas, 1, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=20) self.toolbar = NavigationToolbar(self.canvas) sizer0.Add(self.toolbar, 0, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.LEFT | wx.RIGHT, border=20) sizer0.Add((-1, 10)) self.mouseMove = self.canvas.mpl_connect('motion_notify_event', self.updateStatusBar) self.onKey = self.canvas.mpl_connect('key_press_event', self.onKey) self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) self.plotLogo() # Redefine close event #self.Bind(wx.EVT_CLOSE, self.OnClose) def ChangeCursor(self, event): self.canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS)) def onKey(self, event): if event.inaxes and event.key == "s": x, y = event.xdata, event.ydata try: cmd.delete("mtsslPlot") cmd.select("mtsslPlot", "resi %i or resi %i" % (x, y)) except: print "Could not select: resi %i or resi %i" % (x, y) def updateStatusBar(self, event): #could be made faster using animation blits: #http://scipy-cookbook.readthedocs.org/items/Matplotlib_Animations.html if event.inaxes: x, y = event.xdata, event.ydata if event.inaxes == self.mainAxes: if self.currentGraph[ "Type"] == "DistanceMap" or self.currentGraph[ "Type"] == "DifferenceMap": z = self.currentGraph["zData"][x, y] statusString = "x = %i; y = %i; z = %i" % (x, y, z) pub.sendMessage('update.statusBar', data=statusString) #plot crosshair try: self.mainCrosshairX.remove() self.mainCrosshairY.remove() self.upperCrosshairY.remove() self.rightCrosshairX.remove() except: pass try: self.mainCrosshairX = self.mainAxes.axhline(y, color="red") self.mainCrosshairY = self.mainAxes.axvline(x, color="red") self.upperCrosshairY = self.axes1.axvline(x, color="red") self.rightCrosshairX = self.axes3.axhline(y, color="red") self.figure.tight_layout() self.canvas.draw() except: pass else: statusString = "x = %i; y = %i" % (x, y) pub.sendMessage('update.statusBar', data=statusString) def plotGraphs(self): # Which type of graph is it if len(self.graphsToPlot) > 0: graphType = self.graphsToPlot[0]["Type"] if (graphType == 'DistanceMap'): self.plotDistanceMap(self.graphsToPlot) if (graphType == 'DifferenceMap'): self.plotDifferenceMap(self.graphsToPlot) if (graphType == 'DistancePlot'): self.plotDistancePlot(self.graphsToPlot) if (graphType == 'AccessibilityPlot'): self.plotAccessibilityPlot(self.graphsToPlot) if (graphType == 'DistanceDistribution'): self.plotDistanceDistribution(self.graphsToPlot) self.currentGraph = self.graphsToPlot[0] pub.sendMessage('update.statusBar', data="Data plotted.") else: self.figure.clf() self.plotLogo() self.canvas.draw() pub.sendMessage('update.statusBar', data="Nothing to plot. Please select a plot.") def refreshFigure(self): self.figure.clear() self.mainAxes.set_xlabel('X-Axis') self.mainAxes.set_ylabel('Y-Axis') self.mainAxes.set_xlim(0.0, 1.0) self.mainAxes.set_ylim(0.0, 1.0) matplotlib.rcParams.update({'font.size': 12}) def plotDistanceMap(self, graphs): #there should only be one graph in graphs graph = graphs[0] # Read on x,y,z x = graph['xData'] - 0.5 * numpy.ones(len(graph['xData'])) y = graph['yData'] - 0.5 * numpy.ones(len(graph['yData'])) id = graph["id"] accessibilityPlots = [] for plot in stored.plots: try: if id == plot["id"] and plot["Type"] == "AccessibilityPlot": accessibilityPlots.append(plot) except: pass #print accessibilityPlots acc1x = accessibilityPlots[0]["xData"] acc1y = accessibilityPlots[0]["yData"] acc2x = accessibilityPlots[1]["xData"] acc2y = accessibilityPlots[1]["yData"] xlim = graph['xlim'] ylim = graph['ylim'] X, Y = numpy.meshgrid(x, y) Z = graph['zData'] # Define colormap cmap = colors.ListedColormap( ['blue', 'green', 'yellow', 'orange', 'red']) cmap.set_under('white') cmap.set_over('red') cmap.set_bad(color="grey") bounds = [1, 15, 40, 60, 80, 100] norm = colors.BoundaryNorm(bounds, cmap.N) # Draw plot self.mainAxes = plt.subplot2grid((5, 5), (1, 0), colspan=4, rowspan=4) self.axes1 = plt.subplot2grid((5, 5), (0, 0), colspan=4, sharex=self.mainAxes) self.axes3 = plt.subplot2grid((5, 5), (1, 4), rowspan=4, sharey=self.mainAxes) self.axes4 = plt.subplot2grid((5, 5), (0, 4)) self.axes1.plot(acc1x, acc1y, linestyle='solid', linewidth=0.5, color='dimgrey', markersize=6, markeredgewidth=1) img = self.mainAxes.pcolormesh(x, y, Z, cmap=cmap, norm=norm) self.mainAxes.set_xlim(xlim) self.mainAxes.set_ylim(ylim) self.mainAxes.set_xlabel(graph['xTitle']) self.mainAxes.set_ylabel(graph['yTitle']) self.axes3.plot(acc2y, acc2x, linestyle='solid', linewidth=0.5, color='dimgrey', markersize=6, markeredgewidth=1) # Cosmetics xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) self.axes1.xaxis.set_ticks_position('top') self.axes1.set_yticks(self.axes1.get_ylim()) self.axes1.set_ylabel("Access.") self.axes3.yaxis.set_ticks_position('right') self.axes3.set_xticks(self.axes1.get_ylim()) self.axes3.set_xlabel("Access.") # Draw colorbar colorbar = plt.colorbar(img, cax=self.axes4) colorbar.ax.set_xlabel('Angstrom') colorbar.ax.xaxis.set_label_position('top') #colorbar.ax.xaxis.labelpad = 20 self.figure.tight_layout() self.canvas.draw() def plotDifferenceMap(self, graphs): #there should only be one graph in graphs graph = graphs[0] # Read on x,y,z x = graph['xData'] - 0.5 * numpy.ones(len(graph['xData'])) y = graph['yData'] - 0.5 * numpy.ones(len(graph['yData'])) id = graph["id"] accessibilityPlots = [] for plot in stored.plots: if id == plot["id"] and plot["Type"] == "AccessibilityPlot": accessibilityPlots.append(plot) #print accessibilityPlots acc1x = accessibilityPlots[0]["xData"] acc1y = accessibilityPlots[0]["yData"] acc2x = accessibilityPlots[1]["xData"] acc2y = accessibilityPlots[1]["yData"] X, Y = numpy.meshgrid(x, y) Z = graph['zData'] xlim = graph['xlim'] ylim = graph['ylim'] # Draw surface plot self.mainAxes = plt.subplot2grid((5, 5), (1, 0), colspan=4, rowspan=4) self.axes1 = plt.subplot2grid((5, 5), (0, 0), colspan=4, sharex=self.mainAxes) self.axes3 = plt.subplot2grid((5, 5), (1, 4), rowspan=4, sharey=self.mainAxes) self.axes4 = plt.subplot2grid((5, 5), (0, 4)) self.axes1.plot(acc1x, acc1y, linestyle='solid', linewidth=0.5, color='dimgrey', markersize=6, markeredgewidth=1) try: plt.register_cmap(name='plasma', cmap=cmaps.plasma) plt.set_cmap(cmaps.plasma) cmap = plt.get_cmap(cmaps.plasma) except: cmap = matplotlib.cm.jet cmap.set_bad(color="grey") img = self.mainAxes.pcolormesh(X, Y, Z, cmap=cmap, vmin=0.0, vmax=numpy.amax(Z)) self.mainAxes.set_xlim(xlim) self.mainAxes.set_ylim(ylim) self.mainAxes.set_xlabel(graph['xTitle']) self.mainAxes.set_ylabel(graph['yTitle']) self.axes3.plot(acc2y, acc2x, linestyle='solid', linewidth=0.5, color='dimgrey', markersize=6, markeredgewidth=1) # Cosmetics xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) self.mainAxes.xaxis.set_minor_locator(xminorLocator) self.mainAxes.yaxis.set_minor_locator(yminorLocator) self.mainAxes.tick_params(direction='out', length=6, width=1) self.mainAxes.tick_params(which='minor', direction='out', length=3, width=1) self.mainAxes.xaxis.labelpad = 15 self.mainAxes.yaxis.labelpad = 15 self.axes1.xaxis.set_ticks_position('top') self.axes1.set_yticks(self.axes1.get_ylim()) self.axes1.set_ylabel("Access.") self.axes3.yaxis.set_ticks_position('right') self.axes3.set_xticks(self.axes1.get_ylim()) self.axes3.set_xlabel("Access.") # Draw colorbar colorbar = plt.colorbar(img, cax=self.axes4) colorbar.ax.set_xlabel('Angstrom') colorbar.ax.xaxis.set_label_position('top') #colorbar.ax.xaxis.labelpad = 20 self.figure.tight_layout() self.canvas.draw() def plotDistancePlot(self, graphs): # Plot graph axes = plt.subplot2grid((1, 1), (0, 0)) for graph in graphs: axes.plot( graph['xData'], graph['yData'], linestyle='solid', linewidth=3, color=graph['Color'], #marker='o', #markerfacecolor='white', #markeredgecolor='black', #markersize=3.5, #markeredgewidth=1 ) Xmin = 0 Xmax = graph['xData'].max() + 1 Ymin = 0 Ymax = 100 axes.set_xlim(graph['xlim']) axes.set_ylim(Ymin, Ymax) axes.set_xlabel(graph['xTitle']) axes.set_ylabel(graph['yTitle']) # Color the distance ranges axes.fill_between([Xmin, Xmax], 15, Ymin, color='blue', alpha=0.15) axes.fill_between([Xmin, Xmax], 40, 15, color='green', alpha=0.15) axes.fill_between([Xmin, Xmax], 60, 40, color='yellow', alpha=0.15) axes.fill_between([Xmin, Xmax], 80, 60, color='orange', alpha=0.15) axes.fill_between([Xmin, Xmax], Ymax, 80, color='red', alpha=0.15) # Cosmetics xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) axes.xaxis.set_minor_locator(xminorLocator) axes.yaxis.set_minor_locator(yminorLocator) axes.tick_params(direction='out', length=6, width=1) axes.tick_params(which='minor', direction='out', length=3, width=1) axes.xaxis.labelpad = 15 axes.yaxis.labelpad = 15 self.figure.tight_layout() self.canvas.draw() def plotDistanceDistribution(self, graphs): axes = plt.subplot2grid((1, 1), (0, 0)) for graph in graphs: index = numpy.zeros(1) for i in range(0, graph['yData'].shape[0]): if (graph['yData'][i] <= 0): index = numpy.append(index, i) index = numpy.delete(index, 0) Y = numpy.delete(graph['yData'], index) X = numpy.delete(graph['xData'], index) axes.plot( X, Y, linestyle='solid', linewidth=3, color=graph['Color'], #markerfacecolor='white', #markeredgecolor='black', markersize=3.5, #markeredgewidth=1 ) Xmin = 0 Xmax = graph['xData'].max() + 1 Ymin = 0 Ymax = graph['yData'].max() * 1.05 axes.set_xlim(graph['xlim']) axes.set_ylim(Ymin, Ymax) axes.set_xlabel(graph['xTitle']) axes.set_ylabel(graph['yTitle']) xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) axes.xaxis.set_minor_locator(xminorLocator) axes.yaxis.set_minor_locator(yminorLocator) axes.tick_params(direction='out', length=6, width=1) axes.tick_params(which='minor', direction='out', length=3, width=1) axes.xaxis.labelpad = 15 axes.yaxis.labelpad = 15 self.figure.tight_layout() self.canvas.draw() def plotAccessibilityPlot(self, graphs): axes = plt.subplot2grid((1, 1), (0, 0)) for graph in graphs: axes.plot( graph['xData'], graph['yData'], linestyle='solid', linewidth=3, color=graph['Color'], marker='.', #markerfacecolor='white', #markeredgecolor='black', markersize=3.5, #markeredgewidth=1 ) Xmin = 0 Xmax = graph['xData'].max() + 1 Ymin = 0 Ymax = graph['yData'].max() * 1.05 axes.set_xlim(graph['xlim']) axes.set_ylim(Ymin, Ymax) axes.set_xlabel(graph['xTitle']) axes.set_ylabel(graph['yTitle']) # Cosmetics xminorLocator = MultipleLocator(10) yminorLocator = MultipleLocator(10) axes.xaxis.set_minor_locator(xminorLocator) axes.yaxis.set_minor_locator(yminorLocator) axes.tick_params(direction='out', length=6, width=1) axes.tick_params(which='minor', direction='out', length=3, width=1) axes.xaxis.labelpad = 15 axes.yaxis.labelpad = 15 self.figure.tight_layout() self.canvas.draw() def plotLogo(self): axes = plt.subplot2grid((1, 1), (0, 0)) img = mpimg.imread(os.path.dirname(__file__) + "/logo.png") axes.imshow(img)
class MainPanel(wx.Dialog): def __init__(self, parent, pathToPlugins=None): #, main_playlist, nb_playlist): if (not pathToPlugins == None): RESFILE = os.path.join(pathToPlugins, 'x2') + os.sep + "layout_x2.xml" wx.Dialog.__init__(self, parent, -1, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) self.parent = parent self.nb_playlist = 0 self.main_playlist = self.parent.lc_playlist #self.super_parent = super_parent # XML Resources can be loaded from a file like this: res = xrc.XmlResource(RESFILE) # Now create a panel from the resource data panel = res.LoadPanel(self, "m_pa_x2main") #self.panel = panel #background = 'tulips.jpg' #img = wx.Image(background, wx.BITMAP_TYPE_ANY) #self.buffer = wx.BitmapFromImage(img) #dc = wx.BufferedDC(wx.ClientDC(panel), self.buffer) #self.panel.Bind(wx.EVT_PAINT, self.OnPaint) # control references -------------------- self.pa_x2main = xrc.XRCCTRL(self, 'm_pa_x2main') self.pa_x2_graph = xrc.XRCCTRL(self, 'm_pa_x2_graph') self.lc_x2_plist = xrc.XRCCTRL(self, 'm_lc_x2_plist') self.cl_x2_features = xrc.XRCCTRL(self, 'm_cl_x2_features') self.sl_x2_pointsize = xrc.XRCCTRL(self, 'm_sl_x2_pointsize') self.lc_x2_plist.InsertColumn(0, "Artist") self.lc_x2_plist.InsertColumn(1, "Song") self.lc_x2_plist.SetColumnWidth(0, 100) self.lc_x2_plist.SetColumnWidth(1, 100) self.Bind(wx.EVT_BUTTON, self.OnAutoGenerateX2Playist, id=xrc.XRCID('m_bu_x2_plize')) self.Bind(wx.EVT_BUTTON, self.OnCenterClick, id=xrc.XRCID('m_bu_x2_center')) self.Bind(wx.EVT_SLIDER, self.OnPointSizeClick, id=xrc.XRCID('m_sl_x2_pointsize')) self.Bind(wx.EVT_SPIN, self.OnZoomClick, id=xrc.XRCID('m_sb_x2_zoom')) self.Bind(wx.EVT_SPIN, self.OnPanXClick, id=xrc.XRCID('m_sb_x2_panx')) self.Bind(wx.EVT_SPIN, self.OnPanYClick, id=xrc.XRCID('m_sb_x2_pany')) self.Bind(wx.EVT_CHECKBOX, self.OnXAxisClick, id=xrc.XRCID('m_cb_x2_xlog')) self.Bind(wx.EVT_CHECKBOX, self.OnYAxisClick, id=xrc.XRCID('m_cb_x2_ylog')) self.Bind(wx.EVT_CHECKLISTBOX, self.OnCheckListBox, self.cl_x2_features) self.current_zoom = 0 self.current_panx = 0 self.current_pany = 0 #features array #tag_array = GetTags() self.cl_x2_features.Set(FEATURES_ARRAY) #self.cl_x2_features.AppendItems(tag_array) self.figure = Figure(None, None, (1, 1, 1), None, 1.0, True, None) #facecolor=0.75, edgecolor='white') #(figsize=None, dpi=None, facecolor=None, edgecolor=None, linewidth=1.0, frameon=True, subplotpars=None) self.MakeScatt([0, 1, 2, 3]) self.build_graph() self.build_collection() self.canvas = FigureCanvas(self.pa_x2_graph, -1, self.figure) self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRightDown) #self.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.Bind(wx.EVT_RIGHT_UP, self.OnMouseRightUp) self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRightDown) #self.canvas.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.canvas.Bind(wx.EVT_RIGHT_UP, self.OnMouseRightUp) # Note that event is a MplEvent #self.canvas.mpl_connect('motion_notify_event', self.OnMouseMotion) #self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) #lasso self.mpl = self.canvas.mpl_connect('button_press_event', self.onpress) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.pa_x2main, 1, wx.EXPAND | wx.ALL, 5) self.SetSizer(sizer) self.SetAutoLayout(True) self.Fit() # ----------------------------------------- # ----------------------------------------- def OnPaint(self, evt): dc = wx.BufferedPaintDC(self.panel, self.buffer) def ChangeCursor(self, curtype): self.canvas.SetCursor(wx.StockCursor(curtype)) def OnMouseRightDown(self, evt): self.canvas.mpl_disconnect(self.mpl) self.canvas.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.Bind(wx.EVT_MOTION, self.OnMouseMotion) self.ChangeCursor(wx.CURSOR_HAND) self.Refresh() self.oldx = evt.GetPosition()[0] self.oldy = evt.GetPosition()[1] #self.wPos = self.ClientToScreen((0,0)) self.CaptureMouse() #print 'right-down' def OnMouseMotion(self, evt): if evt.Dragging() and evt.RightIsDown(): dPos = evt.GetPosition( ) #evt.GetEventObject().ClientToScreen(evt.GetPosition()) #nPos = (self.wPos.x + (dPos.x - self.ldPos.x), -2) #nPos = (self.wPos.x + (dPos.x - self.ldPos.x), self.wPos.y + (dPos.y - self.ldPos.y)) #print(nPos) #print self.ldPos curx = dPos[0] cury = dPos[1] x = self.axes.get_xaxis() y = self.axes.get_yaxis() if (curx - self.oldx) < -10: x.pan(.5) self.oldx = curx if (curx - self.oldx) > 10: x.pan(-.5) self.oldx = curx if (cury - self.oldy) > 10: y.pan(.5) self.oldy = cury if (cury - self.oldy) < -10: y.pan(-.5) self.oldy = cury self.canvas.draw() def OnMouseRightUp(self, evt): try: self.ReleaseMouse() except wx._core.PyAssertionError: pass self.ChangeCursor(wx.CURSOR_DEFAULT) self.canvas.Unbind(wx.EVT_MOTION) self.Unbind(wx.EVT_MOTION) self.mpl = self.canvas.mpl_connect('button_press_event', self.onpress) def UpdateStatusBar(self, event): if event.inaxes: x, y = event.xdata, event.ydata self.statusBar.SetStatusText(("x= " + str(x) + " y=" + str(y)), 0) def OnPointSizeClick(self, event): self.point_size = self.sl_x2_pointsize.GetValue( ) + 50 # range 50 to 300 self.figure.clear() self.build_graph() self.build_collection() self.canvas.draw() def OnCenterClick(self, event): self.figure.clear() self.build_graph() self.build_collection() self.canvas.draw() def OnZoomClick(self, event=None): x = self.axes.get_xaxis() y = self.axes.get_yaxis() if event.GetPosition() > self.current_zoom: x.zoom(1) y.zoom(1) else: x.zoom(-1) y.zoom(-1) self.current_zoom = event.GetPosition() self.canvas.draw() def OnMouseWheel(self, evt): rotation = evt.GetWheelRotation() x = self.axes.get_xaxis() y = self.axes.get_yaxis() if rotation > 0: x.zoom(1) y.zoom(1) else: x.zoom(-1) y.zoom(-1) self.canvas.draw() # Done handling event #evt.Skip() def OnPanXClick(self, event): x = self.axes.get_xaxis() y = self.axes.get_yaxis() if event.GetPosition() > self.current_panx: x.pan(1) else: x.pan(-1) self.current_panx = event.GetPosition() self.canvas.draw() def OnPanYClick(self, event): x = self.axes.get_xaxis() y = self.axes.get_yaxis() if event.GetPosition() > self.current_pany: y.pan(1) else: y.pan(-1) self.current_pany = event.GetPosition() self.canvas.draw() def OnXAxisClick(self, event): if self.axes.get_xscale() == 'log': self.axes.set_xscale('linear') else: self.axes.set_xscale('log') #self.axes.autoscale_view() #self.canvas.draw_idle() #self.axes.autoscale_view() self.canvas.draw() #self.canvas.Refresh(eraseBackground=False) def OnYAxisClick(self, event): if self.axes.get_yscale() == 'log': self.axes.set_yscale('linear') else: self.axes.set_yscale('log') #self.axes.autoscale_view() self.canvas.draw() # ---------------------------------------------------------- def OnCheckListBox(self, event): index = event.GetSelection() label = self.cl_x2_features.GetString(index) #print label #print index self.cl_x2_features.SetSelection( index) # so that (un)checking also selects (moves the highlight) #print self.cl_x2_features.GetCount() selected_array = [] for x in range(0, self.cl_x2_features.GetCount()): if self.cl_x2_features.IsChecked(x) == True: selected_array.append(x) print selected_array if len(selected_array) >= 1: #print 'fofofofof' self.figure.clear() self.MakeScatt(selected_array) self.build_graph() self.build_collection() self.canvas.draw() # ---------------------------------------------------------- # ---------------------------------------------------------- def MakeScatt(self, selected_array): pre_data_array, self.song_array, self.color_array, use_std = GetResultsArray( selected_array) #print pre_data_array pca1, pca2, pca3 = pca_module.PCA_svd(pre_data_array, use_std) #print self.data_array #print pca1 #self.data = pca1 #print pca2 #grab the first 2 components self.data_array = np.array_split(pca1, [ 2, ], axis=1)[0] #print self.data_array #self.axes.set_xlabel(r'$\Delta_i$', fontsize=20) #self.axes.set_ylabel(r'$\Delta_{i+1}$', fontsize=20) #self.axes.set_title('Volume and percent change') #self.axes.grid(True) ### use zoom instead #self.xmin = self.data1.min()# - (self.data1.max() * 0.1) #self.xmax = self.data1.max()# * 1.1 #self.ymin = self.data2.min()# - (self.data2.max() * 0.1) #self.ymax = self.data2.max()# * 1.1 def build_graph(self): self.axes = self.figure.add_subplot(111, axisbg=(1, 1, 1)) self.figure.subplots_adjust(left=0, right=1, top=1, bottom=0) #self.axes.frame_on(False) #subplot(111, axisbg='darkslategray') #ax = fig.add_subplot(111) #self.axes.scatter(self.data2, self.data1, c=[0.5,0.5,1.0], s=200, alpha=0.5) def build_collection(self): self.point_size = self.sl_x2_pointsize.GetValue( ) + 50 # range 50 to 300 self.collection = RegularPolyCollection( #self.axes.figure.dpi, numsides=80, sizes=(self.point_size, ), facecolors=self.color_array, offsets=self.data_array, transOffset=self.axes.transData) self.collection.set_alpha(0.7) self.axes.add_collection(self.collection) #self.axes.axis([self.xmin, self.xmax, self.ymin, self.ymax]) self.axes.autoscale_view() x = self.axes.get_xaxis() y = self.axes.get_yaxis() x.zoom(-1) y.zoom(-1) #self.axes.axis('tight') ##self.axes.axis('off') def callback(self, verts): facecolors = self.collection.get_facecolors() ind = nonzero(points_inside_poly(self.data_array, verts))[0] for i in range(len(self.data_array)): if i in ind: facecolors[i] = (1, 1, 0, .5) #print facecolors[i] #pass else: facecolors[i] = self.color_array[i] #pass #print facecolors[i] self.canvas.draw_idle() self.canvas.widgetlock.release(self.lasso) del self.lasso #self.ind = ind self.pass_data(ind) def onpress(self, event): #print event.button if self.canvas.widgetlock.locked(): #print 'foo' self.canvas.widgetlock.release(self.lasso) #return if event.inaxes is None: return self.lasso = Lasso(event.inaxes, (event.xdata, event.ydata), self.callback) # acquire a lock on the widget drawing self.canvas.widgetlock(self.lasso) def pass_data(self, ind): #populate parents list control self.lc_x2_plist.DeleteAllItems() for x in ind: self.lc_x2_plist.InsertStringItem(0, self.song_array[x][0]) self.lc_x2_plist.SetStringItem(0, 1, self.song_array[x][1]) #pass def update_data(self): pass #self.figure.clf() #build_graph(self) #self.MakeScatt() #self.build_collection() def OnAutoGenerateX2Playist(self, event): # copy the sifted list to the playlist self.parent.CheckClear() insert_at = self.parent.lc_playlist.GetItemCount() for x in range(self.lc_x2_plist.GetItemCount(), 0, -1): artist = self.lc_x2_plist.GetItem(x - 1, 0).GetText() song = self.lc_x2_plist.GetItem(x - 1, 1).GetText() self.parent.SetPlaylistItem(insert_at, artist, song, '', '') #save the playlist self.parent.SavePlaylist() # switch tabs self.parent.nb_main.SetSelection(self.nb_playlist)
class PlotPanel(wx.Panel): ''' Base class for the plotting in GenX - all the basic functionallity should be implemented in this class. The plots should be derived from this class. These classes should implement an update method to update the plots. ''' def __init__(self, parent, id = -1, color = None, dpi = None , style = wx.NO_FULL_REPAINT_ON_RESIZE|wx.EXPAND|wx.ALL , config = None, config_name = '', **kwargs): wx.Panel.__init__(self,parent, id = id, style = style, **kwargs) self.parent = parent self.callback_window = self self.config = config self.config_name = config_name self.figure = Figure(None,dpi) self.canvas = FigureCanvasWxAgg(self, -1, self.figure) self.canvas.SetExtraStyle(wx.EXPAND) self.SetColor(color) self.Bind(wx.EVT_IDLE, self._onIdle) self.Bind(wx.EVT_SIZE, self._onSize) self._resizeflag = True self.print_size = (15./2.54, 12./2.54) #self._SetSize() # Flags and bindings for zooming self.zoom = False self.zooming = False self.scale = 'linear' self.autoscale = True self.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnLeftMouseButtonDown) self.canvas.Bind(wx.EVT_LEFT_UP, self.OnLeftMouseButtonUp) self.canvas.Bind(wx.EVT_MOTION, self.OnMouseMove) self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDblClick) self.canvas.Bind(wx.EVT_RIGHT_UP, self.OnContextMenu) cursor = wx.StockCursor(wx.CURSOR_CROSS) self.canvas.SetCursor(cursor) self.old_scale_state = True self.ax = None # Init printout stuff self.fig_printer = FigurePrinter(self) # Create the drawing bitmap self.bitmap =wx.EmptyBitmap(1, 1) # DEBUG_MSG("__init__() - bitmap w:%d h:%d" % (w,h), 2, self) self._isDrawn = False def SetColor(self, rgbtuple=None): ''' Set the figure and canvas color to be the same ''' if not rgbtuple: rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() col = [c/255. for c in rgbtuple] self.figure.set_facecolor(col) self.figure.set_edgecolor(col) self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple)) def _onSize(self, evt): self._resizeflag = True self._SetSize() #self.canvas.draw(repaint = False) def _onIdle(self, evt): if self._resizeflag: self._resizeflag = False self._SetSize() #self.canvas.gui_repaint(drawDC = wx.PaintDC(self)) def _SetSize(self, pixels = None): ''' This method can be called to force the Plot to be a desired size which defaults to the ClientSize of the Panel. ''' if not pixels: pixels = self.GetClientSize() self.canvas.SetSize(pixels) #self.figure.set_size_inches(pixels[0]/self.figure.get_dpi() #, pixels[1]/self.figure.get_dpi()) def ReadConfig(self): '''ReadConfig(self) --> None Reads in the config file ''' bool_items = ['zoom', 'autoscale'] bool_func = [self.SetZoom, self.SetAutoScale] if not self.config: return vals = [] for index in range(len(bool_items)): try: val = self.config.get_boolean(self.config_name,\ bool_items[index]) except io.OptionError as e: print('Could not locate option %s.%s'\ %(self.config_name, bool_items[index])) vals.append(None) else: vals.append(val) try: scale = self.config.get(self.config_name, 'y scale') string_sucess = True except io.OptionError as e: string_sucess = False print('Could not locate option %s.%s'\ %(self.config_name, 'scale')) else: self.SetYScale(scale) # This is done due to that the zoom and autoscale has to read # before any commands are issued in order not to overwrite # the config [bool_func[i](vals[i]) for i in range(len(vals)) if vals[i]] def WriteConfig(self): '''WriteConfig(self) --> None Writes the current settings to the config file ''' if self.config: self.config.set(self.config_name, 'zoom', self.GetZoom()) self.config.set(self.config_name, 'autoscale', self.GetAutoScale()) self.config.set(self.config_name, 'y scale', self.GetYScale()) def SetZoom(self, active = False): ''' set the zoomstate ''' #if not self.zoom_sel: #self.zoom_sel = RectangleSelector(self.ax,\ # self.box_select_callback, drawtype='box',useblit=False) #print help(self.zoom_sel.ignore) if active: #self.zoom_sel.ignore = lambda x: False self.zoom = True cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER) self.canvas.SetCursor(cursor) if self.callback_window: evt = state_changed(zoomstate = True,\ yscale = self.GetYScale(), autoscale = self.autoscale) wx.PostEvent(self.callback_window, evt) if self.ax: #self.ax.set_autoscale_on(False) self.old_scale_state = self.GetAutoScale() self.SetAutoScale(False) else: #self.zoom_sel.ignore = lambda x: True self.zoom = False cursor = wx.StockCursor(wx.CURSOR_CROSS) self.canvas.SetCursor(cursor) if self.callback_window: evt = state_changed(zoomstate = False,\ yscale = self.GetYScale(), autoscale = self.autoscale) wx.PostEvent(self.callback_window, evt) if self.ax: #self.ax.set_autoscale_on(self.autoscale) self.SetAutoScale(self.old_scale_state) self.WriteConfig() def GetZoom(self): '''GetZoom(self) --> state [bool] Returns the zoom state of the plot panel. True = zoom active False = zoom inactive ''' return self.zoom def SetAutoScale(self, state): '''SetAutoScale(self, state) --> None Sets autoscale of the main axes wheter or not it should autoscale when plotting ''' #self.ax.set_autoscale_on(state) self.autoscale = state self.WriteConfig() evt = state_changed(zoomstate = self.GetZoom(),\ yscale = self.GetYScale(), autoscale = self.autoscale) wx.PostEvent(self.callback_window, evt) def GetAutoScale(self): '''GetAutoScale(self) --> state [bool] Returns the autoscale state, true if the plots is automatically scaled for each plot command. ''' return self.autoscale def AutoScale(self, force = False): '''AutoScale(self) --> None A log safe way to autoscale the plots - the ordinary axis tight does not work for negative log data. This works! ''' if not (self.autoscale or force): return # If nothing is plotted no autoscale use defaults... if sum([len(line.get_ydata()) > 0 for line in self.ax.lines]) == 0: self.ax.set_xlim(0, 1) self.ax.set_ylim(1e-3, 1.0) return if self.scale == 'log': #print 'log scaling' # Find the lowest possible value of all the y-values that are #greater than zero. check so that y data contain data before min # is applied tmp = [line.get_ydata().compress(line.get_ydata() > 0.0).min()\ for line in self.ax.lines if array(line.get_ydata() > 0.0).sum() > 0] if len(tmp) > 0: ymin = min(tmp) else: ymin = 1e-3 tmp = [line.get_ydata().compress(line.get_ydata() > 0.0).max()\ for line in self.ax.lines if array(line.get_ydata() > 0.0).sum() > 0] if len(tmp) > 0: ymax = max(tmp) else: ymax = 1 else: ymin = min([array(line.get_ydata()).min()\ for line in self.ax.lines if len(line.get_ydata()) > 0]) ymax = max([array(line.get_ydata()).max()\ for line in self.ax.lines if len(line.get_ydata()) > 0]) tmp = [array(line.get_xdata()).min()\ for line in self.ax.lines if len(line.get_ydata()) > 0] if len(tmp) > 0: xmin = min(tmp) else: xmin = 0 tmp = [array(line.get_xdata()).max()\ for line in self.ax.lines if len(line.get_ydata()) > 0] if len(tmp) > 0: xmax = max(tmp) else: xmax = 1 # Set the limits #print 'Autoscaling to: ', ymin, ymax self.ax.set_xlim(xmin, xmax) self.ax.set_ylim(ymin*(1-sign(ymin)*0.05), ymax*(1+sign(ymax)*0.05)) #self.ax.set_yscale(self.scale) self.flush_plot() def SetYScale(self, scalestring): ''' SetYScale(self, scalestring) --> None Sets the y-scale of the main plotting axes. Currently accepts 'log' or 'lin'. ''' if self.ax: if scalestring == 'log': self.scale = 'log' self.AutoScale(force = True) try: self.ax.set_yscale('log') except OverflowError: self.AutoScale(force = True) elif scalestring == 'linear' or scalestring == 'lin': self.scale = 'linear' self.ax.set_yscale('linear') self.AutoScale(force = True) else: raise ValueError('Not allowed scaling') self.flush_plot() evt = state_changed(zoomstate = self.GetZoom(),\ yscale = self.GetYScale(), autoscale = self.autoscale) wx.PostEvent(self.callback_window, evt) self.WriteConfig() def GetYScale(self): '''GetYScale(self) --> String Returns the current y-scale in use. Currently the string 'log' or 'linear'. If the axes does not exist it returns None. ''' if self.ax: return self.ax.get_yscale() else: return None def CopyToClipboard(self, event = None): '''CopyToClipboard(self, event) --> None Copy the plot to the clipboard. ''' self.canvas.Copy_to_Clipboard(event = event) def PrintSetup(self, event = None): '''PrintSetup(self) --> None Sets up the printer. Creates a dialog box ''' self.fig_printer.pageSetup() def PrintPreview(self, event = None): '''PrintPreview(self) --> None Prints a preview on screen. ''' self.fig_printer.previewFigure(self.figure) def Print(self, event= None): '''Print(self) --> None Print the figure. ''' self.fig_printer.printFigure(self.figure) def SetCallbackWindow(self, window): '''SetCallbackWindow(self, window) --> None Sets the callback window that should recieve the events from picking. ''' self.callback_window = window def OnLeftDblClick(self, event): if self.ax and self.zoom: tmp = self.GetAutoScale() self.SetAutoScale(True) self.AutoScale() self.SetAutoScale(tmp) #self.AutoScale() #self.flush_plot() #self.ax.set_autoscale_on(False) def OnLeftMouseButtonDown(self, event): self.start_pos = event.GetPosition() #print 'Left Mouse button pressed ', self.ax.transData.inverse_xy_tup(self.start_pos) class Point: pass p = Point() p.x, p.y = self.start_pos size = self.canvas.GetClientSize() p.y = (size.height - p.y) if self.zoom and self.ax: if mat_ver > zoom_ver: in_axes = self.ax.in_axes(p) else: in_axes = self.ax.in_axes(*self.start_pos) if in_axes: self.zooming = True self.cur_rect = None self.canvas.CaptureMouse() else: self.zooming = False elif self.ax: size = self.canvas.GetClientSize() if mat_ver > zoom_ver: xy = self.ax.transData.inverted().transform(\ array([self.start_pos[0], size.height-self.start_pos[1]])\ [newaxis,:]) x, y = xy[0,0], xy[0,1] else: x, y = self.ax.transData.inverse_xy_tup(\ (self.start_pos[0], size.height - self.start_pos[1])) if self.callback_window: evt = plot_position(text = '(%.3e, %.3e)'%(x, y)) wx.PostEvent(self.callback_window, evt) #print x,y def OnMouseMove(self, event): if self.zooming and event.Dragging() and event.LeftIsDown(): self.cur_pos = event.GetPosition() #print 'Mouse Move ', self.ax.transData.inverse_xy_tup(self.cur_pos) class Point: pass p = Point() p.x, p.y = self.cur_pos size = self.canvas.GetClientSize() p.y = (size.height - p.y) if mat_ver > zoom_ver: in_axes = self.ax.in_axes(p) else: in_axes = self.ax.in_axes(*self.start_pos) if in_axes: new_rect = (min(self.start_pos[0], self.cur_pos[0]), min(self.start_pos[1], self.cur_pos[1]), abs(self.cur_pos[0] - self.start_pos[0]), abs(self.cur_pos[1] - self.start_pos[1])) self._DrawAndErase(new_rect, self.cur_rect) self.cur_rect = new_rect #event.Skip() def OnLeftMouseButtonUp(self, event): if self.canvas.HasCapture(): #print 'Left Mouse button up' self.canvas.ReleaseMouse() if self.zooming and self.cur_rect: # Note: The coordinte system for matplotlib have a different # direction of the y-axis and a different origin! size = self.canvas.GetClientSize() if mat_ver > zoom_ver: start = self.ax.transData.inverted().transform(\ array([self.start_pos[0], size.height-self.start_pos[1]])[newaxis,:]) end = self.ax.transData.inverted().transform(\ array([self.cur_pos[0], size.height-self.cur_pos[1]])[newaxis, :]) xend, yend = end[0,0], end[0,1] xstart, ystart = start[0,0], start[0,1] else: xstart, ystart = self.ax.transData.inverse_xy_tup(\ (self.start_pos[0], size.height-self.start_pos[1])) xend, yend = self.ax.transData.inverse_xy_tup(\ (self.cur_pos[0], size.height-self.cur_pos[1])) #print xstart, xend #print ystart, yend self.ax.set_xlim(min(xstart,xend), max(xstart,xend)) self.ax.set_ylim(min(ystart,yend), max(ystart,yend)) self.flush_plot() self.zooming = False def _DrawAndErase(self, box_to_draw, box_to_erase = None): '''_DrawAndErase(self, box_to_draw, box_to_erase = None) --> None ''' dc = wx.ClientDC(self.canvas) # dc.BeginDrawing() dc.SetPen(wx.Pen(wx.WHITE, 1, wx.DOT)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetLogicalFunction(wx.XOR) if box_to_erase: dc.DrawRectangle(*box_to_erase) dc.DrawRectangle(*box_to_draw) # dc.EndDrawing() def OnContextMenu(self, event): '''OnContextMenu(self, event) --> None Callback to show the popmenu for the plot which allows various settings to be made. ''' menu = wx.Menu() zoomID = wx.NewId() menu.AppendCheckItem(zoomID, "Zoom") menu.Check(zoomID, self.GetZoom()) def OnZoom(event): self.SetZoom(not self.GetZoom()) self.Bind(wx.EVT_MENU, OnZoom, id = zoomID) zoomallID = wx.NewId() menu.Append(zoomallID, 'Zoom All') def zoomall(event): tmp = self.GetAutoScale() self.SetAutoScale(True) self.AutoScale() self.SetAutoScale(tmp) #self.flush_plot() self.Bind(wx.EVT_MENU, zoomall, id = zoomallID) copyID = wx.NewId() menu.Append(copyID, "Copy") def copy(event): self.CopyToClipboard() self.Bind(wx.EVT_MENU, copy, id = copyID) yscalemenu = wx.Menu() logID = wx.NewId() linID = wx.NewId() yscalemenu.AppendRadioItem(logID, "log") yscalemenu.AppendRadioItem(linID, "linear") menu.AppendMenu(-1, "y-scale", yscalemenu) if self.GetYScale() == 'log': yscalemenu.Check(logID, True) else: yscalemenu.Check(linID, True) def yscale_log(event): if self.ax: self.SetYScale('log') self.AutoScale() self.flush_plot() def yscale_lin(event): if self.ax: self.SetYScale('lin') self.AutoScale() self.flush_plot() self.Bind(wx.EVT_MENU, yscale_log, id = logID) self.Bind(wx.EVT_MENU, yscale_lin, id = linID) autoscaleID = wx.NewId() menu.AppendCheckItem(autoscaleID, "Autoscale") menu.Check(autoscaleID, self.GetAutoScale()) def OnAutoScale(event): self.SetAutoScale(not self.GetAutoScale()) self.Bind(wx.EVT_MENU, OnAutoScale, id = autoscaleID) # Time to show the menu self.PopupMenu(menu) menu.Destroy() def flush_plot(self): #self._SetSize() #self.canvas.gui_repaint(drawDC = wx.PaintDC(self)) #self.ax.set_yscale(self.scale) self.canvas.draw() def update(self, data): pass