class XYFitFrame(wx.Frame): _about = """Larch XYFit: XY Data Viewing & Curve Fitting Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, parent=None, size=(875, 550), _larch=None, **kws): wx.Frame.__init__(self, parent, -1, size=size, style=FRAMESTYLE) self.last_array_sel = {} self.paths2read = [] title = "Larch XYFit: XY Data Viewing & Curve Fitting" self.larch_buffer = parent if not isinstance(parent, LarchFrame): self.larch_buffer = LarchFrame(_larch=_larch) self.larch_buffer.Show() self.larch_buffer.Raise() self.larch=self.larch_buffer.larchshell self.controller = XYFitController(wxparent=self, _larch=self.larch) self.subframes = {} self.plotframe = None self.SetTitle(title) self.SetSize(size) self.SetFont(Font(10)) self.larch_buffer.Hide() 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) def createMainPanel(self): splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(250) leftpanel = wx.Panel(splitter) ltop = wx.Panel(leftpanel) def Btn(msg, x, act): b = Button(ltop, msg, size=(x, 30), action=act) b.SetFont(Font(10)) return b plot_one = Btn('Plot One', 120, self.onPlotOne) plot_sel = Btn('Plot Selected', 120, self.onPlotSel) sel_none = Btn('Select None', 120, self.onSelNone) sel_all = Btn('Select All', 120, self.onSelAll) self.controller.filelist = FileCheckList(leftpanel, main=self, select_action=self.ShowFile, remove_action=self.RemoveFile) self.controller.filelist.SetBackgroundColour(wx.Colour(255, 255, 255)) tsizer = wx.GridBagSizer(1, 1) tsizer.Add(plot_one, (0, 0), (1, 1), LCEN, 2) tsizer.Add(plot_sel, (0, 1), (1, 1), LCEN, 2) tsizer.Add(sel_all, (1, 0), (1, 1), LCEN, 2) tsizer.Add(sel_none, (1, 1), (1, 1), LCEN, 2) pack(ltop, tsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(ltop, 0, LCEN|wx.GROW, 1) sizer.Add(self.controller.filelist, 1, LCEN|wx.GROW|wx.ALL, 1) pack(leftpanel, sizer) # right hand side panel = wx.Panel(splitter) sizer = wx.BoxSizer(wx.VERTICAL) self.title = SimpleText(panel, 'initializing...', size=(300, -1)) self.title.SetFont(Font(10)) ir = 0 sizer.Add(self.title, 0, LCEN|wx.GROW|wx.ALL, 1) self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE) self.nb.SetTabAreaColour(wx.Colour(250,250,250)) self.nb.SetActiveTabColour(wx.Colour(254,254,195)) self.nb.SetNonActiveTabTextColour(wx.Colour(10,10,128)) self.nb.SetActiveTabTextColour(wx.Colour(128,0,0)) panel_opts = dict(parent=self.nb, controller=self.controller) self.proc_panel = ProcessPanel(**panel_opts) self.fit_panel = XYFitPanel(**panel_opts) self.nb.AddPage(self.proc_panel, ' Data Processing ', True) self.nb.AddPage(self.fit_panel, ' Curve Fitting ', True) sizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2) self.nb.SetSelection(0) pack(panel, sizer) splitter.SplitVertically(leftpanel, panel, 1) wx.CallAfter(self.init_larch) def onSelAll(self, event=None): self.controller.filelist.SetCheckedStrings(self.controller.file_groups.keys()) def onSelNone(self, event=None): self.controller.filelist.SetCheckedStrings([]) def init_larch(self): self.SetStatusText('initializing Larch') self.title.SetLabel('') self.fit_panel.larch = self.controller.larch self.controller.init_larch() plotframe = self.controller.get_display(stacked=False) xpos, ypos = self.GetPosition() xsiz, ysiz = self.GetSize() plotframe.SetPosition((xpos+xsiz, ypos)) self.SetStatusText('ready') self.Raise() def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def onPlotOne(self, evt=None, groupname=None): if groupname is None: groupname = self.controller.groupname dgroup = self.controller.get_group(groupname) if dgroup is not None: self.controller.plot_group(groupname=groupname, new=True) def onPlotSel(self, evt=None): newplot = True group_ids = self.controller.filelist.GetCheckedStrings() for checked in group_ids: groupname = self.controller.file_groups[str(checked)] dgroup = self.controller.get_group(groupname) if dgroup is not None: self.controller.plot_group(groupname=groupname, title='', new=newplot, label=dgroup.filename) newplot=False def plot_group(self, groupname=None, title=None, new=True, **kws): self.controller.plot_group(groupname=groupname, title=title, new=new, **kws) self.Raise() def RemoveFile(self, fname=None, **kws): if fname is not None: s = str(fname) if s in self.controller.file_groups: group = self.controller.file_groups.pop(s) def ShowFile(self, evt=None, groupname=None, **kws): filename = None if evt is not None: filename = str(evt.GetString()) if groupname is None and filename is not None: groupname = self.controller.file_groups[filename] if not hasattr(self.larch.symtable, groupname): return dgroup = self.controller.get_group(groupname) self.controller.group = dgroup self.controller.groupname = groupname self.nb.SetSelection(0) self.proc_panel.fill(dgroup) if filename is None: filename = dgroup.filename self.title.SetLabel(filename) def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Open Data File", self.onReadDialog) fmenu.AppendSeparator() MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L', 'Show Larch Programming Buffer', self.onShowLarchBuffer) MenuItem(self, fmenu, "debug wx\tCtrl+I", "", self.showInspectionTool) MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onCloseNicely) self.menubar.Append(fmenu, "&File") omenu = wx.Menu() self.menubar.Append(omenu, "Options") MenuItem(self, omenu, "Configure Data Processing", "Configure Data Processing", self.onConfigDataProcessing) MenuItem(self, omenu, "Configure Data Fitting", "Configure Data Fitting", self.onConfigDataFitting) self.SetMenuBar(self.menubar) self.Bind(wx.EVT_CLOSE, self.onExit) def onShowLarchBuffer(self, evt=None): if self.larch_buffer is None: self.larch_buffer = LarchFrame(_larch=self.larch) self.larch_buffer.Show() self.larch_buffer.Raise() def onConfigDataProcessing(self, event=None): pass def onConfigDataFitting(self, event=None): pass def showInspectionTool(self, event=None): app = wx.GetApp() app.ShowInspectionTool() def onAbout(self,evt): dlg = wx.MessageDialog(self, self._about, "About Larch XYFit", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onExit(self, evt): for nam in dir(self.larch.symtable._plotter): obj = getattr(self.larch.symtable._plotter, nam) time.sleep(0.05) try: obj.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) time.sleep(0.05) del obj if self.larch_buffer is not None: try: self.larch_buffer.Destroy() except: pass self.Destroy() def onCloseNicely(self, evt): dlg = wx.MessageDialog(None, 'Really Quit?', 'Question', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if wx.ID_YES != dlg.ShowModal(): return self.controller.save_config() self.proc_panel.proc_timer.Stop() time.sleep(0.05) self.onExit(evt) def show_subframe(self, name, frameclass, **opts): shown = False if name in self.subframes: try: self.subframes[name].Raise() shown = True except: del self.subframes[name] if not shown: self.subframes[name] = frameclass(self, **opts) def onSelectColumns(self, evt=None): dgroup = self.controller.get_group(self.controller.groupname) self.show_subframe('readfile', ColumnDataFileFrame, group=dgroup.raw, last_array_sel=self.last_array_sel, _larch=self.larch, read_ok_cb=partial(self.onRead_OK, overwrite=True)) def onReadDialog(self, evt=None): dlg = wx.FileDialog(self, message="Read Data File", defaultDir=os.getcwd(), wildcard=FILE_WILDCARDS, style=wx.FD_OPEN|wx.FD_MULTIPLE) self.paths2read = [] if dlg.ShowModal() == wx.ID_OK: self.paths2read = dlg.GetPaths() dlg.Destroy() if len(self.paths2read) < 1: return path = self.paths2read.pop(0) path = path.replace('\\', '/') do_read = True if path in self.controller.file_groups: do_read = (wx.ID_YES == popup(self, "Re-read file '%s'?" % path, 'Re-read file?')) if do_read: self.onRead(path) def onRead(self, path): filedir, filename = os.path.split(path) if self.controller.get_config('chdir_on_fileopen'): os.chdir(filedir) self.controller.set_workdir() # check for athena projects if is_athena_project(path): kwargs = dict(filename=path, _larch = self.controller.larch, read_ok_cb=self.onReadAthenaProject_OK) self.show_subframe('athena_import', AthenaImporter, **kwargs) else: kwargs = dict(filename=path, _larch=self.larch_buffer.larchshell, last_array_sel = self.last_array_sel, read_ok_cb=self.onRead_OK) self.show_subframe('readfile', ColumnDataFileFrame, **kwargs) def onReadAthenaProject_OK(self, path, namelist): """read groups from a list of groups from an athena project file""" self.larch.eval("_prj = read_athena('{path:s}', do_fft=False, do_bkg=False)".format(path=path)) s = """{group:s} = _prj.{group:s} {group:s}.datatype = 'xas' {group:s}.x = {group:s}.xdat = {group:s}.energy {group:s}.y = {group:s}.ydat = {group:s}.mu {group:s}.yerr = 1.0 {group:s}.plot_ylabel = 'mu' {group:s}.plot_xlabel = 'energy' """ for gname in namelist: self.larch.eval(s.format(group=gname)) self.install_group(gname, gname) self.larch.eval("del _prj") def onRead_OK(self, script, path, groupname=None, array_sel=None, overwrite=False): """ called when column data has been selected and is ready to be used overwrite: whether to overwrite the current datagroup, as when editing a datagroup """ abort_read = False filedir, filename = os.path.split(path) if not overwrite and hasattr(self.larch.symtable, groupname): newname = file2groupname(filename, symtable=self.larch.symtable) msg = """Warning: groupname '%s' already used. Will use groupname '%s' instead """ % (groupname, newname) dlg = wx.MessageDialog(self, msg, 'Warning', wx.OK | wx.CANCEL ) abort_read = (wx.ID_OK != dlg.ShowModal()) dlg.Destroy() groupname = newname if abort_read: return self.larch.eval(script.format(group=groupname, path=path)) if array_sel is not None: self.last_array_sel = array_sel self.install_group(groupname, filename) if len(self.paths2read) > 0 : path = self.paths2read.pop(0) path = path.replace('\\', '/') filedir, filename = os.path.split(path) gname = file2groupname(filename, symtable=self.larch.symtable) self.onRead_OK(script, path, groupname=gname) def install_group(self, groupname, filename): """add groupname / filename to list of available data groups""" thisgroup = getattr(self.larch.symtable, groupname) thisgroup.groupname = groupname thisgroup.filename = filename datatype = getattr(thisgroup, 'datatype', 'raw') # file /group may already exist in list if filename in self.controller.file_groups and not overwrite: for i in range(1, 101): ftest = "%s (%i)" % (filename, i) if ftest not in self.controller.file_groups: filename = ftest break if filename not in self.controller.file_groups: self.controller.filelist.Append(filename) self.controller.file_groups[filename] = groupname self.nb.SetSelection(0) self.ShowFile(groupname=groupname)
class ProcessPanel(wx.Panel): def __init__(self, parent, controller=None, reporter=None, **kws): wx.Panel.__init__(self, parent, -1, **kws) self.controller = controller self.reporter = reporter self.needs_update = False self.proc_timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onProcessTimer, self.proc_timer) self.proc_timer.Start(100) self.build_display() def edit_config(self, event=None): pass def fill(self, dgroup): opts = self.controller.get_proc_opts(dgroup) self.xshift.SetValue(opts['xshift']) self.yshift.SetValue(opts['yshift']) self.xscale.SetValue(opts['xscale']) self.yscale.SetValue(opts['yscale']) self.smooth_op.SetStringSelection(opts['smooth_op']) self.smooth_conv.SetStringSelection(opts['smooth_conv']) self.smooth_c0.SetValue(opts['smooth_c0']) self.smooth_c1.SetValue(opts['smooth_c1']) self.smooth_sig.SetValue(opts['smooth_sig']) if dgroup.datatype == 'xas': self.xas_op.SetStringSelection(opts['xas_op']) self.xas_e0.SetValue(opts['e0']) self.xas_step.SetValue(opts['edge_step']) self.xas_pre1.SetValue(opts['pre1']) self.xas_pre2.SetValue(opts['pre2']) self.xas_nor1.SetValue(opts['norm1']) self.xas_nor2.SetValue(opts['norm2']) self.xas_vict.SetSelection(opts['nvict']) self.xas_nnor.SetSelection(opts['nnorm']) self.xas_showe0.SetValue(opts['show_e0']) self.xas_autoe0.SetValue(opts['auto_e0']) self.xas_autostep.SetValue(opts['auto_step']) def build_display(self): self.SetFont(Font(10)) titleopts = dict(font=Font(11), colour='#AA0000') gopts = dict(ncols=4, nrows=4, pad=2, itemstyle=LCEN) xas = self.xaspanel = GridPanel(self, **gopts) gen = self.genpanel = GridPanel(self, **gopts) self.btns = {} #gen opts = dict(action=self.UpdatePlot, size=(65, -1), gformat=True) self.xshift = FloatCtrl(gen, value=0.0, **opts) self.xscale = FloatCtrl(gen, value=1.0, **opts) self.yshift = FloatCtrl(gen, value=0.0, **opts) self.yscale = FloatCtrl(gen, value=1.0, **opts) self.btns['xshift'] = BitmapButton(gen, get_icon('plus'), action=partial(self.on_selpoint, opt='xshift'), tooltip='use last point selected from plot') self.btns['yshift'] = BitmapButton(gen, get_icon('plus'), action=partial(self.on_selpoint, opt='yshift'), tooltip='use last point selected from plot') opts = dict(action=self.onSmoothChoice, size=(30, -1)) sm_row1 = wx.Panel(gen) sm_row2 = wx.Panel(gen) sm_siz1= wx.BoxSizer(wx.HORIZONTAL) sm_siz2= wx.BoxSizer(wx.HORIZONTAL) self.smooth_c0 = FloatCtrl(sm_row1, value=2, precision=0, minval=1, **opts) self.smooth_c1 = FloatCtrl(sm_row1, value=1, precision=0, minval=1, **opts) self.smooth_msg = SimpleText(sm_row1, label=' ', size=(205, -1)) opts['size'] = (65, -1) self.smooth_sig = FloatCtrl(sm_row2, value=1, gformat=True, **opts) opts['size'] = (120, -1) self.smooth_op = Choice(sm_row1, choices=SMOOTH_OPS, **opts) self.smooth_op.SetSelection(0) self.smooth_conv = Choice(sm_row2, choices=CONV_OPS, **opts) self.smooth_c0.Disable() self.smooth_c1.Disable() self.smooth_sig.Disable() self.smooth_conv.SetSelection(0) self.smooth_conv.Disable() sm_siz1.Add(self.smooth_op, 0, LCEN, 1) sm_siz1.Add(SimpleText(sm_row1, ' n= '), 0, LCEN, 1) sm_siz1.Add(self.smooth_c0, 0, LCEN, 1) sm_siz1.Add(SimpleText(sm_row1, ' order= '), 0, LCEN, 1) sm_siz1.Add(self.smooth_c1, 0, LCEN, 1) sm_siz1.Add(self.smooth_msg, 0, LCEN, 1) sm_siz2.Add(SimpleText(sm_row2, ' form= '), 0, LCEN, 1) sm_siz2.Add(self.smooth_conv, 0, LCEN, 1) sm_siz2.Add(SimpleText(sm_row2, ' sigma= '), 0, LCEN, 1) sm_siz2.Add(self.smooth_sig, 0, LCEN, 1) pack(sm_row1, sm_siz1) pack(sm_row2, sm_siz2) gen.Add(SimpleText(gen, ' General Data Processing', **titleopts), dcol=8) gen.Add(SimpleText(gen, ' X shift:'), newrow=True) gen.Add(self.btns['xshift']) gen.Add(self.xshift, dcol=2) gen.Add(SimpleText(gen, ' X scale:')) gen.Add(self.xscale, dcol=2) gen.Add(SimpleText(gen, ' Y shift:'), newrow=True) gen.Add(self.btns['yshift']) gen.Add(self.yshift, dcol=2) gen.Add(SimpleText(gen, ' Y scale:')) gen.Add(self.yscale, dcol=2) gen.Add(SimpleText(gen, ' Smoothing:'), newrow=True) gen.Add(sm_row1, dcol=8) gen.Add(sm_row2, icol=1, dcol=7, newrow=True) gen.pack() #xas opts = {'action': self.UpdatePlot} e0opts_panel = wx.Panel(xas) self.xas_autoe0 = Check(e0opts_panel, default=True, label='auto?', **opts) self.xas_showe0 = Check(e0opts_panel, default=True, label='show?', **opts) sx = wx.BoxSizer(wx.HORIZONTAL) sx.Add(self.xas_autoe0, 0, LCEN, 4) sx.Add(self.xas_showe0, 0, LCEN, 4) pack(e0opts_panel, sx) self.xas_autostep = Check(xas, default=True, label='auto?', **opts) opts['size'] = (250, -1) self.xas_op = Choice(xas, choices=XASOPChoices, **opts) self.xas_op.SetStringSelection('Normalized') for name in ('e0', 'pre1', 'pre2', 'nor1', 'nor2'): bb = BitmapButton(xas, get_icon('plus'), action=partial(self.on_selpoint, opt=name), tooltip='use last point selected from plot') self.btns[name] = bb opts = {'size': (65, -1), 'gformat': True} self.xas_e0 = FloatCtrl(xas, value=0, action=self.onSet_XASE0, **opts) self.xas_step = FloatCtrl(xas, value=0, action=self.onSet_XASStep, **opts) opts['precision'] = 1 opts['action'] = self.UpdatePlot self.xas_pre1 = FloatCtrl(xas, value=-200, **opts) self.xas_pre2 = FloatCtrl(xas, value= -30, **opts) self.xas_nor1 = FloatCtrl(xas, value= 50, **opts) self.xas_nor2 = FloatCtrl(xas, value= -50, **opts) opts = {'size': (50, -1), 'choices': ('0', '1', '2', '3'), 'action': self.UpdatePlot} self.xas_vict = Choice(xas, **opts) self.xas_nnor = Choice(xas, **opts) self.xas_vict.SetSelection(1) self.xas_nnor.SetSelection(1) def CopyBtn(name): return Button(xas, 'Copy', size=(50, 30), action=partial(self.onCopyParam, name)) xas.Add(SimpleText(xas, ' XAS Data Processing', **titleopts), dcol=6) xas.Add(SimpleText(xas, ' Copy to Selected Groups?'), style=RCEN, dcol=3) xas.Add(SimpleText(xas, 'Arrays to Plot: '), newrow=True) xas.Add(self.xas_op, dcol=6) xas.Add((10, 10)) xas.Add(CopyBtn('xas_op'), style=RCEN) xas.Add(SimpleText(xas, 'E0 : '), newrow=True) xas.Add(self.btns['e0']) xas.Add(self.xas_e0) xas.Add(e0opts_panel, dcol=4) xas.Add((10, 1)) xas.Add(CopyBtn('xas_e0'), style=RCEN) xas.Add(SimpleText(xas, 'Edge Step: '), newrow=True) xas.Add((10, 1)) xas.Add(self.xas_step) xas.Add(self.xas_autostep, dcol=3) xas.Add((10, 1)) xas.Add((10, 1)) xas.Add(CopyBtn('xas_step'), style=RCEN) xas.Add(SimpleText(xas, 'Pre-edge range: '), newrow=True) xas.Add(self.btns['pre1']) xas.Add(self.xas_pre1) xas.Add(SimpleText(xas, ':')) xas.Add(self.btns['pre2']) xas.Add(self.xas_pre2) xas.Add(SimpleText(xas, 'Victoreen:')) xas.Add(self.xas_vict) xas.Add(CopyBtn('xas_pre'), style=RCEN) xas.Add(SimpleText(xas, 'Normalization range: '), newrow=True) xas.Add(self.btns['nor1']) xas.Add(self.xas_nor1) xas.Add(SimpleText(xas, ':')) xas.Add(self.btns['nor2']) xas.Add(self.xas_nor2) xas.Add(SimpleText(xas, 'PolyOrder:')) xas.Add(self.xas_nnor) xas.Add(CopyBtn('xas_norm'), style=RCEN) xas.pack() saveconf = Button(self, 'Save as Default Settings', size=(175, 30), action=self.onSaveConfigBtn) hxline = HLine(self, size=(550, 2)) sizer = wx.BoxSizer(wx.VERTICAL) sizer.AddMany([((10, 10), 0, LCEN, 10), (gen, 0, LCEN, 10), ((10, 10), 0, LCEN, 10), (hxline, 0, LCEN, 10), ((10, 10), 0, LCEN, 10), (xas, 0, LCEN, 10), ((10, 10), 0, LCEN, 10), (saveconf, 0, LCEN, 10), ]) xas.Disable() pack(self, sizer) def onSaveConfigBtn(self, evt=None): conf = self.controller.larch.symtable._sys.xyfit data_proc = {} data_proc.update(getattr(conf, 'data_proc', {})) data_proc['xshift'] = self.xshift.GetValue() data_proc['yshift'] = self.yshift.GetValue() data_proc['xscale'] = self.xscale.GetValue() data_proc['yscale'] = self.yscale.GetValue() data_proc['smooth_op'] = str(self.smooth_op.GetStringSelection()) data_proc['smooth_c0'] = int(self.smooth_c0.GetValue()) data_proc['smooth_c1'] = int(self.smooth_c1.GetValue()) data_proc['smooth_sig'] = float(self.smooth_sig.GetValue()) data_proc['smooth_conv'] = str(self.smooth_conv.GetStringSelection()) conf.data_proc = data_proc if self.xaspanel.Enabled: xas_proc = {} xas_proc.update(getattr(conf, 'xas_proc', {})) xas_proc['auto_e0'] = True xas_proc['auto_step'] = True xas_proc['pre1'] = self.xas_pre1.GetValue() xas_proc['pre2'] = self.xas_pre2.GetValue() xas_proc['norm1'] = self.xas_nor1.GetValue() xas_proc['norm2'] = self.xas_nor2.GetValue() xas_proc['nvict'] = self.xas_vict.GetSelection() xas_proc['nnorm'] = self.xas_nnor.GetSelection() xas_proc['show_e0'] = self.xas_showe0.IsChecked() xas_proc['nnorm'] = int(self.xas_nnor.GetSelection()) xas_proc['nvict'] = int(self.xas_vict.GetSelection()) xas_proc['xas_op'] = str(self.xas_op.GetStringSelection()) conf.xas_proc = xas_proc def onCopyParam(self, name=None, event=None): proc_opts = self.controller.group.proc_opts opts = {} name = str(name) if name == 'xas_op': opts['xas_op'] = proc_opts['xas_op'] elif name == 'xas_e0': opts['e0'] = proc_opts['e0'] opts['show_e0'] = proc_opts['show_e0'] opts['auto_e0'] = False elif name == 'xas_step': opts['edge_step'] = proc_opts['edge_step'] opts['auto_step'] = False elif name == 'xas_pre': opts['nvict'] = proc_opts['nvict'] opts['pre1'] = proc_opts['pre1'] opts['pre2'] = proc_opts['pre2'] elif name == 'xas_norm': opts['nnorm'] = proc_opts['nnorm'] opts['norm1'] = proc_opts['norm1'] opts['norm2'] = proc_opts['norm2'] for checked in self.controller.filelist.GetCheckedStrings(): groupname = self.controller.file_groups[str(checked)] grp = self.controller.get_group(groupname) if grp != self.controller.group: grp.proc_opts.update(opts) self.fill(grp) self.process(grp.groupname) def onSmoothChoice(self, evt=None, value=1): try: choice = self.smooth_op.GetStringSelection().lower() conv = self.smooth_conv.GetStringSelection() self.smooth_c0.Disable() self.smooth_c1.Disable() self.smooth_conv.Disable() self.smooth_sig.Disable() self.smooth_msg.SetLabel('') self.smooth_c0.SetMin(1) self.smooth_c0.odd_only = False if choice.startswith('box'): self.smooth_c0.Enable() elif choice.startswith('savi'): self.smooth_c0.Enable() self.smooth_c1.Enable() self.smooth_c0.Enable() self.smooth_c0.odd_only = True c0 = int(self.smooth_c0.GetValue()) c1 = int(self.smooth_c1.GetValue()) x0 = max(c1+1, c0) if x0 % 2 == 0: x0 += 1 self.smooth_c0.SetMin(c1+1) if c0 != x0: self.smooth_c0.SetValue(x0) self.smooth_msg.SetLabel('n must odd and > order+1') elif choice.startswith('conv'): self.smooth_conv.Enable() self.smooth_sig.Enable() self.needs_update = True except AttributeError: pass def onSet_XASE0(self, evt=None, **kws): self.xas_autoe0.SetValue(0) self.needs_update = True def onSet_XASStep(self, evt=None, **kws): self.xas_autostep.SetValue(0) self.needs_update = True def onProcessTimer(self, evt=None): if self.needs_update and self.controller.groupname is not None: self.process(self.controller.groupname) self.controller.plot_group(groupname=self.controller.groupname, new=True) self.needs_update = False def UpdatePlot(self, evt=None, **kws): self.needs_update = True def on_selpoint(self, evt=None, opt='e0'): xval, yval = self.controller.get_cursor() if xval is None: return e0 = self.xas_e0.GetValue() if opt == 'e0': self.xas_e0.SetValue(xval) self.xas_autoe0.SetValue(0) elif opt == 'pre1': self.xas_pre1.SetValue(xval-e0) elif opt == 'pre2': self.xas_pre2.SetValue(xval-e0) elif opt == 'nor1': self.xas_nor1.SetValue(xval-e0) elif opt == 'nor2': self.xas_nor2.SetValue(xval-e0) elif opt == 'xshift': self.xshift.SetValue(xval) elif opt == 'yshift': self.yshift.SetValue(yval) def process(self, gname, **kws): """ handle process (pre-edge/normalize) XAS data from XAS form, overwriting larch group 'x' and 'y' attributes to be plotted """ dgroup = self.controller.get_group(gname) proc_opts = {} proc_opts['xshift'] = self.xshift.GetValue() proc_opts['yshift'] = self.yshift.GetValue() proc_opts['xscale'] = self.xscale.GetValue() proc_opts['yscale'] = self.yscale.GetValue() proc_opts['smooth_op'] = self.smooth_op.GetStringSelection() proc_opts['smooth_c0'] = int(self.smooth_c0.GetValue()) proc_opts['smooth_c1'] = int(self.smooth_c1.GetValue()) proc_opts['smooth_sig'] = float(self.smooth_sig.GetValue()) proc_opts['smooth_conv'] = self.smooth_conv.GetStringSelection() self.xaspanel.Enable(dgroup.datatype.startswith('xas')) if dgroup.datatype.startswith('xas'): proc_opts['datatype'] = 'xas' proc_opts['e0'] = self.xas_e0.GetValue() proc_opts['edge_step'] = self.xas_step.GetValue() proc_opts['pre1'] = self.xas_pre1.GetValue() proc_opts['pre2'] = self.xas_pre2.GetValue() proc_opts['norm1'] = self.xas_nor1.GetValue() proc_opts['norm2'] = self.xas_nor2.GetValue() proc_opts['nvict'] = self.xas_vict.GetSelection() proc_opts['nnorm'] = self.xas_nnor.GetSelection() proc_opts['auto_e0'] = self.xas_autoe0.IsChecked() proc_opts['show_e0'] = self.xas_showe0.IsChecked() proc_opts['auto_step'] = self.xas_autostep.IsChecked() proc_opts['nnorm'] = int(self.xas_nnor.GetSelection()) proc_opts['nvict'] = int(self.xas_vict.GetSelection()) proc_opts['xas_op'] = self.xas_op.GetStringSelection() self.controller.process(dgroup, proc_opts=proc_opts) if dgroup.datatype.startswith('xas'): if self.xas_autoe0.IsChecked(): self.xas_e0.SetValue(dgroup.proc_opts['e0'], act=False) if self.xas_autostep.IsChecked(): self.xas_step.SetValue(dgroup.proc_opts['edge_step'], act=False) self.xas_pre1.SetValue(dgroup.proc_opts['pre1']) self.xas_pre2.SetValue(dgroup.proc_opts['pre2']) self.xas_nor1.SetValue(dgroup.proc_opts['norm1']) self.xas_nor2.SetValue(dgroup.proc_opts['norm2']) dgroup.orig_ylabel = dgroup.plot_ylabel dgroup.plot_ylabel = '$\mu$' dgroup.plot_y2label = None dgroup.plot_xlabel = '$E \,\mathrm{(eV)}$' dgroup.plot_yarrays = [(dgroup.mu, PLOTOPTS_1, dgroup.plot_ylabel)] y4e0 = dgroup.mu out = self.xas_op.GetStringSelection().lower() # raw, pre, norm, flat if out.startswith('raw data + pre'): dgroup.plot_yarrays = [(dgroup.mu, PLOTOPTS_1, '$\mu$'), (dgroup.pre_edge, PLOTOPTS_2, 'pre edge'), (dgroup.post_edge, PLOTOPTS_2, 'post edge')] elif out.startswith('pre'): dgroup.pre_edge_sub = dgroup.norm * dgroup.edge_step dgroup.plot_yarrays = [(dgroup.pre_edge_sub, PLOTOPTS_1, 'pre-edge subtracted $\mu$')] y4e0 = dgroup.pre_edge_sub dgroup.plot_ylabel = 'pre-edge subtracted $\mu$' elif 'norm' in out and 'deriv' in out: dgroup.plot_yarrays = [(dgroup.norm, PLOTOPTS_1, 'normalized $\mu$'), (dgroup.dmude, PLOTOPTS_D, '$d\mu/dE$')] y4e0 = dgroup.norm dgroup.plot_ylabel = 'normalized $\mu$' dgroup.plot_y2label = '$d\mu/dE$' dgroup.y = dgroup.norm elif out.startswith('norm'): dgroup.plot_yarrays = [(dgroup.norm, PLOTOPTS_1, 'normalized $\mu$')] y4e0 = dgroup.norm dgroup.plot_ylabel = 'normalized $\mu$' dgroup.y = dgroup.norm elif out.startswith('deriv'): dgroup.plot_yarrays = [(dgroup.dmude, PLOTOPTS_1, '$d\mu/dE$')] y4e0 = dgroup.dmude dgroup.plot_ylabel = '$d\mu/dE$' dgroup.y = dgroup.dmude dgroup.plot_ymarkers = [] if self.xas_showe0.IsChecked(): ie0 = index_of(dgroup.xdat, dgroup.e0) dgroup.plot_ymarkers = [(dgroup.e0, y4e0[ie0], {'label': '_nolegend_'})]
class ColumnDataFileFrame(wx.Frame): """Column Data File, select columns""" def __init__(self, parent, filename=None, groupname=None, last_array_sel=None, read_ok_cb=None, edit_groupname=True, _larch=None): self.parent = parent self._larch = _larch self.path = filename group = self.initgroup = self.read_column_file(self.path) self.subframes = {} self.workgroup = Group(raw=group) for attr in ('path', 'filename', 'groupname', 'datatype', 'array_labels'): setattr(self.workgroup, attr, getattr(group, attr, None)) arr_labels = [l.lower() for l in self.initgroup.array_labels] if self.workgroup.datatype is None: self.workgroup.datatype = 'raw' if ('energ' in arr_labels[0] or 'energ' in arr_labels[1]): self.workgroup.datatype = 'xas' self.read_ok_cb = read_ok_cb self.array_sel = { 'xpop': '', 'xarr': None, 'ypop': '', 'yop': '/', 'yarr1': None, 'yarr2': None, 'use_deriv': False } if last_array_sel is not None: self.array_sel.update(last_array_sel) if self.array_sel['yarr2'] is None and 'i0' in arr_labels: self.array_sel['yarr2'] = 'i0' if self.array_sel['yarr1'] is None: if 'itrans' in arr_labels: self.array_sel['yarr1'] = 'itrans' elif 'i1' in arr_labels: self.array_sel['yarr1'] = 'i1' message = "Data Columns for %s" % group.filename wx.Frame.__init__(self, None, -1, 'Build Arrays from Data Columns for %s' % group.filename, style=FRAMESTYLE) self.SetFont(Font(10)) panel = wx.Panel(self) self.SetMinSize((600, 600)) self.colors = GUIColors() # title row title = SimpleText(panel, message, font=Font(13), colour=self.colors.title, style=LCEN) opts = dict(action=self.onUpdate, size=(120, -1)) yarr_labels = self.yarr_labels = arr_labels + ['1.0', '0.0', ''] xarr_labels = self.xarr_labels = arr_labels + ['_index'] self.xarr = Choice(panel, choices=xarr_labels, **opts) self.yarr1 = Choice(panel, choices=arr_labels, **opts) self.yarr2 = Choice(panel, choices=yarr_labels, **opts) self.yerr_arr = Choice(panel, choices=yarr_labels, **opts) self.yerr_arr.Disable() self.datatype = Choice(panel, choices=DATATYPES, **opts) self.datatype.SetStringSelection(self.workgroup.datatype) opts['size'] = (50, -1) self.yop = Choice(panel, choices=ARR_OPS, **opts) opts['size'] = (120, -1) self.use_deriv = Check(panel, label='use derivative', default=self.array_sel['use_deriv'], **opts) self.xpop = Choice(panel, choices=XPRE_OPS, **opts) self.ypop = Choice(panel, choices=YPRE_OPS, **opts) opts['action'] = self.onYerrChoice self.yerr_op = Choice(panel, choices=YERR_OPS, **opts) self.yerr_op.SetSelection(0) self.yerr_const = FloatCtrl(panel, value=1, precision=4, size=(90, -1)) ylab = SimpleText(panel, 'Y = ') xlab = SimpleText(panel, 'X = ') yerr_lab = SimpleText(panel, 'Yerror = ') self.xsuf = SimpleText(panel, '') self.ysuf = SimpleText(panel, '') self.xpop.SetStringSelection(self.array_sel['xpop']) self.ypop.SetStringSelection(self.array_sel['ypop']) self.yop.SetStringSelection(self.array_sel['yop']) if '(' in self.array_sel['ypop']: self.ysuf.SetLabel(')') ixsel, iysel, iy2sel = 0, 1, len(yarr_labels) - 1 if self.array_sel['xarr'] in xarr_labels: ixsel = xarr_labels.index(self.array_sel['xarr']) if self.array_sel['yarr1'] in arr_labels: iysel = arr_labels.index(self.array_sel['yarr1']) if self.array_sel['yarr2'] in yarr_labels: iy2sel = yarr_labels.index(self.array_sel['yarr2']) self.xarr.SetSelection(ixsel) self.yarr1.SetSelection(iysel) self.yarr2.SetSelection(iy2sel) bpanel = wx.Panel(panel) bsizer = wx.BoxSizer(wx.HORIZONTAL) _ok = Button(bpanel, 'OK', action=self.onOK) _cancel = Button(bpanel, 'Cancel', action=self.onCancel) _edit = Button(bpanel, 'Edit Array Names', action=self.onEditNames) bsizer.Add(_ok) bsizer.Add(_cancel) bsizer.Add(_edit) _ok.SetDefault() pack(bpanel, bsizer) sizer = wx.GridBagSizer(4, 8) sizer.Add(title, (0, 0), (1, 7), LCEN, 5) ir = 1 sizer.Add(xlab, (ir, 0), (1, 1), LCEN, 0) sizer.Add(self.xpop, (ir, 1), (1, 1), CEN, 0) sizer.Add(self.xarr, (ir, 2), (1, 1), CEN, 0) sizer.Add(self.xsuf, (ir, 3), (1, 1), CEN, 0) ir += 1 sizer.Add(ylab, (ir, 0), (1, 1), LCEN, 0) sizer.Add(self.ypop, (ir, 1), (1, 1), CEN, 0) sizer.Add(self.yarr1, (ir, 2), (1, 1), CEN, 0) sizer.Add(self.yop, (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yarr2, (ir, 4), (1, 1), CEN, 0) sizer.Add(self.ysuf, (ir, 5), (1, 1), CEN, 0) sizer.Add(self.use_deriv, (ir, 6), (1, 1), LCEN, 0) ir += 1 sizer.Add(yerr_lab, (ir, 0), (1, 1), LCEN, 0) sizer.Add(self.yerr_op, (ir, 1), (1, 1), CEN, 0) sizer.Add(self.yerr_arr, (ir, 2), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, 'Value:'), (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yerr_const, (ir, 4), (1, 2), CEN, 0) ir += 1 sizer.Add(SimpleText(panel, 'Data Type:'), (ir, 0), (1, 1), LCEN, 0) sizer.Add(self.datatype, (ir, 1), (1, 2), LCEN, 0) ir += 1 self.wid_groupname = wx.TextCtrl(panel, value=group.groupname, size=(240, -1)) if not edit_groupname: self.wid_groupname.Disable() sizer.Add(SimpleText(panel, 'Group Name:'), (ir, 0), (1, 1), LCEN, 0) sizer.Add(self.wid_groupname, (ir, 1), (1, 2), LCEN, 0) ir += 1 sizer.Add(bpanel, (ir, 0), (1, 5), LCEN, 3) pack(panel, sizer) self.nb = fnb.FlatNotebook(self, -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.plotpanel = PlotPanel(self, messenger=self.plot_messages) textpanel = wx.Panel(self) ftext = wx.TextCtrl(textpanel, style=wx.TE_MULTILINE | wx.TE_READONLY, size=(400, 250)) ftext.SetValue(group.text) ftext.SetFont(Font(10)) textsizer = wx.BoxSizer(wx.VERTICAL) textsizer.Add(ftext, 1, LCEN | wx.GROW, 1) pack(textpanel, textsizer) self.nb.AddPage(textpanel, ' Text of Data File ', True) self.nb.AddPage(self.plotpanel, ' Plot of Selected Arrays ', True) mainsizer = wx.BoxSizer(wx.VERTICAL) mainsizer.Add(panel, 0, wx.GROW | wx.ALL, 2) mainsizer.Add(self.nb, 1, LCEN | wx.GROW, 2) pack(self, mainsizer) self.statusbar = self.CreateStatusBar(2, 0) self.statusbar.SetStatusWidths([-1, -1]) statusbar_fields = [group.filename, ""] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) self.Show() self.Raise() self.onUpdate(self) def read_column_file(self, path): """read column file, generally as initial read""" parent, filename = os.path.split(path) with open(path, 'r') as fh: lines = fh.readlines() text = ''.join(lines) line1 = lines[0].lower() reader = 'read_ascii' if 'epics stepscan file' in line1: reader = 'read_gsexdi' elif 'xdi' in line1: reader = 'read_xdi' elif 'epics scan' in line1: reader = 'read_gsescan' tmpname = '_tmp_file_' read_cmd = "%s = %s('%s')" % (tmpname, reader, path) self.reader = reader deeplarch = self._larch._larch try: deeplarch.eval(read_cmd, add_history=False) except: pass if deeplarch.error: # self._larch.input.clear() msg = ["Error trying to read '%s':" % path, ""] for err in deeplarch.error: exc_name, errmsg = err.get_error() msg.append(errmsg) title = "Cannot read %s" % path r = Popup(self.parent, "\n".join(msg), title) return None group = self._larch.symtable.get_symbol(tmpname) self._larch.symtable.del_symbol(tmpname) group.text = text group.path = path group.filename = filename group.groupname = file2groupname(filename, symtable=self._larch.symtable) return group def show_subframe(self, name, frameclass, **opts): shown = False if name in self.subframes: try: self.subframes[name].Raise() shown = True except: del self.subframes[name] if not shown: self.subframes[name] = frameclass(self, **opts) def onEditNames(self, evt=None): self.show_subframe('editcol', EditColumnFrame, group=self.workgroup, on_ok=self.set_array_labels) def set_array_labels(self, arr_labels): self.workgroup.array_labels = arr_labels yarr_labels = self.yarr_labels = arr_labels + ['1.0', '0.0', ''] xarr_labels = self.xarr_labels = arr_labels + ['_index'] def update(wid, choices): curstr = wid.GetStringSelection() curind = wid.GetSelection() wid.SetChoices(choices) if curstr in choices: wid.SetStringSelection(curstr) else: wid.SetSelection(curind) update(self.xarr, xarr_labels) update(self.yarr1, yarr_labels) update(self.yarr2, yarr_labels) update(self.yerr_arr, yarr_labels) self.onUpdate() def onOK(self, event=None): """ build arrays according to selection """ if self.wid_groupname is not None: groupname = fix_varname(self.wid_groupname.GetValue()) yerr_op = self.yerr_op.GetStringSelection().lower() yerr_expr = '1' if yerr_op.startswith('const'): yerr_expr = "%f" % self.yerr_const.GetValue() elif yerr_op.startswith('array'): yerr_expr = '%%s.data[%i, :]' % self.yerr_arr.GetSelection() elif yerr_op.startswith('sqrt'): yerr_expr = 'sqrt(%s.ydat)' self.expressions['yerr'] = yerr_expr # generate script to pass back to calling program: labels = ', '.join(self.workgroup.array_labels) read_cmd = "%s('{path:s}', labels='%s')" % (self.reader, labels) buff = ["{group:s} = %s" % read_cmd, "{group:s}.path = '{path:s}'"] for attr in ('datatype', 'plot_xlabel', 'plot_ylabel'): val = getattr(self.workgroup, attr) buff.append("{group:s}.%s = '%s'" % (attr, val)) for aname in ('xdat', 'ydat', 'yerr'): expr = self.expressions[aname].replace('%s', '{group:s}') buff.append("{group:s}.%s = %s" % (aname, expr)) if getattr(self.workgroup, 'datatype', 'raw') == 'xas': if self.reader == 'read_gsescan': buff.append("{group:s}.energy = {group:s}.x") else: buff.append("{group:s}.energy = {group:s}.xdat") buff.append("{group:s}.mu = {group:s}.ydat") script = "\n".join(buff) if self.read_ok_cb is not None: self.read_ok_cb(script, self.path, groupname=groupname, array_sel=self.array_sel) self.Destroy() def onCancel(self, event=None): self.workgroup.import_ok = False self.Destroy() def onYerrChoice(self, evt=None): yerr_choice = evt.GetString() self.yerr_arr.Disable() self.yerr_const.Disable() if 'const' in yerr_choice.lower(): self.yerr_const.Enable() elif 'array' in yerr_choice.lower(): self.yerr_arr.Enable() self.onUpdate() def onUpdate(self, value=None, evt=None): """column selections changed calc xdat and ydat""" # dtcorr = self.dtcorr.IsChecked() # print("Column Frame on Update ") dtcorr = False use_deriv = self.use_deriv.IsChecked() rawgroup = self.initgroup workgroup = self.workgroup rdata = self.initgroup.data # print("onUpdate ", dir(rawgroup)) ix = self.xarr.GetSelection() xname = self.xarr.GetStringSelection() exprs = dict(xdat=None, ydat=None, yerr=None) ncol, npts = rdata.shape if xname.startswith('_index') or ix >= ncol: workgroup.xdat = 1.0 * np.arange(npts) xname = '_index' exprs['xdat'] = 'arange(%i)' % npts else: workgroup.xdat = rdata[ix, :] exprs['xdat'] = '%%s.data[%i, : ]' % ix workgroup.datatype = self.datatype.GetStringSelection().strip().lower() def pre_op(opwid, arr): opstr = opwid.GetStringSelection().strip() suf = '' if opstr in ('-log(', 'log('): suf = ')' if opstr == 'log(': arr = np.log(arr) elif opstr == '-log(': arr = -np.log(arr) return suf, opstr, arr try: xsuf, xpop, workgroup.xdat = pre_op(self.xpop, workgroup.xdat) self.xsuf.SetLabel(xsuf) exprs['xdat'] = '%s%s%s' % (xpop, exprs['xdat'], xsuf) except: return try: xunits = rawgroup.array_units[ix].strip() xlabel = '%s (%s)' % (xname, xunits) except: xlabel = xname yname1 = self.yarr1.GetStringSelection().strip() yname2 = self.yarr2.GetStringSelection().strip() iy1 = self.yarr1.GetSelection() iy2 = self.yarr2.GetSelection() yop = self.yop.GetStringSelection().strip() ylabel = yname1 if len(yname2) == 0: yname2 = '1.0' else: ylabel = "%s%s%s" % (ylabel, yop, yname2) if yname1 == '0.0': yarr1 = np.zeros(npts) * 1.0 yexpr1 = 'zeros(%i)' % npts elif len(yname1) == 0 or yname1 == '1.0' or iy1 >= ncol: yarr1 = np.ones(npts) * 1.0 yexpr1 = 'ones(%i)' % npts else: yarr1 = rdata[iy1, :] yexpr1 = '%%s.data[%i, : ]' % iy1 if yname2 == '0.0': yarr2 = np.zeros(npts) * 1.0 yexpr2 = '0.0' elif len(yname2) == 0 or yname2 == '1.0' or iy2 >= ncol: yarr2 = np.ones(npts) * 1.0 yexpr2 = '1.0' else: yarr2 = rdata[iy2, :] yexpr2 = '%%s.data[%i, : ]' % iy2 workgroup.ydat = yarr1 exprs['ydat'] = yexpr1 if yop in ('+', '-', '*', '/'): exprs['ydat'] = "%s %s %s" % (yexpr1, yop, yexpr2) if yop == '+': workgroup.ydat = yarr1.__add__(yarr2) elif yop == '-': workgroup.ydat = yarr1.__sub__(yarr2) elif yop == '*': workgroup.ydat = yarr1.__mul__(yarr2) elif yop == '/': workgroup.ydat = yarr1.__truediv__(yarr2) ysuf, ypop, workgroup.ydat = pre_op(self.ypop, workgroup.ydat) self.ysuf.SetLabel(ysuf) exprs['ydat'] = '%s%s%s' % (ypop, exprs['ydat'], ysuf) yerr_op = self.yerr_op.GetStringSelection().lower() exprs['yerr'] = '1' if yerr_op.startswith('const'): yerr = self.yerr_const.GetValue() exprs['yerr'] = '%f' % yerr elif yerr_op.startswith('array'): iyerr = self.yerr_arr.GetSelection() yerr = rdata[iyerr, :] exprs['yerr'] = '%%s.data[%i, :]' % iyerr elif yerr_op.startswith('sqrt'): yerr = np.sqrt(workgroup.ydat) exprs['yerr'] = 'sqrt(%s.ydat)' if use_deriv: try: workgroup.ydat = (np.gradient(workgroup.ydat) / np.gradient(workgroup.xdat)) exprs['ydat'] = 'deriv(%s)/deriv(%s)' % (exprs['ydat'], exprs['xdat']) except: pass self.expressions = exprs self.array_sel = { 'xpop': xpop, 'xarr': xname, 'ypop': ypop, 'yop': yop, 'yarr1': yname1, 'yarr2': yname2, 'use_deriv': use_deriv } try: npts = min(len(workgroup.xdat), len(workgroup.ydat)) except AttributeError: return workgroup.filename = rawgroup.filename workgroup.npts = npts workgroup.plot_xlabel = xlabel workgroup.plot_ylabel = ylabel workgroup.xdat = np.array(workgroup.xdat[:npts]) workgroup.ydat = np.array(workgroup.ydat[:npts]) workgroup.y = workgroup.ydat workgroup.yerr = yerr if isinstance(yerr, np.ndarray): workgroup.yerr = np.array(yerr[:npts]) if workgroup.datatype == 'xas': workgroup.energy = workgroup.xdat workgroup.mu = workgroup.ydat path, fname = os.path.split(workgroup.filename) popts = dict(marker='o', markersize=4, linewidth=1.5, title=fname, ylabel=ylabel, xlabel=xlabel, label="%s: %s" % (fname, workgroup.plot_ylabel)) self.plotpanel.plot(workgroup.xdat, workgroup.ydat, **popts) for i in range(self.nb.GetPageCount()): if 'plot' in self.nb.GetPageText(i).lower(): self.nb.SetSelection(i) def plot_messages(self, msg, panel=1): self.SetStatusText(msg, panel)
class ScanViewerFrame(wx.Frame): _about = """Scan 2D Plotter Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, _larch=None, **kws): wx.Frame.__init__(self, None, -1, style=FRAMESTYLE) self.file_groups = {} self.file_paths = [] title = "Column Data File Viewer" self.larch = _larch self.larch_buffer = None self.subframes = {} self.plotframe = None self.groupname = None self.SetTitle(title) self.SetSize((850, 650)) self.SetFont(Font(10)) self.config = {'chdir_on_fileopen': True} 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) read_workdir('scanviewer.dat') def createMainPanel(self): splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(225) 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 = Choice(panel, choices=[], action=self.onColumnChoices, size=(120, -1)) self.xop = Choice(panel, choices=('', 'log'), action=self.onColumnChoices, size=(90, -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 = [] opts = { 'choices': [], 'size': (120, -1), 'action': self.onColumnChoices } for i in range(3): self.yarr.append(Choice(panel, **opts)) for opts, sel, siz in ((PRE_OPS, 0, 90), (ARR_OPS, 3, 50), (ARR_OPS, 3, 50)): w1 = Choice(panel, choices=opts, action=self.onColumnChoices, size=(siz, -1)) w1.SetSelection(sel) self.yops.append(w1) ir += 1 label = 'Y = ' sizer.Add(SimpleText(panel, label), (ir, 0), (1, 1), CEN, 0) sizer.Add(self.yops[0], (ir, 1), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, '[('), (ir, 2), (1, 1), CEN, 0) sizer.Add(self.yarr[0], (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yops[1], (ir, 4), (1, 1), CEN, 0) sizer.Add(self.yarr[1], (ir, 5), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ')'), (ir, 6), (1, 1), LCEN, 0) ir += 1 sizer.Add(self.yops[2], (ir, 4), (1, 1), CEN, 0) sizer.Add(self.yarr[2], (ir, 5), (1, 1), CEN, 0) sizer.Add(SimpleText(panel, ']'), (ir, 6), (1, 1), LCEN, 0) self.use_deriv = Check(panel, default=False, label='Use Derivative?', action=self.onColumnChoices) self.dtcorr = Check(panel, default=True, label='correct deadtime?', action=self.onColumnChoices) ir += 1 sizer.Add(self.use_deriv, (ir, 0), (1, 3), LCEN, 0) sizer.Add(self.dtcorr, (ir, 3), (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) btnbox = wx.Panel(mainpanel) btnsizer = wx.BoxSizer(wx.HORIZONTAL) for ttl, opt in (('New Plot', 'new'), ('Over Plot (left)', 'left'), ('Over Plot (right)', 'right')): btnsizer.Add( Button(btnbox, ttl, size=(135, -1), action=partial(self.onPlot, opt=opt)), LCEN, 1) pack(btnbox, btnsizer) mainsizer.Add(btnbox, 0, LCEN, 2) mainsizer.Add(self.nb, 1, LCEN | wx.EXPAND, 2) pack(mainpanel, mainsizer) return mainpanel def CreateFitPanel(self, parent): panel = wx.Panel(parent) tpan = wx.Panel(panel) self.fit_model = Choice(tpan, size=(100, -1), choices=('Gaussian', 'Lorentzian', 'Voigt', 'Linear', 'Quadratic', 'Step', 'Rectangle', 'Exponential')) self.fit_bkg = Choice(tpan, size=(100, -1), choices=('None', 'constant', 'linear', 'quadratic')) self.fit_step = Choice(tpan, size=(100, -1), choices=('linear', 'error function', 'arctan')) tsizer = wx.GridBagSizer(10, 4) tsizer.Add(SimpleText(tpan, 'Fit Model: '), (0, 0), (1, 1), LCEN) tsizer.Add(self.fit_model, (0, 1), (1, 1), LCEN) tsizer.Add(SimpleText(tpan, 'Background: '), (0, 2), (1, 1), LCEN) tsizer.Add(self.fit_bkg, (0, 3), (1, 1), LCEN) tsizer.Add( Button(tpan, 'Show Fit', size=(100, -1), action=self.onFitPeak), (1, 1), (1, 1), LCEN) tsizer.Add(SimpleText(tpan, 'Step Form: '), (1, 2), (1, 1), LCEN) tsizer.Add(self.fit_step, (1, 3), (1, 1), LCEN) pack(tpan, tsizer) self.fit_report = RichTextCtrl(panel, size=(525, 250), style=wx.VSCROLL | wx.NO_BORDER) self.fit_report.SetEditable(False) self.fit_report.SetFont(Font(9)) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(tpan, 0, wx.GROW | wx.ALL, 2) sizer.Add(self.fit_report, 1, LCEN | wx.GROW, 2) pack(panel, sizer) return panel def InitializeXASPanel(self): if self.groupname is None: lgroup = None lgroup = getattr(self.larch.symtable, self.groupname) self.xas_e0.SetValue(getattr(lgroup, 'e0', 0)) self.xas_step.SetValue(getattr(lgroup, 'edge_step', 0)) self.xas_pre1.SetValue(getattr(lgroup, 'pre1', -200)) self.xas_pre2.SetValue(getattr(lgroup, 'pre2', -30)) self.xas_nor1.SetValue(getattr(lgroup, 'norm1', 50)) self.xas_nor2.SetValue(getattr(lgroup, 'norm2', -10)) self.xas_vict.SetSelection(getattr(lgroup, 'nvict', 1)) self.xas_nnor.SetSelection(getattr(lgroup, 'nnorm', 2)) def CreateXASPanel(self, parent): p = panel = wx.Panel(parent) self.xas_autoe0 = Check(panel, default=True, label='auto?') self.xas_showe0 = Check(panel, default=True, label='show?') self.xas_autostep = Check(panel, default=True, label='auto?') self.xas_op = Choice( panel, size=(225, -1), choices=('Raw Data', 'Normalized', 'Derivative', 'Normalized + Derivative', 'Pre-edge subtracted', 'Raw Data With Pre-edge/Post-edge Curves'), action=self.onXASChoice) opts = { 'size': (95, -1), 'precision': 3 } # , 'action': self.onXASChoice} self.xas_e0 = FloatCtrl(panel, value=0, **opts) self.xas_step = FloatCtrl(panel, value=0, **opts) opts['precision'] = 1 self.xas_pre1 = FloatCtrl(panel, value=-200, **opts) self.xas_pre2 = FloatCtrl(panel, value=-30, **opts) self.xas_nor1 = FloatCtrl(panel, value=50, **opts) self.xas_nor2 = FloatCtrl(panel, value=-50, **opts) opts = { 'size': (50, -1), 'choices': ('0', '1', '2', '3'), 'action': self.onXASChoice } self.xas_vict = Choice(panel, **opts) self.xas_nnor = Choice(panel, **opts) 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, 3), 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_showe0, (1, 4), (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 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) try: lgroup = getattr(self.larch.symtable, gname) x = lgroup._xdat_ y = lgroup._ydat_ except AttributeError: self.write_message('need data to fit!') return if step.startswith('error'): step = 'erf' elif step.startswith('arctan'): step = 'atan' pgroup = fit_peak(x, y, model, background=bkg, step=step, _larch=self.larch) dtext = '\n'.join(dtext) dtext = '%s\n%s\n' % ( dtext, fit_report( pgroup.params, min_correl=0.25, _larch=self.larch)) self.fit_report.SetEditable(True) self.fit_report.SetValue(dtext) self.fit_report.SetEditable(False) popts1 = dict(style='solid', linewidth=3, marker='None', markersize=4) popts2 = dict(style='short dashed', linewidth=2, marker='None', markersize=4) lgroup.plot_yarrays = [(lgroup._ydat_, popts1, lgroup.plot_ylabel)] if bkg is None: lgroup._fit = pgroup.fit[:] lgroup.plot_yarrays.append((lgroup._fit, popts2, 'fit')) else: lgroup._fit = pgroup.fit[:] lgroup._fit_bgr = pgroup.bkg[:] lgroup.plot_yarrays.append((lgroup._fit, popts2, 'fit')) lgroup.plot_yarrays.append((lgroup._fit_bgr, popts2, 'background')) self.onPlot() def xas_process(self, gname, new_mu=False, **kws): """ 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 preopts = {'group': gname, 'e0': None} lgroup = getattr(self.larch.symtable, gname) dtcorr = self.dtcorr.IsChecked() if new_mu: try: del lgroup.e0, lgroup.edge_step except: pass if not self.xas_autoe0.IsChecked(): e0 = self.xas_e0.GetValue() if e0 < max(lgroup._xdat_) and e0 > min(lgroup._xdat_): preopts['e0'] = e0 if not self.xas_autostep.IsChecked(): preopts['step'] = self.xas_step.GetValue() dt = debugtime() 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['nvict'] = self.xas_vict.GetSelection() preopts['nnorm'] = self.xas_nnor.GetSelection() preopts['make_flat'] = 'False' preopts['group'] = gname preopts = ", ".join(["%s=%s" % (k, v) for k, v in preopts.items()]) preedge_cmd = "pre_edge(%s._xdat_, %s._ydat_, %s)" self.larch(preedge_cmd % (gname, gname, preopts)) if self.xas_autoe0.IsChecked(): self.xas_e0.SetValue(lgroup.e0) if self.xas_autostep.IsChecked(): self.xas_step.SetValue(lgroup.edge_step) details_group = lgroup try: details_group = lgroup.pre_edge_details except: pass self.xas_pre1.SetValue(details_group.pre1) self.xas_pre2.SetValue(details_group.pre2) self.xas_nor1.SetValue(details_group.norm1) self.xas_nor2.SetValue(details_group.norm2) popts1 = dict(style='solid', linewidth=3, marker='None', markersize=4) popts2 = dict(style='short dashed', linewidth=2, zorder=-5, marker='None', markersize=4) poptsd = dict(style='solid', linewidth=2, zorder=-5, side='right', y2label='derivative', marker='None', markersize=4) lgroup.plot_yarrays = [(lgroup._ydat_, popts1, lgroup.plot_ylabel)] y4e0 = lgroup._ydat_ if out.startswith('raw data with'): lgroup.plot_yarrays = [(lgroup._ydat_, popts1, lgroup.plot_ylabel), (lgroup.pre_edge, popts2, 'pre edge'), (lgroup.post_edge, popts2, 'post edge')] elif out.startswith('pre'): self.larch('%s.pre_edge_sub = %s.norm * %s.edge_step' % (gname, gname, gname)) lgroup.plot_yarrays = [(lgroup.pre_edge_sub, popts1, 'pre edge subtracted XAFS')] y4e0 = lgroup.pre_edge_sub elif 'norm' in out and 'deriv' in out: lgroup.plot_yarrays = [(lgroup.norm, popts1, 'normalized XAFS'), (lgroup.dmude, poptsd, 'derivative')] y4e0 = lgroup.norm elif out.startswith('norm'): lgroup.plot_yarrays = [(lgroup.norm, popts1, 'normalized XAFS')] y4e0 = lgroup.norm elif out.startswith('deriv'): lgroup.plot_yarrays = [(lgroup.dmude, popts1, 'derivative')] y4e0 = lgroup.dmude lgroup.plot_ymarkers = [] if self.xas_showe0.IsChecked(): ie0 = index_of(lgroup._xdat_, lgroup.e0) lgroup.plot_ymarkers = [(lgroup.e0, y4e0[ie0], {'label': 'e0'})] return def init_larch(self): t0 = time.time() if self.larch is None: self.larch = Interpreter() self.larch.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp()) self.larch.symtable.set_symbol('_sys.wx.parent', self) 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_data(self, group, arrayname, correct=False): if hasattr(group, 'get_data'): return group.get_data(arrayname, correct=correct) return getattr(group, arrayname, None) def onXASChoice(self, evt=None, **kws): if self.groupname is None: return self.xas_process(self.groupname, **kws) self.onPlot() def onColumnChoices(self, evt=None): """column selections changed .. recalculate _xdat_ and _ydat_ arrays for this larch group""" dtcorr = self.dtcorr.IsChecked() use_deriv = self.use_deriv.IsChecked() ix = self.xarr.GetSelection() x = self.xarr.GetStringSelection() xop = self.xop.GetStringSelection() op1 = self.yops[0].GetStringSelection() op2 = self.yops[1].GetStringSelection() op3 = self.yops[2].GetStringSelection() y1 = self.yarr[0].GetStringSelection() y2 = self.yarr[1].GetStringSelection() y3 = self.yarr[2].GetStringSelection() array_sel = { 'xop': xop, 'xarr': x, 'op1': op1, 'op2': op2, 'op3': op3, 'y1': y1, 'y2': y2, 'y3': y3, 'dtcorr': dtcorr, 'use_deriv': use_deriv } try: gname = self.groupname lgroup = getattr(self.larch.symtable, gname) except: gname = SCANGROUP lgroup = getattr(self.larch.symtable, gname) xlabel = x try: xunits = lgroup.array_units[ix] except: xunits = '' if xop != '': xlabel = "%s(%s)" % (xop, xlabel) if xunits != '': xlabel = '%s (%s)' % (xlabel, xunits) ylabel = y1 if y2 == '': y2, op2 = '1.0', '*' else: ylabel = "%s%s%s" % (ylabel, op2, y2) if y3 == '': y3, op3 = '1.0', '*' else: ylabel = "(%s)%s%s" % (ylabel, op3, y3) if op1 != '': ylabel = "%s(%s)" % (op1, ylabel) if y1 in ('0.0', '1.0'): y1 = float(yl1) else: y1 = self.get_data(lgroup, y1, correct=dtcorr) if y2 in ('0.0', '1.0'): y2 = float(y2) if op2 == '/': y2 = 1.0 else: y2 = self.get_data(lgroup, y2, correct=dtcorr) if y3 in ('0.0', '1.0'): y3 = float(y3) if op3 == '/': y3 = 1.0 else: y3 = self.get_data(lgroup, y3, correct=dtcorr) if x not in ('0', '1'): x = self.get_data(lgroup, x) lgroup._x = x lgroup._y1 = y1 lgroup._y2 = y2 lgroup._y3 = y3 self.larch("%s._xdat_ = %s(%s._x)" % (gname, xop, gname)) try: yexpr = "%s._ydat_ = %s((%s._y1 %s %s._y2) %s %s._y3)" % ( gname, op1, gname, op2, gname, op3, gname) self.larch(yexpr) except RuntimeWarning: self.larch("%s._ydat_ = %s._y1") try: if use_deriv: d_calc = "%s._ydat_ = gradient(%s._ydat_)/gradient(%s._xdat_)" self.larch(d_calc % (gname, gname, gname)) except: pass try: npts = min(len(lgroup._xdat_), len(lgroup._ydat_)) except AttributeError: print('Error calculating arrays (npts not correct)') return del lgroup._x, lgroup._y1, lgroup._y2, lgroup._y3 lgroup.array_sel = array_sel lgroup.plot_xlabel = xlabel lgroup.plot_ylabel = ylabel lgroup._xdat_ = np.array(lgroup._xdat_[:npts]) lgroup._ydat_ = np.array(lgroup._ydat_[:npts]) if (self.nb.GetCurrentPage() == self.xas_panel): self.xas_process(self.groupname, new_mu=True) else: lgroup.plot_yarrays = [(lgroup._ydat_, {}, None)] def onPlot(self, evt=None, opt='new', npts=None, reprocess=False): try: self.plotframe.Show() except: # wx.PyDeadObjectError self.plotframe = PlotFrame(None, size=(650, 400)) self.plotframe.Show() self.plotpanel = self.plotframe.panel if reprocess: if (self.nb.GetCurrentPage() == self.xas_panel): self.xas_process(self.groupname, new_mu=True) side = 'left' update = False plotcmd = self.plotpanel.plot if opt in ('left', 'right'): side = opt plotcmd = self.plotpanel.oplot elif opt == 'update' and npts > 4: plotcmd = self.plotpanel.update_line update = True if 'new' in opt: self.plotpanel.clear() popts = {'side': side} try: gname = self.groupname lgroup = getattr(self.larch.symtable, gname) except: gname = SCANGROUP lgroup = getattr(self.larch.symtable, gname) return if not hasattr(lgroup, '_xdat_'): self.onColumnChoices() lgroup._xdat_ = np.array(lgroup._xdat_[:npts]) plot_yarrays = [(lgroup._ydat_, {}, None)] if hasattr(lgroup, 'plot_yarrays'): plot_yarrays = lgroup.plot_yarrays #for yarr in plot_yarrays: # yarr = np.array(yarr[:npts]) path, fname = os.path.split(lgroup.filename) popts['label'] = "%s: %s" % (fname, lgroup.plot_ylabel) if side == 'right': popts['y2label'] = lgroup.plot_ylabel else: popts['ylabel'] = lgroup.plot_ylabel if plotcmd == self.plotpanel.plot: popts['title'] = fname if update: self.plotpanel.set_xlabel(lgroup.plot_xlabel) self.plotpanel.set_ylabel(lgroup.plot_ylabel) for itrace, yarr, label in enumerate(plot_yarrays): plotcmd(itrace, lgroup._xdat_, yarr[0], draw=True, update_limits=((npts < 5) or (npts % 5 == 0)), **yarr[1]) self.plotpanel.set_xylims( (min(lgroup._xdat_), max(lgroup._xdat_), min(yarr), max(yarr))) else: for yarr in plot_yarrays: popts.update(yarr[1]) if yarr[2] is not None: popts['label'] = yarr[2] plotcmd(lgroup._xdat_, yarr[0], **popts) plotcmd = self.plotpanel.oplot if hasattr(lgroup, 'plot_ymarkers'): for x, y, opts in lgroup.plot_ymarkers: popts = {'marker': 'o', 'markersize': 4} popts.update(opts) self.plotpanel.oplot([x], [y], **popts) self.plotpanel.canvas.draw() def onShowLarchBuffer(self, evt=None): if self.larch_buffer is None: self.larch_buffer = larchframe.LarchFrame(_larch=self.larch) self.larch_buffer.Show() self.larch_buffer.Raise() def ShowFile(self, evt=None, groupname=None, **kws): if groupname is None and evt is not None: fpath = self.file_paths[evt.GetInt()] groupname = self.file_groups[fpath] if not hasattr(self.datagroups, groupname): print('Error reading file ', groupname) return self.groupname = groupname self.lgroup = getattr(self.datagroups, groupname, None) if groupname == SCANGROUP: self.lgroup.filename = filename elif self.lgroup is not None: if hasattr(self.lgroup, 'array_labels'): array_labels = self.lgroup.array_labels[:] elif hasattr(self.lgroup, 'column_labels'): array_labels = self.lgroup.column_labels[:] else: array_labels = [] for attr in dir(self.lgroup): if isinstance(getattr(self.lgroup, attr), np.ndarray): array_labels.append(attr) self.lgroup.array_labels = array_labels self.set_array_labels() if hasattr(self.lgroup, 'array_sel'): sel = self.lgroup.array_sel try: self.xarr.SetStringSelection(sel['xarr']) self.xop.SetStringSelection(sel['xop']) self.yops[0].SetStringSelection(sel['op1']) self.yops[1].SetStringSelection(sel['op2']) self.yops[2].SetStringSelection(sel['op3']) self.yarr[0].SetStringSelection(sel['y1']) self.yarr[1].SetStringSelection(sel['y2']) self.yarr[2].SetStringSelection(sel['y3']) self.dtcorr.SetValue({True: 1, False: 0}[sel['dtcorr']]) self.use_deriv.SetValue({ True: 1, False: 0 }[sel['use_deriv']]) except: pass def set_array_labels(self, labels=None): """set choices for array dropdowns from array labels""" array_labels = self.lgroup.array_labels xcols = array_labels[:] ycols = array_labels[:] y2cols = array_labels[:] + ['1.0', '0.0', ''] ncols = len(xcols) self.title.SetLabel(self.lgroup.filename) _xarr = self.xarr.GetStringSelection() if len(_xarr) < 1 or _xarr not in xcols: _xarr = xcols[0] _yarr = [[], [], []] for j in range(3): _yarr[j] = self.yarr[j].GetStringSelection() if _yarr[j] not in ycols: _yarr[j] = '' self.xarr.SetItems(xcols) self.xarr.SetStringSelection(_xarr) for j in range(3): if j == 0: self.yarr[j].SetItems(ycols) if _yarr[j] in ycols and len(_yarr[j]) > 0: self.yarr[j].SetStringSelection(_yarr[j]) elif ycols[0] == _xarr and len(ycols) > 1: self.yarr[j].SetStringSelection(ycols[1]) else: self.yarr[j].SetItems(y2cols) self.yarr[j].SetStringSelection(_yarr[j]) inb = 0 for colname in xcols: if 'energ' in colname.lower(): inb = 1 self.nb.SetSelection(inb) if inb == 1: self.InitializeXASPanel() def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Read Scan File", self.onReadScan) MenuItem(self, fmenu, "Show Larch Buffer", "Show Larch Programming Buffer", self.onShowLarchBuffer) fmenu.AppendSeparator() MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) self.menubar.Append(fmenu, "&File") omenu = wx.Menu() MenuItem(self, omenu, "Edit Column Labels\tCtrl+E", "Edit Column Labels", self.onEditColumnLabels) self.menubar.Append(omenu, "Options") # fmenu.AppendSeparator() # MenuItem(self, fmenu, "&Copy\tCtrl+C", # "Copy Figure to Clipboard", self.onClipboard) # MenuItem(self, fmenu, "&Save\tCtrl+S", "Save Figure", self.onSaveFig) # MenuItem(self, fmenu, "&Print\tCtrl+P", "Print Figure", self.onPrint) # MenuItem(self, fmenu, "Page Setup", "Print Page Setup", self.onPrintSetup) # MenuItem(self, fmenu, "Preview", "Print Preview", self.onPrintPreview) # #MenuItem(self, pmenu, "Unzoom\tCtrl+Z", "Unzoom Plot", self.onUnzoom) ##pmenu.AppendSeparator() #MenuItem(self, pmenu, "Toggle Legend\tCtrl+L", # "Toggle Legend on Plot", self.onToggleLegend) #MenuItem(self, pmenu, "Toggle Grid\tCtrl+G", # "Toggle Grid on Plot", self.onToggleGrid) # self.menubar.Append(pmenu, "Plot Options") self.SetMenuBar(self.menubar) self.Bind(wx.EVT_CLOSE, self.onClose) 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): save_workdir('scanviewer.dat') try: self.plotframe.Destroy() except: pass if self.larch_buffer is not None: try: self.larch_buffer.onClose() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) del obj self.Destroy() def show_subframe(self, name, frameclass): shown = False if name in self.subframes: try: self.subframes[name].Raise() shown = True except: del self.subframes[name] if not shown: self.subframes[name] = frameclass(self) def onEditColumnLabels(self, evt=None): self.show_subframe('coledit', EditColumnFrame) def onReadScan(self, evt=None): dlg = wx.FileDialog(self, message="Load Column 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.file_groups: if wx.ID_YES != popup(self, "Re-read file '%s'?" % path, 'Re-read file?'): return gname = '_sview0001' count, maxcount = 1, 9999 while hasattr(self.datagroups, gname) and count < maxcount: count += 1 gname = '_sview%4.4i' % count if hasattr(self.datagroups, gname): gname = randname() parent, fname = os.path.split(path) if self.config['chdir_on_fileopen']: os.chdir(parent) fh = open(path, 'r') line1 = fh.readline().lower() fh.close() reader = 'read_ascii' if 'epics scan' in line1: reader = 'read_gsescan' elif 'xdi' in line1: reader = 'read_xdi' if 'epics stepscan file' in line1: reader = 'read_gsexdi' self.larch("%s = %s('%s')" % (gname, reader, path)) self.larch("%s.path = '%s'" % (gname, path)) self.filelist.Append(fname) self.file_paths.append(path) self.file_groups[path] = gname self.ShowFile(groupname=gname) dlg.Destroy()
class XYFitFrame(wx.Frame): _about = """Larch XYFit: XY Data Viewing & Curve Fitting Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, parent=None, size=(875, 550), _larch=None, **kws): wx.Frame.__init__(self, parent, -1, size=size, style=FRAMESTYLE) self.last_array_sel = {} title = "Larch XYFit (BETA!!): XY Data Viewing & Curve Fitting" self.larch_buffer = parent if not isinstance(parent, LarchFrame): self.larch_buffer = LarchFrame(_larch=_larch) self.larch_buffer.Show() self.larch_buffer.Raise() self.larch = self.larch_buffer._larch self.controller = XYFitController(wxparent=self, _larch=self.larch_buffer.larchshell) self.subframes = {} self.plotframe = None self.SetTitle(title) self.SetSize(size) self.SetFont(Font(10)) self.config = {'chdir_on_fileopen': True} 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) read_workdir('xyfit.dat') self.larch_buffer.Hide() def createMainPanel(self): splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(250) leftpanel = wx.Panel(splitter) ltop = wx.Panel(leftpanel) def Btn(msg, x, act): b = Button(ltop, msg, size=(x, 30), action=act) b.SetFont(Font(10)) return b plot_one = Btn('Plot One', 120, self.onPlotOne) plot_sel = Btn('Plot Selected', 120, self.onPlotSel) sel_none = Btn('Select None', 120, self.onSelNone) sel_all = Btn('Select All', 120, self.onSelAll) self.controller.filelist = FileCheckList(leftpanel, main=self, select_action=self.ShowFile) self.controller.filelist.SetBackgroundColour(wx.Colour(255, 255, 255)) tsizer = wx.GridBagSizer(1, 1) tsizer.Add(plot_one, (0, 0), (1, 1), LCEN, 2) tsizer.Add(plot_sel, (0, 1), (1, 1), LCEN, 2) tsizer.Add(sel_all, (1, 0), (1, 1), LCEN, 2) tsizer.Add(sel_none, (1, 1), (1, 1), LCEN, 2) pack(ltop, tsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(ltop, 0, LCEN | wx.GROW, 1) sizer.Add(self.controller.filelist, 1, LCEN | wx.GROW | wx.ALL, 1) pack(leftpanel, sizer) # right hand side panel = wx.Panel(splitter) sizer = wx.BoxSizer(wx.VERTICAL) self.title = SimpleText(panel, 'initializing...', size=(300, -1)) self.title.SetFont(Font(10)) ir = 0 sizer.Add(self.title, 0, LCEN | wx.GROW | wx.ALL, 1) self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE) self.nb.SetTabAreaColour(wx.Colour(250, 250, 250)) self.nb.SetActiveTabColour(wx.Colour(254, 254, 195)) self.nb.SetNonActiveTabTextColour(wx.Colour(10, 10, 128)) self.nb.SetActiveTabTextColour(wx.Colour(128, 0, 0)) panel_opts = dict(parent=self.nb, controller=self.controller) self.proc_panel = ProcessPanel(**panel_opts) self.fit_panel = XYFitPanel(**panel_opts) self.nb.AddPage(self.proc_panel, ' Data Processing ', True) self.nb.AddPage(self.fit_panel, ' Curve Fitting ', True) sizer.Add(self.nb, 1, LCEN | wx.EXPAND, 2) self.nb.SetSelection(0) pack(panel, sizer) splitter.SplitVertically(leftpanel, panel, 1) wx.CallAfter(self.init_larch) def onSelAll(self, event=None): self.controller.filelist.SetCheckedStrings( self.controller.file_groups.keys()) def onSelNone(self, event=None): self.controller.filelist.SetCheckedStrings([]) def init_larch(self): self.SetStatusText('ready') self.title.SetLabel('') self.fit_panel.larch = self.controller.larch fico = self.controller.get_iconfile() plotframe = self.controller.get_display(stacked=False) xpos, ypos = self.GetPosition() xsiz, ysiz = self.GetSize() plotframe.SetPosition((xpos + xsiz, ypos)) self.Raise() def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def onPlotOne(self, evt=None, groupname=None): if groupname is None: groupname = self.controller.groupname dgroup = self.controller.get_group(groupname) if dgroup is not None: self.controller.plot_group(groupname=groupname, new=True) def onPlotSel(self, evt=None): newplot = True group_ids = self.controller.filelist.GetCheckedStrings() for checked in group_ids: groupname = self.controller.file_groups[str(checked)] dgroup = self.controller.get_group(groupname) if dgroup is None: continue dgroup.plot_yarrays = [(dgroup.y, PLOTOPTS_1, dgroup.filename)] if dgroup.datatype == 'xas': dgroup.plot_xlabel = '$E\,\mathrm{(eV)}$' dgroup.plot_ymarkers = [] self.controller.plot_group(groupname=groupname, title='', new=newplot) newplot = False def plot_group(self, groupname=None, title=None, new=True, **kws): self.controller.plot_group(groupname=groupname, title=title, new=new, **kws) self.Raise() def ShowFile(self, evt=None, groupname=None, **kws): filename = None if evt is not None: filename = str(evt.GetString()) if groupname is None and filename is not None: groupname = self.controller.file_groups[filename] if not hasattr(self.larch.symtable, groupname): print('Error reading file ', groupname) return dgroup = self.controller.get_group(groupname) self.controller.group = dgroup self.controller.groupname = groupname self.nb.SetSelection(0) self.proc_panel.fill(dgroup) if filename is None: filename = dgroup.filename self.title.SetLabel(filename) def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Open Data File", self.onReadDialog) fmenu.AppendSeparator() MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L', 'Show Larch Programming Buffer', self.onShowLarchBuffer) MenuItem(self, fmenu, "debug wx\tCtrl+I", "", self.showInspectionTool) MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) self.menubar.Append(fmenu, "&File") omenu = wx.Menu() self.menubar.Append(omenu, "Options") MenuItem(self, omenu, "Configure Data Processing", "Configure Data Processing", self.onConfigDataProcessing) MenuItem(self, omenu, "Configure Data Fitting", "Configure Data Fitting", self.onConfigDataFitting) self.SetMenuBar(self.menubar) self.Bind(wx.EVT_CLOSE, self.onClose) def onShowLarchBuffer(self, evt=None): if self.larch_buffer is None: self.larch_buffer = LarchFrame(_larch=self.larch) self.larch_buffer.Show() self.larch_buffer.Raise() def onConfigDataProcessing(self, event=None): pass def onConfigDataFitting(self, event=None): pass def showInspectionTool(self, event=None): app = wx.GetApp() app.ShowInspectionTool() def onAbout(self, evt): dlg = wx.MessageDialog(self, self._about, "About Larch XYFit", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self, evt): save_workdir('xyfit.dat') self.proc_panel.proc_timer.Stop() for nam in dir(self.larch.symtable._plotter): obj = getattr(self.larch.symtable._plotter, nam) try: obj.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) del obj if self.larch_buffer is not None: try: self.larch_buffer.Destroy() except: pass self.Destroy() def show_subframe(self, name, frameclass, **opts): shown = False if name in self.subframes: try: self.subframes[name].Raise() shown = True except: del self.subframes[name] if not shown: self.subframes[name] = frameclass(self, **opts) def onSelectColumns(self, evt=None): dgroup = self.controller.get_group(self.controller.groupname) self.show_subframe('readfile', ColumnDataFileFrame, group=dgroup.raw, last_array_sel=self.last_array_sel, _larch=self.larch, read_ok_cb=partial(self.onRead_OK, overwrite=True)) def onReadDialog(self, evt=None): dlg = wx.FileDialog(self, message="Read Data File", defaultDir=os.getcwd(), wildcard=FILE_WILDCARDS, style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() path = path.replace('\\', '/') self.onRead(path) dlg.Destroy() def onRead(self, path): if path in self.controller.file_groups: if wx.ID_YES != popup(self, "Re-read file '%s'?" % path, 'Re-read file?'): return filedir, filename = os.path.split(path) pref = fix_varname(filename.replace('.', '_')) if len(pref) > 15: pref = pref[:15] groupname = pref count, maxcount = 0, 999 while hasattr(self.larch.symtable, groupname) and count < maxcount: count += 1 groupname = '%s_%2.2i' % (pref, count) if self.config['chdir_on_fileopen']: os.chdir(filedir) kwargs = dict(filename=path, _larch=self.larch_buffer.larchshell, last_array_sel=self.last_array_sel, read_ok_cb=self.onRead_OK) # check for athena projects if is_athena_project(path): self.show_subframe('athena_import', AthenaImporter, **kwargs) else: self.show_subframe('readfile', ColumnDataFileFrame, **kwargs) def onRead_OK(self, datagroup, array_sel=None, overwrite=False): """ called when column data has been selected and is ready to be used overwrite: whether to overwrite the current datagroup, as when editing a datagroup """ gname = datagroup.groupname fname = datagroup.filename path = datagroup.path datatype = getattr(datagroup, 'datatype', 'raw') if array_sel is not None: self.last_array_sel = array_sel # file /group may already exist in list if fname in self.controller.file_groups and not overwrite: for i in range(1, 101): ftest = "%s (%i)" % (fname, i) if ftest not in self.controller.file_groups: fname = ftest break if fname not in self.controller.file_groups: self.controller.filelist.Append(fname) self.controller.file_groups[fname] = gname self.nb.SetSelection(0) self.ShowFile(groupname=gname)
class XASFrame(wx.Frame): _about = """Larch XAS GUI: XAS Visualization and Analysis Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, parent=None, _larch=None, **kws): wx.Frame.__init__(self, parent, -1, size=XASVIEW_SIZE, style=FRAMESTYLE) self.last_array_sel = {} self.paths2read = [] title = "Larch XAS GUI: XAS Visualization and Analysis" self.larch_buffer = parent if not isinstance(parent, LarchFrame): self.larch_buffer = LarchFrame(_larch=_larch) self.larch_buffer.Show() self.larch_buffer.Raise() self.larch=self.larch_buffer.larchshell self.controller = XASController(wxparent=self, _larch=self.larch) self.current_filename = None self.subframes = {} self.plotframe = None self.SetTitle(title) self.SetSize(XASVIEW_SIZE) self.SetFont(Font(10)) self.larch_buffer.Hide() 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) def createMainPanel(self): splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(250) leftpanel = wx.Panel(splitter) ltop = wx.Panel(leftpanel) def Btn(msg, x, act): b = Button(ltop, msg, size=(x, 30), action=act) b.SetFont(Font(10)) return b sel_none = Btn('Select None', 120, self.onSelNone) sel_all = Btn('Select All', 120, self.onSelAll) self.controller.filelist = FileCheckList(leftpanel, # main=self, select_action=self.ShowFile, remove_action=self.RemoveFile) self.controller.filelist.SetBackgroundColour(wx.Colour(255, 255, 255)) tsizer = wx.BoxSizer(wx.HORIZONTAL) tsizer.Add(sel_all, 1, LCEN|wx.GROW, 1) tsizer.Add(sel_none, 1, LCEN|wx.GROW, 1) pack(ltop, tsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(ltop, 0, LCEN|wx.GROW, 1) sizer.Add(self.controller.filelist, 1, LCEN|wx.GROW|wx.ALL, 1) pack(leftpanel, sizer) # right hand side panel = wx.Panel(splitter) sizer = wx.BoxSizer(wx.VERTICAL) self.title = SimpleText(panel, 'initializing...', size=(300, -1)) self.title.SetFont(Font(10)) ir = 0 sizer.Add(self.title, 0, LCEN|wx.GROW|wx.ALL, 1) self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE) self.nb.SetTabAreaColour(wx.Colour(250,250,250)) self.nb.SetActiveTabColour(wx.Colour(254,254,195)) self.nb.SetNonActiveTabTextColour(wx.Colour(10,10,128)) self.nb.SetActiveTabTextColour(wx.Colour(128,0,0)) self.nb_panels = [] for name, creator in NB_PANELS: _panel = creator(parent=self, controller=self.controller) self.nb.AddPage(_panel," %s " % name, True) self.nb_panels.append(_panel) sizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2) self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onNBChanged) self.nb.SetSelection(0) pack(panel, sizer) splitter.SplitVertically(leftpanel, panel, 1) wx.CallAfter(self.init_larch) def onNBChanged(self, event=None): idx = self.nb.GetSelection() pan = self.nb_panels[idx] callback = getattr(pan, 'onPanelExposed', None) if callable(callback): callback() def onSelAll(self, event=None): self.controller.filelist.SetCheckedStrings(self.controller.file_groups.keys()) def onSelNone(self, event=None): self.controller.filelist.SetCheckedStrings([]) def init_larch(self): self.SetStatusText('initializing Larch') self.title.SetLabel('') self.controller.init_larch() plotframe = self.controller.get_display(stacked=False) xpos, ypos = self.GetPosition() xsiz, ysiz = self.GetSize() plotframe.SetPosition((xpos+xsiz+5, ypos)) self.SetStatusText('ready') self.Raise() def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def RemoveFile(self, fname=None, **kws): if fname is not None: s = str(fname) if s in self.controller.file_groups: group = self.controller.file_groups.pop(s) def ShowFile(self, evt=None, groupname=None, with_plot=True, **kws): filename = None if evt is not None: # filename = str(evt.GetString()) # could have clicking on filename add to "Selected": # checked = list(self.controller.filelist.GetCheckedStrings()) # if filename not in checked: # checked.append(filename) # self.controller.filelist.SetCheckedStrings(checked) if groupname is None and filename is not None: groupname = self.controller.file_groups[filename] if not hasattr(self.larch.symtable, groupname): return dgroup = self.controller.get_group(groupname) self.controller.group = dgroup self.controller.groupname = groupname current_nbpanel = self.nb_panels[self.nb.GetSelection()] self.nb_panels[0].fill_form(dgroup) if with_plot: self.nb_panels[0].plot(dgroup) if filename is None: filename = dgroup.filename self.title.SetLabel(filename) self.current_filename = filename def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() group_menu = wx.Menu() data_menu = wx.Menu() ppeak_menu = wx.Menu() m = {} MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Open Data File", self.onReadDialog) MenuItem(self, fmenu, "&Save Project\tCtrl+S", "Save Session to Project File", self.onSaveProject) MenuItem(self, fmenu, "Export Selected Groups to Athena Project", "Export Selected Groups to Athena Project", self.onExportAthena) MenuItem(self, fmenu, "Export Selected Groups to CSV", "Export Selected Groups to CSV", self.onExportCSV) fmenu.AppendSeparator() MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L', 'Show Larch Programming Buffer', self.onShowLarchBuffer) # MenuItem(self, fmenu, "&Inspect \tCtrl+I", # "e", self.showInspectionTool) MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) MenuItem(self, group_menu, "Copy This Group", "Copy This Group", self.onCopyGroup) MenuItem(self, group_menu, "Rename This Group", "Rename This Group", self.onRenameGroup) MenuItem(self, group_menu, "Remove Selected Groups", "Remove Selected Group", self.onRemoveGroups) MenuItem(self, group_menu, "Merge Selected Groups", "Merge Selected Groups", self.onMergeData) MenuItem(self, data_menu, "Deglitch Data", "Deglitch Data", self.onDeglitchData) MenuItem(self, data_menu, "Recalibrate Energy", "Recalibrate Energy", self.onEnergyCalibrateData) MenuItem(self, data_menu, "Smooth Data", "Smooth Data", self.onSmoothData) MenuItem(self, data_menu, "Rebin Data", "Rebin Data", self.onRebinData) MenuItem(self, data_menu, "Correct Over-absorption", "Correct Over-absorption", self.onCorrectOverAbsorptionData) MenuItem(self, ppeak_menu, "&Read Fit Model\tCtrl+R", "Read Fit Model from File", self.onLoadFitResult) fsave = MenuItem(self, ppeak_menu, "Save Fit Model", "Save Fit Model to File", self.onSaveFitResult) fexport = MenuItem(self, ppeak_menu, "Export Data and Fit", "Export Data and Fit", self.onExportFitResult) self.afterfit_menus = (fsave, fexport) for m in self.afterfit_menus: m.Enable(False) self.menubar.Append(fmenu, "&File") self.menubar.Append(group_menu, "Groups") self.menubar.Append(data_menu, "Data") self.menubar.Append(ppeak_menu, "PreEdgePeaks") self.SetMenuBar(self.menubar) self.Bind(wx.EVT_CLOSE, self.onClose) def onShowLarchBuffer(self, evt=None): if self.larch_buffer is None: self.larch_buffer = LarchFrame(_larch=self.larch) self.larch_buffer.Show() self.larch_buffer.Raise() def onExportCSV(self, evt=None): group_ids = self.controller.filelist.GetCheckedStrings() savegroups = [] groupnames = [] for checked in group_ids: groupname = self.controller.file_groups[str(checked)] dgroup = self.controller.get_group(groupname) savegroups.append(dgroup) groupnames.append(groupname) if len(savegroups) < 1: Popup(self, "No files selected to export to CSV", "No files selected") return deffile = "%s_%i.csv" % (groupname, len(groupnames)) wcards = 'CSV Files (*.csv)|*.cvs|All files (*.*)|*.*' outfile = FileSave(self, 'Export Selected Groups to CSV File', default_file=deffile, wildcard=wcards) if outfile is None: return groups2csv(savegroups, outfile, x='energy', y='norm', _larch=self.larch) def onExportAthena(self, evt=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(self.controller.file_groups[str(checked)]) if len(groups) < 1: Popup(self, "No files selected to export to Athena", "No files selected") return self.save_athena_project(groups[0], groups, prompt=True) def onSaveProject(self, evt=None): groups = [gname for gname in self.controller.file_groups] if len(groups) < 1: Popup(self, "No files selected to export to Athena", "No files selected") return self.save_athena_project(groups[0], groups, prompt=True) def save_athena_project(self, filename, grouplist, prompt=True): if len(grouplist) < 1: return savegroups = [self.controller.get_group(gname) for gname in grouplist] deffile = "%s_%i.prj" % (filename, len(grouplist)) wcards = 'Athena Projects (*.prj)|*.prj|All files (*.*)|*.*' outfile = FileSave(self, 'Save Groups to Athena Project File', default_file=deffile, wildcard=wcards) if outfile is None: return aprj = AthenaProject(filename=outfile, _larch=self.larch) for label, grp in zip(grouplist, savegroups): aprj.add_group(grp, label=label) aprj.save(use_gzip=True) def onConfigDataProcessing(self, event=None): pass def onCopyGroup(self, event=None): fname = self.current_filename if fname is None: fname = self.current_filename = self.controller.filelist.GetStringSelection() groupname = self.controller.file_groups[fname] if not hasattr(self.larch.symtable, groupname): return ogroup = self.controller.get_group(groupname) ngroup = Group(datatype=ogroup.datatype, energy=1.0*ogroup.energy, mu=1.0*ogroup.mu, xdat=1.0*ogroup.energy, ydat=1.0*ogroup.mu) for attr in dir(ogroup): if attr in ('i0', 'data' 'yerr'): val = getattr(ogroup, attr)*1.0 if attr in ('norm', 'flat', 'deriv', 'deconv', 'post_edge', 'pre_edge'): pass else: try: val = copy.deepcopy(getattr(ogroup, attr)) except ValueError: val = None setattr(ngroup, attr, val) new_fname = unique_name(fname, self.controller.file_groups.keys()) new_gname = unique_name(groupname, self.controller.file_groups.values()) setattr(self.larch.symtable, new_gname, ngroup) self.install_group(new_gname, new_fname, overwrite=False) self.nb_panels[0].process(ngroup) self.ShowFile(groupname=new_gname) def onRenameGroup(self, event=None): fname = self.current_filename = self.controller.filelist.GetStringSelection() if fname is None: return dlg = RenameDialog(self, fname) res = dlg.GetResponse() dlg.Destroy() if res.ok: groupname = self.controller.file_groups.pop(fname) self.controller.file_groups[res.newname] = groupname self.controller.filelist.rename_item(self.current_filename, res.newname) dgroup = self.controller.get_group(groupname) dgroup.filename = self.current_filename = res.newname self.controller.filelist.SetStringSelection(res.newname) def onRemoveGroups(self, event=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(self.controller.file_groups[str(checked)]) if len(groups) < 1: return dlg = RemoveDialog(self, groups) res = dlg.GetResponse() dlg.Destroy() if res.ok: filelist = self.controller.filelist all_fnames = filelist.GetItems() for fname in groups: gname = self.controller.file_groups.pop(fname) delattr(self.controller.symtable, gname) all_fnames.remove(fname) filelist.Clear() for name in all_fnames: filelist.Append(name) def onMergeData(self, event=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(self.controller.file_groups[str(checked)]) if len(groups) < 1: return outgroup = unique_name('merge', self.controller.file_groups) dlg = MergeDialog(self, groups, outgroup=outgroup) res = dlg.GetResponse() dlg.Destroy() if res.ok: fname = res.group gname = fix_varname(res.group.lower()) yname = 'norm' if res.ynorm else 'mu' self.controller.merge_groups(groups, master=res.master, yarray=yname, outgroup=gname) self.install_group(gname, fname, overwrite=False) self.controller.filelist.SetStringSelection(fname) def onDeglitchData(self, event=None): DeglitchDialog(self, self.controller).Show() def onSmoothData(self, event=None): SmoothDataDialog(self, self.controller).Show() def onRebinData(self, event=None): RebinDataDialog(self, self.controller).Show() def onCorrectOverAbsorptionData(self, event=None): OverAbsorptionDialog(self, self.controller).Show() def onEnergyCalibrateData(self, event=None): EnergyCalibrateDialog(self, self.controller).Show() def onConfigDataFitting(self, event=None): pass def showInspectionTool(self, event=None): app = wx.GetApp() app.ShowInspectionTool() def onAbout(self,evt): dlg = wx.MessageDialog(self, self._about, "About Larch XAS GUI", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self, event): dlg = QuitDialog(self) res = dlg.GetResponse() dlg.Destroy() if not res.ok: return if res.save: groups = [gname for gname in self.controller.file_groups] if len(groups) > 0: self.save_athena_project(groups[0], groups, prompt=True) self.controller.save_config() self.controller.get_display().Destroy() if self.larch_buffer is not None: try: self.larch_buffer.Destroy() except: pass time.sleep(0.05) for nam in dir(self.larch.symtable._plotter): obj = getattr(self.larch.symtable._plotter, nam) time.sleep(0.05) try: obj.Destroy() except: pass for name, wid in self.subframes.items(): if wid is not None: try: wid.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) self.Destroy() def show_subframe(self, name, frameclass, **opts): shown = False if name in self.subframes: try: self.subframes[name].Raise() shown = True except: del self.subframes[name] if not shown: self.subframes[name] = frameclass(self, **opts) def onSelectColumns(self, event=None): dgroup = self.controller.get_group() self.show_subframe('readfile', ColumnDataFileFrame, group=dgroup.raw, last_array_sel=self.last_array_sel, _larch=self.larch, read_ok_cb=partial(self.onRead_OK, overwrite=True)) def onLoadFitResult(self, event=None): self.nb.SetSelection(1) self.nb_panels[1].onLoadFitResult(event=event) def onSaveFitResult(self, event=None): self.nb_panels[1].onSaveFitResult(event=event) def onExportFitResult(self, event=None): self.nb_panels[1].onExportFitResult(event=event) def onReadDialog(self, event=None): dlg = wx.FileDialog(self, message="Read Data File", defaultDir=os.getcwd(), wildcard=FILE_WILDCARDS, style=wx.FD_OPEN|wx.FD_MULTIPLE) self.paths2read = [] if dlg.ShowModal() == wx.ID_OK: self.paths2read = dlg.GetPaths() dlg.Destroy() if len(self.paths2read) < 1: return path = self.paths2read.pop(0) path = path.replace('\\', '/') do_read = True if path in self.controller.file_groups: do_read = (wx.ID_YES == Popup(self, "Re-read file '%s'?" % path, 'Re-read file?')) if do_read: self.onRead(path) def onRead(self, path): filedir, filename = os.path.split(path) if self.controller.get_config('chdir_on_fileopen'): os.chdir(filedir) self.controller.set_workdir() # check for athena projects if is_athena_project(path): kwargs = dict(filename=path, _larch = self.controller.larch, read_ok_cb=self.onReadAthenaProject_OK) self.show_subframe('athena_import', AthenaImporter, **kwargs) else: kwargs = dict(filename=path, _larch=self.larch_buffer.larchshell, last_array_sel = self.last_array_sel, read_ok_cb=self.onRead_OK) self.show_subframe('readfile', ColumnDataFileFrame, **kwargs) def onReadAthenaProject_OK(self, path, namelist): """read groups from a list of groups from an athena project file""" self.larch.eval("_prj = read_athena('{path:s}', do_fft=False, do_bkg=False)".format(path=path)) dgroup = None s = """ {group:s} = _prj.{group:s} {group:s}.datatype = 'xas' {group:s}.xdat = 1.0*{group:s}.energy {group:s}.ydat = 1.0*{group:s}.mu {group:s}.yerr = 1.0 {group:s}.plot_ylabel = 'mu' {group:s}.plot_xlabel = 'energy' """ for gname in namelist: self.larch.eval(s.format(group=gname)) dgroup = self.install_group(gname, gname, with_plot=False) # self.nb_panels[0].fill_form(dgroup) if dgroup is not None: self.nb_panels[0].plot(dgroup) self.larch.eval("del _prj") def onRead_OK(self, script, path, groupname=None, array_sel=None, overwrite=False): """ called when column data has been selected and is ready to be used overwrite: whether to overwrite the current datagroup, as when editing a datagroup """ abort_read = False filedir, filename = os.path.split(path) if not overwrite and hasattr(self.larch.symtable, groupname): newname = file2groupname(filename, symtable=self.larch.symtable) msg = """Warning: groupname '%s' already used. Will use groupname '%s' instead """ % (groupname, newname) dlg = wx.MessageDialog(self, msg, 'Warning', wx.OK | wx.CANCEL ) abort_read = (wx.ID_OK != dlg.ShowModal()) dlg.Destroy() groupname = newname if abort_read: return self.larch.eval(script.format(group=groupname, path=path)) if array_sel is not None: self.last_array_sel = array_sel self.install_group(groupname, filename, overwrite=overwrite) for path in self.paths2read: path = path.replace('\\', '/') filedir, filename = os.path.split(path) gname = file2groupname(filename, symtable=self.larch.symtable) self.larch.eval(script.format(group=gname, path=path)) self.install_group(gname, filename, overwrite=True) def install_group(self, groupname, filename, overwrite=False, with_plot=True): """add groupname / filename to list of available data groups""" thisgroup = getattr(self.larch.symtable, groupname) thisgroup.groupname = groupname thisgroup.filename = filename datatype = getattr(thisgroup, 'datatype', 'raw') # file /group may already exist in list if filename in self.controller.file_groups and not overwrite: for i in range(1, 101): ftest = "%s (%i)" % (filename, i) if ftest not in self.controller.file_groups: filename = ftest break if filename not in self.controller.file_groups: self.controller.filelist.Append(filename) self.controller.file_groups[filename] = groupname self.nb.SetSelection(0) self.ShowFile(groupname=groupname, with_plot=with_plot) self.controller.filelist.SetStringSelection(filename) return thisgroup
class EditColumnFrame(wx.Frame): """Set Column Labels for a file""" def __init__(self, parent, group=None, last_array_sel=None, read_ok_cb=None, edit_groupname=True): self.parent = parent self.dgroup = group if not hasattr(self.dgroup, 'is_xas'): try: self.dgroup.is_xas = 'energ' in self.dgroup.array_labels[ 0].lower() except: self.dgroup.is_xas = False self.read_ok_cb = read_ok_cb self.array_sel = { 'xpop': '', 'xarr': None, 'ypop': '', 'yop': '/', 'yarr1': None, 'yarr2': None, 'use_deriv': False } if last_array_sel is not None: self.array_sel.update(last_array_sel) if self.array_sel['yarr2'] is None and 'i0' in self.dgroup.array_labels: self.array_sel['yarr2'] = 'i0' if self.array_sel['yarr1'] is None: if 'itrans' in self.dgroup.array_labels: self.array_sel['yarr1'] = 'itrans' elif 'i1' in self.dgroup.array_labels: self.array_sel['yarr1'] = 'i1' message = "Build Arrys from Data Columns for %s" % self.dgroup.filename wx.Frame.__init__(self, None, -1, 'Build Arrays from Data Columns for %s' % self.dgroup.filename, style=FRAMESTYLE) self.SetFont(Font(10)) panel = scrolled.ScrolledPanel(self) self.SetMinSize((600, 600)) self.colors = GUIColors() self.plotframe = None # title row title = SimpleText(panel, message, font=Font(13), colour=self.colors.title, style=LCEN) opts = dict(action=self.onColumnChoice, size=(120, -1)) arr_labels = self.dgroup.array_labels yarr_labels = arr_labels + ['1.0', '0.0', ''] xarr_labels = arr_labels + ['<index>'] self.xarr = Choice(panel, choices=xarr_labels, **opts) self.yarr1 = Choice(panel, choices=arr_labels, **opts) self.yarr2 = Choice(panel, choices=yarr_labels, **opts) opts['size'] = (90, -1) self.xpop = Choice(panel, choices=XPRE_OPS, **opts) self.ypop = Choice(panel, choices=YPRE_OPS, **opts) opts['size'] = (50, -1) self.yop = Choice(panel, choices=ARR_OPS, **opts) ylab = SimpleText(panel, 'Y = ') xlab = SimpleText(panel, 'X = ') self.xsuf = SimpleText(panel, '') self.ysuf = SimpleText(panel, '') self.xpop.SetStringSelection(self.array_sel['xpop']) self.ypop.SetStringSelection(self.array_sel['ypop']) self.yop.SetStringSelection(self.array_sel['yop']) if '(' in self.array_sel['ypop']: self.ysuf.SetLabel(')') ixsel, iysel, iy2sel = 0, 1, len(yarr_labels) - 1 if self.array_sel['xarr'] in xarr_labels: ixsel = xarr_labels.index(self.array_sel['xarr']) if self.array_sel['yarr1'] in arr_labels: iysel = arr_labels.index(self.array_sel['yarr1']) if self.array_sel['yarr2'] in yarr_labels: iy2sel = yarr_labels.index(self.array_sel['yarr2']) self.xarr.SetSelection(ixsel) self.yarr1.SetSelection(iysel) self.yarr2.SetSelection(iy2sel) opts['size'] = (150, -1) self.use_deriv = Check(panel, label='use derivative', default=self.array_sel['use_deriv'], **opts) self.is_xas = Check(panel, label='use as XAS data', default=self.dgroup.is_xas, **opts) bpanel = wx.Panel(panel) bsizer = wx.BoxSizer(wx.HORIZONTAL) bsizer.Add(Button(bpanel, 'Preview', action=self.onColumnChoice), 4) bsizer.Add(Button(bpanel, 'OK', action=self.onOK), 4) bsizer.Add(Button(bpanel, 'Cancel', action=self.onCancel), 4) pack(bpanel, bsizer) sizer = wx.GridBagSizer(4, 8) sizer.Add(title, (0, 0), (1, 7), LCEN, 5) ir = 1 sizer.Add(xlab, (ir, 0), (1, 1), CEN, 0) sizer.Add(self.xpop, (ir, 1), (1, 1), CEN, 0) sizer.Add(self.xarr, (ir, 2), (1, 1), CEN, 0) sizer.Add(self.xsuf, (ir, 3), (1, 1), CEN, 0) ir += 1 sizer.Add(ylab, (ir, 0), (1, 1), CEN, 0) sizer.Add(self.ypop, (ir, 1), (1, 1), CEN, 0) sizer.Add(self.yarr1, (ir, 2), (1, 1), CEN, 0) sizer.Add(self.yop, (ir, 3), (1, 1), CEN, 0) sizer.Add(self.yarr2, (ir, 4), (1, 1), CEN, 0) sizer.Add(self.ysuf, (ir, 5), (1, 1), CEN, 0) ir += 1 sizer.Add(self.use_deriv, (ir, 0), (1, 3), LCEN, 0) ir += 1 sizer.Add(self.is_xas, (ir, 0), (1, 3), LCEN, 0) self.wid_groupname = None if edit_groupname: wid_grouplab = SimpleText(panel, 'Use Group Name: ') self.wid_groupname = wx.TextCtrl(panel, value=self.dgroup._groupname, size=(100, -1)) ir += 1 sizer.Add(wid_grouplab, (ir, 0), (1, 2), LCEN, 3) sizer.Add(self.wid_groupname, (ir, 2), (1, 3), LCEN, 3) ir += 1 sizer.Add(bpanel, (ir, 0), (1, 5), LCEN, 3) pack(panel, sizer) ftext = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY, size=(-1, 150)) try: m = open(self.dgroup.filename, 'r') text = m.read() m.close() except: text = "The file '%s'\n was not found" % self.dgroup.filename ftext.SetValue(text) ftext.SetFont(Font(9)) mainsizer = wx.BoxSizer(wx.VERTICAL) mainsizer.Add(panel, 0, wx.GROW | wx.ALL, 2) mainsizer.Add(ftext, 1, LCEN | wx.GROW, 2) pack(self, mainsizer) self.Show() self.Raise() def onOK(self, event=None): """ build arrays according to selection """ if not hasattr(self.dgroup, '_xdat'): self.onColumnChoice() if self.wid_groupname is not None: self.dgroup._groupname = fix_varname(self.wid_groupname.GetValue()) if self.plotframe is not None: try: self.plotframe.Destroy() except: pass if self.read_ok_cb is not None: self.read_ok_cb(self.dgroup, self.array_sel) self.Destroy() def onCancel(self, event=None): self.dgroup.import_ok = False if self.plotframe is not None: self.plotframe.Destroy() self.Destroy() def onColumnChoice(self, evt=None): """column selections changed calc _xdat and _ydat""" # dtcorr = self.dtcorr.IsChecked() dtcorr = False use_deriv = self.use_deriv.IsChecked() dgroup = self.dgroup ix = self.xarr.GetSelection() xname = self.xarr.GetStringSelection() if xname == '<index>': xname = self.dgroup.array_labels[0] dgroup._index = 1.0 * np.arange(len(getattr(dgroup, xname))) xname = '_index' dgroup.is_xas = self.is_xas.IsChecked() dgroup._xdat = getattr(dgroup, xname) def do_preop(opwid, arr): opstr = opwid.GetStringSelection().strip() suf = '' if opstr in ('-log(', 'log('): suf = ')' if opstr == 'log(': arr = np.log(arr) elif opstr == '-log(': arr = -np.log(arr) return suf, opstr, arr xsuf, xpop, dgroup._xdat = do_preop(self.xpop, dgroup._xdat) self.xsuf.SetLabel(xsuf) try: xunits = dgroup.array_units[ix].strip() xlabel = '%s (%s)' % (xname, xunits) except: xlabel = xname def get_data(group, arrayname, correct=False): if hasattr(group, 'get_data'): return group.get_data(arrayname, correct=correct) return getattr(group, arrayname, None) yname1 = self.yarr1.GetStringSelection().strip() yname2 = self.yarr2.GetStringSelection().strip() yop = self.yop.GetStringSelection().strip() ylabel = yname1 if len(yname2) == 0: yname2, yop = '1.0', '*' else: ylabel = "%s%s%s" % (ylabel, yop, yname2) yarr1 = get_data(dgroup, yname1, correct=dtcorr) if yname2 in ('0.0', '1.0'): yarr2 = float(yname2) if yop == '/': yarr2 = 1.0 else: yarr2 = get_data(dgroup, yname2, correct=dtcorr) dgroup._ydat = yarr1 if yop == '+': dgroup._ydat = yarr1.__add__(yarr2) elif yop == '-': dgroup._ydat = yarr1.__sub__(yarr2) elif yop == '*': dgroup._ydat = yarr1.__mul__(yarr2) elif yop == '/': dgroup._ydat = yarr1.__truediv__(yarr2) ysuf, ypop, dgroup._ydat = do_preop(self.ypop, dgroup._ydat) self.ysuf.SetLabel(ysuf) if use_deriv: try: dgroup._ydat = np.gradient(dgroup._ydat) / np.gradient( dgroup._xdat) except: pass self.array_sel = { 'xpop': xpop, 'xarr': xname, 'ypop': ypop, 'yop': yop, 'yarr1': yname1, 'yarr2': yname2, 'use_deriv': use_deriv } try: npts = min(len(dgroup._xdat), len(dgroup._ydat)) except AttributeError: print('Error calculating arrays (npts not correct)') return dgroup._npts = npts dgroup.plot_xlabel = xlabel dgroup.plot_ylabel = ylabel dgroup._xdat = np.array(dgroup._xdat[:npts]) dgroup._ydat = np.array(dgroup._ydat[:npts]) if dgroup.is_xas: dgroup.energy = dgroup._xdat dgroup.mu = dgroup._ydat self.raise_plotframe() ppanel = self.plotframe.panel popts = {} path, fname = os.path.split(dgroup.filename) popts['label'] = "%s: %s" % (fname, dgroup.plot_ylabel) popts['title'] = fname popts['ylabel'] = dgroup.plot_ylabel popts['xlabel'] = dgroup.plot_xlabel ppanel.plot(dgroup._xdat, dgroup._ydat, **popts) def raise_plotframe(self): if self.plotframe is not None: try: self.plotframe.Show() except: self.plotframe = None if self.plotframe is None: self.plotframe = PlotFrame(None, size=(650, 400)) self.plotframe.Show()
class PrePeakPanel(wx.Panel): def __init__(self, parent=None, controller=None, **kws): wx.Panel.__init__(self, parent, -1, size=(550, 625), **kws) self.parent = parent self.controller = controller self.larch = controller.larch self.fit_components = OrderedDict() self.fit_model = None self.fit_params = None self.user_added_params = None self.summary = None self.sizer = wx.GridBagSizer(10, 6) self.build_display() self.pick2_timer = wx.Timer(self) self.pick2_group = None self.Bind(wx.EVT_TIMER, self.onPick2Timer, self.pick2_timer) self.pick2_t0 = 0. self.pick2_timeout = 15. self.pick2erase_timer = wx.Timer(self) self.pick2erase_panel = None self.Bind(wx.EVT_TIMER, self.onPick2EraseTimer, self.pick2erase_timer) def onPanelExposed(self, **kws): # called when notebook is selected try: fname = self.controller.filelist.GetStringSelection() gname = self.controller.file_groups[fname] dgroup = self.controller.get_group(gname) # print(" Fill prepeak panel from group ", fname, gname, dgroup) self.fill_form_from_group(dgroup) except: pass # print(" Cannot Fill prepeak panel from group ") def larch_eval(self, cmd): """eval""" self.controller.larch.eval(cmd) def build_display(self): self.mod_nb = flat_nb.FlatNotebook(self, -1, agwStyle=FNB_STYLE) self.mod_nb.SetTabAreaColour(wx.Colour(250,250,250)) self.mod_nb.SetActiveTabColour(wx.Colour(254,254,195)) self.mod_nb.SetNonActiveTabTextColour(wx.Colour(10,10,128)) self.mod_nb.SetActiveTabTextColour(wx.Colour(128,0,0)) self.mod_nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onNBChanged) pan = self.panel = GridPanel(self, ncols=4, nrows=4, pad=2, itemstyle=LCEN) self.btns = {} for name in ('ppeak_e0', 'ppeak_elo', 'ppeak_emin', 'ppeak_emax', 'ppeak_ehi'): bb = BitmapButton(pan, get_icon('plus'), action=partial(self.on_selpoint, opt=name), tooltip='use last point selected from plot') self.btns[name] = bb opts = dict(size=(75, -1), gformat=True, precision=1) self.ppeak_e0 = FloatCtrl(pan, value=0, **opts) self.ppeak_emin = FloatCtrl(pan, value=-30, **opts) self.ppeak_emax = FloatCtrl(pan, value=0, **opts) self.ppeak_elo = FloatCtrl(pan, value=-15, **opts) self.ppeak_ehi = FloatCtrl(pan, value=-5, **opts) self.fitbline_btn = Button(pan,'Fit Baseline', action=self.onFitBaseline, size=(150, 25)) self.fitmodel_btn = Button(pan, 'Fit Model', action=self.onFitModel, size=(150, 25)) self.fitsel_btn = Button(pan, 'Fit Selected Groups', action=self.onFitSelected, size=(150, 25)) self.fitmodel_btn.Disable() self.fitsel_btn.Disable() self.array_choice = Choice(pan, size=(125, -1), choices=list(Array_Choices.keys())) self.array_choice.SetSelection(1) models_peaks = Choice(pan, size=(125, -1), choices=ModelChoices['peaks'], action=self.addModel) models_other = Choice(pan, size=(125, -1), choices=ModelChoices['other'], action=self.addModel) self.plot_choice = Choice(pan, size=(125, -1), choices=PlotChoices, action=self.onPlot) self.message = SimpleText(pan, 'first fit baseline, then add peaks to fit model.') self.msg_centroid = SimpleText(pan, '----') opts = dict(default=True, size=(75, -1), action=self.onPlot) self.show_centroid = Check(pan, label='show?', **opts) self.show_peakrange = Check(pan, label='show?', **opts) self.show_fitrange = Check(pan, label='show?', **opts) self.show_e0 = Check(pan, label='show?', **opts) opts = dict(default=False, size=(200, -1), action=self.onPlot) self.plot_sub_bline = Check(pan, label='Subtract Baseline?', **opts) titleopts = dict(font=Font(11), colour='#AA0000') pan.Add(SimpleText(pan, ' Pre-edge Peak Fitting', **titleopts), dcol=7) pan.Add(SimpleText(pan, ' Run Fit:'), style=LCEN) pan.Add(SimpleText(pan, 'Array to fit: '), newrow=True) pan.Add(self.array_choice, dcol=4) pan.Add((10, 10), dcol=2) pan.Add(self.fitbline_btn) pan.Add(SimpleText(pan, 'E0: '), newrow=True) pan.Add(self.btns['ppeak_e0']) pan.Add(self.ppeak_e0) pan.Add((10, 10), dcol=3) pan.Add(self.show_e0) pan.Add(self.fitmodel_btn) pan.Add(SimpleText(pan, 'Fit Energy Range: '), newrow=True) pan.Add(self.btns['ppeak_emin']) pan.Add(self.ppeak_emin) pan.Add(SimpleText(pan, ':')) pan.Add(self.btns['ppeak_emax']) pan.Add(self.ppeak_emax) pan.Add(self.show_fitrange, dcol=1) pan.Add(self.fitsel_btn) t = SimpleText(pan, 'Pre-edge Peak Range: ') t.SetToolTip('Range used as mask for background') pan.Add(t, newrow=True) pan.Add(self.btns['ppeak_elo']) pan.Add(self.ppeak_elo) pan.Add(SimpleText(pan, ':')) pan.Add(self.btns['ppeak_ehi']) pan.Add(self.ppeak_ehi) pan.Add(self.show_peakrange, dcol=1) pan.Add(SimpleText(pan, 'Peak Centroid: '), newrow=True) pan.Add(self.msg_centroid, dcol=5) pan.Add(self.show_centroid, dcol=1) # plot buttons ts = wx.BoxSizer(wx.HORIZONTAL) ts.Add(self.plot_choice) ts.Add(self.plot_sub_bline) pan.Add(SimpleText(pan, 'Plot: '), newrow=True) pan.Add(ts, dcol=7) # add model ts = wx.BoxSizer(wx.HORIZONTAL) ts.Add(models_peaks) ts.Add(models_other) pan.Add(SimpleText(pan, 'Add Component: '), newrow=True) pan.Add(ts, dcol=7) pan.Add(SimpleText(pan, 'Messages: '), newrow=True) pan.Add(self.message, dcol=7) pan.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add((5,5), 0, LCEN, 3) sizer.Add(HLine(self, size=(550, 2)), 0, LCEN, 3) sizer.Add(pan, 0, LCEN, 3) sizer.Add((5,5), 0, LCEN, 3) sizer.Add(HLine(self, size=(550, 2)), 0, LCEN, 3) sizer.Add((5,5), 0, LCEN, 3) sizer.Add(self.mod_nb, 1, LCEN|wx.GROW, 10) pack(self, sizer) def get_config(self, dgroup=None): """get processing configuration for a group""" if dgroup is None: dgroup = self.controller.get_group() conf = getattr(dgroup, 'prepeak_config', {}) if 'e0' not in conf: conf = default_prepeak_config() if not hasattr(dgroup, 'prepeaks'): dgroup.prepeaks = Group() dgroup.prepeaks.config = conf return conf def fill_form_from_group(self, dgroup): self.ppeak_e0.SetValue(dgroup.e0) if hasattr(dgroup, 'prepeaks'): self.ppeak_emin.SetValue(dgroup.prepeaks.emin) self.ppeak_emax.SetValue(dgroup.prepeaks.emax) self.ppeak_elo.SetValue(dgroup.prepeaks.elo) self.ppeak_ehi.SetValue(dgroup.prepeaks.ehi) def fill_form_from_dict(self, data): self.ppeak_e0.SetValue(data['e0']) self.ppeak_emin.SetValue(data['emin']) self.ppeak_emax.SetValue(data['emax']) self.ppeak_elo.SetValue(data['elo']) self.ppeak_ehi.SetValue(data['ehi']) self.array_choice.SetStringSelection(data['array_desc']) self.show_e0.Enable(data['show_e0']) self.show_centroid.Enable(data['show_centroid']) self.show_fitrange.Enable(data['show_fitrange']) self.show_peakrange.Enable(data['show_peakrange']) self.plot_sub_bline.Enable(data['plot_sub_bline']) def read_form(self): "read for, returning dict of values" dgroup = self.controller.get_group() array_desc = self.array_choice.GetStringSelection() form_opts = {'gname': dgroup.groupname, 'array_desc': array_desc.lower(), 'array_name': Array_Choices[array_desc], 'baseline_form': 'lorentzian'} form_opts['e0'] = self.ppeak_e0.GetValue() form_opts['emin'] = self.ppeak_emin.GetValue() form_opts['emax'] = self.ppeak_emax.GetValue() form_opts['elo'] = self.ppeak_elo.GetValue() form_opts['ehi'] = self.ppeak_ehi.GetValue() form_opts['plot_sub_bline'] = self.plot_sub_bline.IsChecked() form_opts['show_centroid'] = self.show_centroid.IsChecked() form_opts['show_peakrange'] = self.show_peakrange.IsChecked() form_opts['show_fitrange'] = self.show_fitrange.IsChecked() form_opts['show_e0'] = self.show_e0.IsChecked() return form_opts def onFitBaseline(self, evt=None): opts = self.read_form() cmd = """{gname:s}.ydat = 1.0*{gname:s}.{array_name:s} pre_edge_baseline(energy={gname:s}.energy, norm={gname:s}.ydat, group={gname:s}, form='{baseline_form:s}', with_line=True, elo={elo:.3f}, ehi={ehi:.3f}, emin={emin:.3f}, emax={emax:.3f}) """ self.larch_eval(cmd.format(**opts)) dgroup = self.controller.get_group() ppeaks = dgroup.prepeaks dgroup.centroid_msg = "%.4f +/- %.4f eV" % (ppeaks.centroid, ppeaks.delta_centroid) self.msg_centroid.SetLabel(dgroup.centroid_msg) if 'loren_' not in self.fit_components: self.addModel(model='Lorentzian', prefix='loren_', isbkg=True) if 'line_' not in self.fit_components: self.addModel(model='Linear', prefix='line_', isbkg=True) for prefix in ('loren_', 'line_'): cmp = self.fit_components[prefix] # cmp.bkgbox.SetValue(1) self.fill_model_params(prefix, dgroup.prepeaks.fit_details.params) self.fill_form_from_group(dgroup) self.fitmodel_btn.Enable() # self.fitallmodel_btn.Enable() i1, i2 = self.get_xranges(dgroup.energy) dgroup.yfit = dgroup.xfit = 0.0*dgroup.energy[i1:i2] self.plot_choice.SetStringSelection(PLOT_BASELINE) self.onPlot() def fill_model_params(self, prefix, params): comp = self.fit_components[prefix] parwids = comp.parwids for pname, par in params.items(): pname = prefix + pname if pname in parwids: wids = parwids[pname] if wids.minval is not None: wids.minval.SetValue(par.min) if wids.maxval is not None: wids.maxval.SetValue(par.max) wids.value.SetValue(par.value) varstr = 'vary' if par.vary else 'fix' if par.expr is not None: varstr = 'constrain' if wids.vary is not None: wids.vary.SetStringSelection(varstr) def onPlot(self, evt=None): plot_choice = self.plot_choice.GetStringSelection() opts = self.read_form() dgroup = self.controller.get_group() ppeaks = getattr(dgroup, 'prepeaks', None) if ppeaks is None: return i1, i2 = self.get_xranges(dgroup.xdat) # i2 = len(ppeaks.baseline) + i1 if len(dgroup.yfit) > len(ppeaks.baseline): i2 = i1 + len(ppeaks.baseline) # print(" Indexes: ", i1, i2, i2-i1, len(dgroup.yfit), len(ppeaks.baseline)) xdat = 1.0*dgroup.energy ydat = 1.0*dgroup.ydat yfit = 1.0*dgroup.ydat baseline = 1.0*dgroup.ydat yfit[i1:i2] = dgroup.yfit[:i2-i1] baseline[i1:i2] = ppeaks.baseline[:i2-i1] if opts['plot_sub_bline']: ydat = ydat - baseline if plot_choice in (PLOT_FIT, PLOT_RESID): yfit = yfit - baseline if plot_choice == PLOT_RESID: resid = ydat - yfit _xs = dgroup.energy[i1:i2] xrange = max(_xs) - min(_xs) pxmin = min(_xs) - 0.05 * xrange pxmax = max(_xs) + 0.05 * xrange jmin = index_of(dgroup.energy, pxmin) jmax = index_of(dgroup.energy, pxmax) + 1 _ys = ydat[jmin:jmax] yrange = max(_ys) - min(_ys) pymin = min(_ys) - 0.05 * yrange pymax = max(_ys) + 0.05 * yrange title = ' pre-edge fit' if plot_choice == PLOT_BASELINE: title = ' pre-edge baseline' if opts['plot_sub_bline']: title = ' pre-edge peaks' array_desc = self.array_choice.GetStringSelection() plotopts = {'xmin': pxmin, 'xmax': pxmax, 'ymin': pymin, 'ymax': pymax, 'title': '%s: %s' % (opts['gname'], title), 'xlabel': 'Energy (eV)', 'ylabel': '%s $\mu$' % opts['array_desc'], 'label': '%s $\mu$' % opts['array_desc'], 'delay_draw': True, 'show_legend': True} plot_extras = [] if opts['show_fitrange']: popts = {'color': '#DDDDCC'} emin = opts['emin'] emax = opts['emax'] imin = index_of(dgroup.energy, emin) imax = index_of(dgroup.energy, emax) plot_extras.append(('vline', emin, None, popts)) plot_extras.append(('vline', emax, None, popts)) if opts['show_peakrange']: popts = {'marker': '+', 'markersize': 6} elo = opts['elo'] ehi = opts['ehi'] ilo = index_of(dgroup.xdat, elo) ihi = index_of(dgroup.xdat, ehi) plot_extras.append(('marker', elo, ydat[ilo], popts)) plot_extras.append(('marker', ehi, ydat[ihi], popts)) if opts['show_centroid']: popts = {'color': '#EECCCC'} ecen = getattr(dgroup.prepeaks, 'centroid', -1) if ecen > min(dgroup.energy): plot_extras.append(('vline', ecen, None, popts)) pframe = self.controller.get_display(stacked=(plot_choice==PLOT_RESID)) ppanel = pframe.panel axes = ppanel.axes plotopts.update(PLOTOPTS_1) ppanel.plot(xdat, ydat, **plotopts) if plot_choice == PLOT_BASELINE: if not opts['plot_sub_bline']: ppanel.oplot(dgroup.prepeaks.energy, dgroup.prepeaks.baseline, label='baseline', **PLOTOPTS_2) elif plot_choice in (PLOT_FIT, PLOT_RESID): ppanel.oplot(dgroup.energy, yfit, label='fit', **PLOTOPTS_1) if hasattr(dgroup, 'ycomps'): ncomp = len(dgroup.ycomps) icomp = 0 for label, ycomp in dgroup.ycomps.items(): icomp +=1 fcomp = self.fit_components[label] # print("ycomp: ", plot_choice, label, len(ycomp), len(dgroup.xfit), # fcomp.bkgbox.IsChecked(), opts['plot_sub_bline'], icomp, ncomp) if not (fcomp.bkgbox.IsChecked() and opts['plot_sub_bline']): ppanel.oplot(dgroup.xfit, ycomp, label=label, delay_draw=(icomp!=ncomp), style='short dashed') if plot_choice == PLOT_RESID: _ys = resid yrange = max(_ys) - min(_ys) plotopts['ymin'] = min(_ys) - 0.05 * yrange plotopts['ymax'] = max(_ys) + 0.05 * yrange plotopts['delay_draw'] = False plotopts['ylabel'] = 'data-fit' plotopts['label'] = '_nolegend_' pframe.plot(dgroup.energy, resid, panel='bot', **plotopts) pframe.Show() # print(" RESIDUAL PLOT margins: ") # print(" top : ", pframe.panel.conf.margins) # print(" bot : ", pframe.panel_bot.conf.margins) for etype, x, y, opts in plot_extras: if etype == 'marker': popts = {'marker': 'o', 'markersize': 4, 'label': '_nolegend_', 'markerfacecolor': 'red', 'markeredgecolor': '#884444'} popts.update(opts) axes.plot([x], [y], **popts) elif etype == 'vline': popts = {'ymin': 0, 'ymax': 1.0, 'color': '#888888', 'label': '_nolegend_'} popts.update(opts) axes.axvline(x, **popts) ppanel.canvas.draw() def onNBChanged(self, event=None): idx = self.mod_nb.GetSelection() def addModel(self, event=None, model=None, prefix=None, isbkg=False): if model is None and event is not None: model = event.GetString() if model is None or model.startswith('<'): return if prefix is None: p = model[:5].lower() curmodels = ["%s%i_" % (p, i+1) for i in range(1+len(self.fit_components))] for comp in self.fit_components: if comp in curmodels: curmodels.remove(comp) prefix = curmodels[0] label = "%s(prefix='%s')" % (model, prefix) title = "%s: %s " % (prefix[:-1], model) title = prefix[:-1] mclass_kws = {'prefix': prefix} if 'step' in model.lower(): form = model.lower().replace('step', '').strip() if form.startswith('err'): form = 'erf' label = "Step(form='%s', prefix='%s')" % (form, prefix) title = "%s: Step %s" % (prefix[:-1], form[:3]) mclass = lm_models.StepModel mclass_kws['form'] = form minst = mclass(form=form, prefix=prefix) else: if model in ModelFuncs: mclass = getattr(lm_models, ModelFuncs[model]) else: mclass = getattr(lm_models, model+'Model') minst = mclass(prefix=prefix) panel = GridPanel(self.mod_nb, ncols=1, nrows=1, pad=1, itemstyle=CEN) def SLabel(label, size=(80, -1), **kws): return SimpleText(panel, label, size=size, style=wx.ALIGN_LEFT, **kws) usebox = Check(panel, default=True, label='Use in Fit?', size=(100, -1)) bkgbox = Check(panel, default=False, label='Is Baseline?', size=(125, -1)) if isbkg: bkgbox.SetValue(1) delbtn = Button(panel, 'Delete Component', size=(125, -1), action=partial(self.onDeleteComponent, prefix=prefix)) pick2msg = SimpleText(panel, " ", size=(125, -1)) pick2btn = Button(panel, 'Pick Values from Data', size=(150, -1), action=partial(self.onPick2Points, prefix=prefix)) # SetTip(mname, 'Label for the model component') SetTip(usebox, 'Use this component in fit?') SetTip(bkgbox, 'Label this component as "background" when plotting?') SetTip(delbtn, 'Delete this model component') SetTip(pick2btn, 'Select X range on Plot to Guess Initial Values') panel.Add(SLabel(label, size=(275, -1), colour='#0000AA'), dcol=3, style=wx.ALIGN_LEFT, newrow=True) panel.Add(usebox, dcol=1) panel.Add(bkgbox, dcol=2, style=LCEN) panel.Add(delbtn, dcol=1, style=wx.ALIGN_LEFT) panel.Add(pick2btn, dcol=2, style=wx.ALIGN_LEFT, newrow=True) panel.Add(pick2msg, dcol=2, style=wx.ALIGN_RIGHT) # panel.Add((10, 10), newrow=True) # panel.Add(HLine(panel, size=(150, 3)), dcol=4, style=wx.ALIGN_CENTER) panel.Add(SLabel("Parameter "), style=wx.ALIGN_LEFT, newrow=True) panel.AddMany((SLabel(" Value"), SLabel(" Type"), SLabel(' Bounds'), SLabel(" Min", size=(60, -1)), SLabel(" Max", size=(60, -1)), SLabel(" Expression"))) parwids = OrderedDict() parnames = sorted(minst.param_names) for a in minst._func_allargs: pname = "%s%s" % (prefix, a) if (pname not in parnames and a in minst.param_hints and a not in minst.independent_vars): parnames.append(pname) for pname in parnames: sname = pname[len(prefix):] hints = minst.param_hints.get(sname, {}) par = Parameter(name=pname, value=0, vary=True) if 'min' in hints: par.min = hints['min'] if 'max' in hints: par.max = hints['max'] if 'value' in hints: par.value = hints['value'] if 'expr' in hints: par.expr = hints['expr'] pwids = ParameterWidgets(panel, par, name_size=100, expr_size=125, float_size=80, prefix=prefix, widgets=('name', 'value', 'minval', 'maxval', 'vary', 'expr')) parwids[par.name] = pwids panel.Add(pwids.name, newrow=True) panel.AddMany((pwids.value, pwids.vary, pwids.bounds, pwids.minval, pwids.maxval, pwids.expr)) for sname, hint in minst.param_hints.items(): pname = "%s%s" % (prefix, sname) if 'expr' in hint and pname not in parnames: par = Parameter(name=pname, value=0, expr=hint['expr']) pwids = ParameterWidgets(panel, par, name_size=100, expr_size=225, float_size=80, prefix=prefix, widgets=('name', 'value', 'expr')) parwids[par.name] = pwids panel.Add(pwids.name, newrow=True) panel.Add(pwids.value) panel.Add(pwids.expr, dcol=4, style=wx.ALIGN_RIGHT) pwids.value.Disable() fgroup = Group(prefix=prefix, title=title, mclass=mclass, mclass_kws=mclass_kws, usebox=usebox, panel=panel, parwids=parwids, float_size=65, expr_size=150, pick2_msg=pick2msg, bkgbox=bkgbox) self.fit_components[prefix] = fgroup panel.pack() self.mod_nb.AddPage(panel, title, True) sx,sy = self.GetSize() self.SetSize((sx, sy+1)) self.SetSize((sx, sy)) def onDeleteComponent(self, evt=None, prefix=None): fgroup = self.fit_components.get(prefix, None) if fgroup is None: return for i in range(self.mod_nb.GetPageCount()): if fgroup.title == self.mod_nb.GetPageText(i): self.mod_nb.DeletePage(i) for attr in dir(fgroup): setattr(fgroup, attr, None) self.fit_components.pop(prefix) # sx,sy = self.GetSize() # self.SetSize((sx, sy+1)) # self.SetSize((sx, sy)) def onPick2EraseTimer(self, evt=None): """erases line trace showing automated 'Pick 2' guess """ self.pick2erase_timer.Stop() panel = self.pick2erase_panel ntrace = panel.conf.ntrace - 1 trace = panel.conf.get_mpl_line(ntrace) panel.conf.get_mpl_line(ntrace).set_data(np.array([]), np.array([])) panel.conf.ntrace = ntrace panel.draw() def onPick2Timer(self, evt=None): """checks for 'Pick 2' events, and initiates 'Pick 2' guess for a model from the selected data range """ try: plotframe = self.controller.get_display(stacked=False) curhist = plotframe.cursor_hist[:] plotframe.Raise() except: return if (time.time() - self.pick2_t0) > self.pick2_timeout: msg = self.pick2_group.pick2_msg.SetLabel(" ") plotframe.cursor_hist = [] self.pick2_timer.Stop() return if len(curhist) < 2: self.pick2_group.pick2_msg.SetLabel("%i/2" % (len(curhist))) return self.pick2_group.pick2_msg.SetLabel("done.") self.pick2_timer.Stop() # guess param values xcur = (curhist[0][0], curhist[1][0]) xmin, xmax = min(xcur), max(xcur) dgroup = getattr(self.larch.symtable, self.controller.groupname) x, y = dgroup.xdat, dgroup.ydat i0 = index_of(dgroup.xdat, xmin) i1 = index_of(dgroup.xdat, xmax) x, y = dgroup.xdat[i0:i1+1], dgroup.ydat[i0:i1+1] mod = self.pick2_group.mclass(prefix=self.pick2_group.prefix) parwids = self.pick2_group.parwids try: guesses = mod.guess(y, x=x) except: return for name, param in guesses.items(): if name in parwids: parwids[name].value.SetValue(param.value) dgroup._tmp = mod.eval(guesses, x=dgroup.xdat) plotframe = self.controller.get_display(stacked=False) plotframe.cursor_hist = [] plotframe.oplot(dgroup.xdat, dgroup._tmp) self.pick2erase_panel = plotframe.panel self.pick2erase_timer.Start(5000) def onPick2Points(self, evt=None, prefix=None): fgroup = self.fit_components.get(prefix, None) if fgroup is None: return plotframe = self.controller.get_display(stacked=False) plotframe.Raise() plotframe.cursor_hist = [] fgroup.npts = 0 self.pick2_group = fgroup if fgroup.pick2_msg is not None: fgroup.pick2_msg.SetLabel("0/2") self.pick2_t0 = time.time() self.pick2_timer.Start(250) def onSaveFitResult(self, event=None): dgroup = self.controller.get_group() deffile = dgroup.filename.replace('.', '_') + '.modl' outfile = FileSave(self, 'Save Fit Result', default_file=deffile, wildcard=ModelWcards) if outfile is not None: try: self.save_fit_result(dgroup.fit_history[-1], outfile) except IOError: print('could not write %s' % outfile) def onLoadFitResult(self, event=None): mfile = FileOpen(self, 'Load Fit Result', default_file='', wildcard=ModelWcards) if mfile is not None: self.load_modelresult(mfile) def save_fit_result(self, fitresult, outfile): """saves a customized ModelResult""" save_modelresult(fitresult, outfile) def load_modelresult(self, inpfile): """read a customized ModelResult""" result = load_modelresult(inpfile) for prefix in list(self.fit_components.keys()): self.onDeleteComponent(self, prefix=prefix) for comp in result.model.components: isbkg = comp.prefix in result.user_options['bkg_components'] self.addModel(model=comp.func.__name__, prefix=comp.prefix, isbkg=isbkg) for comp in result.model.components: parwids = self.fit_components[comp.prefix].parwids for pname, par in result.params.items(): if pname in parwids: wids = parwids[pname] if wids.minval is not None: wids.minval.SetValue(par.min) if wids.maxval is not None: wids.maxval.SetValue(par.max) val = result.init_values.get(pname, par.value) wids.value.SetValue(val) self.fill_form_from_dict(result.user_options) return result def onExportFitResult(self, event=None): dgroup = self.controller.get_group() deffile = dgroup.filename.replace('.', '_') + '_result.xdi' wcards = 'All files (*.*)|*.*' outfile = FileSave(self, 'Export Fit Result', default_file=deffile, wildcard=wcards) if outfile is not None: i1, i2 = self.get_xranges(dgroup.xdat) x = dgroup.xdat[i1:i2] y = dgroup.ydat[i1:i2] yerr = None if hasattr(dgroup, 'yerr'): yerr = 1.0*dgroup.yerr if not isinstance(yerr, np.ndarray): yerr = yerr * np.ones(len(y)) else: yerr = yerr[i1:i2] export_modelresult(dgroup.fit_history[-1], filename=outfile, datafile=dgroup.filename, ydata=y, yerr=yerr, x=x) def on_selpoint(self, evt=None, opt='xmin'): xval = None try: xval = self.larch.symtable._plotter.plot1_x except: return wid = getattr(self, opt, None) if wid is not None: wid.SetValue(xval) def get_xranges(self, x): opts = self.read_form() dgroup = self.controller.get_group() en_eps = min(np.diff(dgroup.energy)) / 5. i1 = index_of(x, opts['emin'] + en_eps) i2 = index_of(x, opts['emax'] + en_eps) + 1 return i1, i2 def build_fitmodel(self): """ use fit components to build model""" dgroup = self.controller.get_group() fullmodel = None params = Parameters() self.summary = {'components': [], 'options': {}} peaks = [] for comp in self.fit_components.values(): _cen, _amp = None, None if comp.usebox is not None and comp.usebox.IsChecked(): for parwids in comp.parwids.values(): params.add(parwids.param) #print(" add param ", parwids.param) if parwids.param.name.endswith('_center'): _cen = parwids.param.name elif parwids.param.name.endswith('_amplitude'): _amp = parwids.param.name self.summary['components'].append((comp.mclass.__name__, comp.mclass_kws)) thismodel = comp.mclass(**comp.mclass_kws) if fullmodel is None: fullmodel = thismodel else: fullmodel += thismodel if not comp.bkgbox.IsChecked() and _cen is not None and _amp is not None: peaks.append((_amp, _cen)) if len(peaks) > 0: denom = '+'.join([p[0] for p in peaks]) numer = '+'.join(["%s*%s "% p for p in peaks]) params.add('fit_centroid', expr="(%s)/(%s)" %(numer, denom)) self.fit_model = fullmodel self.fit_params = params if dgroup is not None: i1, i2 = self.get_xranges(dgroup.xdat) xsel = dgroup.xdat[i1:i2] dgroup.xfit = xsel dgroup.yfit = self.fit_model.eval(self.fit_params, x=xsel) dgroup.ycomps = self.fit_model.eval_components(params=self.fit_params, x=xsel) return dgroup def onFitSelected(self, event=None): dgroup = self.build_fitmodel() opts = self.read_form() print("fitting selected groups in progress") def onFitModel(self, event=None): dgroup = self.build_fitmodel() opts = self.read_form() i1, i2 = self.get_xranges(dgroup.xdat) dgroup.xfit = dgroup.xdat[i1:i2] ysel = dgroup.ydat[i1:i2] # print('onFit Model : xrange ', i1, i2, len(dgroup.xfit), len(dgroup.yfit)) weights = np.ones(len(ysel)) if hasattr(dgroup, 'yerr'): yerr = 1.0*dgroup.yerr if not isinstance(yerr, np.ndarray): yerr = yerr * np.ones(len(ysel)) else: yerr = yerr[i1:i2] yerr_min = 1.e-9*ysel.mean() yerr[np.where(yerr < yerr_min)] = yerr_min weights = 1.0/yerr result = self.fit_model.fit(ysel, params=self.fit_params, x=dgroup.xfit, weights=weights, method='leastsq') self.summary['xmin'] = dgroup.xdat[i1] self.summary['xmax'] = dgroup.xdat[i2] for attr in ('aic', 'bic', 'chisqr', 'redchi', 'ci_out', 'covar', 'flatchain', 'success', 'nan_policy', 'nfev', 'ndata', 'nfree', 'nvarys', 'init_values'): self.summary[attr] = getattr(result, attr) self.summary['params'] = result.params dgroup.yfit = result.best_fit dgroup.ycomps = self.fit_model.eval_components(params=result.params, x=dgroup.xfit) result.model_repr = self.fit_model._reprstring(long=True) ## hacks to save user options result.user_options = opts bkg_comps = [] for label, comp in self.fit_components.items(): if comp.bkgbox.IsChecked(): bkg_comps.append(label) result.user_options['bkg_components'] = bkg_comps self.autosave_modelresult(result) if not hasattr(dgroup, 'fit_history'): dgroup.fit_history = [] dgroup.fit_history.append(result) self.plot_choice.SetStringSelection(PLOT_FIT) self.onPlot() self.parent.show_subframe('result_frame', FitResultFrame, datagroup=dgroup, peakframe=self) self.parent.subframes['result_frame'].show_fitresult() [m.Enable(True) for m in self.parent.afterfit_menus] def update_start_values(self, params): """fill parameters with best fit values""" allparwids = {} for comp in self.fit_components.values(): if comp.usebox is not None and comp.usebox.IsChecked(): for name, parwids in comp.parwids.items(): allparwids[name] = parwids for pname, par in params.items(): if pname in allparwids: allparwids[pname].value.SetValue(par.value) def autosave_modelresult(self, result, fname=None): """autosave model result to user larch folder""" xasguidir = os.path.join(site_config.usr_larchdir, 'xasgui') if not os.path.exists(xasguidir): try: os.makedirs(xasguidir) except OSError: print("Warning: cannot create XAS GUI user folder") return if not HAS_MODELSAVE: print("Warning: cannot save model results: upgrade lmfit") return if fname is None: fname = 'autosave.fitresult' fname = os.path.join(xasguidir, fname) self.save_fit_result(result, fname)
class ScanViewerFrame(wx.Frame): _about = """Scan 2D Plotter Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, parent=None, size=(850, 650), _larch=None, **kws): wx.Frame.__init__(self, parent, -1, size=size, style=FRAMESTYLE) self.file_groups = {} self.last_array_sel = {} title = "Column Data File Viewer" self.larch = _larch self.larch_buffer = None self.subframes = {} self.plotframe = None self.groupname = None self.SetTitle(title) self.SetSize(size) self.SetFont(Font(10)) self.config = {'chdir_on_fileopen': True} 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) read_workdir('scanviewer.dat') self.need_xas_update = False self.xas_timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onXASProcessTimer, self.xas_timer) self.xas_timer.Start(500) def createMainPanel(self): splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(225) self.filelist = EditableCheckListBox(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.plot_one = Button(panel, 'Plot', size=(200, 30), action=self.onPlotOne) self.plot_sel = Button(panel, 'Plot Selected', size=(200, 30), action=self.onPlotSel) ir += 1 sizer.Add(self.plot_one, (ir, 0), (1, 2), LCEN, 0) sizer.Add(self.plot_sel, (ir, 2), (1, 2), LCEN, 0) pack(panel, sizer) mainsizer.Add(panel, 0, LCEN | wx.EXPAND, 2) o = """ btnbox = wx.Panel(mainpanel) btnsizer = wx.BoxSizer(wx.HORIZONTAL) for ttl, opt in (('New Plot', 'new'), ('Over Plot (left)', 'left'), ('Over Plot (right)', 'right')): btnsizer.Add(Button(btnbox, ttl, size=(135, -1), action=partial(self.onPlot, opt=opt)), LCEN, 1) pack(btnbox, btnsizer) mainsizer.Add(btnbox, 0, LCEN, 2) """ 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 Curve Fitting ', True) self.nb.AddPage(self.xas_panel, ' XAS Processing ', True) mainsizer.Add(self.nb, 1, LCEN | wx.EXPAND, 2) pack(mainpanel, mainsizer) return mainpanel def CreateFitPanel(self, parent): panel = wx.Panel(parent) tpan = wx.Panel(panel) self.fit_model = Choice(tpan, size=(100, -1), choices=('Gaussian', 'Lorentzian', 'Voigt', 'Linear', 'Quadratic', 'Step', 'Rectangle', 'Exponential')) self.fit_bkg = Choice(tpan, size=(100, -1), choices=('None', 'constant', 'linear', 'quadratic')) self.fit_step = Choice(tpan, size=(100, -1), choices=('linear', 'error function', 'arctan')) tsizer = wx.GridBagSizer(10, 4) tsizer.Add(SimpleText(tpan, 'Fit Model: '), (0, 0), (1, 1), LCEN) tsizer.Add(self.fit_model, (0, 1), (1, 1), LCEN) tsizer.Add(SimpleText(tpan, 'Background: '), (0, 2), (1, 1), LCEN) tsizer.Add(self.fit_bkg, (0, 3), (1, 1), LCEN) tsizer.Add( Button(tpan, 'Show Fit', size=(100, -1), action=self.onFitPeak), (1, 1), (1, 1), LCEN) tsizer.Add(SimpleText(tpan, 'Step Form: '), (1, 2), (1, 1), LCEN) tsizer.Add(self.fit_step, (1, 3), (1, 1), LCEN) pack(tpan, tsizer) self.fit_report = RichTextCtrl(panel, size=(525, 250), style=wx.VSCROLL | wx.NO_BORDER) self.fit_report.SetEditable(False) self.fit_report.SetFont(Font(9)) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(tpan, 0, wx.GROW | wx.ALL, 2) sizer.Add(self.fit_report, 1, LCEN | wx.GROW, 2) pack(panel, sizer) return panel def InitializeXASPanel(self, dgroup): predefs = dict(e0=0, pre1=-200, pre2=-30, norm1=50, edge_step=0, norm2=-10, nnorm=3, nvict=2, auto_step=True, auto_e0=True, show_e0=True) if hasattr(dgroup, 'pre_edge_details'): predefs.update(group2dict(dgroup.pre_edge_details)) self.xas_e0.SetValue(predefs['e0']) self.xas_step.SetValue(predefs['edge_step']) self.xas_pre1.SetValue(predefs['pre1']) self.xas_pre2.SetValue(predefs['pre2']) self.xas_nor1.SetValue(predefs['norm1']) self.xas_nor2.SetValue(predefs['norm2']) self.xas_vict.SetSelection(predefs['nvict']) self.xas_nnor.SetSelection(predefs['nnorm']) self.xas_showe0.SetValue(predefs['show_e0']) self.xas_autoe0.SetValue(predefs['auto_e0']) self.xas_autostep.SetValue(predefs['auto_step']) def CreateXASPanel(self, parent): opchoices = ('Raw Data', 'Normalized', 'Derivative', 'Normalized + Derivative', 'Pre-edge subtracted', 'Raw Data + Pre-edge/Post-edge') p = panel = wx.Panel(parent) opts = {'action': self.UpdateXASPlot} self.xas_autoe0 = Check(panel, default=True, label='auto?', **opts) self.xas_showe0 = Check(panel, default=True, label='show?', **opts) self.xas_autostep = Check(panel, default=True, label='auto?', **opts) self.xas_op = Choice(panel, size=(300, -1), choices=opchoices, **opts) self.btns = {} for name in ('e0', 'pre1', 'pre2', 'nor1', 'nor2'): bb = BitmapButton(panel, get_icon('plus'), action=partial(self.onXAS_selpoint, opt=name), tooltip='use last point selected from plot') self.btns[name] = bb opts = {'size': (85, -1), 'precision': 3, 'action': self.UpdateXASPlot} self.xwids = {} self.xas_e0 = FloatCtrl(panel, value=0, **opts) self.xas_step = FloatCtrl(panel, value=0, **opts) opts['precision'] = 1 self.xas_pre1 = FloatCtrl(panel, value=-200, **opts) self.xas_pre2 = FloatCtrl(panel, value=-30, **opts) self.xas_nor1 = FloatCtrl(panel, value=50, **opts) self.xas_nor2 = FloatCtrl(panel, value=-50, **opts) opts = { 'size': (50, -1), 'choices': ('0', '1', '2', '3'), 'action': self.UpdateXASPlot } self.xas_vict = Choice(panel, **opts) self.xas_nnor = Choice(panel, **opts) self.xas_vict.SetSelection(1) self.xas_nnor.SetSelection(2) sizer = wx.GridBagSizer(10, 7) 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, 6), LCEN) sizer.Add(self.btns['e0'], (1, 1), (1, 1), LCEN) sizer.Add(self.xas_e0, (1, 2), (1, 1), LCEN) sizer.Add(self.xas_autoe0, (1, 3), (1, 3), LCEN) sizer.Add(self.xas_showe0, (1, 6), (1, 2), LCEN) sizer.Add(self.xas_step, (2, 2), (1, 1), LCEN) sizer.Add(self.xas_autostep, (2, 3), (1, 3), LCEN) sizer.Add(self.btns['pre1'], (3, 1), (1, 1), LCEN) sizer.Add(self.xas_pre1, (3, 2), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (3, 3), (1, 1), LCEN) sizer.Add(self.btns['pre2'], (3, 4), (1, 1), LCEN) sizer.Add(self.xas_pre2, (3, 5), (1, 1), LCEN) sizer.Add(self.btns['nor1'], (4, 1), (1, 1), LCEN) sizer.Add(self.xas_nor1, (4, 2), (1, 1), LCEN) sizer.Add(SimpleText(p, ':'), (4, 3), (1, 1), LCEN) sizer.Add(self.btns['nor2'], (4, 4), (1, 1), LCEN) sizer.Add(self.xas_nor2, (4, 5), (1, 1), LCEN) sizer.Add(SimpleText(p, 'Victoreen:'), (3, 6), (1, 1), LCEN) sizer.Add(self.xas_vict, (3, 7), (1, 1), LCEN) sizer.Add(SimpleText(p, 'PolyOrder:'), (4, 6), (1, 1), LCEN) sizer.Add(self.xas_nnor, (4, 7), (1, 1), LCEN) pack(panel, sizer) return panel def onXAS_selpoint(self, evt=None, opt='e0'): xval = None try: xval = self.larch.symtable._plotter.plot1_x except: pass if xval is None: return e0 = self.xas_e0.GetValue() if opt == 'e0': self.xas_e0.SetValue(xval) self.xas_autoe0.SetValue(0) elif opt == 'pre1': self.xas_pre1.SetValue(xval - e0) elif opt == 'pre2': self.xas_pre2.SetValue(xval - e0) elif opt == 'nor1': self.xas_nor1.SetValue(xval - e0) elif opt == 'nor2': self.xas_nor2.SetValue(xval - e0) def onCustomColumns(self, evt=None): pass def onFitPeak(self, evt=None): gname = self.groupname 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) try: lgroup = getattr(self.larch.symtable, gname) x = lgroup._xdat y = lgroup._ydat except AttributeError: self.write_message('need data to fit!') return if step.startswith('error'): step = 'erf' elif step.startswith('arctan'): step = 'atan' pgroup = fit_peak(x, y, model, background=bkg, step=step, _larch=self.larch) dtext = '\n'.join(dtext) dtext = '%s\n%s\n' % ( dtext, fit_report( pgroup.params, min_correl=0.25, _larch=self.larch)) self.fit_report.SetEditable(True) self.fit_report.SetValue(dtext) self.fit_report.SetEditable(False) lgroup.plot_yarrays = [(lgroup._ydat, PLOTOPTS_1, lgroup.plot_ylabel)] if bkg is None: lgroup._fit = pgroup.fit[:] lgroup.plot_yarrays.append((lgroup._fit, PLOTOPTS_2, 'fit')) else: lgroup._fit = pgroup.fit[:] lgroup._fit_bgr = pgroup.bkg[:] lgroup.plot_yarrays.append((lgroup._fit, PLOTOPTS_2, 'fit')) lgroup.plot_yarrays.append( (lgroup._fit_bgr, PLOTOPTS_2, 'background')) self.plot_group(gname, new=True) def xas_process(self, gname, new_mu=False, **kws): """ process (pre-edge/normalize) XAS data from XAS form, overwriting larch group '_y1_' attribute to be plotted """ dgroup = getattr(self.larch.symtable, gname) if not hasattr(dgroup, 'energy'): dgroup.energy = dgroup._xdat if not hasattr(dgroup, 'mu'): dgroup.mu = dgroup._ydat e0 = None if not self.xas_autoe0.IsChecked(): _e0 = self.xas_e0.GetValue() if _e0 < max(dgroup.energy) and _e0 > min(dgroup.energy): e0 = float(_e0) 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['make_flat'] = False preopts['_larch'] = self.larch pre_edge(dgroup, **preopts) dgroup.pre_edge_details.e0 = dgroup.e0 dgroup.pre_edge_details.edge_step = dgroup.edge_step dgroup.pre_edge_details.auto_e0 = self.xas_autoe0.IsChecked() dgroup.pre_edge_details.show_e0 = self.xas_showe0.IsChecked() dgroup.pre_edge_details.auto_step = self.xas_autostep.IsChecked() if self.xas_autoe0.IsChecked(): self.xas_e0.SetValue(dgroup.e0) if self.xas_autostep.IsChecked(): self.xas_step.SetValue(dgroup.edge_step) details_group = dgroup.pre_edge_details self.xas_pre1.SetValue(details_group.pre1) self.xas_pre2.SetValue(details_group.pre2) self.xas_nor1.SetValue(details_group.norm1) self.xas_nor2.SetValue(details_group.norm2) dgroup.orig_ylabel = dgroup.plot_ylabel dgroup.plot_ylabel = '$\mu$' dgroup.plot_y2label = None dgroup.plot_xlabel = '$E \,\mathrm{(eV)}$' dgroup.plot_yarrays = [(dgroup.mu, PLOTOPTS_1, dgroup.plot_ylabel)] y4e0 = dgroup.mu out = self.xas_op.GetStringSelection().lower() # raw, pre, norm, flat if out.startswith('raw data + pre'): dgroup.plot_yarrays = [(dgroup.mu, PLOTOPTS_1, '$\mu$'), (dgroup.pre_edge, PLOTOPTS_2, 'pre edge'), (dgroup.post_edge, PLOTOPTS_2, 'post edge')] elif out.startswith('pre'): dgroup.pre_edge_sub = dgroup.norm * dgroup.edge_step dgroup.plot_yarrays = [(dgroup.pre_edge_sub, PLOTOPTS_1, 'pre-edge subtracted $\mu$')] y4e0 = dgroup.pre_edge_sub dgroup.plot_ylabel = 'pre-edge subtracted $\mu$' elif 'norm' in out and 'deriv' in out: dgroup.plot_yarrays = [(dgroup.norm, PLOTOPTS_1, 'normalized $\mu$'), (dgroup.dmude, PLOTOPTS_D, '$d\mu/dE$')] y4e0 = dgroup.norm dgroup.plot_ylabel = 'normalized $\mu$' dgroup.plot_y2label = '$d\mu/dE$' elif out.startswith('norm'): dgroup.plot_yarrays = [(dgroup.norm, PLOTOPTS_1, 'normalized $\mu$')] y4e0 = dgroup.norm dgroup.plot_ylabel = 'normalized $\mu$' elif out.startswith('deriv'): dgroup.plot_yarrays = [(dgroup.dmude, PLOTOPTS_1, '$d\mu/dE$')] y4e0 = dgroup.dmude dgroup.plot_ylabel = '$d\mu/dE$' dgroup.plot_ymarkers = [] if self.xas_showe0.IsChecked(): ie0 = index_of(dgroup._xdat, dgroup.e0) dgroup.plot_ymarkers = [(dgroup.e0, y4e0[ie0], {'label': 'e0'})] return def init_larch(self): t0 = time.time() if self.larch is None: self.larch = Interpreter() self.larch.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp()) self.larch.symtable.set_symbol('_sys.wx.parent', self) self.SetStatusText('ready') self.title.SetLabel('') def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def onXASProcessTimer(self, evt=None): if self.groupname is None: return if self.need_xas_update: self.xas_process(self.groupname) self.plot_group(self.groupname, new=True) self.need_xas_update = False def UpdateXASPlot(self, evt=None, **kws): self.need_xas_update = True def onPlotOne(self, evt=None, groupname=None): if groupname is None: groupname = self.groupname dgroup = getattr(self.larch.symtable, groupname, None) if dgroup is None: return self.groupname = groupname if (dgroup.is_xas and (getattr(dgroup, 'plot_yarrays', None) is None or getattr(dgroup, 'energy', None) is None or getattr(dgroup, 'mu', None) is None)): self.xas_process(groupname) self.plot_group(groupname, new=True) def onPlotSel(self, evt=None): newplot = True group_ids = self.filelist.GetCheckedStrings() for checked in group_ids: groupname = self.file_groups[str(checked)] dgroup = getattr(self.larch.symtable, groupname, None) if dgroup is None: continue if dgroup.is_xas: if ((getattr(dgroup, 'plot_yarrays', None) is None or getattr(dgroup, 'energy', None) is None or getattr(dgroup, 'mu', None) is None)): self.xas_process(groupname) dgroup.plot_yarrays = [(dgroup.norm, PLOTOPTS_1, '%s norm' % dgroup._filename)] dgroup.plot_ylabel = 'normalized $\mu$' dgroup.plot_xlabel = '$E\,\mathrm{(eV)}$' dgroup.plot_ymarkers = [] else: dgroup.plot_yarrays = [(dgroup._ydat, PLOTOPTS_1, dgroup._filename)] self.plot_group(groupname, title='', new=newplot) newplot = False def plot_group(self, groupname, title=None, new=True): oplot = self.larch.symtable._plotter.plot newplot = self.larch.symtable._plotter.newplot getdisplay = self.larch.symtable._plotter.get_display plotcmd = oplot if new: plotcmd = newplot dgroup = getattr(self.larch.symtable, groupname, None) if not hasattr(dgroup, '_xdat'): print("Cannot plot group ", groupname) if hasattr(dgroup, 'plot_yarrays'): plot_yarrays = dgroup.plot_yarrays else: plot_yarrays = [(dgroup._ydat, {}, None)] # print("Plt Group ", groupname, hasattr(dgroup,'plot_yarrays')) popts = {} path, fname = os.path.split(dgroup.filename) popts['label'] = "%s: %s" % (fname, dgroup.plot_ylabel) popts['xlabel'] = dgroup.plot_xlabel popts['ylabel'] = dgroup.plot_ylabel if getattr(dgroup, 'plot_y2label', None) is not None: popts['y2label'] = dgroup.plot_y2label if plotcmd == newplot and title is None: title = fname popts['title'] = title for yarr in plot_yarrays: popts.update(yarr[1]) if yarr[2] is not None: popts['label'] = yarr[2] plotcmd(dgroup._xdat, yarr[0], **popts) plotcmd = oplot # self.plotpanel.oplot ppanel = getdisplay(_larch=self.larch).panel if hasattr(dgroup, 'plot_ymarkers'): axes = ppanel.axes for x, y, opts in dgroup.plot_ymarkers: popts = { 'marker': 'o', 'markersize': 4, 'markerfacecolor': 'red', 'markeredgecolor': 'black' } popts.update(opts) axes.plot([x], [y], **popts) ppanel.canvas.draw() def onShowLarchBuffer(self, evt=None): if self.larch_buffer is None: self.larch_buffer = larchframe.LarchFrame(_larch=self.larch) self.larch_buffer.Show() self.larch_buffer.Raise() def ShowFile(self, evt=None, groupname=None, **kws): if groupname is None and evt is not None: groupname = self.file_groups[str(evt.GetString())] if not hasattr(self.larch.symtable, groupname): print('Error reading file ', groupname) return self.groupname = groupname self.dgroup = getattr(self.larch.symtable, groupname, None) if self.dgroup.is_xas: self.nb.SetSelection(1) else: self.nb.SetSelection(0) def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Read Scan File", self.onReadScan) MenuItem(self, fmenu, "Show Larch Buffer\tCtrl+L", "Show Larch Programming Buffer", self.onShowLarchBuffer) fmenu.AppendSeparator() MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) self.menubar.Append(fmenu, "&File") omenu = wx.Menu() MenuItem(self, omenu, "Edit Column Labels\tCtrl+E", "Edit Column Labels", self.onEditColumnLabels) self.menubar.Append(omenu, "Options") self.SetMenuBar(self.menubar) self.Bind(wx.EVT_CLOSE, self.onClose) def onAbout(self, evt): dlg = wx.MessageDialog(self, self._about, "About ScanViewer", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self, evt): save_workdir('scanviewer.dat') for nam in dir(self.larch.symtable._plotter): obj = getattr(self.larch.symtable._plotter, nam) try: obj.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) del obj if self.larch_buffer is not None: try: self.larch_buffer.onClose() except: pass for w in self.GetChildren(): w.Destroy() self.Destroy() def show_subframe(self, name, frameclass, **opts): shown = False if name in self.subframes: try: self.subframes[name].Raise() shown = True except: del self.subframes[name] if not shown: self.subframes[name] = frameclass(self, **opts) def onEditColumnLabels(self, evt=None): self.show_subframe('coledit', EditColumnFrame, group=self.dgroup, last_array_sel=self.last_array_sel, read_ok_cb=self.onReadScan_Success) def onReadScan(self, evt=None): dlg = wx.FileDialog(self, message="Load Column 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.file_groups: if wx.ID_YES != popup(self, "Re-read file '%s'?" % path, 'Re-read file?'): return filedir, filename = os.path.split(path) pref = fix_varname((filename + '____')[:7]).replace('.', '_') count, maxcount = 1, 9999 groupname = "%s%3.3i" % (pref, count) while hasattr(self.larch.symtable, groupname) and count < maxcount: count += 1 groupname = '%s%3.3i' % (pref, count) if self.config['chdir_on_fileopen']: os.chdir(filedir) fh = open(path, 'r') line1 = fh.readline().lower() fh.close() reader = read_ascii if 'epics stepscan file' in line1: reader = read_gsexdi elif 'epics scan' in line1: reader = gsescan_group elif 'xdi' in line1: reader = read_xdi dgroup = reader(str(path), _larch=self.larch) if reader == gsescan_group: assign_gsescan_groups(dgroup) dgroup._path = path dgroup._filename = filename dgroup._groupname = groupname self.show_subframe('coledit', EditColumnFrame, group=dgroup, last_array_sel=self.last_array_sel, read_ok_cb=self.onReadScan_Success) dlg.Destroy() def onReadScan_Success(self, datagroup, array_sel): """ called when column data has been selected and is ready to be used""" self.last_array_sel = array_sel filename = datagroup._filename groupname = datagroup._groupname # print(" storing datagroup ", datagroup, groupname, filename) # file /group may already exist in list if filename in self.file_groups: for i in range(1, 101): ftest = "%s (%i)" % (filename, i) if ftest not in self.groups: filename = ftest break if filename not in self.file_groups: self.filelist.Append(filename) self.file_groups[filename] = groupname setattr(self.larch.symtable, groupname, datagroup) if datagroup.is_xas: self.nb.SetSelection(1) self.InitializeXASPanel(datagroup) else: self.nb.SetSelection(0) self.onPlotOne(groupname=groupname)