def createMainPanel(self): display0 = wx.Display(0) client_area = display0.ClientArea xmin, ymin, xmax, ymax = client_area xpos = int((xmax-xmin)*0.02) + xmin ypos = int((ymax-ymin)*0.04) + ymin self.SetPosition((xpos, ypos)) splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(250) leftpanel = wx.Panel(splitter) ltop = wx.Panel(leftpanel) def Btn(msg, x, act): b = Button(ltop, msg, size=(x, 30), action=act) b.SetFont(Font(FONTSIZE)) return b sel_none = Btn('Select None', 120, self.onSelNone) sel_all = Btn('Select All', 120, self.onSelAll) self.controller.filelist = FileCheckList(leftpanel, # main=self, select_action=self.ShowFile, remove_action=self.RemoveFile) tsizer = wx.BoxSizer(wx.HORIZONTAL) tsizer.Add(sel_all, 1, LCEN|wx.GROW, 1) tsizer.Add(sel_none, 1, LCEN|wx.GROW, 1) pack(ltop, tsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(ltop, 0, LCEN|wx.GROW, 1) sizer.Add(self.controller.filelist, 1, LCEN|wx.GROW|wx.ALL, 1) pack(leftpanel, sizer) # right hand side panel = wx.Panel(splitter) sizer = wx.BoxSizer(wx.VERTICAL) self.title = SimpleText(panel, 'initializing...', size=(300, -1)) self.title.SetFont(Font(FONTSIZE+2)) ir = 0 sizer.Add(self.title, 0, LCEN|wx.GROW|wx.ALL, 1) self.nb = flatnotebook(panel, NB_PANELS, panelkws=dict(controller=self.controller), on_change=self.onNBChanged) sizer.Add(self.nb, 1, LCEN|wx.EXPAND, 2) pack(panel, sizer) splitter.SplitVertically(leftpanel, panel, 1) wx.CallAfter(self.init_larch)
def build_display(self): """build display""" self.panel.Add(SimpleText(self.panel, self.title, **titleopts), dcol=7) self.panel.Add(SimpleText(self.panel, ' coming soon....'), dcol=7, newrow=True) self.panel.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.panel, 1, wx.LEFT|wx.CENTER, 3) pack(self, sizer)
def add_text(text, dcol=1, newrow=True): pan.Add(SimpleText(pan, text), dcol=dcol, newrow=newrow)
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.wids = {} def FloatSpinWithPin(name, value, **kws): s = wx.BoxSizer(wx.HORIZONTAL) self.wids[name] = FloatSpin(pan, value=value, **kws) bb = BitmapButton(pan, get_icon('pin'), size=(25, 25), action=partial(self.onSelPoint, opt=name), tooltip='use last point selected from plot') s.Add(self.wids[name]) s.Add(bb) return s opts = dict(digits=2, increment=0.1) ppeak_e0 = FloatSpinWithPin('ppeak_e0', value=0, **opts) ppeak_elo = FloatSpinWithPin('ppeak_elo', value=-15, **opts) ppeak_ehi = FloatSpinWithPin('ppeak_ehi', value=-5, **opts) ppeak_emin = FloatSpinWithPin('ppeak_emin', value=-30, **opts) ppeak_emax = FloatSpinWithPin('ppeak_emax', value=0, **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=(150, -1), choices=list(Array_Choices.keys())) self.array_choice.SetSelection(1) models_peaks = Choice(pan, size=(150, -1), choices=ModelChoices['peaks'], action=self.addModel) models_other = Choice(pan, size=(150, -1), choices=ModelChoices['other'], action=self.addModel) self.plot_choice = Choice(pan, size=(150, -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) def add_text(text, dcol=1, newrow=True): pan.Add(SimpleText(pan, text), dcol=dcol, newrow=newrow) titleopts = dict(font=Font(12), colour='#AA0000') pan.Add(SimpleText(pan, ' Pre-edge Peak Fitting', **titleopts), dcol=5) add_text(' Run Fit:', newrow=False) add_text('Array to fit: ') pan.Add(self.array_choice, dcol=3) pan.Add((10, 10)) pan.Add(self.fitbline_btn) add_text('E0: ') pan.Add(ppeak_e0) pan.Add((10, 10), dcol=2) pan.Add(self.show_e0) pan.Add(self.fitmodel_btn) add_text('Fit Energy Range: ') pan.Add(ppeak_emin) add_text(' : ', newrow=False) pan.Add(ppeak_emax) pan.Add(self.show_fitrange) 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(ppeak_elo) add_text(' : ', newrow=False) pan.Add(ppeak_ehi) pan.Add(self.show_peakrange) add_text( 'Peak Centroid: ') pan.Add(self.msg_centroid, dcol=3) 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)
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(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.wids = {} def FloatSpinWithPin(name, value, **kws): s = wx.BoxSizer(wx.HORIZONTAL) self.wids[name] = FloatSpin(pan, value=value, **kws) bb = BitmapButton(pan, get_icon('pin'), size=(25, 25), action=partial(self.onSelPoint, opt=name), tooltip='use last point selected from plot') s.Add(self.wids[name]) s.Add(bb) return s opts = dict(digits=2, increment=0.1) ppeak_e0 = FloatSpinWithPin('ppeak_e0', value=0, **opts) ppeak_elo = FloatSpinWithPin('ppeak_elo', value=-15, **opts) ppeak_ehi = FloatSpinWithPin('ppeak_ehi', value=-5, **opts) ppeak_emin = FloatSpinWithPin('ppeak_emin', value=-30, **opts) ppeak_emax = FloatSpinWithPin('ppeak_emax', value=0, **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=(150, -1), choices=list(Array_Choices.keys())) self.array_choice.SetSelection(1) models_peaks = Choice(pan, size=(150, -1), choices=ModelChoices['peaks'], action=self.addModel) models_other = Choice(pan, size=(150, -1), choices=ModelChoices['other'], action=self.addModel) self.plot_choice = Choice(pan, size=(150, -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) def add_text(text, dcol=1, newrow=True): pan.Add(SimpleText(pan, text), dcol=dcol, newrow=newrow) titleopts = dict(font=Font(12), colour='#AA0000') pan.Add(SimpleText(pan, ' Pre-edge Peak Fitting', **titleopts), dcol=5) add_text(' Run Fit:', newrow=False) add_text('Array to fit: ') pan.Add(self.array_choice, dcol=3) pan.Add((10, 10)) pan.Add(self.fitbline_btn) add_text('E0: ') pan.Add(ppeak_e0) pan.Add((10, 10), dcol=2) pan.Add(self.show_e0) pan.Add(self.fitmodel_btn) add_text('Fit Energy Range: ') pan.Add(ppeak_emin) add_text(' : ', newrow=False) pan.Add(ppeak_emax) pan.Add(self.show_fitrange) 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(ppeak_elo) add_text(' : ', newrow=False) pan.Add(ppeak_ehi) pan.Add(self.show_peakrange) add_text( 'Peak Centroid: ') pan.Add(self.msg_centroid, dcol=3) 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 = dict(e0 = dgroup.e0, elo=-10, ehi=-5, emin=-40, emax=0, yarray='norm') dgroup.prepeak_config = conf if not hasattr(dgroup, 'prepeaks'): dgroup.prepeaks = Group() return conf def fill_form(self, dat): if isinstance(dat, Group): self.wids['ppeak_e0'].SetValue(dat.e0) if hasattr(dat, 'prepeaks'): self.wids['ppeak_emin'].SetValue(dat.prepeaks.emin) self.wids['ppeak_emax'].SetValue(dat.prepeaks.emax) self.wids['ppeak_elo'].SetValue(dat.prepeaks.elo) self.wids['ppeak_ehi'].SetValue(dat.prepeaks.ehi) elif instance(dat, dict): self.wids['ppeak_e0'].SetValue(dat['e0']) self.wids['ppeak_emin'].SetValue(dat['emin']) self.wids['ppeak_emax'].SetValue(dat['emax']) self.wids['ppeak_elo'].SetValue(dat['elo']) self.wids['ppeak_ehi'].SetValue(dat['ehi']) self.array_choice.SetStringSelection(dat['array_desc']) self.show_e0.Enable(dat['show_e0']) self.show_centroid.Enable(dat['show_centroid']) self.show_fitrange.Enable(dat['show_fitrange']) self.show_peakrange.Enable(dat['show_peakrange']) self.plot_sub_bline.Enable(dat['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.wids['ppeak_e0'].GetValue() form_opts['emin'] = self.wids['ppeak_emin'].GetValue() form_opts['emax'] = self.wids['ppeak_emax'].GetValue() form_opts['elo'] = self.wids['ppeak_elo'].GetValue() form_opts['ehi'] = self.wids['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(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(win=2, 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=2, nrows=5, pad=2, 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() 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() 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() 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(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 onSelPoint(self, evt=None, opt='__', relative_e0=False, win=None): """ get last selected point from a specified plot window and fill in the value for the widget defined by `opt`. by default it finds the latest cursor position from the cursor history of the first 20 plot windows. """ if opt not in self.wids: return None _x, _y = last_cursor_pos(win=win, _larch=self.larch) if _x is not None: if relative_e0 and 'e0' in self.wids: _x -= self.wids['e0'].GetValue() self.wids[opt].SetValue(_x) 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('prepeak_result_frame', FitResultFrame, datagroup=dgroup, peakframe=self) self.parent.subframes['prepeak_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 PrePeakPanel(TaskPanel): def __init__(self, parent=None, controller=None, **kws): TaskPanel.__init__(self, parent, controller, configname='prepeaks_config', config=defaults, **kws) self.fit_components = OrderedDict() self.user_added_params = None 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) self.fill_form(dgroup) except: pass # print(" Cannot Fill prepeak panel from group ") def build_display(self): self.mod_nb = flatnotebook(self, {}) pan = self.panel = GridPanel(self, ncols=4, nrows=4, pad=2, itemstyle=LEFT) self.wids = {} fsopts = dict(digits=2, increment=0.1, with_pin=True) ppeak_e0 = self.add_floatspin('ppeak_e0', value=0, **fsopts) ppeak_elo = self.add_floatspin('ppeak_elo', value=-15, **fsopts) ppeak_ehi = self.add_floatspin('ppeak_ehi', value=-5, **fsopts) ppeak_emin = self.add_floatspin('ppeak_emin', value=-30, **fsopts) ppeak_emax = self.add_floatspin('ppeak_emax', value=0, **fsopts) self.fitbline_btn = Button(pan,'Fit Baseline', action=self.onFitBaseline, size=(125, -1)) self.plotmodel_btn = Button(pan, 'Plot Model', action=self.onPlotModel, size=(125, -1)) self.fitmodel_btn = Button(pan, 'Fit Model', action=self.onFitModel, size=(125, -1)) self.loadmodel_btn = Button(pan, 'Load Model', action=self.onLoadFitResult, size=(125, -1)) self.fitmodel_btn.Disable() self.array_choice = Choice(pan, size=(175, -1), choices=list(Array_Choices.keys())) self.array_choice.SetSelection(1) models_peaks = Choice(pan, size=(150, -1), choices=ModelChoices['peaks'], action=self.addModel) models_other = Choice(pan, size=(150, -1), choices=ModelChoices['other'], action=self.addModel) self.models_peaks = models_peaks self.models_other = models_other 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) def add_text(text, dcol=1, newrow=True): pan.Add(SimpleText(pan, text), dcol=dcol, newrow=newrow) pan.Add(SimpleText(pan, ' Pre-edge Peak Fitting', **self.titleopts), dcol=5) add_text(' Run Fit:', newrow=False) add_text('Array to fit: ') pan.Add(self.array_choice, dcol=3) pan.Add((10, 10)) pan.Add(self.fitbline_btn) add_text('E0: ') pan.Add(ppeak_e0) pan.Add((10, 10), dcol=2) pan.Add(self.show_e0) pan.Add(self.plotmodel_btn) add_text('Fit Energy Range: ') pan.Add(ppeak_emin) add_text(' : ', newrow=False) pan.Add(ppeak_emax) pan.Add(self.show_fitrange) pan.Add(self.fitmodel_btn) t = SimpleText(pan, 'Pre-edge Peak Range: ') SetTip(t, 'Range used as mask for background') pan.Add(t, newrow=True) pan.Add(ppeak_elo) add_text(' : ', newrow=False) pan.Add(ppeak_ehi) pan.Add(self.show_peakrange) # pan.Add(self.fitsel_btn) add_text( 'Peak Centroid: ') pan.Add(self.msg_centroid, dcol=3) pan.Add(self.show_centroid, dcol=1) pan.Add(self.loadmodel_btn) # 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((10, 10), 0, LEFT, 3) sizer.Add(pan, 0, LEFT, 3) sizer.Add((10, 10), 0, LEFT, 3) sizer.Add(HLine(self, size=(550, 2)), 0, LEFT, 3) sizer.Add((10, 10), 0, LEFT, 3) sizer.Add(self.mod_nb, 1, LEFT|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 = defaults conf['e0'] = getattr(dgroup, 'e0', -1) dgroup.prepeak_config = conf if not hasattr(dgroup, 'prepeaks'): dgroup.prepeaks = Group() return conf def fill_form(self, dat): if isinstance(dat, Group): self.wids['ppeak_e0'].SetValue(dat.e0) if hasattr(dat, 'prepeaks'): self.wids['ppeak_emin'].SetValue(dat.prepeaks.emin) self.wids['ppeak_emax'].SetValue(dat.prepeaks.emax) self.wids['ppeak_elo'].SetValue(dat.prepeaks.elo) self.wids['ppeak_ehi'].SetValue(dat.prepeaks.ehi) elif isinstance(dat, dict): self.wids['ppeak_e0'].SetValue(dat['e0']) self.wids['ppeak_emin'].SetValue(dat['emin']) self.wids['ppeak_emax'].SetValue(dat['emax']) self.wids['ppeak_elo'].SetValue(dat['elo']) self.wids['ppeak_ehi'].SetValue(dat['ehi']) self.array_choice.SetStringSelection(dat['array_desc']) self.show_e0.Enable(dat['show_e0']) self.show_centroid.Enable(dat['show_centroid']) self.show_fitrange.Enable(dat['show_fitrange']) self.show_peakrange.Enable(dat['show_peakrange']) 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, 'filename': dgroup.filename, 'array_desc': array_desc.lower(), 'array_name': Array_Choices[array_desc], 'baseline_form': 'lorentzian', 'bkg_components': []} form_opts['e0'] = self.wids['ppeak_e0'].GetValue() form_opts['emin'] = self.wids['ppeak_emin'].GetValue() form_opts['emax'] = self.wids['ppeak_emax'].GetValue() form_opts['elo'] = self.wids['ppeak_elo'].GetValue() form_opts['ehi'] = self.wids['ppeak_ehi'].GetValue() form_opts['plot_sub_bline'] = False # 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 'bpeak_' not in self.fit_components: self.addModel(model='Lorentzian', prefix='bpeak_', isbkg=True) if 'bline_' not in self.fit_components: self.addModel(model='Linear', prefix='bline_', isbkg=True) for prefix in ('bpeak_', 'bline_'): cmp = self.fit_components[prefix] # cmp.bkgbox.SetValue(1) self.fill_model_params(prefix, dgroup.prepeaks.fit_details.params) self.fill_form(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(baseline_only=True) 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 onPlotModel(self, evt=None): dgroup = self.controller.get_group() g = self.build_fitmodel(dgroup) self.onPlot(show_init=True) def onPlot(self, evt=None, baseline_only=False, show_init=False): opts = self.read_form() dgroup = self.controller.get_group() opts['group'] = opts['gname'] self.larch_eval(COMMANDS['prepeaks_setup'].format(**opts)) cmd = "plot_prepeaks_fit" args = ['{gname}'] if baseline_only: cmd = "plot_prepeaks_baseline" else: args.append("show_init=%s" % (show_init)) cmd = "%s(%s)" % (cmd, ', '.join(args)) self.larch_eval(cmd.format(**opts)) 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 self.models_peaks.SetSelection(0) self.models_other.SetSelection(0) 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=2, nrows=5, 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 This Component', size=(200, -1), action=partial(self.onDeleteComponent, prefix=prefix)) pick2msg = SimpleText(panel, " ", size=(125, -1)) pick2btn = Button(panel, 'Pick Values from Plotted Data', size=(200, -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=4, style=wx.ALIGN_LEFT, newrow=True) panel.Add(usebox, dcol=2) panel.Add(bkgbox, dcol=1, style=RIGHT) panel.Add(pick2btn, dcol=2, style=wx.ALIGN_LEFT, newrow=True) panel.Add(pick2msg, dcol=3, style=wx.ALIGN_RIGHT) panel.Add(delbtn, dcol=2, style=wx.ALIGN_RIGHT) # 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=150, 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=400, 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=5, 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)) self.fitmodel_btn.Enable() 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) if len(self.fit_components) < 1: self.fitmodel_btn.Disable() # 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(win=1) 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(win=1) 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(win=1) 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 onLoadFitResult(self, event=None): dlg = wx.FileDialog(self, message="Load Saved File Model", wildcard=ModelWcards, style=wx.FD_OPEN) rfile = None if dlg.ShowModal() == wx.ID_OK: rfile = dlg.GetPath() dlg.Destroy() if rfile is None: return self.larch_eval("# peakmodel = lm_load_modelresult('%s')" %rfile) result = load_modelresult(str(rfile)) 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(result.user_options) def onSelPoint(self, evt=None, opt='__', relative_e0=False, win=None): """ get last selected point from a specified plot window and fill in the value for the widget defined by `opt`. by default it finds the latest cursor position from the cursor history of the first 20 plot windows. """ if opt not in self.wids: return None _x, _y = last_cursor_pos(win=win, _larch=self.larch) if _x is not None: if relative_e0 and 'e0' in self.wids: _x -= self.wids['e0'].GetValue() self.wids[opt].SetValue(_x) 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, dgroup): """ use fit components to build model""" # self.summary = {'components': [], 'options': {}} peaks = [] cmds = ["## set up pre-edge peak parameters", "peakpars = Parameters()"] modcmds = ["## define pre-edge peak model"] modop = " =" opts = self.read_form() opts['group'] = opts['gname'] self.larch_eval(COMMANDS['prepeaks_setup'].format(**opts)) 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(): this = parwids.param pargs = ["'%s'" % this.name, 'value=%f' % (this.value), 'min=%f' % (this.min), 'max=%f' % (this.max)] if this.expr is not None: pargs.append("expr='%s'" % (this.expr)) elif not this.vary: pargs.pop() pargs.pop() pargs.append("vary=False") cmds.append("peakpars.add(%s)" % (', '.join(pargs))) if this.name.endswith('_center'): _cen = this.name elif parwids.param.name.endswith('_amplitude'): _amp = this.name compargs = ["%s='%s'" % (k,v) for k,v in comp.mclass_kws.items()] modcmds.append("peakmodel %s %s(%s)" % (modop, comp.mclass.__name__, ', '.join(compargs))) modop = "+=" 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]) cmds.append("peakpars.add('fit_centroid', expr='(%s)/(%s)')" % (numer, denom)) cmds.extend(modcmds) cmds.append(COMMANDS['prepfit'].format(group=dgroup.groupname, user_opts=repr(opts))) self.larch_eval("\n".join(cmds)) def onFitSelected(self, event=None): dgroup = self.controller.get_group() self.build_fitmodel(dgroup) def onFitModel(self, event=None): dgroup = self.controller.get_group() if dgroup is None: return self.build_fitmodel(dgroup) opts = self.read_form() dgroup = self.controller.get_group() opts['group'] = opts['gname'] self.larch_eval(COMMANDS['prepeaks_setup'].format(**opts)) ppeaks = dgroup.prepeaks # add bkg_component to saved user options bkg_comps = [] for label, comp in self.fit_components.items(): if comp.bkgbox.IsChecked(): bkg_comps.append(label) opts['bkg_components'] = bkg_comps imin, imax = self.get_xranges(dgroup.xdat) cmds = ["## do peak fit: "] yerr_type = 'set_yerr_const' yerr = getattr(dgroup, 'yerr', None) if yerr is None: if hasattr(dgroup, 'norm_std'): cmds.append("{group}.yerr = {group}.norm_std") yerr_type = 'set_yerr_array' elif hasattr(dgroup, 'mu_std'): cmds.append("{group}.yerr = {group}.mu_std/(1.e-15+{group}.edge_step)") yerr_type = 'set_yerr_array' else: cmds.append("{group}.yerr = 1") elif isinstance(dgroup.yerr, np.ndarray): yerr_type = 'set_yerr_array' cmds.extend([COMMANDS[yerr_type], COMMANDS['dofit']]) cmd = '\n'.join(cmds) self.larch_eval(cmd.format(group=dgroup.groupname, imin=imin, imax=imax, user_opts=repr(opts))) self.autosave_modelresult(self.larch_get("peakresult")) self.onPlot() self.show_subframe('prepeak_result_frame', FitResultFrame, datagroup=dgroup, peakframe=self) self.subframes['prepeak_result_frame'].show_results() 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""" confdir = os.path.join(site_config.usr_larchdir, 'xas_viewer') if not os.path.exists(confdir): try: os.makedirs(confdir) except OSError: print("Warning: cannot create XAS_Viewer user folder") return if not HAS_MODELSAVE: print("Warning: cannot save model results: upgrade lmfit") return if fname is None: fname = 'autosave.fitmodel' save_modelresult(result, os.path.join(confdir, fname))
class XASFrame(wx.Frame): _about = """Larch XAS GUI: XAS Visualization and Analysis Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, parent=None, _larch=None, **kws): wx.Frame.__init__(self, parent, -1, size=XASVIEW_SIZE, style=FRAMESTYLE) self.last_array_sel = {} self.paths2read = [] title = "Larch XAS GUI: XAS Visualization and Analysis" self.larch_buffer = parent if not isinstance(parent, LarchFrame): self.larch_buffer = LarchFrame(_larch=_larch) self.larch_buffer.Show() self.larch_buffer.Raise() self.larch = self.larch_buffer.larchshell self.larch.symtable._sys.xas_viewer = Group() self.controller = XASController(wxparent=self, _larch=self.larch) self.current_filename = None self.subframes = {} self.plotframe = None self.SetTitle(title) self.SetSize(XASVIEW_SIZE) self.SetFont(Font(FONTSIZE)) self.larch_buffer.Hide() self.createMainPanel() self.createMenus() self.statusbar = self.CreateStatusBar(2, 0) self.statusbar.SetStatusWidths([-3, -1]) statusbar_fields = ["Initializing....", " "] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) def createMainPanel(self): display0 = wx.Display(0) client_area = display0.ClientArea xmin, ymin, xmax, ymax = client_area xpos = int((xmax - xmin) * 0.02) + xmin ypos = int((ymax - ymin) * 0.04) + ymin self.SetPosition((xpos, ypos)) splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(250) leftpanel = wx.Panel(splitter) ltop = wx.Panel(leftpanel) def Btn(msg, x, act): b = Button(ltop, msg, size=(x, 30), action=act) b.SetFont(Font(FONTSIZE)) return b sel_none = Btn('Select None', 120, self.onSelNone) sel_all = Btn('Select All', 120, self.onSelAll) self.controller.filelist = FileCheckList( leftpanel, # main=self, select_action=self.ShowFile, remove_action=self.RemoveFile) tsizer = wx.BoxSizer(wx.HORIZONTAL) tsizer.Add(sel_all, 1, LCEN | wx.GROW, 1) tsizer.Add(sel_none, 1, LCEN | wx.GROW, 1) pack(ltop, tsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(ltop, 0, LCEN | wx.GROW, 1) sizer.Add(self.controller.filelist, 1, LCEN | wx.GROW | wx.ALL, 1) pack(leftpanel, sizer) # right hand side panel = wx.Panel(splitter) sizer = wx.BoxSizer(wx.VERTICAL) self.title = SimpleText(panel, 'initializing...', size=(300, -1)) self.title.SetFont(Font(FONTSIZE + 1)) ir = 0 sizer.Add(self.title, 0, LCEN | wx.GROW | wx.ALL, 1) self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE) self.nb.SetTabAreaColour(wx.Colour(250, 250, 250)) self.nb.SetActiveTabColour(wx.Colour(254, 254, 195)) self.nb.SetNonActiveTabTextColour(wx.Colour(10, 10, 128)) self.nb.SetActiveTabTextColour(wx.Colour(128, 0, 0)) self.nb_panels = [] for name, creator in NB_PANELS: _panel = creator(parent=self, controller=self.controller) self.nb.AddPage(_panel, " %s " % name, True) self.nb_panels.append(_panel) sizer.Add(self.nb, 1, LCEN | wx.EXPAND, 2) self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onNBChanged) self.nb.SetSelection(0) pack(panel, sizer) splitter.SplitVertically(leftpanel, panel, 1) wx.CallAfter(self.init_larch) def onNBChanged(self, event=None): idx = self.nb.GetSelection() pan = self.nb_panels[idx] callback = getattr(pan, 'onPanelExposed', None) if callable(callback): callback() def onSelAll(self, event=None): self.controller.filelist.SetCheckedStrings( self.controller.file_groups.keys()) def onSelNone(self, event=None): self.controller.filelist.SetCheckedStrings([]) def init_larch(self): self.SetStatusText('initializing Larch') self.title.SetLabel('') self.controller.init_larch() plotframe = self.controller.get_display(stacked=False) xpos, ypos = self.GetPosition() xsiz, ysiz = self.GetSize() plotframe.SetPosition((xpos + xsiz + 5, ypos)) plotframe.SetSize((ysiz, ysiz)) self.SetStatusText('ready') self.Raise() def write_message(self, s, panel=0): """write a message to the Status Bar""" self.SetStatusText(s, panel) def RemoveFile(self, fname=None, **kws): if fname is not None: s = str(fname) if s in self.controller.file_groups: group = self.controller.file_groups.pop(s) def ShowFile(self, evt=None, groupname=None, process=True, plot=True, **kws): filename = None if evt is not None: filename = str(evt.GetString()) if groupname is None and filename is not None: groupname = self.controller.file_groups[filename] if not hasattr(self.larch.symtable, groupname): return dgroup = self.controller.get_group(groupname) if filename is None: filename = dgroup.filename self.title.SetLabel(filename) self.current_filename = filename self.controller.group = dgroup self.controller.groupname = groupname cur_panel = self.nb_panels[self.nb.GetSelection()] if process: cur_panel.fill_form(dgroup=dgroup) cur_panel.process(dgroup=dgroup) if plot and hasattr(cur_panel, 'plot'): cur_panel.plot(dgroup=dgroup) def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() # fmenu = wx.Menu() group_menu = wx.Menu() data_menu = wx.Menu() ppeak_menu = wx.Menu() m = {} MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Open Data File", self.onReadDialog) MenuItem(self, fmenu, "&Save Project\tCtrl+S", "Save Session to Project File", self.onSaveProject) MenuItem(self, fmenu, "Export Selected Groups to Athena Project", "Export Selected Groups to Athena Project", self.onExportAthena) MenuItem(self, fmenu, "Export Selected Groups to CSV", "Export Selected Groups to CSV", self.onExportCSV) fmenu.AppendSeparator() MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L', 'Show Larch Programming Buffer', self.onShowLarchBuffer) MenuItem(self, fmenu, 'Save Larch Script of History\tCtrl+H', 'Save Session History as Larch Script', self.onSaveLarchHistory) if WX_DEBUG: MenuItem(self, fmenu, "&Inspect \tCtrl+J", " wx inspection tool ", self.showInspectionTool) MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) MenuItem(self, group_menu, "Copy This Group", "Copy This Group", self.onCopyGroup) MenuItem(self, group_menu, "Rename This Group", "Rename This Group", self.onRenameGroup) MenuItem(self, group_menu, "Remove Selected Groups", "Remove Selected Group", self.onRemoveGroups) MenuItem(self, group_menu, "Merge Selected Groups", "Merge Selected Groups", self.onMergeData) MenuItem(self, data_menu, "Deglitch Data", "Deglitch Data", self.onDeglitchData) MenuItem(self, data_menu, "Recalibrate Energy", "Recalibrate Energy", self.onEnergyCalibrateData) MenuItem(self, data_menu, "Smooth Data", "Smooth Data", self.onSmoothData) MenuItem(self, data_menu, "Rebin Data", "Rebin Data", self.onRebinData) MenuItem(self, data_menu, "Deconvolve Data", "Deconvolution of Data", self.onDeconvolveData) MenuItem(self, data_menu, "Correct Over-absorption", "Correct Over-absorption", self.onCorrectOverAbsorptionData) MenuItem(self, ppeak_menu, "&Read Fit Model\tCtrl+R", "Read Fit Model from File", self.onLoadFitResult) fsave = MenuItem(self, ppeak_menu, "Save Fit Model", "Save Fit Model to File", self.onSaveFitResult) fexport = MenuItem(self, ppeak_menu, "Export Data and Fit", "Export Data and Fit", self.onExportFitResult) self.afterfit_menus = (fsave, fexport) for m in self.afterfit_menus: m.Enable(False) self.menubar.Append(fmenu, "&File") self.menubar.Append(group_menu, "Groups") self.menubar.Append(data_menu, "Data") self.menubar.Append(ppeak_menu, "PreEdgePeaks") self.SetMenuBar(self.menubar) self.Bind(wx.EVT_CLOSE, self.onClose) def onShowLarchBuffer(self, evt=None): if self.larch_buffer is None: self.larch_buffer = LarchFrame(_larch=self.larch) self.larch_buffer.Show() self.larch_buffer.Raise() def onSaveLarchHistory(self, evt=None): wildcard = 'Larch file (*.lar)|*.lar|All files (*.*)|*.*' path = FileSave(self, message='Save Session History as Larch Script', wildcard=wildcard, default_file='xas_viewer_history.lar') if path is not None: self.larch._larch.input.history.save(path, session_only=True) self.SetStatusText("Wrote %s" % path, 0) def onExportCSV(self, evt=None): group_ids = self.controller.filelist.GetCheckedStrings() savegroups = [] groupnames = [] for checked in group_ids: groupname = self.controller.file_groups[str(checked)] dgroup = self.controller.get_group(groupname) savegroups.append(dgroup) groupnames.append(groupname) if len(savegroups) < 1: Popup(self, "No files selected to export to CSV", "No files selected") return deffile = "%s_%i.csv" % (groupname, len(groupnames)) wcards = 'CSV Files (*.csv)|*.cvs|All files (*.*)|*.*' outfile = FileSave(self, 'Export Selected Groups to CSV File', default_file=deffile, wildcard=wcards) if outfile is None: return groups2csv(savegroups, outfile, x='energy', y='norm', _larch=self.larch) def onExportAthena(self, evt=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(self.controller.file_groups[str(checked)]) if len(groups) < 1: Popup(self, "No files selected to export to Athena", "No files selected") return self.save_athena_project(groups[0], groups, prompt=True) def onSaveProject(self, evt=None): groups = [gname for gname in self.controller.file_groups] if len(groups) < 1: Popup(self, "No files selected to export to Athena", "No files selected") return self.save_athena_project(groups[0], groups, prompt=True) def save_athena_project(self, filename, grouplist, prompt=True): if len(grouplist) < 1: return savegroups = [self.controller.get_group(gname) for gname in grouplist] deffile = "%s_%i.prj" % (filename, len(grouplist)) wcards = 'Athena Projects (*.prj)|*.prj|All files (*.*)|*.*' outfile = FileSave(self, 'Save Groups to Athena Project File', default_file=deffile, wildcard=wcards) if outfile is None: return aprj = AthenaProject(filename=outfile, _larch=self.larch) for label, grp in zip(grouplist, savegroups): aprj.add_group(grp, label=label) aprj.save(use_gzip=True) def onConfigDataProcessing(self, event=None): pass def onNewGroup(self, datagroup): """ install and display a new group, as from 'copy / modify' Note: this is a group object, not the groupname or filename """ dgroup = datagroup self.install_group(dgroup.groupname, dgroup.filename, overwrite=False) self.ShowFile(groupname=dgroup.groupname) def onCopyGroup(self, event=None): fname = self.current_filename if fname is None: fname = self.controller.filelist.GetStringSelection() ngroup = self.controller.copy_group(fname) self.onNewGroup(ngroup) def onRenameGroup(self, event=None): fname = self.current_filename = self.controller.filelist.GetStringSelection( ) if fname is None: return dlg = RenameDialog(self, fname) res = dlg.GetResponse() dlg.Destroy() if res.ok: selected = [] for checked in self.controller.filelist.GetCheckedStrings(): selected.append(str(checked)) if self.current_filename in selected: selected.remove(self.current_filename) selected.append(res.newname) groupname = self.controller.file_groups.pop(fname) self.controller.file_groups[res.newname] = groupname self.controller.filelist.rename_item(self.current_filename, res.newname) dgroup = self.controller.get_group(groupname) dgroup.filename = self.current_filename = res.newname self.controller.filelist.SetCheckedStrings(selected) self.controller.filelist.SetStringSelection(res.newname) def onRemoveGroups(self, event=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(str(checked)) if len(groups) < 1: return dlg = RemoveDialog(self, groups) res = dlg.GetResponse() dlg.Destroy() if res.ok: filelist = self.controller.filelist all_fnames = filelist.GetItems() for fname in groups: gname = self.controller.file_groups.pop(fname) delattr(self.controller.symtable, gname) all_fnames.remove(fname) filelist.Clear() for name in all_fnames: filelist.Append(name) def onMergeData(self, event=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(self.controller.file_groups[str(checked)]) if len(groups) < 1: return outgroup = unique_name('merge', self.controller.file_groups) dlg = MergeDialog(self, groups, outgroup=outgroup) res = dlg.GetResponse() dlg.Destroy() if res.ok: fname = res.group gname = fix_varname(res.group.lower()) yname = 'norm' if res.ynorm else 'mu' self.controller.merge_groups(groups, master=res.master, yarray=yname, outgroup=gname) self.install_group(gname, fname, overwrite=False) self.controller.filelist.SetStringSelection(fname) def onDeglitchData(self, event=None): DeglitchDialog(self, self.controller).Show() def onSmoothData(self, event=None): SmoothDataDialog(self, self.controller).Show() def onRebinData(self, event=None): RebinDataDialog(self, self.controller).Show() def onCorrectOverAbsorptionData(self, event=None): OverAbsorptionDialog(self, self.controller).Show() def onEnergyCalibrateData(self, event=None): EnergyCalibrateDialog(self, self.controller).Show() def onDeconvolveData(self, event=None): DeconvolutionDialog(self, self.controller).Show() def onConfigDataFitting(self, event=None): pass def showInspectionTool(self, event=None): app = wx.GetApp() app.ShowInspectionTool() def onAbout(self, evt): dlg = wx.MessageDialog(self, self._about, "About Larch XAS GUI", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self, event): dlg = QuitDialog(self) res = dlg.GetResponse() dlg.Destroy() if not res.ok: return if res.save: groups = [gname for gname in self.controller.file_groups] if len(groups) > 0: self.save_athena_project(groups[0], groups, prompt=True) self.controller.save_config() self.controller.get_display().Destroy() if self.larch_buffer is not None: try: self.larch_buffer.Destroy() except: pass time.sleep(0.05) for nam in dir(self.larch.symtable._plotter): obj = getattr(self.larch.symtable._plotter, nam) time.sleep(0.05) try: obj.Destroy() except: pass for name, wid in self.subframes.items(): if wid is not None: try: wid.Destroy() except: pass for nam in dir(self.larch.symtable._sys.wx): obj = getattr(self.larch.symtable._sys.wx, nam) self.Destroy() def show_subframe(self, name, frameclass, **opts): shown = False if name in self.subframes: try: self.subframes[name].Raise() shown = True except: del self.subframes[name] if not shown: self.subframes[name] = frameclass(self, **opts) def onSelectColumns(self, event=None): dgroup = self.controller.get_group() self.show_subframe('readfile', ColumnDataFileFrame, group=dgroup.raw, last_array_sel=self.last_array_sel, _larch=self.larch, read_ok_cb=partial(self.onRead_OK, overwrite=True)) def onLoadFitResult(self, event=None): self.nb.SetSelection(1) self.nb_panels[1].onLoadFitResult(event=event) def onSaveFitResult(self, event=None): self.nb_panels[1].onSaveFitResult(event=event) def onExportFitResult(self, event=None): self.nb_panels[1].onExportFitResult(event=event) def onReadDialog(self, event=None): dlg = wx.FileDialog(self, message="Read Data File", defaultDir=os.getcwd(), wildcard=FILE_WILDCARDS, style=wx.FD_OPEN | wx.FD_MULTIPLE) self.paths2read = [] if dlg.ShowModal() == wx.ID_OK: self.paths2read = dlg.GetPaths() dlg.Destroy() if len(self.paths2read) < 1: return path = self.paths2read.pop(0) path = path.replace('\\', '/') do_read = True if path in self.controller.file_groups: do_read = (wx.ID_YES == Popup(self, "Re-read file '%s'?" % path, 'Re-read file?')) if do_read: self.onRead(path) def onRead(self, path): filedir, filename = os.path.split(path) if self.controller.get_config('chdir_on_fileopen'): os.chdir(filedir) self.controller.set_workdir() # check for athena projects if is_athena_project(path): kwargs = dict(filename=path, _larch=self.controller.larch, read_ok_cb=self.onReadAthenaProject_OK) self.show_subframe('athena_import', AthenaImporter, **kwargs) else: kwargs = dict(filename=path, _larch=self.larch_buffer.larchshell, last_array_sel=self.last_array_sel, read_ok_cb=self.onRead_OK) self.show_subframe('readfile', ColumnDataFileFrame, **kwargs) def onReadAthenaProject_OK(self, path, namelist): """read groups from a list of groups from an athena project file""" self.larch.eval( "_prj = read_athena('{path:s}', do_fft=False, do_bkg=False)". format(path=path)) dgroup = None script = "{group:s} = extract_athenagroup(_prj.{prjgroup:s})" for gname in namelist: this = getattr(self.larch.symtable._prj, gname) gid = str(getattr(this, 'athena_id', gname)) self.larch.eval(script.format(group=gid, prjgroup=gname)) dgroup = self.install_group(gid, gname, process=True, plot=False) self.larch.eval("del _prj") def onRead_OK(self, script, path, groupname=None, array_sel=None, overwrite=False): """ called when column data has been selected and is ready to be used overwrite: whether to overwrite the current datagroup, as when editing a datagroup """ abort_read = False filedir, filename = os.path.split(path) if not overwrite and hasattr(self.larch.symtable, groupname): newname = file2groupname(filename, symtable=self.larch.symtable) msg = """Warning: groupname '%s' already used. Will use groupname '%s' instead """ % (groupname, newname) dlg = wx.MessageDialog(self, msg, 'Warning', wx.OK | wx.CANCEL) abort_read = (wx.ID_OK != dlg.ShowModal()) dlg.Destroy() groupname = newname if abort_read: return self.larch.eval(script.format(group=groupname, path=path)) if array_sel is not None: self.last_array_sel = array_sel self.install_group(groupname, filename, overwrite=overwrite) for path in self.paths2read: path = path.replace('\\', '/') filedir, filename = os.path.split(path) gname = file2groupname(filename, symtable=self.larch.symtable) self.larch.eval(script.format(group=gname, path=path)) self.install_group(gname, filename, overwrite=True) def install_group(self, groupname, filename, overwrite=False, process=True, plot=True): """add groupname / filename to list of available data groups""" thisgroup = getattr(self.larch.symtable, groupname) thisgroup.groupname = groupname thisgroup.filename = filename datatype = getattr(thisgroup, 'datatype', 'raw') # file /group may already exist in list if filename in self.controller.file_groups and not overwrite: for i in range(1, 101): ftest = "%s (%i)" % (filename, i) if ftest not in self.controller.file_groups: filename = ftest break if filename not in self.controller.file_groups: self.controller.filelist.Append(filename) self.controller.file_groups[filename] = groupname self.nb.SetSelection(0) self.ShowFile(groupname=groupname, process=process, plot=plot) self.controller.filelist.SetStringSelection(filename) return thisgroup
class XASFrame(wx.Frame): _about = """Larch XAS GUI: XAS Visualization and Analysis Matt Newville <newville @ cars.uchicago.edu> """ def __init__(self, parent=None, _larch=None, filename=None, **kws): wx.Frame.__init__(self, parent, -1, size=XASVIEW_SIZE, style=FRAMESTYLE) self.last_array_sel = {} self.paths2read = [] title = "Larch XAS GUI: XAS Visualization and Analysis" self.larch_buffer = parent if not isinstance(parent, LarchFrame): self.larch_buffer = LarchFrame(_larch=_larch, is_standalone=False) self.larch_buffer.Show() self.larch_buffer.Raise() self.larch = self.larch_buffer.larchshell self.larch.symtable._sys.xas_viewer = Group() self.controller = XASController(wxparent=self, _larch=self.larch) self.subframes = {} self.plotframe = None self.SetTitle(title) self.SetSize(XASVIEW_SIZE) self.SetFont(Font(FONTSIZE)) self.larch_buffer.Hide() self.createMainPanel() self.createMenus() self.statusbar = self.CreateStatusBar(2, style=wx.STB_DEFAULT_STYLE) self.statusbar.SetStatusWidths([-3, -1]) statusbar_fields = [" ", "initializing...."] for i in range(len(statusbar_fields)): self.statusbar.SetStatusText(statusbar_fields[i], i) self.current_filename = filename self.Show() if filename is not None: wx.CallAfter(self.onRead, filename) def createMainPanel(self): display0 = wx.Display(0) client_area = display0.ClientArea xmin, ymin, xmax, ymax = client_area xpos = int((xmax - xmin) * 0.02) + xmin ypos = int((ymax - ymin) * 0.04) + ymin self.SetPosition((xpos, ypos)) splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(250) leftpanel = wx.Panel(splitter) ltop = wx.Panel(leftpanel) def Btn(msg, x, act): b = Button(ltop, msg, size=(x, 30), action=act) b.SetFont(Font(FONTSIZE)) return b sel_none = Btn('Select None', 120, self.onSelNone) sel_all = Btn('Select All', 120, self.onSelAll) self.controller.filelist = FileCheckList(leftpanel, select_action=self.ShowFile, remove_action=self.RemoveFile) tsizer = wx.BoxSizer(wx.HORIZONTAL) tsizer.Add(sel_all, 1, LEFT | wx.GROW, 1) tsizer.Add(sel_none, 1, LEFT | wx.GROW, 1) pack(ltop, tsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(ltop, 0, LEFT | wx.GROW, 1) sizer.Add(self.controller.filelist, 1, LEFT | wx.GROW | wx.ALL, 1) pack(leftpanel, sizer) # right hand side panel = wx.Panel(splitter) sizer = wx.BoxSizer(wx.VERTICAL) self.title = SimpleText(panel, 'initializing...', size=(300, -1)) self.title.SetFont(Font(FONTSIZE + 2)) ir = 0 sizer.Add(self.title, 0, LEFT | wx.GROW | wx.ALL, 1) self.nb = flatnotebook(panel, NB_PANELS, panelkws=dict(controller=self.controller), on_change=self.onNBChanged) sizer.Add(self.nb, 1, LEFT | wx.EXPAND, 2) pack(panel, sizer) splitter.SplitVertically(leftpanel, panel, 1) wx.CallAfter(self.init_larch) def onNBChanged(self, event=None): callback = getattr(self.nb.GetCurrentPage(), 'onPanelExposed', None) if callable(callback): callback() def onSelAll(self, event=None): self.controller.filelist.select_all() def onSelNone(self, event=None): self.controller.filelist.select_none() def init_larch(self): self.SetStatusText('initializing Larch', 1) self.title.SetLabel('') self.controller.init_larch() plotframe = self.controller.get_display(stacked=False) xpos, ypos = self.GetPosition() xsiz, ysiz = self.GetSize() plotframe.SetPosition((xpos + xsiz + 5, ypos)) plotframe.SetSize((600, 650)) self.SetStatusText('ready', 1) self.Raise() def write_message(self, msg, panel=0): """write a message to the Status Bar""" self.statusbar.SetStatusText(msg, panel) def RemoveFile(self, fname=None, **kws): if fname is not None: s = str(fname) if s in self.controller.file_groups: group = self.controller.file_groups.pop(s) def ShowFile(self, evt=None, groupname=None, process=True, plot=True, **kws): filename = None if evt is not None: filename = str(evt.GetString()) if groupname is None and filename is not None: groupname = self.controller.file_groups[filename] if not hasattr(self.larch.symtable, groupname): return dgroup = self.controller.get_group(groupname) if dgroup is None: return if filename is None: filename = dgroup.filename self.title.SetLabel(filename) self.current_filename = filename self.controller.group = dgroup self.controller.groupname = groupname cur_panel = self.nb.GetCurrentPage() if process: cur_panel.fill_form(dgroup) cur_panel.skip_process = True cur_panel.process(dgroup=dgroup) if plot and hasattr(cur_panel, 'plot'): cur_panel.plot(dgroup=dgroup) cur_panel.skip_process = False def createMenus(self): # ppnl = self.plotpanel self.menubar = wx.MenuBar() fmenu = wx.Menu() group_menu = wx.Menu() data_menu = wx.Menu() # ppeak_menu = wx.Menu() m = {} MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Open Data File", self.onReadDialog) MenuItem(self, fmenu, "&Save Project\tCtrl+S", "Save Session to Project File", self.onSaveProject) MenuItem(self, fmenu, "Export Selected Groups to Athena Project", "Export Selected Groups to Athena Project", self.onExportAthena) MenuItem(self, fmenu, "Export Selected Groups to CSV", "Export Selected Groups to CSV", self.onExportCSV) fmenu.AppendSeparator() MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L', 'Show Larch Programming Buffer', self.onShowLarchBuffer) MenuItem(self, fmenu, 'Save Larch Script of History\tCtrl+H', 'Save Session History as Larch Script', self.onSaveLarchHistory) if WX_DEBUG: MenuItem(self, fmenu, "&Inspect \tCtrl+J", " wx inspection tool ", self.showInspectionTool) MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose) MenuItem(self, group_menu, "Copy This Group", "Copy This Group", self.onCopyGroup) MenuItem(self, group_menu, "Rename This Group", "Rename This Group", self.onRenameGroup) MenuItem(self, group_menu, "Remove Selected Groups", "Remove Selected Group", self.onRemoveGroups) group_menu.AppendSeparator() MenuItem(self, group_menu, "Merge Selected Groups", "Merge Selected Groups", self.onMergeData) group_menu.AppendSeparator() MenuItem(self, group_menu, "Freeze Selected Groups", "Freeze Selected Groups", self.onFreezeGroups) MenuItem(self, group_menu, "UnFreeze Selected Groups", "UnFreeze Selected Groups", self.onUnFreezeGroups) MenuItem(self, data_menu, "Deglitch Data", "Deglitch Data", self.onDeglitchData) MenuItem(self, data_menu, "Recalibrate Energy", "Recalibrate Energy", self.onEnergyCalibrateData) MenuItem(self, data_menu, "Smooth Data", "Smooth Data", self.onSmoothData) MenuItem(self, data_menu, "Rebin Data", "Rebin Data", self.onRebinData) MenuItem(self, data_menu, "Deconvolve Data", "Deconvolution of Data", self.onDeconvolveData) MenuItem(self, data_menu, "Correct Over-absorption", "Correct Over-absorption", self.onCorrectOverAbsorptionData) MenuItem(self, data_menu, "Add and Subtract Sepctra", "Calculations of Spectra", self.onSpectraCalc) self.menubar.Append(fmenu, "&File") self.menubar.Append(group_menu, "Groups") self.menubar.Append(data_menu, "Data") # self.menubar.Append(ppeak_menu, "PreEdgePeaks") self.SetMenuBar(self.menubar) self.Bind(wx.EVT_CLOSE, self.onClose) def onShowLarchBuffer(self, evt=None): if self.larch_buffer is None: self.larch_buffer = LarchFrame(_larch=self.larch, is_standalone=False) self.larch_buffer.Show() self.larch_buffer.Raise() def onSaveLarchHistory(self, evt=None): wildcard = 'Larch file (*.lar)|*.lar|All files (*.*)|*.*' path = FileSave(self, message='Save Session History as Larch Script', wildcard=wildcard, default_file='xas_viewer_history.lar') if path is not None: self.larch._larch.input.history.save(path, session_only=True) self.write_message("Wrote history %s" % path, 0) def onExportCSV(self, evt=None): filenames = self.controller.filelist.GetCheckedStrings() if len(filenames) < 1: Popup(self, "No files selected to export to CSV", "No files selected") return dlg = ExportCSVDialog(self, filenames) res = dlg.GetResponse() dlg.Destroy() if res.ok: savegroups = [self.controller.filename2group(res.master)] for fname in filenames: dgroup = self.controller.filename2group(fname) if dgroup not in savegroups: savegroups.append(dgroup) groups2csv(savegroups, res.filename, x='energy', y=res.yarray, _larch=self.larch) self.write_message("Exported CSV file %s" % (res.filename)) def onExportAthena(self, evt=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(self.controller.file_groups[str(checked)]) if len(groups) < 1: Popup(self, "No files selected to export to Athena", "No files selected") return self.save_athena_project(groups[0], groups, prompt=True) def onSaveProject(self, evt=None): groups = [gname for gname in self.controller.file_groups] if len(groups) < 1: Popup(self, "No files selected to export to Athena", "No files selected") return self.save_athena_project(groups[0], groups, prompt=True) def save_athena_project(self, filename, grouplist, prompt=True): if len(grouplist) < 1: return savegroups = [self.controller.get_group(gname) for gname in grouplist] deffile = "%s_%i.prj" % (filename, len(grouplist)) wcards = 'Athena Projects (*.prj)|*.prj|All files (*.*)|*.*' outfile = FileSave(self, 'Save Groups to Athena Project File', default_file=deffile, wildcard=wcards) if outfile is None: return aprj = AthenaProject(filename=outfile, _larch=self.larch) for label, grp in zip(grouplist, savegroups): aprj.add_group(grp) aprj.save(use_gzip=True) self.write_message("Saved project file %s" % (outfile)) def onConfigDataProcessing(self, event=None): pass def onNewGroup(self, datagroup): """ install and display a new group, as from 'copy / modify' Note: this is a group object, not the groupname or filename """ dgroup = datagroup self.install_group(dgroup.groupname, dgroup.filename, overwrite=False) self.ShowFile(groupname=dgroup.groupname) def onCopyGroup(self, event=None): fname = self.current_filename if fname is None: fname = self.controller.filelist.GetStringSelection() ngroup = self.controller.copy_group(fname) self.onNewGroup(ngroup) def onRenameGroup(self, event=None): fname = self.current_filename = self.controller.filelist.GetStringSelection( ) if fname is None: return dlg = RenameDialog(self, fname) res = dlg.GetResponse() dlg.Destroy() if res.ok: selected = [] for checked in self.controller.filelist.GetCheckedStrings(): selected.append(str(checked)) if self.current_filename in selected: selected.remove(self.current_filename) selected.append(res.newname) groupname = self.controller.file_groups.pop(fname) self.controller.file_groups[res.newname] = groupname self.controller.filelist.rename_item(self.current_filename, res.newname) dgroup = self.controller.get_group(groupname) dgroup.filename = self.current_filename = res.newname self.controller.filelist.SetCheckedStrings(selected) self.controller.filelist.SetStringSelection(res.newname) def onRemoveGroups(self, event=None): groups = [] for checked in self.controller.filelist.GetCheckedStrings(): groups.append(str(checked)) if len(groups) < 1: return dlg = RemoveDialog(self, groups) res = dlg.GetResponse() dlg.Destroy() if res.ok: filelist = self.controller.filelist all_fnames = filelist.GetItems() for fname in groups: gname = self.controller.file_groups.pop(fname) delattr(self.controller.symtable, gname) all_fnames.remove(fname) filelist.Clear() for name in all_fnames: filelist.Append(name) def onFreezeGroups(self, event=None): self._freeze_handler(True) def onUnFreezeGroups(self, event=None): self._freeze_handler(False) def _freeze_handler(self, freeze): current_filename = self.current_filename reproc_group = None for fname in self.controller.filelist.GetCheckedStrings(): groupname = self.controller.file_groups[str(fname)] dgroup = self.controller.get_group(groupname) if fname == current_filename: reproc_group = groupname dgroup.is_frozen = freeze if reproc_group is not None: self.ShowFile(groupname=reproc_group, process=True) def onMergeData(self, event=None): groups = OrderedDict() for checked in self.controller.filelist.GetCheckedStrings(): cname = str(checked) groups[cname] = self.controller.file_groups[cname] if len(groups) < 1: return outgroup = common_startstring(list(groups.keys())) outgroup = "%s (merge %d)" % (outgroup, len(groups)) outgroup = unique_name(outgroup, self.controller.file_groups) dlg = MergeDialog(self, list(groups.keys()), outgroup=outgroup) res = dlg.GetResponse() dlg.Destroy() if res.ok: fname = res.group gname = fix_varname(res.group.lower()) master = self.controller.file_groups[res.master] yname = 'norm' if res.ynorm else 'mu' self.controller.merge_groups(list(groups.values()), master=master, yarray=yname, outgroup=gname) self.install_group(gname, fname, overwrite=False) self.controller.filelist.SetStringSelection(fname) def onDeglitchData(self, event=None): DeglitchDialog(self, self.controller).Show() def onSmoothData(self, event=None): SmoothDataDialog(self, self.controller).Show() def onRebinData(self, event=None): RebinDataDialog(self, self.controller).Show() def onCorrectOverAbsorptionData(self, event=None): OverAbsorptionDialog(self, self.controller).Show() def onSpectraCalc(self, event=None): SpectraCalcDialog(self, self.controller).Show() def onEnergyCalibrateData(self, event=None): EnergyCalibrateDialog(self, self.controller).Show() def onDeconvolveData(self, event=None): DeconvolutionDialog(self, self.controller).Show() def onConfigDataFitting(self, event=None): pass def showInspectionTool(self, event=None): app = wx.GetApp() app.ShowInspectionTool() def onAbout(self, evt): dlg = wx.MessageDialog(self, self._about, "About Larch XAS GUI", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def onClose(self, event): dlg = QuitDialog(self) dlg.Raise() dlg.SetWindowStyle(wx.STAY_ON_TOP) res = dlg.GetResponse() dlg.Destroy() if not res.ok: return if res.save: groups = [gname for gname in self.controller.file_groups] if len(groups) > 0: self.save_athena_project(groups[0], groups, prompt=True) self.controller.save_config() wx.CallAfter(self.controller.close_all_displays) if self.larch_buffer is not None: wx.CallAfter(self.larch_buffer.Destroy) for name, wid in self.subframes.items(): if hasattr(wid, 'Destroy'): wx.CallAfter(wid.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 onSelectColumns(self, event=None): dgroup = self.controller.get_group() self.show_subframe('readfile', ColumnDataFileFrame, group=dgroup.raw, last_array_sel=self.last_array_sel, _larch=self.larch, read_ok_cb=partial(self.onRead_OK, overwrite=True)) def onLoadFitResult(self, event=None): pass # print("onLoadFitResult??") # self.nb.SetSelection(1) # self.nb_panels[1].onLoadFitResult(event=event) def onReadDialog(self, event=None): dlg = wx.FileDialog(self, message="Read Data File", defaultDir=os.getcwd(), wildcard=FILE_WILDCARDS, style=wx.FD_OPEN | wx.FD_MULTIPLE) self.paths2read = [] if dlg.ShowModal() == wx.ID_OK: self.paths2read = dlg.GetPaths() dlg.Destroy() if len(self.paths2read) < 1: return path = self.paths2read.pop(0) path = path.replace('\\', '/') do_read = True if path in self.controller.file_groups: do_read = (wx.ID_YES == Popup(self, "Re-read file '%s'?" % path, 'Re-read file?')) if do_read: self.onRead(path) def onRead(self, path): filedir, filename = os.path.split(os.path.abspath(path)) if self.controller.get_config('chdir_on_fileopen'): os.chdir(filedir) self.controller.set_workdir() # check for athena projects if is_athena_project(path): kwargs = dict(filename=path, _larch=self.controller.larch, read_ok_cb=self.onReadAthenaProject_OK) self.show_subframe('athena_import', AthenaImporter, **kwargs) else: kwargs = dict(filename=path, _larch=self.larch_buffer.larchshell, last_array_sel=self.last_array_sel, read_ok_cb=self.onRead_OK) self.show_subframe('readfile', ColumnDataFileFrame, **kwargs) def onReadAthenaProject_OK(self, path, namelist): """read groups from a list of groups from an athena project file""" self.larch.eval( "_prj = read_athena('{path:s}', do_fft=False, do_bkg=False)". format(path=path)) dgroup = None script = "{group:s} = extract_athenagroup(_prj.{prjgroup:s})" cur_panel = self.nb.GetCurrentPage() cur_panel.skip_plotting = True for gname in namelist: cur_panel.skip_plotting = (gname == namelist[-1]) this = getattr(self.larch.symtable._prj, gname) gid = str(getattr(this, 'athena_id', gname)) if self.larch.symtable.has_group(gid): count, prefix = 0, gname[:3] while count < 1e7 and self.larch.symtable.has_group(gid): gid = prefix + make_hashkey(length=7) count += 1 self.larch.eval(script.format(group=gid, prjgroup=gname)) dgroup = self.install_group(gid, gname, process=True, plot=False) self.larch.eval("del _prj") cur_panel.skip_plotting = False if len(namelist) > 0: gname = self.controller.file_groups[namelist[0]] self.ShowFile(groupname=gname, process=True, plot=True) self.write_message("read %d datasets from %s" % (len(namelist), path)) def onRead_OK(self, script, path, groupname=None, filename=None, array_sel=None, overwrite=False): """ called when column data has been selected and is ready to be used overwrite: whether to overwrite the current datagroup, as when editing a datagroup """ if groupname is None: return abort_read = False filedir, real_filename = os.path.split(path) if filename is None: filename = real_filename if not overwrite and hasattr(self.larch.symtable, groupname): groupname = file2groupname(real_filename, symtable=self.larch.symtable) if abort_read: return self.larch.eval(script.format(group=groupname, path=path)) if array_sel is not None: self.last_array_sel = array_sel self.install_group(groupname, filename, overwrite=overwrite) # check if rebin is needed thisgroup = getattr(self.larch.symtable, groupname) do_rebin = False if thisgroup.datatype == 'xas': try: en = thisgroup.energy except: do_rebin = True en = thisgroup.energy = thisgroup.xdat # test for rebinning: # too many data points # unsorted energy data or data in angle # too fine a step size at the end of the data range if (len(en) > 1200 or any(np.diff(en) < 0) or ((max(en) - min(en)) > 300 and (np.diff(en[-50:]).mean() < 0.75))): msg = """This dataset may need to be rebinned. Rebin now?""" dlg = wx.MessageDialog(self, msg, 'Warning', wx.YES | wx.NO) do_rebin = (wx.ID_YES == dlg.ShowModal()) dlg.Destroy() for path in self.paths2read: path = path.replace('\\', '/') filedir, real_filename = os.path.split(path) gname = file2groupname(real_filename, symtable=self.larch.symtable) self.larch.eval(script.format(group=gname, path=path)) self.install_group(gname, real_filename, overwrite=overwrite) self.write_message("read %s" % (real_filename)) if do_rebin: RebinDataDialog(self, self.controller).Show() def install_group(self, groupname, filename, overwrite=False, process=True, rebin=False, plot=True): """add groupname / filename to list of available data groups""" thisgroup = getattr(self.larch.symtable, groupname) datatype = getattr(thisgroup, 'datatype', 'raw') # file /group may already exist in list if filename in self.controller.file_groups and not overwrite: fbase, i = filename, 0 while i < 10000 and filename in self.controller.file_groups: filename = "%s_%d" % (fbase, i) i += 1 cmds = [ "%s.groupname = '%s'" % (groupname, groupname), "%s.filename = '%s'" % (groupname, filename) ] self.larch.eval('\n'.join(cmds)) self.controller.filelist.Append(filename) self.controller.file_groups[filename] = groupname self.nb.SetSelection(0) self.ShowFile(groupname=groupname, process=process, plot=plot) self.controller.filelist.SetStringSelection(filename) return thisgroup
def build_display(self): panel = self.panel self.wids = {} self.plotone_op = Choice(panel, choices=list(PlotOne_Choices.keys()), action=self.onPlotOne, size=(200, -1)) self.plotsel_op = Choice(panel, choices=list(PlotSel_Choices.keys()), action=self.onPlotSel, size=(200, -1)) self.plotone_op.SetSelection(1) self.plotsel_op.SetSelection(1) plot_one = Button(panel, 'Plot Current Group', size=(170, -1), action=self.onPlotOne) plot_sel = Button(panel, 'Plot Selected Groups', size=(170, -1), action=self.onPlotSel) e0panel = wx.Panel(panel) self.wids['auto_e0'] = Check(e0panel, default=True, label='auto?', action=self.onSet_XASE0) self.wids['showe0'] = Check(e0panel, default=True, label='show?', action=self.onSet_XASE0) sx = wx.BoxSizer(wx.HORIZONTAL) sx.Add(self.wids['auto_e0'], 0, LEFT, 4) sx.Add(self.wids['showe0'], 0, LEFT, 4) pack(e0panel, sx) self.wids['auto_step'] = Check(panel, default=True, label='auto?', action=self.onNormMethod) self.wids['nvict'] = Choice(panel, choices=('0', '1', '2', '3'), size=(100, -1), action=self.onNormMethod, default=0) self.wids['nnorm'] = Choice(panel, choices=list(Nnorm_choices.values()), size=(100, -1), action=self.onNormMethod, default=0) opts = { 'size': (100, -1), 'digits': 2, 'increment': 5.0, 'action': self.onSet_Ranges } xas_pre1 = self.add_floatspin('pre1', value=defaults['pre1'], **opts) xas_pre2 = self.add_floatspin('pre2', value=defaults['pre2'], **opts) xas_norm1 = self.add_floatspin('norm1', value=defaults['norm1'], **opts) xas_norm2 = self.add_floatspin('norm2', value=defaults['norm2'], **opts) opts = {'digits': 3, 'increment': 0.1, 'value': 0} plot_voff = self.add_floatspin('plot_voff', with_pin=False, size=(80, -1), action=self.onVoffset, **opts) xas_e0 = self.add_floatspin('e0', action=self.onSet_XASE0Val, **opts) xas_step = self.add_floatspin('step', action=self.onSet_XASStep, with_pin=False, min_val=0.0, **opts) opts['value'] = 1.0 scale = self.add_floatspin('scale', action=self.onSet_Scale, **opts) self.wids['norm_method'] = Choice( panel, choices=('polynomial', 'mback'), # , 'area'), size=(120, -1), action=self.onNormMethod) self.wids['norm_method'].SetSelection(0) atsyms = ['?'] + self.larch.symtable._xray._xraydb.atomic_symbols edges = ('K', 'L3', 'L2', 'L1', 'M5') self.wids['atsym'] = Choice(panel, choices=atsyms, size=(75, -1)) self.wids['edge'] = Choice(panel, choices=edges, size=(60, -1)) self.wids['is_frozen'] = Check(panel, default=False, label='Freeze Group', action=self.onFreezeGroup) saveconf = Button(panel, 'Save as Default Settings', size=(200, -1), action=self.onSaveConfigBtn) use_auto = Button(panel, 'Use Default Settings', size=(200, -1), action=self.onAutoNorm) copy_auto = Button(panel, 'Copy', size=(60, -1), action=self.onCopyAuto) def CopyBtn(name): return Button(panel, 'Copy', size=(60, -1), action=partial(self.onCopyParam, name)) add_text = self.add_text HLINEWID = 575 panel.Add(SimpleText(panel, 'XAS Pre-edge subtraction and Normalization', **self.titleopts), dcol=4) panel.Add(SimpleText(panel, 'Copy to Selected Groups:'), style=RIGHT, dcol=2) panel.Add(plot_sel, newrow=True) panel.Add(self.plotsel_op, dcol=3) panel.Add(SimpleText(panel, 'Y Offset:'), style=RIGHT) panel.Add(plot_voff, style=RIGHT) panel.Add(plot_one, newrow=True) panel.Add(self.plotone_op, dcol=4) panel.Add(CopyBtn('plotone_op'), dcol=1, style=RIGHT) panel.Add(HLine(panel, size=(HLINEWID, 3)), dcol=6, newrow=True) add_text('Non-XAS Data Scale:') panel.Add(scale, dcol=2) panel.Add(HLine(panel, size=(HLINEWID, 3)), dcol=6, newrow=True) add_text('XAS Data:') panel.Add(use_auto, dcol=4) panel.Add(copy_auto, dcol=1, style=RIGHT) add_text('Element and Edge: ', newrow=True) panel.Add(self.wids['atsym']) panel.Add(self.wids['edge'], dcol=3) panel.Add(CopyBtn('atsym'), dcol=1, style=RIGHT) add_text('E0 : ') panel.Add(xas_e0) panel.Add(e0panel, dcol=3) panel.Add(CopyBtn('xas_e0'), dcol=1, style=RIGHT) add_text('Edge Step: ') panel.Add(xas_step) panel.Add(self.wids['auto_step'], dcol=3) panel.Add(CopyBtn('xas_step'), dcol=1, style=RIGHT) panel.Add((5, 5), newrow=True) panel.Add(HLine(panel, size=(HLINEWID, 3)), dcol=6, newrow=True) add_text('Pre-edge range: ') panel.Add(xas_pre1) add_text(' : ', newrow=False) panel.Add(xas_pre2, dcol=2) panel.Add(CopyBtn('xas_pre'), dcol=1, style=RIGHT) panel.Add(SimpleText(panel, 'Victoreen order:'), newrow=True) panel.Add(self.wids['nvict'], dcol=4) panel.Add((5, 5), newrow=True) panel.Add(HLine(panel, size=(HLINEWID, 3)), dcol=6, newrow=True) add_text('Normalization method: ') panel.Add(self.wids['norm_method'], dcol=4) panel.Add(CopyBtn('xas_norm'), dcol=1, style=RIGHT) add_text('Normalization range: ') panel.Add(xas_norm1) add_text(' : ', newrow=False) panel.Add(xas_norm2, dcol=2) panel.Add(SimpleText(panel, 'Polynomial Type:'), newrow=True) panel.Add(self.wids['nnorm'], dcol=4) panel.Add(HLine(panel, size=(HLINEWID, 3)), dcol=6, newrow=True) panel.Add((5, 5), newrow=True) panel.Add(self.wids['is_frozen'], newrow=True) panel.Add(saveconf, dcol=5) panel.Add((5, 5), newrow=True) panel.Add(HLine(panel, size=(HLINEWID, 3)), dcol=6, newrow=True) panel.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add((5, 5), 0, LEFT, 3) sizer.Add(panel, 0, LEFT, 3) sizer.Add((5, 5), 0, LEFT, 3) pack(self, sizer)
def build_display(self): panel = self.panel wids = self.wids self.skip_process = True wids['fitspace'] = Choice(panel, choices=FitSpace_Choices, size=(250, -1)) wids['fitspace'].SetStringSelection(norm) # wids['plotchoice'] = Choice(panel, choices=Plot_Choices, # size=(250, -1), action=self.onPlot) wids['method'] = Choice(panel, choices=Regress_Choices, size=(250, -1), action=self.onRegressMethod) add_text = self.add_text opts = dict(digits=2, increment=1.0) w_xmin = self.add_floatspin('xmin', value=defaults['xmin'], **opts) w_xmax = self.add_floatspin('xmax', value=defaults['xmax'], **opts) wids['alpha'] = NumericCombo(panel, make_steps(), fmt='%.6g', default_val=0.01, width=100) wids['auto_scale_pls'] = Check(panel, default=True, label='auto scale?') wids['auto_alpha'] = Check(panel, default=False, label='auto alpha?') wids['fit_intercept'] = Check(panel, default=True, label='fit intercept?') wids['save_csv'] = Button(panel, 'Save CSV File', size=(150, -1), action=self.onSaveCSV) wids['load_csv'] = Button(panel, 'Load CSV File', size=(150, -1), action=self.onLoadCSV) wids['save_model'] = Button(panel, 'Save Model', size=(150, -1), action=self.onSaveModel) wids['save_model'].Disable() wids['load_model'] = Button(panel, 'Load Model', size=(150, -1), action=self.onLoadModel) wids['train_model'] = Button(panel, 'Train Model From These Data', size=(275, -1), action=self.onTrainModel) wids['fit_group'] = Button(panel, 'Predict Variable for Selected Groups', size=(275, -1), action=self.onPredictGroups) wids['fit_group'].Disable() w_cvfolds = self.add_floatspin('cv_folds', digits=0, with_pin=False, value=0, increment=1, min_val=-1) w_cvreps = self.add_floatspin('cv_repeats', digits=0, with_pin=False, value=0, increment=1, min_val=-1) w_ncomps = self.add_floatspin('ncomps', digits=0, with_pin=False, value=3, increment=1, min_val=1) wids['varname'] = wx.TextCtrl(panel, -1, 'valence', size=(150, -1)) wids['stat1'] = SimpleText(panel, ' - - - ') wids['stat2'] = SimpleText(panel, ' - - - ') collabels = [' File /Group Name ', 'External Value', 'Predicted Value'] colsizes = [300, 120, 120] coltypes = ['str', 'float:12,4', 'float:12,4'] coldefs = ['', 0.0, 0.0] wids['table'] = DataTableGrid(panel, nrows=MAX_ROWS, collabels=collabels, datatypes=coltypes, defaults=coldefs, colsizes=colsizes) wids['table'].SetMinSize((625, 175)) wids['use_selected'] = Button(panel, 'Use Selected Groups', size=(150, -1), action=self.onFillTable) panel.Add(SimpleText(panel, 'Feature Regression, Model Selection', **self.titleopts), dcol=4) add_text('Array to Use: ', newrow=True) panel.Add(wids['fitspace'], dcol=4) # add_text('Plot : ', newrow=True) # panel.Add(wids['plotchoice'], dcol=3) add_text('Fit Energy Range: ') panel.Add(w_xmin) add_text(' : ', newrow=False) panel.Add(w_xmax, dcol=3) add_text('Regression Method:') panel.Add(wids['method'], dcol=4) add_text('PLS # components: ') panel.Add(w_ncomps) panel.Add(wids['auto_scale_pls'], dcol=2) add_text('Lasso Alpha: ') panel.Add(wids['alpha']) panel.Add(wids['auto_alpha'], dcol=2) panel.Add(wids['fit_intercept']) wids['alpha'].Disable() wids['auto_alpha'].Disable() wids['fit_intercept'].Disable() add_text('Cross Validation: ') add_text(' # folds, # repeats: ', newrow=False) panel.Add(w_cvfolds, dcol=2) panel.Add(w_cvreps) panel.Add(HLine(panel, size=(600, 2)), dcol=6, newrow=True) add_text('Build Model: ', newrow=True) panel.Add(wids['use_selected'], dcol=2) add_text('Attribute Name: ', newrow=False) panel.Add(wids['varname'], dcol=4) add_text('Read/Save Data: ', newrow=True) panel.Add(wids['load_csv'], dcol=3) panel.Add(wids['save_csv'], dcol=2) panel.Add(wids['table'], newrow=True, dcol=5) # , drow=3) panel.Add(HLine(panel, size=(550, 2)), dcol=5, newrow=True) panel.Add((5, 5), newrow=True) add_text('Train Model : ') panel.Add(wids['train_model'], dcol=3) panel.Add(wids['load_model']) add_text('Use This Model : ') panel.Add(wids['fit_group'], dcol=3) panel.Add(wids['save_model']) add_text('Fit Statistics : ') panel.Add(wids['stat1'], dcol=4) panel.Add((5, 5), newrow=True) panel.Add(wids['stat2'], dcol=4) panel.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add((10, 10), 0, LEFT, 3) sizer.Add(panel, 1, LEFT, 3) pack(self, sizer) self.skip_process = False
def build_display(self): panel = self.panel wids = self.wids self.skip_process = True wids['fitspace'] = Choice(panel, choices=FitSpace_Choices, size=(175, -1)) wids['fitspace'].SetStringSelection(norm) add_text = self.add_text opts = dict(digits=2, increment=1.0, relative_e0=False) # True) elo_wids = self.add_floatspin('elo', value=defaults['elo'], **opts) ehi_wids = self.add_floatspin('ehi', value=defaults['ehi'], **opts) wids['fit_group'] = Button(panel, 'Fit this Group', size=(175, -1), action=self.onFitOne) wids['fit_selected'] = Button(panel, 'Fit Selected Groups', size=(175, -1), action=self.onFitAll) wids['add_selected'] = Button(panel, 'Use Selected Groups as Components', size=(300, -1), action=self.onUseSelected) wids['saveconf'] = Button(panel, 'Save as Default Settings', size=(225, -1), action=self.onSaveConfigBtn) opts = dict(default=True, size=(75, -1), action=self.onPlotOne) wids['show_fitrange'] = Check(panel, label='show?', **opts) wids['sum_to_one'] = Check(panel, label='Weights Must Sum to 1?', default=True) wids['all_combos'] = Check(panel, label='Fit All Combinations?', default=True) max_ncomps = self.add_floatspin('max_ncomps', value=10, digits=0, increment=1, min_val=0, max_val=20, size=(60, -1), with_pin=False) panel.Add(SimpleText(panel, ' Linear Combination Analysis', **self.titleopts), dcol=4) add_text('Array to Fit: ', newrow=True) panel.Add(wids['fitspace'], dcol=3) add_text('Fit Energy Range: ') panel.Add(elo_wids) add_text(' : ', newrow=False) panel.Add(ehi_wids) panel.Add(wids['show_fitrange']) panel.Add(HLine(panel, size=(625, 3)), dcol=5, newrow=True) add_text('Run Fit: ') panel.Add(wids['fit_group'], dcol=2) panel.Add(wids['fit_selected'], dcol=3) add_text('Fit Options: ') panel.Add(wids['sum_to_one'], dcol=2) panel.Add((10, 10), dcol=1, newrow=True) panel.Add(wids['all_combos'], dcol=2) add_text('Max # Components: ', newrow=False) panel.Add(max_ncomps, dcol=2) panel.Add(HLine(panel, size=(625, 3)), dcol=5, newrow=True) add_text('Components: ') panel.Add(wids['add_selected'], dcol=4) collabels = [' File /Group Name ', 'weight', 'min', 'max'] colsizes = [300, 80, 80, 80] coltypes = ['str', 'float:12,4', 'float:12,4', 'float:12,4'] coldefs = ['', 1.0 / MAX_COMPONENTS, 0.0, 1.0] wids['table'] = DataTableGrid(panel, nrows=MAX_COMPONENTS, collabels=collabels, datatypes=coltypes, defaults=coldefs, colsizes=colsizes) wids['table'].SetMinSize((625, 250)) panel.Add(wids['table'], newrow=True, dcol=6) panel.Add(HLine(panel, size=(625, 3)), dcol=5, newrow=True) panel.Add(wids['saveconf'], dcol=4, newrow=True) panel.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add((10, 10), 0, LEFT, 3) sizer.Add(panel, 1, LEFT, 3) pack(self, sizer) self.skip_process = False
def build(self): sizer = wx.GridBagSizer(5, 5) sizer.SetVGap(5) sizer.SetHGap(5) splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(200) self.datalistbox = EditableListBox(splitter, self.ShowDataSet, size=(250, -1)) panel = scrolled.ScrolledPanel(splitter) self.SetMinSize((650, 600)) self.colors = GUIColors() # title row self.wids = wids = {} title = SimpleText(panel, 'Linear Combination Results', font=Font(FONTSIZE + 2), colour=self.colors.title, style=LEFT) wids['plot_one'] = Button(panel, 'Plot This Fit', size=(125, -1), action=self.onPlotOne) wids['plot_sel'] = Button(panel, 'Plot N Best Fits', size=(125, -1), action=self.onPlotSel) wids['plot_ntitle'] = SimpleText(panel, 'N fits to plot: ') wids['plot_nchoice'] = Choice(panel, size=(60, -1), choices=['%d' % i for i in range(1, 21)]) wids['plot_nchoice'].SetStringSelection('5') wids['data_title'] = SimpleText(panel, '<--> ', font=Font(FONTSIZE + 2), colour=self.colors.title, style=LEFT) wids['nfits_title'] = SimpleText(panel, 'showing 5 best fits') copts = dict(size=(125, 30), default=True, action=self.onPlotOne) # wids['show_e0'] = Check(panel, label='show E0?', **copts) wids['show_fitrange'] = Check(panel, label='show fit range?', **copts) irow = 0 sizer.Add(title, (irow, 0), (1, 1), LEFT) sizer.Add(wids['data_title'], (irow, 1), (1, 2), LEFT) irow += 1 sizer.Add(wids['nfits_title'], (irow, 0), (1, 1), LEFT) irow += 1 self.wids['paramstitle'] = SimpleText(panel, '[[Parameters]]', font=Font(FONTSIZE + 2), colour=self.colors.title, style=LEFT) sizer.Add(self.wids['paramstitle'], (irow, 0), (1, 1), LEFT) pview = self.wids['params'] = dv.DataViewListCtrl(panel, style=DVSTYLE) pview.SetMinSize((475, 200)) pview.AppendTextColumn(' Parameter ', width=230) pview.AppendTextColumn(' Best-Fit Value', width=120) pview.AppendTextColumn(' Standard Error ', width=120) for col in range(3): this = pview.Columns[col] isort, align = True, wx.ALIGN_RIGHT if col == 0: align = wx.ALIGN_LEFT this.Sortable = isort this.Alignment = this.Renderer.Alignment = align irow += 1 sizer.Add(self.wids['params'], (irow, 0), (4, 1), LEFT) sizer.Add(self.wids['plot_one'], (irow, 1), (1, 2), LEFT) sizer.Add(self.wids['plot_sel'], (irow + 1, 1), (1, 2), LEFT) sizer.Add(self.wids['plot_ntitle'], (irow + 2, 1), (1, 1), LEFT) sizer.Add(self.wids['plot_nchoice'], (irow + 2, 2), (1, 1), LEFT) # sizer.Add(self.wids['show_e0'], (irow+3, 1), (1, 2), LEFT) sizer.Add(self.wids['show_fitrange'], (irow + 3, 1), (1, 2), LEFT) irow += 4 sizer.Add(HLine(panel, size=(675, 3)), (irow, 0), (1, 4), LEFT) sview = self.wids['stats'] = dv.DataViewListCtrl(panel, style=DVSTYLE) sview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectFitStat) sview.AppendTextColumn(' Fit #', width=50) sview.AppendTextColumn(' N_vary', width=50) sview.AppendTextColumn(' N_eval', width=60) sview.AppendTextColumn(' \u03c7\u00B2', width=110) sview.AppendTextColumn(' \u03c7\u00B2_reduced', width=110) sview.AppendTextColumn(' Akaike Info', width=110) sview.AppendTextColumn(' Bayesian Info', width=110) for col in range(sview.ColumnCount): this = sview.Columns[col] isort, align = True, wx.ALIGN_RIGHT if col == 0: align = wx.ALIGN_CENTER this.Sortable = isort this.Alignment = this.Renderer.Alignment = align sview.SetMinSize((675, 175)) irow += 1 title = SimpleText(panel, '[[Fit Statistics]]', font=Font(FONTSIZE + 2), colour=self.colors.title, style=LEFT) sizer.Add(title, (irow, 0), (1, 4), LEFT) irow += 1 sizer.Add(sview, (irow, 0), (1, 4), LEFT) irow += 1 sizer.Add(HLine(panel, size=(675, 3)), (irow, 0), (1, 4), LEFT) irow += 1 title = SimpleText(panel, '[[Weights]]', font=Font(FONTSIZE + 2), colour=self.colors.title, style=LEFT) sizer.Add(title, (irow, 0), (1, 4), LEFT) self.wids['weightspanel'] = ppan = wx.Panel(panel) p1 = SimpleText(ppan, ' < Weights > ') os = wx.BoxSizer(wx.VERTICAL) os.Add(p1, 1, 3) pack(ppan, os) ppan.SetMinSize((675, 175)) irow += 1 sizer.Add(ppan, (irow, 0), (1, 4), LEFT) irow += 1 sizer.Add(HLine(panel, size=(675, 3)), (irow, 0), (1, 4), LEFT) pack(panel, sizer) panel.SetupScrolling() splitter.SplitVertically(self.datalistbox, panel, 1) mainsizer = wx.BoxSizer(wx.VERTICAL) mainsizer.Add(splitter, 1, wx.GROW | wx.ALL, 5) pack(self, mainsizer) # self.SetSize((725, 750)) self.Show() self.Raise()
def build_display(self): titleopts = dict(font=Font(12), colour='#AA0000') panel = self.panel wids = self.wids self.skip_process = True wids['fitspace'] = Choice(panel, choices=FitSpace_Choices, size=(175, -1)) wids['fitspace'].SetStringSelection(norm) wids['plotchoice'] = Choice(panel, choices=Plot_Choices, size=(175, -1), action=self.onPlot) wids['plotchoice'].SetSelection(1) add_text = self.add_text opts = dict(digits=2, increment=1.0, relative_e0=True) e0_wids = self.add_floatspin('e0', value=0, **opts) elo_wids = self.add_floatspin('elo', value=-20, **opts) ehi_wids = self.add_floatspin('ehi', value=30, **opts) wids['fit_group'] = Button(panel, 'Fit this Group', size=(150, -1), action=self.onFitOne) wids['fit_selected'] = Button(panel, 'Fit Selected Groups', size=(150, -1), action=self.onFitAll) wids['add_selected'] = Button(panel, 'Use Selected Groups as Components', size=(250, -1), action=self.onUseSelected) wids['saveconf'] = Button(panel, 'Save as Default Settings', size=(200, -1), action=self.onSaveConfigBtn) opts = dict(default=True, size=(75, -1), action=self.onPlotOne) wids['show_e0'] = Check(panel, label='show?', **opts) wids['show_fitrange'] = Check(panel, label='show?', **opts) wids['sum_to_one'] = Check(panel, label='Weights Must Sum to 1?', default=True) wids['all_combos'] = Check(panel, label='Fit All Combinations?', default=True) panel.Add(SimpleText(panel, ' Linear Combination Analysis', **titleopts), dcol=5) add_text('Run Fit', newrow=False) add_text('Array to Fit: ', newrow=True) panel.Add(wids['fitspace'], dcol=4) panel.Add(wids['fit_group']) add_text('Plot : ', newrow=True) panel.Add(wids['plotchoice'], dcol=4) panel.Add(wids['fit_selected']) add_text('E0: ') panel.Add(e0_wids, dcol=3) panel.Add(wids['show_e0']) add_text('Fit Energy Range: ') panel.Add(elo_wids) add_text(' : ', newrow=False) panel.Add(ehi_wids) panel.Add(wids['show_fitrange']) panel.Add(wids['sum_to_one'], dcol=2, newrow=True) panel.Add(wids['all_combos'], dcol=3) panel.Add(HLine(panel, size=(400, 2)), dcol=5, newrow=True) add_text('Components: ') panel.Add(wids['add_selected'], dcol=4) groupnames = [noname] + list(self.controller.file_groups.keys()) sgrid = GridPanel(panel, nrows=6) sgrid.Add(SimpleText(sgrid, "#")) sgrid.Add(SimpleText(sgrid, "Group")) sgrid.Add(SimpleText(sgrid, "Weight")) sgrid.Add(SimpleText(sgrid, "Min Weight")) sgrid.Add(SimpleText(sgrid, "Max Weight")) fopts = dict(minval=-10, maxval=20, precision=4, size=(60, -1)) for i in range(1, 1 + MAX_COMPONENTS): si = ("comp", "_%2.2d" % i) sgrid.Add(SimpleText(sgrid, "%2i" % i), newrow=True) wids['%schoice%s' % si] = Choice(sgrid, choices=groupnames, size=(200, -1), action=partial(self.onComponent, comp=i)) wids['%sval%s' % si] = FloatCtrl(sgrid, value=0, **fopts) wids['%smin%s' % si] = FloatCtrl(sgrid, value=0, **fopts) wids['%smax%s' % si] = FloatCtrl(sgrid, value=1, **fopts) for cname in ('choice', 'val', 'min', 'max'): sgrid.Add(wids[("%%s%s%%s" % cname) % si]) sgrid.pack() panel.Add(sgrid, dcol=5, newrow=True) panel.Add(HLine(panel, size=(400, 2)), dcol=5, newrow=True) panel.Add(wids['saveconf'], dcol=4, newrow=True) panel.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(panel, 1, LCEN, 3) pack(self, sizer) self.skip_process = False
def build(self): sizer = wx.GridBagSizer(10, 5) sizer.SetVGap(5) sizer.SetHGap(5) panel = scrolled.ScrolledPanel(self) self.SetMinSize((675, 600)) self.colors = GUIColors() # title row self.wids = wids = {} title = SimpleText(panel, 'Linear Combination Results', font=Font(12), colour=self.colors.title, style=LCEN) wids['plot_one'] = Button(panel, 'Plot This Fit', size=(150, -1), action=self.onPlotOne) wids['plot_sel'] = Button(panel, 'Plot top N Fits', size=(150, -1), action=self.onPlotSel) wids['plot_ntitle'] = SimpleText(panel, 'N fits to plot: ') wids['plot_nchoice'] = Choice(panel, size=(100, -1), choices=['%d' % i for i in range(1, 21)]) wids['plot_nchoice'].SetStringSelection('5') wids['data_title'] = SimpleText(panel, '<--> ', font=Font(12), colour=self.colors.title, style=LCEN) wids['nfits_title'] = SimpleText(panel, 'showing top 5 fits') irow = 0 sizer.Add(title, (irow, 0), (1, 2), LCEN) sizer.Add(wids['data_title'], (irow, 2), (1, 2), LCEN) irow += 1 sizer.Add(wids['nfits_title'], (irow, 0), (1, 4), LCEN) irow += 1 sizer.Add(self.wids['plot_one'], (irow, 0), (1, 1), LCEN) sizer.Add(self.wids['plot_sel'], (irow, 1), (1, 1), LCEN) sizer.Add(self.wids['plot_ntitle'], (irow, 2), (1, 1), LCEN) sizer.Add(self.wids['plot_nchoice'], (irow, 3), (1, 1), LCEN) irow += 1 self.wids['paramstitle'] = SimpleText(panel, '[[Parameters]]', font=Font(12), colour=self.colors.title, style=LCEN) sizer.Add(self.wids['paramstitle'], (irow, 0), (1, 4), LCEN) pview = self.wids['params'] = dv.DataViewListCtrl(panel, style=DVSTYLE) pview.SetMinSize((675, 200)) pview.AppendTextColumn(' Parameter ', width=250) pview.AppendTextColumn(' Best-Fit Value', width=150) pview.AppendTextColumn(' Uncertainty ', width=150) for col in range(3): this = pview.Columns[col] isort, align = True, wx.ALIGN_RIGHT if col == 0: align = wx.ALIGN_LEFT this.Sortable = isort this.Alignment = this.Renderer.Alignment = align irow += 1 sizer.Add(self.wids['params'], (irow, 0), (1, 4), LCEN) irow += 1 sizer.Add(HLine(panel, size=(675, 3)), (irow, 0), (1, 4), LCEN) sview = self.wids['stats'] = dv.DataViewListCtrl(panel, style=DVSTYLE) sview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectFitStat) sview.AppendTextColumn(' Fit #', width=50) sview.AppendTextColumn(' N_Vary', width=60) sview.AppendTextColumn(' N_Data', width=60) sview.AppendTextColumn(' N_eval', width=60) sview.AppendTextColumn(u' \u03c7\u00B2', width=100) sview.AppendTextColumn(u' \u03c7\u00B2_reduced', width=100) sview.AppendTextColumn(' Akaike Info', width=100) sview.AppendTextColumn(' Bayesian Info', width=100) for col in range(8): this = sview.Columns[col] isort, align = True, wx.ALIGN_RIGHT if col == 0: align = wx.ALIGN_CENTER this.Sortable = isort this.Alignment = this.Renderer.Alignment = align sview.SetMinSize((675, 175)) irow += 1 title = SimpleText(panel, '[[Fit Statistics]]', font=Font(12), colour=self.colors.title, style=LCEN) sizer.Add(title, (irow, 0), (1, 4), LCEN) irow += 1 sizer.Add(sview, (irow, 0), (1, 4), LCEN) irow += 1 sizer.Add(HLine(panel, size=(675, 3)), (irow, 0), (1, 4), LCEN) irow += 1 title = SimpleText(panel, '[[Weights]]', font=Font(12), colour=self.colors.title, style=LCEN) sizer.Add(title, (irow, 0), (1, 4), LCEN) self.wids['weightspanel'] = ppan = wx.Panel(self) p1 = SimpleText(ppan, ' < Weights > ') os = wx.BoxSizer(wx.VERTICAL) os.Add(p1, 1, 3) pack(ppan, os) ppan.SetMinSize((675, 175)) irow += 1 sizer.Add(ppan, (irow, 0), (1, 4), LCEN) irow += 1 sizer.Add(HLine(panel, size=(675, 3)), (irow, 0), (1, 4), LCEN) pack(panel, sizer) panel.SetupScrolling() mainsizer = wx.BoxSizer(wx.VERTICAL) mainsizer.Add(panel, 1, wx.GROW | wx.ALL, 1) pack(self, mainsizer) self.Show() self.Raise()
def build_display(self): self.mod_nb = flatnotebook(self, {}) pan = self.panel = GridPanel(self, ncols=4, nrows=4, pad=2, itemstyle=LEFT) self.wids = {} fsopts = dict(digits=2, increment=0.1, with_pin=True) ppeak_e0 = self.add_floatspin('ppeak_e0', value=0, **fsopts) ppeak_elo = self.add_floatspin('ppeak_elo', value=-15, **fsopts) ppeak_ehi = self.add_floatspin('ppeak_ehi', value=-5, **fsopts) ppeak_emin = self.add_floatspin('ppeak_emin', value=-30, **fsopts) ppeak_emax = self.add_floatspin('ppeak_emax', value=0, **fsopts) self.fitbline_btn = Button(pan,'Fit Baseline', action=self.onFitBaseline, size=(125, -1)) self.plotmodel_btn = Button(pan, 'Plot Model', action=self.onPlotModel, size=(125, -1)) self.fitmodel_btn = Button(pan, 'Fit Model', action=self.onFitModel, size=(125, -1)) self.loadmodel_btn = Button(pan, 'Load Model', action=self.onLoadFitResult, size=(125, -1)) self.fitmodel_btn.Disable() self.array_choice = Choice(pan, size=(175, -1), choices=list(Array_Choices.keys())) self.array_choice.SetSelection(1) models_peaks = Choice(pan, size=(150, -1), choices=ModelChoices['peaks'], action=self.addModel) models_other = Choice(pan, size=(150, -1), choices=ModelChoices['other'], action=self.addModel) self.models_peaks = models_peaks self.models_other = models_other 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) def add_text(text, dcol=1, newrow=True): pan.Add(SimpleText(pan, text), dcol=dcol, newrow=newrow) pan.Add(SimpleText(pan, ' Pre-edge Peak Fitting', **self.titleopts), dcol=5) add_text(' Run Fit:', newrow=False) add_text('Array to fit: ') pan.Add(self.array_choice, dcol=3) pan.Add((10, 10)) pan.Add(self.fitbline_btn) add_text('E0: ') pan.Add(ppeak_e0) pan.Add((10, 10), dcol=2) pan.Add(self.show_e0) pan.Add(self.plotmodel_btn) add_text('Fit Energy Range: ') pan.Add(ppeak_emin) add_text(' : ', newrow=False) pan.Add(ppeak_emax) pan.Add(self.show_fitrange) pan.Add(self.fitmodel_btn) t = SimpleText(pan, 'Pre-edge Peak Range: ') SetTip(t, 'Range used as mask for background') pan.Add(t, newrow=True) pan.Add(ppeak_elo) add_text(' : ', newrow=False) pan.Add(ppeak_ehi) pan.Add(self.show_peakrange) # pan.Add(self.fitsel_btn) add_text( 'Peak Centroid: ') pan.Add(self.msg_centroid, dcol=3) pan.Add(self.show_centroid, dcol=1) pan.Add(self.loadmodel_btn) # 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((10, 10), 0, LEFT, 3) sizer.Add(pan, 0, LEFT, 3) sizer.Add((10, 10), 0, LEFT, 3) sizer.Add(HLine(self, size=(550, 2)), 0, LEFT, 3) sizer.Add((10, 10), 0, LEFT, 3) sizer.Add(self.mod_nb, 1, LEFT|wx.GROW, 10) pack(self, sizer)
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=2, nrows=5, pad=2, 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 SLabel(label, size=(80, -1), **kws): return SimpleText(panel, label, size=size, style=wx.ALIGN_LEFT, **kws)
def build_display(self): panel = self.panel wids = self.wids self.skip_process = True wids['fitspace'] = Choice(panel, choices=FitSpace_Choices, size=(175, -1)) wids['fitspace'].SetStringSelection(norm) wids['plotchoice'] = Choice(panel, choices=Plot_Choices, size=(175, -1), action=self.onPlot) wids['plotchoice'].SetSelection(0) add_text = self.add_text opts = dict(digits=2, increment=1.0) w_xmin = self.add_floatspin('xmin', value=defaults['xmin'], **opts) w_xmax = self.add_floatspin('xmax', value=defaults['xmax'], **opts) w_wmin = self.add_floatspin('weight_min', digits=4, value=defaults['weight_min'], increment=0.001, with_pin=False, min_val=0, max_val=0.5, action=self.onSet_WeightMin) autoset_fs_increment(self.wids['weight_min'], defaults['weight_min']) self.wids['weight_auto'] = Check(panel, default=True, label='auto?') w_mcomps = self.add_floatspin('max_components', digits=0, value=defaults['max_components'], increment=1, with_pin=False, min_val=0) b_build_model = Button(panel, 'Build Model With Selected Groups', size=(275, -1), action=self.onBuildPCAModel) wids['fit_group'] = Button(panel, 'Test Current Group with Model', size=(225, -1), action=self.onFitGroup) wids['save_model'] = Button(panel, 'Save PCA Model', size=(150, -1), action=self.onSavePCAModel) wids['load_model'] = Button(panel, 'Load PCA Model', size=(150, -1), action=self.onLoadPCAModel) wids['fit_group'].Disable() wids['load_model'].Disable() wids['save_model'].Disable() collabels = [ ' Variance ', ' IND value ', ' IND / IND_Best', ' Factor Weight' ] colsizes = [100, 100, 100, 200] coltypes = ['float:12,6', 'float:12,6', 'float:12,5', 'string'] coldefs = [0.0, 0.0, 1.0, '0.0'] wids['table'] = DataTableGrid(panel, nrows=MAX_ROWS, collabels=collabels, datatypes=coltypes, defaults=coldefs, colsizes=colsizes, rowlabelsize=60) wids['table'].SetMinSize((625, 175)) wids['table'].EnableEditing(False) # # sview = self.wids['stats'] = dv.DataViewListCtrl(panel, style=DVSTYLE) # sview.AppendTextColumn(' Component', width=75) # sview.AppendTextColumn(' Weight', width=100) # sview.AppendTextColumn(' Significant?', width=75) # # for col in range(sview.ColumnCount): # this = sview.Columns[col] # align = wx.ALIGN_LEFT if col == 0 else wx.ALIGN_RIGHT # this.Sortable = False # this.Alignment = this.Renderer.Alignment = align # sview.SetMinSize((275, 250)) wids['status'] = SimpleText(panel, ' ') rfont = self.GetFont() rfont.SetPointSize(rfont.GetPointSize() + 1) wids['fit_chi2'] = SimpleText(panel, '0.000', font=rfont) wids['fit_dscale'] = SimpleText(panel, '1.000', font=rfont) panel.Add(SimpleText(panel, ' Principal Component Analysis', **self.titleopts), dcol=4) add_text('Array to Use: ', newrow=True) panel.Add(wids['fitspace'], dcol=2) panel.Add(wids['load_model'], dcol=2) add_text('Plot : ', newrow=True) panel.Add(wids['plotchoice'], dcol=2) panel.Add(wids['save_model'], dcol=2) add_text('Fit Energy Range: ') panel.Add(w_xmin) add_text(' : ', newrow=False) panel.Add(w_xmax) #panel.Add(wids['show_fitrange']) add_text('Min Weight: ') panel.Add(w_wmin) panel.Add(wids['weight_auto']) add_text('Max Components:', dcol=1, newrow=True) panel.Add(w_mcomps) panel.Add(Button(panel, 'Copy To Selected Groups', size=(200, -1), action=partial(self.onCopyParam, 'pca')), dcol=2) add_text('Status: ') panel.Add(wids['status'], dcol=3) panel.Add(HLine(panel, size=(550, 2)), dcol=5, newrow=True) panel.Add(b_build_model, dcol=5, newrow=True) panel.Add(wids['table'], dcol=5, newrow=True) panel.Add(wids['fit_group'], dcol=3, newrow=True) add_text('chi-square: ') panel.Add(wids['fit_chi2']) add_text('scale factor: ') panel.Add(wids['fit_dscale']) # # ## add weights report: slightly tricky layout # ## working with GridBagSizer under gridpanel... # icol = panel.icol - 2 # irow = panel.irow # pstyle, ppad = panel.itemstyle, panel.pad # # panel.sizer.Add(SimpleText(panel, 'data scalefactor = '), # (irow+1, icol), (1, 1), pstyle, ppad) # panel.sizer.Add(wids['fit_dscale'], # (irow+1, icol+1), (1, 1), pstyle, ppad) # irow +=1 # for i in range(1, NWTS+1): # wids['fit_wt%d' % i] = SimpleText(panel, '--', font=rfont) # panel.sizer.Add(SimpleText(panel, 'weight_%d ='%i, font=rfont), # (irow+i, icol), (1, 1), pstyle, ppad) # panel.sizer.Add(wids['fit_wt%d'%i], # (irow+i, icol+1), (1, 1), pstyle, ppad) # panel.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add((10, 10), 0, LCEN, 3) sizer.Add(panel, 1, LCEN, 3) pack(self, sizer) self.skip_process = False
def build_display(self): titleopts = dict(font=Font(12), colour='#AA0000') xas = self.panel self.wids = {} self.plotone_op = Choice(xas, choices=list(PlotOne_Choices.keys()), action=self.onPlotOne, size=(175, -1)) self.plotsel_op = Choice(xas, choices=list(PlotSel_Choices.keys()), action=self.onPlotSel, size=(175, -1)) self.plotone_op.SetSelection(1) self.plotsel_op.SetSelection(1) 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) opts = dict(action=self.onReprocess) e0opts_panel = wx.Panel(xas) self.wids['autoe0'] = Check(e0opts_panel, default=True, label='auto?', **opts) self.wids['showe0'] = Check(e0opts_panel, default=True, label='show?', **opts) sx = wx.BoxSizer(wx.HORIZONTAL) sx.Add(self.wids['autoe0'], 0, LCEN, 4) sx.Add(self.wids['showe0'], 0, LCEN, 4) pack(e0opts_panel, sx) self.wids['autostep'] = Check(xas, default=True, label='auto?', **opts) opts['size'] = (50, -1) self.wids['vict'] = Choice(xas, choices=('0', '1', '2', '3'), **opts) self.wids['nnor'] = Choice(xas, choices=('0', '1', '2', '3'), **opts) self.wids['vict'].SetSelection(1) self.wids['nnor'].SetSelection(1) opts.update({'size': (100, -1), 'digits': 2, 'increment': 5.0}) xas_pre1 = self.add_floatspin('pre1', value=-1000, **opts) xas_pre2 = self.add_floatspin('pre2', value=-30, **opts) xas_nor1 = self.add_floatspin('nor1', value=50, **opts) xas_nor2 = self.add_floatspin('nor2', value=5000, **opts) opts = {'digits': 2, 'increment': 0.1, 'value': 0} xas_e0 = self.add_floatspin('e0', action=self.onSet_XASE0, **opts) xas_step = self.add_floatspin('step', action=self.onSet_XASStep, with_pin=False, **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)) add_text = self.add_text xas.Add(SimpleText(xas, ' XAS Pre-edge subtraction and Normalization', **titleopts), dcol=4) 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=4) xas.Add((10, 10)) xas.Add(CopyBtn('plotone_op'), style=RCEN) add_text('E0 : ') xas.Add(xas_e0) xas.Add(e0opts_panel, dcol=3) xas.Add((10, 1)) xas.Add(CopyBtn('xas_e0'), style=RCEN) add_text('Edge Step: ') xas.Add(xas_step) xas.Add(self.wids['autostep'], dcol=3) xas.Add((10, 1)) xas.Add(CopyBtn('xas_step'), style=RCEN) add_text('Pre-edge range: ') xas.Add(xas_pre1) add_text(' : ', newrow=False) xas.Add(xas_pre2) xas.Add(SimpleText(xas, 'Victoreen:')) xas.Add(self.wids['vict']) xas.Add(CopyBtn('xas_pre'), style=RCEN) add_text('Normalization range: ') xas.Add(xas_nor1) add_text(' : ', newrow=False) xas.Add(xas_nor2) xas.Add(SimpleText(xas, 'Poly Order:')) xas.Add(self.wids['nnor']) xas.Add(CopyBtn('xas_norm'), 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 build_display(self): titleopts = dict(font=Font(12), colour='#AA0000') panel = self.panel wids = self.wids self.skip_process = True wids['plotone_op'] = Choice(panel, choices=PlotOne_Choices, action=self.onPlotOne, size=(175, -1)) wids['plotalt_op'] = Choice(panel, choices=PlotAlt_Choices, action=self.onPlotOne, size=(175, -1)) wids['plotsel_op'] = Choice(panel, choices=PlotSel_Choices, action=self.onPlotSel, size=(175, -1)) wids['plotone_op'].SetStringSelection(chik) wids['plotsel_op'].SetStringSelection(chik) wids['plotalt_op'].SetStringSelection(noplot) plot_one = Button(panel, 'Plot This Group', size=(150, -1), action=self.onPlotOne) plot_sel = Button(panel, 'Plot Selected Groups', size=(150, -1), action=self.onPlotSel) saveconf = Button(panel, 'Save as Default Settings', size=(200, -1), action=self.onSaveConfigBtn) def FloatSpinWithPin(name, value, **kws): s = wx.BoxSizer(wx.HORIZONTAL) self.wids[name] = FloatSpin(panel, value=value, **kws) bb = BitmapButton(panel, get_icon('pin'), size=(25, 25), action=partial(self.onSelPoint, opt=name), tooltip='use last point selected from plot') s.Add(wids[name]) s.Add(bb) return s wids['plot_voffset'] = FloatSpin(panel, value=0, digits=2, increment=0.25, action=self.onProcess) wids['plot_kweight'] = FloatSpin(panel, value=2, digits=1, increment=1, action=self.onProcess, min_val=0, max_val=5) wids['plot_kweight_alt'] = FloatSpin(panel, value=2, digits=1, increment=1, action=self.onProcess, min_val=0, max_val=5) opts = dict(digits=2, increment=0.1, min_val=0, action=self.onProcess) wids['e0'] = FloatSpin(panel, **opts) opts['max_val'] = 5 wids['rbkg'] = FloatSpin(panel, value=1.0, **opts) opts['max_val'] = 125 bkg_kmin = FloatSpinWithPin('bkg_kmin', value=0, **opts) bkg_kmax = FloatSpinWithPin('bkg_kmax', value=20, **opts) fft_kmin = FloatSpinWithPin('fft_kmin', value=0, **opts) fft_kmax = FloatSpinWithPin('fft_kmax', value=20, **opts) wids['fft_dk'] = FloatSpin(panel, value=3, **opts) opts.update({'increment': 1, 'digits': 1, 'max_val': 5}) wids['bkg_kweight'] = FloatSpin(panel, value=1, **opts) wids['fft_kweight'] = FloatSpin(panel, value=1, **opts) opts = dict(choices=CLAMPLIST, size=(80, -1), action=self.onProcess) wids['bkg_clamplo'] = Choice(panel, **opts) wids['bkg_clamphi'] = Choice(panel, **opts) wids['fft_kwindow'] = Choice(panel, choices=list(FTWINDOWS), action=self.onProcess, size=(125, -1)) def add_text(text, dcol=1, newrow=True): panel.Add(SimpleText(panel, text), dcol=dcol, newrow=newrow) panel.Add(SimpleText(panel, ' EXAFS Processing', **titleopts), dcol=5) panel.Add(plot_sel, newrow=True) panel.Add(self.wids['plotsel_op'], dcol=2) add_text('Vertical offset: ', newrow=False) panel.Add(wids['plot_voffset'], dcol=2) panel.Add(plot_one, newrow=True) panel.Add(self.wids['plotone_op'], dcol=2) add_text('Plot k weight: ', newrow=False) panel.Add(wids['plot_kweight']) add_text('Add Second Plot: ', newrow=True) panel.Add(self.wids['plotalt_op'], dcol=2) add_text('Plot2 k weight: ', newrow=False) panel.Add(wids['plot_kweight_alt']) panel.Add(HLine(panel, size=(500, 3)), dcol=6, newrow=True) panel.Add(SimpleText(panel, ' Background subtraction', **titleopts), dcol=2, newrow=True) panel.Add(Button(panel, 'Copy To Selected Groups', size=(175, -1), action=partial(self.onCopyParam, 'bkg')), dcol=2) add_text('R bkg: ') panel.Add(wids['rbkg']) add_text('E0: ', newrow=False) panel.Add(wids['e0']) add_text('k min: ') panel.Add(bkg_kmin) add_text('k max:', newrow=False) panel.Add(bkg_kmax) add_text('kweight: ', newrow=True) panel.Add(wids['bkg_kweight'], dcol=1) add_text('Clamps Low E: ', newrow=True) panel.Add(wids['bkg_clamplo']) add_text('high E: ', newrow=False) panel.Add(wids['bkg_clamphi']) panel.Add(HLine(panel, size=(500, 3)), dcol=6, newrow=True) panel.Add(SimpleText(panel, ' Fourier transform', **titleopts), dcol=2, newrow=True) panel.Add(Button(panel, 'Copy to Selected Groups', size=(175, -1), action=partial(self.onCopyParam, 'fft')), dcol=2) panel.Add(SimpleText(panel, 'k min: '), newrow=True) panel.Add(fft_kmin) panel.Add(SimpleText(panel, 'k max:')) panel.Add(fft_kmax) panel.Add(SimpleText(panel, 'k weight : '), newrow=True) panel.Add(wids['fft_kweight']) panel.Add(SimpleText(panel, 'K window : '), newrow=True) panel.Add(wids['fft_kwindow']) panel.Add(SimpleText(panel, ' dk : ')) panel.Add(wids['fft_dk']) panel.Add(HLine(panel, size=(500, 3)), dcol=6, newrow=True) panel.Add(saveconf, dcol=4, newrow=True) panel.pack() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(panel, 1, LCEN, 3) pack(self, sizer) self.skip_process = False
def add_text(self, text, dcol=1, newrow=True): self.panel.Add(SimpleText(self.panel, text), dcol=dcol, newrow=newrow)
def build(self): sizer = wx.GridBagSizer(10, 5) sizer.SetVGap(5) sizer.SetHGap(5) panel = scrolled.ScrolledPanel(self) self.SetMinSize((600, 450)) self.colors = GUIColors() # title row self.wids = wids = {} title = SimpleText(panel, 'Fit Results', font=Font(12), colour=self.colors.title, style=LCEN) wids['data_title'] = SimpleText(panel, '< > ', font=Font(12), colour=self.colors.title, style=LCEN) wids['hist_info'] = SimpleText(panel, ' ___ ', font=Font(12), colour=self.colors.title, style=LCEN) sizer.Add(title, (0, 0), (1, 2), LCEN) sizer.Add(wids['data_title'], (0, 2), (1, 2), LCEN) sizer.Add(wids['hist_info'], (0, 4), (1, 2), LCEN) irow = 1 wids['model_desc'] = SimpleText(panel, '<Model>', font=Font(12), size=(550, 75), style=LCEN) sizer.Add(wids['model_desc'], (irow, 0), (1, 6), LCEN) irow += 1 sizer.Add(HLine(panel, size=(400, 3)), (irow, 0), (1, 5), LCEN) irow += 1 title = SimpleText(panel, '[[Fit Statistics]]', font=Font(12), colour=self.colors.title, style=LCEN) sizer.Add(title, (irow, 0), (1, 4), LCEN) for label, attr in (('Fit method', 'method'), ('# Fit Evaluations', 'nfev'), ('# Data Points', 'ndata'), ('# Fit Variables', 'nvarys'), ('# Free Points', 'nfree'), ('Chi-square', 'chisqr'), ('Reduced Chi-square', 'redchi'), ('Akaike Info Criteria', 'aic'), ('Bayesian Info Criteria', 'bic')): irow += 1 wids[attr] = SimpleText(panel, '?') sizer.Add(SimpleText(panel, " %s = " % label), (irow, 0), (1, 1), LCEN) sizer.Add(wids[attr], (irow, 1), (1, 1), LCEN) irow += 1 sizer.Add(HLine(panel, size=(400, 3)), (irow, 0), (1, 5), LCEN) irow += 1 title = SimpleText(panel, '[[Variables]]', font=Font(12), colour=self.colors.title, style=LCEN) sizer.Add(title, (irow, 0), (1, 1), LCEN) self.wids['copy_params'] = Button(panel, 'Update Model with Best Fit Values', size=(250, -1), action=self.onCopyParams) sizer.Add(self.wids['copy_params'], (irow, 1), (1, 3), LCEN) dvstyle = dv.DV_SINGLE|dv.DV_VERT_RULES|dv.DV_ROW_LINES pview = self.wids['params'] = dv.DataViewListCtrl(panel, style=dvstyle) self.wids['paramsdata'] = [] pview.AppendTextColumn('Parameter', width=150) pview.AppendTextColumn('Best-Fit Value', width=100) pview.AppendTextColumn('Standard Error', width=100) pview.AppendTextColumn('Info ', width=275) for col in (0, 1, 2, 3): this = pview.Columns[col] isort, align = True, wx.ALIGN_LEFT if col in (1, 2): isort, align = False, wx.ALIGN_RIGHT this.Sortable = isort this.Alignment = this.Renderer.Alignment = align pview.SetMinSize((650, 200)) pview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectParameter) irow += 1 sizer.Add(pview, (irow, 0), (1, 5), LCEN) irow += 1 sizer.Add(HLine(panel, size=(400, 3)), (irow, 0), (1, 5), LCEN) irow += 1 title = SimpleText(panel, '[[Correlations]]', font=Font(12), colour=self.colors.title, style=LCEN) self.wids['all_correl'] = Button(panel, 'Show All', size=(100, -1), action=self.onAllCorrel) self.wids['min_correl'] = FloatSpin(panel, value=MIN_CORREL, min_val=0, size=(60, -1), digits=3, increment=0.1) ctitle = SimpleText(panel, 'minimum correlation: ') sizer.Add(title, (irow, 0), (1, 1), LCEN) sizer.Add(ctitle, (irow, 1), (1, 1), LCEN) sizer.Add(self.wids['min_correl'], (irow, 2), (1, 1), LCEN) sizer.Add(self.wids['all_correl'], (irow, 3), (1, 1), LCEN) irow += 1 cview = self.wids['correl'] = dv.DataViewListCtrl(panel, style=dvstyle) cview.AppendTextColumn('Parameter 1', width=150) cview.AppendTextColumn('Parameter 2', width=150) cview.AppendTextColumn('Correlation', width=100) for col in (0, 1, 2): this = cview.Columns[col] isort, align = True, wx.ALIGN_LEFT if col == 1: isort = False if col == 2: align = wx.ALIGN_RIGHT this.Sortable = isort this.Alignment = this.Renderer.Alignment = align cview.SetMinSize((450, 200)) irow += 1 sizer.Add(cview, (irow, 0), (1, 5), LCEN) irow += 1 sizer.Add(HLine(panel, size=(400, 3)), (irow, 0), (1, 5), LCEN) pack(panel, sizer) panel.SetupScrolling() mainsizer = wx.BoxSizer(wx.VERTICAL) mainsizer.Add(panel, 1, wx.GROW|wx.ALL, 1) pack(self, mainsizer) self.Show() self.Raise()
def createMainPanel(self): display0 = wx.Display(0) client_area = display0.ClientArea xmin, ymin, xmax, ymax = client_area xpos = int((xmax - xmin) * 0.02) + xmin ypos = int((ymax - ymin) * 0.04) + ymin self.SetPosition((xpos, ypos)) splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) splitter.SetMinimumPaneSize(250) leftpanel = wx.Panel(splitter) ltop = wx.Panel(leftpanel) def Btn(msg, x, act): b = Button(ltop, msg, size=(x, 30), action=act) b.SetFont(Font(FONTSIZE)) return b sel_none = Btn('Select None', 120, self.onSelNone) sel_all = Btn('Select All', 120, self.onSelAll) self.controller.filelist = FileCheckList( leftpanel, # main=self, select_action=self.ShowFile, remove_action=self.RemoveFile) tsizer = wx.BoxSizer(wx.HORIZONTAL) tsizer.Add(sel_all, 1, LCEN | wx.GROW, 1) tsizer.Add(sel_none, 1, LCEN | wx.GROW, 1) pack(ltop, tsizer) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(ltop, 0, LCEN | wx.GROW, 1) sizer.Add(self.controller.filelist, 1, LCEN | wx.GROW | wx.ALL, 1) pack(leftpanel, sizer) # right hand side panel = wx.Panel(splitter) sizer = wx.BoxSizer(wx.VERTICAL) self.title = SimpleText(panel, 'initializing...', size=(300, -1)) self.title.SetFont(Font(FONTSIZE + 1)) ir = 0 sizer.Add(self.title, 0, LCEN | wx.GROW | wx.ALL, 1) self.nb = flat_nb.FlatNotebook(panel, -1, agwStyle=FNB_STYLE) self.nb.SetTabAreaColour(wx.Colour(250, 250, 250)) self.nb.SetActiveTabColour(wx.Colour(254, 254, 195)) self.nb.SetNonActiveTabTextColour(wx.Colour(10, 10, 128)) self.nb.SetActiveTabTextColour(wx.Colour(128, 0, 0)) self.nb_panels = [] for name, creator in NB_PANELS: _panel = creator(parent=self, controller=self.controller) self.nb.AddPage(_panel, " %s " % name, True) self.nb_panels.append(_panel) sizer.Add(self.nb, 1, LCEN | wx.EXPAND, 2) self.nb.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onNBChanged) self.nb.SetSelection(0) pack(panel, sizer) splitter.SplitVertically(leftpanel, panel, 1) wx.CallAfter(self.init_larch)
def build(self): sizer = wx.GridBagSizer(10, 5) sizer.SetVGap(5) sizer.SetHGap(5) panel = scrolled.ScrolledPanel(self) self.SetMinSize((700, 450)) self.colors = GUIColors() # title row self.wids = wids = {} title = SimpleText(panel, 'Fit Results', font=Font(FONTSIZE+2), colour=self.colors.title, style=LEFT) wids['data_title'] = SimpleText(panel, '< > ', font=Font(FONTSIZE+2), colour=self.colors.title, style=LEFT) wids['hist_info'] = SimpleText(panel, ' ___ ', font=Font(FONTSIZE+2), colour=self.colors.title, style=LEFT) wids['hist_hint'] = SimpleText(panel, ' (Fit #01 is most recent)', font=Font(FONTSIZE+2), colour=self.colors.title, style=LEFT) opts = dict(default=False, size=(200, -1), action=self.onPlot) wids['plot_bline'] = Check(panel, label='Plot baseline-subtracted?', **opts) wids['plot_resid'] = Check(panel, label='Plot with residual?', **opts) self.plot_choice = Button(panel, 'Plot Selected Fit', size=(175, -1), action=self.onPlot) self.save_result = Button(panel, 'Save Selected Model', size=(175, -1), action=self.onSaveFitResult) SetTip(self.save_result, 'save model and result to be loaded later') self.export_fit = Button(panel, 'Export Fit', size=(175, -1), action=self.onExportFitResult) SetTip(self.export_fit, 'save arrays and results to text file') irow = 0 sizer.Add(title, (irow, 0), (1, 2), LEFT) sizer.Add(wids['data_title'], (irow, 2), (1, 2), LEFT) irow += 1 sizer.Add(wids['hist_info'], (irow, 0), (1, 2), LEFT) sizer.Add(wids['hist_hint'], (irow, 2), (1, 2), LEFT) irow += 1 wids['model_desc'] = SimpleText(panel, '<Model>', font=Font(FONTSIZE+1), size=(700, 50), style=LEFT) sizer.Add(wids['model_desc'], (irow, 0), (1, 6), LEFT) irow += 1 sizer.Add(self.save_result, (irow, 0), (1, 1), LEFT) sizer.Add(self.export_fit, (irow, 1), (1, 2), LEFT) irow += 1 # sizer.Add(SimpleText(panel, 'Plot: '), (irow, 0), (1, 1), LEFT) sizer.Add(self.plot_choice, (irow, 0), (1, 2), LEFT) sizer.Add(wids['plot_bline'], (irow, 2), (1, 1), LEFT) sizer.Add(wids['plot_resid'], (irow, 3), (1, 1), LEFT) irow += 1 sizer.Add(HLine(panel, size=(650, 3)), (irow, 0), (1, 5), LEFT) irow += 1 title = SimpleText(panel, '[[Fit Statistics]]', font=Font(FONTSIZE+2), colour=self.colors.title, style=LEFT) sizer.Add(title, (irow, 0), (1, 4), LEFT) sview = self.wids['stats'] = dv.DataViewListCtrl(panel, style=DVSTYLE) sview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectFit) sview.AppendTextColumn(' Fit #', width=50) sview.AppendTextColumn(' N_data', width=50) sview.AppendTextColumn(' N_vary', width=50) sview.AppendTextColumn(' N_eval', width=60) sview.AppendTextColumn(' \u03c7\u00B2', width=110) sview.AppendTextColumn(' \u03c7\u00B2_reduced', width=110) sview.AppendTextColumn(' Akaike Info', width=110) sview.AppendTextColumn(' Bayesian Info', width=110) for col in range(sview.ColumnCount): this = sview.Columns[col] isort, align = True, wx.ALIGN_RIGHT if col == 0: align = wx.ALIGN_CENTER this.Sortable = isort this.Alignment = this.Renderer.Alignment = align sview.SetMinSize((700, 125)) irow += 1 sizer.Add(sview, (irow, 0), (1, 5), LEFT) irow += 1 sizer.Add(HLine(panel, size=(650, 3)), (irow, 0), (1, 5), LEFT) irow += 1 title = SimpleText(panel, '[[Variables]]', font=Font(FONTSIZE+2), colour=self.colors.title, style=LEFT) sizer.Add(title, (irow, 0), (1, 1), LEFT) self.wids['copy_params'] = Button(panel, 'Update Model with these values', size=(250, -1), action=self.onCopyParams) sizer.Add(self.wids['copy_params'], (irow, 1), (1, 3), LEFT) pview = self.wids['params'] = dv.DataViewListCtrl(panel, style=DVSTYLE) self.wids['paramsdata'] = [] pview.AppendTextColumn('Parameter', width=150) pview.AppendTextColumn('Best-Fit Value', width=125) pview.AppendTextColumn('Standard Error', width=125) pview.AppendTextColumn('Info ', width=275) for col in range(4): this = pview.Columns[col] align = wx.ALIGN_LEFT if col in (1, 2): align = wx.ALIGN_RIGHT this.Sortable = False this.Alignment = this.Renderer.Alignment = align pview.SetMinSize((700, 200)) pview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectParameter) irow += 1 sizer.Add(pview, (irow, 0), (1, 5), LEFT) irow += 1 sizer.Add(HLine(panel, size=(650, 3)), (irow, 0), (1, 5), LEFT) irow += 1 title = SimpleText(panel, '[[Correlations]]', font=Font(FONTSIZE+2), colour=self.colors.title, style=LEFT) self.wids['all_correl'] = Button(panel, 'Show All', size=(100, -1), action=self.onAllCorrel) self.wids['min_correl'] = FloatSpin(panel, value=MIN_CORREL, min_val=0, size=(100, -1), digits=3, increment=0.1) ctitle = SimpleText(panel, 'minimum correlation: ') sizer.Add(title, (irow, 0), (1, 1), LEFT) sizer.Add(ctitle, (irow, 1), (1, 1), LEFT) sizer.Add(self.wids['min_correl'], (irow, 2), (1, 1), LEFT) sizer.Add(self.wids['all_correl'], (irow, 3), (1, 1), LEFT) irow += 1 cview = self.wids['correl'] = dv.DataViewListCtrl(panel, style=DVSTYLE) cview.AppendTextColumn('Parameter 1', width=150) cview.AppendTextColumn('Parameter 2', width=150) cview.AppendTextColumn('Correlation', width=150) for col in (0, 1, 2): this = cview.Columns[col] this.Sortable = False align = wx.ALIGN_LEFT if col == 2: align = wx.ALIGN_RIGHT this.Alignment = this.Renderer.Alignment = align cview.SetMinSize((475, 200)) irow += 1 sizer.Add(cview, (irow, 0), (1, 5), LEFT) irow += 1 sizer.Add(HLine(panel, size=(400, 3)), (irow, 0), (1, 5), LEFT) pack(panel, sizer) panel.SetupScrolling() mainsizer = wx.BoxSizer(wx.VERTICAL) mainsizer.Add(panel, 1, wx.GROW|wx.ALL, 1) pack(self, mainsizer) self.Show() self.Raise()