class XYFitPanel(wx.Panel): def __init__(self, parent=None, controller=None, **kws): wx.Panel.__init__(self, parent, -1, size=(550, 500), **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 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) self.param_panel = AllParamsPanel(self, controller=self.controller) # self.mod_nb.AddPage(self.param_panel, 'Parameters', True) range_row = wx.Panel(self) rsizer = wx.BoxSizer(wx.HORIZONTAL) xmin_sel = BitmapButton(range_row, get_icon('plus'), action=partial(self.on_selpoint, opt='xmin'), tooltip='use last point selected from plot') xmax_sel = BitmapButton(range_row, get_icon('plus'), action=partial(self.on_selpoint, opt='xmax'), tooltip='use last point selected from plot') opts = {'size': (70, -1), 'gformat': True} self.xmin = FloatCtrl(range_row, value=-np.inf, **opts) self.xmax = FloatCtrl(range_row, value=np.inf, **opts) rsizer.Add(SimpleText(range_row, 'Fit Range X=[ '), 0, LCEN, 3) rsizer.Add(xmin_sel, 0, LCEN, 3) rsizer.Add(self.xmin, 0, LCEN, 3) rsizer.Add(SimpleText(range_row, ' : '), 0, LCEN, 3) rsizer.Add(xmax_sel, 0, LCEN, 3) rsizer.Add(self.xmax, 0, LCEN, 3) rsizer.Add(SimpleText(range_row, ' ] '), 0, LCEN, 3) rsizer.Add( Button(range_row, 'Full Data Range', size=(150, -1), action=self.onResetRange), 0, LCEN, 3) pack(range_row, rsizer) action_row = wx.Panel(self) rsizer = wx.BoxSizer(wx.HORIZONTAL) self.plot_comps = Check(action_row, label='Plot Components?', default=True, size=(150, -1)) rsizer.Add( Button(action_row, 'Run Fit', size=(100, -1), action=self.onRunFit), 0, RCEN, 3) savebtn = Button(action_row, 'Save Fit', size=(100, -1), action=self.onSaveFit) savebtn.Disable() rsizer.Add(savebtn, 0, LCEN, 3) rsizer.Add( Button(action_row, 'Plot Current Model', size=(150, -1), action=self.onShowModel), 0, LCEN, 3) rsizer.Add(self.plot_comps, 0, LCEN, 3) pack(action_row, rsizer) models_row = wx.Panel(self) rsizer = wx.BoxSizer(wx.HORIZONTAL) self.model_choice = Choice(models_row, size=(200, -1), choices=ModelChoices['peaks'], action=self.addModel) rsizer.Add(SimpleText(models_row, ' Add Model Type: '), 0, LCEN, 3) rsizer.Add( Choice(models_row, size=(100, -1), choices=ModelTypes, action=self.onModelTypes), 0, LCEN, 3) rsizer.Add(SimpleText(models_row, ' Model: '), 0, LCEN, 3) rsizer.Add(self.model_choice, 0, LCEN, 3) pack(models_row, rsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.AddMany([(range_row, 0, LCEN, 4), ((9, 9), 0, LCEN, 4), (models_row, 0, LCEN, 4), ((9, 9), 0, LCEN, 4), (action_row, 0, LCEN, 4), ((9, 9), 0, LCEN, 4), (HLine(self, size=(550, 3)), 0, LCEN, 4), ((10, 10), 0, LCEN, 2), (self.mod_nb, 1, LCEN | wx.GROW, 10)]) pack(self, sizer) def onNBChanged(self, event=None): idx = self.mod_nb.GetSelection() if self.mod_nb.GetPage(idx) is self.param_panel: self.build_fitmodel() self.param_panel.show_parameters(self.fit_params, self.user_added_params) def onModelTypes(self, event=None): modtype = event.GetString().lower() self.model_choice.SetChoices(ModelChoices[modtype]) def addModel(self, event=None, model=None): if model is None and event is not None: model = event.GetString() if model is None or model.startswith('<'): return curmodels = [ "c%i_" % (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 + ' ' * 8)[:8]) 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: 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?', size=(75, -1)) delbtn = Button(panel, 'Delete Model', size=(120, -1), action=partial(self.onDeleteComponent, prefix=prefix)) pick2msg = SimpleText(panel, " ", size=(75, -1)) pick2btn = Button(panel, 'Pick Data Range', size=(135, -1), action=partial(self.onPick2Points, prefix=prefix)) # SetTip(mname, 'Label for the model component') SetTip(usebox, 'Use this component in fit?') SetTip(delbtn, 'Delete this model component') SetTip(pick2btn, 'Select X range on Plot to Guess Initial Values') panel.Add(HLine(panel, size=(520, 3)), style=wx.ALIGN_CENTER, dcol=6) panel.Add(SLabel(label, size=(200, -1), colour='#0000AA'), dcol=3, newrow=True) panel.AddMany((usebox, pick2msg, pick2btn)) panel.Add(SLabel("Parameter"), newrow=True) panel.AddMany((SLabel("Value"), SLabel("Type"), SLabel("Min"), SLabel("Max"), 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=80, expr_size=175, 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.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=80, expr_size=275, float_size=80, prefix=prefix, widgets=('name', 'value', 'vary', 'expr')) parwids[par.name] = pwids panel.Add(pwids.name, newrow=True) panel.AddMany((pwids.value, pwids.vary)) panel.Add(pwids.expr, dcol=3, style=wx.ALIGN_RIGHT) pwids.value.Disable() pwids.vary.Disable() panel.Add(HLine(panel, size=(90, 3)), style=wx.ALIGN_CENTER, newrow=True) panel.Add(delbtn, dcol=2) panel.Add(HLine(panel, size=(250, 3)), dcol=3, style=wx.ALIGN_CENTER) 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) 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.x, dgroup.y i0 = index_of(dgroup.x, xmin) i1 = index_of(dgroup.x, xmax) x, y = dgroup.x[i0:i1 + 1], dgroup.y[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.x) plotframe = self.controller.get_display(stacked=False) plotframe.cursor_hist = [] plotframe.oplot(dgroup.x, 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 onSaveFit(self, event=None): dgroup = self.get_datagroup() deffile = dgroup.filename.replace('.', '_') + '.fitconf' outfile = FileSave(self, 'Save Fit Configuration and Results', default_file=deffile, wildcard=FITCONF_WILDCARDS) if outfile is None: return buff = ['#XYFit Config version 1'] buff.append( json.dumps(encode4js(self.summary), encoding='UTF-8', default=str)) buff.append('') try: fout = open(outfile, 'w') fout.write('\n'.join(buff)) fout.close() except IOError: print('could not write %s' % outfile) def onResetRange(self, event=None): dgroup = self.get_datagroup() self.xmin.SetValue(min(dgroup.x)) self.xmax.SetValue(max(dgroup.x)) def on_selpoint(self, evt=None, opt='xmin'): xval = None try: xval = self.larch.symtable._plotter.plot1_x except: xval = None if xval is not None: if opt == 'xmin': self.xmin.SetValue(xval) elif opt == 'xmax': self.xmax.SetValue(xval) def get_datagroup(self): dgroup = None if self.controller.groupname is not None: try: dgroup = getattr(self.larch.symtable, self.controller.groupname) except: pass return dgroup def get_xranges(self, x): xmin, xmax = min(x), max(x) i1, i2 = 0, len(x) _xmin = self.xmin.GetValue() _xmax = self.xmax.GetValue() if _xmin > min(x): i1 = index_of(x, _xmin) xmin = x[i1] if _xmax < max(x): i2 = index_of(x, _xmax) + 1 xmax = x[i2] xv1 = max(min(x), xmin - (xmax - xmin) / 5.0) xv2 = min(max(x), xmax + (xmax - xmin) / 5.0) return i1, i2, xv1, xv2 def build_fitmodel(self): """ use fit components to build model""" dgroup = self.get_datagroup() fullmodel = None params = Parameters() self.summary = {'components': [], 'options': {}} for comp in self.fit_components.values(): if comp.usebox is not None and comp.usebox.IsChecked(): for parwids in comp.parwids.values(): params.add(parwids.param) 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 self.fit_model = fullmodel self.fit_params = params if dgroup is not None: i1, i2, xv1, xv2 = self.get_xranges(dgroup.x) xsel = dgroup.x[slice(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 onShowModel(self, event=None): dgroup = self.build_fitmodel() if dgroup is not None: with_components = (self.plot_comps.IsChecked() and len(dgroup.ycomps) > 1) self.plot_fitmodel(dgroup, show_resid=False, with_components=with_components) def plot_fitmodel(self, dgroup, show_resid=False, with_components=None): if dgroup is None: return i1, i2, xv1, xv2 = self.get_xranges(dgroup.x) ysel = dgroup.y[slice(i1, i2)] plotframe = self.controller.get_display(stacked=True) plotframe.plot(dgroup.xfit, ysel, new=True, panel='top', xmin=xv1, xmax=xv2, label='data', xlabel=dgroup.plot_xlabel, ylabel=dgroup.plot_ylabel, title='Larch XYFit: %s' % dgroup.filename) plotframe.oplot(dgroup.xfit, dgroup.yfit, label='fit') plotframe.plot(dgroup.xfit, ysel - dgroup.yfit, grid=False, marker='o', markersize=4, linewidth=1, panel='bot') if with_components is None: with_components = (self.plot_comps.IsChecked() and len(dgroup.ycomps) > 1) if with_components: for label, _y in dgroup.ycomps.items(): plotframe.oplot(dgroup.xfit, _y, label=label, style='short dashed') line_opts = dict(color='#AAAAAA', label='_nolegend_', linewidth=1, zorder=-5) plotframe.panel_bot.axes.axhline(0, **line_opts) axvline = plotframe.panel.axes.axvline if i1 > 0: axvline(dgroup.x[i1], **line_opts) if i2 < len(dgroup.x): axvline(dgroup.x[i2 - 1], **line_opts) plotframe.panel.canvas.draw() def onRunFit(self, event=None): dgroup = self.build_fitmodel() if dgroup is None: return i1, i2, xv1, xv2 = self.get_xranges(dgroup.x) dgroup.xfit = dgroup.x[slice(i1, i2)] ysel = dgroup.y[slice(i1, i2)] weights = np.ones(len(ysel)) if hasattr(dgroup, 'yerr'): yerr = dgroup.yerr if not isinstance(yerr, np.ndarray): yerr = yerr * np.ones(len(ysel)) else: yerr = yerr[slice(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'] = xv1 self.summary['xmax'] = xv2 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.fit_history = [] dgroup.fit_history.append(self.summary) dgroup.yfit = result.best_fit dgroup.ycomps = self.fit_model.eval_components(params=result.params, x=dgroup.xfit) with_components = (self.plot_comps.IsChecked() and len(dgroup.ycomps) > 1) self.plot_fitmodel(dgroup, show_resid=True, with_components=with_components) # print(" == fit model == ", self.fit_model) # print(" == fit result == ", result) model_repr = self.fit_model._reprstring(long=True) report = fit_report(result, show_correl=True, min_correl=0.25, sort_pars=True) report = '[[Model]]\n %s\n%s\n' % (model_repr, report) self.summary['report'] = report self.controller.show_report(report) # 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 result.params.items(): if pname in allparwids: allparwids[pname].value.SetValue(par.value)
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 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 XASNormPanel(wx.Panel): """XAS normalization Panel""" def __init__(self, parent, controller=None, reporter=None, **kws): wx.Panel.__init__(self, parent, -1, **kws) self.parent = parent self.controller = controller self.reporter = reporter self.skip_process = False self.build_display() 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) self.fill_form(dgroup) except: pass def larch_eval(self, cmd): """eval""" self.controller.larch.eval(cmd) def build_display(self): self.SetFont(Font(10)) titleopts = dict(font=Font(11), colour='#AA0000') xas = self.xaspanel = GridPanel(self, ncols=4, nrows=4, pad=2, itemstyle=LCEN) self.plotone_op = Choice(xas, choices=list(PlotOne_Choices.keys()), action=self.onPlotOne, size=(200, -1)) self.plotsel_op = Choice(xas, choices=list(PlotSel_Choices.keys()), action=self.onPlotSel, size=(200, -1)) self.plotone_op.SetStringSelection('Normalized') self.plotsel_op.SetStringSelection('Normalized') plot_one = Button(xas, 'Plot This Group', size=(150, -1), action=self.onPlotOne) plot_sel = Button(xas, 'Plot Selected Groups', size=(150, -1), action=self.onPlotSel) self.btns = {} opts = dict(action=self.onReprocess) self.deconv_ewid = FloatCtrl(xas, value=0.5, precision=2, minval=0, size=(50, -1), **opts) self.deconv_form = Choice(xas, choices=DECONV_OPS, size=(100, -1), **opts) 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) 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'] = (50, -1) self.xas_vict = Choice(xas, choices=('0', '1', '2', '3'), **opts) self.xas_nnor = Choice(xas, choices=('0', '1', '2', '3'), **opts) self.xas_vict.SetSelection(1) self.xas_nnor.SetSelection(1) opts.update({'size': (75, -1), 'precision': 1}) self.xas_pre1 = FloatCtrl(xas, value=-np.inf, **opts) self.xas_pre2 = FloatCtrl(xas, value=-30, **opts) self.xas_nor1 = FloatCtrl(xas, value=50, **opts) self.xas_nor2 = FloatCtrl(xas, value=np.inf, **opts) opts = {'size': (75, -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) saveconf = Button(xas, 'Save as Default Settings', size=(200, -1), action=self.onSaveConfigBtn) def CopyBtn(name): return Button(xas, 'Copy', size=(50, -1), action=partial(self.onCopyParam, name)) xas.Add(SimpleText(xas, ' XAS Pre-edge subtraction and Normalization', **titleopts), dcol=6) xas.Add(SimpleText(xas, ' Copy to Selected Groups?'), style=RCEN, dcol=3) xas.Add(plot_sel, newrow=True) xas.Add(self.plotsel_op, dcol=6) xas.Add(plot_one, newrow=True) xas.Add(self.plotone_op, dcol=6) xas.Add((10, 10)) xas.Add(CopyBtn('plotone_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, 'Poly Order:')) xas.Add(self.xas_nnor) xas.Add(CopyBtn('xas_norm'), style=RCEN) xas.Add(SimpleText(xas, ' Deconvolution:'), newrow=True) xas.Add(self.deconv_form, dcol=5) xas.Add(SimpleText(xas, 'Energy width:')) xas.Add(self.deconv_ewid) xas.Add(CopyBtn('deconv'), style=RCEN) xas.Add(saveconf, dcol=6, newrow=True) xas.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(xas, 0, LCEN, 3) sizer.Add((5, 5), 0, LCEN, 3) sizer.Add(HLine(self, size=(550, 2)), 0, LCEN, 3) 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, 'xasnorm_config', {}) if 'e0' not in conf: conf = default_xasnorm_config() dgroup.xasnorm_config = conf return conf def fill_form(self, dgroup): """fill in form from a data group""" opts = self.get_config(dgroup) self.skip_process = True widlist = (self.xas_e0, self.xas_step, self.xas_pre1, self.xas_pre2, self.xas_nor1, self.xas_nor2, self.xas_vict, self.xas_nnor, self.xas_showe0, self.xas_autoe0, self.xas_autostep, self.deconv_form, self.deconv_ewid) if dgroup.datatype == 'xas': for k in widlist: k.Enable() self.plotone_op.SetChoices(list(PlotOne_Choices.keys())) self.plotsel_op.SetChoices(list(PlotSel_Choices.keys())) self.plotone_op.SetStringSelection(opts['plotone_op']) self.plotsel_op.SetStringSelection(opts['plotsel_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']) self.deconv_form.SetStringSelection(opts['deconv_form']) self.deconv_ewid.SetValue(opts['deconv_ewid']) else: self.plotone_op.SetChoices(list(PlotOne_Choices_nonxas.keys())) self.plotsel_op.SetChoices(list(PlotSel_Choices_nonxas.keys())) self.plotone_op.SetStringSelection('Raw Data') self.plotsel_op.SetStringSelection('Raw Data') for k in widlist: k.Disable() self.skip_process = False self.process(dgroup) def read_form(self): "read for, returning dict of values" form_opts = {} form_opts['e0'] = self.xas_e0.GetValue() form_opts['edge_step'] = self.xas_step.GetValue() form_opts['pre1'] = self.xas_pre1.GetValue() form_opts['pre2'] = self.xas_pre2.GetValue() form_opts['norm1'] = self.xas_nor1.GetValue() form_opts['norm2'] = self.xas_nor2.GetValue() form_opts['nnorm'] = int(self.xas_nnor.GetSelection()) form_opts['nvict'] = int(self.xas_vict.GetSelection()) form_opts['plotone_op'] = self.plotone_op.GetStringSelection() form_opts['plotsel_op'] = self.plotsel_op.GetStringSelection() form_opts['show_e0'] = self.xas_showe0.IsChecked() form_opts['auto_e0'] = self.xas_autoe0.IsChecked() form_opts['auto_step'] = self.xas_autostep.IsChecked() form_opts['deconv_form'] = self.deconv_form.GetStringSelection() form_opts['deconv_ewid'] = self.deconv_ewid.GetValue() return form_opts def onPlotOne(self, evt=None): self.plot(self.controller.get_group()) def onPlotSel(self, evt=None): newplot = True group_ids = self.controller.filelist.GetCheckedStrings() if len(group_ids) < 1: return last_id = group_ids[-1] yarray_name = PlotSel_Choices[self.plotsel_op.GetStringSelection()] ylabel = getattr(plotlabels, yarray_name) # print("Plot Sel:: ", group_ids) for checked in group_ids: groupname = self.controller.file_groups[str(checked)] dgroup = self.controller.get_group(groupname) plot_yarrays = [(yarray_name, PLOTOPTS_1, dgroup.filename)] dgroup.plot_ylabel = ylabel if dgroup is not None: dgroup.plot_extras = [] # print(" PlotSel -> plot ", checked, (last_id!=checked) ) self.plot(dgroup, title='', new=newplot, plot_yarrays=plot_yarrays, show_legend=True, with_extras=False, delay_draw=(last_id != checked)) newplot = False self.controller.get_display(stacked=False).panel.canvas.draw() def onSaveConfigBtn(self, evt=None): conf = self.controller.larch.symtable._sys.xas_viewer opts = {} opts.update(getattr(conf, 'xas_norm', {})) opts.update(self.read_form()) conf.xas_norm = opts def onCopyParam(self, name=None, evt=None): conf = self.get_config() conf.update(self.read_form()) opts = {} name = str(name) def copy_attrs(*args): for a in args: opts[a] = conf[a] if name == 'plotone_op': copy_attrs('plotone_op') elif name == 'xas_e0': copy_attrs('e0', 'show_e0') opts['auto_e0'] = False elif name == 'xas_step': copy_attrs('edge_step') opts['auto_step'] = False elif name == 'xas_pre': copy_attrs('pre1', 'pre2', 'nvict') elif name == 'xas_norm': copy_attrs('nnorm', 'norm1', 'norm2') elif name == 'deconv': copy_attrs('deconv_form', 'deconv_ewid') 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.xasnorm_config.update(opts) self.fill_form(grp) self.process(grp) def onSet_XASE0(self, evt=None, value=None): self.xas_autoe0.SetValue(0) self.onReprocess() def onSet_XASStep(self, evt=None, value=None): self.xas_autostep.SetValue(0) self.onReprocess() def onReprocess(self, evt=None, value=None, **kws): if self.skip_process: return try: dgroup = self.controller.get_group() except TypeError: return self.process(dgroup) self.plot(dgroup) 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) else: print(" unknown selection point ", opt) def process(self, dgroup, **kws): """ handle process (pre-edge/normalize, deconvolve) of XAS data from XAS form """ if self.skip_process: return self.skip_process = True dgroup.custom_plotopts = {} # print("XAS norm process ", dgroup.datatype) if dgroup.datatype != 'xas': self.skip_process = False dgroup.mu = dgroup.ydat * 1.0 return en_units = getattr(dgroup, 'energy_units', None) if en_units is None: en_units = 'eV' units = guess_energy_units(dgroup.energy) if units != 'eV': dlg = EnergyUnitsDialog(self.parent, units, dgroup.energy) res = dlg.GetResponse() dlg.Destroy() if res.ok: en_units = res.units dgroup.xdat = dgroup.energy = res.energy dgroup.energy_units = en_units form = self.read_form() e0 = form['e0'] edge_step = form['edge_step'] form['group'] = dgroup.groupname copts = [dgroup.groupname] if not form['auto_e0']: if e0 < max(dgroup.energy) and e0 > min(dgroup.energy): copts.append("e0=%.4f" % float(e0)) if not form['auto_step']: copts.append("step=%.4f" % float(edge_step)) for attr in ('pre1', 'pre2', 'nvict', 'nnorm', 'norm1', 'norm2'): copts.append("%s=%.2f" % (attr, form[attr])) self.larch_eval("pre_edge(%s)" % (', '.join(copts))) if form['auto_e0']: self.xas_e0.SetValue(dgroup.e0, act=False) if form['auto_step']: self.xas_step.SetValue(dgroup.edge_step, act=False) self.xas_pre1.SetValue(dgroup.pre_edge_details.pre1) self.xas_pre2.SetValue(dgroup.pre_edge_details.pre2) self.xas_nor1.SetValue(dgroup.pre_edge_details.norm1) self.xas_nor2.SetValue(dgroup.pre_edge_details.norm2) # deconvolution deconv_form = form['deconv_form'].lower() deconv_ewid = float(form['deconv_ewid']) if not deconv_form.startswith('none') and deconv_ewid > 1.e-3: dopts = [ dgroup.groupname, "form='%s'" % (deconv_form), "esigma=%.4f" % (deconv_ewid) ] self.larch_eval("xas_deconvolve(%s)" % (', '.join(dopts))) for attr in ('e0', 'edge_step'): dgroup.xasnorm_config[attr] = getattr(dgroup, attr) for attr in ('pre1', 'pre2', 'nnorm', 'norm1', 'norm2'): dgroup.xasnorm_config[attr] = getattr(dgroup.pre_edge_details, attr) self.skip_process = False def get_plot_arrays(self, dgroup): form = self.read_form() lab = plotlabels.norm dgroup.plot_y2label = None dgroup.plot_xlabel = plotlabels.energy dgroup.plot_yarrays = [('norm', PLOTOPTS_1, lab)] if dgroup.datatype != 'xas': pchoice = PlotOne_Choices_nonxas[ self.plotone_op.GetStringSelection()] dgroup.plot_xlabel = 'x' dgroup.plot_ylabel = 'y' dgroup.plot_yarrays = [('ydat', PLOTOPTS_1, 'ydat')] dgroup.dmude = np.gradient(dgroup.ydat) / np.gradient(dgroup.xdat) if pchoice == 'dmude': dgroup.plot_ylabel = 'dy/dx' dgroup.plot_yarrays = [('dmude', PLOTOPTS_1, 'dy/dx')] elif pchoice == 'norm+deriv': lab = plotlabels.norm dgroup.plot_y2label = 'dy/dx' dgroup.plot_yarrays = [('ydat', PLOTOPTS_1, 'y'), ('dmude', PLOTOPTS_D, 'dy/dx')] return pchoice = PlotOne_Choices[self.plotone_op.GetStringSelection()] if pchoice in ('mu', 'norm', 'flat', 'dmude'): lab = getattr(plotlabels, pchoice) dgroup.plot_yarrays = [(pchoice, PLOTOPTS_1, lab)] elif pchoice == 'prelines': dgroup.plot_yarrays = [('mu', PLOTOPTS_1, lab), ('pre_edge', PLOTOPTS_2, 'pre edge'), ('post_edge', PLOTOPTS_2, 'post edge')] elif pchoice == 'preedge': dgroup.pre_edge_sub = dgroup.norm * dgroup.edge_step dgroup.plot_yarrays = [('pre_edge_sub', PLOTOPTS_1, r'pre-edge subtracted $\mu$')] lab = r'pre-edge subtracted $\mu$' elif pchoice == 'norm+deriv': lab = plotlabels.norm lab2 = plotlabels.dmude dgroup.plot_yarrays = [('norm', PLOTOPTS_1, lab), ('dmude', PLOTOPTS_D, lab2)] dgroup.plot_y2label = lab2 elif pchoice == 'deconv' and hasattr(dgroup, 'deconv'): lab = plotlabels.deconv dgroup.plot_yarrays = [('deconv', PLOTOPTS_1, lab)] elif pchoice == 'deconv+norm' and hasattr(dgroup, 'deconv'): lab1 = plotlabels.norm lab2 = plotlabels.deconv dgroup.plot_yarrays = [('deconv', PLOTOPTS_1, lab2), ('norm', PLOTOPTS_1, lab1)] lab = lab1 + ' + ' + lab2 dgroup.plot_ylabel = lab y4e0 = dgroup.ydat = getattr(dgroup, dgroup.plot_yarrays[0][0], dgroup.mu) dgroup.plot_extras = [] if form['show_e0']: ie0 = index_of(dgroup.energy, dgroup.e0) dgroup.plot_extras.append(('marker', dgroup.e0, y4e0[ie0], {})) def plot(self, dgroup, title=None, plot_yarrays=None, delay_draw=False, new=True, zoom_out=True, with_extras=True, **kws): self.get_plot_arrays(dgroup) ppanel = self.controller.get_display(stacked=False).panel viewlims = ppanel.get_viewlimits() plotcmd = ppanel.oplot if new: plotcmd = ppanel.plot groupname = dgroup.groupname if not hasattr(dgroup, 'xdat'): print("Cannot plot group ", groupname) if ((getattr(dgroup, 'plot_yarrays', None) is None or getattr(dgroup, 'energy', None) is None or getattr(dgroup, 'mu', None) is None)): self.process(dgroup) if plot_yarrays is None and hasattr(dgroup, 'plot_yarrays'): plot_yarrays = dgroup.plot_yarrays popts = kws path, fname = os.path.split(dgroup.filename) if not 'label' in popts: popts['label'] = dgroup.plot_ylabel zoom_out = (zoom_out or min(dgroup.xdat) >= viewlims[1] or max(dgroup.xdat) <= viewlims[0] or min(dgroup.ydat) >= viewlims[3] or max(dgroup.ydat) <= viewlims[2]) if not zoom_out: popts['xmin'] = viewlims[0] popts['xmax'] = viewlims[1] popts['ymin'] = viewlims[2] popts['ymax'] = viewlims[3] popts['xlabel'] = dgroup.plot_xlabel popts['ylabel'] = dgroup.plot_ylabel if getattr(dgroup, 'plot_y2label', None) is not None: popts['y2label'] = dgroup.plot_y2label plot_extras = None if new: if title is None: title = fname plot_extras = getattr(dgroup, 'plot_extras', None) popts['title'] = title popts['delay_draw'] = delay_draw if hasattr(dgroup, 'custom_plotopts'): popts.update(dgroup.custom_plotopts) narr = len(plot_yarrays) - 1 for i, pydat in enumerate(plot_yarrays): yaname, yopts, yalabel = pydat popts.update(yopts) if yalabel is not None: popts['label'] = yalabel popts['delay_draw'] = delay_draw or (i != narr) # print("plot:: ", i, popts['delay_draw'], plotcmd) # print(popts) plotcmd(dgroup.xdat, getattr(dgroup, yaname), **popts) plotcmd = ppanel.oplot if with_extras and plot_extras is not None: axes = ppanel.axes for etype, x, y, opts in plot_extras: if etype == 'marker': xpopts = { 'marker': 'o', 'markersize': 4, 'label': '_nolegend_', 'markerfacecolor': 'red', 'markeredgecolor': '#884444' } xpopts.update(opts) axes.plot([x], [y], **xpopts) elif etype == 'vline': xpopts = { 'ymin': 0, 'ymax': 1.0, 'label': '_nolegend_', 'color': '#888888' } xpopts.update(opts) axes.axvline(x, **xpopts) if not popts['delay_draw']: ppanel.canvas.draw()
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 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)