class PlotterFrame(wx.Frame): _about = """StepScan 2D Plotter Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, dbname=None, server='sqlite', host=None, port=None, user=None, password=None, create=True, **kws): wx.Frame.__init__(self, None, -1, style=FRAMESTYLE) self.data = None self.filemap = {} title = "Step Scan Data File Viewer" self.scandb = None if dbname is not None: self.scandb = ScanDB(dbname=dbname, server=server, host=host, user=user, password=password, port=port, create=create) self.filemap[CURSCAN] = SCANGROUP title = '%s, with Live Scan Viewing' % title self.larch = None self.plotters = [] self.SetTitle(title) self.SetSize((850, 650)) self.SetFont(Font(9)) self.createMainPanel() self.createMenus() self.statusbar = self.CreateStatusBar(2, 0) self.statusbar.SetStatusWidths([-3, -1]) statusbar_fields = ["Initializing....", " "] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) if dbname is not None: self.live_scanfile = None self.live_cpt = -1 self.filelist.Append(CURSCAN) self.scantimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onScanTimer, self.scantimer) self.scantimer.Start(250) def onScanTimer(self, evt=None, **kws): if self.larch is None: return group = getattr(self.larch.symtable, SCANGROUP) curfile = fix_filename(self.scandb.get_info('filename')) if curfile != self.live_scanfile: self.live_scanfile = curfile group.filename = self.live_scanfile group.array_units = [] self.live_cpt = -1 sdata = self.scandb.get_scandata() if len(sdata) <= 1: return npts = len(sdata[-1].data) if npts <= self.live_cpt: return self.live_cpt = npts if len(group.array_units) < 1: group.array_units = [str(row.notes) for row in sdata] for row in sdata: setattr(group, fix_filename(row.name), np.array(row.data)) if npts > 1: self.onPlot() def createMainPanel(self): splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(175) self.filelist = wx.ListBox(splitter) self.filelist.SetBackgroundColour(wx.Colour(255, 255, 255)) self.filelist.Bind(wx.EVT_LISTBOX, self.ShowFile) self.detailspanel = self.createDetailsPanel(splitter) splitter.SplitVertically(self.filelist, self.detailspanel, 1) wx.CallAfter(self.init_larch) def createDetailsPanel(self, parent): mainpanel = wx.Panel(parent) mainsizer = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(mainpanel) sizer = wx.GridBagSizer(8, 7) self.title = SimpleText(panel, 'initializing...') ir = 0 sizer.Add(self.title, (ir, 0), (1, 6), LCEN, 2) # x-axis self.xarr = add_choice(panel, choices=[], action=self.onYchoice, size=(120, -1)) self.xop = add_choice(panel, choices=('', 'log'), action=self.onYchoice, size=(75, -1)) ir += 1 sizer.Add(SimpleText(panel, 'X = '), (ir, 0), (1, 1), CEN, 0) sizer.Add(self.xop, (ir, 1), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, '('), (ir, 2), (1, 1), CEN, 0) sizer.Add(self.xarr, (ir, 3), (1, 1), RCEN, 0) sizer.Add(SimpleText(panel, ')'), (ir, 4), (1, 1), CEN, 0) self.yops = [[],[]] self.yarr = [[],[]] for opts, sel, siz in ((PRE_OPS, 0, 75), (ARR_OPS, 3, 50), (ARR_OPS, 3, 50)): w1 = add_choice(panel, choices=opts, action=self.onYchoice, size=(siz, -1)) w1.SetSelection(sel) self.yops[0].append(w1) w2 = add_choice(panel, choices=opts, action=self.onYchoice, size=(siz, -1)) w2.SetSelection(sel) self.yops[1].append(w2) opts= {'choices':[], 'size':(120, -1), 'action':self.onYchoice} for i in range(3): self.yarr[0].append(add_choice(panel, **opts)) self.yarr[1].append(add_choice(panel, **opts)) for i in range(2): ir += 1 label = 'Y%i = ' % (i+1) sizer.Add(SimpleText(panel, label), (ir, 0), (1, 1), CEN, 0) sizer.Add(self.yops[i][0], (ir, 1), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, '[('), (ir, 2), (1, 1), CEN, 0) sizer.Add(self.yarr[i][0], (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yops[i][1], (ir, 4), (1, 1), CEN, 0) sizer.Add(self.yarr[i][1], (ir, 5), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ')'), (ir, 6), (1, 1), LCEN, 0) sizer.Add(self.yops[i][2], (ir, 7), (1, 1), CEN, 0) sizer.Add(self.yarr[i][2], (ir, 8), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ']'), (ir, 9), (1, 1), LCEN, 0) ir += 1 # sizer.Add(SimpleText(panel, ' New Plot: '), (ir, 0), (1, 3), LCEN, 0) # sizer.Add(SimpleText(panel, ' Over Plot: '), (ir+1, 0), (1, 3), LCEN, 0) for jr, ic, dc, opt, ttl in ((0, 0, 4, 'win old', 'New Plot, This Window'), (0, 4, 2, 'win new', 'New Plot, New Window'), (1, 0, 4, 'over left', 'Over Plot, Left Axis'), (1, 4, 2, 'over right', 'Over Plot, Right Axis')): sizer.Add(add_button(panel, ttl, size=(165, -1), action=Closure(self.onPlot, opt=opt)), (ir+jr, ic), (1, dc), LCEN, 2) ir += 2 self.dtcorr = check(panel, default=True, label='correct deadtime?') sizer.Add(self.dtcorr, (ir, 0), (1, 3), LCEN, 0) ir += 1 sizer.Add(SimpleText(panel, ''), (ir, 0), (1, 3), LCEN, 0) pack(panel, sizer) # self.nb = flat_nb.FlatNotebook(mainpanel, -1, agwStyle=FNB_STYLE) # # self.nb.SetTabAreaColour(wx.Colour(248,248,240)) # self.nb.SetActiveTabColour(wx.Colour(254,254,195)) # # self.nb.SetNonActiveTabTextColour(wx.Colour(40,40,180)) # self.nb.SetActiveTabTextColour(wx.Colour(80,0,0)) # # self.xas_panel = self.CreateXASPanel(self.nb) # mainpanel) # self.fit_panel = self.CreateFitPanel(self.nb) # mainpanel) # # self.nb.AddPage(self.fit_panel, ' General Analysis ', True) # self.nb.AddPage(self.xas_panel, ' XAS Processing ', True) mainsizer.Add(panel, 0, LCEN|wx.EXPAND, 2) self.plotpanel = PlotPanel(mainpanel, size=(500, 670)) self.plotpanel.messenger = self.write_message bgcol = panel.GetBackgroundColour() bgcol = (bgcol[0]/255., bgcol[1]/255., bgcol[2]/255.) self.plotpanel.canvas.figure.set_facecolor(bgcol) mainsizer.Add(self.plotpanel, 1, wx.GROW|wx.ALL, 1) # mainsizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2) pack(mainpanel, mainsizer) return mainpanel def CreateFitPanel(self, parent): p = panel = wx.Panel(parent) self.fit_model = add_choice(panel, size=(100, -1), choices=('Gaussian', 'Lorentzian', 'Voigt', 'Linear', 'Quadratic', 'Step', 'Rectangle', 'Exponential')) self.fit_bkg = add_choice(panel, size=(100, -1), choices=('None', 'constant', 'linear', 'quadtratic')) self.fit_step = add_choice(panel, size=(100, -1), choices=('linear', 'error function', 'arctan')) self.fit_report = wx.StaticText(panel, -1, "", (180, 200)) sizer = wx.GridBagSizer(10, 4) sizer.Add(SimpleText(p, 'Fit Model: '), (0, 0), (1, 1), LCEN) sizer.Add(self.fit_model, (0, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Background: '), (1, 0), (1, 1), LCEN) sizer.Add(self.fit_bkg, (1, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Step Function Form: '), (2, 0), (1, 1), LCEN) sizer.Add(self.fit_step, (2, 1), (1, 1), LCEN) sizer.Add(add_button(panel, 'Show Fit', size=(100, -1), action=self.onFitPeak), (3, 0), (1, 1), LCEN) sizer.Add(self.fit_report, (0, 2), (4, 2), LCEN, 3) pack(panel, sizer) return panel def CreateXASPanel(self, parent): p = panel = wx.Panel(parent) self.xas_autoe0 = check(panel, default=True, label='auto?') self.xas_autostep = check(panel, default=True, label='auto?') self.xas_op = add_choice(panel, size=(95, -1), choices=('Raw Data', 'Pre-edged', 'Normalized', 'Flattened')) self.xas_e0 = FloatCtrl(panel, value = 0, precision=3, size=(95, -1)) self.xas_step = FloatCtrl(panel, value = 0, precision=3, size=(95, -1)) self.xas_pre1 = FloatCtrl(panel, value=-200, precision=1, size=(95, -1)) self.xas_pre2 = FloatCtrl(panel, value= -30, precision=1, size=(95, -1)) self.xas_nor1 = FloatCtrl(panel, value= 30, precision=1, size=(95, -1)) self.xas_nor2 = FloatCtrl(panel, value= 300, precision=1, size=(95, -1)) self.xas_vict = add_choice(panel, size=(50, -1), choices=('0', '1', '2', '3')) self.xas_nnor = add_choice(panel, size=(50, -1), choices=('0', '1', '2', '3')) self.xas_vict.SetSelection(1) self.xas_nnor.SetSelection(2) sizer = wx.GridBagSizer(10, 4) sizer.Add(SimpleText(p, 'Plot XAS as: '), (0, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'E0 : '), (1, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Edge Step: '), (2, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Pre-edge range: '), (3, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Normalization range: '), (4, 0), (1, 1), LCEN) sizer.Add(self.xas_op, (0, 1), (1, 1), LCEN) sizer.Add(self.xas_e0, (1, 1), (1, 1), LCEN) sizer.Add(self.xas_step, (2, 1), (1, 1), LCEN) sizer.Add(self.xas_pre1, (3, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (3, 2), (1, 1), LCEN) sizer.Add(self.xas_pre2, (3, 3), (1, 1), LCEN) sizer.Add(self.xas_nor1, (4, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (4, 2), (1, 1), LCEN) sizer.Add(self.xas_nor2, (4, 3), (1, 1), LCEN) sizer.Add(self.xas_autoe0, (1, 2), (1, 2), LCEN) sizer.Add(self.xas_autostep, (2, 2), (1, 2), LCEN) sizer.Add(SimpleText(p, 'Victoreen:'), (3, 4), (1, 1), LCEN) sizer.Add(self.xas_vict, (3, 5), (1, 1), LCEN) sizer.Add(SimpleText(p, 'PolyOrder:'), (4, 4), (1, 1), LCEN) sizer.Add(self.xas_nnor, (4, 5), (1, 1), LCEN) pack(panel, sizer) return panel def onFitPeak(self, evt=None): gname = self.groupname if self.dtcorr.IsChecked(): print('fit needs to dt correct!') dtext = [] model = self.fit_model.GetStringSelection().lower() dtext.append('Fit Model: %s' % model) bkg = self.fit_bkg.GetStringSelection() if bkg == 'None': bkg = None if bkg is None: dtext.append('No Background') else: dtext.append('Background: %s' % bkg) step = self.fit_step.GetStringSelection().lower() if model in ('step', 'rectangle'): dtext.append('Step form: %s' % step) lgroup = getattr(self.larch.symtable, gname) x = lgroup._x1_ y = lgroup._y1_ pgroup = fit_peak(x, y, model, background=bkg, step=step, _larch=self.larch) text = fit_report(pgroup.params, _larch=self.larch) dtext.append('Parameters: ') for pname in dir(pgroup.params): par = getattr(pgroup.params, pname) if isParameter(par): ptxt = " %s= %.4f" % (par.name, par.value) if (hasattr(par, 'stderr') and par.stderr is not None): ptxt = "%s(%.4f)" % (ptxt, par.stderr) dtext.append(ptxt) dtext = '\n'.join(dtext) # plotframe = self.get_plotwindow() # plotframe.oplot(x, pgroup.fit, label='fit (%s)' % model) text = fit_report(pgroup.params, _larch=self.larch) self.fit_report.SetLabel(dtext) def xas_process(self, gname, plotopts): """ process (pre-edge/normalize) XAS data from XAS form, overwriting larch group '_y1_' attribute to be plotted """ out = self.xas_op.GetStringSelection().lower() # raw, pre, norm, flat if out.startswith('raw'): return plotopts preopts = {'group': gname, 'e0': None, 'step': None} lgroup = getattr(self.larch.symtable, gname) if self.dtcorr.IsChecked(): print( 'need to dt correct!') if not self.xas_autoe0.IsChecked(): xmin, xmax = min(lgroup._x1_), max(lgroup._x1_) e0 = self.xas_e0.GetValue() if e0 < xmax and e0 > xmin: preopts['e0'] = e0 if not self.xas_autostep.IsChecked(): preopts['step'] = self.xas_step.GetValue() preopts['pre1'] = self.xas_pre1.GetValue() preopts['pre2'] = self.xas_pre2.GetValue() preopts['norm1'] = self.xas_nor1.GetValue() preopts['norm2'] = self.xas_nor2.GetValue() preopts['nvict'] = self.xas_vict.GetSelection() preopts['nnorm'] = self.xas_nnor.GetSelection() preopts = ", ".join(["%s=%s" %(k, v) for k,v in preopts.items()]) preedge_cmd = "pre_edge(%s._x1_, %s._y1_, %s)" % (gname, gname, preopts) self.larch(preedge_cmd) self.xas_e0.SetValue(lgroup.e0) self.xas_step.SetValue(lgroup.edge_step) if out.startswith('pre'): self.larch('%s._y1_ = %s.norm * %s.edge_step' % (gname, gname, gname)) elif out.startswith('norm'): self.larch('%s._y1_ = %s.norm' % (gname, gname)) elif out.startswith('flat'): self.larch('%s._y1_ = %s.flat' % (gname, gname)) return plotopts def init_larch(self): t0 = time.time() from larch.wxlib import inputhook self.larch = Interpreter() self.larch.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp()) self.larch.symtable.set_symbol('_sys.wx.parent', self) self.larch('%s = group(filename="%s")' % (SCANGROUP, CURSCAN)) self.SetStatusText('ready') self.datagroups = self.larch.symtable self.title.SetLabel('') def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def get_plotwindow(self, new=False, **kws): pframe = None if not new: while pframe is None: try: pframe = self.plotters.pop() pframe.Show() pframe.Raise() except IndexError: pframe = None break except PyDeadObjectError: pframe = None if pframe is None: pframe = PlotFrame() pframe.Show() pframe.Raise() self.plotters.append(pframe) return pframe def onYchoice(self, evt=None, side='left'): self.onPlot() def onPlot(self, evt=None, opt='new old', npts=None): # 'win new', 'New Window'), # 'win old', 'Old Window'), # 'over left', 'Left Axis'), # 'over right', 'Right Axis')): # 'update left', from scan optwords = opt.split() # plotframe = self.get_plotwindow(new=('new' in optwords[1])) # plotcmd = plotframe.plot plotcmd = self.plotpanel.plot optwords = opt.split() side = 'left' update = False if optwords[0] == 'over': side = optwords[1] plotcmd = self.plotpanel.oplot elif optwords[0] == 'update' and npts > 4: plotcmd = self.plotpanel.update_line update = True popts = {'side': side} ix = self.xarr.GetSelection() x = self.xarr.GetStringSelection() try: gname = self.groupname lgroup = getattr(self.larch.symtable, gname) except: gname = SCANGROUP lgroup = getattr(self.larch.symtable, gname) xfmt = "%s._x1_ = %s(%s)" yfmt = "%s._y1_ = %s((%s %s %s) %s (%s))" xop = self.xop.GetStringSelection() xlabel = x try: xunits = lgroup.array_units[ix] except: xunits = '' if xop != '': xlabel = "%s(%s)" % (xop, xlabel) if xunits != '': xlabel = '%s (%s)' % (xlabel, xunits) popts['xlabel'] = xlabel opl1 = self.yops[0][0].GetStringSelection() opl2 = self.yops[0][1].GetStringSelection() opl3 = self.yops[0][2].GetStringSelection() yl1 = self.yarr[0][0].GetStringSelection() yl2 = self.yarr[0][1].GetStringSelection() yl3 = self.yarr[0][2].GetStringSelection() opr1 = self.yops[1][0].GetStringSelection() opr2 = self.yops[1][1].GetStringSelection() opr3 = self.yops[1][2].GetStringSelection() yr1 = self.yarr[1][0].GetStringSelection() yr2 = self.yarr[1][1].GetStringSelection() yr3 = self.yarr[1][2].GetStringSelection() ylabel = yl1 if yl2 == '': yl2, opl2 = '1', '*' else: ylabel = "%s%s%s" % (ylabel, opl2, yl2) if yl3 == '': yl3, opl3 = '1', '*' else: ylabel = "(%s)%s%s" % (ylabel, opl3, yl3) if opl1 != '': ylabel = "%s(%s)" % (opl1, ylabel) if yl1 not in ('0', '1'): yl1 = "%s.%s" % (gname, yl1) if yl2 not in ('0', '1'): yl2 = "%s.%s" % (gname, yl2) if yl3 not in ('0', '1'): yl3 = "%s.%s" % (gname, yl3) if x not in ('0', '1'): x = "%s.%s" % (gname, x) self.larch(xfmt % (gname, xop, x)) self.larch(yfmt % (gname, opl1, yl1, opl2, yl2, opl3, yl3)) try: npts = min(len(lgroup._x1_), len(lgroup._y1_)) except AttributeError: return lgroup._x1_ = np.array( lgroup._x1_[:npts]) lgroup._y1_ = np.array( lgroup._y1_[:npts]) path, fname = os.path.split(lgroup.filename) popts['label'] = "%s: %s" % (fname, ylabel) if side == 'right': popts['y2label'] = ylabel else: popts['ylabel'] = ylabel if plotcmd == self.plotpanel.plot: popts['title'] = fname # XAFS Processing! #if (self.nb.GetCurrentPage() == self.xas_panel): # popts = self.xas_process(gname, popts) if update: self.plotpanel.set_xlabel(popts['xlabel']) self.plotpanel.set_ylabel(popts['ylabel']) plotcmd(0, lgroup._x1_, lgroup._y1_, draw=True, update_limits=True) # ((npts < 5) or (npts % 5 == 0))) self.plotpanel.set_xylims(( min(lgroup._x1_), max(lgroup._x1_), min(lgroup._y1_), max(lgroup._y1_))) else: plotcmd(lgroup._x1_, lgroup._y1_, **popts) self.plotpanel.canvas.draw() def ShowFile(self, evt=None, filename=None, **kws): if filename is None and evt is not None: filename = evt.GetString() key = filename if filename in self.filemap: key = self.filemap[filename] if key == SCANGROUP: array_labels = [fix_filename(s.name) for s in self.scandb.get_scandata()] title = filename elif hasattr(self.datagroups, key): data = getattr(self.datagroups, key) title = data.filename array_labels = data.array_labels[:] self.groupname = key xcols = array_labels[:] ycols = array_labels[:] y2cols = array_labels[:] + ['1.0', '0.0', ''] ncols = len(xcols) self.title.SetLabel(title) self.xarr.SetItems(xcols) self.xarr.SetSelection(0) self.xop.SetSelection(0) for i in range(2): for j in range(3): self.yarr[i][j].SetItems(y2cols) self.yarr[i][j].SetSelection(len(y2cols)) if i == 0: self.yarr[i][0].SetItems(ycols) self.yarr[i][0].SetSelection(1) inb = 0 for colname in xcols: if 'energ' in colname.lower(): inb = 1 #self.nb.SetSelection(inb) def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() pmenu = wx.Menu() add_menu(self, fmenu, "&Open Scan File\tCtrl+O", "Read Scan File", self.onReadScan) fmenu.AppendSeparator() add_menu(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) self.menubar.Append(fmenu, "&File") # fmenu.AppendSeparator() # add_menu(self, fmenu, "&Copy\tCtrl+C", # "Copy Figure to Clipboard", self.onClipboard) # add_menu(self, fmenu, "&Save\tCtrl+S", "Save Figure", self.onSaveFig) # add_menu(self, fmenu, "&Print\tCtrl+P", "Print Figure", self.onPrint) # add_menu(self, fmenu, "Page Setup", "Print Page Setup", self.onPrintSetup) # add_menu(self, fmenu, "Preview", "Print Preview", self.onPrintPreview) # # add_menu(self, pmenu, "Configure\tCtrl+K", # "Configure Plot", self.onConfigurePlot) #add_menu(self, pmenu, "Unzoom\tCtrl+Z", "Unzoom Plot", self.onUnzoom) ##pmenu.AppendSeparator() #add_menu(self, pmenu, "Toggle Legend\tCtrl+L", # "Toggle Legend on Plot", self.onToggleLegend) #add_menu(self, pmenu, "Toggle Grid\tCtrl+G", # "Toggle Grid on Plot", self.onToggleGrid) # self.menubar.Append(pmenu, "Plot Options") self.SetMenuBar(self.menubar) def onAbout(self,evt): dlg = wx.MessageDialog(self, self._about,"About Epics StepScan", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self,evt): for obj in self.plotters: try: obj.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) del obj self.Destroy() def onReadScan(self, evt=None): dlg = wx.FileDialog(self, message="Load Epics Scan Data File", defaultDir=os.getcwd(), wildcard=FILE_WILDCARDS, style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() path = path.replace('\\', '/') if path in self.filemap: if wx.ID_YES != popup(self, "Re-read file '%s'?" % path, 'Re-read file?'): return gname = randname(n=5) if hasattr(self.datagroups, gname): time.sleep(0.005) gname = randname(n=6) parent, fname = os.path.split(path) self.larch("%s = read_xdi('%s')" % (gname, path)) self.larch("%s.path = '%s'" % (gname, path)) self.filelist.Append(fname) self.filemap[fname] = gname print( 'Larch:: ', gname, path, fname) self.ShowFile(filename=fname) dlg.Destroy()
class StripChartFrame(wx.Frame): def __init__(self, parent, ID, **kws): kws["style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL wx.Frame.__init__(self, parent, ID, '', wx.DefaultPosition, wx.Size(-1, -1), **kws) self.SetTitle("wxmplot StripChart Demo") self.tmin = 15.0 self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False)) menu = wx.Menu() ID_EXIT = wx.NewId() ID_TIMER = wx.NewId() menu_exit = menu.Append(ID_EXIT, "E&xit", "Terminate the program") menuBar = wx.MenuBar() menuBar.Append(menu, "&File") self.SetMenuBar(menuBar) self.Bind(wx.EVT_MENU, self.OnExit, menu_exit) self.Bind(wx.EVT_CLOSE, self.OnExit) sbar = self.CreateStatusBar(2, wx.CAPTION) sfont = sbar.GetFont() sfont.SetWeight(wx.BOLD) sfont.SetPointSize(11) sbar.SetFont(sfont) self.SetStatusWidths([-3, -1]) self.SetStatusText('', 0) mainsizer = wx.BoxSizer(wx.VERTICAL) btnpanel = wx.Panel(self, -1) btnsizer = wx.BoxSizer(wx.HORIZONTAL) b_on = wx.Button(btnpanel, -1, 'Start', size=(-1, -1)) b_off = wx.Button(btnpanel, -1, 'Stop', size=(-1, -1)) b_on.Bind(wx.EVT_BUTTON, self.onStartTimer) b_off.Bind(wx.EVT_BUTTON, self.onStopTimer) tlabel = wx.StaticText(btnpanel, -1, ' Time range:') self.time_range = FloatCtrl(btnpanel, size=(100, -1), value=abs(self.tmin), precision=1) btnsizer.Add(b_on, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0) btnsizer.Add(b_off, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0) btnsizer.Add( tlabel, 1, wx.GROW | wx.ALL | wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0) btnsizer.Add(self.time_range, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0) btnpanel.SetSizer(btnsizer) btnsizer.Fit(btnpanel) self.plotpanel = PlotPanel(self, messenger=self.write_message) self.plotpanel.BuildPanel() self.plotpanel.set_xlabel('Time from Present (s)') mainsizer.Add(btnpanel, 0, wx.GROW | wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0) mainsizer.Add( self.plotpanel, 1, wx.GROW | wx.ALL | wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 0) self.SetSizer(mainsizer) mainsizer.Fit(self) self.Bind(wx.EVT_TIMER, self.onTimer) self.timer = wx.Timer(self) self.count = 0 self.Refresh() wx.CallAfter(self.onStartTimer) def write_message(self, msg, panel=0): """write a message to the Status Bar""" self.SetStatusText(msg, panel) def onStartTimer(self, event=None): self.count = 0 t0, y0 = next_data() self.ylist = [y0] self.tlist = [t0] self.tmin_last = -10000 self.time0 = time.time() self.timer.Start(50) def onStopTimer(self, event=None): self.timer.Stop() def onTimer(self, event): self.count += 1 etime = time.time() - self.time0 self.tmin = float(self.time_range.GetValue()) t1, y1 = next_data() self.tlist.append(t1) self.ylist.append(y1) tdat = np.array(self.tlist) - t1 mask = np.where(tdat > -abs(self.tmin)) ydat = np.array(self.ylist) n = len(self.ylist) if n <= 2: self.plotpanel.plot(tdat, ydat) else: self.plotpanel.update_line(0, tdat, ydat, draw=True) self.write_message(" %i points in %8.4f s" % (n, etime)) lims = self.plotpanel.get_viewlimits() try: ymin, ymax = ydat[mask].min(), ydat[mask].max() except: ymin, ymax = ydat.min(), ydat.max() tmin = max(int(min(tdat)) - 1.0, -self.tmin) if (ymin < lims[2] or ymax > lims[3] or tmin != self.tmin_last or time.time() - self.last_update > 2): self.tmin_last = tmin self.last_update = time.time() self.plotpanel.set_xylims((tmin, 0, ymin, ymax)) def OnAbout(self, event): dlg = wx.MessageDialog(self, "wxmplot example: stripchart app", "About WXMPlot test", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def OnExit(self, event): self.Destroy()
class Viewer1DXRD(wx.Panel): ''' Frame for housing all 1D XRD viewer widgets ''' label='Viewer' def __init__(self,parent,owner=None,_larch=None): wx.Panel.__init__(self, parent) self.parent = parent self.owner = owner ## Default information self.data_name = [] self.xy_data = [] self.xy_plot = [] self.plotted_data = [] self.xy_scale = [] self.wavelength = None self.xlabel = 'q (A^-1)' self.xunits = ['q','d'] self.cif_name = [] self.cif_data = [] self.cif_plot = [] self.plotted_cif = [] self.x_for_zoom = None self.Panel1DViewer() ############################################## #### PANEL DEFINITIONS def Panel1DViewer(self): ''' Frame for housing all 1D XRD viewer widgets ''' leftside = self.LeftSidePanel(self) rightside = self.RightSidePanel(self) panel1D = wx.BoxSizer(wx.HORIZONTAL) panel1D.Add(leftside,flag=wx.ALL,border=10) panel1D.Add(rightside,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) self.SetSizer(panel1D) def Toolbox(self,panel): ''' Frame for visual toolbox ''' tlbx = wx.StaticBox(self,label='PLOT TOOLBOX') vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) ########################### ## X-Scale hbox_xaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_xaxis = wx.StaticText(self, label='X-SCALE') self.ch_xaxis = wx.Choice(self,choices=self.xunits) self.ch_xaxis.Bind(wx.EVT_CHOICE, self.checkXaxis) hbox_xaxis.Add(ttl_xaxis, flag=wx.RIGHT, border=8) hbox_xaxis.Add(self.ch_xaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_xaxis, flag=wx.ALL, border=10) ########################### ## Y-Scale hbox_yaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_yaxis = wx.StaticText(self, label='Y-SCALE') yscales = ['linear','log'] self.ch_yaxis = wx.Choice(self,choices=yscales) self.ch_yaxis.Bind(wx.EVT_CHOICE, None) hbox_yaxis.Add(ttl_yaxis, flag=wx.RIGHT, border=8) hbox_yaxis.Add(self.ch_yaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_yaxis, flag=wx.ALL, border=10) return vbox def DataBox(self,panel): ''' Frame for data toolbox ''' tlbx = wx.StaticBox(self,label='DATA TOOLBOX') vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) ########################### ## DATA CHOICE self.ch_data = wx.Choice(self,choices=self.data_name) self.ch_data.Bind(wx.EVT_CHOICE, self.onSELECT) vbox.Add(self.ch_data, flag=wx.EXPAND|wx.ALL, border=8) #self.ttl_data = wx.StaticText(self, label='') #vbox.Add(self.ttl_data, flag=wx.EXPAND|wx.ALL, border=8) ########################### # self.ck_bkgd = wx.CheckBox(self,label='BACKGROUND') # self.ck_smth = wx.CheckBox(self,label='SMOOTHING') # # self.ck_bkgd.Bind(wx.EVT_CHECKBOX, None) # self.ck_smth.Bind(wx.EVT_CHECKBOX, None) # # vbox.Add(self.ck_bkgd, flag=wx.ALL, border=8) # vbox.Add(self.ck_smth, flag=wx.ALL, border=8) ########################### ## Scale hbox_scl = wx.BoxSizer(wx.HORIZONTAL) ttl_scl = wx.StaticText(self, label='SCALE Y TO:') self.entr_scale = wx.TextCtrl(self,wx.TE_PROCESS_ENTER) btn_scale = wx.Button(self,label='set') btn_scale.Bind(wx.EVT_BUTTON, self.normalize1Ddata) hbox_scl.Add(ttl_scl, flag=wx.RIGHT, border=8) hbox_scl.Add(self.entr_scale, flag=wx.RIGHT, border=8) hbox_scl.Add(btn_scale, flag=wx.RIGHT, border=8) vbox.Add(hbox_scl, flag=wx.BOTTOM|wx.TOP, border=8) ########################### ## Hide/show and reset hbox_btns = wx.BoxSizer(wx.HORIZONTAL) btn_hide = wx.Button(self,label='hide') btn_reset = wx.Button(self,label='reset') btn_rmv = wx.Button(self,label='remove') btn_hide.Bind(wx.EVT_BUTTON, self.hide1Ddata) btn_reset.Bind(wx.EVT_BUTTON, self.reset1Dscale) btn_rmv.Bind(wx.EVT_BUTTON, self.remove1Ddata) btn_hide.Disable() btn_rmv.Disable() hbox_btns.Add(btn_reset, flag=wx.ALL, border=10) hbox_btns.Add(btn_hide, flag=wx.ALL, border=10) hbox_btns.Add(btn_rmv, flag=wx.ALL, border=10) vbox.Add(hbox_btns, flag=wx.ALL, border=10) return vbox def AddPanel(self,panel): hbox = wx.BoxSizer(wx.HORIZONTAL) btn_data = wx.Button(panel,label='ADD NEW DATA SET') btn_data.Bind(wx.EVT_BUTTON, self.loadXYFILE) btn_cif = wx.Button(panel,label='ADD NEW CIF') btn_cif.Bind(wx.EVT_BUTTON, self.loadCIF) hbox.Add(btn_data, flag=wx.ALL, border=8) hbox.Add(btn_cif, flag=wx.ALL, border=8) return hbox def LeftSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) plttools = self.Toolbox(self) addbtns = self.AddPanel(self) dattools = self.DataBox(self) vbox.Add(plttools,flag=wx.ALL,border=10) vbox.Add(addbtns,flag=wx.ALL,border=10) vbox.Add(dattools,flag=wx.ALL,border=10) return vbox def RightSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) self.plot1DXRD(panel) btnbox = self.QuickButtons(panel) vbox.Add(self.plot1D,proportion=1,flag=wx.ALL|wx.EXPAND,border = 10) vbox.Add(btnbox,flag=wx.ALL|wx.ALIGN_RIGHT,border = 10) return vbox def QuickButtons(self,panel): buttonbox = wx.BoxSizer(wx.HORIZONTAL) btn_img = wx.Button(panel,label='SAVE FIGURE') btn_calib = wx.Button(panel,label='PLOT SETTINGS') btn_integ = wx.Button(panel,label='RESET PLOT') btn_img.Bind(wx.EVT_BUTTON, self.onSAVEfig) btn_calib.Bind(wx.EVT_BUTTON, self.onPLOTset) btn_integ.Bind(wx.EVT_BUTTON, self.onRESETplot) buttonbox.Add(btn_img, flag=wx.ALL, border=8) buttonbox.Add(btn_calib, flag=wx.ALL, border=8) buttonbox.Add(btn_integ, flag=wx.ALL, border=8) return buttonbox ############################################## #### PLOTPANEL FUNCTIONS def plot1DXRD(self,panel): self.plot1D = PlotPanel(panel,size=(1000, 500)) self.plot1D.messenger = self.owner.write_message ## Set defaults for plotting self.plot1D.set_ylabel('Intensity (a.u.)') self.plot1D.cursor_mode = 'zoom' ## trying to get this functionality into our gui ## mkak 2016.11.10 # interactive_legend().show() def onSAVEfig(self,event): self.plot1D.save_figure() def onPLOTset(self,event): self.plot1D.configure() def onRESETplot(self,event): self.plot1D.reset_config() ############################################## #### XRD PLOTTING FUNCTIONS def add1Ddata(self,x,y,name=None,cif=False,wavelength=None): plt_no = len(self.data_name) if cif: if name is None: name = 'cif %i' % plt_no else: name = 'cif: %s' % name else: if name is None: name = 'dataset %i' % plt_no else: name = 'data: %s' % name if wavelength is not None: self.addLAMBDA(wavelength) ## Add to data array lists self.data_name.append(name) self.xy_scale.append(max(y)) self.xy_data.extend([x,y]) ## redefine x,y based on scales self.xy_plot.extend([x,y]) ## Add to plot self.plotted_data.append(self.plot1D.oplot(x,y,label=name,show_legend=True))#,xlabel=self.xlabel)) ## Use correct x-axis units self.checkXaxis(None) self.ch_data.Set(self.data_name) self.ch_data.SetStringSelection(name) ## Update toolbox panel, scale all cif to 1000 if cif is True: self.entr_scale.SetValue('1000') self.normalize1Ddata(None) else: self.entr_scale.SetValue(str(self.xy_scale[plt_no])) def addLAMBDA(self,wavelength,units='m'): ## convert to units A if units == 'm': self.wavelength = wavelength*1e10 elif units == 'cm': self.wavelength = wavelength*1e8 elif units == 'mm': self.wavelength = wavelength*1e7 elif units == 'um': self.wavelength = wavelength*1e4 elif units == 'nm': self.wavelength = wavelength*1e1 else: ## units 'A' self.wavelength = wavelength self.xunits.append(u'2\u03B8') self.ch_xaxis.Set(self.xunits) def normalize1Ddata(self,event): plt_no = self.ch_data.GetSelection() self.xy_scale[plt_no] = float(self.entr_scale.GetValue()) if self.xy_scale[plt_no] <= 0: self.xy_scale[plt_no] = max(self.xy_data[(plt_no*2+1)]) self.entr_scale.SetValue(str(self.xy_scale[plt_no])) y = self.xy_data[(plt_no*2+1)] self.xy_plot[(plt_no*2+1)] = y/np.max(y) * self.xy_scale[plt_no] self.updatePLOT() def remove1Ddata(self,event): ## Needs pop up warning: "Do you really want to delete this data set from plotter? ## Current settings will not be saved." ## mkak 2016.11.10 plt_no = self.ch_data.GetSelection() print('EVENTUALLY, button will remove plot: %s' % self.data_name[plt_no]) ## removing name from list works... do not activate till rest is working ## mkak 2016.11.10 # self.data_name.remove(self.data_name[plt_no]) # self.ch_data.Set(self.data_name) def hide1Ddata(self,event): plt_no = self.ch_data.GetSelection() print('EVENTUALLY, button will hide plot: %s' % self.data_name[plt_no]) def onSELECT(self,event): data_str = self.ch_data.GetString(self.ch_data.GetSelection()) # self.ttl_data.SetLabel('SELECTED: %s' % data_str) plt_no = self.ch_data.GetSelection() self.entr_scale.SetValue(str(self.xy_scale[plt_no])) def checkXaxis(self, event): if self.ch_xaxis.GetSelection() == 2: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_2th(self.xy_data[plt_no*2],self.wavelength) elif self.ch_xaxis.GetSelection() == 1: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_d(self.xy_data[plt_no*2]) else: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = self.xy_data[plt_no*2] if self.ch_xaxis.GetSelection() == 2: self.xlabel = r'$2\Theta$'+r' $(^\circ)$' elif self.ch_xaxis.GetSelection() == 1: self.xlabel = 'd ($\AA$)' else: self.xlabel = 'q (1/$\AA$)' self.plot1D.set_xlabel(self.xlabel) self.updatePLOT() def updatePLOT(self): xmax,xmin,ymax,ymin = None,0,None,0 if len(self.plotted_data) > 0: for plt_no in range(len(self.plotted_data)): i = plt_no*2 j = i+1 x = self.xy_plot[i] y = self.xy_plot[j] if xmax is None or xmax < max(x): xmax = max(x) if xmin > min(x): xmin = min(x) if ymax is None or ymax < max(y): ymax = max(y) if ymin > min(y): ymin = min(y) self.plot1D.update_line(plt_no,x,y) self.unzoom_all() self.plot1D.canvas.draw() if self.ch_xaxis.GetSelection() == 1: xmax = 5 self.plot1D.set_xylims([xmin, xmax, ymin, ymax]) def reset1Dscale(self,event): plt_no = self.ch_data.GetSelection() self.xy_plot[(plt_no*2+1)] = self.xy_data[(plt_no*2+1)] self.plot1D.update_line(plt_no,self.xy_plot[(plt_no*2)], self.xy_plot[(plt_no*2+1)]) self.plot1D.canvas.draw() self.unzoom_all() self.updatePLOT() self.xy_scale[plt_no] = max(self.xy_data[(plt_no*2+1)]) self.entr_scale.SetValue(str(self.xy_scale[plt_no])) ####### BEGIN ####### ## THIS IS DIRECTLY FROM XRDDISPLAY.PY ## mkak 2016.11.11 def unzoom_all(self, event=None): xmid, xrange, xmin, xmax = self._get1Dlims() self._set_xview(xmin, xmax) self.xview_range = None def _get1Dlims(self): xmin, xmax = self.plot1D.axes.get_xlim() xrange = xmax-xmin xmid = (xmax+xmin)/2.0 if self.x_for_zoom is not None: xmid = self.x_for_zoom return (xmid, xrange, xmin, xmax) def _set_xview(self, x1, x2, keep_zoom=False, pan=False): xmin,xmax = self.abs_limits() xrange = x2-x1 x1 = max(xmin,x1) x2 = min(xmax,x2) if pan: if x2 == xmax: x1 = x2-xrange elif x1 == xmin: x2 = x1+xrange if not keep_zoom: self.x_for_zoom = (x1+x2)/2.0 self.plot1D.axes.set_xlim((x1, x2)) self.xview_range = [x1, x2] self.plot1D.canvas.draw() def abs_limits(self): if len(self.data_name) > 0: xmin, xmax = self.xy_plot[0].min(), self.xy_plot[0].max() return xmin,xmax ####### END ####### ############################################## #### XRD FILE OPENING/SAVING def loadXYFILE(self,event): wildcards = 'XRD data file (*.xy)|*.xy|All files (*.*)|*.*' dlg = wx.FileDialog(self, message='Choose 1D XRD data file', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.FD_OPEN) path, read = None, False if dlg.ShowModal() == wx.ID_OK: read = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if read: try: x,y = xy_file_reader(path) self.add1Ddata(x,y,name=os.path.split(path)[-1]) except: print('incorrect xy file format: %s' % os.path.split(path)[-1]) def saveXYFILE(self,event): wildcards = 'XRD data file (*.xy)|*.xy|All files (*.*)|*.*' dlg = wx.FileDialog(self, 'Save data as...', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.SAVE|wx.OVERWRITE_PROMPT) path, save = None, False if dlg.ShowModal() == wx.ID_OK: save = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if save: ## mkak 2016.11.16 print('need to write something to save data - like pyFAI does?') def loadCIF(self,event): wildcards = 'XRD cifile (*.cif)|*.cif|All files (*.*)|*.*' dlg = wx.FileDialog(self, message='Choose CIF', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.FD_OPEN) path, read = None, False if dlg.ShowModal() == wx.ID_OK: read = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if read: cifile = os.path.split(path)[-1] try: cif = xu.materials.Crystal.fromCIF(path) except: print('incorrect file format: %s' % os.path.split(path)[-1]) return ## generate hkl list hkllist = [] maxhkl = 8 for i in range(-maxhkl,maxhkl+1): for j in range(-maxhkl,maxhkl+1): for k in range(-maxhkl,maxhkl+1): if i+j+k > 0: # as long as h,k,l all positive, eliminates 0,0,0 hkllist.append([i,j,k]) hc = constants.value(u'Planck constant in eV s') * \ constants.value(u'speed of light in vacuum') * 1e-3 ## units: keV-m if self.wavelength is not None: qlist = cif.Q(hkllist) Flist = cif.StructureFactorForQ(qlist,(hc/(self.wavelength*(1e-10))*1e3)) Fall = [] qall = [] hklall = [] for i,hkl in enumerate(hkllist): if np.abs(Flist[i]) > 0.01: Fadd = np.abs(Flist[i]) qadd = np.linalg.norm(qlist[i]) if qadd not in qall and qadd < 6: Fall.extend((0,Fadd,0)) qall.extend((qadd,qadd,qadd)) if np.shape(Fall)[0] > 0: Fall = np.array(Fall) qall = np.array(qall) self.add1Ddata(qall,Fall,name=os.path.split(path)[-1],cif=True) else: print('Could not calculate real structure factors.') else: print('Wavelength/energy must be specified for structure factor calculations.') def openPONI(self,event): wildcards = 'pyFAI calibration file (*.poni)|*.poni|All files (*.*)|*.*' dlg = wx.FileDialog(self, message='Choose pyFAI calibration file', defaultDir=os.getcwd(), wildcard=wildcards, style=wx.FD_OPEN) path, read = None, False if dlg.ShowModal() == wx.ID_OK: read = True path = dlg.GetPath().replace('\\', '/') dlg.Destroy() if read: try: print('Loading calibration file: %s' % path) ai = pyFAI.load(path) except: print('Not recognized as a pyFAI calibration file.') return self.addLAMBDA(ai._wavelength,units='m') def setLAMBDA(self,event): dlg = SetLambdaDialog() path, okay = None, False if dlg.ShowModal() == wx.ID_OK: okay = True wavelength = dlg.wavelength dlg.Destroy() if okay: self.addLAMBDA(wavelength,units='A')
class Fitting1DXRD(wx.Panel): ''' Frame for housing all 1D XRD fitting widgets ''' label='Fitting' def __init__(self,parent,owner=None,_larch=None): wx.Panel.__init__(self, parent) self.parent = parent self.owner = owner ## Default information self.xlabel = 'q (A^-1)' self.xunits = ['q','d'] self.Panel1DFitting() ############################################## #### PANEL DEFINITIONS def Panel1DFitting(self): ''' Frame for housing all 1D XRD viewer widgets ''' leftside = self.LeftSidePanel(self) rightside = self.RightSidePanel(self) panel1D = wx.BoxSizer(wx.HORIZONTAL) panel1D.Add(leftside,flag=wx.ALL,border=10) panel1D.Add(rightside,proportion=1,flag=wx.EXPAND|wx.ALL,border=10) self.SetSizer(panel1D) def Toolbox(self,panel): ''' Frame for visual toolbox ''' tlbx = wx.StaticBox(self,label='PLOT TOOLBOX') vbox = wx.StaticBoxSizer(tlbx,wx.VERTICAL) ########################### ## X-Scale hbox_xaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_xaxis = wx.StaticText(self, label='X-SCALE') self.ch_xaxis = wx.Choice(self,choices=self.xunits) self.ch_xaxis.Bind(wx.EVT_CHOICE, self.checkXaxis) hbox_xaxis.Add(ttl_xaxis, flag=wx.RIGHT, border=8) hbox_xaxis.Add(self.ch_xaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_xaxis, flag=wx.ALL, border=10) ########################### ## Y-Scale hbox_yaxis = wx.BoxSizer(wx.HORIZONTAL) ttl_yaxis = wx.StaticText(self, label='Y-SCALE') yscales = ['linear','log'] self.ch_yaxis = wx.Choice(self,choices=yscales) self.ch_yaxis.Bind(wx.EVT_CHOICE, None) hbox_yaxis.Add(ttl_yaxis, flag=wx.RIGHT, border=8) hbox_yaxis.Add(self.ch_yaxis, flag=wx.EXPAND, border=8) vbox.Add(hbox_yaxis, flag=wx.ALL, border=10) return vbox def LeftSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) plttools = self.Toolbox(self) vbox.Add(plttools,flag=wx.ALL,border=10) return vbox def RightSidePanel(self,panel): vbox = wx.BoxSizer(wx.VERTICAL) self.plot1DXRD(panel) btnbox = self.QuickButtons(panel) vbox.Add(self.plot1D,proportion=1,flag=wx.ALL|wx.EXPAND,border = 10) vbox.Add(btnbox,flag=wx.ALL|wx.ALIGN_RIGHT,border = 10) return vbox def QuickButtons(self,panel): buttonbox = wx.BoxSizer(wx.HORIZONTAL) btn_img = wx.Button(panel,label='SAVE FIGURE') btn_calib = wx.Button(panel,label='PLOT SETTINGS') btn_integ = wx.Button(panel,label='RESET PLOT') btn_img.Bind(wx.EVT_BUTTON, self.onSAVEfig) btn_calib.Bind(wx.EVT_BUTTON, self.onPLOTset) btn_integ.Bind(wx.EVT_BUTTON, self.onRESETplot) buttonbox.Add(btn_img, flag=wx.ALL, border=8) buttonbox.Add(btn_calib, flag=wx.ALL, border=8) buttonbox.Add(btn_integ, flag=wx.ALL, border=8) return buttonbox ############################################## #### PLOTPANEL FUNCTIONS def plot1DXRD(self,panel): self.plot1D = PlotPanel(panel,size=(1000, 500)) self.plot1D.messenger = self.owner.write_message ## Set defaults for plotting self.plot1D.set_ylabel('Intensity (a.u.)') self.plot1D.cursor_mode = 'zoom' ## trying to get this functionality into our gui ## mkak 2016.11.10 # interactive_legend().show() def onSAVEfig(self,event): self.plot1D.save_figure() def onPLOTset(self,event): self.plot1D.configure() def onRESETplot(self,event): self.plot1D.reset_config() def checkXaxis(self, event): if self.ch_xaxis.GetSelection() == 2: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_2th(self.xy_data[plt_no*2],self.wavelength) elif self.ch_xaxis.GetSelection() == 1: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = calc_q_to_d(self.xy_data[plt_no*2]) else: for plt_no in range(len(self.plotted_data)): self.xy_plot[plt_no*2] = self.xy_data[plt_no*2] if self.ch_xaxis.GetSelection() == 2: self.xlabel = r'$2\Theta$'+r' $(^\circ)$' elif self.ch_xaxis.GetSelection() == 1: self.xlabel = 'd ($\AA$)' else: self.xlabel = 'q (1/$\AA$)' self.plot1D.set_xlabel(self.xlabel) self.updatePLOT() def updatePLOT(self): xmax,xmin,ymax,ymin = None,0,None,0 if len(self.plotted_data) > 0: for plt_no in range(len(self.plotted_data)): i = plt_no*2 j = i+1 x = self.xy_plot[i] y = self.xy_plot[j] if xmax is None or xmax < max(x): xmax = max(x) if xmin > min(x): xmin = min(x) if ymax is None or ymax < max(y): ymax = max(y) if ymin > min(y): ymin = min(y) self.plot1D.update_line(plt_no,x,y) self.unzoom_all() self.plot1D.canvas.draw() if self.ch_xaxis.GetSelection() == 1: xmax = 5 self.plot1D.set_xylims([xmin, xmax, ymin, ymax]) def reset1Dscale(self,event): plt_no = self.ch_data.GetSelection() self.xy_plot[(plt_no*2+1)] = self.xy_data[(plt_no*2+1)] self.plot1D.update_line(plt_no,self.xy_plot[(plt_no*2)], self.xy_plot[(plt_no*2+1)]) self.plot1D.canvas.draw() self.unzoom_all() self.updatePLOT() self.xy_scale[plt_no] = max(self.xy_data[(plt_no*2+1)]) self.entr_scale.SetValue(str(self.xy_scale[plt_no])) ####### BEGIN ####### ## THIS IS DIRECTLY FROM XRDDISPLAY.PY ## mkak 2016.11.11 def unzoom_all(self, event=None): xmid, xrange, xmin, xmax = self._get1Dlims() self._set_xview(xmin, xmax) self.xview_range = None def _get1Dlims(self): xmin, xmax = self.plot1D.axes.get_xlim() xrange = xmax-xmin xmid = (xmax+xmin)/2.0 if self.x_for_zoom is not None: xmid = self.x_for_zoom return (xmid, xrange, xmin, xmax) def _set_xview(self, x1, x2, keep_zoom=False, pan=False): xmin,xmax = self.abs_limits() xrange = x2-x1 x1 = max(xmin,x1) x2 = min(xmax,x2) if pan: if x2 == xmax: x1 = x2-xrange elif x1 == xmin: x2 = x1+xrange if not keep_zoom: self.x_for_zoom = (x1+x2)/2.0 self.plot1D.axes.set_xlim((x1, x2)) self.xview_range = [x1, x2] self.plot1D.canvas.draw() def abs_limits(self): if len(self.data_name) > 0: xmin, xmax = self.xy_plot[0].min(), self.xy_plot[0].max() return xmin,xmax
class StripChartFrame(wx.Frame): def __init__(self, parent, ID, **kws): kws["style"] = wx.DEFAULT_FRAME_STYLE|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL wx.Frame.__init__(self, parent, ID, '', wx.DefaultPosition, wx.Size(-1,-1), **kws) self.SetTitle("wxmplot StripChart Demo") self.tmin = 15.0 self.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.BOLD,False)) menu = wx.Menu() ID_EXIT = wx.NewId() ID_TIMER = wx.NewId() menu_exit = menu.Append(ID_EXIT, "E&xit", "Terminate the program") menuBar = wx.MenuBar() menuBar.Append(menu, "&File"); self.SetMenuBar(menuBar) self.Bind(wx.EVT_MENU, self.OnExit, menu_exit) self.Bind(wx.EVT_CLOSE, self.OnExit) sbar = self.CreateStatusBar(2,wx.CAPTION) sfont = sbar.GetFont() sfont.SetWeight(wx.BOLD) sfont.SetPointSize(11) sbar.SetFont(sfont) self.SetStatusWidths([-3,-1]) self.SetStatusText('',0) mainsizer = wx.BoxSizer(wx.VERTICAL) btnpanel = wx.Panel(self, -1) btnsizer = wx.BoxSizer(wx.HORIZONTAL) b_on = wx.Button(btnpanel, -1, 'Start', size=(-1,-1)) b_off = wx.Button(btnpanel, -1, 'Stop', size=(-1,-1)) b_on.Bind(wx.EVT_BUTTON, self.onStartTimer) b_off.Bind(wx.EVT_BUTTON, self.onStopTimer) tlabel = wx.StaticText(btnpanel, -1, ' Time range:') self.time_range = FloatCtrl(btnpanel, size=(100, -1), value=abs(self.tmin), precision=1) btnsizer.Add(b_on, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0) btnsizer.Add(b_off, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0) btnsizer.Add(tlabel, 1, wx.GROW|wx.ALL|wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0) btnsizer.Add(self.time_range, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0) btnpanel.SetSizer(btnsizer) btnsizer.Fit(btnpanel) self.plotpanel = PlotPanel(self, messenger=self.write_message) self.plotpanel.BuildPanel() self.plotpanel.set_xlabel('Time from Present (s)') mainsizer.Add(btnpanel, 0, wx.GROW|wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0) mainsizer.Add(self.plotpanel, 1, wx.GROW|wx.ALL|wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 0) self.SetSizer(mainsizer) mainsizer.Fit(self) self.Bind(wx.EVT_TIMER, self.onTimer) self.timer = wx.Timer(self) self.count = 0 self.Refresh() wx.CallAfter(self.onStartTimer) def write_message(self, msg, panel=0): """write a message to the Status Bar""" self.SetStatusText(msg, panel) def onStartTimer(self,event=None): self.count = 0 t0,y0 = next_data() self.ylist = [y0] self.tlist = [t0] self.tmin_last = -10000 self.time0 = time.time() self.timer.Start(50) def onStopTimer(self,event=None): self.timer.Stop() def onTimer(self, event): self.count += 1 etime = time.time() - self.time0 self.tmin = float(self.time_range.GetValue()) t1, y1 = next_data() self.tlist.append(t1) self.ylist.append(y1) tdat = np.array(self.tlist) - t1 mask = np.where(tdat > -abs(self.tmin)) ydat = np.array(self.ylist) n = len(self.ylist) if n <= 2: self.plotpanel.plot(tdat, ydat) else: self.plotpanel.update_line(0, tdat, ydat, draw=True) self.write_message(" %i points in %8.4f s" % (n,etime)) lims = self.plotpanel.get_viewlimits() try: ymin, ymax = ydat[mask].min(), ydat[mask].max() except: ymin, ymax = ydat.min(), ydat.max() tmin = max(int(min(tdat)) - 1.0, -self.tmin) if (ymin < lims[2] or ymax > lims[3] or tmin != self.tmin_last or time.time()-self.last_update > 2): self.tmin_last = tmin self.last_update = time.time() self.plotpanel.set_xylims((tmin, 0, ymin, ymax)) def OnAbout(self, event): dlg = wx.MessageDialog(self, "wxmplot example: stripchart app", "About WXMPlot test", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def OnExit(self, event): self.Destroy()
class PlotterFrame(wx.Frame): _about = """StepScan 2D Plotter Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, dbname=None, server='sqlite', host=None, port=None, user=None, password=None, create=True, **kws): wx.Frame.__init__(self, None, -1, style=FRAMESTYLE) self.data = None self.filemap = {} title = "Step Scan Data File Viewer" self.scandb = None if dbname is not None: self.scandb = ScanDB(dbname=dbname, server=server, host=host, user=user, password=password, port=port, create=create) self.filemap[CURSCAN] = SCANGROUP title = '%s, with Live Scan Viewing' % title self.larch = None self.plotters = [] self.SetTitle(title) self.SetSize((850, 650)) self.SetFont(Font(9)) self.createMainPanel() self.createMenus() self.statusbar = self.CreateStatusBar(2, 0) self.statusbar.SetStatusWidths([-3, -1]) statusbar_fields = ["Initializing....", " "] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) if dbname is not None: self.live_scanfile = None self.live_cpt = -1 self.filelist.Append(CURSCAN) self.scantimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onScanTimer, self.scantimer) self.scantimer.Start(250) def onScanTimer(self, evt=None, **kws): if self.larch is None: return group = getattr(self.larch.symtable, SCANGROUP) curfile = fix_filename(self.scandb.get_info('filename')) if curfile != self.live_scanfile: self.live_scanfile = curfile group.filename = self.live_scanfile group.array_units = [] self.live_cpt = -1 sdata = self.scandb.get_scandata() if len(sdata) <= 1: return npts = len(sdata[-1].data) if npts <= self.live_cpt: return self.live_cpt = npts if len(group.array_units) < 1: group.array_units = [str(row.notes) for row in sdata] for row in sdata: setattr(group, fix_filename(row.name), np.array(row.data)) if npts > 1: self.onPlot() def createMainPanel(self): splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(175) self.filelist = wx.ListBox(splitter) self.filelist.SetBackgroundColour(wx.Colour(255, 255, 255)) self.filelist.Bind(wx.EVT_LISTBOX, self.ShowFile) self.detailspanel = self.createDetailsPanel(splitter) splitter.SplitVertically(self.filelist, self.detailspanel, 1) wx.CallAfter(self.init_larch) def createDetailsPanel(self, parent): mainpanel = wx.Panel(parent) mainsizer = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(mainpanel) sizer = wx.GridBagSizer(8, 7) self.title = SimpleText(panel, 'initializing...') ir = 0 sizer.Add(self.title, (ir, 0), (1, 6), LCEN, 2) # x-axis self.xarr = add_choice(panel, choices=[], action=self.onYchoice, size=(120, -1)) self.xop = add_choice(panel, choices=('', 'log'), action=self.onYchoice, size=(75, -1)) ir += 1 sizer.Add(SimpleText(panel, 'X = '), (ir, 0), (1, 1), CEN, 0) sizer.Add(self.xop, (ir, 1), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, '('), (ir, 2), (1, 1), CEN, 0) sizer.Add(self.xarr, (ir, 3), (1, 1), RCEN, 0) sizer.Add(SimpleText(panel, ')'), (ir, 4), (1, 1), CEN, 0) self.yops = [[], []] self.yarr = [[], []] for opts, sel, siz in ((PRE_OPS, 0, 75), (ARR_OPS, 3, 50), (ARR_OPS, 3, 50)): w1 = add_choice(panel, choices=opts, action=self.onYchoice, size=(siz, -1)) w1.SetSelection(sel) self.yops[0].append(w1) w2 = add_choice(panel, choices=opts, action=self.onYchoice, size=(siz, -1)) w2.SetSelection(sel) self.yops[1].append(w2) opts = {'choices': [], 'size': (120, -1), 'action': self.onYchoice} for i in range(3): self.yarr[0].append(add_choice(panel, **opts)) self.yarr[1].append(add_choice(panel, **opts)) for i in range(2): ir += 1 label = 'Y%i = ' % (i + 1) sizer.Add(SimpleText(panel, label), (ir, 0), (1, 1), CEN, 0) sizer.Add(self.yops[i][0], (ir, 1), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, '[('), (ir, 2), (1, 1), CEN, 0) sizer.Add(self.yarr[i][0], (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yops[i][1], (ir, 4), (1, 1), CEN, 0) sizer.Add(self.yarr[i][1], (ir, 5), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ')'), (ir, 6), (1, 1), LCEN, 0) sizer.Add(self.yops[i][2], (ir, 7), (1, 1), CEN, 0) sizer.Add(self.yarr[i][2], (ir, 8), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ']'), (ir, 9), (1, 1), LCEN, 0) ir += 1 # sizer.Add(SimpleText(panel, ' New Plot: '), (ir, 0), (1, 3), LCEN, 0) # sizer.Add(SimpleText(panel, ' Over Plot: '), (ir+1, 0), (1, 3), LCEN, 0) for jr, ic, dc, opt, ttl in ((0, 0, 4, 'win old', 'New Plot, This Window'), (0, 4, 2, 'win new', 'New Plot, New Window'), (1, 0, 4, 'over left', 'Over Plot, Left Axis'), (1, 4, 2, 'over right', 'Over Plot, Right Axis')): sizer.Add( add_button(panel, ttl, size=(165, -1), action=Closure(self.onPlot, opt=opt)), (ir + jr, ic), (1, dc), LCEN, 2) ir += 2 self.dtcorr = check(panel, default=True, label='correct deadtime?') sizer.Add(self.dtcorr, (ir, 0), (1, 3), LCEN, 0) ir += 1 sizer.Add(SimpleText(panel, ''), (ir, 0), (1, 3), LCEN, 0) pack(panel, sizer) # self.nb = flat_nb.FlatNotebook(mainpanel, -1, agwStyle=FNB_STYLE) # # self.nb.SetTabAreaColour(wx.Colour(248,248,240)) # self.nb.SetActiveTabColour(wx.Colour(254,254,195)) # # self.nb.SetNonActiveTabTextColour(wx.Colour(40,40,180)) # self.nb.SetActiveTabTextColour(wx.Colour(80,0,0)) # # self.xas_panel = self.CreateXASPanel(self.nb) # mainpanel) # self.fit_panel = self.CreateFitPanel(self.nb) # mainpanel) # # self.nb.AddPage(self.fit_panel, ' General Analysis ', True) # self.nb.AddPage(self.xas_panel, ' XAS Processing ', True) mainsizer.Add(panel, 0, LCEN | wx.EXPAND, 2) self.plotpanel = PlotPanel(mainpanel, size=(500, 670)) self.plotpanel.messenger = self.write_message bgcol = panel.GetBackgroundColour() bgcol = (bgcol[0] / 255., bgcol[1] / 255., bgcol[2] / 255.) self.plotpanel.canvas.figure.set_facecolor(bgcol) mainsizer.Add(self.plotpanel, 1, wx.GROW | wx.ALL, 1) # mainsizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2) pack(mainpanel, mainsizer) return mainpanel def CreateFitPanel(self, parent): p = panel = wx.Panel(parent) self.fit_model = add_choice(panel, size=(100, -1), choices=('Gaussian', 'Lorentzian', 'Voigt', 'Linear', 'Quadratic', 'Step', 'Rectangle', 'Exponential')) self.fit_bkg = add_choice(panel, size=(100, -1), choices=('None', 'constant', 'linear', 'quadtratic')) self.fit_step = add_choice(panel, size=(100, -1), choices=('linear', 'error function', 'arctan')) self.fit_report = wx.StaticText(panel, -1, "", (180, 200)) sizer = wx.GridBagSizer(10, 4) sizer.Add(SimpleText(p, 'Fit Model: '), (0, 0), (1, 1), LCEN) sizer.Add(self.fit_model, (0, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Background: '), (1, 0), (1, 1), LCEN) sizer.Add(self.fit_bkg, (1, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Step Function Form: '), (2, 0), (1, 1), LCEN) sizer.Add(self.fit_step, (2, 1), (1, 1), LCEN) sizer.Add( add_button(panel, 'Show Fit', size=(100, -1), action=self.onFitPeak), (3, 0), (1, 1), LCEN) sizer.Add(self.fit_report, (0, 2), (4, 2), LCEN, 3) pack(panel, sizer) return panel def CreateXASPanel(self, parent): p = panel = wx.Panel(parent) self.xas_autoe0 = check(panel, default=True, label='auto?') self.xas_autostep = check(panel, default=True, label='auto?') self.xas_op = add_choice(panel, size=(95, -1), choices=('Raw Data', 'Pre-edged', 'Normalized', 'Flattened')) self.xas_e0 = FloatCtrl(panel, value=0, precision=3, size=(95, -1)) self.xas_step = FloatCtrl(panel, value=0, precision=3, size=(95, -1)) self.xas_pre1 = FloatCtrl(panel, value=-200, precision=1, size=(95, -1)) self.xas_pre2 = FloatCtrl(panel, value=-30, precision=1, size=(95, -1)) self.xas_nor1 = FloatCtrl(panel, value=30, precision=1, size=(95, -1)) self.xas_nor2 = FloatCtrl(panel, value=300, precision=1, size=(95, -1)) self.xas_vict = add_choice(panel, size=(50, -1), choices=('0', '1', '2', '3')) self.xas_nnor = add_choice(panel, size=(50, -1), choices=('0', '1', '2', '3')) self.xas_vict.SetSelection(1) self.xas_nnor.SetSelection(2) sizer = wx.GridBagSizer(10, 4) sizer.Add(SimpleText(p, 'Plot XAS as: '), (0, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'E0 : '), (1, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Edge Step: '), (2, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Pre-edge range: '), (3, 0), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Normalization range: '), (4, 0), (1, 1), LCEN) sizer.Add(self.xas_op, (0, 1), (1, 1), LCEN) sizer.Add(self.xas_e0, (1, 1), (1, 1), LCEN) sizer.Add(self.xas_step, (2, 1), (1, 1), LCEN) sizer.Add(self.xas_pre1, (3, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (3, 2), (1, 1), LCEN) sizer.Add(self.xas_pre2, (3, 3), (1, 1), LCEN) sizer.Add(self.xas_nor1, (4, 1), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (4, 2), (1, 1), LCEN) sizer.Add(self.xas_nor2, (4, 3), (1, 1), LCEN) sizer.Add(self.xas_autoe0, (1, 2), (1, 2), LCEN) sizer.Add(self.xas_autostep, (2, 2), (1, 2), LCEN) sizer.Add(SimpleText(p, 'Victoreen:'), (3, 4), (1, 1), LCEN) sizer.Add(self.xas_vict, (3, 5), (1, 1), LCEN) sizer.Add(SimpleText(p, 'PolyOrder:'), (4, 4), (1, 1), LCEN) sizer.Add(self.xas_nnor, (4, 5), (1, 1), LCEN) pack(panel, sizer) return panel def onFitPeak(self, evt=None): gname = self.groupname if self.dtcorr.IsChecked(): print('fit needs to dt correct!') dtext = [] model = self.fit_model.GetStringSelection().lower() dtext.append('Fit Model: %s' % model) bkg = self.fit_bkg.GetStringSelection() if bkg == 'None': bkg = None if bkg is None: dtext.append('No Background') else: dtext.append('Background: %s' % bkg) step = self.fit_step.GetStringSelection().lower() if model in ('step', 'rectangle'): dtext.append('Step form: %s' % step) lgroup = getattr(self.larch.symtable, gname) x = lgroup._x1_ y = lgroup._y1_ pgroup = fit_peak(x, y, model, background=bkg, step=step, _larch=self.larch) text = fit_report(pgroup.params, _larch=self.larch) dtext.append('Parameters: ') for pname in dir(pgroup.params): par = getattr(pgroup.params, pname) if isParameter(par): ptxt = " %s= %.4f" % (par.name, par.value) if (hasattr(par, 'stderr') and par.stderr is not None): ptxt = "%s(%.4f)" % (ptxt, par.stderr) dtext.append(ptxt) dtext = '\n'.join(dtext) # plotframe = self.get_plotwindow() # plotframe.oplot(x, pgroup.fit, label='fit (%s)' % model) text = fit_report(pgroup.params, _larch=self.larch) self.fit_report.SetLabel(dtext) def xas_process(self, gname, plotopts): """ process (pre-edge/normalize) XAS data from XAS form, overwriting larch group '_y1_' attribute to be plotted """ out = self.xas_op.GetStringSelection().lower() # raw, pre, norm, flat if out.startswith('raw'): return plotopts preopts = {'group': gname, 'e0': None, 'step': None} lgroup = getattr(self.larch.symtable, gname) if self.dtcorr.IsChecked(): print('need to dt correct!') if not self.xas_autoe0.IsChecked(): xmin, xmax = min(lgroup._x1_), max(lgroup._x1_) e0 = self.xas_e0.GetValue() if e0 < xmax and e0 > xmin: preopts['e0'] = e0 if not self.xas_autostep.IsChecked(): preopts['step'] = self.xas_step.GetValue() preopts['pre1'] = self.xas_pre1.GetValue() preopts['pre2'] = self.xas_pre2.GetValue() preopts['norm1'] = self.xas_nor1.GetValue() preopts['norm2'] = self.xas_nor2.GetValue() preopts['nvict'] = self.xas_vict.GetSelection() preopts['nnorm'] = self.xas_nnor.GetSelection() preopts = ", ".join(["%s=%s" % (k, v) for k, v in preopts.items()]) preedge_cmd = "pre_edge(%s._x1_, %s._y1_, %s)" % (gname, gname, preopts) self.larch(preedge_cmd) self.xas_e0.SetValue(lgroup.e0) self.xas_step.SetValue(lgroup.edge_step) if out.startswith('pre'): self.larch('%s._y1_ = %s.norm * %s.edge_step' % (gname, gname, gname)) elif out.startswith('norm'): self.larch('%s._y1_ = %s.norm' % (gname, gname)) elif out.startswith('flat'): self.larch('%s._y1_ = %s.flat' % (gname, gname)) return plotopts def init_larch(self): t0 = time.time() from larch.wxlib import inputhook self.larch = Interpreter() self.larch.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp()) self.larch.symtable.set_symbol('_sys.wx.parent', self) self.larch('%s = group(filename="%s")' % (SCANGROUP, CURSCAN)) self.SetStatusText('ready') self.datagroups = self.larch.symtable self.title.SetLabel('') def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def get_plotwindow(self, new=False, **kws): pframe = None if not new: while pframe is None: try: pframe = self.plotters.pop() pframe.Show() pframe.Raise() except IndexError: pframe = None break except PyDeadObjectError: pframe = None if pframe is None: pframe = PlotFrame() pframe.Show() pframe.Raise() self.plotters.append(pframe) return pframe def onYchoice(self, evt=None, side='left'): self.onPlot() def onPlot(self, evt=None, opt='new old', npts=None): # 'win new', 'New Window'), # 'win old', 'Old Window'), # 'over left', 'Left Axis'), # 'over right', 'Right Axis')): # 'update left', from scan optwords = opt.split() # plotframe = self.get_plotwindow(new=('new' in optwords[1])) # plotcmd = plotframe.plot plotcmd = self.plotpanel.plot optwords = opt.split() side = 'left' update = False if optwords[0] == 'over': side = optwords[1] plotcmd = self.plotpanel.oplot elif optwords[0] == 'update' and npts > 4: plotcmd = self.plotpanel.update_line update = True popts = {'side': side} ix = self.xarr.GetSelection() x = self.xarr.GetStringSelection() try: gname = self.groupname lgroup = getattr(self.larch.symtable, gname) except: gname = SCANGROUP lgroup = getattr(self.larch.symtable, gname) xfmt = "%s._x1_ = %s(%s)" yfmt = "%s._y1_ = %s((%s %s %s) %s (%s))" xop = self.xop.GetStringSelection() xlabel = x try: xunits = lgroup.array_units[ix] except: xunits = '' if xop != '': xlabel = "%s(%s)" % (xop, xlabel) if xunits != '': xlabel = '%s (%s)' % (xlabel, xunits) popts['xlabel'] = xlabel opl1 = self.yops[0][0].GetStringSelection() opl2 = self.yops[0][1].GetStringSelection() opl3 = self.yops[0][2].GetStringSelection() yl1 = self.yarr[0][0].GetStringSelection() yl2 = self.yarr[0][1].GetStringSelection() yl3 = self.yarr[0][2].GetStringSelection() opr1 = self.yops[1][0].GetStringSelection() opr2 = self.yops[1][1].GetStringSelection() opr3 = self.yops[1][2].GetStringSelection() yr1 = self.yarr[1][0].GetStringSelection() yr2 = self.yarr[1][1].GetStringSelection() yr3 = self.yarr[1][2].GetStringSelection() ylabel = yl1 if yl2 == '': yl2, opl2 = '1', '*' else: ylabel = "%s%s%s" % (ylabel, opl2, yl2) if yl3 == '': yl3, opl3 = '1', '*' else: ylabel = "(%s)%s%s" % (ylabel, opl3, yl3) if opl1 != '': ylabel = "%s(%s)" % (opl1, ylabel) if yl1 not in ('0', '1'): yl1 = "%s.%s" % (gname, yl1) if yl2 not in ('0', '1'): yl2 = "%s.%s" % (gname, yl2) if yl3 not in ('0', '1'): yl3 = "%s.%s" % (gname, yl3) if x not in ('0', '1'): x = "%s.%s" % (gname, x) self.larch(xfmt % (gname, xop, x)) self.larch(yfmt % (gname, opl1, yl1, opl2, yl2, opl3, yl3)) try: npts = min(len(lgroup._x1_), len(lgroup._y1_)) except AttributeError: return lgroup._x1_ = np.array(lgroup._x1_[:npts]) lgroup._y1_ = np.array(lgroup._y1_[:npts]) path, fname = os.path.split(lgroup.filename) popts['label'] = "%s: %s" % (fname, ylabel) if side == 'right': popts['y2label'] = ylabel else: popts['ylabel'] = ylabel if plotcmd == self.plotpanel.plot: popts['title'] = fname # XAFS Processing! #if (self.nb.GetCurrentPage() == self.xas_panel): # popts = self.xas_process(gname, popts) if update: self.plotpanel.set_xlabel(popts['xlabel']) self.plotpanel.set_ylabel(popts['ylabel']) plotcmd(0, lgroup._x1_, lgroup._y1_, draw=True, update_limits=True) # ((npts < 5) or (npts % 5 == 0))) self.plotpanel.set_xylims((min(lgroup._x1_), max(lgroup._x1_), min(lgroup._y1_), max(lgroup._y1_))) else: plotcmd(lgroup._x1_, lgroup._y1_, **popts) self.plotpanel.canvas.draw() def ShowFile(self, evt=None, filename=None, **kws): if filename is None and evt is not None: filename = evt.GetString() key = filename if filename in self.filemap: key = self.filemap[filename] if key == SCANGROUP: array_labels = [ fix_filename(s.name) for s in self.scandb.get_scandata() ] title = filename elif hasattr(self.datagroups, key): data = getattr(self.datagroups, key) title = data.filename array_labels = data.array_labels[:] self.groupname = key xcols = array_labels[:] ycols = array_labels[:] y2cols = array_labels[:] + ['1.0', '0.0', ''] ncols = len(xcols) self.title.SetLabel(title) self.xarr.SetItems(xcols) self.xarr.SetSelection(0) self.xop.SetSelection(0) for i in range(2): for j in range(3): self.yarr[i][j].SetItems(y2cols) self.yarr[i][j].SetSelection(len(y2cols)) if i == 0: self.yarr[i][0].SetItems(ycols) self.yarr[i][0].SetSelection(1) inb = 0 for colname in xcols: if 'energ' in colname.lower(): inb = 1 #self.nb.SetSelection(inb) def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() pmenu = wx.Menu() add_menu(self, fmenu, "&Open Scan File\tCtrl+O", "Read Scan File", self.onReadScan) fmenu.AppendSeparator() add_menu(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) self.menubar.Append(fmenu, "&File") # fmenu.AppendSeparator() # add_menu(self, fmenu, "&Copy\tCtrl+C", # "Copy Figure to Clipboard", self.onClipboard) # add_menu(self, fmenu, "&Save\tCtrl+S", "Save Figure", self.onSaveFig) # add_menu(self, fmenu, "&Print\tCtrl+P", "Print Figure", self.onPrint) # add_menu(self, fmenu, "Page Setup", "Print Page Setup", self.onPrintSetup) # add_menu(self, fmenu, "Preview", "Print Preview", self.onPrintPreview) # # add_menu(self, pmenu, "Configure\tCtrl+K", # "Configure Plot", self.onConfigurePlot) #add_menu(self, pmenu, "Unzoom\tCtrl+Z", "Unzoom Plot", self.onUnzoom) ##pmenu.AppendSeparator() #add_menu(self, pmenu, "Toggle Legend\tCtrl+L", # "Toggle Legend on Plot", self.onToggleLegend) #add_menu(self, pmenu, "Toggle Grid\tCtrl+G", # "Toggle Grid on Plot", self.onToggleGrid) # self.menubar.Append(pmenu, "Plot Options") self.SetMenuBar(self.menubar) def onAbout(self, evt): dlg = wx.MessageDialog(self, self._about, "About Epics StepScan", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self, evt): for obj in self.plotters: try: obj.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) del obj self.Destroy() def onReadScan(self, evt=None): dlg = wx.FileDialog(self, message="Load Epics Scan Data File", defaultDir=os.getcwd(), wildcard=FILE_WILDCARDS, style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() path = path.replace('\\', '/') if path in self.filemap: if wx.ID_YES != popup(self, "Re-read file '%s'?" % path, 'Re-read file?'): return gname = randname(n=5) if hasattr(self.datagroups, gname): time.sleep(0.005) gname = randname(n=6) parent, fname = os.path.split(path) self.larch("%s = read_xdi('%s')" % (gname, path)) self.larch("%s.path = '%s'" % (gname, path)) self.filelist.Append(fname) self.filemap[fname] = gname print('Larch:: ', gname, path, fname) self.ShowFile(filename=fname) dlg.Destroy()