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 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 DemoFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, 'wxutil demo', style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL) self.SetTitle('wxutil demo') self.SetFont(Font(11)) self.set_menu() self.statusbar = self.CreateStatusBar(2, 1) self.statusbar.SetStatusWidths([-2, -1]) statusbar_fields = ['Initializing....', ' '] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) self.Bind(wx.EVT_CLOSE, self.onExit) panel = GridPanel(self, nrows=8, ncols=4) tctrl_name = TextCtrl(panel, value='', action=self.onName, size=(250, -1)) lctrl_addr = LabeledTextCtrl(self, value='<>', action=self.onAddr, labeltext=' Address: ', size=(250, -1)) lab3 = HyperText(panel, ' FloatCtrl: ', size=(100, -1), action=self.onHyperText) val3 = FloatCtrl(panel, '3', action=self.onFloat1, precision=2, minval=0, maxval=1000, size=(250, -1)) lab4 = HyperText(panel, ' FloatSpin: ', size=(100, -1), action=self.onHyperText) val4 = FloatSpin(panel, '12.2', action=self.onFloatSpin, digits=2, increment=0.1, size=(250, -1)) labx = HyperText(panel, ' NumericCombo: ', size=(100, -1), action=self.onHyperText) steps = make_steps(prec=1, tmin=0, tmax=100) valx = NumericCombo(panel, steps, precision=1) self.choice1 = Choice(panel, size=(200, -1), action=self.onChoice) self.choice1.SetChoices(['Apple', 'Banana', 'Cherry']) yesno = YesNo(panel) check1 = Check(panel, label='enable? ', action=self.onCheck) btn1 = Button(panel, label='Start', size=(100, -1), action=self.onStart) pinbtn = BitmapButton(panel, get_icon('pin'), size=(50, -1), action=partial(self.onBMButton, opt='pin1'), tooltip='use last point selected from plot') togbtn = ToggleButton(panel, 'Press Me', action=self.onToggleButton, size=(100, -1), tooltip='do it, do it now, you will like it') browse_btn = Button(panel, 'Open File', action=self.onFileOpen, size=(150, -1)) okcancel = OkCancel(panel, onOK=self.onOK, onCancel=self.onCancel) ptable_btn = Button(panel, 'Show Periodic Table', action=self.onPTable, size=(175, -1)) edlist_btn = Button(panel, 'Show Editable Listbox', action=self.onEdList, size=(175, -1)) filelist_btn = Button(panel, 'Show File CheckList', action=self.onFileList, size=(175, -1)) panel.AddText(' Name: ', style=LEFT) panel.Add(tctrl_name, dcol=2) panel.Add(lctrl_addr.label, newrow=True) panel.Add(lctrl_addr, dcol=2) panel.Add(lab3, newrow=True) panel.Add(val3, dcol=3) panel.Add(lab4, newrow=True) panel.Add(val4, dcol=3) panel.Add(labx, newrow=True) panel.Add(valx, dcol=3) panel.AddText(' Choice : ', newrow=True) panel.Add(check1) panel.Add(self.choice1) panel.AddText(' Yes or No: ', newrow=True) panel.Add(yesno) panel.Add(HLine(panel, size=(500, -1)), dcol=3, newrow=True) panel.Add(btn1, newrow=True) panel.Add(pinbtn) panel.Add(togbtn) panel.Add(browse_btn, newrow=True) panel.Add(ptable_btn) panel.Add(edlist_btn, newrow=True) panel.Add(filelist_btn) panel.Add(okcancel, newrow=True) panel.pack() self.timer = wx.Timer(self) self.last_time = time.time() self.Bind(wx.EVT_TIMER, self.onTimer, self.timer) fsizer = wx.BoxSizer(wx.VERTICAL) fsizer.Add(panel, 0, LEFT | wx.EXPAND) wx.CallAfter(self.init_timer) psize = panel.GetBestSize() self.SetSize((psize[0] + 5, psize[1] + 25)) pack(self, fsizer) self.Refresh() def init_timer(self): self.timer.Start(500) def onTimer(self, event): idle_time = (time.time() - self.last_time) msg = "Time remaining = %.1f sec" % (30 - idle_time) self.statusbar.SetStatusText(msg, 1) if (time.time() - self.last_time) > 30: print("quitting...") self.onExit() def report(self, reason, value): self.statusbar.SetStatusText("%s: %s" % (reason, value), 0) self.last_time = time.time() def set_menu(self): menu = wx.Menu() mexit = MenuItem(self, menu, "Q&uit", "Quit Program", self.onExit) menubar = wx.MenuBar() menubar.Append(menu, "&File") self.SetMenuBar(menubar) def onOK(self, event=None): self.report("on OK: ", '') def onCancel(self, event=None): self.report("on Cancel: ", '') def onName(self, event=None): self.report("on Name: ", event) def onAddr(self, event=None): self.report("on Addr: ", event) def onHyperText(self, event=None, label=None): self.report("on HyperText ", label) def onFloat1(self, value=None): self.report("on Float1 ", value) def onFloatSpin(self, event=None): self.report("on FloatSpin ", event.GetString()) def onChoice(self, event=None): self.report("on Choice ", event.GetString()) def onCheck(self, event=None): self.report("on Check ", event.IsChecked()) self.choice1.Enable(event.IsChecked()) def onStart(self, event=None): self.report("on Start Button ", '') def onBMButton(self, event=None, opt='xxx'): self.report("on Bitmap Button ", opt) def onToggleButton(self, event=None): self.report(" on Toggle Button %s " % event.GetString(), event.IsChecked()) def onPTable(self, event=None): PTableFrame(fontsize=10).Show() def onEdList(self, event=None): frame = wx.Frame(self) edlist = EditableListBox(frame, self.onEdListSelect) edlist.Append(" Item 1 ") edlist.Append(" Item 2 ") edlist.Append(" Next ") sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(edlist, 1, wx.EXPAND | wx.ALL, 5) pack(frame, sizer) frame.Show() frame.Raise() def onEdListSelect(self, event=None, **kws): self.report(" Editable List selected ", event.GetString()) def onFileList(self, event=None): frame = wx.Frame(self) edlist = FileCheckList(frame, select_action=self.onFileListSelect) for i in range(8): edlist.Append("File.%3.3d" % (i + 1)) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(edlist, 1, wx.EXPAND | wx.ALL, 5) pack(frame, sizer) frame.Show() frame.Raise() def onFileListSelect(self, event=None, **kws): self.report(" File List selected ", event.GetString()) def onFileOpen(self, event=None): wildcards = "%s|%s" % (PY_FILES, ALL_FILES) dlg = wx.FileDialog(self, message='Select File', wildcard=wildcards, style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: path = os.path.abspath(dlg.GetPath()) self.report("file ", path) dlg.Destroy() def onExit(self, event=None): self.Destroy()