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

1#!/usr/bin/env python 

2""" 

3 

4""" 

5import os 

6import re 

7import numpy as np 

8np.seterr(all='ignore') 

9 

10from functools import partial 

11 

12import wx 

13import wx.lib.scrolledpanel as scrolled 

14import wx.lib.agw.flatnotebook as fnb 

15from wxmplot import PlotPanel 

16 

17from wxutils import (SimpleText, FloatCtrl, GUIColors, Button, Choice, 

18 FileCheckList, pack, Popup, Check, MenuItem, CEN, 

19 RIGHT, LEFT, FRAMESTYLE, HLine, Font) 

20 

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 

28 

29CEN |= wx.ALL 

30FNB_STYLE = fnb.FNB_NO_X_BUTTON|fnb.FNB_SMART_TABS 

31FNB_STYLE |= fnb.FNB_NO_NAV_BUTTONS|fnb.FNB_NODRAG 

32 

33XPRE_OPS = ('', 'log(', '-log(') 

34YPRE_OPS = ('', 'log(', '-log(') 

35ARR_OPS = ('+', '-', '*', '/') 

36 

37YERR_OPS = ('Constant', 'Sqrt(Y)', 'Array') 

38CONV_OPS = ('Lorenztian', 'Gaussian') 

39 

40XDATATYPES = ('raw', 'xas') 

41ENUNITS_TYPES = ('eV', 'keV', 'degrees', 'not energy') 

42 

43 

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 

53 

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 

67 

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) 

74 

75 self.array_labels = [l.lower() for l in self.curscan.array_labels] 

76 

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' 

82 

83 self.read_ok_cb = read_ok_cb 

84 

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={}) 

90 

91 if config is not None: 

92 self.config.update(config) 

93 

94 if self.config['yarr2'] is None and 'i0' in self.array_labels: 

95 self.config['yarr2'] = 'i0' 

96 

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' 

102 

103 wx.Frame.__init__(self, None, -1, f'Build Arrays for {filename:s}', 

104 style=FRAMESTYLE) 

105 

106 self.SetMinSize((750, 550)) 

107 self.SetSize((850, 650)) 

108 self.colors = GUIColors() 

109 

110 x0, y0 = parent.GetPosition() 

111 self.SetPosition((x0+60, y0+60)) 

112 self.SetFont(Font(10)) 

113 

114 splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) 

115 splitter.SetMinimumPaneSize(200) 

116 

117 leftpanel = wx.Panel(splitter) 

118 ltop = wx.Panel(leftpanel) 

119 

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) 

123 

124 self.scanlist = FileCheckList(leftpanel, select_action=self.onScanSelect) 

125 self.scanlist.AppendItems(self.scans) 

126 

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) 

132 

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) 

137 

138 # right hand side 

139 rightpanel = wx.Panel(splitter) 

140 

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) 

146 

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) 

151 

152 yarr_labels = self.yarr_labels = self.array_labels + ['1.0', '0.0', ''] 

153 xarr_labels = self.xarr_labels = self.array_labels + ['_index'] 

154 

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() 

160 

161 self.datatype = Choice(panel, choices=XDATATYPES, action=self.onUpdate, size=(150, -1)) 

162 self.datatype.SetStringSelection(self.workgroup.datatype) 

163 

164 self.en_units = Choice(panel, choices=ENUNITS_TYPES, action=self.onEnUnitsSelect, 

165 size=(150, -1)) 

166 

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)) 

170 

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)) 

173 

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:') 

181 

182 self.ysuf = SimpleText(panel, '') 

183 self.message = SimpleText(panel, '', font=Font(11), 

184 colour=self.colors.title, style=LEFT) 

185 

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) 

190 

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(')') 

197 

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) 

211 

212 self.info_message = SimpleText(panel, ' ', font=Font(12), 

213 colour=wx.Colour(100, 10, 10), style=LEFT) 

214 

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) 

225 

226 sizer = wx.GridBagSizer(2, 2) 

227 ir = 0 

228 sizer.Add(self.title, (ir, 0), (1, 7), LEFT, 5) 

229 

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) 

233 

234 

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) 

240 

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) 

246 

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) 

254 

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) 

261 

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) 

266 

267 pack(panel, sizer) 

268 

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)) 

274 

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 

282 

283 self.plotpanel.SetMinSize((300, 250)) 

284 

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) 

293 

294 

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) 

303 

304 

305 

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) 

309 

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) 

314 

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) 

321 

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) 

331 

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}'") 

340 

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') 

351 

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) 

363 

364 self.wid_scantitle.SetLabel(" %s" % self.curscan.title) 

365 self.wid_scantime.SetLabel(self.curscan.timestring) 

366 

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 

371 

372 yarr_labels = self.yarr_labels = self.array_labels + ['1.0', '0.0', ''] 

373 xarr_labels = self.xarr_labels = self.array_labels + ['_index'] 

374 

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) 

382 

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) 

390 

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) 

396 

397 xsel = self.xarr.GetStringSelection() 

398 self.workgroup.datatype = 'xas' if 'en' in xsel else 'raw' 

399 self.datatype.SetStringSelection(self.workgroup.datatype) 

400 

401 self.scanheader.SetValue('\n'.join(self.curscan.scan_header)) 

402 self.set_energy_units() 

403 self.onUpdate() 

404 

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() 

413 

414 def onMultiColumn(self, event=None): 

415 if 'multicol_config' not in self.config: 

416 self.config['multicol_config'] = {} 

417 

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) 

426 

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() 

445 

446 

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() 

459 

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() 

477 

478 def onSelAll(self, event=None): 

479 self.scanlist.SetCheckedStrings(self.scans) 

480 

481 def onSelNone(self, event=None): 

482 self.scanlist.SetCheckedStrings([]) 

483 

484 def onOK(self, event=None): 

485 """ build arrays according to selection """ 

486 

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 

499 

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 

505 

506 if self.ypop.Enabled: #not using multicolumn mode 

507 conf['multicol_config'] = {'channels': [], 'i0': conf['iy2']} 

508 

509 self.expressions = conf['expressions'] 

510 

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"] 

516 

517 for attr in ('datatype', 'plot_xlabel', 'plot_ylabel'): 

518 val = getattr(self.workgroup, attr) 

519 buff.append("{group}.%s = '%s'" % (attr, val)) 

520 

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}") 

530 

531 for aname in ('ydat', 'yerr'): 

532 expr = self.expressions[aname] 

533 buff.append(f"{{group}}.{aname} = {expr}") 

534 

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) 

542 

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) 

549 

550 for f in self.subframes.values(): 

551 try: 

552 f.Destroy() 

553 except: 

554 pass 

555 self.Destroy() 

556 

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() 

565 

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() 

575 

576 def onXSelect(self, evt=None): 

577 ix = self.xarr.GetSelection() 

578 xname = self.xarr.GetStringSelection() 

579 

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, :] 

587 

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) 

600 

601 self.onUpdate() 

602 

603 def onEnUnitsSelect(self, evt=None): 

604 self.monod_val.Enable(self.en_units.GetStringSelection().startswith('deg')) 

605 self.onUpdate() 

606 

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') 

612 

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 

631 

632 

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 

638 

639 conf = self.read_form() 

640 cout = create_arrays(workgroup, **conf) 

641 

642 self.expression = cout.pop('expressions') 

643 conf.update(cout) 

644 

645 if energy_may_need_rebinning(workgroup): 

646 self.info_message.SetLabel("Warning: XAS data may need to be rebinned!") 

647 

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 

657 

658 

659 def plot_messages(self, msg, panel=1): 

660 self.statusbar.SetStatusText(msg, panel)