Coverage for /Users/Newville/Codes/xraylarch/larch/wxlib/specfile_importer.py: 10%
478 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
1#!/usr/bin/env python
2"""
4"""
5import os
6import re
7import numpy as np
8np.seterr(all='ignore')
10from functools import partial
12import wx
13import wx.lib.scrolledpanel as scrolled
14import wx.lib.agw.flatnotebook as fnb
15from wxmplot import PlotPanel
17from wxutils import (SimpleText, FloatCtrl, GUIColors, Button, Choice,
18 FileCheckList, pack, Popup, Check, MenuItem, CEN,
19 RIGHT, LEFT, FRAMESTYLE, HLine, Font)
21import larch
22from larch import Group
23from larch.utils.strutils import fix_varname
24from larch.xafs.xafsutils import guess_energy_units
25from larch.io import look_for_nans, is_specfile, open_specfile
26from larch.utils.physical_constants import PLANCK_HC, DEG2RAD, PI
27from .columnframe import MultiColumnFrame, create_arrays, energy_may_need_rebinning
29CEN |= wx.ALL
30FNB_STYLE = fnb.FNB_NO_X_BUTTON|fnb.FNB_SMART_TABS
31FNB_STYLE |= fnb.FNB_NO_NAV_BUTTONS|fnb.FNB_NODRAG
33XPRE_OPS = ('', 'log(', '-log(')
34YPRE_OPS = ('', 'log(', '-log(')
35ARR_OPS = ('+', '-', '*', '/')
37YERR_OPS = ('Constant', 'Sqrt(Y)', 'Array')
38CONV_OPS = ('Lorenztian', 'Gaussian')
40XDATATYPES = ('raw', 'xas')
41ENUNITS_TYPES = ('eV', 'keV', 'degrees', 'not energy')
44class SpecfileImporter(wx.Frame) :
45 """Column Data File, select columns"""
46 def __init__(self, parent, filename=None, config=None, _larch=None,
47 read_ok_cb=None):
48 if not is_specfile(filename):
49 title = "Not a Specfile: %s" % filename
50 message = "Error reading %s as a Specfile" % filename
51 r = Popup(parent, message, title)
52 return None
54 self.parent = parent
55 self.path = filename
56 path, fname = os.path.split(filename)
57 self.filename = fname
58 self._larch = _larch
59 self.specfile = open_specfile(filename)
60 self.scans = []
61 curscan = None
62 for scandata in self.specfile.get_scans():
63 name, cmd, dtime = scandata
64 self.scans.append("%s | %s" % (name, cmd))
65 if curscan is None:
66 curscan = name
68 self.curscan = self.specfile.get_scan(curscan)
69 self.subframes = {}
70 self.workgroup = Group()
71 for attr in ('path', 'filename', 'datatype',
72 'array_labels', 'data'):
73 setattr(self.workgroup, attr, None)
75 self.array_labels = [l.lower() for l in self.curscan.array_labels]
77 if self.workgroup.datatype is None:
78 self.workgroup.datatype = 'raw'
79 for arrlab in self.array_labels[:4]:
80 if 'ener' in arrlab.lower():
81 self.workgroup.datatype = 'xas'
83 self.read_ok_cb = read_ok_cb
85 self.config = dict(xarr=self.curscan.axis.lower(), yarr1=None,
86 yarr2=None, yop='/', ypop='',
87 monod=3.1355316, en_units='eV',
88 yerror=YERR_OPS[0], yerr_val=1,
89 yerr_arr=None, dtc_config={}, multicol_config={})
91 if config is not None:
92 self.config.update(config)
94 if self.config['yarr2'] is None and 'i0' in self.array_labels:
95 self.config['yarr2'] = 'i0'
97 if self.config['yarr1'] is None:
98 if 'itrans' in self.array_labels:
99 self.config['yarr1'] = 'itrans'
100 elif 'i1' in self.array_labels:
101 self.config['yarr1'] = 'i1'
103 wx.Frame.__init__(self, None, -1, f'Build Arrays for {filename:s}',
104 style=FRAMESTYLE)
106 self.SetMinSize((750, 550))
107 self.SetSize((850, 650))
108 self.colors = GUIColors()
110 x0, y0 = parent.GetPosition()
111 self.SetPosition((x0+60, y0+60))
112 self.SetFont(Font(10))
114 splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
115 splitter.SetMinimumPaneSize(200)
117 leftpanel = wx.Panel(splitter)
118 ltop = wx.Panel(leftpanel)
120 sel_none = Button(ltop, 'Select None', size=(100, 30), action=self.onSelNone)
121 sel_all = Button(ltop, 'Select All', size=(100, 30), action=self.onSelAll)
122 sel_imp = Button(ltop, 'Import Selected Scans', size=(200, -1), action=self.onOK)
124 self.scanlist = FileCheckList(leftpanel, select_action=self.onScanSelect)
125 self.scanlist.AppendItems(self.scans)
127 tsizer = wx.GridBagSizer(2, 2)
128 tsizer.Add(sel_all, (0, 0), (1, 1), LEFT, 0)
129 tsizer.Add(sel_none, (0, 1), (1, 1), LEFT, 0)
130 tsizer.Add(sel_imp, (1, 0), (1, 2), LEFT, 0)
131 pack(ltop, tsizer)
133 sizer = wx.BoxSizer(wx.VERTICAL)
134 sizer.Add(ltop, 0, LEFT|wx.GROW, 1)
135 sizer.Add(self.scanlist, 1, LEFT|wx.GROW|wx.ALL, 1)
136 pack(leftpanel, sizer)
138 # right hand side
139 rightpanel = wx.Panel(splitter)
141 panel = wx.Panel(rightpanel)
142 # title row
143 self.title = SimpleText(panel,
144 " %s, scan %s" % (self.path, self.curscan.scan_name),
145 font=Font(11), colour=self.colors.title, style=LEFT)
147 self.wid_scantitle = SimpleText(panel, " %s" % self.curscan.title,
148 font=Font(11), style=LEFT)
149 self.wid_scantime = SimpleText(panel, self.curscan.timestring,
150 font=Font(11), style=LEFT)
152 yarr_labels = self.yarr_labels = self.array_labels + ['1.0', '0.0', '']
153 xarr_labels = self.xarr_labels = self.array_labels + ['_index']
155 self.xarr = Choice(panel, choices=xarr_labels, action=self.onXSelect, size=(150, -1))
156 self.yarr1 = Choice(panel, choices=yarr_labels, action=self.onUpdate, size=(150, -1))
157 self.yarr2 = Choice(panel, choices=yarr_labels, action=self.onUpdate, size=(150, -1))
158 self.yerr_arr = Choice(panel, choices=yarr_labels, action=self.onUpdate, size=(150, -1))
159 self.yerr_arr.Disable()
161 self.datatype = Choice(panel, choices=XDATATYPES, action=self.onUpdate, size=(150, -1))
162 self.datatype.SetStringSelection(self.workgroup.datatype)
164 self.en_units = Choice(panel, choices=ENUNITS_TYPES, action=self.onEnUnitsSelect,
165 size=(150, -1))
167 self.ypop = Choice(panel, choices=YPRE_OPS, action=self.onUpdate, size=(150, -1))
168 self.yop = Choice(panel, choices=ARR_OPS, action=self.onUpdate, size=(50, -1))
169 self.yerr_op = Choice(panel, choices=YERR_OPS, action=self.onYerrChoice, size=(150, -1))
171 self.yerr_val = FloatCtrl(panel, value=1, precision=4, size=(90, -1))
172 self.monod_val = FloatCtrl(panel, value=3.1355316, precision=7, size=(90, -1))
174 xlab = SimpleText(panel, ' X array: ')
175 ylab = SimpleText(panel, ' Y array: ')
176 units_lab = SimpleText(panel, ' Units: ')
177 yerr_lab = SimpleText(panel, ' Yerror: ')
178 dtype_lab = SimpleText(panel, ' Data Type: ')
179 monod_lab = SimpleText(panel, ' Mono D spacing (Ang): ')
180 yerrval_lab = SimpleText(panel, ' Value:')
182 self.ysuf = SimpleText(panel, '')
183 self.message = SimpleText(panel, '', font=Font(11),
184 colour=self.colors.title, style=LEFT)
186 self.ypop.SetStringSelection(self.config['ypop'])
187 self.yop.SetStringSelection(self.config['yop'])
188 self.monod_val.SetValue(self.config['monod'])
189 self.monod_val.SetAction(self.onUpdate)
191 self.monod_val.Enable(self.config['en_units'].startswith('deg'))
192 self.en_units.SetStringSelection(self.config['en_units'])
193 self.yerr_op.SetStringSelection(self.config['yerror'])
194 self.yerr_val.SetValue(self.config['yerr_val'])
195 if '(' in self.config['ypop']:
196 self.ysuf.SetLabel(')')
198 ixsel, iysel, iy2sel, iyesel = 0, 1, len(yarr_labels)-1, len(yarr_labels)-1
199 if self.config['xarr'] in xarr_labels:
200 ixsel = xarr_labels.index(self.config['xarr'])
201 if self.config['yarr1'] in self.array_labels:
202 iysel = self.array_labels.index(self.config['yarr1'])
203 if self.config['yarr2'] in yarr_labels:
204 iy2sel = yarr_labels.index(self.config['yarr2'])
205 if self.config['yerr_arr'] in yarr_labels:
206 iyesel = yarr_labels.index(self.config['yerr_arr'])
207 self.xarr.SetSelection(ixsel)
208 self.yarr1.SetSelection(iysel)
209 self.yarr2.SetSelection(iy2sel)
210 self.yerr_arr.SetSelection(iyesel)
212 self.info_message = SimpleText(panel, ' ', font=Font(12),
213 colour=wx.Colour(100, 10, 10), style=LEFT)
215 bpanel = wx.Panel(panel)
216 bsizer = wx.BoxSizer(wx.HORIZONTAL)
217 self.multi_sel = Button(bpanel, 'Select Multilple Columns', action=self.onMultiColumn)
218 self.multi_clear = Button(bpanel, 'Clear Multiple Columns', action=self.onClearMultiColumn)
219 self.multi_clear.Disable()
220 self.multi_sel.SetToolTip('Select Multiple Columns to import as separate groups')
221 self.multi_clear.SetToolTip('Clear Multiple Column Selection')
222 bsizer.Add(self.multi_sel)
223 bsizer.Add(self.multi_clear)
224 pack(bpanel, bsizer)
226 sizer = wx.GridBagSizer(2, 2)
227 ir = 0
228 sizer.Add(self.title, (ir, 0), (1, 7), LEFT, 5)
230 ir += 1
231 sizer.Add(self.wid_scantitle, (ir, 0), (1, 3), LEFT, 0)
232 sizer.Add(self.wid_scantime, (ir, 3), (1, 2), LEFT, 0)
235 ir += 1
236 sizer.Add(xlab, (ir, 0), (1, 1), LEFT, 0)
237 sizer.Add(self.xarr, (ir, 1), (1, 1), LEFT, 0)
238 sizer.Add(units_lab, (ir, 2), (1, 2), RIGHT, 0)
239 sizer.Add(self.en_units, (ir, 4), (1, 2), LEFT, 0)
241 ir += 1
242 sizer.Add(dtype_lab, (ir, 0), (1, 1), LEFT, 0)
243 sizer.Add(self.datatype, (ir, 1), (1, 1), LEFT, 0)
244 sizer.Add(monod_lab, (ir, 2), (1, 2), RIGHT, 0)
245 sizer.Add(self.monod_val, (ir, 4), (1, 1), LEFT, 0)
247 ir += 1
248 sizer.Add(ylab, (ir, 0), (1, 1), LEFT, 0)
249 sizer.Add(self.ypop, (ir, 1), (1, 1), LEFT, 0)
250 sizer.Add(self.yarr1, (ir, 2), (1, 1), LEFT, 0)
251 sizer.Add(self.yop, (ir, 3), (1, 1), RIGHT, 0)
252 sizer.Add(self.yarr2, (ir, 4), (1, 1), LEFT, 0)
253 sizer.Add(self.ysuf, (ir, 5), (1, 1), LEFT, 0)
255 ir += 1
256 sizer.Add(yerr_lab, (ir, 0), (1, 1), LEFT, 0)
257 sizer.Add(self.yerr_op, (ir, 1), (1, 1), LEFT, 0)
258 sizer.Add(self.yerr_arr, (ir, 2), (1, 1), LEFT, 0)
259 sizer.Add(yerrval_lab, (ir, 3), (1, 1), RIGHT, 0)
260 sizer.Add(self.yerr_val, (ir, 4), (1, 2), LEFT, 0)
262 ir += 1
263 sizer.Add(self.message, (ir, 0), (1, 4), LEFT, 0)
264 ir +=1
265 sizer.Add(bpanel, (ir, 0), (1, 5), LEFT, 3)
267 pack(panel, sizer)
269 self.nb = fnb.FlatNotebook(rightpanel, -1, agwStyle=FNB_STYLE)
270 self.nb.SetTabAreaColour(wx.Colour(248,248,240))
271 self.nb.SetActiveTabColour(wx.Colour(254,254,195))
272 self.nb.SetNonActiveTabTextColour(wx.Colour(40,40,180))
273 self.nb.SetActiveTabTextColour(wx.Colour(80,0,0))
275 self.plotpanel = PlotPanel(rightpanel, messenger=self.plot_messages)
276 try:
277 plotopts = self._larch.symtable._sys.wx.plotopts
278 self.plotpanel.conf.set_theme(plotopts['theme'])
279 self.plotpanel.conf.enable_grid(plotopts['show_grid'])
280 except:
281 pass
283 self.plotpanel.SetMinSize((300, 250))
285 shead = wx.Panel(rightpanel)
286 self.scanheader = wx.TextCtrl(shead, style=wx.TE_MULTILINE|wx.TE_READONLY,
287 size=(400, 250))
288 self.scanheader.SetValue('\n'.join(self.curscan.scan_header))
289 self.scanheader.SetFont(Font(10))
290 textsizer = wx.BoxSizer(wx.VERTICAL)
291 textsizer.Add(self.scanheader, 1, LEFT|wx.GROW, 1)
292 pack(shead, textsizer)
295 fhead = wx.Panel(rightpanel)
296 self.fileheader = wx.TextCtrl(fhead, style=wx.TE_MULTILINE|wx.TE_READONLY,
297 size=(400, 250))
298 self.fileheader.SetValue('\n'.join(self.curscan.file_header))
299 self.fileheader.SetFont(Font(10))
300 textsizer = wx.BoxSizer(wx.VERTICAL)
301 textsizer.Add(self.fileheader, 1, LEFT|wx.GROW, 1)
302 pack(fhead, textsizer)
306 self.nb.AddPage(fhead, ' File Header ', True)
307 self.nb.AddPage(shead, ' Scan Header ', True)
308 self.nb.AddPage(self.plotpanel, ' Plot of Selected Arrays ', True)
310 sizer = wx.BoxSizer(wx.VERTICAL)
311 sizer.Add(panel, 0, LEFT|wx.GROW, 1)
312 sizer.Add(self.nb, 1, LEFT|wx.GROW|wx.ALL, 1)
313 pack(rightpanel, sizer)
315 splitter.SplitVertically(leftpanel, rightpanel, 1)
316 self.statusbar = self.CreateStatusBar(2, 0)
317 self.statusbar.SetStatusWidths([-1, -1])
318 statusbar_fields = [filename, ""]
319 for i in range(len(statusbar_fields)):
320 self.statusbar.SetStatusText(statusbar_fields[i], i)
322 self.set_energy_units()
323 csize = self.GetSize()
324 bsize = self.GetBestSize()
325 if bsize[0] > csize[0]: csize[0] = bsize[0]
326 if bsize[1] > csize[1]: csize[1] = bsize[1]
327 self.SetSize(csize)
328 self.Show()
329 self.Raise()
330 self.onUpdate(self)
332 def set_energy_units(self):
333 ix = self.xarr.GetSelection()
334 xname = self.xarr.GetStringSelection()
335 rdata = self.curscan.data
336 try:
337 ncol, npts = rdata.shape
338 except:
339 self.statusbar.SetStatusText(f"Warning: Could not read data for scan '{self.curscan.title:s}'")
341 workgroup = self.workgroup
342 if xname.startswith('_index') or ix >= ncol:
343 workgroup.xdat = 1.0*np.arange(npts)
344 else:
345 workgroup.xdat = 1.0*rdata[ix, :]
346 eguess = guess_energy_units(workgroup.xdat)
347 if eguess.startswith('eV'):
348 self.en_units.SetStringSelection('eV')
349 elif eguess.startswith('keV'):
350 self.en_units.SetStringSelection('keV')
352 def onScanSelect(self, event=None):
353 try:
354 scan_desc = event.GetString()
355 name = [s.strip() for s in scan_desc.split(' | ')][0]
356 self.curscan = self.specfile.get_scan(name)
357 except:
358 return
359 slist = list(self.scanlist.GetCheckedStrings())
360 if scan_desc not in slist:
361 slist.append(scan_desc)
362 self.scanlist.SetCheckedStrings(slist)
364 self.wid_scantitle.SetLabel(" %s" % self.curscan.title)
365 self.wid_scantime.SetLabel(self.curscan.timestring)
367 self.title.SetLabel(" %s, scan %s" % (self.path, self.curscan.scan_name))
368 self.array_labels = [l.lower() for l in self.curscan.array_labels]
369 self.workgroup.array_labels = self.array_labels
370 self.workgroup.data = self.curscan.data
372 yarr_labels = self.yarr_labels = self.array_labels + ['1.0', '0.0', '']
373 xarr_labels = self.xarr_labels = self.array_labels + ['_index']
375 xsel = self.xarr.GetStringSelection()
376 self.xarr.Clear()
377 self.xarr.AppendItems(xarr_labels)
378 if xsel in xarr_labels:
379 self.xarr.SetStringSelection(xsel)
380 else:
381 self.xarr.SetSelection(0)
383 y1sel = self.yarr1.GetStringSelection()
384 self.yarr1.Clear()
385 self.yarr1.AppendItems(yarr_labels)
386 if y1sel in yarr_labels:
387 self.yarr1.SetStringSelection(y1sel)
388 else:
389 self.yarr1.SetSelection(1)
391 y2sel = self.yarr2.GetStringSelection()
392 self.yarr2.Clear()
393 self.yarr2.AppendItems(yarr_labels)
394 if y2sel in yarr_labels:
395 self.yarr2.SetStringSelection(y2sel)
397 xsel = self.xarr.GetStringSelection()
398 self.workgroup.datatype = 'xas' if 'en' in xsel else 'raw'
399 self.datatype.SetStringSelection(self.workgroup.datatype)
401 self.scanheader.SetValue('\n'.join(self.curscan.scan_header))
402 self.set_energy_units()
403 self.onUpdate()
405 def onClearMultiColumn(self, event=None):
406 self.config['multicol_config'] = {}
407 self.message.SetLabel(f" cleared reading of multiple columns")
408 self.multi_clear.Disable()
409 self.yarr1.Enable()
410 self.ypop.Enable()
411 self.yop.Enable()
412 self.onUpdate()
414 def onMultiColumn(self, event=None):
415 if 'multicol_config' not in self.config:
416 self.config['multicol_config'] = {}
418 if len(self.array_labels) < 1:
419 self.array_labels = [l.lower() for l in self.curscan.array_labels]
420 self.workgroup.array_labels = self.array_labels
421 self.workgroup.data = self.curscan.data
422 self.show_subframe('multicol', MultiColumnFrame,
423 config=self.config['multicol_config'],
424 group=self.workgroup,
425 on_ok=self.onMultiColumn_OK)
427 def onMultiColumn_OK(self, config, update=True, **kws):
428 chans = config.get('channels', [])
429 if len(chans) == 0:
430 self.config['multicol_config'] = {}
431 else:
432 self.config['multicol_config'] = config
433 self.yarr1.SetSelection(chans[0])
434 self.yarr2.SetSelection(config['i0'])
435 self.ypop.SetStringSelection('')
436 self.yarr1.Disable()
437 self.ypop.Disable()
438 self.yop.Disable()
439 y2 = self.yarr2.GetStringSelection()
440 msg = f" Will import {len(config['channels'])} Y arrays, divided by '{y2}'"
441 self.message.SetLabel(msg)
442 self.multi_clear.Enable()
443 if update:
444 self.onUpdate()
447 def show_subframe(self, name, frameclass, **opts):
448 shown = False
449 if name in self.subframes:
450 try:
451 self.subframes[name].Raise()
452 shown = True
453 except:
454 pass
455 if not shown:
456 self.subframes[name] = frameclass(self, **opts)
457 self.subframes[name].Show()
458 self.subframes[name].Raise()
460 def set_array_labels(self, arr_labels):
461 self.workgroup.array_labels = arr_labels
462 yarr_labels = self.yarr_labels = arr_labels + ['1.0', '0.0', '']
463 xarr_labels = self.xarr_labels = arr_labels + ['_index']
464 def update(wid, choices):
465 curstr = wid.GetStringSelection()
466 curind = wid.GetSelection()
467 wid.SetChoices(choices)
468 if curstr in choices:
469 wid.SetStringSelection(curstr)
470 else:
471 wid.SetSelection(curind)
472 update(self.xarr, xarr_labels)
473 update(self.yarr1, yarr_labels)
474 update(self.yarr2, yarr_labels)
475 update(self.yerr_arr, yarr_labels)
476 self.onUpdate()
478 def onSelAll(self, event=None):
479 self.scanlist.SetCheckedStrings(self.scans)
481 def onSelNone(self, event=None):
482 self.scanlist.SetCheckedStrings([])
484 def onOK(self, event=None):
485 """ build arrays according to selection """
487 scanlist = []
488 for s in self.scanlist.GetCheckedStrings():
489 words = [s.strip() for s in s.split('|')]
490 scanlist.append(words[0])
491 if len(scanlist) == 0:
492 cancel = Popup(self, """No scans selected.
493 Cancel import from this project?""", 'Cancel Import?',
494 style=wx.YES_NO)
495 if wx.ID_YES == cancel:
496 self.Destroy()
497 else:
498 return
500 self.read_form()
501 cout = create_arrays(self.workgroup, **self.config)
502 self.config.update(cout)
503 conf = self.config
504 conf['array_labels'] = self.workgroup.array_labels
506 if self.ypop.Enabled: #not using multicolumn mode
507 conf['multicol_config'] = {'channels': [], 'i0': conf['iy2']}
509 self.expressions = conf['expressions']
511 # generate script to pass back to calling program:
512 # read_cmd = "_specfile.get_scan(scan='{scan}')"
513 buff = ["{group} = {specfile}.get_scan(scan='{scan}')",
514 "{group}.path = '{path}'",
515 "{group}.is_frozen = False"]
517 for attr in ('datatype', 'plot_xlabel', 'plot_ylabel'):
518 val = getattr(self.workgroup, attr)
519 buff.append("{group}.%s = '%s'" % (attr, val))
521 xexpr = self.expressions['xdat']
522 en_units = conf['en_units']
523 if en_units.startswith('deg'):
524 buff.append(f"mono_dspace = {dspace:.9f}")
525 buff.append(f"{{group}}.xdat = PLANCK_HC/(2*mono_dspace*sin(DEG2RAD*({expr:s})))")
526 elif en_units.startswith('keV'):
527 buff.append(f"{{group}}.xdat = 1000.0*{xexpr:s}")
528 else:
529 buff.append(f"{{group}}.xdat = {xexpr:s}")
531 for aname in ('ydat', 'yerr'):
532 expr = self.expressions[aname]
533 buff.append(f"{{group}}.{aname} = {expr}")
535 if getattr(self.workgroup, 'datatype', 'raw') == 'xas':
536 buff.append("{group}.energy = {group}.xdat")
537 buff.append("{group}.mu = {group}.ydat")
538 buff.append("sort_xafs({group}, overwrite=True, fix_repeats=True)")
539 else:
540 buff.append("{group}.scale = 1./({group}.ydat.ptp()+1.e-16)")
541 script = "\n".join(buff)
543 self.config['array_desc'] = dict(xdat=self.workgroup.plot_xlabel,
544 ydat=self.workgroup.plot_ylabel,
545 yerr=self.expressions['yerr'])
546 if self.read_ok_cb is not None:
547 self.read_ok_cb(script, self.path, scanlist,
548 config=self.config)
550 for f in self.subframes.values():
551 try:
552 f.Destroy()
553 except:
554 pass
555 self.Destroy()
557 def onCancel(self, event=None):
558 self.workgroup.import_ok = False
559 for f in self.subframes.values():
560 try:
561 f.Destroy()
562 except:
563 pass
564 self.Destroy()
566 def onYerrChoice(self, evt=None):
567 yerr_choice = evt.GetString()
568 self.yerr_arr.Disable()
569 self.yerr_val.Disable()
570 if 'const' in yerr_choice.lower():
571 self.yerr_val.Enable()
572 elif 'array' in yerr_choice.lower():
573 self.yerr_arr.Enable()
574 self.onUpdate()
576 def onXSelect(self, evt=None):
577 ix = self.xarr.GetSelection()
578 xname = self.xarr.GetStringSelection()
580 workgroup = self.workgroup
581 rdata = self.curscan.data
582 ncol, npts = rdata.shape
583 if xname.startswith('_index') or ix >= ncol:
584 workgroup.xdat = 1.0*np.arange(npts)
585 else:
586 workgroup.xdat = 1.0*rdata[ix, :]
588 self.monod_val.Disable()
589 if self.datatype.GetStringSelection().strip().lower() == 'raw':
590 self.en_units.SetSelection(4)
591 else:
592 eguess = guess_energy_units(workgroup.xdat)
593 if eguess.startswith('keV'):
594 self.en_units.SetSelection(1)
595 elif eguess.startswith('deg'):
596 self.en_units.SetSelection(2)
597 self.monod_val.Enable()
598 else:
599 self.en_units.SetSelection(0)
601 self.onUpdate()
603 def onEnUnitsSelect(self, evt=None):
604 self.monod_val.Enable(self.en_units.GetStringSelection().startswith('deg'))
605 self.onUpdate()
607 def read_form(self, **kws):
608 """return form configuration"""
609 datatype = self.datatype.GetStringSelection().strip().lower()
610 if datatype == 'raw':
611 self.en_units.SetStringSelection('not energy')
613 conf = {'datatype': datatype,
614 'ix': self.xarr.GetSelection(),
615 'xarr': self.xarr.GetStringSelection(),
616 'en_units': self.en_units.GetStringSelection(),
617 'monod': float(self.monod_val.GetValue()),
618 'yarr1': self.yarr1.GetStringSelection().strip(),
619 'yarr2': self.yarr2.GetStringSelection().strip(),
620 'iy1': self.yarr1.GetSelection(),
621 'iy2': self.yarr2.GetSelection(),
622 'yop': self.yop.GetStringSelection().strip(),
623 'ypop': self.ypop.GetStringSelection().strip(),
624 'iyerr': self.yerr_arr.GetSelection(),
625 'yerr_arr': self.yerr_arr.GetStringSelection(),
626 'yerr_op': self.yerr_op.GetStringSelection().lower(),
627 'yerr_val': self.yerr_val.GetValue(),
628 }
629 self.config.update(conf)
630 return conf
633 def onUpdate(self, value=None, evt=None):
634 """column selections changed calc xdat and ydat"""
635 workgroup = self.workgroup
636 workgroup.data = self.curscan.data
637 workgroup.filename = self.curscan.filename
639 conf = self.read_form()
640 cout = create_arrays(workgroup, **conf)
642 self.expression = cout.pop('expressions')
643 conf.update(cout)
645 if energy_may_need_rebinning(workgroup):
646 self.info_message.SetLabel("Warning: XAS data may need to be rebinned!")
648 path, fname = os.path.split(workgroup.filename)
649 popts = dict(marker='o', markersize=4, linewidth=1.5, title=fname,
650 ylabel=workgroup.plot_ylabel,
651 xlabel=workgroup.plot_xlabel,
652 label=workgroup.plot_ylabel)
653 try:
654 self.plotpanel.plot(workgroup.xdat, workgroup.ydat, **popts)
655 except:
656 pass
659 def plot_messages(self, msg, panel=1):
660 self.statusbar.SetStatusText(msg, panel)