class Plot(wx.Panel): def __init__(self, parent, id=-1, dpi=None): ps = parent.GetSize() wx.Panel.__init__(self, parent, id=id, size=ps) self.SetBackgroundColour('WHITE') self.figure = mpl.figure.Figure(dpi=dpi, facecolor='w', figsize=(ps[0] * .09, ps[1] * .09)) #self.figure.SetBackgroundColour('WHITE') self.canvas = Canvas(self, -1, self.figure) self.canvas.SetBackgroundColour('WHITE') self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.doSave) def doSave(self, event): dlg = wx.FileDialog(self, message="Save file as ...", defaultDir=os.curdir, defaultFile="", wildcard="*.png", style=wx.FD_SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() dlg.Destroy() self.figure.savefig(path, dpi=None, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format='png', transparent=False, bbox_inches=None, pad_inches=0.1, frameon=None)
class RandomPanel(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) self._figure = Figure() self._axes = self._figure.add_subplot(1, 1, 1) self._canvas = FigureCanvas(self, -1, self._figure) self._sizer = wx.BoxSizer(wx.VERTICAL) self._sizer.Add(self._canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.SetSizer(self._sizer) self.Fit() self._scale = 2.0 self._canvas.Bind(wx.EVT_LEFT_DOWN, self.up) self._canvas.Bind(wx.EVT_RIGHT_DOWN, self.down) return def draw(self, size=200): im = numpy.empty([size, size]) import random for i in range(size): for j in range(size): im[i, j] = random.random() * self._scale plot = self._axes.imshow(im) plot.set_clim(0.0, 1.0) self._canvas.draw() return def up(self, event): self._scale += 0.1 self.draw() return def down(self, event): self._scale -= 0.1 self.draw() return
def __init__(self,parent,id,title): wx.Frame.__init__(self,parent,id,title,style= wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER, size = (480,640)) self.fig = Figure((6,6),dpi=80) panel = wx.Panel(self,-1) sizer = wx.BoxSizer(wx.VERTICAL) agg = FigureCanvasWxAgg(panel,-1,self.fig) self.point_x = [] self.point_y = [] sizer.Add(agg,0,wx.TOP) self.labelText = wx.StaticText(panel,-1,"You have not clicked! ") sizer.Add(self.labelText,0,wx.Top) panel.SetSizer(sizer) agg.Bind(wx.EVT_LEFT_DOWN,self.onLeftClick) self.clickcount = 0 self.draw_figure()
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 Frame(wx.Frame): def __init__(self): wx.Frame.__init__(self, parent=None, title="Colourmap Selection") self.figure = Figure(dpi=80, figsize=(2, 2)) self.canvas = Canvas(self, -1, self.figure) self.axes = self.figure.gca() x = y = numpy.linspace(-3, 3, 80) X, Y = numpy.meshgrid(x, y) V = numpy.sin(Y**2 + X**2) self.mapper = FigureImage(self.figure) im = self.axes.pcolor(x, y, V, shading='flat') try: cb = self.mapper.callbacksSM.connect('changed', ChangeCM(im)) except AttributeError: # Using 0.91 style self.mapper.add_observer(im) #self.figure.colorbar(self.mapper) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.canvas, 1, wx.EXPAND) self.SetSizer(sizer) self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnContext) def OnContext(self, evt): popup = wx.Menu() item = popup.Append(wx.ID_ANY, '&Grid on/off', 'Toggle grid lines') wx.EVT_MENU(self, item.GetId(), self.OnGridToggle) cmapmenu = CMapMenu(self, callback=self.OnColormap, mapper=self.mapper, canvas=self.canvas) item = popup.AppendMenu(wx.ID_ANY, "Colourmaps", cmapmenu) self.PopupMenu(popup, evt.GetPositionTuple()) def OnColormap(self, name): print "Selected colormap", name def OnGridToggle(self, event): self.axes.grid() self.canvas.draw_idle()
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 RegistrationPanel(wx.Panel): def __init__(self, parent, ID=-1, label="", pos=wx.DefaultPosition, size=(100, 25)): #(0) Initialize panel: wx.Panel.__init__(self, parent, ID, pos, size, style=wx.STATIC_BORDER | wx.WANTS_CHARS, name=label) self.SetMinSize(size) self.parent = parent self.q = [0, 0, 0, 1] self.th = 5 #(1) Create Matplotlib figure: self.figure = Figure(facecolor='0.8') self.canvas = FigureCanvasWxAgg(self, -1, self.figure) self._resize() self._create_axes() self.canvas.Bind(wx.EVT_KEY_DOWN, self.callback_key) self.canvas.Bind(wx.EVT_CHAR_HOOK, self.callback_key) def callback_key(self, event): keycode = event.GetKeyCode() #(0) Escape to exit: if keycode == wx.WXK_ESCAPE: ans = wx.MessageBox('Are you sure you want to quit?', '', wx.YES_NO | wx.CENTRE | wx.NO_DEFAULT, self) if ans == wx.YES: self.parent.quit() #(1) Enter to finish: if keycode == wx.WXK_RETURN: self.parent.forward() #(2) Update transformation parameters: amp = 0.1 + (event.ControlDown() * (1 - 0.1)) + (event.ShiftDown() * (5 - 0.1)) if keycode == wx.WXK_UP: self.q[1] += amp if keycode == wx.WXK_DOWN: self.q[1] -= amp if keycode == wx.WXK_LEFT: self.q[0] -= amp if keycode == wx.WXK_RIGHT: self.q[0] += amp if keycode == 328: self.q[0] -= amp if keycode == 330: self.q[0] += amp if keycode == 326: self.q[1] -= amp if keycode == 332: self.q[1] += amp if keycode in [91, 123]: self.q[2] += 0.2 * amp # '[' if keycode in [93, 125]: self.q[2] -= 0.2 * amp # ']' self.transform() def _create_axes(self): self.ax = self.figure.add_axes((0, 0, 1, 1), axisbg=[0.5] * 3) pyplot.setp(self.ax, xticks=[], yticks=[]) def _resize(self): szPixels = tuple(self.GetClientSize()) self.canvas.SetSize(szPixels) szInches = float(szPixels[0]) / self.figure.get_dpi(), float( szPixels[1]) / self.figure.get_dpi() self.figure.set_size_inches(szInches[0], szInches[1]) def cla(self): self.ax.cla() self.ax.set_position([0, 0, 1, 1]) self.ax.set_axis_bgcolor([0.5] * 3) pyplot.setp(self.ax, xticks=[], yticks=[], xlim=(0, 1), ylim=(0, 1)) self.ax.axis('tight') self.canvas.draw() def plot(self): #initial plot (after navigating to a new image) I = PM.transform2D(self.I, self.q) self.IT = I.copy() self.plot_source() # I[I==0] = np.nan # self.ax.imshow(I, interpolation='nearest', origin='lower', vmin=0, vmax=self.cmax) pyplot.setp(self.ax, xticks=[], yticks=[]) self.ax.set_axis_bgcolor([0.05] * 3) self.ax.axis('image') self.canvas.draw() def plot_source( self): #plot source (thresholded according to slider value) if self.ax.images: self.ax.images.pop(0) I = self.IT.copy() I[I <= self.th] = np.nan self.ax.imshow(I, interpolation='nearest', origin='lower', vmin=0, vmax=self.cmax) def plot_template( self, I0, th=0): #plot template (thresholded according to slider value) self.th = th if self.ax.collections: self.ax.collections.pop(0) self.ax.contour(I0 > th, 1, colors="0.5", linewidths=3) self.plot_source() self.canvas.draw() def set_Iq(self, I, q): self.I = I.copy() self.q = q self.cmax = 0.95 * I.max() def transform(self): #transform the source I = PM.transform2D(self.I, self.q) self.IT = I.copy() self.plot_source() self.canvas.draw()
class ModelView(wx.Panel): title = 'Profile' default_size = (600, 400) def __init__(self, *args, **kw): wx.Panel.__init__(self, *args, **kw) # Fig self.fig = Figure( figsize=(1, 1), dpi=75, facecolor='white', edgecolor='white', ) # Canvas self.canvas = FigureCanvas(self, -1, self.fig) self.fig.set_canvas(self.canvas) # Axes self.axes = self.fig.add_axes(Subplot(self.fig, 111)) self.axes.set_autoscale_on(False) self.theta_axes = self.axes.twinx() self.theta_axes.set_autoscale_on(False) # Show toolbar or not? self.toolbar = NavigationToolbar2WxAgg(self.canvas) self.toolbar.Show(True) # Create a figure manager to manage things self.figmgr = FigureManager(self.canvas, 1, self) # Panel layout self.profile_selector_label = wx.StaticText(self, label="Sample") self.profile_selector = wx.Choice(self) self.profile_selector.Hide() self.profile_selector_label.Hide() self.Bind(wx.EVT_CHOICE, self.OnProfileSelect) self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, border=2, flag=wx.LEFT | wx.TOP | wx.GROW) self.tbsizer = wx.BoxSizer(wx.HORIZONTAL) self.tbsizer.Add(self.toolbar, 0, wx.ALIGN_CENTER_VERTICAL) self.tbsizer.AddSpacer(20) self.tbsizer.Add(self.profile_selector_label, 0, wx.ALIGN_CENTER_VERTICAL) self.tbsizer.AddSpacer(5) self.tbsizer.Add(self.profile_selector, 0, wx.ALIGN_CENTER_VERTICAL) self.sizer.Add(self.tbsizer) self.SetSizer(self.sizer) self.sizer.Fit(self) # Status bar frame = self.GetTopLevelParent() self.statusbar = frame.GetStatusBar() if self.statusbar is None: self.statusbar = frame.CreateStatusBar() status_update = lambda msg: self.statusbar.SetStatusText(msg) # Set the profile interactor self.profile = ProfileInteractor(self.axes, self.theta_axes, status_update=status_update) # Add context menu and keyboard support to canvas self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnContextMenu) #self.canvas.Bind(wx.EVT_LEFT_DOWN, lambda evt: self.canvas.SetFocus()) self.model = None self._need_interactors = self._need_redraw = False self.Bind(wx.EVT_SHOW, self.OnShow) def OnContextMenu(self, event): """ Forward the context menu invocation to profile, if profile exists. """ sx, sy = event.GetX(), event.GetY() #transform = self.axes.transData #data_x,data_y = pixel_to_data(transform, sx, self.fig.bbox.height-sy) popup = wx.Menu() item = popup.Append(wx.ID_ANY, '&Grid on/off', 'Toggle grid lines') wx.EVT_MENU(self, item.GetId(), lambda _: (self.axes.grid(), self.fig.canvas.draw_idle())) item = popup.Append(wx.ID_ANY, '&Rescale', 'Show entire profile') wx.EVT_MENU( self, item.GetId(), lambda _: (self.profile.reset_limits(), self.profile.draw_idle())) self.PopupMenu(popup, (sx, sy)) return False def OnProfileSelect(self, event): self._set_profile(*self.profiles[event.GetInt()]) # ==== Model view interface === def OnShow(self, event): if not event.Show: return #print "showing profile" if self._need_redraw: self.redraw(reset_interactors=False, reset_limits=True) #event.Skip() def get_state(self): return self.model def set_state(self, state): self.set_model(state) def set_model(self, model): # print ">>>>>>> refl1d profile set model" self.model = model self.redraw(reset_interactors=True, reset_limits=True) def update_model(self, model): # print ">>>>>>> refl1d profile update model" if self.model == model: self.redraw(reset_interactors=False, reset_limits=True) def update_parameters(self, model): # print ">>>>>>> refl1d profile update parameters" if self.model == model: self.redraw(reset_interactors=False, reset_limits=False) def redraw(self, reset_interactors=False, reset_limits=False): if reset_interactors: self._need_interactors = True if not self.IsShown(): self._need_redraw = True return if self._need_interactors: self._create_interactors() self._set_profile(*self.profiles[0]) self._need_interactors = False self.profile.redraw(reset_limits=reset_limits) # ============================================= def _create_interactors(self): self.profiles = [] def add_profiles(name, exp, idx): if isinstance(exp, MixedExperiment): for i, p in enumerate(exp.parts): self.profiles.append((name + chr(ord("a") + i), p, idx)) else: self.profiles.append((name, exp, idx)) if isinstance(self.model, MultiFitProblem): for i, p in enumerate(self.model.models): if hasattr(p.fitness, "reflectivity"): name = p.fitness.name if not name: name = "M%d" % (i + 1) add_profiles(name, p.fitness, i) else: add_profiles("", self.model.fitness, -1) self.profile_selector.Clear() if len(self.profiles) > 1: self.profile_selector.AppendItems([k for k, _, _ in self.profiles]) self.profile_selector_label.Show() self.profile_selector.Show() self.profile_selector.SetSelection(0) else: self.profile_selector_label.Hide() self.profile_selector.Hide() def _set_profile(self, name, experiment, idx): # Turn the model into a user interface # It is the responsibility of the party that is indicating # that a redraw is necessary to clear the precalculated # parts of the view; otherwise the theory function calculator # is going to be triggered twice. This happens inside profile # before the profile is calculated. Note that the profile # panel will receive its own signal, which will cause the # profile interactor to draw itself again. We hope this isn't # too much of a problem. def signal_update(): """Notify other views that the model has changed""" signal.update_parameters(model=self.model) def force_recalc(): self.model.model_update() if isinstance(self.model, MultiFitProblem): self.model.set_active_model(idx) self.profile.set_experiment(experiment, force_recalc=force_recalc, signal_update=signal_update) def onPrinterSetup(self, event=None): self.canvas.Printer_Setup(event=event) def onPrinterPreview(self, event=None): self.canvas.Printer_Preview(event=event) def onPrint(self, event=None): self.canvas.Printer_Print(event=event) def OnSaveFigureMenu(self, evt): """ Save the current figure as an image file """ dlg = wx.FileDialog( self, message="Save Figure As ...", defaultDir=os.getcwd(), defaultFile="", wildcard= "PNG files (*.png)|*.png|BMP files (*.bmp)|*.bmp|All files (*.*)|*.*", style=wx.SAVE) _val = dlg.ShowModal() if _val == wx.ID_CANCEL: return #Do nothing if _val == wx.ID_OK: outfile = dlg.GetPath() dlg.Destroy() # Save self.fig.savefig(outfile) def GetToolBar(self): """ backend_wx call this function. KEEP it """ return None def OnPanelFrameClose(self, evt): """ On Close this Frame """ self.Destroy() evt.Skip() def OnCopyFigureMenu(self, evt): """ Copy the current figure """ CopyImage(self.canvas) def CanShowContextMenu(self): return True def quit_on_error(self): numpy.seterr(all='raise') ProfileInteractor._debug = True BaseInteractor._debug = True
class PanelSpec(wx.Panel): def __init__(self, parent, parentMainFrame): wx.Panel.__init__(self, parent) self.CreatePanel() self.setSpLabel() self.parent = parentMainFrame self.FFT_Max_X = 5995 self.FFT_Min_X = 70 self.FFT_Max_Y = 60 self.FFT_Min_Y = -120 ######## upload ########### self.start_upload = 0 ###### download ######### self.download = 0 self.dir = "" ############################ self.thread = 0 def getstartUploadOnce(self): return self.start_upload def getisDownLoad(self): return self.download def getDownloadDir(self): return self.dir def restore2unstart(self): self.start_upload = 0 def restoreisDownLoad(self): self.download = 0 ###################################################### def CreatePanel(self): self.Figure = matplotlib.figure.Figure() self.axes = self.Figure.add_axes([0.05, 0.05, 0.93, 0.93]) self.FigureCanvas = FigureCanvas(self, -1, self.Figure) self.ButtonAutoY = wx.Button(self, -1, label=u"纵轴恢复") self.ButtonAutoX = wx.Button(self, -1, label=u"横轴恢复") self.Max_Y = wx.TextCtrl(self, -1, '60', size=(60, 20), style=wx.TE_PROCESS_ENTER) self.Min_Y = wx.TextCtrl(self, -1, '-120', size=(60, 20), style=wx.TE_PROCESS_ENTER) self.Min_X = wx.TextCtrl(self, -1, '70', size=(60, 20), style=wx.TE_PROCESS_ENTER) self.Max_X = wx.TextCtrl(self, -1, '5995', size=(60, 20), style=wx.TE_PROCESS_ENTER) self.Upload = wx.Button(self, -1, label=u"数据上传") self.Download = wx.Button(self, -1, label=u"本地存储") ###################################test sizer############################## self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) bSizer4 = wx.BoxSizer(wx.VERTICAL) gSizer6 = wx.GridSizer(1, 7, 0, 0) gSizer6.Add(self.ButtonAutoX, 0, wx.ALL | wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT, 5) gSizer6.Add(self.ButtonAutoY, 0, wx.ALL, 5) gSizer6.AddSpacer((0, 0), 1, wx.EXPAND, 5) gSizer6.AddSpacer((0, 0), 1, wx.EXPAND, 5) gSizer6.AddSpacer((0, 0), 1, wx.EXPAND, 5) gSizer6.Add(self.Upload, 0, wx.ALL | wx.ALIGN_RIGHT, 5) gSizer6.Add(self.Download, 0, wx.ALL | wx.ALIGN_LEFT, 5) bSizer4.Add(gSizer6, 0, wx.EXPAND, 5) bSizer5 = wx.BoxSizer(wx.HORIZONTAL) gSizer8 = wx.GridSizer(2, 1, 0, 0) gSizer8.Add(self.Max_Y, 0, wx.ALL, 5) gSizer8.Add(self.Min_Y, 0, wx.ALIGN_BOTTOM | wx.ALL, 5) bSizer5.Add(gSizer8, 0, wx.EXPAND, 5) gSizer10 = wx.GridSizer(1, 1, 0, 0) gSizer10.Add(self.FigureCanvas, 1, wx.ALL | wx.EXPAND, 5) bSizer5.Add(gSizer10, 5, wx.EXPAND, 5) bSizer4.Add(bSizer5, 4, wx.EXPAND, 5) gSizer9 = wx.GridSizer(1, 2, 0, 0) # gSizer9.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) # self.m_textCtrl16 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 80,-1 ), 0 ) gSizer9.Add(self.Min_X, 0, wx.ALL, 5) # self.m_textCtrl17 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 80,-1 ), 0 ) gSizer9.Add(self.Max_X, 0, wx.ALIGN_RIGHT | wx.ALL, 5) bSizer4.Add(gSizer9, 0, wx.EXPAND, 5) self.SetSizer(bSizer4) self.Layout() self.Centre(wx.BOTH) ##################################################################################### self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMin_X, self.Min_X) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMax_X, self.Max_X) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMax_Y, self.Max_Y) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMin_Y, self.Min_Y) self.Bind(wx.EVT_BUTTON, self.OnAutoX, self.ButtonAutoX) self.Bind(wx.EVT_BUTTON, self.OnAutoY, self.ButtonAutoY) self.Bind(wx.EVT_BUTTON, self.OnUpload, self.Upload) self.Bind(wx.EVT_BUTTON, self.OnDownload, self.Download) self.popupmenu = wx.Menu() StringList = ["Add Marker", "Remove Marker", "All Marker Off"] for text in StringList: item = self.popupmenu.Append(-1, text) self.FigureCanvas.Bind(wx.EVT_CONTEXT_MENU, self.OnShowPopup) self.FigureCanvas.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item) ''' Array=linspace(70, 5995,238) self.xDataList=[] self.LineSpec=[] self.LineSpecBack=[] for i in xrange(237): xData=linspace(Array[i],Array[i+1],1024) self.xDataList.append(xData) ydata=[0]*1024 for xData in self.xDataList: lineSpec,=self.axes.plot(xData,ydata,'y') lineSpecBack,=self.axes.plot(xData,ydata,'r') self.LineSpec.append(lineSpec) self.LineSpecBack.append(lineSpecBack) ''' self.xData = linspace(70, 6470, 1024) self.yData = [0] * 1024 self.lineSpec, = self.axes.plot(self.xData, self.yData, 'y') self.lineSpecBack, = self.axes.plot(self.xData, self.yData, 'r') ####Marker############ self.drs = [] def OnUpload(self, event): self.start_upload = 1 def OnDownload(self, event): if (self.Download.GetLabel() == "LocalSave"): ''' dlg=dialog_download(self) dlg.ShowModal() if(dlg.isValid): self.dir=dlg.m_dirPick.GetPath() print self.dir ''' self.download = 1 self.Download.SetLabel(u"停止存储") '''start the thread localsave''' if (self.thread == 0): self.thread = thread_localsave.LocalSaveThread( self.parent, self.parent.queueFFTLocalSave, self.parent.queueAbLocalSave) self.thread.start() else: self.thread.event.set() else: '''stop the thread localsave''' self.thread.stop() self.Download.SetLabel(u"本地存储") self.download = 0 def OnAutoX(self, event): self.setSpLabel(begin_X=self.parent.FreqMin,end_X=self.parent.FreqMax , \ begin_Y=self.FFT_Min_Y,end_Y=self.FFT_Max_Y) self.FigureCanvas.draw() self.FFT_Min_X = self.parent.FreqMin self.FFT_Max_X = self.parent.FreqMax self.Min_X.SetValue(str(self.FFT_Min_X)) self.Max_X.SetValue(str(self.FFT_Max_X)) def OnAutoY(self, event): self.setSpLabel(begin_X=self.FFT_Min_X, end_X=self.FFT_Max_X) self.FigureCanvas.draw() self.FFT_Min_Y = -120 self.FFT_Max_Y = 60 self.Min_Y.SetValue("-120") self.Max_Y.SetValue("60") def OnEnterMin_X(self, event): self.FFT_Min_X = int(self.Min_X.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnEnterMax_X(self, event): self.FFT_Max_X = int(self.Max_X.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnEnterMin_Y(self, event): self.FFT_Min_Y = int(self.Min_Y.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnEnterMax_Y(self, event): self.FFT_Max_Y = int(self.Max_Y.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnShowPopup(self, event): pos = event.GetPosition() pos = self.FigureCanvas.ScreenToClient(pos) self.FigureCanvas.PopupMenu(self.popupmenu, pos) def OnPopupItemSelected(self, event): item = self.popupmenu.FindItemById(event.GetId()) text = item.GetText() if (text == "Add Marker"): self.OnAddMarker() elif (text == "Remove Marker"): self.OnRemove() elif (text == "All Marker Off"): self.OnAllRemove() def DrawMarker(self, Max_X, Max_Y): distance = ((self.FFT_Max_X - self.FFT_Min_X) / 10)**2 index = len(self.drs) + 1 rect, = self.axes.plot(Max_X, Max_Y, 'rd', markersize=10) text = self.axes.text(Max_X + 5, Max_Y + 2, 'M' + str(index), color='r') textM=self.axes.text(self.FFT_Min_X+5,self.FFT_Max_Y-5*(index),'M'+str(index)+':' \ +'%.2f'%(Max_X)+'MHz '+'%.2f'%(Max_Y)+'dBm') # DragRect=DraggableRectangle(rect,text,textM,self.LineSpec,self.FigureCanvas) # DragRect.setM_id('M'+str(index)+':') # # DragRect.setRadius(distance) # DragRect.connect() # self.drs.append(DragRect) #self.FigureCanvas.draw() def OnAddMarker(self): if (len(self.drs) < 4): startSection = (self.FFT_Min_X - 70) / 25 endSection = (self.FFT_Max_X - 70) / 25 lenStart = len(self.LineSpec[startSection].get_ydata()) lenEnd = len(self.LineSpec[endSection].get_ydata()) indexStart = int( (self.FFT_Min_X - (startSection * 25 + 70)) * lenStart / 25.0) indexEnd = int( (self.FFT_Max_X - (endSection * 25 + 70)) * lenEnd / 25.0) MaxList = [] MaxList.append( max( list(self.LineSpec[startSection].get_ydata()) [indexStart:lenStart])) for i in range(startSection + 1, endSection, 1): MaxList.append(max(list(self.LineSpec[i].get_ydata()))) if (indexEnd != 0): MaxList.append( max( list(self.LineSpec[endSection].get_ydata()) [0:indexEnd])) Max_Y = max(MaxList) Max_Y_Index = MaxList.index(Max_Y) + startSection y = self.LineSpec[Max_Y_Index].get_ydata() Max_X_Index = list(y).index(Max_Y) Max_X = 70 + Max_Y_Index * 25 + Max_X_Index * 25.0 / len(y) self.DrawMarker(Max_X, Max_Y) def OnRemove(self): if (len(self.axes.texts)): self.axes.lines.pop() self.axes.texts.pop() self.axes.texts.pop() self.drs.pop() #self.FigureCanvas.draw() def OnAllRemove(self): while (len(self.axes.texts)): self.axes.lines.pop() self.axes.texts.pop() self.axes.texts.pop() self.drs.pop() #self.FigureCanvas.draw() def setSpLabel(self, begin_X=70, end_X=5995, begin_Y=-120, end_Y=60): self.ylabel('dBm') self.xlabel('MHz') self.ylim(begin_Y, end_Y) self.xlim(begin_X, end_X) yticks = linspace(begin_Y, end_Y, 11) ##11个数总共### yticklabels = [str(int(i)) for i in yticks] xticks = linspace(begin_X, end_X, 11) xticklabels = [str('%0.1f' % (i)) for i in xticks] self.axes.set_xticks(xticks) self.axes.set_xticklabels(xticklabels, rotation=0) self.axes.set_yticks(yticks) self.axes.set_yticklabels(yticklabels, rotation=0) self.axes.grid(True) #self.FigureCanvas.draw() def PowerSpectrum(self, funcPara, y): if (funcPara == 0x51 or funcPara == 0x56): self.lineSpec.set_ydata(array(y)) ''' for i in range(len(self.drs)): self.drs[i].yData=self.LineSpec self.DrawAfterRelease() ''' elif (funcPara == 0x52 or funcPara == 0x57): self.lineSpecBack.set_ydata(array(y)) self.FigureCanvas.draw() def DrawAfterRelease(self): for i in range(len(self.drs)): xData = self.drs[i].rect.get_xdata() index = (int(xData) - 70) / 25 Section = index * 25 + 70 y = self.LineSpec[index].get_ydata() index_Y = (xData - Section) * len(y) / 25.0 Marker_Y = list(y)[int(index_Y)] self.drs[i].rect.set_ydata(Marker_Y) self.drs[i].textMarker.set_position((xData, Marker_Y + 2)) self.drs[i].textM.set_text(self.drs[i].M_index+'%.2f'%(xData)+ \ 'MHz '+'%.2f'%(Marker_Y)+'dBm') def xlim(self, x_min, x_max): self.axes.set_xlim(x_min, x_max) def ylim(self, y_min, y_max): self.axes.set_ylim(y_min, y_max) def xlabel(self, XabelString="X"): self.axes.set_xlabel(XabelString) def ylabel(self, YabelString="Y"): self.axes.set_ylabel(YabelString)
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 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 RightGraph(wx.Panel): def __init__(self, parent, statusbar): wx.Panel.__init__(self, parent, wx.ID_ANY) self.statusbar = statusbar self.fig = Figure((7.0, 6.0)) self.canvas = FigCanvas(self, -1, self.fig) self.fig.patch.set_facecolor(colorBackgroundGraph) self.ax = self.fig.add_subplot(111) self.ax.set_ylabel("Intensity (a.u.)", fontdict=font) self.ax.set_xlabel(r'2$\theta$ (deg.)', fontdict=font) self.toolbar = NavigationToolbar(self.canvas) self.toolbar.Hide() self.canvas.toolbar.zoom() self.toolbar.Disable() self.ly = self.ax.axvline(color='r', lw=0.0) # the vert line self.lx = self.ax.axhline(color='r', lw=0.0) # the horiz line if not hasattr(self, "UnzoomID"): self.UnzoomID = wx.NewId() self.CheckedGridId = wx.NewId() self.CursorId = wx.NewId() self.Bind(wx.EVT_MENU, self.OnUnzoom, id=self.UnzoomID) self.Bind(wx.EVT_MENU, self.CheckedGrid, id=self.CheckedGridId) self.Bind(wx.EVT_MENU, self.CursorMove, id=self.CursorId) """build the menu""" self.menu = wx.Menu() self.item_unzoom = self.menu.Append(self.UnzoomID, "Unzoom") self.item_grid = self.menu.Append(self.CheckedGridId, "Show/Hide grid", kind=wx.ITEM_CHECK) self.item_cursor = self.menu.Append(self.CursorId, "Show/Hide cursor", kind=wx.ITEM_CHECK) self.item_unzoom.Enable(False) self.item_grid.Enable(False) self.item_cursor.Enable(False) self.connect = self.canvas.mpl_connect self.disconnect = self.canvas.mpl_disconnect self.update_zoom = self.connect('motion_notify_event', self.MouseOnGraph) self.update_coord = self.connect('motion_notify_event', self.on_update_coordinate) self.disconnect(self.update_zoom) self.disconnect(self.update_coord) self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.c_data = "" self.c_fit = "" self.c_live = "" self.l_data = "" self.l_fit = "" self.l_live = "" mastersizer = wx.BoxSizer(wx.VERTICAL) mastersizer.Add(self.canvas, 1, wx.EXPAND) mastersizer.Add(self.toolbar, 0, wx.EXPAND) pub.subscribe(self.OnDrawGraph, pubsub_Draw_XRD) pub.subscribe(self.OnDrawGraphLive, pubsub_Draw_Fit_Live_XRD) pub.subscribe(self.onFit, pubsub_OnFit_Graph) pub.subscribe(self.on_color, pubsub_Graph_change_color_style) self.on_color() self.SetSizer(mastersizer) self.Layout() self.Fit() def on_color(self): a = P4Rm() self.c_data = a.DefaultDict['c_data'] self.c_fit = a.DefaultDict['c_fit'] self.c_live = a.DefaultDict['c_fit_live'] self.l_data = a.DefaultDict['l_data'] self.l_fit = a.DefaultDict['l_fit'] self.l_live = a.DefaultDict['l_fit_live'] self.c_bkg = a.DefaultDict['c_graph_background'] def OnDrawGraph(self, b=None): a = P4Rm() self.ax.clear() if b == 1: self.ax.semilogy(2 * a.ParamDict['th'] * 180 / np.pi, a.ParamDict['Iobs'], 'o-k') elif b == 2: self.ax.set_xlim([0, 1]) self.ax.set_ylim([0, 1]) self.ax.clear() else: a = P4Rm() xx = 2 * a.ParamDict['th'] * 180 / np.pi Iobs_len = len(a.ParamDict['Iobs']) I_i_len = len(a.ParamDict['I_i']) if Iobs_len == I_i_len: I_val = a.ParamDict['I_i'] else: I_val = a.ParamDictbackup['I_i'] self.ax.semilogy(xx, a.ParamDict['Iobs'], color=self.c_data, ls=self.l_data, marker='o') self.ax.semilogy(xx, I_val, color=self.c_fit, ls=self.l_fit) middle = int(len(a.ParamDict['th']) / 2) self.ly = self.ax.axvline(x=xx[middle], color='r', lw=0.0) self.lx = self.ax.axhline(color='r', lw=0.0) # the horiz line self.ax.set_ylabel("Intensity (a.u.)", fontdict=font) self.ax.set_xlabel(r'2$\theta$ (deg.)', 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.CheckedGrid() self.CursorMove() def OnDrawGraphLive(self, val=None): a = P4Rm() if val != []: P4Rm.ParamDict['I_fit'] = val self.ax.clear() self.ax.semilogy(a.ParamDict['th4live'], a.ParamDict['Iobs'], color=self.c_data, ls=self.l_data, marker='o') self.ax.semilogy(a.ParamDict['th4live'], a.ParamDict['I_fit'], color=self.c_live, ls=self.l_live) self.ax.set_ylabel("Intensity (a.u.)", fontdict=font) self.ax.set_xlabel(r'2$\theta$ (deg.)', fontdict=font) self.canvas.draw() def onFit(self, b=None): if b == 1: self.update_zoom = self.connect('motion_notify_event', self.MouseOnGraph) self.update_coord = self.connect('motion_notify_event', self.on_update_coordinate) self.item_unzoom.Enable(True) self.item_grid.Enable(True) self.item_cursor.Enable(True) else: self.disconnect(self.update_zoom) self.disconnect(self.update_coord) self.menu.Check(self.CursorId, check=False) self.item_unzoom.Enable(False) self.item_grid.Enable(False) self.item_cursor.Enable(False) self.ly.set_linewidth(0) self.lx.set_linewidth(0) def MouseOnGraph(self, event): a = P4Rm() if a.fitlive == 1: return if event.inaxes != None: if a.ParamDict['Iobs'] != "": xlim = self.ax.get_xlim() xlim_min = xlim[0] * np.pi / (2 * 180) xlim_max = xlim[1] * np.pi / (2 * 180) itemindex = where((a.ParamDictbackup['th'] > xlim_min) & (a.ParamDictbackup['th'] < xlim_max)) t1 = itemindex[0][0] t2 = itemindex[0][-1] P4Rm.ParamDict['th'] = a.ParamDictbackup['th'][t1:t2] P4Rm.ParamDict['Iobs'] = a.ParamDictbackup['Iobs'][t1:t2] P4Rm.ParamDict['th4live'] = 2 * a.ParamDict['th'] * 180 / np.pi def OnRightDown(self, event): a = P4Rm() if a.fitlive == 1: return else: self.PopupMenu(self.menu) def OnUnzoom(self, event=None): self.canvas.toolbar.home() P4Rm.zoomOn = 0 a = P4Rm() P4Rm.ParamDict['th'] = a.ParamDictbackup['th'] P4Rm.ParamDict['Iobs'] = a.ParamDictbackup['Iobs'] P4Rm.ParamDict['th4live'] = 2 * a.ParamDict['th'] * 180 / np.pi pub.sendMessage(pubsub_Re_Read_field_paramters_panel) self.CheckedGrid() self.CursorMove() def CheckedGrid(self, event=None): if self.menu.IsChecked(self.CheckedGridId) is True: self.ax.grid(True, color='gray') elif self.menu.IsChecked(self.CheckedGridId) is False: self.ax.grid(False) self.canvas.draw() def CursorMove(self, event=None): if self.menu.IsChecked(self.CursorId) is True: self.ly.set_linewidth(1) self.lx.set_linewidth(1) elif self.menu.IsChecked(self.CursorId) is False: self.ly.set_linewidth(0) self.lx.set_linewidth(0) def on_update_coordinate(self, event): if event.inaxes is None: self.statusbar.SetStatusText(u"", 1) self.statusbar.SetStatusText(u"", 2) return else: x, y = event.xdata, event.ydata self.ly.set_xdata(x) self.lx.set_ydata(y) xfloat = round(float(x), 4) yfloat = round(float(y), 8) self.statusbar.SetStatusText(u"x = " + str(xfloat), 1) self.statusbar.SetStatusText(u"y = " + str(yfloat), 2) self.canvas.draw()
class RTPWindow(wx.Frame): #########################Init Funcions############################# def __init__(self,parent=None,dpi=100,geoid=Geodesic.WGS84,resolution="50m",center_lon=0.,fontsize=8, verbose=False): """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="Pole Plot %s"%parent.__version__,style=default_style, size=(600*2,600*2)) self.Bind(wx.EVT_CLOSE, self.on_close_main) self.parent=parent if not pymax_found: self.parent.user_warning("PyRot module PyMax not found, pole plot viewer will not be usable"); self.on_close_window(-1) else: self.parent.rtp_open=True self.center_lon = center_lon self.dpi = dpi self.geoid = geoid self.resolution = resolution self.fontsize = fontsize self.verbose = verbose self.poles_to_plot = [] 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 DropDown Box-----------------------------------------------------# latlon_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Window Boundaries"), wx.VERTICAL) proj_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Choose Projection"), wx.VERTICAL) refresh_sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, wx.ID_ANY, "Refresh Figure"), wx.HORIZONTAL) projs = ["North Polar Stereographic","South Polar Stereographic","Orthographic"] self.proj_box = wx.ComboBox(self.panel, id=wx.ID_ANY,size=(100, 25), value=projs[0], choices=projs, style=wx.CB_DROPDOWN|wx.TE_READONLY) self.Bind(wx.EVT_COMBOBOX, self.on_select_proj,self.proj_box) self.max_lat_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25)) self.min_lat_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25)) self.max_lon_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25)) self.min_lon_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(25,25)) # self.down_sample_box = wx.TextCtrl(self.panel, id=wx.ID_ANY|wx.TE_CENTRE, size=(50,25))\ self.re_render_button = wx.Button(self.panel, id=wx.ID_ANY, label='Refresh Figure',size=(50,25)) self.Bind(wx.EVT_BUTTON, self.on_re_render_button, self.re_render_button) self.add_pole_button = wx.Button(self.panel, id=wx.ID_ANY, label='Add Pole',size=(50,25)) self.Bind(wx.EVT_BUTTON, self.on_add_pole_button, self.add_pole_button) #Projection sizer proj_sizer.Add(self.proj_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing) #Lat-Lon Sizer lat_sizer = wx.BoxSizer(wx.HORIZONTAL) lat_sizer.AddMany([(self.min_lat_box, 1, wx.ALIGN_LEFT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing), (self.max_lat_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_TOP|wx.EXPAND|wx.ALL, spacing)]) lon_sizer = wx.BoxSizer(wx.HORIZONTAL) lon_sizer.AddMany([(self.min_lon_box, 1, wx.ALIGN_LEFT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing), (self.max_lon_box, 1, wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing)]) latlon_sizer.AddMany([(lat_sizer, 1, wx.ALIGN_TOP|wx.EXPAND, spacing), (lon_sizer, 1, wx.ALIGN_BOTTOM|wx.EXPAND, spacing)]) #Downsample sizer with downsample box and refresh button refresh_sizer.AddMany([(self.re_render_button, 1, wx.ALIGN_LEFT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing), (self.add_pole_button, 1, wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM|wx.EXPAND|wx.ALL, spacing)]) #Combine projection and downsample sizers proj_ds_sizer = wx.BoxSizer(wx.VERTICAL) proj_ds_sizer.AddMany([(proj_sizer, 1, wx.ALIGN_TOP|wx.EXPAND, spacing), (refresh_sizer, 1, wx.ALIGN_BOTTOM|wx.EXPAND, spacing)]) #Combine all in final sizer all_txt_btn_sizer = wx.BoxSizer(wx.HORIZONTAL) all_txt_btn_sizer.AddMany([(proj_ds_sizer, 1, wx.ALIGN_LEFT|wx.EXPAND, spacing), (latlon_sizer, 1, wx.ALIGN_RIGHT|wx.EXPAND, spacing)]) #-------------------------------------Make Figure----------------------------------------------------------# self.fig = Figure((2, 2), dpi=self.dpi) self.canvas = FigCanvas(self.panel, -1, self.fig) self.toolbar = NavigationToolbar(self.canvas) self.ax = self.fig.add_subplot(111) 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_DCLICK, self.on_select_dleft_click) self.canvas.Bind(wx.EVT_RIGHT_DCLICK, self.on_select_dright_click) #----------------------------------Build UI and Fit--------------------------------------------------------# outer_sizer = wx.BoxSizer(wx.VERTICAL) outer_sizer.AddMany([#(grd_sizer,1,wx.ALIGN_CENTER|wx.ALIGN_TOP|wx.EXPAND|wx.LEFT|wx.RIGHT,spacing), (all_txt_btn_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() m_import_poles = menu_file.Append(-1, "&Import Poles From CSV", "ImportPoles") self.Bind(wx.EVT_MENU, self.on_import_poles, m_import_poles) menu_file.AppendSeparator() submenu_save_plots = wx.Menu() m_save_plot = submenu_save_plots.Append(-1, "&Save Plot", "") self.Bind(wx.EVT_MENU, self.on_save_plot, m_save_plot,"save-plot") m_new_sub_plots = menu_file.Append(-1, "&Save Result", submenu_save_plots) menu_file.AppendSeparator() m_exit = menu_file.Append(-1, "&Exit\tCtrl-Q", "Exit") self.Bind(wx.EVT_MENU, self.on_close_main, m_exit) #----------------- # Edit Menu #----------------- menu_edit = wx.Menu() self.m_remove_pole = menu_edit.Append(-1, "&Remove Last Pole\tCtrl-Z", "RemovePole") self.Bind(wx.EVT_MENU, self.on_remove_pole, self.m_remove_pole) self.m_remove_all_poles = menu_edit.Append(-1, "&Remove All Poles\tCtrl-Z", "RemovePolesAll") self.Bind(wx.EVT_MENU, self.on_remove_all_poles, self.m_remove_all_poles) self.m_add_strike_unc = menu_edit.AppendCheckItem(-1, "&Add Strike Uncertainty\tCtrl-R", "CalcStrikes") self.Bind(wx.EVT_MENU, self.on_add_strike_unc, self.m_add_strike_unc) self.m_solve_askw = menu_edit.AppendCheckItem(-1, "&Solve for Anomalous Skewness\tCtrl-A-R", "SolveAskw") self.Bind(wx.EVT_MENU, self.on_solve_askw, self.m_solve_askw) #----------------- # View Menu #----------------- menu_view = wx.Menu() self.m_show_lunes = menu_view.AppendCheckItem(-1, "&Show Lunes", "ShowLunes") self.m_show_lunes.Check() self.Bind(wx.EVT_MENU, self.on_show_lunes, self.m_show_lunes) self.m_show_pole = menu_view.AppendCheckItem(-1, "&Show Pole", "ShowPole") # self.m_show_pole.Check() self.Bind(wx.EVT_MENU, self.on_show_pole, self.m_show_pole) self.m_show_a95 = menu_view.AppendCheckItem(-1, "&Show A95", "ShowA95") self.m_show_a95.Check() self.Bind(wx.EVT_MENU, self.on_show_a95, self.m_show_a95) self.m_show_selected = menu_view.AppendCheckItem(-1, "&Show Selected", "ShowSelected") self.m_show_selected.Check() self.Bind(wx.EVT_MENU, self.on_show_selected, self.m_show_selected) #----------------- self.menubar.Append(menu_file, "&File") self.menubar.Append(menu_edit, "&Edit") self.menubar.Append(menu_view, "&View") self.SetMenuBar(self.menubar) def configure(self): self.min_lat_box.SetValue("%.1f"%60.) self.max_lat_box.SetValue("%.1f"%90.) self.min_lon_box.SetValue("%.1f"%-180.) self.max_lon_box.SetValue("%.1f"%180.) self.window = [None,None,None,None] #########################Update UI Funcions############################# def update(self): #Populates Logger and makes plot self.make_map() #Make Background Map if self.m_show_pole.IsChecked(): if len(self.parent.deskew_df[self.parent.deskew_df["track_type"]=="ship"]) > 0: self.parent.save_max_file(".tmp.max",ship_only=True) #Save tmp max file to disk for debugging purposes and to more easily punch data into format using previous functions comment,header,ship_data = pymax.read_max_file(".tmp.max") #Read max file if len(ship_data["phs"])>2: #If more than 2 profiles (even-determined) invert ship (plat,plon,pmag,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(ship_data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment) s1_ship = np.sqrt(chisq/dof)*ship_data["phs"][0][1][1] #ship 1sigma else: s1_ship = 0 else: ship_data,s1_ship = {"phs":[["none",[0.,0.]]]},0 if len(self.parent.deskew_df[self.parent.deskew_df["track_type"]=="aero"]) > 0: self.parent.save_max_file(".tmp.max",aero_only=True) #Do same for aero only data comment,header,aero_data = pymax.read_max_file(".tmp.max") if len(aero_data["phs"])>2: (plat,plon,pmag,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(aero_data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment) s1_aero = np.sqrt(chisq/dof)*aero_data["phs"][0][1][1] else: s1_aero = 0 else: aero_data,s1_aero = {"phs":[["none",[0.,0.]]]},0 self.parent.save_max_file(".tmp.max") #now read all data and change s1 to match above comment,header,data = pymax.read_max_file(".tmp.max") if len(data["phs"])==0: return for i in range(len(data["phs"])): if len(ship_data["phs"]) > 0 and data["phs"][i][1][1]==ship_data["phs"][0][1][1]: data["phs"][i][1][1] = s1_ship elif len(aero_data["phs"]) > 0 and data["phs"][i][1][1]==aero_data["phs"][0][1][1]: data["phs"][i][1][1] = s1_aero if self.m_solve_askw.IsChecked(): (plat,plon,pmag,askw,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment, solve_anom_skew=self.m_solve_askw.IsChecked()) else: (plat,plon,pmag,maj_se,min_se,phi),chisq,dof = pymax.max_likelihood_pole(data, trial_pole=header[:3], out_path="synth_mag_gui.maxout", save_full_data_kernel=self.verbose, step=header[-1], max_steps=100, comment=comment, solve_anom_skew=self.m_solve_askw.IsChecked()) if self.m_add_strike_unc.IsChecked(): #If strike unc is to be included calculate it!!! (maj_se,min_se,phi) = cs.calc_strikes_and_add_err(self.parent.deskew_path,mlat=plat,mlon=plon,ma=maj_se,mb=min_se,mphi=phi,geoid=self.geoid,outfile=".tmp_dsk_cs",filter_by_quality=False,visualize=False,convergence_level=1e-5) os.remove(".tmp_dsk_cs") #write pole coordinates and 1sigmas to plot for user if phi<0: phi = phi+180 elif phi>180: phi = phi%180 if self.m_show_a95.IsChecked(): f_factor = f.ppf(.95,2,dof) print(f_factor) maj_se,min_se = maj_se*np.sqrt(f_factor),min_se*np.sqrt(f_factor) if self.m_solve_askw.IsChecked(): self.ax.annotate(r"%.1f$^\circ$N, %.1f$^\circ$E"%(plat,plon)+"\n"+r"%.1f$^\circ$, %.1f$^\circ$, N%.1fE"%(maj_se,min_se,phi)+"\n"+"Anom. Skw. = %.1f"%askw+"\n"+r"$\chi^2_\nu$ = %.2f"%(chisq/dof)+"\n"+r"$1\sigma_{aero}$=%.1f"%(s1_aero)+"\n"+r"$1\sigma_{ship}$=%.1f"%(s1_ship),xy=(1-0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,ha='right',va='top') else: self.ax.annotate(r"%.1f$^\circ$N, %.1f$^\circ$E"%(plat,plon)+"\n"+r"%.1f$^\circ$, %.1f$^\circ$, N%.1fE"%(maj_se,min_se,phi)+"\n"+r"$\chi^2_\nu$ = %.2f"%(chisq/dof)+"\n"+r"$1\sigma_{aero}$=%.1f"%(s1_aero)+"\n"+r"$1\sigma_{ship}$=%.1f"%(s1_ship),xy=(1-0.02,1-0.02),xycoords="axes fraction",bbox=dict(boxstyle="round", fc="w",alpha=.5),fontsize=self.fontsize,ha='right',va='top') #plot inverted pole self.ax = psk.plot_pole(plon,plat,phi,np.sqrt(chisq/dof)*maj_se,np.sqrt(chisq/dof)*min_se,m=self.ax, alpha=.5, zorder=10000) if self.m_show_lunes.IsChecked(): #filter deskew_df to only data labeled "good" and plot lunes if self.m_solve_askw.IsChecked(): srf,asf = self.parent.get_srf_asf() new_asf = lambda sr: asf(sr)+askw self.parent.deskew_df = sk.calc_aei(self.parent.deskew_df,srf,new_asf) else: self.parent.deskew_df = sk.calc_aei(self.parent.deskew_df,*self.parent.get_srf_asf()) dsk_to_plot = self.parent.deskew_df[self.parent.deskew_df["quality"]=="g"] if self.m_show_selected.IsChecked(): try: self.ax = psk.plot_lunes(dsk_to_plot,self.ax,idx_selected=self.parent.dsk_idx) except AttributeError: self.ax = psk.plot_lunes(dsk_to_plot,self.ax) #catch no selected data case else: self.ax = psk.plot_lunes(dsk_to_plot,self.ax) # os.remove(".tmp.max") #remove the deskew file on disk #plot any additional poles for pole_rec in self.poles_to_plot: print(pole_rec) self.ax = psk.plot_pole(*pole_rec[0],color=pole_rec[1],m=self.ax,zorder=1000) #set the map extent to match user input print([float(self.min_lon_box.GetValue()),float(self.max_lon_box.GetValue()),float(self.min_lat_box.GetValue()),float(self.max_lat_box.GetValue())]) self.ax.set_extent([float(self.min_lon_box.GetValue()),float(self.max_lon_box.GetValue()),float(self.min_lat_box.GetValue()),float(self.max_lat_box.GetValue())], ccrs.PlateCarree()) self.canvas.draw() #rerender def on_close_main(self,event): self.parent.rtp_open=False self.Destroy() ############################Menu Funcions################################ def on_import_poles(self,event): dlg = wx.FileDialog( self, message="Choose CSV File", defaultDir=self.parent.WD, wildcard="Files (*.csv)|*.csv|All Files (*.*)|*.*", style=wx.FD_OPEN ) if dlg.ShowModal() == wx.ID_OK: import_csv=dlg.GetPath() df_poles = pd.read_csv(import_csv,sep=None) dlg.Destroy() uniform_cols = list(map(lambda x: str(x).lower(), df_poles.columns)) df_poles.columns = uniform_cols try: lat_col = next(filter(lambda x: x.startswith("lat"), uniform_cols)) lon_col = next(filter(lambda x: x.startswith("lon"), uniform_cols)) maj_col = next(filter(lambda x: x.startswith("maj"), uniform_cols)) min_col = next(filter(lambda x: x.startswith("min"), uniform_cols)) azi_col = next(filter(lambda x: x.startswith("azi"), uniform_cols)) except: self.parent.user_warning("""Couldn't find a required column. There must be at least 5 columns. These 5 columns must have labels that start with lat, lon, maj, min, azi in any order and case insensitive. If more than one column fits these conditions then the first column is taken.""") return try: color_col = next(filter(lambda x: "color" in x, uniform_cols)) except: color_col=None for i,row in df_poles.iterrows(): if isinstance(color_col,type(None)): self.parent.user_warning("No Color for Pole (%.1f,%.1f), please specify"%(row[lat_col],row[lon_col])) cdlg = wx.ColourDialog(self) if cdlg.ShowModal() == wx.ID_OK: color = tuple(np.array(cdlg.GetColourData().GetColour().Get())/255) else: color = "tab:blue" else: color = row[color_col] self.poles_to_plot.append([row[[lon_col,lat_col,azi_col,maj_col,min_col]].values,color]) self.update() def on_save_plot(self,event): self.toolbar.save_figure() def on_remove_pole(self,event): self.poles_to_plot = self.poles_to_plot[:-1] self.update() def on_remove_all_poles(self,event): self.poles_to_plot = [] self.update() def on_add_strike_unc(self,event): self.update() def on_solve_askw(self,event): self.update() def on_show_lunes(self,event): self.update() def on_show_pole(self,event): self.update() def on_show_a95(self,event): self.update() def on_show_selected(self,event): self.update() ###################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_proj(self,event): self.update() def on_re_render_button(self,event): self.update() def on_add_pole_button(self,event): pdlg = PoleDialog(self) #run text entry dialog if pdlg.ShowModal() == wx.ID_OK: new_pole = [pdlg.lon,pdlg.lat,pdlg.phi,pdlg.a,pdlg.b] else: return pdlg.Destroy() cdata = wx.ColourData() cdata.SetChooseFull(True) # cdata.SetChooseAlpha(True) cdata.SetColour(wx.Colour(255, 0, 0, 128)) cdlg = wx.ColourDialog(self,cdata) if cdlg.ShowModal() == wx.ID_OK: new_color = tuple(np.array(cdlg.GetColourData().GetColour().Get())/255) else: color = "#00FFFF88" if len(new_color)==3 or new_color[3]==1.: new_color = (new_color[0],new_color[1],new_color[2],.5) elif len(new_color)<3: raise RuntimeError("If you're looking at this error in the terminal while running SynthMag GUI, you shouldn't be able to get here and something is significantly wrong with the color picker. Contact the dev on github.") cdlg.Destroy() self.poles_to_plot.append([new_pole,new_color]) #add new pole to list self.update() #update figure ###########################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 = "Zoom" self.toolbar.zoom() event.Skip() # def on_move_mouse_plot(self,event): # try: dsk_row = self.parent.dsk_row # except AttributeError: event.Skip(); return # pos=event.GetPosition() # width, height = self.canvas.get_width_height() # pos = [pos[0],height-pos[1]] # pos = self.ax.transData.inverted().transform(pos) # lonlat = ccrs.PlateCarree().transform_point(*pos,self.proj) # self.plot_tracer_on_self_and_parent(dsk_row,lonlat) # self.parent.canvas.draw() # self.canvas.draw() # event.Skip() def on_select_dleft_click(self,event): #TODO make rtp try: self.parent.dsk_row except AttributeError: event.Skip(); return pos=event.GetPosition() width, height = self.canvas.get_width_height() pos = [pos[0],height-pos[1]] pos = self.ax.transData.inverted().transform(pos) plonlat = ccrs.PlateCarree().transform_point(*pos,self.proj) srf,asf = self.parent.get_srf_asf() reduced_skewness,rel_reduced_amplitude = sk.reduce_dsk_row_to_pole(self.parent.dsk_row,*plonlat,asf,srf) self.parent.phase_shift_box.SetValue("%.1f"%reduced_skewness) self.parent.deskew_df.at[self.parent.dsk_idx,'phase_shift'] = reduced_skewness self.parent.deskew_df.at[self.parent.dsk_idx,'rel_amp'] = rel_reduced_amplitude self.parent.dsk_row = self.parent.deskew_df.loc[self.parent.dsk_idx].iloc[0] self.parent.update(event) self.update() def on_select_dright_click(self,event): #TODO make rtp try: self.parent.deskew_df except AttributeError: event.Skip(); return pos=event.GetPosition() width, height = self.canvas.get_width_height() pos = [pos[0],height-pos[1]] pos = self.ax.transData.inverted().transform(pos) plonlat = ccrs.PlateCarree().transform_point(*pos,self.proj) srf,asf = self.parent.get_srf_asf() for i,row in self.parent.deskew_df.iterrows(): reduced_skewness,rel_reduced_amplitude = sk.reduce_dsk_row_to_pole(row,*plonlat,asf,srf) self.parent.deskew_df.at[i,'phase_shift'] = reduced_skewness self.parent.deskew_df.at[i,'rel_amp'] = rel_reduced_amplitude self.parent.deskew_df = sk.calc_aei(self.parent.deskew_df,srf,asf) try: self.parent.dsk_row = self.parent.deskew_df.loc[self.parent.dsk_idx].iloc[0] except (AttributeError,KeyError) as e: pass self.parent.update(event) self.update() ##########################Additional Plotting and Backend Functions################ def on_parent_select_track(self): self.update() def make_map(self): #set basemap try: self.fig.delaxes(self.ax) except AttributeError: self.parent.user_warning("Unable to remove previous axis and refresh map, raise issue with Dev.") #TODO: ADD TRANSVERSE MERCATOR AT STRIKE AS OPTION if self.proj_box.GetValue() == 'North Polar Stereographic': self.proj = ccrs.NorthPolarStereo(central_longitude=self.center_lon,true_scale_latitude=None,globe=None) self.ax = self.fig.add_subplot(111,projection=self.proj) # pgeo.make_circular_ax(self.ax) elif self.proj_box.GetValue() == 'South Polar Stereographic': self.proj = ccrs.SouthPolarStereo(central_longitude=self.center_lon,true_scale_latitude=None,globe=None) self.ax = self.fig.add_subplot(111,projection=self.proj) # pgeo.make_circular_ax(self.ax) elif self.proj_box.GetValue() == 'Orthographic': self.proj = ccrs.Orthographic(central_longitude=self.center_lon) self.ax = self.fig.add_subplot(111,projection=self.proj) else: self.parent.user_warning("Projection %s not supported"%str(self.proj_box.GetValue())); return # self.ax.set_xticks(np.arange(0, 370, 10.), crs=ccrs.PlateCarree()) # self.ax.set_yticks(np.arange(-80, 90, 10.), crs=ccrs.PlateCarree()) # self.ax.tick_params(grid_linewidth=.5,grid_linestyle=":",color="k",labelsize=8) # lon_formatter = LongitudeFormatter(zero_direction_label=True) # lat_formatter = LatitudeFormatter() # self.ax.xaxis.set_major_formatter(lon_formatter) # self.ax.yaxis.set_major_formatter(lat_formatter) self.ax.gridlines(color='grey', alpha=0.5, linestyle='--',linewidth=.5) land = cfeature.NaturalEarthFeature('physical', 'land', self.resolution, edgecolor="black", facecolor="grey", linewidth=2) self.ax.add_feature(land)
class SRMWindow(wx.Frame): #########################Init Funcions############################# def __init__(self, spreading_rate_path, parent=None, starting_sz="", fontsize=8, dpi=200): """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="Spreading Rate Model %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.spreading_rate_path = spreading_rate_path self.panel = wx.Panel(self, -1, size=(400 * 2, 300 * 2)) #Populate UI and Menu self.init_UI() self.create_menu() self.sz = starting_sz try: self.open_srm() except: self.srm = None self.update() def init_UI(self): spacing = 10 #---------------------------------Make ListCtrl for SR---------------------------------------------------# self.logger = EditableListCtrl(self.panel, ID=wx.ID_ANY, size=(300, 300), style=wx.LC_REPORT) self.logger.InsertColumn(0, 'End Age', width=150) self.logger.InsertColumn(1, 'Half Rate', width=150) # self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_click_listctrl, self.logger) # self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK,self.on_right_click_listctrl,self.logger) # self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_select_measurement, self.logger) #-----------------------------Make DropDown Box and Update-----------------------------------------------# sz_sizer = wx.StaticBoxSizer( wx.StaticBox(self.panel, wx.ID_ANY, "Choose Spreading Zone"), wx.VERTICAL) self.sz_box = wx.ComboBox(self.panel, id=wx.ID_ANY, size=(150, 25), choices=[], style=wx.CB_DROPDOWN | wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_COMBOBOX, self.on_select_sz, self.sz_box) self.Bind(wx.EVT_TEXT_ENTER, self.on_enter_sz, self.sz_box) add_rate_sizer = wx.StaticBoxSizer( wx.StaticBox(self.panel, wx.ID_ANY, "Add Rate to Model"), wx.HORIZONTAL) self.add_end_age_box = wx.TextCtrl(self.panel, id=wx.ID_ANY, size=(50, 25)) self.add_half_rate_box = wx.TextCtrl(self.panel, id=wx.ID_ANY, size=(50, 25)) self.add_rate_btn = wx.Button(self.panel, id=wx.ID_ANY, label='Add Rate', size=(50, 25)) self.Bind(wx.EVT_BUTTON, self.on_add_rate_btn, self.add_rate_btn) add_rate_sizer.AddMany([ (self.add_end_age_box, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.BOTTOM | wx.EXPAND, spacing), (self.add_half_rate_box, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.BOTTOM | wx.EXPAND, spacing), (self.add_rate_btn, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, spacing), ]) update_delete_sizer = wx.BoxSizer(wx.HORIZONTAL) delete_btn = wx.Button(self.panel, id=wx.ID_ANY, label='Delete Selected', size=(75, 25)) self.Bind(wx.EVT_BUTTON, self.on_delete_btn, delete_btn) update_button = wx.Button(self.panel, id=wx.ID_ANY, label='Save and Update', size=(75, 25)) self.Bind(wx.EVT_BUTTON, self.on_update_button, update_button) update_delete_sizer.AddMany([ (update_button, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.EXPAND, spacing), (delete_btn, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT | wx.EXPAND, spacing) ]) sz_sizer.AddMany([ (self.sz_box, 2, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, spacing), (add_rate_sizer, 3, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT | wx.TOP | wx.EXPAND, spacing), (update_delete_sizer, 2, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM | wx.EXPAND, spacing) ]) #-------------------------------------Make Figure----------------------------------------------------------# self.fig = Figure((2, 2), dpi=self.dpi) self.canvas = FigCanvas(self.panel, -1, self.fig) self.toolbar = NavigationToolbar(self.canvas) self.ax = self.fig.add_subplot(111) 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) #----------------------------------Build UI and Fit--------------------------------------------------------# side_bar_sizer = wx.BoxSizer(wx.VERTICAL) side_bar_sizer.AddMany([ (sz_sizer, 1, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP | wx.EXPAND, spacing), (self.canvas, 8, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, spacing) ]) outer_sizer = wx.BoxSizer(wx.HORIZONTAL) outer_sizer.AddMany([ (self.logger, 1, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.EXPAND), (side_bar_sizer, 3, wx.ALIGN_LEFT | 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) #########################Update UI Funcions############################# def update_self_and_parent(self): utl.write_sr_model_file(self.srm, self.spreading_rate_path) try: srf, _ = sk.generate_spreading_rate_model(self.spreading_rate_path) self.parent.sr_box.SetValue( "%.1f" % (srf(self.parent.dsk_row["sz_name"], (self.parent.dsk_row["age_min"] + self.parent.dsk_row["age_max"]) / 2))) except (AttributeError, KeyError) as e: pass self.update() self.parent.update_synth = True self.parent.update(-1) def update(self): #Populates Logger and makes plot if self.parent.spreading_rate_path != self.spreading_rate_path: self.spreading_rate_path = self.parent.spreading_rate_path self.open_srm() if self.spreading_rate_path == None: return self.logger.DeleteAllItems() points = [[], []] if self.sz in self.srm.keys(): prev_age = 0 for i, (end_age, half_rate) in enumerate(self.srm[self.sz]): self.logger.InsertItem(i, "%.3f" % end_age) self.logger.SetItem(i, 1, "%.3f" % half_rate) if end_age > 1e3: end_age = prev_age + 10 if i == 0 and end_age > 10: prev_age = end_age - 10 if prev_age == 0 and end_age <= 0: prev_age = end_age - 10 points[0].append(prev_age) points[0].append(end_age) points[1].append(half_rate) points[1].append(half_rate) prev_age = end_age self.ax.clear() self.ax.plot(points[0], points[1], 'k-') self.canvas.draw() def on_close_main(self, event): self.parent.srmw_open = False self.Destroy() ###################Button and Dropdown Functions######################### def on_select_sz(self, event): self.sz = self.sz_box.GetValue() self.update() def on_enter_sz(self, event): sz_tmp = self.sz_box.GetValue() if sz_tmp in sz_box.GetItems(): self.sz = sz_tmp else: if self.srm != None and self.parent.user_warning( "Spreading Zone provided not in spreading rate model would you like to add to model?" ): self.sz = sz_tmp self.srm[self.sz] = [1e10, 40] else: self.sz_box.SetValue("") self.sz = None self.update() def on_update_button( self, event): #Saves the edits and calls update on self and parent new_sz_srm = [] for i in range(self.logger.GetItemCount()): try: new_sz_srm.append([ float(self.logger.GetItemText(i, 0)), float(self.logger.GetItemText(i, 1)) ]) except ValueError: self.parent.user_warning( "Half Rate and Age to add must be numbers got %s,%s instead" % (self.logger.GetItemText( i, 0), self.logger.GetItemText(i, 1))) return self.srm[self.sz] = new_sz_srm self.update_self_and_parent() def on_add_rate_btn(self, event): try: new_end_age, new_half_rate = float( self.add_end_age_box.GetValue()), float( self.add_half_rate_box.GetValue()) except ValueError: self.parent.user_warning( "Half Rate and Age to add must be numbers got %s,%s instead" % (str(new_end_age), str(new_half_rate))) return try: if new_end_age in np.array(self.srm[self.sz])[:, 0]: self.srm[self.sz] = [ [new_end_age, new_half_rate] if self.srm[self.sz][i][0] == new_end_age else self.srm[self.sz][i] for i in range(len(self.srm[self.sz])) ] else: self.srm[self.sz] += [[new_end_age, new_half_rate]] self.srm[self.sz].sort(key=cmp_to_key(lambda x, y: x[0] - y[0])) except (KeyError, IndexError) as e: self.srm[self.sz] = [[new_end_age, new_half_rate]] self.update_self_and_parent() def on_delete_btn(self, event): next_i, del_idxs = self.logger.GetNextSelected(-1), [] if next_i == -1: return while next_i != -1: del_idxs.append(next_i) next_i = self.logger.GetNextSelected(next_i) new_sz_srm = [] for i in range(self.logger.GetItemCount()): if i in del_idxs: continue #Skip deleted data try: new_sz_srm.append([ float(self.logger.GetItemText(i, 0)), float(self.logger.GetItemText(i, 1)) ]) except ValueError: self.parent.user_warning( "Half Rate and Age to add must be numbers got %s,%s instead" % (self.logger.GetItemText( i, 0), self.logger.GetItemText(i, 1))) return self.srm[self.sz] = new_sz_srm self.update_self_and_parent() ###########################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 = "Zoom" self.toolbar.zoom() event.Skip() ###########################Utility Funcions############################### def open_srm(self): self.srm = utl.open_sr_model_file(self.spreading_rate_path) self.sz_box.SetItems([""] + sorted(list(self.srm.keys()))) self.sz_box.SetValue(self.sz)
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 PanelSpec(wx.Panel): def __init__(self, parent, parentMainFrame): wx.Panel.__init__(self, parent) self.CreatePanel() self.setSpLabel() self.parent = parentMainFrame self.FFT_Max_X = 5995 self.FFT_Min_X = 70 self.FFT_Max_Y = 60 self.FFT_Min_Y = -120 def CreatePanel(self): self.Figure = matplotlib.figure.Figure() self.axes = self.Figure.add_axes([0.05, 0.05, 0.93, 0.93]) self.FigureCanvas = FigureCanvas(self, -1, self.Figure) self.ButtonAutoY = wx.Button(self, -1, label="AutoScaleY") self.ButtonAutoX = wx.Button(self, -1, label="AutoScaleX") self.Max_Y = wx.TextCtrl(self, -1, '60', size=(60, 20), style=wx.TE_PROCESS_ENTER) self.Min_Y = wx.TextCtrl(self, -1, '-120', size=(60, 20), style=wx.TE_PROCESS_ENTER) self.Min_X = wx.TextCtrl(self, -1, '70', size=(60, 20), style=wx.TE_PROCESS_ENTER) self.Max_X = wx.TextCtrl(self, -1, '5995', size=(60, 20), style=wx.TE_PROCESS_ENTER) sizer = wx.GridBagSizer(5, 5) sizer.Add(self.ButtonAutoX, pos=(0, 1), flag=wx.TOP, border=5) sizer.Add(self.ButtonAutoY, pos=(0, 2), flag=wx.TOP, border=5) sizer.Add(self.Max_Y, pos=(1, 0), flag=wx.ALL, border=5) sizer.Add(self.Min_Y, pos=(17, 0), flag=wx.ALL, border=5) sizer.Add(self.FigureCanvas, pos=(1, 1), span=(18, 14), flag=wx.EXPAND) sizer.Add(self.Min_X, pos=(19, 1), flag=wx.RIGHT | wx.BOTTOM, border=5) sizer.Add(self.Max_X, pos=(19, 14), flag=wx.BOTTOM, border=5) sizer.AddGrowableCol(10) sizer.AddGrowableRow(10) self.SetSizer(sizer) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMin_X, self.Min_X) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMax_X, self.Max_X) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMax_Y, self.Max_Y) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterMin_Y, self.Min_Y) self.Bind(wx.EVT_BUTTON, self.OnAutoX, self.ButtonAutoX) self.Bind(wx.EVT_BUTTON, self.OnAutoY, self.ButtonAutoY) self.popupmenu = wx.Menu() StringList = ["Add Marker", "Remove Marker", "All Marker Off"] for text in StringList: item = self.popupmenu.Append(-1, text) self.FigureCanvas.Bind(wx.EVT_CONTEXT_MENU, self.OnShowPopup) self.FigureCanvas.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item) ''' Array=linspace(70, 5995,238) self.xDataList=[] self.LineSpec=[] self.LineSpecBack=[] for i in xrange(237): xData=linspace(Array[i],Array[i+1],1024) self.xDataList.append(xData) ydata=[0]*1024 for xData in self.xDataList: lineSpec,=self.axes.plot(xData,ydata,'y') lineSpecBack,=self.axes.plot(xData,ydata,'r') self.LineSpec.append(lineSpec) self.LineSpecBack.append(lineSpecBack) ''' self.xData = linspace(70, 6470, 1024) self.yData = [0] * 1024 self.lineSpec, = self.axes.plot(self.xData, self.yData, 'y') self.lineSpecBack, = self.axes.plot(self.xData, self.yData, 'r') ####Marker############ self.drs = [] def OnAutoX(self, event): self.setSpLabel(begin_X=self.parent.FreqMin,end_X=self.parent.FreqMax , \ begin_Y=self.FFT_Min_Y,end_Y=self.FFT_Max_Y) self.FigureCanvas.draw() self.FFT_Min_X = self.parent.FreqMin self.FFT_Max_X = self.parent.FreqMax self.Min_X.SetValue(str(self.FFT_Min_X)) self.Max_X.SetValue(str(self.FFT_Max_X)) def OnAutoY(self, event): self.setSpLabel(begin_X=self.FFT_Min_X, end_X=self.FFT_Max_X) self.FigureCanvas.draw() self.FFT_Min_Y = -120 self.FFT_Max_Y = 60 self.Min_Y.SetValue("-120") self.Max_Y.SetValue("60") def OnEnterMin_X(self, event): self.FFT_Min_X = int(self.Min_X.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnEnterMax_X(self, event): self.FFT_Max_X = int(self.Max_X.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnEnterMin_Y(self, event): self.FFT_Min_Y = int(self.Min_Y.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnEnterMax_Y(self, event): self.FFT_Max_Y = int(self.Max_Y.GetValue()) self.setSpLabel(self.FFT_Min_X, self.FFT_Max_X, self.FFT_Min_Y, self.FFT_Max_Y) self.FigureCanvas.draw() def OnShowPopup(self, event): pos = event.GetPosition() pos = self.FigureCanvas.ScreenToClient(pos) self.FigureCanvas.PopupMenu(self.popupmenu, pos) def OnPopupItemSelected(self, event): item = self.popupmenu.FindItemById(event.GetId()) text = item.GetText() if (text == "Add Marker"): self.OnAddMarker() elif (text == "Remove Marker"): self.OnRemove() elif (text == "All Marker Off"): self.OnAllRemove() def DrawMarker(self, Max_X, Max_Y): distance = ((self.FFT_Max_X - self.FFT_Min_X) / 10)**2 index = len(self.drs) + 1 rect, = self.axes.plot(Max_X, Max_Y, 'rd', markersize=10) text = self.axes.text(Max_X + 5, Max_Y + 2, 'M' + str(index), color='r') textM=self.axes.text(self.FFT_Min_X+5,self.FFT_Max_Y-5*(index),'M'+str(index)+':' \ +'%.2f'%(Max_X)+'MHz '+'%.2f'%(Max_Y)+'dBm') # DragRect=DraggableRectangle(rect,text,textM,self.LineSpec,self.FigureCanvas) # DragRect.setM_id('M'+str(index)+':') # # DragRect.setRadius(distance) # DragRect.connect() # self.drs.append(DragRect) #self.FigureCanvas.draw() def OnAddMarker(self): if (len(self.drs) < 4): startSection = (self.FFT_Min_X - 70) / 25 endSection = (self.FFT_Max_X - 70) / 25 lenStart = len(self.LineSpec[startSection].get_ydata()) lenEnd = len(self.LineSpec[endSection].get_ydata()) indexStart = int( (self.FFT_Min_X - (startSection * 25 + 70)) * lenStart / 25.0) indexEnd = int( (self.FFT_Max_X - (endSection * 25 + 70)) * lenEnd / 25.0) MaxList = [] MaxList.append( max( list(self.LineSpec[startSection].get_ydata()) [indexStart:lenStart])) for i in range(startSection + 1, endSection, 1): MaxList.append(max(list(self.LineSpec[i].get_ydata()))) if (indexEnd != 0): MaxList.append( max( list(self.LineSpec[endSection].get_ydata()) [0:indexEnd])) Max_Y = max(MaxList) Max_Y_Index = MaxList.index(Max_Y) + startSection y = self.LineSpec[Max_Y_Index].get_ydata() Max_X_Index = list(y).index(Max_Y) Max_X = 70 + Max_Y_Index * 25 + Max_X_Index * 25.0 / len(y) self.DrawMarker(Max_X, Max_Y) def OnRemove(self): if (len(self.axes.texts)): self.axes.lines.pop() self.axes.texts.pop() self.axes.texts.pop() self.drs.pop() #self.FigureCanvas.draw() def OnAllRemove(self): while (len(self.axes.texts)): self.axes.lines.pop() self.axes.texts.pop() self.axes.texts.pop() self.drs.pop() #self.FigureCanvas.draw() def setSpLabel(self, begin_X=70, end_X=5995, begin_Y=-120, end_Y=60): self.ylabel('dBm') self.xlabel('MHz') self.ylim(begin_Y, end_Y) self.xlim(begin_X, end_X) yticks = linspace(begin_Y, end_Y, 11) ##11个数总共### yticklabels = [str(int(i)) for i in yticks] xticks = linspace(begin_X, end_X, 11) xticklabels = [str(int(i)) for i in xticks] self.axes.set_xticks(xticks) self.axes.set_xticklabels(xticklabels, rotation=0) self.axes.set_yticks(yticks) self.axes.set_yticklabels(yticklabels, rotation=0) self.axes.grid(True) #self.FigureCanvas.draw() def PowerSpectrum(self, funcPara, y): if (funcPara == 0x51 or funcPara == 0x56): self.lineSpec.set_ydata(array(y)) ''' for i in range(len(self.drs)): self.drs[i].yData=self.LineSpec self.DrawAfterRelease() ''' elif (funcPara == 0x52 or funcPara == 0x57): self.lineSpecBack.set_ydata(array(y)) self.FigureCanvas.draw() def DrawAfterRelease(self): for i in range(len(self.drs)): xData = self.drs[i].rect.get_xdata() index = (int(xData) - 70) / 25 Section = index * 25 + 70 y = self.LineSpec[index].get_ydata() index_Y = (xData - Section) * len(y) / 25.0 Marker_Y = list(y)[int(index_Y)] self.drs[i].rect.set_ydata(Marker_Y) self.drs[i].textMarker.set_position((xData, Marker_Y + 2)) self.drs[i].textM.set_text(self.drs[i].M_index+'%.2f'%(xData)+ \ 'MHz '+'%.2f'%(Marker_Y)+'dBm') def xlim(self, x_min, x_max): self.axes.set_xlim(x_min, x_max) def ylim(self, y_min, y_max): self.axes.set_ylim(y_min, y_max) def xlabel(self, XabelString="X"): self.axes.set_xlabel(XabelString) def ylabel(self, YabelString="Y"): self.axes.set_ylabel(YabelString)
class PlotPanel(wx.Panel): """ The PlotPanel """ def __init__(self, parent, color=None, dpi=None, **kwargs): # initialize Panel if 'id' not in kwargs.keys(): kwargs['id'] = wx.ID_ANY if 'style' not in kwargs.keys(): kwargs['style'] = wx.NO_FULL_REPAINT_ON_RESIZE wx.Panel.__init__(self, parent, **kwargs) self.SetMinSize((100, 40)) # initialize matplotlib stuff self.figure = Figure(None, dpi=dpi, facecolor='white') self.canvas = FigureCanvas(self, -1, self.figure) self.canvas.SetMinSize((30, 10)) self.SetBackgroundColour('white') # Add the canvas to the sizer. self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.EXPAND) self.SetSizer(self.sizer) #self.canvas.mpl_connect('button_press_event', self.onClick) self.canvas.Bind(wx.EVT_SET_FOCUS, self.onSetFocus) self.Bind(wx.EVT_SET_FOCUS, self.onSetFocus2) self.canvas.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.Bind(wx.EVT_KEY_DOWN, self.onKeyDown) self.canvas.Bind(wx.EVT_KEY_UP, self.onKeyUp) self.Bind(wx.EVT_KEY_UP, self.onKeyUp) self.Bind(wx.EVT_LEFT_DOWN, self.onLeftDown) self.canvas.Bind(wx.EVT_LEFT_DOWN, self.onLeftDown) def onClick(self, event): print "Clicked in View. event: %s" % event.guiEvent event.guiEvent.ResumePropagation(1) event.guiEvent.Skip() def onWxClick(self, event): print "Got the WX event." def onSetFocus(self, event): print "Canvas got Focus" event.Skip() def onSetFocus2(self, event): print "PlotPanel got Focus" def onKeyDown(self, event): print "Propagating keyDown in plotPanel" event.ResumePropagation(1) event.Skip() def onKeyUp(self, event): print "Propagating keyUp in plotPanel" event.ResumePropagation(1) event.Skip() def onLeftDown(self, event): print "PlotPanel LEFT DOWN" event.ResumePropagation(30) event.Skip() def SetColor(self, rgbtuple=None): """Set figure and canvas colours to be the same.""" if rgbtuple is None: rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() clr = [c / 255. for c in rgbtuple] self.figure.set_facecolor(clr) self.figure.set_edgecolor(clr) self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple)) self.canvas.Refresh()
class MyFrame(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self,parent, id, 'scrollable plot', style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER, size=(800, 400)) self.panel = wx.Panel(self, -1) self.fig = Figure((5, 4), 75) self.canvas = FigureCanvasWxAgg(self.panel, -1, self.fig) self.scroll_range = 400 self.canvas.SetScrollbar(wx.HORIZONTAL, 0, 5, self.scroll_range) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.canvas, -1, wx.EXPAND) self.panel.SetSizer(sizer) self.panel.Fit() self.init_data() self.init_plot() self.canvas.Bind(wx.EVT_SCROLLWIN, self.OnScrollEvt) def init_data(self): # Generate some data to plot: self.dt = 0.01 self.t = arange(0,5,self.dt) self.x = sin(2*pi*self.t) # Extents of data sequence: self.i_min = 0 self.i_max = len(self.t) # Size of plot window: self.i_window = 100 # Indices of data interval to be plotted: self.i_start = 0 self.i_end = self.i_start + self.i_window def init_plot(self): self.axes = self.fig.add_subplot(111) self.plot_data = \ self.axes.plot(self.t[self.i_start:self.i_end], self.x[self.i_start:self.i_end])[0] def draw_plot(self): # Update data in plot: self.plot_data.set_xdata(self.t[self.i_start:self.i_end]) self.plot_data.set_ydata(self.x[self.i_start:self.i_end]) # Adjust plot limits: self.axes.set_xlim((min(self.t[self.i_start:self.i_end]), max(self.t[self.i_start:self.i_end]))) self.axes.set_ylim((min(self.x[self.i_start:self.i_end]), max(self.x[self.i_start:self.i_end]))) # Redraw: self.canvas.draw() def OnScrollEvt(self, event): # Update the indices of the plot: self.i_start = self.i_min + event.GetPosition() self.i_end = self.i_min + self.i_window + event.GetPosition() self.draw_plot()
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 Spectrogram(StandardMonitorPage): """Main class for a page that generates real-time spectrogram plots of EEG. """ def __init__(self, *args, **kwargs): """Construct a new Spectrogram page. Args: *args, **kwargs: Arguments to pass to the Page base class. """ self.initConfig() # initialize Page base class StandardMonitorPage.__init__(self, name='Spectrogram', configPanelClass=ConfigPanel, *args, **kwargs) self.initCanvas() self.initLayout() def initConfig(self): self.filter = True # use raw or filtered signal self.chanIndex = 0 # index of channel to show self.width = 5.0 # width of window to use for computing PSD self.decimationFactor = 1 # decimation factor, e.g., 2 will decimate to half sampRate self.interpolation = 'none' self.normScale = 'log' self.scale = -2 self.method = 'Wavelet' self.setRefreshDelay(200) self.waveletConfig = util.Holder(nFreq=100, span=10) self.fourierConfig = util.Holder() def initCanvas(self): """Initialize a new matplotlib canvas, figure and axis. """ self.plotPanel = wx.Panel(self) self.plotPanel.SetBackgroundColour('white') plotSizer = wx.BoxSizer(orient=wx.VERTICAL) self.plotPanel.SetSizer(plotSizer) self.fig = plt.Figure(facecolor='white') #self.canvas = FigureCanvas(parent=self, id=wx.ID_ANY, figure=self.fig) self.canvas = FigureCanvas(parent=self.plotPanel, id=wx.ID_ANY, figure=self.fig) self.ax = self.fig.add_subplot(1, 1, 1) self.ax.set_xlabel('Time (s)') self.ax.set_ylabel('Frequency (Hz)') self.cbAx = self.fig.add_axes([0.91, 0.05, 0.03, 0.93]) #self.fig.subplots_adjust(hspace=0.0, wspace=0.0, # left=0.035, right=0.92, top=0.98, bottom=0.05) self.adjustMargins() self.firstPlot() self.lastSize = (0, 0) self.needsResizePlot = True self.canvas.Bind(wx.EVT_SIZE, self.resizePlot) self.canvas.Bind(wx.EVT_IDLE, self.idleResizePlot) ##self.plotToolbar = widgets.PyPlotNavbar(self.canvas) ##plotSizer.Add(self.plotToolbar, proportion=0, flag=wx.EXPAND) plotSizer.Add(self.canvas, proportion=1, flag=wx.EXPAND) #self.plotToolbar.Hide() def initLayout(self): self.initStandardLayout() plotPaneAuiInfo = aui.AuiPaneInfo().Name('canvas').Caption( 'Spectrogram').CenterPane() #self.auiManager.AddPane(self.canvas, plotPaneAuiInfo) self.auiManager.AddPane(self.plotPanel, plotPaneAuiInfo) self.auiManager.Update() self.canvas.Hide() def afterUpdateSource(self): self.configPanel.updateChannels() def afterStart(self): # make sure canvas is visible self.canvas.Show() self.plotPanel.Layout() # trigger initial plot update self.needsFirstPlot = True def getCap(self): cap = self.src.getEEGSecs(self.width, filter=self.filter, copy=False) if self.decimationFactor > 1: cap.decimate(self.decimationFactor) return cap def getSpectrum(self, cap): # configurable XXX - idfah data = cap.data[:, self.chanIndex] * sig.windows.tukey( cap.data.shape[0]) # tukey or hann? XXX - idfah freqs, powers, phases = self.cwt.apply(data) # configurable XXX - idfah powers = np.clip(powers, 1.0e-10, np.inf) return freqs, powers def firstPlot(self, event=None): cap = self.getCap() self.cwt = sig.CWT(sampRate=cap.getSampRate(), freqs=self.waveletConfig.nFreq, span=self.waveletConfig.span) if self.isRunning(): freqs, powers = self.getSpectrum(cap) else: freqs = np.arange(1, self.src.getSampRate() // 2 + 1) powers = np.zeros((128, 10, 1)) powers[0, 0, 0] = 1.0 self.ax.cla() self.cbAx.cla() self.ax.set_xlabel('Time (s)') self.ax.set_ylabel('Frequency (Hz)') self.wimg = self.ax.imshow(powers[:, :, 0].T, interpolation=self.interpolation, origin='lower', aspect='auto', norm=self.getNorm(), extent=self.getExtent(cap, freqs), cmap=plt.cm.get_cmap('jet'), animated=True) self.cbar = self.fig.colorbar(self.wimg, cax=self.cbAx) self.cbar.set_label(r'Power Density ($V^2 / Hz$)') #self.updateNorm(powers) self.canvas.draw() #self.background = self.canvas.copy_from_bbox(self.fig.bbox) self.background = self.canvas.copy_from_bbox(self.ax.bbox) self.needsFirstPlot = False def adjustMargins(self): self.fig.subplots_adjust(hspace=0.0, wspace=0.0, left=0.045, right=0.90, top=0.98, bottom=0.07) def resizePlot(self, event): # prevents handling extra resize events, hack XXX - idfah size = self.canvas.GetSize() if self.lastSize == size: return else: self.lastSize = size # this is all a hack to do resizing on idle when page is not running # should this be a custom FigureCanvas derived widget? XXX - idfah if self.isRunning(): # when running, just do event.Skip() this will # call canvas._onSize since it is second handler self.needsResizePlot = False event.Skip() else: # flag to resize on next idle event self.needsResizePlot = True def idleResizePlot(self, event): # if not running and flagged for resize if not self.isRunning() and self.needsResizePlot: ##self.adjustMargins() self.needsResizePlot = False # call canvas resize method manually # hack alert, we just pass None as event # since it's not used anyway self.canvas._onSize(None) def getExtent(self, cap, freqs): return (0.0, cap.getNObs() / float(cap.getSampRate()), np.min(freqs), np.max(freqs)) def getNorm(self): mx = 10**self.scale if self.normScale == 'linear': mn = 0.0 norm = pltLinNorm(mn, mx) elif self.normScale == 'log': mn = 1e-10 norm = pltLogNorm(mn, mx) else: raise RuntimeError('Invalid norm %s.' % norm) return norm def updatePlot(self, event=None): """Draw the spectrogram plot. """ if self.needsFirstPlot: self.firstPlot() else: cap = self.getCap() freqs, powers = self.getSpectrum(cap) #self.updateNorm(powers) self.canvas.restore_region(self.background) self.wimg.set_array(powers[:, :, 0].T) self.wimg.set_extent(self.getExtent(cap, freqs)) self.ax.draw_artist(self.wimg) ##self.cbAx.draw_artist(self.cbar.patch) ##self.cbAx.draw_artist(self.cbar.solids) #self.cbar.draw_all() #self.canvas.blit(self.cbAx.bbox) #self.canvas.blit(self.fig.bbox) self.canvas.blit(self.ax.bbox) # for debugging, redraws everything ##self.canvas.draw() def captureImage(self, event=None): ## Parts borrowed from backends_wx.py from matplotlib # Fetch the required filename and file type. filetypes, exts, filter_index = self.canvas._get_imagesave_wildcards() default_file = self.canvas.get_default_filename() dlg = wx.FileDialog(self, "Save to file", "", default_file, filetypes, wx.SAVE | wx.OVERWRITE_PROMPT) dlg.SetFilterIndex(filter_index) if dlg.ShowModal() == wx.ID_OK: dirname = dlg.GetDirectory() filename = dlg.GetFilename() format = exts[dlg.GetFilterIndex()] basename, ext = os.path.splitext(filename) if ext.startswith('.'): ext = ext[1:] if ext in ('svg', 'pdf', 'ps', 'eps', 'png') and format != ext: #looks like they forgot to set the image type drop #down, going with the extension. format = ext self.canvas.print_figure(os.path.join(dirname, filename), format=format)
class FIRBandpassConfigPanel(FilterConfigPanel): def __init__(self, *args, **kwargs): FilterConfigPanel.__init__(self, *args, **kwargs) # options go in top-level sizer self.initOptions() # other stuff split horizontally by bottomSizer self.bottomSizer = wx.BoxSizer(wx.HORIZONTAL) self.initSliders() self.initResponse() self.sizer.Add(self.bottomSizer, proportion=1, flag=wx.EXPAND) self.initLayout() def initOptions(self): optionsSizer = wx.BoxSizer(wx.HORIZONTAL) self.filtTypeComboBox = wx.ComboBox(self, choices=list(self.flt.filtMap.keys()), value=self.flt.filtType, style=wx.CB_DROPDOWN) self.Bind(wx.EVT_COMBOBOX, self.setFiltType, self.filtTypeComboBox) optionsSizer.Add(self.filtTypeComboBox, proportion=1, flag=wx.LEFT | wx.TOP | wx.RIGHT | wx.ALIGN_CENTER, border=20) self.sizer.Add(optionsSizer, proportion=0)#, flag=wx.EXPAND) def setFiltType(self, event): filtType = self.filtTypeComboBox.GetValue() if filtType not in self.flt.filtMap.keys(): raise RuntimeError('Invalid filter type: %s.' % str(filtType)) self.flt.filtType = filtType self.updateResponse() def initSliders(self): sliderSizer = wx.BoxSizer(wx.HORIZONTAL) lowFreqControlBox = widgets.ControlBox(self, label='lowFreq', orient=wx.VERTICAL) self.lowFreqText = wx.StaticText(self, label='%6.2f(Hz)' % self.flt.lowFreq) lowFreqTextSizer = wx.BoxSizer(orient=wx.VERTICAL) lowFreqTextSizer.Add(self.lowFreqText, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL) self.lowFreqSlider = wx.Slider(self, style=wx.SL_VERTICAL | wx.SL_INVERSE, minValue=0, maxValue=int(self.flt.nyquist*4), value=int(self.flt.lowFreq*4)) self.Bind(wx.EVT_SLIDER, self.setLowFreq, self.lowFreqSlider) lowFreqControlBox.Add(lowFreqTextSizer, proportion=0, flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=8) lowFreqControlBox.Add(self.lowFreqSlider, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=25) sliderSizer.Add(lowFreqControlBox, proportion=1, flag=wx.ALL | wx.EXPAND, border=10) highFreqControlBox = widgets.ControlBox(self, label='highFreq', orient=wx.VERTICAL) self.highFreqText = wx.StaticText(self, label='%6.2f(Hz)' % self.flt.highFreq) highFreqTextSizer = wx.BoxSizer(orient=wx.VERTICAL) highFreqTextSizer.Add(self.highFreqText, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL) self.highFreqSlider = wx.Slider(self, style=wx.SL_VERTICAL | wx.SL_INVERSE, minValue=0, maxValue=int(self.flt.nyquist*4), value=int(self.flt.highFreq*4)) self.Bind(wx.EVT_SLIDER, self.setHighFreq, self.highFreqSlider) highFreqControlBox.Add(highFreqTextSizer, proportion=0, flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=8) highFreqControlBox.Add(self.highFreqSlider, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=25) sliderSizer.Add(highFreqControlBox, proportion=1, flag=wx.ALL | wx.EXPAND, border=10) orderControlBox = widgets.ControlBox(self, label='Order', orient=wx.VERTICAL) self.orderText = wx.StaticText(self, label='%2d' % self.flt.order) orderTextSizer = wx.BoxSizer(orient=wx.VERTICAL) orderTextSizer.Add(self.orderText, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL) self.orderSlider = wx.Slider(self, style=wx.SL_VERTICAL | wx.SL_INVERSE, minValue=2, maxValue=50, value=self.flt.order // 2) self.Bind(wx.EVT_SLIDER, self.setOrder, self.orderSlider) orderControlBox.Add(orderTextSizer, proportion=0, flag=wx.TOP | wx.BOTTOM | wx.EXPAND, border=8) orderControlBox.Add(self.orderSlider, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=25) sliderSizer.Add(orderControlBox, proportion=1, flag=wx.ALL | wx.EXPAND, border=10) self.bottomSizer.Add(sliderSizer, proportion=1, flag=wx.EXPAND) def setLowFreq(self, event): self.flt.lowFreq = self.lowFreqSlider.GetValue() / 4.0 self.lowFreqText.SetLabel('%6.2f(Hz)' % self.flt.lowFreq) self.updateResponse() def setHighFreq(self, event): self.flt.highFreq = self.highFreqSlider.GetValue() / 4.0 self.highFreqText.SetLabel('%6.2f(Hz)' % self.flt.highFreq) self.updateResponse() def setOrder(self, event): self.flt.order = self.orderSlider.GetValue() * 2 self.orderText.SetLabel('%2d' % self.flt.order) self.updateResponse() def initResponse(self): self.freqResponseFig = plt.Figure() self.freqResponseCanvas = FigureCanvas(parent=self, id=wx.ID_ANY, figure=self.freqResponseFig) self.freqResponseAx = self.freqResponseFig.add_subplot(1,1,1) #self.freqResponseFig.tight_layout() self.phaseResponseFig = plt.Figure() self.phaseResponseCanvas = FigureCanvas(parent=self, id=wx.ID_ANY, figure=self.phaseResponseFig) self.phaseResponseAx = self.phaseResponseFig.add_subplot(1,1,1) #self.freqResponseFig.tight_layout() responseSizer = wx.BoxSizer(wx.VERTICAL) freqResponseControlBox = widgets.ControlBox(self, label='Frequency Response', orient=wx.VERTICAL) freqResponseControlBox.Add(self.freqResponseCanvas, proportion=1, flag=wx.ALL | wx.EXPAND, border=8) responseSizer.Add(freqResponseControlBox, proportion=1, flag=wx.TOP | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=10) phaseResponseControlBox = widgets.ControlBox(self, label='Phase Response', orient=wx.VERTICAL) phaseResponseControlBox.Add(self.phaseResponseCanvas, proportion=1, flag=wx.ALL | wx.EXPAND, border=8) responseSizer.Add(phaseResponseControlBox, proportion=1, flag=wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=10) self.bottomSizer.Add(responseSizer, proportion=1, flag=wx.EXPAND) self.freqResponseCanvas.SetMinSize((0,0)) self.phaseResponseCanvas.SetMinSize((0,0)) # could we prevent resize when panel is not visible? XXX - idfah self.freqResponseLastSize = (0,0) self.freqResponseCanvas.Bind(wx.EVT_SIZE, self.freqResponseResize) self.phaseResponseLastSize = (0,0) self.phaseResponseCanvas.Bind(wx.EVT_SIZE, self.phaseResponseResize) self.updateResponse() def freqResponseResize(self, event): # prevents handling extra resize events, hack XXX - idfah size = self.freqResponseCanvas.GetSize() if self.freqResponseLastSize == size: return self.freqResponseLastSize = size event.Skip() def phaseResponseResize(self, event): # prevents handling extra resize events, hack XXX - idfah size = self.phaseResponseCanvas.GetSize() if self.phaseResponseLastSize == size: return self.phaseResponseLastSize = size event.Skip() def updateResponse(self): self.flt.updateFilter() self.freqResponseAx.cla() self.flt.bp.plotFreqResponse(ax=self.freqResponseAx, linewidth=2) self.freqResponseAx.autoscale(tight=True) self.freqResponseAx.legend(prop={'size': 12}) self.freqResponseCanvas.draw() self.phaseResponseAx.cla() self.flt.bp.plotPhaseResponse(ax=self.phaseResponseAx, linewidth=2) self.phaseResponseAx.legend(prop={'size': 12}) self.phaseResponseAx.autoscale(tight=True) self.phaseResponseCanvas.draw()
class PlotPanel(wx.Panel): zoom_levels = [100.0, 110.0, 125.0, 150.0, 200.0, 250.0, 300.0, 400.0] dose_contour_levels = [ 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 95.0, 98 - 0, 100.0, 102.0 ] def __init__(self, parent): wx.Panel.__init__(self, parent) self.is_closeable = False self.parent = parent self.active_plan = None self.plot_mouse_action = None pub.subscribe(self.on_patient_loaded, "patient.loaded.ini") pub.subscribe(self.set_active_image, "plot.image.active_id") pub.subscribe(self.voi_changed, "voi.selection_changed") pub.subscribe(self.plan_changed, "plan.active.changed") pub.subscribe(self.plan_field_changed, "plan.field.selection_changed") pub.subscribe(self.plan_dose_changed, "plan.dose.active_changed") pub.subscribe(self.plan_dose_removed, "plan.dose.removed") pub.subscribe(self.plan_let_added, "plan.let.added") pub.subscribe(self.plan_let_removed, "plan.let.removed") pub.subscribe(self.target_dose_changed, "plan.dose.target_dose_changed") self.plotmode = "Transversal" def __del__(self): pub.unsubscribe(self.on_patient_loaded, "patient.loaded.ini") pub.unsubscribe(self.set_active_image, "plot.image.active_id") pub.unsubscribe(self.voi_changed, "voi.selection_changed") pub.unsubscribe(self.plan_changed, "plan.active.changed") pub.unsubscribe(self.plan_field_changed, "plan.field.selection_changed") pub.unsubscribe(self.plan_dose_changed, "plan.dose.active_changed") pub.unsubscribe(self.plan_dose_removed, "plan.dose.removed") pub.unsubscribe(self.plan_let_added, "plan.let.added") pub.unsubscribe(self.plan_let_removed, "plan.let.removed") pub.unsubscribe(self.target_dose_changed, "plan.dose.target_dose_changed") def target_dose_changed(self, msg): self.Draw() def Init(self): self.plotutil = PlotUtil() self.figure = Figure(None, 100) self.canvas = FigureCanvasWxAgg(self, -1, self.figure) # ~ self.canvas.SetDoubleBuffered(True) self.clear() self.plotutil.set_draw_in_gui(True) self.figure.set_frameon(True) rect = self.figure.patch rect.set_facecolor('black') def plan_dose_changed(self, msg): if msg.data["plan"] is self.active_plan: self.plotutil.set_dose(msg.data["dose"].get_dosecube()) self.Draw() def plan_field_changed(self, msg): self.Draw() def plan_dose_removed(self, msg): if msg.data["plan"] is self.active_plan: self.plotutil.set_dose(None) self.Draw() def plan_let_added(self, msg): if msg.data["plan"] is self.active_plan: self.plotutil.set_let(msg.data["let"]) self.Draw() def plan_let_removed(self, msg): if msg.data["plan"] is self.active_plan: self.plotutil.set_let(None) self.Draw() def plan_changed(self, msg): self.active_plan = msg.data if self.active_plan is None: self.plotutil.set_plan(None) self.plotutil.set_dose(None) self.plotutil.set_let(None) else: self.plotutil.set_plan(self.active_plan) doseobj = self.active_plan.get_dose() if doseobj is not None: self.plotutil.set_dose(doseobj.get_dosecube()) else: self.plotutil.set_dose(None) self.plotutil.set_let(self.active_plan.get_let()) self.Draw() def set_toolbar(self, toolbar): id = wx.NewId() selector = wx.Choice(toolbar, id) selector.Append("Transversal") selector.Append("Sagital") selector.Append("Coronal") idx = selector.FindString(self.plotmode) selector.Select(idx) toolbar.AddControl(selector) wx.EVT_CHOICE(selector, id, self.plot_mode_changed) id = wx.NewId() self.zoom_in_btn = toolbar.AddLabelTool( id, '', wx.Bitmap(get_resource_path('zoom_in.png'))) wx.EVT_MENU(toolbar, id, self.zoom_in) id = wx.NewId() self.zoom_out_btn = toolbar.AddLabelTool( id, '', wx.Bitmap(get_resource_path('zoom_out.png'))) wx.EVT_MENU(toolbar, id, self.zoom_out) def zoom_buttons_visible(self): zoom_idx = self.zoom_levels.index(self.plotutil.get_zoom()) self.zoom_in_btn.Enable(True) self.zoom_out_btn.Enable(True) if len(self.zoom_levels) == zoom_idx + 1: self.zoom_in_btn.Enable(False) if zoom_idx == 0: self.zoom_out_btn.Enable(False) def zoom_in(self, evt): zoom_idx = self.zoom_levels.index(self.plotutil.get_zoom()) zoom_idx += 1 if len(self.zoom_levels) > zoom_idx: zoom = self.zoom_levels[zoom_idx] self.plotutil.set_zoom(zoom) self.zoom_buttons_visible() self.Draw() def zoom_out(self, evt): zoom_idx = self.zoom_levels.index(self.plotutil.get_zoom()) zoom_idx -= 1 if zoom_idx >= 0: zoom = self.zoom_levels[zoom_idx] self.plotutil.set_zoom(zoom) self.zoom_buttons_visible() self.Draw() def plot_mode_changed(self, evt): self.plotmode = evt.GetString() self.plotutil.set_plot_plan(self.plotmode) self.image_idx = int(self.plotutil.get_images_count() / 2) self.clear() self.Draw() def clear(self): self.figure.clear() self.subplot = self.figure.add_subplot(111) self.plotutil.set_figure(self.subplot) def voi_changed(self, msg): voi = msg.data if voi.is_selected(): self.plotutil.add_voi(voi.voxelplan_voi) else: self.plotutil.remove_voi(voi.voxelplan_voi) self.Draw() def set_active_image(self, msg): if self.plotmode == "Transversal": self.image_idx = msg.data self.Draw() def on_patient_loaded(self, msg): self.data = msg.data ctx = self.data.get_images().get_voxelplan() self.plotutil.set_ct(ctx) self.image_idx = int(ctx.dimz / 2) self.setSize() self.bind_keys() def get_figure(self): return self.figure def bind_keys(self): self.Bind(wx.EVT_MOUSEWHEEL, self.on_mouse_wheel) self.Bind(wx.EVT_ENTER_WINDOW, self.on_mouse_enter) self.Bind(wx.EVT_LEAVE_WINDOW, self.on_mouse_leave) self.Bind(wx.EVT_SIZE, self.on_size) self.canvas.Bind(wx.EVT_KEY_DOWN, self.on_key_down) self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move_plot) self.canvas.mpl_connect('button_press_event', self.on_mouse_press_plot) self.canvas.mpl_connect('button_release_event', self.on_mouse_action_ended) self.canvas.mpl_connect('figure_leave_event', self.on_mouse_action_ended) def on_mouse_press_plot(self, evt): if evt.button is 3: pos = evt.guiEvent.GetPosition() standard = True if hasattr(self.plotutil, "contrast_bar"): bar = self.plotutil.contrast_bar if evt.inaxes is bar.ax: menu = self.right_click_contrast() standard = False if hasattr(self.plotutil, "dose_bar"): bar = self.plotutil.dose_bar if evt.inaxes is bar.ax: menu = self.right_click_dose() standard = False if standard: menu = self.normal_right_click_menu() wx.CallAfter(self.show_menu, menu) if self.canvas.HasCapture(): self.canvas.ReleaseMouse() elif evt.button is 1: if hasattr(self.plotutil, "contrast_bar"): bar = self.plotutil.contrast_bar if evt.inaxes is bar.ax: if evt.ydata >= 0.50: self.plot_mouse_action = "contrast_top" else: self.plot_mouse_action = "contrast_bottom" if hasattr(self.plotutil, "dose_bar"): bar = self.plotutil.dose_bar if evt.inaxes is bar.ax: if evt.ydata >= 0.50: self.plot_mouse_action = "dose_top" else: self.plot_mouse_action = "dose_bottom" if hasattr(self.plotutil, "let_bar"): bar = self.plotutil.let_bar if evt.inaxes is bar.ax: if evt.ydata >= 0.50: self.plot_mouse_action = "let_top" else: self.plot_mouse_action = "let_bottom" self.mouse_pos_ini = [evt.x, evt.y] evt.guiEvent.Skip() def show_menu(self, menu): self.PopupMenu(menu) def on_mouse_action_ended(self, evt): self.plot_mouse_action = None def on_mouse_move_plot(self, evt): pos = [evt.x, evt.y] if self.plot_mouse_action is not None: step = [ pos[0] - self.mouse_pos_ini[0], pos[1] - self.mouse_pos_ini[1] ] if self.plot_mouse_action == "contrast_top": contrast = self.plotutil.get_contrast() stepsize = np.log(contrast[1] - contrast[0]) contrast[1] -= stepsize * step[1] self.plotutil.set_contrast(contrast) elif self.plot_mouse_action == "contrast_bottom": contrast = self.plotutil.get_contrast() stepsize = np.log(contrast[1] - contrast[0]) contrast[0] -= stepsize * step[1] self.plotutil.set_contrast(contrast) elif self.plot_mouse_action == "dose_top": dose = self.plotutil.get_min_max_dose() dose[1] -= 0.30 * step[1] self.plotutil.set_dose_min_max(dose) elif self.plot_mouse_action == "dose_bottom": dose = self.plotutil.get_min_max_dose() dose[0] -= 0.30 * step[1] self.plotutil.set_dose_min_max(dose) elif self.plot_mouse_action == "let_top": let = self.plotutil.get_min_max_let() let[1] -= 0.30 * step[1] self.plotutil.set_let_min_max(let) elif self.plot_mouse_action == "let_bottom": let = self.plotutil.get_min_max_let() let[0] -= 0.30 * step[1] self.plotutil.set_let_min_max(let) self.Draw() elif evt.button == 1 and evt.inaxes is self.plotutil.fig_ct.axes: if not None in self.mouse_pos_ini: step = [ pos[0] - self.mouse_pos_ini[0], pos[1] - self.mouse_pos_ini[1] ] if self.plotutil.move_center(step): self.Draw() self.mouse_pos_ini = [evt.x, evt.y] if hasattr(self.plotutil, "fig_ct") and evt.inaxes is self.plotutil.fig_ct.axes: point = self.plotutil.pixel_to_pos( [round(evt.xdata), round(evt.ydata)]) text = "X: %.2f mm Y: %.2f mm / X: %d px Y: %d px" % ( point[1][0], point[1][1], point[0][0], point[0][1]) pub.sendMessage("statusbar.update", {"number": 1, "text": text}) dim = self.data.get_image_dimensions() if self.plotmode == "Transversal": pos = [round(evt.xdata), round(evt.ydata), self.image_idx] elif self.plotmode == "Sagital": pos = [ dim[0] - round(evt.xdata), self.image_idx, dim[2] - round(evt.ydata) ] elif self.plotmode == "Coronal": pos = [ self.image_idx, dim[1] - round(evt.xdata), dim[2] - round(evt.ydata) ] try: ct_value = self.data.get_image_cube()[pos[2], pos[1], pos[0]] text = "Value: %.1f" % (ct_value) plan = self.active_plan if plan is not None: dose = plan.get_dose_cube() if dose is not None: dose_value = dose[pos[2], pos[1], pos[0]] target_dose = plan.get_dose().get_dose() if not target_dose == 0.0: dose_value *= target_dose / 1000 text += " / Dose: %.1f Gy" % (float(dose_value)) else: dose_value /= 10 text += " / Dose: %.1f %%" % (float(dose_value)) let = plan.get_let_cube() if let is not None: let_value = let[pos[2], pos[1], pos[0]] text += " / LET: %.1f kev/um" % (let_value) except IndexError as e: pass pub.sendMessage("statusbar.update", {"number": 2, "text": text}) def normal_right_click_menu(self): menu = wx.Menu() voi_menu = wx.Menu() for voi in self.data.get_vois(): id = wx.NewId() item = voi_menu.AppendCheckItem(id, voi.get_name()) if voi.is_selected(): item.Check() wx.EVT_MENU(self, id, self.menu_voi_selected) if voi_menu.GetMenuItemCount() > 0: menu.AppendSubMenu(voi_menu, "Vois") view_menu = wx.Menu() active_plan = self.active_plan if active_plan is not None: dose = active_plan.get_dose() dose_type_menu = wx.Menu() if dose is not None: id = wx.NewId() item = view_menu.AppendCheckItem(id, "View Dose") if self.plotutil.get_dose() is not None: item.Check() wx.EVT_MENU(self, id, self.toogle_dose) id = wx.NewId() item = dose_type_menu.Append(id, "Color wash") wx.EVT_MENU(self, id, self.change_dose_to_colorwash) id = wx.NewId() item = dose_type_menu.Append(id, "Contour") wx.EVT_MENU(self, id, self.change_dose_to_contour) menu.AppendSubMenu(dose_type_menu, "Dose Visalization") if self.plotutil.get_dose_plot() == "contour": dose_contour_menu = wx.Menu() for level in self.dose_contour_levels: id = wx.NewId() item = dose_contour_menu.AppendCheckItem( id, "%d %%" % level) for contour in self.plotutil.get_dose_contours(): if contour["doselevel"] == level: item.Check() wx.EVT_MENU(self, id, self.toogle_dose_contour) menu.AppendSubMenu(dose_contour_menu, "Dose Contour levels") let = active_plan.get_let() if let is not None: id = wx.NewId() item = view_menu.AppendCheckItem(id, "View LET") if self.plotutil.get_let() is not None: item.Check() wx.EVT_MENU(self, id, self.toogle_let) if view_menu.GetMenuItemCount() > 0: menu.AppendSubMenu(view_menu, "View") field_menu = wx.Menu() for field in active_plan.get_fields(): id = wx.NewId() item = field_menu.AppendCheckItem(id, field.get_name()) if field.is_selected(): item.Check() wx.EVT_MENU(self, id, self.menu_field_selected) if field_menu.GetMenuItemCount() > 0: menu.AppendSubMenu(field_menu, "Fields") jump_menu = wx.Menu() id = wx.NewId() item = jump_menu.Append(id, "First") wx.EVT_MENU(self, id, self.jump_to_first) id = wx.NewId() item = jump_menu.Append(id, "Middle") wx.EVT_MENU(self, id, self.jump_to_middle) id = wx.NewId() item = jump_menu.Append(id, "Last") wx.EVT_MENU(self, id, self.jump_to_last) menu.AppendSubMenu(jump_menu, "Jump To") return menu def right_click_dose(self): menu = wx.Menu() id = wx.NewId() item = menu.Append(id, "Reset") wx.EVT_MENU(menu, id, self.reset_dose_range) colormap_menu = wx.Menu() id = wx.NewId() colormap_menu.Append(id, "Continuous") wx.EVT_MENU(colormap_menu, id, self.set_colormap_dose) id = wx.NewId() colormap_menu.Append(id, "Discrete") wx.EVT_MENU(colormap_menu, id, self.set_colormap_dose) item = menu.AppendSubMenu(colormap_menu, "Colorscale") scale_menu = wx.Menu() id = wx.NewId() scale_menu.Append(id, "Auto") wx.EVT_MENU(scale_menu, id, self.set_dose_scale) if self.active_plan.get_dose().get_dose() > 0.0: id = wx.NewId() scale_menu.Append(id, "Absolute") wx.EVT_MENU(scale_menu, id, self.set_dose_scale) id = wx.NewId() scale_menu.Append(id, "Relative") wx.EVT_MENU(scale_menu, id, self.set_dose_scale) item = menu.AppendSubMenu(scale_menu, "Scale") return menu def right_click_contrast(self): menu = wx.Menu() id = wx.NewId() item = menu.Append(id, "Reset") wx.EVT_MENU(menu, id, self.reset_contrast) return menu def set_colormap_dose(self, evt): colormap = plt.get_cmap(None) name = evt.GetEventObject().GetLabel(evt.GetId()) if name == "Discrete": colormap = cmap_discretize(colormap, 10) self.plotutil.set_colormap_dose(colormap) self.Draw() def set_dose_scale(self, evt): scale = {"auto": "auto", "absolute": "abs", "relative": "rel"} name = evt.GetEventObject().GetLabel(evt.GetId()) self.plotutil.set_dose_axis(scale[name.lower()]) self.Draw() def reset_dose_range(self, evt): self.plotutil.set_dose_min_max(0, 100) self.Draw() def reset_contrast(self, evt): contrast = [-100, 400] self.plotutil.set_contrast(contrast) self.Draw() def jump_to_first(self, evt): self.image_idx = 0 self.Draw() def jump_to_middle(self, evt): self.image_idx = self.plotutil.get_images_count() / 2 self.Draw() def jump_to_last(self, evt): self.image_idx = self.plotutil.get_images_count() - 1 self.Draw() def toogle_dose_contour(self, evt): value = float(evt.GetEventObject().GetLabel(evt.GetId()).split()[0]) if evt.IsChecked(): self.plotutil.add_dose_contour({"doselevel": value, "color": "b"}) else: for contour in self.plotutil.get_dose_contours(): if contour["doselevel"] == value: self.plotutil.remove_dose_contour(contour) self.Draw() def toogle_dose(self, evt): if self.plotutil.get_dose() is None: self.plotutil.set_dose(self.active_plan.get_dose().get_dosecube()) else: self.plotutil.set_dose(None) self.Draw() def toogle_let(self, evt): if self.plotutil.get_let() is None: self.plotutil.set_let(self.active_plan.get_let()) else: self.plotutil.set_let(None) self.Draw() def menu_voi_selected(self, evt): name = evt.GetEventObject().GetLabel(evt.GetId()) name = name.replace("__", "_") voi = self.data.get_vois().get_voi_by_name(name) if not voi is None: voi.toogle_selected() def menu_field_selected(self, evt): name = evt.GetEventObject().GetLabel(evt.GetId()) field = self.active_plan.get_fields().get_field_by_name(name) field.toogle_selected(self.active_plan) def change_dose_to_colorwash(self, evt): self.plotutil.set_dose_plot("colorwash") self.Draw() def change_dose_to_contour(self, evt): self.plotutil.set_dose_plot("contour") self.Draw() def on_size(self, evt): """Refresh the view when the size of the panel changes.""" self.setSize() def on_mouse_wheel(self, evt): delta = evt.GetWheelDelta() rot = evt.GetWheelRotation() rot = rot / delta if evt.ControlDown(): if (rot >= 1): self.zoom_in(None) elif (rot < 1): self.zoom_out(None) return n_images = self.data.get_images().get_voxelplan().dimz if n_images: if (rot >= 1): if (self.image_idx > 0): self.image_idx -= 1 self.Draw() if (rot <= -1): if (self.image_idx < self.plotutil.get_images_count() - 1): self.image_idx += 1 self.Draw() def on_key_down(self, evt): prevkey = [wx.WXK_UP, wx.WXK_PAGEUP] nextkey = [wx.WXK_DOWN, wx.WXK_PAGEDOWN] code = evt.GetKeyCode() if code in prevkey: if (self.image_idx > 0): self.image_idx -= 1 self.Draw() elif code in nextkey: if (self.image_idx < self.plotutil.get_images_count() - 1): self.image_idx += 1 self.Draw() def on_mouse_enter(self, evt): """Set a flag when the cursor enters the window.""" self.mouse_in_window = True def on_mouse_leave(self, evt): """Set a flag when the cursor leaves the window.""" self.mouse_in_window = False def setSize(self): size = self.parent.GetClientSize() size[1] = size[1] - 40 size[0] = size[0] - 5 pixels = tuple(size) self.canvas.SetSize(pixels) self.figure.set_size_inches( float(pixels[0]) / self.figure.get_dpi(), float(pixels[1]) / self.figure.get_dpi()) self.Draw() def Draw(self): self.plotutil.plot(self.image_idx) self.figure.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None) # self.figure.tight_layout(pad=0.0) if hasattr(self.plotutil, "dose_bar"): bar = self.plotutil.dose_bar bar.ax.yaxis.label.set_color('white') bar.ax.tick_params(axis='y', colors='white', labelsize=8) if hasattr(self.plotutil, "let_bar"): bar = self.plotutil.let_bar bar.ax.yaxis.label.set_color('white') bar.ax.yaxis.label.set_color('white') bar.ax.tick_params(axis='y', colors='white', labelsize=8) if hasattr(self.plotutil, "contrast_bar"): bar = self.plotutil.contrast_bar bar.ax.yaxis.label.set_color('white') bar.ax.yaxis.set_label_position('left') [t.set_color("white") for t in bar.ax.yaxis.get_ticklabels()] [t.set_size(8) for t in bar.ax.yaxis.get_ticklabels()] # bar.ax.tick_params(axis='y', colors='white',labelsize=8,labelleft=True,labelright=False) self.canvas.draw()
class Calculatrice(Panel_simple): __titre__ = u"Calculatrice" # Donner un titre a chaque module def __init__(self, *args, **kw): Panel_simple.__init__(self, *args, **kw) self.interprete = Interprete(calcul_exact = self.param("calcul_exact"), ecriture_scientifique = self.param("ecriture_scientifique"), changer_separateurs = self.param("changer_separateurs"), separateurs_personnels = self.param("separateurs_personnels"), copie_automatique = self.param("copie_automatique"), formatage_OOo = self.param("formatage_OOo"), formatage_LaTeX = self.param("formatage_LaTeX"), ecriture_scientifique_decimales = self.param("ecriture_scientifique_decimales"), precision_calcul = self.param("precision_calcul"), precision_affichage = self.param("precision_affichage"), simpify = True, ) ## self.entrees = wx.BoxSizer(wx.HORIZONTAL) ## self.entree = wx.TextCtrl(self, size = (550, -1), style = wx.TE_PROCESS_ENTER) ## self.entrees.Add(self.entree, 1, wx.ALL|wx.GROW, 5) ## self.valider = wx.Button(self, wx.ID_OK) ## self.entrees.Add(self.valider, 0, wx.ALL, 5) self.entree = LigneCommande(self, longueur = 550, action = self.affichage_resultat) self.entree.SetToolTip(wx.ToolTip(u"[Maj]+[Entrée] pour une valeur approchée.")) self.corps = wx.BoxSizer(wx.HORIZONTAL) self.gauche = wx.BoxSizer(wx.VERTICAL) self.resultats = wx.TextCtrl(self, size = (450,310), style = wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH) self.gauche.Add(self.resultats, 0, wx.ALL, 5) self.figure = Figure(figsize=(5,1.3),frameon=True, facecolor="w") self.visualisation = FigureCanvas(self, -1, self.figure) self.axes = self.figure.add_axes([0, 0, 1, 1], frameon=False) self.axes.axison = False self.pp_texte = self.axes.text(0.5, 0.5, "", horizontalalignment='center', verticalalignment='center', transform = self.axes.transAxes, size=18) self.gauche.Add(self.visualisation, 0, wx.ALL|wx.ALIGN_CENTER, 5) self.corps.Add(self.gauche, 0, wx.ALL, 5) ### Pave numerique de la calculatrice ### # On construit le pavé de la calculatrice. # Chaque bouton du pavé doit provoquer l'insertion de la commande correspondante. self.pave = wx.BoxSizer(wx.VERTICAL) self.corps.Add(self.pave, 0, wx.ALL, 5) boutons = ["2nde", "ans", "ouv", "ferm", "egal", "7", "8", "9", "div", "x", "4", "5", "6", "mul", "y", "1", "2", "3", "minus", "z", "0", "pt", "pow", "plus", "t", "rac", "sin", "cos", "tan", "exp", "i", "pi", "e", "abs", "mod"] inserer = ["", "ans()", "(", ")", "=", "7", "8", "9", "/", "x", "4", "5", "6", "*", "y", "1", "2", "3", "-", "z", "0", ".", "^", "+", "t", "sqrt(", ("sin(", "asin(", "sinus / arcsinus"), ("cos(", "acos(", "cosinus / arccosinus"), ("tan(", "atan(", "tangente / arctangente"), ("exp(", "ln(", "exponentielle / logarithme neperien"), ("i", "cbrt(", "i / racine cubique"), ("pi", "sinh(", "pi / sinus hyperbolique"), ("e", "cosh", "e / cosinus hyperbolique"), ("abs(", "tanh", "valeur absolue / tangente hyperbolique"), (" mod ", "log10(", "modulo / logarithme decimal")] self.seconde = False # indique si la touche 2nde est activee. def action(event = None): self.seconde = not self.seconde if self.seconde: self.message(u"Touche [2nde] activée.") else: self.message("") self.actions = [action] for i in range(len(boutons)): # On aligne les boutons de la calculatrice par rangees de 5. if i%5 == 0: self.rangee = wx.BoxSizer(wx.HORIZONTAL) self.pave.Add(self.rangee, 0, wx.ALL,0) # Ensuite, on construit une liste de fonctions, parallelement à la liste des boutons. if i > 0: def action(event = None, entree = self.entree, j = i): if type(inserer[j]) == tuple: entree.WriteText(inserer[j][self.seconde]) else: entree.WriteText(inserer[j]) n = entree.GetInsertionPoint() entree.SetFocus() entree.SetInsertionPoint(n) self.seconde = False self.message("") self.actions.append(action) bmp = png('btn_' + boutons[i]) bouton = wx.BitmapButton(self, -1, bmp, style=wx.NO_BORDER) bouton.SetBackgroundColour(self.GetBackgroundColour()) espace = 3 if param.plateforme == "Linux": espace = 0 self.rangee.Add(bouton, 0, wx.ALL, espace) # A chaque bouton, on associe une fonction de la liste. bouton.Bind(wx.EVT_BUTTON, self.actions[i]) if type(inserer[i]) == tuple: bouton.SetToolTipString(inserer[i][2]) self.pave.Add(wx.BoxSizer(wx.HORIZONTAL)) ### Liste des options ### # En dessous du pavé apparait la liste des différents modes de fonctionnement de la calculatrice. # Calcul exact ligne = wx.BoxSizer(wx.HORIZONTAL) self.cb_calcul_exact = wx.CheckBox(self) self.cb_calcul_exact.SetValue(not self.param("calcul_exact")) ligne.Add(self.cb_calcul_exact, flag = wx.ALIGN_CENTER_VERTICAL) ligne.Add(wx.StaticText(self, -1, u" Valeur approchée."), flag = wx.ALIGN_CENTER_VERTICAL) self.pave.Add(ligne) self.cb_calcul_exact.Bind(wx.EVT_CHECKBOX, self.EvtCalculExact) # Notation scientifique ligne = wx.BoxSizer(wx.HORIZONTAL) self.cb_notation_sci = wx.CheckBox(self) self.cb_notation_sci.SetValue(self.param("ecriture_scientifique")) ligne.Add(self.cb_notation_sci, flag = wx.ALIGN_CENTER_VERTICAL) self.st_notation_sci = wx.StaticText(self, -1, u" Écriture scientifique (arrondie à ") ligne.Add(self.st_notation_sci, flag = wx.ALIGN_CENTER_VERTICAL) self.sc_decimales = wx.SpinCtrl(self, -1, size = (45, -1), min = 0, max = 11) self.sc_decimales.SetValue(self.param("ecriture_scientifique_decimales")) ligne.Add(self.sc_decimales, flag = wx.ALIGN_CENTER_VERTICAL) self.st_decimales = wx.StaticText(self, -1, u" décimales).") ligne.Add(self.st_decimales, flag = wx.ALIGN_CENTER_VERTICAL) self.pave.Add(ligne) self.EvtCalculExact() self.cb_notation_sci.Bind(wx.EVT_CHECKBOX, self.EvtNotationScientifique) self.sc_decimales.Bind(wx.EVT_SPINCTRL, self.EvtNotationScientifique) # Copie du résultat dans le presse-papier ligne = wx.BoxSizer(wx.HORIZONTAL) self.cb_copie_automatique = wx.CheckBox(self) self.cb_copie_automatique.SetValue(self.param("copie_automatique")) ligne.Add(self.cb_copie_automatique, flag = wx.ALIGN_CENTER_VERTICAL) ligne.Add(wx.StaticText(self, -1, u" Copie du résultat dans le presse-papier."), flag = wx.ALIGN_CENTER_VERTICAL) self.pave.Add(ligne) self.cb_copie_automatique.Bind(wx.EVT_CHECKBOX, self.EvtCopieAutomatique) # En mode LaTeX ligne = wx.BoxSizer(wx.HORIZONTAL) self.cb_copie_automatique_LaTeX = wx.CheckBox(self) self.cb_copie_automatique_LaTeX.SetValue(self.param("copie_automatique_LaTeX")) ligne.Add(self.cb_copie_automatique_LaTeX, flag = wx.ALIGN_CENTER_VERTICAL) self.st_copie_automatique_LaTeX = wx.StaticText(self, -1, u" Copie au format LaTeX (si possible).") ligne.Add(self.st_copie_automatique_LaTeX, flag = wx.ALIGN_CENTER_VERTICAL) self.pave.Add(ligne) self.EvtCopieAutomatique() self.cb_copie_automatique_LaTeX.Bind(wx.EVT_CHECKBOX, self.EvtCopieAutomatiqueLatex) # Autres options self.options = [(u"Virgule comme séparateur décimal.", u"changer_separateurs"), ## (u"Copie du résultat dans le presse-papier.", u"copie_automatique"), (u"Accepter la syntaxe OpenOffice.org", u"formatage_OOo"), (u"Accepter la syntaxe LaTeX", u"formatage_LaTeX"), ] self.options_box = [] for i in range(len(self.options)): ligne = wx.BoxSizer(wx.HORIZONTAL) self.options_box.append(wx.CheckBox(self)) ligne.Add(self.options_box[i], flag = wx.ALIGN_CENTER_VERTICAL) self.options_box[i].SetValue(self.param(self.options[i][1])) def action(event, chaine = self.options[i][1], entree = self.entree, self = self): self.param(chaine, not self.param(chaine)) entree.SetFocus() self.options_box[i].Bind(wx.EVT_CHECKBOX, action) ligne.Add(wx.StaticText(self, -1, " " + self.options[i][0]), flag = wx.ALIGN_CENTER_VERTICAL) self.pave.Add(ligne) self.option1 = wx.BoxSizer(wx.HORIZONTAL) self.pave.Add(self.option1) #wx.CheckBox(self) self.option2 = wx.BoxSizer(wx.HORIZONTAL) self.pave.Add(self.option2) self.sizer = wx.BoxSizer(wx.VERTICAL) ## self.sizer.Add(self.entrees, 0, wx.ALL, 5) self.sizer.Add(self.entree, 0, wx.ALL, 5) self.sizer.Add(self.corps, 0, wx.ALL, 5) self.SetSizer(self.sizer) self.Fit() # historique des calculs ## self.entree.Bind(wx.EVT_KEY_UP, self.EvtChar) self.entree.texte.Bind(wx.EVT_RIGHT_DOWN, self.EvtMenu) ## #self.Bind(wx.EVT_CHAR, self.EvtChar, self.entree) ## self.valider.Bind(wx.EVT_BUTTON, self.affichage_resultat) self.visualisation.Bind(wx.EVT_RIGHT_DOWN, self.EvtMenuVisualisation) self.initialiser() def activer(self): # Actions à effectuer lorsque l'onglet devient actif self.entree.SetFocus() def _sauvegarder(self, fgeo): fgeo.contenu["Calculatrice"] = [{}] fgeo.contenu["Calculatrice"][0]["Historique"] = [repr(self.entree.historique)] # fgeo.contenu["Calculatrice"][0]["Resultats"] = [repr(self.interprete.derniers_resultats)] fgeo.contenu["Calculatrice"][0]["Affichage"] = [self.resultats.GetValue()] fgeo.contenu["Calculatrice"][0]["Etat_interne"] = [self.interprete.save_state()] fgeo.contenu["Calculatrice"][0]["Options"] = [{}] for i in range(len(self.options)): fgeo.contenu["Calculatrice"][0]["Options"][0][self.options[i][1]] = [str(self.options_box[i].GetValue())] def _ouvrir(self, fgeo): if fgeo.contenu.has_key("Calculatrice"): calc = fgeo.contenu["Calculatrice"][0] self.initialiser() self.entree.historique = eval_safe(calc["Historique"][0]) # self.interprete.derniers_resultats = securite.eval_safe(calc["Resultats"][0]) self.resultats.SetValue(calc["Affichage"][0] + "\n") self.interprete.load_state(calc["Etat_interne"][0]) liste = calc["Options"][0].items() options = [option for aide, option in self.options] for key, value in liste: value = eval_safe(value[0]) self.param(key, value) if key in options: self.options_box[options.index(key)].SetValue(value) # il faudrait encore sauvegarder les variables, mais la encore, 2 problemes : # - pb de securite pour evaluer les variables # - pb pour obtenir le code source d'une fonction. # Pour remedier a cela, il faut envisager de : # - creer un module d'interpretation securisee. # - rajouter a chaque fonction un attribut __code__, ou creer une nouvelle classe. def modifier_pp_texte(self, chaine): u"""Modifier le résultat affiché en LaTeX (pretty print).""" if self.param("latex"): chaine = "$" + chaine + "$" else: chaine = chaine.replace("\\mapsto", "\\rightarrow") if chaine.startswith(r"$\begin{bmatrix}"): chaine = chaine.replace(r"\begin{bmatrix}", r'\left({') chaine = chaine.replace(r"\end{bmatrix}", r'}\right)') chaine = chaine.replace(r"&", r'\,') self.pp_texte.set_text(chaine) self.visualisation.draw() def vers_presse_papier(self, event = None, texte = None): if texte is None: texte = self.dernier_resultat Panel_simple.vers_presse_papier(texte) def copier_latex(self, event = None): self.vers_presse_papier(texte = self.interprete.latex_dernier_resultat.strip("$")) def initialiser(self, event = None): self.dernier_resultat = "" # dernier resultat, sous forme de chaine formatee pour l'affichage self.entree.initialiser() self.interprete.initialiser() self.resultats.Clear() def affichage_resultat(self, commande, **kw): # Commandes spéciales: if commande in ('clear', 'clear()', 'efface', 'efface()'): self.initialiser() self.modifier_pp_texte(u"Calculatrice réinitialisée.") return self.modifie = True try: try: if kw["shift"]: self.interprete.calcul_exact = False resultat, latex = self.interprete.evaluer(commande) if latex == "$?$": # provoque une erreur (matplotlib 0.99.1.1) latex = u"Désolé, je ne sais pas faire..." finally: self.interprete.calcul_exact = self.param('calcul_exact') aide = resultat.startswith("\n== Aide sur ") #LaTeX debug("Expression LaTeX: " + latex) try: self.modifier_pp_texte((latex or resultat) if not aide else '') except Exception: print_error() self.modifier_pp_texte("<Affichage impossible>") #Presse-papier self.dernier_resultat = resultat if self.param("copie_automatique"): if self.param("copie_automatique_LaTeX"): self.copier_latex() else: self.vers_presse_papier() # TextCtrl numero = str(len(self.interprete.derniers_resultats)) # Évite le décalage entre la première ligne et les suivantes (matrices) if "\n" in resultat and not aide: resultat = "\n" + "\n".join(20*" " + ligne for ligne in resultat.split("\n")) self.resultats.AppendText(u" Calcul n\xb0" + numero + " : " + uu(commande) + u"\n Résultat :" + " "*(4+len(numero)) + resultat + "\n__________________\n\n") self.message(u"Calcul effectué." + self.interprete.warning) self.entree.Clear() self.resultats.SetInsertionPoint(len(self.resultats.GetValue())) self.resultats.SetFocus() self.resultats.ScrollLines(1) self.entree.SetFocus() except Exception: self.message(u"Calcul impossible.") self.entree.SetFocus() if param.debug: raise def EvtMenu(self, event): if not event.ControlDown(): event.Skip() return def generer_fonction(nom, parenthese = True, self = self): def f(event = None, panel = self, nom = nom, parenthese = parenthese): deb, fin = panel.entree.GetSelection() if parenthese: panel.entree.SetInsertionPoint(fin) panel.entree.WriteText(")") panel.entree.SetInsertionPoint(deb) panel.entree.WriteText(nom + "(") panel.entree.SetFocus() if deb == fin: final = fin + len(nom) + 1 else: final = fin + len(nom) + 2 else: panel.entree.WriteText(nom) final = fin + len(nom) panel.entree.SetFocus() panel.entree.SetInsertionPoint(final) panel.entree.SetSelection(final, final) return f menu = wx.Menu() menu.SetTitle(u"Fonctions mathématiques") debut = True for rubrique in __classement__: if not debut: menu.AppendSeparator() debut = False for titre, nom, doc in __classement__[rubrique]: i = wx.NewId() menu.Append(i, titre, doc) if rubrique != "Symboles": menu.Bind(wx.EVT_MENU, generer_fonction(nom), id =i) else: menu.Bind(wx.EVT_MENU, generer_fonction(nom, False), id =i) # pas de parenthese apres un symbole self.PopupMenu(menu) menu.Destroy() # self.entree.SetFocus() def EvtMenuVisualisation(self, event): menu = wx.Menu() i = wx.NewId() menu.Append(i, "Copier LaTeX", "Copier le code LaTeX dans le presse-papier.") menu.Bind(wx.EVT_MENU, self.copier_latex, id=i) self.PopupMenu(menu) menu.Destroy() def param(self, parametre, valeur = no_argument, defaut = False): if valeur is not no_argument: setattr(self.interprete, parametre, valeur) return Panel_simple.param(self, parametre = parametre, valeur = valeur, defaut = defaut) def EvtCalculExact(self, event = None): valeur = self.cb_calcul_exact.GetValue() self.param("calcul_exact", not valeur) if valeur: self.cb_notation_sci.Enable() self.st_notation_sci.Enable() self.sc_decimales.Enable() self.st_decimales.Enable() else: self.cb_notation_sci.Disable() self.st_notation_sci.Disable() self.sc_decimales.Disable() self.st_decimales.Disable() def EvtNotationScientifique(self, event = None): self.param("ecriture_scientifique", self.cb_notation_sci.GetValue()) self.param("ecriture_scientifique_decimales", self.sc_decimales.GetValue()) def EvtCopieAutomatique(self, event = None): valeur = self.cb_copie_automatique.GetValue() self.param("copie_automatique", valeur) if valeur: self.cb_copie_automatique_LaTeX.Enable() self.st_copie_automatique_LaTeX.Enable() else: self.cb_copie_automatique_LaTeX.Disable() self.st_copie_automatique_LaTeX.Disable() def EvtCopieAutomatiqueLatex(self, event = None): self.param("copie_automatique_LaTeX", self.cb_copie_automatique_LaTeX.GetValue()) def EtatInterne(self, event): contenu = self.interprete.save_state() h = FenCode(self, u"État interne de l'inteprète", contenu, self.interprete.load_state) h.Show(True)
class matplotsink(wx.Panel): def __init__(self, parent, title, queue, gsz, zoom): wx.Panel.__init__(self, parent, wx.SIMPLE_BORDER) self.gsz = gsz self.parent = parent self.title = title self.q = queue self.zoom = zoom self.paused = False # self.create_menu() # self.create_status_bar() self.create_main_panel() def create_menu(self): self.menubar = wx.MenuBar() menu_file = wx.Menu() m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to file") self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt) menu_file.AppendSeparator() m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit") self.Bind(wx.EVT_MENU, self.on_exit, m_exit) self.menubar.Append(menu_file, "&File") self.SetMenuBar(self.menubar) def create_main_panel(self): self.panel = self self.init_plot() self.canvas = FigCanvas(self.panel, -1, self.fig) self.scroll_range = 400 self.canvas.SetScrollbar(wx.HORIZONTAL, 0, 5, self.scroll_range) self.canvas.Bind(wx.EVT_SCROLLWIN, self.OnScrollEvt) self.pause_button = wx.Button(self.panel, -1, "Pause") self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button) self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button, self.pause_button) self.cb_grid = wx.CheckBox(self.panel, -1, "Show Grid", style=wx.ALIGN_RIGHT) self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid) self.cb_grid.SetValue(True) self.cb_xlab = wx.CheckBox(self.panel, -1, "Show X labels", style=wx.ALIGN_RIGHT) self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab) self.cb_xlab.SetValue(True) self.hbox1 = wx.BoxSizer(wx.HORIZONTAL) self.hbox1.Add(self.pause_button, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL) self.hbox1.AddSpacer(20) self.hbox1.Add(self.cb_grid, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL) self.hbox1.AddSpacer(10) self.hbox1.Add(self.cb_xlab, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL) self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW) self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP) self.panel.SetSizer(self.vbox) self.vbox.Fit(self) self.ani = animation.FuncAnimation(self.fig, self.draw_plot, interval=100) def OnScrollEvt(self, event): self.i_start = event.GetPosition() self.i_end = self.i_window + event.GetPosition() self.draw_plot(0) def create_status_bar(self): self.statusbar = self.CreateStatusBar() def draw_test(self, event): self.xar = np.arange(len(self.q.queue)) self.yar = np.array(self.q.queue) self.axes.plot(self.xar, self.yar) def init_plot(self): self.dpi = 100 self.fig = Figure((3.0, 3.0), dpi=self.dpi) self.fig.set_size_inches(7.0, 4.0) self.fig.set_dpi(self.dpi) self.axes = self.fig.add_subplot(111) self.axes.set_axis_bgcolor('black') self.axes.set_title(self.title, size=12) pylab.setp(self.axes.get_xticklabels(), fontsize=8) pylab.setp(self.axes.get_yticklabels(), fontsize=8) self.i_window = self.gsz self.i_start = 0 self.i_end = self.i_start + self.i_window # plot the data as a line series, and save the reference # to the plotted line series # self.plot_data = self.axes.plot( [], linewidth=1, color=(1, 1, 0), )[0] def draw_plot(self, event): """ Redraws the plot """ if len(list(self.q.queue)) > 1 and not self.paused: if self.zoom: xmax = len(list( self.q.queue)) if len(list(self.q.queue)) > 50 else 50 xmin = xmax - 50 # for ymin and ymax, find the minimal and maximal values # in the data set and add a mininal margin. # # note that it's easy to change this scheme to the # minimal/maximal value in the current display, and not # the whole data set. # ymin = round(min(list(self.q.queue)), 0) - 1 ymax = round(max(list(self.q.queue)), 0) + 1 self.axes.set_xbound(lower=xmin, upper=xmax) self.axes.set_ybound(lower=ymin, upper=ymax) # anecdote: axes.grid assumes b=True if any other flag is # given even if b is set to False. # so just passing the flag into the first statement won't # work. # if self.cb_grid.IsChecked(): self.axes.grid(True, color='gray') else: self.axes.grid(False) # Using setp here is convenient, because get_xticklabels # returns a list over which one needs to explicitly # iterate, and setp already handles this. # pylab.setp(self.axes.get_xticklabels(), visible=self.cb_xlab.IsChecked()) self.plot_data.set_xdata(np.arange(len(list(self.q.queue)))) self.plot_data.set_ydata(np.array(list(self.q.queue))) self.canvas.draw() else: if self.cb_grid.IsChecked(): self.axes.grid(True, color='gray') else: self.axes.grid(False) # Using setp here is convenient, because get_xticklabels # returns a list over which one needs to explicitly # iterate, and setp already handles this. pylab.setp(self.axes.get_xticklabels(), visible=self.cb_xlab.IsChecked()) self.plot_data.set_xdata( np.arange(len(list( self.q.queue)))[self.i_start:self.i_end]) self.plot_data.set_ydata( np.array(list(self.q.queue))[self.i_start:self.i_end]) self.axes.set_xlim( min( np.arange(len(list( self.q.queue)))[self.i_start:self.i_end]), max( np.arange(len(list( self.q.queue)))[self.i_start:self.i_end])) # if self.zoom: self.axes.set_ylim(min(np.array(list(self.q.queue))), max(np.array(list(self.q.queue)))) self.canvas.draw() def on_pause_button(self, event): self.paused = not self.paused def on_update_pause_button(self, event): label = "Resume" if self.paused else "Pause" self.pause_button.SetLabel(label) def on_cb_grid(self, event): self.draw_plot(0) def on_cb_xlab(self, event): self.draw_plot(0) def on_save_plot(self, event): file_choices = "PNG (*.png)|*.png" dlg = wx.FileDialog(self, message="Save plot as...", defaultDir=os.getcwd(), defaultFile="plot.png", wildcard=file_choices, style=wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path, dpi=self.dpi) self.flash_status_message("Saved to %s" % path) def on_redraw_timer(self, event): # if paused do not add data, but still redraw the plot # (to respond to scale modifications, grid change, etc.) # if not self.paused: self.data += self.datagen.next() self.draw_plot(0) def on_exit(self, event): self.Destroy() def flash_status_message(self, msg, flash_len_ms=1500): self.statusbar.SetStatusText(msg) self.timeroff = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.on_flash_status_off, self.timeroff) self.timeroff.Start(flash_len_ms, oneShot=True) def on_flash_status_off(self, event): self.statusbar.SetStatusText('')
class PlotPanel(wx.Panel): def __init__(self, parent, app): self._app = app self._plot_context = app._plot_context self.animation = None self.canvas_force_resize = False self.canvas_last_resize_s = None wx.Panel.__init__(self, parent, -1) self.canvas = FigureCanvasWxAgg(self, -1, self._plot_context.fig) self.toolbar = NavigationToolbar2WxAgg( self.canvas) # matplotlib toolbar self.toolbar.Realize() self.canvas.Bind(wx.EVT_SIZE, self.OnSizeCanvas) # Now put all into a sizer which will resize the figure when the window size changes sizer = wx.BoxSizer(wx.VERTICAL) # This way of adding to sizer allows resizing sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) # Best to allow the toolbar to resize! sizer.Add(self.toolbar, 0, wx.GROW) self.SetSizer(sizer) self.Fit() def OnSizeCanvas(self, event): logger.debug(f"_on_size_canvas {event.GetSize()}") self.canvas_last_resize_s = time.time() if self.canvas_force_resize: event.Skip() def init_plot_data(self): self.toolbar.update() # Not sure why this is needed - ADS def endless_iter(): yield from itertools.count(start=42) self._plot_context.plotData.startup_duration.log( "FuncAnimation() - before") self.animation = matplotlib.animation.FuncAnimation( fig=self._plot_context.fig, func=self.animate, frames=endless_iter(), # Delay between frames in milliseconds interval=1000, # A function used to draw a clear frame. If not given, the results of drawing from the first item in the frames sequence will be used. init_func=None, repeat=False, ) self._plot_context.plotData.startup_duration.log( "FuncAnimation() - after") # Important: If this statement is BEFORE 'FuncAnimation', the animation sometimes does not start! with Duration("update_presentation():") as elapsed: self._plot_context.update_presentation() def GetToolBar(self): # You will need to override GetToolBar if you are using an # unmanaged toolbar in your frame return self.toolbar @log_duration def animate(self, i): self._plot_context.plotData.startup_duration.log( "animate() - beginning") if self.canvas_last_resize_s: # The frame has been resized if self.canvas_last_resize_s + 0.5 < time.time(): # And the last event was more than 500ms ago logger.info("matplotlib-canvas: delayed resize") # self.canvas.SetSize(self.canvas_requested_size) self.canvas_force_resize = True self.Layout() self.canvas_force_resize = False self.canvas_last_resize_s = None self._plot_context.animate()
class PlotFrame(wx.Frame): help_msg = """ Menus for Save export figure (png,eps,bmp) to file Copy copy bitmap of figure to the system clipboard Print Setup setup size of figure for printing Print Preview preview printer page Print send figure to a system printer Exit end application where 'figure' means an image of the matplotlib canvas In addition, "Ctrl-C" is bound to copy-figure-to-clipboard """ start_msg = """ Use Menus to test printing or Ctrl-C to copy plot image to clipboard """ about_msg = """ printing_in_wx version 0.1 12-Nov-2004 Matt Newville <*****@*****.**>""" def __init__(self): wx.Frame.__init__(self, None, -1, "Test Printing with WX Backend") self.fig = Figure((5.0, 3.0), 100) self.canvas = FigCanvas(self, -1, self.fig) self.axes = self.fig.add_axes([0.15, 0.15, 0.75, 0.75]) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) sizer.Add(wx.StaticText(self, -1, self.start_msg), 0, wx.ALIGN_LEFT | wx.TOP) self.canvas.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent) self.SetSizer(sizer) self.Fit() self.Build_Menus() self.Plot_Data() def Build_Menus(self): """ build menus """ MENU_EXIT = wx.NewId() MENU_SAVE = wx.NewId() MENU_PRINT = wx.NewId() MENU_PSETUP = wx.NewId() MENU_PREVIEW = wx.NewId() MENU_CLIPB = wx.NewId() MENU_HELP = wx.NewId() menuBar = wx.MenuBar() f0 = wx.Menu() f0.Append(MENU_SAVE, "&Export", "Save Image of Plot") f0.AppendSeparator() f0.Append(MENU_PSETUP, "Page Setup...", "Printer Setup") f0.Append(MENU_PREVIEW, "Print Preview...", "Print Preview") f0.Append(MENU_PRINT, "&Print", "Print Plot") f0.AppendSeparator() f0.Append(MENU_EXIT, "E&xit", "Exit") menuBar.Append(f0, "&File") f1 = wx.Menu() f1.Append(MENU_HELP, "Quick Reference", "Quick Reference") menuBar.Append(f1, "&Help") self.SetMenuBar(menuBar) self.Bind(wx.EVT_MENU, self.onPrint, id=MENU_PRINT) self.Bind(wx.EVT_MENU, self.onPrinterSetup, id=MENU_PSETUP) self.Bind(wx.EVT_MENU, self.onPrinterPreview, id=MENU_PREVIEW) self.Bind(wx.EVT_MENU, self.onClipboard, id=MENU_CLIPB) self.Bind(wx.EVT_MENU, self.onExport, id=MENU_SAVE) self.Bind(wx.EVT_MENU, self.onExit, id=MENU_EXIT) self.Bind(wx.EVT_MENU, self.onHelp, id=MENU_HELP) # the printer / clipboard methods are implemented # in backend_wx, and so are very simple to use. def onPrinterSetup(self, event=None): self.canvas.Printer_Setup(event=event) def onPrinterPreview(self, event=None): self.canvas.Printer_Preview(event=event) def onPrint(self, event=None): self.canvas.Printer_Print(event=event) def onClipboard(self, event=None): self.canvas.Copy_to_Clipboard(event=event) def onKeyEvent(self, event=None): """ capture , act upon keystroke events""" if event == None: return key = event.KeyCode() if (key < wx.WXK_SPACE or key > 255): return if (event.ControlDown() and chr(key) == 'C'): # Ctrl-C self.onClipboard(event=event) def onHelp(self, event=None): dlg = wx.MessageDialog(self, self.help_msg, "Quick Reference", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onExport(self, event=None): """ save figure image to file""" file_choices = "PNG (*.png)|*.png|" \ "PS (*.ps)|*.ps|" \ "EPS (*.eps)|*.eps|" \ "BMP (*.bmp)|*.bmp" thisdir = os.getcwd() dlg = wx.FileDialog(self, message='Save Plot Figure as...', defaultDir=thisdir, defaultFile='plot.png', wildcard=file_choices, style=wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path, dpi=300) if (path.find(thisdir) == 0): path = path[len(thisdir) + 1:] print 'Saved plot to %s' % path def onExit(self, event=None): self.Destroy() def Plot_Data(self): t = numpy.arange(0.0, 5.0, 0.01) s = numpy.sin(2.0 * numpy.pi * t) c = numpy.cos(0.4 * numpy.pi * t) self.axes.plot(t, s) self.axes.plot(t, c)
class PlotFrame(wx.Frame): help_msg=""" Menus for Import...import project settings file Export...export figure (png, jpg) to file Print Setup...setup size of figure for printing Print Preview...preview printer page Print...send figure to a system printer Exit...end application Basic-2D...View basic 2D representation of data Advanced-2D...View 2D representation (with span selection control) Advanced-3D...View 3D representation of data View-Grid...Toggle grid View-Legend...Toggle legend View-Fill...Toggle fill representation of data (only for 2D) where 'figure' means an image of the matplotlib canvas In addition, "Ctrl-C" is bound to copy-figure-to-clipboard """ about_msg=""" Option_price_visualisation v0.1 29-Aug-2013 Nathan Floor, [email protected] """ def __init__(self): wx.Frame.__init__(self, None, -1, "Visualise Option Prices and Greeks", size=(300, 500)) self.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent) # intialise variables when start program self.viewLegend = False self.viewGrid = True self.viewFill = False self.reInitialiseData() # build interface self.Build_Menus() self.Build_Panel() self.statusbar = self.CreateStatusBar() self.Plot_Data() self.SetSize(size=(900, 550)) def reInitialiseData(self): self.fileReader = csvReader.Reader() self.current_view = 0 self.time = numpy.arange(0, 31, 1) self.indmin = 0 self.indmax = 31 self.strike_price = 0 # initialise data arrays self.option_price = [] self.stock_price = [] self.delta = [] self.gamma = [] self.vega = [] self.theta = [] self.rho = [] self.risidual = [] # initialise secondary data sets self.option_price_fill = [] self.time_span_fill = [] self.delta_fill = [] self.gamma_fill = [] self.vega_fill = [] self.theta_fill = [] self.rho_fill = [] # initialise bump values self.stock_bump = 0 self.time_bump = 0 self.rate_bump = 0 self.volitile_bump = 0 # on span-selection of graph def onselect(self, xmin, xmax): # initialise data sets option_price = [] delta = [] gamma = [] theta = [] rho = [] vega = [] maxYLimlist = [] minYLimlist = [] # identify the indices of new data set based on selection self.indmin = int(xmin) #self.indmax = numpy.searchsorted(t, (xmin, xmax)) self.indmax = min(len(self.time)-1, int(xmax)+1) self.time_span_fill = self.time[self.indmin:self.indmax] if len(self.option_price) > 0: option_price = numpy.array(map(float, self.option_price[self.stock_bump])) self.option_price_fill = option_price[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.option_price_fill)) minYLimlist.append(min(self.option_price_fill)) if not self.viewFill: self.line1.set_data(self.time_span_fill, self.option_price_fill) if len(self.delta) > 0: delta = numpy.array(map(float, self.delta[self.stock_bump])) self.delta_fill = delta[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.delta_fill)) minYLimlist.append(min(self.delta_fill)) if not self.viewFill: self.line2.set_data(self.time_span_fill, self.delta_fill) if len(self.gamma) > 0: gamma = numpy.array(map(float, self.gamma[self.stock_bump])) self.gamma_fill = gamma[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.gamma_fill)) minYLimlist.append(min(self.gamma_fill)) if not self.viewFill: self.line3.set_data(self.time_span_fill, self.gamma_fill) if len(self.theta) > 0: theta = numpy.array(map(float, self.theta[self.time_bump])) self.theta_fill = theta[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.theta_fill)) minYLimlist.append(min(self.theta_fill)) if not self.viewFill: self.line4.set_data(self.time_span_fill, self.theta_fill) if len(self.rho) > 0: rho = numpy.array(map(float, self.rho[self.rate_bump])) self.rho_fill = rho[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.rho_fill)) minYLimlist.append(min(self.rho_fill)) if not self.viewFill: self.line5.set_data(self.time_span_fill, self.rho_fill) if len(self.vega) > 0: vega = numpy.array(map(float, self.vega[self.volitile_bump])) self.vega_fill = vega[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.vega_fill)) minYLimlist.append(min(self.vega_fill)) if not self.viewFill: self.line6.set_data(self.time_span_fill, self.vega_fill) if len(self.risidual) > 0: risidual = numpy.array(map(float, self.risidual[self.stock_bump])) self.risidual_fill = risidual[self.indmin:self.indmax] # append to lists for axes limits maxYLimlist.append(max(self.risidual_fill)) minYLimlist.append(min(self.risidual_fill)) if not self.viewFill: self.line7.set_data(self.time_span_fill, self.risidual_fill) if len(maxYLimlist) > 0: maxYLim = max(maxYLimlist) else: maxYLim = 1 if len(minYLimlist) > 0: minYLim = min(minYLimlist) else: minYLim = 0 self.axes2.set_xlim(self.time_span_fill[0]-1, self.time_span_fill[-1]+1) self.axes2.set_ylim(minYLim, maxYLim) if not self.viewFill: self.canvas.draw() else: self.Plot_Data() def Build_Panel(self): self.panel = wx.Panel(self) # Create Figure and canvas objects self.fig = Figure((6.0, 4.0)) self.canvas = FigCanvas(self.panel, -1, self.fig) self.axes = self.fig.add_subplot(111) # setup slider-widgets for controlling GUI self.sliderPanel = wx.Panel(self.panel) self.stockSlider_label = wx.StaticText(self.sliderPanel, -1, "Stock Price: ") self.stockSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS) # self.stockSlider.SetTickFreq(9, 1) self.rateSlider_label = wx.StaticText(self.sliderPanel, -1, "Interest Rate: ") self.rateSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS) self.rateSlider.SetTickFreq(1, 1) self.timeStepSlider_label = wx.StaticText(self.sliderPanel, -1, "Time Step: ") self.timeStepSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS) self.timeStepSlider.SetTickFreq(1, 1) self.Bind(wx.EVT_SLIDER, self.onStockSlider, self.stockSlider) self.Bind(wx.EVT_SLIDER, self.onRateSlider, self.rateSlider) self.Bind(wx.EVT_SLIDER, self.ontimeStepSlider, self.timeStepSlider) # setup options-widgets for controlling graphs self.callRadio = wx.RadioButton(self.panel, label="Call options", pos=(10, 10)) self.putRadio = wx.RadioButton(self.panel, label="Put options", pos=(10, 30)) self.callRadio.SetValue(True) self.spaceKeeper = wx.StaticText(self.panel, -1, '') self.optionPriceCheck = wx.CheckBox(self.panel, label="view Option Price", pos=(20, 20)) self.deltaCheck = wx.CheckBox(self.panel, label="show Delta", pos=(20, 20)) self.gammaCheck = wx.CheckBox(self.panel, label="show Gamma", pos=(20, 20)) self.rhoCheck = wx.CheckBox(self.panel, label="show Rho", pos=(20, 20)) self.thetaCheck = wx.CheckBox(self.panel, label="show Theta", pos=(20, 20)) self.fillCheck = wx.CheckBox(self.panel, label="show fill feature", pos=(20, 20)) self.risidualCheck = wx.CheckBox(self.panel, label="Show Residual", pos=(20, 20)) self.differenceCheck = wx.CheckBox(self.panel, label="Show Difference", pos=(20, 20)) self.effectCheck = wx.CheckBox(self.panel, label="Show Greek's effect on option price", pos=(20, 20)) self.effectCheck.SetValue(True) self.Bind(wx.EVT_RADIOBUTTON, self.onCallRadio, self.callRadio) self.Bind(wx.EVT_RADIOBUTTON, self.onPutRadio, self.putRadio) self.Bind(wx.EVT_CHECKBOX, self.onOptionPrice, self.optionPriceCheck) self.Bind(wx.EVT_CHECKBOX, self.onDelta, self.deltaCheck) self.Bind(wx.EVT_CHECKBOX, self.onGamma, self.gammaCheck) self.Bind(wx.EVT_CHECKBOX, self.onRho, self.rhoCheck) self.Bind(wx.EVT_CHECKBOX, self.onTheta, self.thetaCheck) self.Bind(wx.EVT_CHECKBOX, self.onRisidual, self.risidualCheck) self.Bind(wx.EVT_CHECKBOX, self.onDifferenceCheck, self.differenceCheck) self.Bind(wx.EVT_CHECKBOX, self.onShowEffects, self.effectCheck) self.Bind(wx.EVT_CHECKBOX, self.onShowFillEffect, self.fillCheck) # Create the navigation toolbar, tied to the canvas self.toolbar = NavigationToolbar(self.canvas) #################### # Layout with sizers #################### flags = wx.ALIGN_LEFT | wx.ALL | wx.ALIGN_CENTER_VERTICAL self.sizer = wx.BoxSizer(wx.VERTICAL) self.hboxMainBlock = wx.BoxSizer(wx.HORIZONTAL) self.vboxOptions = wx.BoxSizer(wx.VERTICAL) self.hboxSliders = wx.BoxSizer(wx.HORIZONTAL) self.flexiGridSizer = wx.FlexGridSizer(4, 2, 3, 10) # adds border around sliders to group related widgets self.vboxOptions.AddSpacer(10) self.sliderStaticBox = wx.StaticBox(self.sliderPanel, -1, 'Bump Sliders') self.sliderBorder = wx.StaticBoxSizer(self.sliderStaticBox, orient=wx.VERTICAL) self.flexiGridSizer.AddMany([(self.stockSlider_label), (self.stockSlider, 1, wx.ALL), (self.rateSlider_label), (self.rateSlider, 1, wx.EXPAND), (self.timeStepSlider_label), (self.timeStepSlider, 1, wx.EXPAND)]) self.sliderBorder.Add(self.flexiGridSizer, 1, wx.ALL, 5) self.sliderPanel.SetSizer(self.sliderBorder) self.vboxOptions.Add(self.sliderPanel, 0, flag=wx.ALIGN_LEFT|wx.ALL) # add border for type of option price self.optionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Option Price Type'), orient=wx.VERTICAL) self.flexiOptions = wx.FlexGridSizer(3, 1, 3, 10) self.flexiOptions.AddMany([(self.callRadio, 1, wx.EXPAND), (self.putRadio, 1, wx.EXPAND), (self.optionPriceCheck, 1, wx.EXPAND)]) self.optionsBorder.Add(self.flexiOptions, 1, wx.ALL, 5) self.vboxOptions.Add(self.optionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW) # add border for greeks self.greekOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Greek effect Options'), orient=wx.VERTICAL) self.flexiOptions2 = wx.FlexGridSizer(6, 1, 3, 10) self.flexiOptions2.AddMany([(self.deltaCheck, 1, wx.EXPAND), (self.gammaCheck, 1, wx.EXPAND), (self.rhoCheck, 1, wx.EXPAND), (self.thetaCheck, 1, wx.EXPAND), (self.risidualCheck, 1, wx.EXPAND)]) self.greekOptionsBorder.Add(self.flexiOptions2, 1, wx.ALL, 5) self.vboxOptions.Add(self.greekOptionsBorder, 1, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW) #self.vboxOptions.AddSpacer(5) # add border for other checkable options self.otherOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Extra Options'), orient=wx.VERTICAL) self.flexiOptions3 = wx.FlexGridSizer(3, 1, 3, 10) self.flexiOptions3.AddMany([(self.fillCheck, 1, wx.EXPAND), (self.differenceCheck, 1, wx.EXPAND), (self.effectCheck, 1, wx.EXPAND)]) self.otherOptionsBorder.Add(self.flexiOptions3, 1, wx.ALL, 5) self.vboxOptions.Add(self.otherOptionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW) self.vboxOptions.AddSpacer(5) self.hboxMainBlock.Add(self.vboxOptions, 0, flag=flags) self.hboxMainBlock.Add(self.canvas, 1, flag=wx.ALIGN_RIGHT|wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) self.sizer.Add(self.hboxMainBlock, 1, wx.ALL|wx.EXPAND) self.sizer.Add(self.toolbar, 0, wx.ALL|wx.ALIGN_RIGHT) self.sizer.AddSpacer(1) self.canvas.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent) self.Bind(wx.EVT_CLOSE, self.onExit) self.panel.SetSizer(self.sizer) self.sizer.Fit(self) self.Center() def Build_Menus(self): """ build menus """ MENU_EXIT = wx.NewId() MENU_OPEN = wx.NewId() MENU_SAVE = wx.NewId() MENU_PRINT = wx.NewId() MENU_PSETUP = wx.NewId() MENU_PREVIEW =wx.NewId() MENU_CLIPB =wx.NewId() MENU_VIEW_GRID = wx.NewId() MENU_HELP =wx.NewId() MENU_BASIC = wx.NewId() MENU_ADVANCE = wx.NewId() MENU_LEGEND = wx.NewId() MENU_3D = wx.NewId() MENU_ABOUT = wx.NewId() menuBar = wx.MenuBar() f0 = wx.Menu() importItem = wx.MenuItem(f0, MENU_OPEN, "&Import\tCtrl+I") f0.AppendItem(importItem) f0.Append(MENU_SAVE, "&Export", "Save Image of Plot") f0.AppendSeparator() printMenu = wx.Menu() printMenu.Append(MENU_PSETUP, "Page Setup...", "Printer Setup") printMenu.Append(MENU_PREVIEW,"Print Preview...", "Print Preview") printItem = wx.MenuItem(printMenu, MENU_PRINT, "Print\tCtrl+P") printMenu.AppendItem(printItem) f0.AppendMenu(-1, '&Print', printMenu) f0.AppendSeparator() exitItem = wx.MenuItem(f0, MENU_EXIT, 'E&xit\tCtrl+Q') f0.AppendItem(exitItem) menuBar.Append(f0, "&File") f1 = wx.Menu() f1.Append(MENU_BASIC, '&Basic', "Basic View(2D)") f1.Append(MENU_ADVANCE, '&Advanced-2D', "Advanced View(2D)") f1.Append(MENU_3D, 'A&dvanced-3D', "Advanced View(3D)") optionsMenu = wx.Menu() viewGridItem = wx.MenuItem(optionsMenu, MENU_VIEW_GRID, 'View &Grid\tCtrl+G') optionsMenu.AppendItem(viewGridItem) viewLegendItem = wx.MenuItem(optionsMenu, MENU_LEGEND, 'View &Legend\tCtrl+L') optionsMenu.AppendItem(viewLegendItem) f1.AppendMenu(-1, "&Options", optionsMenu) menuBar.Append(f1, "&View") f2 = wx.Menu() f2.Append(MENU_HELP, "Quick &Reference", "Quick Reference") f2.Append(MENU_ABOUT, "&About", "About this interface") menuBar.Append(f2, "&Help") self.SetMenuBar(menuBar) self.Bind(wx.EVT_MENU, self.onImport, id=MENU_OPEN) self.Bind(wx.EVT_MENU, self.onPrint, id=MENU_PRINT) self.Bind(wx.EVT_MENU, self.onPrinterSetup, id=MENU_PSETUP) self.Bind(wx.EVT_MENU, self.onPrinterPreview, id=MENU_PREVIEW) self.Bind(wx.EVT_MENU, self.onClipboard, id=MENU_CLIPB) self.Bind(wx.EVT_MENU, self.onExport, id=MENU_SAVE) self.Bind(wx.EVT_MENU, self.onExit , id=MENU_EXIT) self.Bind(wx.EVT_MENU, self.onViewGrid, id=MENU_VIEW_GRID) self.Bind(wx.EVT_MENU, self.onViewLegend, id=MENU_LEGEND) self.Bind(wx.EVT_MENU, self.onHelp, id=MENU_HELP) self.Bind(wx.EVT_MENU, self.onAbout, id=MENU_ABOUT) self.Bind(wx.EVT_MENU, self.onBasicView, id=MENU_BASIC) self.Bind(wx.EVT_MENU, self.onAdvancedView, id=MENU_ADVANCE) self.Bind(wx.EVT_MENU, self.onAdvanced3DView, id=MENU_3D) """ Menu event methods """ def onViewLegend(self, event=None): if self.viewLegend: self.viewLegend = False self.Plot_Data() else: self.viewLegend = True # use proxy artist plot_op = Line2D([], [], linewidth=3, color="black") plot_delta = Line2D([], [], linewidth=3, color="royalblue") plot_gamma = Line2D([], [], linewidth=3, color="cyan") plot_theta = Line2D([], [], linewidth=3, color="green") plot_rho = Line2D([], [], linewidth=3, color="darkorange") plot_risidual = Line2D([], [], linewidth=3, color="purple") # Shink current axis by 15% box = self.axes.get_position() self.axes.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis self.axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'], loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) if self.current_view == 1: box = self.axes2.get_position() self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) self.canvas.draw() def onBasicView(self, event=None): self.current_view = 0 # show sliders panel self.sliderPanel.Enable() self.toolbar.Enable() self.fillCheck.Enable() self.panel.Layout() self.Plot_Data() def onAdvancedView(self, event=None): self.current_view = 1 # show sliders panel self.sliderPanel.Enable() self.toolbar.Enable() self.fillCheck.Enable() self.panel.Layout() self.Plot_Data() def onAdvanced3DView(self, event=None): self.current_view = 2 # hide slider panel since will not be used self.sliderPanel.Disable() self.toolbar.Disable() self.fillCheck.Disable() self.panel.Layout() self.Plot_Data() def onPrinterSetup(self,event=None): self.canvas.Printer_Setup(event=event) def onPrinterPreview(self,event=None): self.canvas.Printer_Preview(event=event) def onPrint(self,event=None): self.canvas.Printer_Print(event=event) def onClipboard(self,event=None): self.canvas.Copy_to_Clipboard(event=event) def onKeyEvent(self,event=None): """ capture and act upon keystroke events """ if event == None: return key = event.GetKeyCode() if (key < wx.WXK_SPACE or key > 255): return if (event.ControlDown() and chr(key)=='C'): # Ctrl-C self.onClipboard(event=event) if (event.ControlDown() and chr(key)=='P'): # Ctrl-P self.onPrinterPreview(event=event) def onHelp(self, event=None): dlg = wx.MessageDialog(self, self.help_msg, "Quick Reference", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onAbout(self, event=None): dlg = wx.MessageDialog(self, self.about_msg, "About", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onViewGrid(self, event=None): if self.viewGrid: self.viewGrid = False else: self.viewGrid = True for a in self.fig.axes: a.grid(self.viewGrid) self.canvas.draw() def onExport(self,event=None): """ save figure image to file""" file_choices = "PNG (*.png)|*.png|" \ "JPEG (*.jpg)|*.jpg|" \ "BMP (*.bmp)|*.bmp" thisdir = os.getcwd() dlg = wx.FileDialog(self, message='Save Plot Figure as...', defaultDir = thisdir, defaultFile='plot.png', wildcard=file_choices, style=wx.SAVE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.canvas.print_figure(path,dpi=300) if (path.find(thisdir) == 0): path = path[len(thisdir)+1:] print('Saved plot to %s' % path) def onImport(self, event=None): """ Import csv file of option prices and greeks """ file_choices = "SETTINGS (*.settings)|*.settings" thisdir = ''.join(os.getcwd()+'/data') # import output file dlg = wx.FileDialog(self, message='Import option prices and greeks (Outputs)', defaultDir = thisdir, defaultFile='data.settings', wildcard=file_choices, style=wx.OPEN) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() projectDir = path.rsplit('/', 1)[0] #projectDir = path.rsplit('\\', 1)[0] self.reInitialiseData() # this also involves reading in all the data self.number_bumps = self.fileReader.loadSettingsFile(path, projectDir, self.statusbar) print('Opened settings file at %s' % path) else: dlg = wx.MessageDialog(self, "Failed to import the correct settings file.", "Complication", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return # populate data self.strike_price = self.fileReader.getStrikePrice() self.stock_price = self.fileReader.getStockPrice() self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), self.vegaCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked()) self.onBasicView() def onExit(self,event=None): dlg = wx.MessageDialog(None, 'Are you sure to exit?', 'Confirm', wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION) ret = dlg.ShowModal() if ret == wx.ID_YES: self.Destroy() """ GUI event methods """ def onShowFillEffect(self, event=None): if self.fillCheck.IsChecked(): if self.differenceCheck.IsChecked(): self.differenceCheck.SetValue(False) # reload and replot data self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.viewFill = True else: self.viewFill = False self.Plot_Data() def onCallRadio(self, event=None): self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onPutRadio(self, event=None): self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onOptionPrice(self, event=None): self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked()) self.Plot_Data() def onDelta(self, event=None): self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onGamma(self, event=None): self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onRho(self, event=None): self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onTheta(self, event=None): self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onVega(self, event=None): self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onRisidual(self, event=None): self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # print(self.risidual) self.Plot_Data() def onShowEffects(self, event=None): if not self.effectCheck.IsChecked(): warning_msg = """ This setting will plot the value of the greeks, but not terms of the option price. This means that the greek graphs will no-longer be comparable. You will still be able to plot the greeks against each other though. Do you want to continue? """ dlg = wx.MessageDialog(self, warning_msg, "Take Note", wx.YES_NO | wx.ICON_INFORMATION) ret = dlg.ShowModal() if ret == wx.ID_NO: dlg.Destroy() self.effectCheck.SetValue(True) return dlg.Destroy() self.differenceCheck.Disable() self.fillCheck.Disable() self.optionPriceCheck.SetValue(False) self.onOptionPrice() self.optionPriceCheck.Disable() else: self.differenceCheck.Enable() self.optionPriceCheck.Enable() if self.current_view != 2: self.fillCheck.Enable() # reload and replot data self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onDifferenceCheck(self, event=None): if self.fillCheck.IsChecked(): self.fillCheck.SetValue(False) self.viewFill = False # reload and replot data self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), # self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked()) self.Plot_Data() def onStockSlider(self, event=None): self.statusbar.SetStatusText("Stock price bump: "+str(self.stockSlider.GetValue())) self.stock_bump = self.stockSlider.GetValue()-1 self.Plot_Data() def onRateSlider(self, event=None): self.statusbar.SetStatusText("Interest Rate bump: "+str(self.rateSlider.GetValue())) self.rate_bump = self.rateSlider.GetValue()-1 self.Plot_Data() def onVolatilSlider(self, event=None): self.statusbar.SetStatusText("Volatility bump: "+str(self.volatilSlider.GetValue())) self.volitile_bump = self.volatilSlider.GetValue()-1 self.Plot_Data() def ontimeStepSlider(self, event=None): self.statusbar.SetStatusText("Time step bump: "+str(self.timeStepSlider.GetValue())) self.time_bump = self.timeStepSlider.GetValue()-1 self.Plot_Data() self.Plot_Data() """ Graph plotting methods """ def clearPlots(self): """ Clear all graphs and plots for next draw """ for a in self.fig.axes: self.fig.delaxes(a) def Plotter_2D_general(self, axes): # plot option price graph temp_option_price = [] if len(self.option_price) > 0: temp_option_price = numpy.array(map(float, self.option_price[self.stock_bump])) if len(self.option_price) > 0: axes.plot(self.time, self.option_price[self.stock_bump], color='black') # stagger plot effects of greeks temp_delta = [] temp_gamma = [] temp_theta = [] temp_rho = [] temp_risidual = [] if len(self.delta) > 0: temp_delta = numpy.array(self.delta[self.stock_bump]) if len(self.gamma) > 0: temp_gamma = numpy.array(self.gamma[self.stock_bump]) if len(self.rho) > 0: temp_rho = numpy.array(self.rho[self.rate_bump]) if len(self.theta) > 0: temp_theta = numpy.array(self.theta[self.time_bump]) if len(self.risidual) > 0: temp_risidual = numpy.array(self.risidual[self.stock_bump]) if not self.differenceCheck.IsChecked() and len(temp_option_price) > 0: for t in self.time: greeks_below = [] greeks_above = [] # above/below option price if t < 30: # sort arrays if len(temp_delta) > 0: if temp_delta[t+1] > temp_option_price[t+1]: greeks_above.append([temp_delta[t:t+2], 'delta']) else: greeks_below.append([temp_delta[t:t+2], 'delta']) if len(temp_gamma) > 0: if temp_gamma[t+1] > temp_option_price[t+1]: greeks_above.append([temp_gamma[t:t+2], 'gamma']) else: greeks_below.append([temp_gamma[t:t+2], 'gamma']) if len(temp_theta) > 0: if temp_theta[t+1] > temp_option_price[t+1]: greeks_above.append([temp_theta[t:t+2], 'theta']) else: greeks_below.append([temp_theta[t:t+2], 'theta']) if len(temp_rho) > 0: if temp_rho[t+1] > temp_option_price[t+1]: greeks_above.append([temp_rho[t:t+2], 'rho']) else: greeks_below.append([temp_rho[t:t+2], 'rho']) if len(temp_risidual) > 0: if temp_risidual[t+1] > temp_option_price[t+1]: greeks_above.append([temp_risidual[t:t+2], 'risidual']) else: greeks_below.append([temp_risidual[t:t+2], 'risidual']) temp_time = numpy.arange(t, t+2, 1) greeks_above = sorted(greeks_above, key=lambda tup: tup[0][1]) greeks_below = sorted(greeks_below, key=lambda tup: tup[0][1], reverse=True) # PLOT stagger greek effects temp_time = numpy.arange(t, t+2, 1) temp1 = numpy.array(temp_option_price[t:t+2]) # print(t, greeks_below, greeks_above) for g in greeks_above: # print(t) temp2 = numpy.array([temp_option_price[t], g[0][1]]) if self.viewFill and len(self.option_price) > 0: if g[1] == 'delta': axes.fill_between(temp_time, temp2, temp1, color='blue') if g[1] == 'gamma': axes.fill_between(temp_time, temp2, temp1, color='cyan') if g[1] == 'theta': axes.fill_between(temp_time, temp2, temp1, color='green') if g[1] == 'rho': axes.fill_between(temp_time, temp2, temp1, color='darkorange') if g[1] == 'risidual': axes.fill_between(temp_time, temp2, temp1, color='purple') if g[1] == 'delta': axes.plot(temp_time, temp2, label="Delta", color='blue') if g[1] == 'gamma': axes.plot(temp_time, temp2, label="Gamma", color='cyan') if g[1] == 'theta': axes.plot(temp_time, temp2, label="Theta", color='green') if g[1] == 'rho': axes.plot(temp_time, temp2, label="Rho", color='darkorange') if g[1] == 'risidual': axes.plot(temp_time, temp2, label="risidual", color='purple') temp1 = temp2 temp1 = numpy.array(temp_option_price[t:t+2]) for g in greeks_below: temp2 = numpy.array([temp_option_price[t], g[0][1]]) if self.viewFill and len(self.option_price) > 0: if g[1] == 'delta': axes.fill_between(temp_time, temp2, temp1, color='blue') if g[1] == 'gamma': axes.fill_between(temp_time, temp2, temp1, color='cyan') if g[1] == 'theta': axes.fill_between(temp_time, temp2, temp1, color='green') if g[1] == 'rho': axes.fill_between(temp_time, temp2, temp1, color='darkorange') if g[1] == 'risidual': axes.fill_between(temp_time, temp2, temp1, color='purple') if g[1] == 'delta': axes.plot(temp_time, temp2, label="Delta", color='blue') if g[1] == 'gamma': axes.plot(temp_time, temp2, label="Gamma", color='cyan') if g[1] == 'theta': axes.plot(temp_time, temp2, label="Theta", color='green') if g[1] == 'rho': axes.plot(temp_time, temp2, label="Rho", color='darkorange') if g[1] == 'risidual': axes.plot(temp_time, temp2, label="risidual", color='purple') temp1 = temp2 else: # plot difference between greeks and option price if len(self.delta) > 0: axes.plot(self.delta[self.stock_bump], color='blue') if len(self.gamma) > 0: axes.plot(self.gamma[self.stock_bump], color='cyan') # if len(self.vega) > 0: # axes.plot(self.vega[self.volitile_bump], label="Vega", color='yellow') if len(self.theta) > 0: axes.plot(self.time, self.theta[self.time_bump], color='green') if len(self.rho) > 0: axes.plot(self.time, self.rho[self.rate_bump], color='darkorange') if len(self.risidual) > 0: axes.plot(self.time, self.risidual[self.stock_bump], color='purple') if self.viewLegend: # use proxy artist plot_op = Line2D([], [], linewidth=3, color="black") plot_delta = Line2D([], [], linewidth=3, color="royalblue") plot_gamma = Line2D([], [], linewidth=3, color="cyan") plot_theta = Line2D([], [], linewidth=3, color="green") plot_rho = Line2D([], [], linewidth=3, color="darkorange") plot_risidual = Line2D([], [], linewidth=3, color="purple") # Shink current axis by 15% box = axes.get_position() axes.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'], loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) def Plot_Data(self): if self.current_view == 1: self.Plot_Data_advanced() elif self.current_view == 2: self.Plot_Data_3D() elif self.current_view == 0: """ Basic 2D graph plotter """ self.clearPlots() self.axes = self.fig.add_subplot(111) # can use add_axes, but then nav-toolbar would not work self.axes.set_xlim(0, 30) self.axes.grid(self.viewGrid) self.Plotter_2D_general(self.axes) # set caption and axes labels self.axes.set_xlabel('Time (Daily)') if self.effectCheck.IsChecked(): self.axes.set_ylabel('Price (Rands)') if hasattr(self, 'title'): self.title.set_text('Option Prices and breakdown of the effects of Greeks') else: self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks') else: self.axes.set_ylabel('Greek Value') if hasattr(self, 'title'): self.title.set_text('Raw Greek values not in terms of option price') else: self.title = self.fig.suptitle('Greek values not in terms of option price') self.canvas.draw() def Plot_Data_advanced(self): """ Advanced 2D plotter """ self.clearPlots() self.axes2 = self.fig.add_subplot(212) self.axes = self.fig.add_subplot(211, sharex=self.axes2) self.axes.set_xlim(0, 30) self.axes.grid(self.viewGrid) self.axes2.grid(self.viewGrid) self.Plotter_2D_general(self.axes) # plot strike price and stock price curve if self.strike_price > 0: self.axes2.plot([0, 30], [self.strike_price, self.strike_price], label="Strike Price", color='red') # plot stock price curve temp_stock_price = numpy.array(self.stock_price) if len(temp_stock_price) > 0: self.axes2.plot(self.time, temp_stock_price, label="Stock Price", color='blue') # set limits for x and y axes # self.axes2.set_xlim(self.time_span_fill[0], self.time_span_fill[-1]) # self.axes2.set_ylim(min(p, key=float), max(p, key=float)) # set caption and axes labels self.axes2.set_xlabel('Time (Daily)') self.axes2.set_ylabel('Price (Rands)') if self.effectCheck.IsChecked(): self.axes.set_ylabel('Price (Rands)') if hasattr(self, 'title'): self.title.set_text('Option Prices and breakdown of the effects of Greeks') else: self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks') else: self.axes.set_ylabel('Greek Value') if hasattr(self, 'title'): self.title.set_text('Raw Greek values not in terms of option price') else: self.title = self.fig.suptitle('Greek values not in terms of option price') # set useblit True on gtkagg for enhanced performance # self.span = SpanSelector(self.axes, self.onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) if self.viewLegend: # Shink current axis by 15% box = self.axes2.get_position() self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height]) # Put a legend to the right of the current axis self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8}) self.canvas.draw() def Plot_Data_3D(self): """ Advanced 3D plotter """ # plot graphs self.clearPlots() self.axes = self.fig.add_subplot(111, projection='3d') # can use add_axes, but then nav-toolbar would not work self.axes.grid(self.viewGrid) b = numpy.arange(0, 9, 1) X2D, Y2D = numpy.meshgrid(self.time, b) Z2D = None # plot option price surface if len(self.option_price) > 0: Z2D = [[float(string) for string in inner] for inner in self.option_price] surf = self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, cmap=cm.afmhot, zorder=0.5) #cm.coolwarm, cm.winter, cm.autumn cbar = self.fig.colorbar(surf, shrink=0.5, aspect=5) cbar.set_label('Option Price', rotation=90) ### TODO - mayavi ### # X2D, Y2D = numpy.mgrid[self.time, b] # print(X2D) # s = mlab.surf(Z2D) # mlab.show() # plot greek surfaces if len(self.delta) > 0: Z2D = [[float(string) for string in inner] for inner in self.delta] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='blue') if len(self.gamma) > 0: Z2D = [[float(string) for string in inner] for inner in self.gamma] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='cyan') if len(self.theta) > 0: Z2D = [[float(string) for string in inner] for inner in self.theta] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='green') if len(self.rho) > 0: Z2D = [[float(string) for string in inner] for inner in self.rho] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='orange') # if len(self.vega) > 0: # Z2D = [[float(string) for string in inner] for inner in self.vega] # self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, # antialiased=False, alpha=0.75, color='aqua') if len(self.risidual) > 0: Z2D = [[float(string) for string in inner] for inner in self.risidual] self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1, antialiased=False, alpha=0.75, color='rosybrown') if Z2D != None: # cset1 = self.axes.contourf(X2D, Y2D, Z2D, zdir='z', offset=300, cmap=cm.afmhot) self.axes.contourf(X2D, Y2D, Z2D, zdir='x', offset=0, cmap=cm.coolwarm) self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=-0.3, cmap=cm.winter) # cset = self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=10, cmap=cm.afmhot) # cbar = self.fig.colorbar(cset1, shrink=0.7, aspect=3) # cbar = self.fig.colorbar(cset2, shrink=0.7, aspect=3) # cbar = self.fig.colorbar(cset3, shrink=0.5, aspect=5) # cbar.set_label('Option Proce', rotation=90) # set captions and axis labels self.axes.set_xlabel('Time (Days)') self.axes.set_xlim(0, 35) self.axes.set_ylabel('Bump Size') #~ self.axes.set_ylim(-3, 8) # self.axes.set_zlabel('Price (Rands)') # ~ self.axes.set_zlim(-100, 100) if self.effectCheck.IsChecked(): if self.differenceCheck.IsChecked(): self.axes.set_zlabel('Greek Value') else: self.axes.set_zlabel('Price (Rands)') if hasattr(self, 'title'): self.title.set_text('Option Prices and breakdown of the effects of Greeks') else: self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks') else: self.axes.set_zlabel('Greek Value') if hasattr(self, 'title'): self.title.set_text('Raw Greek values not in terms of option price') else: self.title = self.fig.suptitle('Greek values not in terms of option price') self.canvas.draw()
class STAPanel(wx.Panel): """ Receptive field plot. """ def __init__(self, parent, label, name='sta_panel'): super(STAPanel, self).__init__(parent, -1, name=name) self.interpolation_changed = True self.show_colorbar_changed = True self.show_contour_changed = True self.showing_colorbar = True self.showing_contour = False self.image_fitting = None self.image_fitter = None # default data type self.collecting_data = True self.connected_to_server = True self.data = None self.sta_data = None self.psth_data = None self.data_type = None self.start_data() self.update_sta_data_thread = None self.update_psth_data_thread = None self.axes = None self.im = None self.img_dim = None self.cbar = None self.gauss_fitter = None self.gabor_fitter = None self.peak_time = None self.cmap = 'jet' # reverse time in ms time_slider = 85 self.time = time_slider / 1000 self.dpi = 100 self.fig = Figure((6.0, 6.0), dpi=self.dpi, facecolor='w') self.canvas = FigCanvas(self, -1, self.fig) self.fig.subplots_adjust(bottom=0.06, left=0.06, right=0.95, top=0.95) # popup menu of cavas interpolations = ['none', 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', \ 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos'] self.interpolation = 'nearest' self.interpolation_menu = wx.Menu() for interpolation in interpolations: item = self.interpolation_menu.AppendRadioItem(-1, interpolation) # check default interpolation if interpolation == self.interpolation: self.interpolation_menu.Check(item.GetId(), True) self.Bind(wx.EVT_MENU, self.on_interpolation_selected, item) wx.FindWindowByName('main_frame').Bind( wx.EVT_MENU, self.on_interpolation_selected, item) self.popup_menu = wx.Menu() self.popup_menu.AppendMenu(-1, '&Interpolation', self.interpolation_menu) self.canvas.Bind(wx.EVT_CONTEXT_MENU, self.on_show_popup) wx.FindWindowByName('main_frame').menu_view.AppendSubMenu( self.interpolation_menu, '&Interpolation') self.make_chart() #layout things box = wx.StaticBox(self, -1, label) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) # options self.options = OptionPanel(self, 'Options', time=time_slider) self.Bind(EVT_TIME_UPDATED, self.on_update_time_slider) # results self.data_form = STADataPanel(self, 'Results', text_size=(250, 150)) vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(self.options, 1, wx.TOP | wx.CENTER, 0) vbox.Add(self.data_form, 1, wx.TOP | wx.CENTER, 0) # canvas hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add(self.canvas, 0, flag=wx.ALL | wx.ALIGN_LEFT | wx.ALIGN_TOP, border=5) hbox.Add(vbox, 0, flag=wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_TOP, border=5) sizer.Add(hbox, 0, wx.ALIGN_CENTRE) self.SetSizer(sizer) sizer.Fit(self) self.update_sta_data_timer = wx.Timer(self, wx.NewId()) self.Bind(wx.EVT_TIMER, self.on_update_sta_data_timer, self.update_sta_data_timer) self.update_sta_data_timer.Start(2000) self.update_psth_data_timer = wx.Timer(self, wx.NewId()) self.Bind(wx.EVT_TIMER, self.on_update_psth_data_timer, self.update_psth_data_timer) self.update_psth_data_timer.Start(3000) def make_chart(self, img=None): self.fig.clear() self.axes = self.fig.add_subplot(111) if img is None: img = np.zeros((32, 32)) + 0.5 img = self.sta_data.float_to_rgb(img, cmap=self.cmap) self.img_dim = img.shape self.im = self.axes.imshow(img, interpolation=self.interpolation) if self.showing_colorbar: self.cbar = self.fig.colorbar(self.im, shrink=1.0, fraction=0.045, pad=0.05, ticks=[]) adjust_spines(self.axes, spines=['left', 'bottom'], spine_outward=[], xticks='bottom', yticks='left', tick_label=['x', 'y']) #self.axes.autoscale_view(scalex=True, scaley=True) self.fig.canvas.draw() def set_data(self, data): self.data = data def update_slider(self, data): selected_unit = wx.FindWindowByName('unit_choice').get_selected_unit() if selected_unit: channel, unit = selected_unit peak_time = data[channel][unit][ 'peak_time'] if channel in data and unit in data[ channel] else None parent = wx.FindWindowByName('main_frame') options_panel = parent.chart_panel.options auto_time = options_panel.autotime_cb.GetValue() if auto_time and peak_time is not None: self.peak_time = peak_time options_panel.time_slider.SetValue(peak_time) evt = wx.CommandEvent(wx.wxEVT_COMMAND_SLIDER_UPDATED) evt.SetId(options_panel.time_slider.GetId()) options_panel.on_slider_update(evt) wx.PostEvent(parent, evt) def update_chart(self, data=None): if data is None and self.data is None: return elif data is None and self.data is not None: data = self.data if isinstance(self.sta_data, RevCorr.STAData): self.data_type = 'white_noise' if isinstance(self.sta_data, RevCorr.ParamMapData): self.data_type = 'param_mapping' selected_unit = wx.FindWindowByName('unit_choice').get_selected_unit() if selected_unit: channel, unit = selected_unit img = self.sta_data.get_img(data, channel, unit, tau=self.time, img_format='rgb') if self.img_dim != img.shape or self.interpolation_changed or self.show_colorbar_changed \ or self.showing_contour or self.show_contour_changed: self.interpolation_changed = False self.show_colorbar_changed = False self.show_contour_changed = False self.make_chart(img) self.img_dim = img.shape if self.showing_colorbar: self.cbar.set_ticks([0.0, 0.5, 1.0]) if isinstance(self.sta_data, RevCorr.STAData): self.cbar.set_ticklabels(["-1", "0", "1"]) if isinstance(self.sta_data, RevCorr.ParamMapData): self.cbar.set_ticklabels(["0.0", "0.5", "1.0"]) self.data_form.gen_results(self.peak_time) if self.image_fitting is not None: float_img = self.sta_data.get_img(data, channel, unit, tau=self.time, img_format='float') if self.image_fitting == 'gauss': params, img = self.image_fitter.gaussfit2d( float_img, returnfitimage=True) level = twodgaussian(params)(params[3] + params[5], params[2] + params[4]) elif self.image_fitting == 'gabor': params, img = self.image_fitter.gaborfit2d( float_img, returnfitimage=True) level = twodgabor(params)(params[3] + params[5], params[2] + params[4]) if self.showing_contour: self.axes.contour(img, [level]) self.data_form.gen_results(self.peak_time, params, img, self.data_type, self.image_fitting) img = self.sta_data.float_to_rgb(img, cmap=self.cmap) self.im.set_data(img) self.im.autoscale() self.canvas.draw() def on_update_sta_data_timer(self, _event): if self.collecting_data and self.connected_to_server: self.update_sta_data_thread = UpdateDataThread(self, self.sta_data) self.update_sta_data_thread.start() def on_update_psth_data_timer(self, _event): if self.collecting_data and self.connected_to_server: self.update_psth_data_thread = UpdateDataThread( self, self.psth_data) self.update_psth_data_thread.start() def on_update_time_slider(self, event): self.time = event.get_time() self.update_chart() def start_data(self): data_type = wx.FindWindowByName('main_frame').get_data_type() if data_type == 'sparse_noise': self.sta_data = RevCorr.STAData() elif data_type == 'param_map': self.sta_data = RevCorr.ParamMapData() if self.psth_data is None: self.psth_data = TimeHistogram.PSTHAverage() self.collecting_data = True self.connected_to_server = True def stop_data(self): self.collecting_data = False self.clear_data() self.sta_data = None self.psth_data = None def restart_data(self): self.stop_data() self.start_data() def sparse_noise_data(self): self.sta_data = RevCorr.STAData() self.restart_data() def param_mapping_data(self): self.sta_data = RevCorr.ParamMapData() self.restart_data() def choose_fitting(self, fitting): if fitting == 'none': self.image_fitting = None self.image_fitter = None if fitting == 'gauss': self.image_fitting = 'gauss' self.image_fitter = GaussFit() if fitting == 'gabor': self.image_fitting = 'gabor' self.image_fitter = GaborFit() def show_colorbar(self, checked): self.show_colorbar_changed = True self.showing_colorbar = checked def show_contour(self, checked): self.show_contour_changed = True self.showing_contour = checked def on_show_popup(self, event): pos = event.GetPosition() pos = event.GetEventObject().ScreenToClient(pos) self.PopupMenu(self.popup_menu, pos) def on_interpolation_selected(self, event): item = self.interpolation_menu.FindItemById(event.GetId()) interpolation = item.GetText() if interpolation != self.interpolation: self.interpolation_changed = True self.interpolation = interpolation if hasattr(self, 'data'): self.update_chart(self.data) def open_file(self, path, callback): data_type = wx.FindWindowByName('main_frame').get_data_type() if data_type == 'sparse_noise': self.sta_data = RevCorr.STAData(path) elif data_type == 'param_map': self.sta_data = RevCorr.ParamMapData(path) self.psth_data = TimeHistogram.PSTHAverage(path) UpdateFileDataThread(self, self.sta_data, callback).start() UpdateFileDataThread(self, self.psth_data, callback).start() self.connected_to_server = False def save_data(self): data_dict = {} data_dict['data_type'] = self.data_type data_dict['data'] = self.data return data_dict def save_chart(self, path): self.canvas.print_figure(path, dpi=self.dpi) def clear_data(self): self.data = None self.make_chart() wx.FindWindowByName('main_frame').unit_choice.clear_unit() self.data_form.clear_data()
class plot_2d_data(wx.Frame): """Generic 2d plotting routine - inputs are: - data (2d array of values), - x and y extent of the data, - title of graph, and - pixel mask to be used during summation - must have same dimensions as data (only data entries corresponding to nonzero values in pixel_mask will be summed) - plot_title, x_label and y_label are added to the 2d-plot as you might expect""" def __init__(self, data, extent, caller = None, scale = 'log', window_title = 'log plot', pixel_mask = None, plot_title = "data plot", x_label = "x", y_label = "y", parent=None): wx.Frame.__init__(self, parent=None, title=window_title, pos = wx.DefaultPosition, size=wx.Size(800,600)) print parent self.extent = extent self.data = data self.caller = caller self.window_title = window_title x_range = extent[0:2] #x_range.sort() self.x_min, self.x_max = x_range y_range = extent[2:4] #y_range.sort() self.y_min, self.y_max = y_range self.plot_title = plot_title self.x_label = x_label self.y_label = y_label self.slice_xy_range = (x_range, y_range) self.ID_QUIT = wx.NewId() self.ID_LOGLIN = wx.NewId() self.ID_UPCOLLIM = wx.NewId() self.ID_LOWCOLLIM = wx.NewId() menubar = wx.MenuBar() filemenu = wx.Menu() quit = wx.MenuItem(filemenu, 1, '&Quit\tCtrl+Q') #quit.SetBitmap(wx.Bitmap('icons/exit.png')) filemenu.AppendItem(quit) plotmenu = wx.Menu() self.menu_log_lin_toggle = plotmenu.Append(self.ID_LOGLIN, 'Plot 2d data with log color scale', 'plot 2d on log scale', kind=wx.ITEM_CHECK) self.Bind(wx.EVT_MENU, self.toggle_2d_plot_scale, id=self.ID_LOGLIN) menu_upper_colormap_limit = plotmenu.Append(self.ID_UPCOLLIM, 'Set upper limit of color map', 'Set upper limit of color map') self.Bind(wx.EVT_MENU, self.set_new_upper_color_limit, id=self.ID_UPCOLLIM) menu_lower_colormap_limit = plotmenu.Append(self.ID_LOWCOLLIM, 'Set lower limit of color map', 'Set lower limit of color map') self.Bind(wx.EVT_MENU, self.set_new_lower_color_limit, id=self.ID_LOWCOLLIM) #live_on_off = wx.MenuItem(live_update, 1, '&Live Update\tCtrl+L') #quit.SetBitmap(wx.Bitmap('icons/exit.png')) #live_update.AppendItem(self.live_toggle) #self.menu_log_lin_toggle.Check(True) menubar.Append(filemenu, '&File') menubar.Append(plotmenu, '&Plot') self.SetMenuBar(menubar) self.Centre() if pixel_mask == None: pixel_mask = ones(data.shape) if pixel_mask.shape != data.shape: print "Warning: pixel mask shape incompatible with data" pixel_mask = ones(data.shape) self.pixel_mask = pixel_mask self.show_data = transpose(data.copy()) #self.minimum_intensity = self.data[pixel_mask.nonzero()].min() # correct for floating-point weirdness: self.minimum_intensity = self.data[self.data > 1e-17].min() #if scale == 'log': #self.show_data = log ( self.data.copy().T + self.minimum_intensity/2.0 ) #self._scale = 'log' #self.menu_log_lin_toggle.Check(True) #elif (scale =='lin' or scale == 'linear'): #self._scale = 'lin' #self.menu_log_lin_toggle.Check(True) #self.bin_data = caller.bin_data #self.params = caller.params #fig = figure() self.fig = Figure(dpi=80, figsize=(5,5)) #self.fig = figure() fig = self.fig self.canvas = Canvas(self, -1, self.fig) self.show_sliceplots = False # by default, sliceplots on self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) #self.toolbar = Toolbar(self.canvas) self.toolbar = MyNavigationToolbar(self.canvas, True, self) self.toolbar.Realize() if wx.Platform == '__WXMAC__': # Mac platform (OSX 10.3, MacPython) does not seem to cope with # having a toolbar in a sizer. This work-around gets the buttons # back, but at the expense of having the toolbar at the top self.SetToolBar(self.toolbar) else: # On Windows platform, default window size is incorrect, so set # toolbar width to figure width. tw, th = self.toolbar.GetSizeTuple() fw, fh = self.canvas.GetSizeTuple() # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version. # As noted above, doesn't work for Mac. self.toolbar.SetSize(wx.Size(fw, th)) self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) self.statusbar = self.CreateStatusBar() self.statusbar.SetFieldsCount(2) self.statusbar.SetStatusWidths([-1, -2]) self.statusbar.SetStatusText("Current Position:", 0) self.canvas.mpl_connect('motion_notify_event', self.onmousemove) #self.canvas.mpl_connect('button_press_event', self.right_click_handler) #self.axes = fig.add_subplot(111) #self.axes = self.fig.gca() #ax = self.axes self.mapper = FigureImage(self.fig) #im = self.axes.pcolor(x,y,V,shading='flat') #self.mapper.add_observer(im) #self.show_data = transpose(log(self.show_data + self.minimum_intensity / 2.0)) #self.canvas.mpl_connect('pick_event', self.log_lin_select) ax = fig.add_subplot(221, label='2d_plot') fig.sx = fig.add_subplot(222, label='sx', picker=True) fig.sx.xaxis.set_picker(True) fig.sx.yaxis.set_picker(True) fig.sx.yaxis.set_ticks_position('right') fig.sx.set_zorder(1) fig.sz = fig.add_subplot(223, label='sz', picker=True) fig.sz.xaxis.set_picker(True) fig.sz.yaxis.set_picker(True) fig.sz.set_zorder(1) self.RS = RectangleSelector(ax, self.onselect, drawtype='box', useblit=True) fig.slice_overlay = None ax.set_position([0.125,0.1,0.7,0.8]) fig.cb = fig.add_axes([0.85,0.1,0.05,0.8]) fig.cb.set_zorder(2) fig.ax = ax fig.ax.set_zorder(2) self.axes = ax ax.set_title(plot_title) #connect('key_press_event', self.toggle_selector) if scale == 'log': self.show_data = log ( self.data.copy().T + self.minimum_intensity/2.0 ) self.__scale = 'log' self.fig.cb.set_xlabel('$\log_{10}I$') self.menu_log_lin_toggle.Check(True) elif (scale =='lin' or scale == 'linear'): self.__scale = 'lin' self.fig.cb.set_xlabel('$I$') self.menu_log_lin_toggle.Check(False) im = self.axes.imshow(self.show_data, interpolation='nearest', aspect='auto', origin='lower',cmap=cm.jet, extent=extent) #im = ax.imshow(data, interpolation='nearest', aspect='auto', origin='lower',cmap=cm.jet, extent=extent) fig.im = im ax.set_xlabel(x_label, size='large') ax.set_ylabel(y_label, size='large') self.toolbar.update() #zoom_colorbar(im) #fig.colorbar(im, cax=fig.cb) zoom_colorbar(im=im, cax=fig.cb) #figure(fig.number) #fig.canvas.draw() #return self.SetSizer(self.sizer) self.Fit() self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnContext) self.Bind(wx.EVT_CLOSE, self.onExit) self.sliceplots_off() self.SetSize(wx.Size(800,600)) self.canvas.draw() return def onExit(self, event): self.Destroy() def exit(self, event): wx.GetApp().Exit() def set_new_upper_color_limit(self, evt = None): current_uplim = self.fig.im.get_clim()[1] current_lowlim = self.fig.im.get_clim()[0] dlg = wx.TextEntryDialog(None, "Change upper limit of color map (currently %f)" % current_uplim, defaultValue = "%f" % current_uplim) if dlg.ShowModal() == wx.ID_OK: new_val = dlg.GetValue() xlab = self.fig.cb.get_xlabel() ylab = self.fig.cb.get_ylabel() self.fig.im.set_clim((current_lowlim, float(new_val))) self.fig.cb.set_xlabel(xlab) self.fig.cb.set_ylabel(ylab) self.fig.canvas.draw() dlg.Destroy() def set_new_lower_color_limit(self, evt = None): current_uplim = self.fig.im.get_clim()[1] current_lowlim = self.fig.im.get_clim()[0] dlg = wx.TextEntryDialog(None, "Change lower limit of color map (currently %f)" % current_lowlim, defaultValue = "%f" % current_lowlim) if dlg.ShowModal() == wx.ID_OK: new_val = dlg.GetValue() xlab = self.fig.cb.get_xlabel() ylab = self.fig.cb.get_ylabel() self.fig.im.set_clim((float(new_val), current_uplim)) self.fig.cb.set_xlabel(xlab) self.fig.cb.set_ylabel(ylab) self.fig.canvas.draw() dlg.Destroy() def OnContext(self, evt): print self.show_sliceplots mpl_x = evt.X mpl_y = self.fig.canvas.GetSize()[1] - evt.Y mpl_mouseevent = matplotlib.backend_bases.MouseEvent('button_press_event', self.canvas, mpl_x, mpl_y, button = 3) if (mpl_mouseevent.inaxes == self.fig.ax): self.area_context(mpl_mouseevent, evt) elif ((mpl_mouseevent.inaxes == self.fig.sx or mpl_mouseevent.inaxes == self.fig.sz) and (self.show_sliceplots == True)): self.lineplot_context(mpl_mouseevent, evt) def area_context(self, mpl_mouseevent, evt): area_popup = wx.Menu() item1 = area_popup.Append(wx.ID_ANY,'&Grid on/off', 'Toggle grid lines') wx.EVT_MENU(self, item1.GetId(), self.OnGridToggle) cmapmenu = CMapMenu(self, callback = self.OnColormap, mapper=self.mapper, canvas=self.canvas) item2 = area_popup.Append(wx.ID_ANY,'&Toggle log/lin', 'Toggle log/linear scale') wx.EVT_MENU(self, item2.GetId(), lambda evt: self.toggle_log_lin(mpl_mouseevent)) item3 = area_popup.AppendMenu(wx.ID_ANY, "Colourmaps", cmapmenu) self.PopupMenu(area_popup, evt.GetPositionTuple()) def figure_list_dialog(self): figure_list = get_fignums() figure_list_names = [] for fig in figure_list: figure_list_names.append('Figure ' + str(fig)) figure_list_names.insert(0, 'New Figure') figure_list.insert(0, None) #selection_num = wx.GetSingleChoiceIndex('Choose other plot', '', other_plot_names) dlg = wx.SingleChoiceDialog(None, 'Choose figure number', '', figure_list_names) dlg.SetSize(wx.Size(640,480)) if dlg.ShowModal() == wx.ID_OK: selection_num=dlg.GetSelection() dlg.Destroy() print selection_num return figure_list[selection_num] def lineplot_context(self, mpl_mouseevent, evt): popup = wx.Menu() item1 = popup.Append(wx.ID_ANY,'&Toggle log/lin', 'Toggle log/linear scale of slices') wx.EVT_MENU(self, item1.GetId(), lambda evt: self.toggle_log_lin(mpl_mouseevent)) if mpl_mouseevent.inaxes == self.fig.sx: item2 = popup.Append(wx.ID_ANY, "Save x slice", "save this slice") wx.EVT_MENU(self, item2.GetId(), self.save_x_slice) item3 = popup.Append(wx.ID_ANY, '&Popout plot', 'Open this data in a figure window') wx.EVT_MENU(self, item3.GetId(), lambda evt: self.popout_x_slice()) elif mpl_mouseevent.inaxes == self.fig.sz: item2 = popup.Append(wx.ID_ANY, "Save y slice", "save this slice") wx.EVT_MENU(self, item2.GetId(), self.save_y_slice) item3 = popup.Append(wx.ID_ANY, '&Popout plot', 'Open this data in a new plot window') wx.EVT_MENU(self, item3.GetId(), lambda evt: self.popout_y_slice()) self.PopupMenu(popup, evt.GetPositionTuple()) def popout_y_slice(self, event=None, figure_num = None, label = None): if figure_num == None: figure_num = self.figure_list_dialog() fig = figure(figure_num) # if this is None, matplotlib automatically increments figure number to highest + 1 ax = self.fig.sz slice_desc = '\nsliceplot([%f,%f],[%f,%f])' % (self.slice_xy_range[0][0],self.slice_xy_range[0][1],self.slice_xy_range[1][0],self.slice_xy_range[1][1]) if figure_num == None: default_title = self.plot_title + slice_desc dlg = wx.TextEntryDialog(None, 'Enter title for plot', defaultValue = default_title) if dlg.ShowModal() == wx.ID_OK: title = dlg.GetValue() else: title = default_title dlg.Destroy() new_ax = fig.add_subplot(111) new_ax.set_title(title, size='large') new_ax.set_xlabel(self.x_label, size='x-large') new_ax.set_ylabel('$I_{summed}$', size='x-large') else: new_ax = fig.axes[0] if label == None: default_label = self.window_title + ': ' + self.plot_title + slice_desc dlg = wx.TextEntryDialog(None, 'Enter data label (for plot legend)', defaultValue = default_label) if dlg.ShowModal() == wx.ID_OK: label = dlg.GetValue() else: label = default_label dlg.Destroy() xy = ax.lines[0].get_data() x = xy[0] y = xy[1] new_ax.plot(x,y, label = label) font = FontProperties(size='small') lg = legend(prop=font) drag_lg = DraggableLegend(lg) drag_lg.connect() fig.canvas.draw() fig.show() def popout_x_slice(self, event=None, figure_num = None, label = None): if figure_num == None: figure_num = self.figure_list_dialog() fig = figure(figure_num) ax = self.fig.sx slice_desc = '\nsliceplot([%f,%f],[%f,%f])' % (self.slice_xy_range[0][0],self.slice_xy_range[0][1],self.slice_xy_range[1][0],self.slice_xy_range[1][1]) if figure_num == None: default_title = self.plot_title + slice_desc dlg = wx.TextEntryDialog(None, 'Enter title for plot', defaultValue = default_title) if dlg.ShowModal() == wx.ID_OK: title = dlg.GetValue() else: title = default_title dlg.Destroy() new_ax = fig.add_subplot(111) new_ax.set_title(title, size='large') new_ax.set_xlabel(self.y_label, size='x-large') new_ax.set_ylabel('$I_{summed}$', size='x-large') else: new_ax = fig.axes[0] if label == None: default_label = self.window_title + ': ' + self.plot_title + slice_desc dlg = wx.TextEntryDialog(None, 'Enter data label (for plot legend)', defaultValue = default_label) if dlg.ShowModal() == wx.ID_OK: label = dlg.GetValue() else: label = default_label dlg.Destroy() xy = ax.lines[0].get_data() x = xy[1] y = xy[0] new_ax.plot(x,y, label = label) font = FontProperties(size='small') lg = legend(prop=font) drag_lg = DraggableLegend(lg) drag_lg.connect() fig.canvas.draw() fig.show() def save_x_slice(self, event=None, outFileName=None): if outFileName == None: dlg = wx.FileDialog(None, "Save 2d data as:", '', "", "", wx.FD_SAVE) if dlg.ShowModal() == wx.ID_OK: fn = dlg.GetFilename() fd = dlg.GetDirectory() dlg.Destroy() outFileName = fd + '/' + fn outFile = open(outFileName, 'w') outFile.write('#'+self.title+'\n') outFile.write('#xmin: ' + str(self.slice_xy_range[0][0]) + '\n') outFile.write('#xmax: ' + str(self.slice_xy_range[0][1]) + '\n') outFile.write('#ymin: ' + str(self.slice_xy_range[1][0]) + '\n') outFile.write('#ymax: ' + str(self.slice_xy_range[1][1]) + '\n') outFile.write("#y\tslice_x_data\n") if not (self.slice_x_data == None): for i in range(self.slice_x_data.shape[0]): x = self.y[i] y = self.slice_x_data[i] outFile.write(str(x) + "\t" + str(y) + "\n") outFile.close() print('saved x slice in %s' % (outFileName)) return def save_y_slice(self, event=None, outFileName=None): if outFileName == None: dlg = wx.FileDialog(None, "Save 2d data as:", '', "", "", wx.FD_SAVE) if dlg.ShowModal() == wx.ID_OK: fn = dlg.GetFilename() fd = dlg.GetDirectory() dlg.Destroy() outFileName = fd + '/' + fn outFile = open(outFileName, 'w') outFile.write('#'+self.title+'\n') outFile.write('#xmin: ' + str(self.slice_xrange[0]) + '\n') outFile.write('#xmax: ' + str(self.slice_xrange[1]) + '\n') outFile.write('#ymin: ' + str(self.slice_yrange[0]) + '\n') outFile.write('#ymax: ' + str(self.slice_yrange[1]) + '\n') outFile.write("#x\tslice_y_data\n") if not (self.slice_y_data == None): for i in range(self.slice_y_data.shape[0]): x = self.x[i] y = self.slice_y_data[i] outFile.write(str(x) + "\t" + str(y) + "\n") outFile.close() print('saved y slice in %s' % (outFileName)) return def OnGridToggle(self, event): self.fig.ax.grid() self.fig.canvas.draw_idle() def OnColormap(self, name): print "Selected colormap",name self.fig.im.set_cmap(get_cmap(name)) self.fig.canvas.draw() def toggle_2d_plot_scale(self, event=None): if self.__scale == 'log': self.show_data = self.data.T self.fig.im.set_array(self.show_data) self.fig.im.autoscale() self.fig.cb.set_xlabel('$I$') self.__scale = 'lin' self.menu_log_lin_toggle.Check(False) self.statusbar.SetStatusText("%s scale" % self.__scale, 0) self.fig.canvas.draw_idle() elif self.__scale == 'lin': self.show_data = log ( self.data.copy().T + self.minimum_intensity/2.0 ) self.fig.im.set_array(self.show_data) self.fig.im.autoscale() self.fig.cb.set_xlabel('$\log_{10}I$') self.__scale = 'log' self.menu_log_lin_toggle.Check(True) self.statusbar.SetStatusText("%s scale" % self.__scale, 0) self.fig.canvas.draw_idle() def toggle_log_lin(self,event): ax = event.inaxes label = ax.get_label() if label == '2d_plot': self.toggle_2d_plot_scale() if label == 'sz': scale = ax.get_yscale() if scale == 'log': ax.set_yscale('linear') ax.figure.canvas.draw_idle() elif scale == 'linear': ax.set_yscale('log') ax.figure.canvas.draw_idle() elif label == 'sx': scale = ax.get_xscale() if scale == 'log': ax.set_xscale('linear') ax.figure.canvas.draw_idle() elif scale == 'linear': ax.set_xscale('log') ax.figure.canvas.draw_idle() def onmousemove(self,event): # the cursor position is given in the wx status bar #self.fig.gca() if event.inaxes: x, y = event.xdata, event.ydata self.statusbar.SetStatusText("%s scale x = %.3g, y = %.3g" % (self.__scale,x,y), 1) #self.statusbar.SetStatusText("y = %.3g" %y, 2) def onselect(self, eclick, erelease): x_range = [eclick.xdata, erelease.xdata] y_range = [eclick.ydata, erelease.ydata] ax = eclick.inaxes self.sliceplot((x_range, y_range), ax) print 'sliceplot(([%f,%f],[%f,%f]))' % (x_range[0],x_range[1],y_range[0],y_range[1]) def sliceplots_off(self): self.fig.ax.set_position([0.125,0.1,0.7,0.8]) self.fig.cb.set_position([0.85,0.1,0.05,0.8]) #self.fig.cb.set_visible(True) self.fig.sx.set_visible(False) self.fig.sz.set_visible(False) if self.fig.slice_overlay: self.fig.slice_overlay[0].set_visible(False) self.RS.set_active(False) self.show_sliceplots = False self.fig.canvas.draw() def sliceplots_on(self): self.fig.ax.set_position([0.125,0.53636364, 0.35227273,0.36363636]) self.fig.cb.set_position([0.49,0.53636364, 0.02, 0.36363636]) self.fig.sx.set_position([0.58,0.53636364, 0.35227273,0.36363636]) self.fig.sx.set_visible(True) self.fig.sz.set_visible(True) #self.fig.cb.set_visible(False) if self.fig.slice_overlay: self.fig.slice_overlay[0].set_visible(True) self.RS.set_active(True) self.show_sliceplots = True self.fig.canvas.draw() def toggle_sliceplots(self): """switch between views with and without slice plots""" if self.show_sliceplots == True: self.sliceplots_off() else: # self.show_sliceplots == False self.sliceplots_on() def show_slice_overlay(self, x_range, y_range, x, slice_y_data, y, slice_x_data): """sum along x and z within the box defined by qX- and qZrange. sum along qx is plotted to the right of the data, sum along qz is plotted below the data. Transparent white rectangle is overlaid on data to show summing region""" from matplotlib.ticker import FormatStrFormatter, ScalarFormatter if self.fig == None: print('No figure for this dataset is available') return fig = self.fig ax = fig.ax extent = fig.im.get_extent() if fig.slice_overlay == None: fig.slice_overlay = ax.fill([x_range[0],x_range[1],x_range[1],x_range[0]],[y_range[0],y_range[0],y_range[1],y_range[1]],fc='white', alpha=0.3) fig.ax.set_ylim(extent[2],extent[3]) else: fig.slice_overlay[0].xy = [(x_range[0],y_range[0]), (x_range[1],y_range[0]), (x_range[1],y_range[1]), (x_range[0],y_range[1])] fig.sz.clear() default_fmt = ScalarFormatter(useMathText=True) default_fmt.set_powerlimits((-2,4)) fig.sz.xaxis.set_major_formatter(default_fmt) fig.sz.yaxis.set_major_formatter(default_fmt) fig.sz.xaxis.set_major_formatter(FormatStrFormatter('%.2g')) fig.sz.set_xlim(x[0], x[-1]) fig.sz.plot(x, slice_y_data) fig.sx.clear() fig.sx.yaxis.set_major_formatter(default_fmt) fig.sx.xaxis.set_major_formatter(default_fmt) fig.sx.yaxis.set_ticks_position('right') fig.sx.yaxis.set_major_formatter(FormatStrFormatter('%.2g')) fig.sx.set_ylim(y[0], y[-1]) fig.sx.plot(slice_x_data, y) fig.im.set_extent(extent) fig.canvas.draw() def copy_intensity_range_from(self, other_plot): if isinstance(other_plot, type(self)): xlab = self.fig.cb.get_xlabel() ylab = self.fig.cb.get_ylabel() self.fig.im.set_clim(other_plot.fig.im.get_clim()) self.fig.cb.set_xlabel(xlab) self.fig.cb.set_ylabel(ylab) self.fig.canvas.draw() def sliceplot(self, xy_range, ax = None): """sum along x and z within the box defined by qX- and qZrange. sum along qx is plotted to the right of the data, sum along qz is plotted below the data. Transparent white rectangle is overlaid on data to show summing region""" self.sliceplots_on() x_range, y_range = xy_range x, slice_y_data, y, slice_x_data = self.do_xy_slice(x_range, y_range) self.x = x self.slice_y_data = slice_y_data self.y = y self.slice_x_data = slice_x_data self.slice_xy_range = xy_range self.show_slice_overlay(x_range, y_range, x, slice_y_data, y, slice_x_data) def do_xy_slice(self, x_range, y_range): """ slice up the data, once along x and once along z. returns 4 arrays: a y-axis for the x data, an x-axis for the y data.""" #params = self.params print 'doing xy slice' data = self.data pixels = self.pixel_mask # zero out any pixels in the sum that have zero in the pixel count: data[pixels == 0] = 0 normalization_matrix = ones(data.shape) normalization_matrix[pixels == 0] = 0 x_min = min(x_range) x_max = max(x_range) y_min = min(y_range) y_max = max(y_range) x_size,y_size = data.shape global_x_range = (self.x_max - self.x_min) global_y_range = (self.y_max - self.y_min) x_pixel_min = round( (x_min - self.x_min) / global_x_range * x_size ) x_pixel_max = round( (x_max - self.x_min) / global_x_range * x_size ) y_pixel_min = round( (y_min - self.y_min) / global_y_range * y_size ) y_pixel_max = round( (y_max - self.y_min) / global_y_range * y_size ) #correct any sign switches: if (x_pixel_min > x_pixel_max): new_min = x_pixel_max x_pixel_max = x_pixel_min x_pixel_min = new_min if (y_pixel_min > y_pixel_max): new_min = y_pixel_max y_pixel_max = y_pixel_min y_pixel_min = new_min new_x_min = x_pixel_min / x_size * global_x_range + self.x_min new_x_max = x_pixel_max / x_size * global_x_range + self.x_min new_y_min = y_pixel_min / y_size * global_y_range + self.y_min new_y_max = y_pixel_max / y_size * global_y_range + self.y_min x_pixel_min = int(x_pixel_min) x_pixel_max = int(x_pixel_max) y_pixel_min = int(y_pixel_min) y_pixel_max = int(y_pixel_max) y_norm_factor = sum(normalization_matrix[x_pixel_min:x_pixel_max,y_pixel_min:y_pixel_max], axis=1) x_norm_factor = sum(normalization_matrix[x_pixel_min:x_pixel_max,y_pixel_min:y_pixel_max], axis=0) # make sure the normalization has a minimum value of 1 everywhere, # to avoid divide by zero errors: y_norm_factor[y_norm_factor == 0] = 1 x_norm_factor[x_norm_factor == 0] = 1 slice_y_data = sum(data[x_pixel_min:x_pixel_max,y_pixel_min:y_pixel_max], axis=1) / y_norm_factor slice_x_data = sum(data[x_pixel_min:x_pixel_max,y_pixel_min:y_pixel_max], axis=0) / x_norm_factor #slice_y_data = slice_y_data #slice_x_data = slice_x_data x_vals = arange(slice_y_data.shape[0], dtype = 'float') / slice_y_data.shape[0] * (new_x_max - new_x_min) + new_x_min y_vals = arange(slice_x_data.shape[0], dtype = 'float') / slice_x_data.shape[0] * (new_y_max - new_y_min) + new_y_min return x_vals, slice_y_data, y_vals, slice_x_data