Coverage for larch/wxmap/mapviewer.py: 10%

1931 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-10-16 21:04 +0000

1#!/usr/bin/env python 

2""" 

3GUI for displaying maps from HDF5 files 

4 

5""" 

6 

7import os 

8import platform 

9import sys 

10import time 

11import json 

12import socket 

13import datetime 

14from functools import partial 

15from threading import Thread 

16from collections import namedtuple 

17from pathlib import Path 

18 

19import wx 

20from wx.adv import AboutBox, AboutDialogInfo 

21import wx.lib.scrolledpanel as scrolled 

22import wx.lib.mixins.inspection 

23 

24import wx.dataview as dv 

25DVSTY = dv.DV_SINGLE|dv.DV_VERT_RULES|dv.DV_ROW_LINES 

26 

27HAS_EPICS = False 

28try: 

29 from epics import caput 

30 HAS_EPICS = True 

31except: 

32 pass 

33 

34import numpy as np 

35import scipy.stats as stats 

36 

37#from matplotlib.widgets import Slider, Button, RadioButtons 

38 

39from wxmplot import PlotFrame 

40 

41import larch 

42from larch.larchlib import read_workdir, save_workdir 

43from larch.wxlib import (LarchPanel, LarchFrame, EditableListBox, SimpleText, 

44 FloatCtrl, Font, pack, Popup, Button, MenuItem, 

45 Choice, Check, GridPanel, FileSave, HLine, flatnotebook, 

46 HLine, OkCancel, LEFT, LarchUpdaterDialog, LarchWxApp) 

47from larch.wxxas.xas_dialogs import fit_dialog_window 

48from larch.utils.strutils import bytes2str, version_ge 

49from larch.utils import get_cwd 

50from larch.site_config import icondir 

51from larch.version import check_larchversion 

52from larch.utils.physical_constants import PLANCK_HC 

53 

54from ..xrd import lambda_from_E, xrd1d, save1D, calculate_xvalues, read_poni 

55from ..xrmmap import GSEXRM_MapFile, GSEXRM_FileStatus, h5str, ensure_subgroup, DEFAULT_XRAY_ENERGY 

56from ..apps import check_larchversion, update_larch 

57from ..epics import pv_fullname 

58from ..wxlib.xrfdisplay import XRFDisplayFrame 

59 

60from .mapimageframe import MapImageFrame, CorrelatedMapFrame 

61from .mapmathpanel import MapMathPanel 

62from .maptomopanel import TomographyPanel 

63from .mapxrfpanel import XRFAnalysisPanel 

64 

65from ..wxxrd.xrd1d_display import XRD1DFrame 

66 

67def timestring(): 

68 return datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f') 

69 

70FONTSIZE = 8 

71if platform.system() in ('Windows', 'Darwin'): 

72 FONTSIZE = 10 

73 

74CEN = wx.ALIGN_CENTER 

75LEFT = wx.ALIGN_LEFT 

76RIGHT = wx.ALIGN_RIGHT 

77ALL_CEN = wx.ALL|CEN 

78ALL_LEFT = wx.ALL|LEFT 

79ALL_RIGHT = wx.ALL|RIGHT 

80 

81 

82FILE_WILDCARDS = 'X-ray Maps (*.h5)|*.h5|All files (*.*)|*.*' 

83 

84XRF_ICON_FILE = 'gse_xrfmap.ico' 

85 

86NOT_OWNER_MSG = """The File 

87 '%s' 

88appears to be open by another process. Having two 

89processes writing to the file can cause corruption. 

90 

91Do you want to take ownership of the file? 

92""" 

93 

94NOT_GSEXRM_FILE = """The File 

95 '%s' 

96doesn't seem to be a Map File 

97""" 

98 

99NOT_GSEXRM_FOLDER = """The Folder 

100 '%s' 

101doesn't seem to be a Map Folder 

102""" 

103FILE_ALREADY_READ = """The File 

104 '%s' 

105has already been read. 

106""" 

107 

108FRAMESTYLE = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL 

109BEAMLINE = '13-ID-E' 

110FACILITY = 'APS' 

111 

112PLOT_TYPES = ('Single ROI Map', 'Three ROI Map', 'Correlation Plot') 

113PROCROWS_CHOICES = ('All', '500', '200', '100', '50', '20', '10') 

114PLOT_OPERS = ('/', '*', '-', '+') 

115 

116ESCAN_CRED = os.environ.get('ESCAN_CREDENTIALS', None) 

117if ESCAN_CRED is not None: 

118 try: 

119 from ..epics.larchscan import connect_scandb 

120 except ImportError: 

121 ESCAN_CRED = None 

122 

123CWID = 150 

124WWID = 100 + CWID*4 

125 

126class MapPanel(GridPanel): 

127 '''Panel of Controls for viewing maps''' 

128 label = 'ROI Map' 

129 def __init__(self, parent, owner=None, **kws): 

130 

131 self.owner = owner 

132 self.cfile, self.xrmmap = None,None 

133 self.last_process_time = 0 

134 self.detectors_set = False 

135 GridPanel.__init__(self, parent, nrows=8, ncols=6, **kws) 

136 

137 self.plot_choice = Choice(self, choices=PLOT_TYPES, size=(CWID, -1)) 

138 self.plot_choice.Bind(wx.EVT_CHOICE, self.plotSELECT) 

139 

140 self.det_choice = [Choice(self, size=(CWID, -1)), 

141 Choice(self, size=(CWID, -1)), 

142 Choice(self, size=(CWID, -1)), 

143 Choice(self, size=(CWID, -1))] 

144 

145 self.roi_choice = [Choice(self, size=(CWID, -1)), 

146 Choice(self, size=(CWID, -1)), 

147 Choice(self, size=(CWID, -1)), 

148 Choice(self, size=(CWID, -1))] 

149 for i,det_chc in enumerate(self.det_choice): 

150 det_chc.Bind(wx.EVT_CHOICE, partial(self.detSELECT,i)) 

151 

152 for i,roi_chc in enumerate(self.roi_choice): 

153 roi_chc.Bind(wx.EVT_CHOICE, partial(self.roiSELECT,i)) 

154 

155 self.det_label = [SimpleText(self,'Intensity'), 

156 SimpleText(self,''), 

157 SimpleText(self,''), 

158 SimpleText(self, 'Normalization')] 

159 self.roi_label = [SimpleText(self,''), 

160 SimpleText(self,''), 

161 SimpleText(self,''), 

162 SimpleText(self,'')] 

163 

164 fopts = dict(minval=-50000, precision=0, size=(70, -1)) 

165 self.lims = [FloatCtrl(self, value= 0, **fopts), 

166 FloatCtrl(self, value=-1, **fopts), 

167 FloatCtrl(self, value= 0, **fopts), 

168 FloatCtrl(self, value=-1, **fopts)] 

169 

170 self.zigoff = FloatCtrl(self, value=0, minval=-15, maxval=15, 

171 precision=0, size=(70, -1)) 

172 for wid in self.lims: 

173 wid.Disable() 

174 

175 self.use_dtcorr = Check(self, default=True, 

176 label='Correct for Detector Deadtime', 

177 action=self.onDTCorrect) 

178 self.use_hotcols = Check(self, default=False, 

179 label='Remove First and Last columns', 

180 action=self.onHotCols) 

181 

182 self.use_zigzag = Check(self, default=False, label='Fix ZigZag', 

183 action=self.onZigZag) 

184 

185 self.limrange = Check(self, default=False, 

186 label=' Limit Map Range to Pixel Range:', 

187 action=self.onLimitRange) 

188 

189 map_shownew = Button(self, 'Show New Map', size=(CWID, -1), 

190 action=partial(self.onROIMap, new=True)) 

191 map_update = Button(self, 'Replace Last Map', size=(CWID, -1), 

192 action=partial(self.onROIMap, new=False)) 

193 self.mapproc_btn = Button(self, 'Add More Rows', size=(CWID, -1), 

194 action=self.onProcessMap) 

195 

196 map_showxrf = Button(self, 'Show Full XRF', size=(CWID, -1), 

197 action=self.onShowXRF) 

198 

199 self.mapproc_nrows = Choice(self, choices=PROCROWS_CHOICES, size=(CWID, -1)) 

200 self.mapproc_nrows.SetStringSelection('100') 

201 

202 self.Add(SimpleText(self, 'Build Map From Raw Data Folder:'), 

203 dcol=2, style=LEFT, newrow=True) 

204 self.Add(self.mapproc_btn, dcol=1, style=LEFT) 

205 self.Add(SimpleText(self, 'Max # Rows to Add:'), dcol=1, 

206 style=LEFT, newrow=False) 

207 self.Add(self.mapproc_nrows, dcol=1, style=LEFT) 

208 

209 self.Add(HLine(self, size=(WWID, 5)), dcol=8, style=LEFT, newrow=True) 

210 self.Add((5, 5), newrow=True) 

211 

212 self.Add(SimpleText(self, 'Display ROI Maps: Plot Type:'), dcol=2, 

213 style=LEFT, newrow=True) 

214 self.Add(self.plot_choice, dcol=1, style=LEFT) 

215 self.AddMany((SimpleText(self,''), self.det_label[0], 

216 self.det_label[1], self.det_label[2], self.det_label[3]), 

217 style=LEFT, newrow=True) 

218 

219 self.AddMany((SimpleText(self,'Detector:'), self.det_choice[0], 

220 self.det_choice[1], self.det_choice[2], self.det_choice[3]), 

221 style=LEFT, newrow=True) 

222 

223 self.AddMany((SimpleText(self,'ROI:'),self.roi_choice[0], 

224 self.roi_choice[1],self.roi_choice[2], self.roi_choice[3]), 

225 style=LEFT, newrow=True) 

226 

227 self.AddMany((SimpleText(self,''),self.roi_label[0], 

228 self.roi_label[1],self.roi_label[2], self.roi_label[3]), 

229 style=LEFT, newrow=True) 

230 self.Add((5, 5), dcol=1, style=LEFT, newrow=True) 

231 self.Add(map_shownew, dcol=1, style=LEFT) 

232 self.Add(map_update, dcol=1, style=LEFT) 

233 

234 self.Add(HLine(self, size=(WWID, 5)), dcol=8, style=LEFT, newrow=True) 

235 self.Add(SimpleText(self,'Options:'), dcol=1, style=LEFT, newrow=True) 

236 self.Add(self.use_dtcorr, dcol=2, style=LEFT) 

237 self.Add((5, 5), dcol=1, style=LEFT, newrow=True) 

238 self.Add(self.use_hotcols, dcol=2, style=LEFT) 

239 self.Add((5, 5), dcol=1, style=LEFT, newrow=True) 

240 self.Add(self.use_zigzag, dcol=1, style=LEFT) 

241 self.Add(self.zigoff, dcol=1, style=LEFT) 

242 self.Add((5, 5), dcol=1, style=LEFT, newrow=True) 

243 self.Add(self.limrange, dcol=2, style=LEFT) 

244 self.Add((5, 5), dcol=1, style=LEFT, newrow=True) 

245 self.Add(SimpleText(self, 'X Range:'), dcol=1, style=LEFT) 

246 self.Add(self.lims[0], dcol=1, style=LEFT) 

247 self.Add(self.lims[1], dcol=1, style=LEFT) 

248 self.Add((5, 5), dcol=1, style=LEFT, newrow=True) 

249 self.Add(SimpleText(self, 'Y Range:'), dcol=1, style=LEFT) 

250 self.Add(self.lims[2], dcol=1, style=LEFT) 

251 self.Add(self.lims[3], dcol=1, style=LEFT) 

252 self.Add((5, 5), dcol=1, style=LEFT, newrow=True) 

253 self.Add(map_showxrf, dcol=1, style=LEFT) 

254 self.Add(HLine(self, size=(WWID, 5)), dcol=8, style=LEFT, newrow=True) 

255 self.pack() 

256 

257 def onDTCorrect(self, event=None): 

258 xrmfile = self.owner.current_file 

259 if xrmfile is not None: 

260 xrmfile.dtcorrect = self.use_dtcorr.IsChecked() 

261 

262 def onHotCols(self, event=None): 

263 xrmfile = self.owner.current_file 

264 if xrmfile is not None: 

265 xrmfile.hotcols = self.use_hotcols.IsChecked() 

266 

267 def onZigZag(self, event=None): 

268 xrmfile = self.owner.current_file 

269 if xrmfile is not None: 

270 zigzag = 0 

271 if self.use_zigzag.IsChecked(): 

272 zigzag = int(self.zigoff.GetValue()) 

273 xrmfile.zigzag = zigzag 

274 

275 def update_xrmmap(self, xrmfile=None, set_detectors=False): 

276 if xrmfile is None: 

277 xrmfile = self.owner.current_file 

278 self.cfile = xrmfile 

279 self.xrmmap = self.cfile.xrmmap 

280 #if set_detectors or not self.detectors_set: 

281 self.set_det_choices() 

282 self.plotSELECT() 

283 

284 def onLimitRange(self, event=None): 

285 if self.limrange.IsChecked(): 

286 for wid in self.lims: 

287 wid.Enable() 

288 else: 

289 for wid in self.lims: 

290 wid.Disable() 

291 

292 def detSELECT(self, idet, event=None): 

293 self.set_roi_choices(idet=idet) 

294 

295 def roiSELECT(self,iroi,event=None): 

296 

297 detname = self.det_choice[iroi].GetStringSelection() 

298 roiname = self.roi_choice[iroi].GetStringSelection() 

299 

300 if version_ge(self.cfile.version, '2.0.0'): 

301 try: 

302 roi = self.cfile.xrmmap['roimap'][detname][roiname] 

303 limits = roi['limits'][:] 

304 units = bytes2str(roi['limits'].attrs.get('units','')) 

305 roistr = '[%0.1f to %0.1f %s]' % (limits[0],limits[1],units) 

306 except: 

307 roistr = '' 

308 else: 

309 try: 

310 roi = self.cfile.xrmmap[detname] 

311 en = list(roi['energy'][:]) 

312 index = list(roi['roi_name'][:]).index(roiname) 

313 limits = list(roi['roi_limits'][:][index]) 

314 roistr = '[%0.1f to %0.1f keV]' % (en[limits[0]],en[limits[1]]) 

315 except: 

316 roistr = '' 

317 

318 self.roi_label[iroi].SetLabel(roistr) 

319 

320 def plotSELECT(self,event=None): 

321 if len(self.owner.filemap) > 0: 

322 plot_type = self.plot_choice.GetStringSelection().lower() 

323 if 'single' in plot_type: 

324 for i in (1, 2): 

325 self.det_choice[i].Disable() 

326 self.roi_choice[i].Disable() 

327 self.roi_label[i].SetLabel('') 

328 for i, label in enumerate(['Intensity', ' ', ' ']): 

329 self.det_label[i].SetLabel(label) 

330 elif 'three' in plot_type: 

331 for i in (1, 2): 

332 self.det_choice[i].Enable() 

333 self.roi_choice[i].Enable() 

334 for i, label in enumerate(['Red', 'Green', 'Blue']): 

335 self.det_label[i].SetLabel(label) 

336 self.set_roi_choices() 

337 elif 'correl' in plot_type: 

338 self.det_choice[1].Enable() 

339 self.roi_choice[1].Enable() 

340 self.det_choice[2].Disable() 

341 self.roi_choice[2].Disable() 

342 for i, label in enumerate([' X ',' Y ', '']): 

343 self.det_label[i].SetLabel(label) 

344 self.set_roi_choices() 

345 

346 def onClose(self): 

347 for p in self.plotframes: 

348 try: 

349 p.Destroy() 

350 except: 

351 pass 

352 

353 def ShowMap(self, xrmfile=None, new=True): 

354 subtitles = None 

355 plt3 = 'three' in self.plot_choice.GetStringSelection().lower() 

356 

357 if xrmfile is None: 

358 xrmfile = self.owner.current_file 

359 

360 self.onZigZag() 

361 

362 args={'hotcols' : xrmfile.hotcols, 

363 'dtcorrect' : xrmfile.dtcorrect} 

364 

365 det_name, roi_name, plt_name = [], [], [] 

366 for det, roi in zip(self.det_choice, self.roi_choice): 

367 det_name += [det.GetStringSelection()] 

368 roi_name += [roi.GetStringSelection()] 

369 if det_name[-1] == 'scalars': 

370 plt_name += ['%s' % roi_name[-1]] 

371 else: 

372 plt_name += ['%s(%s)' % (roi_name[-1],det_name[-1])] 

373 

374 mapx = 1.0 

375 if roi_name[-1] != '1': 

376 mapx = xrmfile.get_roimap(roi_name[-1], det=det_name[-1], **args) 

377 mapx[np.where(mapx==0)] = 1. 

378 

379 r_map = xrmfile.get_roimap(roi_name[0], det=det_name[0], **args) 

380 if plt3: 

381 g_map = xrmfile.get_roimap(roi_name[1], det=det_name[1], **args) 

382 b_map = xrmfile.get_roimap(roi_name[2], det=det_name[2], **args) 

383 

384 x = xrmfile.get_pos(0, mean=True) 

385 y = xrmfile.get_pos(1, mean=True) 

386 

387 fname = Path(xrmfile.filename).name 

388 

389 if plt3: 

390 map = np.array([r_map/mapx, g_map/mapx, b_map/mapx]) 

391 map = np.einsum('kij->ijk', map) 

392 

393 title = fname 

394 info = '' 

395 if roi_name[-1] == '1': 

396 subtitles = {'red': 'Red: %s' % plt_name[0], 

397 'green': 'Green: %s' % plt_name[1], 

398 'blue': 'Blue: %s' % plt_name[2]} 

399 else: 

400 subtitles = {'red': 'Red: %s / %s' % (plt_name[0], plt_name[-1]), 

401 'green': 'Green: %s / %s' % (plt_name[1], plt_name[-1]), 

402 'blue': 'Blue: %s / %s' % (plt_name[2], plt_name[-1])} 

403 

404 else: 

405 map = r_map/mapx 

406 if roi_name[-1] == '1': 

407 title = plt_name[0] 

408 else: 

409 title = '%s / %s' % (plt_name[0], plt_name[-1]) 

410 title = '%s: %s' % (fname, title) 

411 info = 'Intensity: [%g, %g]' %(map.min(), map.max()) 

412 subtitle = None 

413 

414 det = None 

415 if (plt3 and det_name[0]==det_name[1] and det_name[0]==det_name[2]) or not plt3: 

416 for s in det_name[0]: 

417 if s.isdigit(): det = int(s) 

418 

419 if len(self.owner.im_displays) == 0 or new: 

420 iframe = self.owner.add_imdisplay(title, det=det) 

421 

422 xoff, yoff = 0, 0 

423 if self.limrange.IsChecked(): 

424 lims = [wid.GetValue() for wid in self.lims] 

425 map = map[lims[2]:lims[3], lims[0]:lims[1]] 

426 xoff, yoff = lims[0], lims[2] 

427 self.owner.display_map(map, title=title, info=info, x=x, y=y, det=det, 

428 xoff=xoff, yoff=yoff, subtitles=subtitles, 

429 xrmfile=self.cfile) 

430 

431 def onLasso(self, selected=None, mask=None, data=None, xrmfile=None, **kws): 

432 if xrmfile is None: 

433 xrmfile = self.owner.current_file 

434 ny, nx = xrmfile.get_shape() 

435 indices = [] 

436 for idx in selected: 

437 iy, ix = divmod(idx, ny) 

438 indices.append((ix, iy)) 

439 

440 

441 def ShowCorrel(self, xrmfile=None, new=True): 

442 

443 if xrmfile is None: 

444 xrmfile = self.owner.current_file 

445 self.onZigZag() 

446 args={'hotcols' : xrmfile.hotcols, 

447 'dtcorrect' : xrmfile.dtcorrect} 

448 det_name,roi_name = [],[] 

449 plt_name = [] 

450 

451 xdet = self.det_choice[0].GetStringSelection() 

452 xroi = self.roi_choice[0].GetStringSelection() 

453 xlab = f"{xroi}({xdet})" 

454 if 'scalar' in xdet.lower(): 

455 xlab = xroi 

456 ydet = self.det_choice[1].GetStringSelection() 

457 yroi = self.roi_choice[1].GetStringSelection() 

458 

459 ylab = f"{yroi}({ydet})" 

460 if 'scalar' in ydet.lower(): 

461 ylab = yroi 

462 

463 map1 = xrmfile.get_roimap(xroi, det=xdet, **args) 

464 map2 = xrmfile.get_roimap(yroi, det=ydet, **args) 

465 

466 x = xrmfile.get_pos(0, mean=True) 

467 y = xrmfile.get_pos(1, mean=True) 

468 

469 fname = Path(xrmfile.filename).name 

470 title = f'{fname}: {ylabl} vs. {xlab}' 

471 

472 correl_plot = CorrelatedMapFrame(parent=self.owner, xrmfile=xrmfile) 

473 correl_plot.display(map1, map2, name1=xlab, name2=ylab, 

474 x=x, y=y, title=title) 

475 correl_plot.Show() 

476 correl_plot.Raise() 

477 self.owner.plot_displays.append(correl_plot) 

478 

479 def onProcessMap(self, event=None, max_new_rows=None): 

480 xrmfile = self.owner.current_file 

481 if xrmfile is None: 

482 return 

483 fname = Path(xrmfile.filename).name 

484 if max_new_rows is None: 

485 max_new_rows = self.mapproc_nrows.GetStringSelection().lower() 

486 if max_new_rows.lower() == 'all': 

487 max_new_rows = None 

488 else: 

489 max_new_rows = int(max_new_rows) 

490 self.owner.process_file(fname, max_new_rows=max_new_rows) 

491 self.update_xrmmap(xrmfile=self.owner.current_file, set_detectors=True) 

492 

493 def onROIMap(self, event=None, new=True): 

494 plotcmd = partial(self.ShowMap, new=new) 

495 if 'correlation' in self.plot_choice.GetStringSelection().lower(): 

496 plotcmd = partial(self.ShowCorrel, new=new) 

497 plotcmd() 

498 

499 def onShowXRF(self, event=None): 

500 owner = self.owner 

501 det_list = owner.current_file.get_detector_list() 

502 detname = self.det_choice[0].GetStringSelection() 

503 ny, nx = owner.current_file.get_shape() 

504 

505 xmin, ymin = 0, 0 

506 xmax, ymax = nx, ny 

507 if self.limrange.IsChecked(): 

508 xmin = int(self.lims[0].GetValue()) 

509 xmax = int(self.lims[1].GetValue()) 

510 ymin = int(self.lims[2].GetValue()) 

511 ymax = int(self.lims[3].GetValue()) 

512 if xmax < 0: 

513 xmax += nx 

514 if ymax < 0: 

515 ymax += ny 

516 my, mx= (ymax - ymin), (xmax - xmin) 

517 

518 owner.show_XRFDisplay() 

519 self._mca = owner.current_file.get_mca_rect(ymin, ymax, xmin, xmax, det=detname, 

520 dtcorrect=owner.dtcor) 

521 fname = Path(self.owner.current_file.filename).name 

522 self._mca.filename = fname 

523 self._mca.title = f"({mx} x {my} pixels)" 

524 self._mca.npixels = my*mx 

525 self.owner.message("Plotting Full XRF Spectra (%d x %d) for '%s'" % (mx, my, fname)) 

526 

527 self.owner.subframes['xrfdisplay'].add_mca(self._mca, label=fname, plot=True) 

528 

529 

530 def set_det_choices(self): 

531 det_list = self.cfile.get_detector_list() 

532 for det_ch in self.det_choice: 

533 det_ch.SetChoices(det_list) 

534 if 'scalars' in det_list: ## should set 'denominator' to scalars as default 

535 self.det_choice[-1].SetStringSelection('scalars') 

536 self.set_roi_choices() 

537 

538 def set_roi_choices(self, idet=None): 

539 force_rois = True # not self.detectors_set 

540 if idet is None: 

541 for idet, det_ch in enumerate(self.det_choice): 

542 detname = self.det_choice[idet].GetStringSelection() 

543 rois = self.cfile.get_roi_list(detname, force=force_rois) 

544 cur = self.roi_choice[idet].GetStringSelection() 

545 self.roi_choice[idet].SetChoices(rois) 

546 if cur in rois: 

547 self.roi_choice[idet].SetStringSelection(cur) 

548 self.roiSELECT(idet) 

549 else: 

550 detname = self.det_choice[idet].GetStringSelection() 

551 rois = self.cfile.get_roi_list(detname, force=force_rois) 

552 cur = self.roi_choice[idet].GetStringSelection() 

553 self.roi_choice[idet].SetChoices(rois) 

554 if cur in rois: 

555 self.roi_choice[idet].SetStringSelection(cur) 

556 self.roiSELECT(idet) 

557 

558 def update_roi(self, detname): 

559 force = True # not self.detectors_set 

560 return self.cfile.get_roi_list(detname, force=force) 

561 

562class MapInfoPanel(scrolled.ScrolledPanel): 

563 """Info Panel """ 

564 label = 'Map Info' 

565 def __init__(self, parent, owner=None, **kws): 

566 scrolled.ScrolledPanel.__init__(self, parent, -1, 

567 style=wx.GROW|wx.TAB_TRAVERSAL, **kws) 

568 self.owner = owner 

569 

570 sizer = wx.GridBagSizer(3, 3) 

571 self.wids = {} 

572 

573 ir = 0 

574 for label in ('Facility','Run Cycle','Proposal Number','User group', 

575 'H5 Map Created', 

576 'Scan Time','File Compression','Map Data', 

577 'Ring Current', 'X-ray Energy', 'X-ray Intensity (I0)', 

578 'Original data path', 'User Comments 1', 'User Comments 2', 

579 'Scan Fast Motor', 'Scan Slow Motor', 'Dwell Time', 

580 'Sample Fine Stages', 

581 'Sample Stage X', 'Sample Stage Y', 

582 'Sample Stage Z', 'Sample Stage Theta', 

583 'XRD Calibration'): 

584 

585 ir += 1 

586 thislabel = SimpleText(self, '%s:' % label, style=wx.LEFT, size=(125, -1)) 

587 self.wids[label] = SimpleText(self, ' ' , style=wx.LEFT, size=(350, -1)) 

588 

589 sizer.Add(thislabel, (ir, 0), (1, 1), 1) 

590 sizer.Add(self.wids[label], (ir, 1), (1, 1), 1) 

591 

592 pack(self, sizer) 

593 self.SetupScrolling() 

594 

595 def update_xrmmap(self, xrmfile=None, set_detectors=None): 

596 if xrmfile is None: 

597 xrmfile = self.owner.current_file 

598 xrmmap = xrmfile.xrmmap 

599 def time_between(d1, d2): 

600 d1 = datetime.datetime.strptime(d1, "%Y-%m-%d %H:%M:%S") 

601 d2 = datetime.datetime.strptime(d2, "%Y-%m-%d %H:%M:%S") 

602 diff = d2 - d1 if d2 > d1 else d1 - d2 

603 return diff.days,diff.seconds 

604 

605 config_grp = ensure_subgroup('config',xrmmap) 

606 notes_grp = ensure_subgroup('notes',config_grp) 

607 time_str = bytes2str(notes_grp.attrs.get('h5_create_time','')) 

608 

609 self.wids['H5 Map Created'].SetLabel(time_str) 

610 

611 try: 

612 d,s = time_between(bytes2str(notes_grp.attrs.get('scan_start_time','')), 

613 bytes2str(notes_grp.attrs.get('scan_end_time',''))) 

614 time_str = str(datetime.timedelta(days=d,seconds=s)) 

615 except: 

616 time_str = bytes2str(xrmmap.attrs.get('Start_Time','')) 

617 

618 self.wids['Scan Time'].SetLabel( time_str ) 

619 self.wids['File Compression'].SetLabel(bytes2str(xrmmap.attrs.get('Compression',''))) 

620 

621 comments = h5str(xrmmap['config/scan/comments'][()]).split('\n', 2) 

622 for i, comm in enumerate(comments): 

623 self.wids['User Comments %i' %(i+1)].SetLabel(comm) 

624 

625 pos_addrs = [str(x) for x in xrmmap['config/positioners'].keys()] 

626 pos_label = [h5str(x[()]) for x in xrmmap['config/positioners'].values()] 

627 

628 scan_pos1 = h5str(xrmmap['config/scan/pos1'][()]) 

629 scan_pos2 = h5str(xrmmap['config/scan/pos2'][()]) 

630 i1 = pos_addrs.index(scan_pos1) 

631 i2 = pos_addrs.index(scan_pos2) 

632 

633 start1 = float(xrmmap['config/scan/start1'][()]) 

634 start2 = float(xrmmap['config/scan/start2'][()]) 

635 stop1 = float(xrmmap['config/scan/stop1'][()]) 

636 stop2 = float(xrmmap['config/scan/stop2'][()]) 

637 

638 step1 = float(xrmmap['config/scan/step1'][()]) 

639 step2 = float(xrmmap['config/scan/step2'][()]) 

640 

641 npts1 = int((abs(stop1 - start1) + 1.1*step1)/step1) 

642 npts2 = int((abs(stop2 - start2) + 1.1*step2)/step2) 

643 

644 sfmt = '%s: [%.4f:%.4f], step=%.4f, %i pixels' 

645 scan1 = sfmt % (pos_label[i1], start1, stop1, step1, npts1) 

646 scan2 = sfmt % (pos_label[i2], start2, stop2, step2, npts2) 

647 

648 rowtime = float(xrmmap['config/scan/time1'][()]) 

649 

650 self.wids['Scan Fast Motor'].SetLabel(scan1) 

651 self.wids['Scan Slow Motor'].SetLabel(scan2) 

652 pixtime = xrmfile.pixeltime 

653 if pixtime is None: 

654 pixtime = xrmfile.calc_pixeltime() 

655 pixtime =int(round(1000.0*pixtime)) 

656 self.wids['Dwell Time'].SetLabel('%.1f ms per pixel' % pixtime) 

657 

658 env_names = list(xrmmap['config/environ/name']) 

659 env_vals = list(xrmmap['config/environ/value']) 

660 env_addrs = list(xrmmap['config/environ/address']) 

661 

662 fines = {'X': '?', 'Y': '?'} 

663 i0vals = {'flux':'?', 'current':'?'} 

664 

665 en = xrmfile.get_incident_energy() 

666 enmsg = '%0.1f eV (%0.3f \u00c5)' % (en, lambda_from_E(en, E_units='eV')) 

667 if abs(en - DEFAULT_XRAY_ENERGY) < 1.0: 

668 enmsg = "%s : PROBABLY NOT CORRECT" % enmsg 

669 self.wids['X-ray Energy'].SetLabel(enmsg) 

670 

671 

672 for name, addr, val in zip(env_names, env_addrs, env_vals): 

673 name = bytes2str(name).lower() 

674 val = h5str(val) 

675 if 'ring_current' in name or 'ring current' in name: 

676 self.wids['Ring Current'].SetLabel('%s mA' % val) 

677 elif 'beamline.fluxestimate' in name or 'transmitted flux' in name: 

678 i0vals['flux'] = val 

679 elif 'i0 current' in name: 

680 i0vals['current'] = val 

681 

682 elif name.startswith('sample'): 

683 name = name.replace('samplestage.', '') 

684 if 'coarsex' in name or 'coarse x' in name: 

685 self.wids['Sample Stage X'].SetLabel('%s mm' % val) 

686 elif 'coarsey' in name or 'coarse y' in name: 

687 self.wids['Sample Stage Y'].SetLabel('%s mm' % val) 

688 elif 'coarsez' in name or 'coarse z' in name: 

689 self.wids['Sample Stage Z'].SetLabel('%s mm' % val) 

690 elif 'theta' in name: 

691 self.wids['Sample Stage Theta'].SetLabel('%s deg' % val) 

692 elif 'finex' in name or 'fine x' in name: 

693 fines['X'] = val 

694 elif 'finey' in name or 'fine y' in name: 

695 fines['Y'] = val 

696 

697 if i0vals['current'] == '?': 

698 i0val = 'Flux=%(flux)s Hz' % i0vals 

699 else: 

700 i0val = u'Flux=%(flux)s Hz, I0 Current=%(current)s \u03BCA' % i0vals 

701 self.wids['X-ray Intensity (I0)'].SetLabel(i0val) 

702 self.wids['Sample Fine Stages'].SetLabel('X, Y = %(X)s, %(Y)s mm' % (fines)) 

703 

704 folderpath = bytes2str(xrmmap.attrs.get('Map_Folder','')) 

705 if len(folderpath) > 35: 

706 folderpath = '...'+folderpath[-35:] 

707 self.wids['Original data path'].SetLabel(folderpath) 

708 

709 self.wids['XRD Calibration'].SetLabel('') 

710 xrd_calibration = '' 

711 if 'xrd1d' in xrmmap: 

712 xrd_calibration = bytes2str(xrmmap['xrd1d'].attrs.get('calfile','')) 

713 if not Path(xrd_calibration).exists(): 

714 xrd_calibration = '' 

715 self.wids['XRD Calibration'].SetLabel(Path(xrd_calibration).name) 

716 

717 notes = {} 

718 config_grp = ensure_subgroup('config',xrmmap) 

719 notes_grp = ensure_subgroup('notes',config_grp) 

720 for key in notes_grp.attrs.keys(): 

721 try: 

722 notes[key] = bytes2str(notes_grp.attrs[key]) 

723 except: 

724 pass 

725 note_title = ['Facility','Run Cycle','Proposal Number','User group'] 

726 note_str = ['','','',''] 

727 if 'beamline' in notes and 'facility' in notes: 

728 note_str[0] = '%s @ %s' % (notes['beamline'],notes['facility']) 

729 if 'run' in notes: 

730 note_str[1] = notes['run'] 

731 if 'proposal' in notes: 

732 note_str[2] = notes['proposal'] 

733 if 'user' in notes: 

734 note_str[3] = notes['user'] 

735 

736 for title,note in zip(note_title,note_str): 

737 self.wids[title].SetLabel(note) 

738 

739 xrmfile.reset_flags() 

740 if xrmfile.has_xrf: 

741 if xrmfile.has_xrd2d and xrmfile.has_xrd1d: 

742 datastr = 'XRF, 2D- and 1D-XRD data' 

743 elif xrmfile.has_xrd2d: 

744 datastr = 'XRF, 2D-XRD data' 

745 elif xrmfile.has_xrd1d: 

746 datastr = 'XRF, 1D-XRD data' 

747 else: 

748 datastr = 'XRF data' 

749 else: 

750 if xrmfile.has_xrd2d and xrmfile.has_xrd1d: 

751 datastr = '2D- and 1D-XRD data' 

752 elif xrmfile.has_xrd2d: 

753 datastr = '2D-XRD data' 

754 elif xrmfile.has_xrd1d: 

755 datastr = '1D-XRD data' 

756 else: 

757 datastr = '' 

758 

759 self.wids['Map Data'].SetLabel(datastr) 

760 

761 def onClose(self): 

762 pass 

763 

764 

765class MapAreaPanel(scrolled.ScrolledPanel): 

766 

767 label = 'Map Areas' 

768 delstr = """ Delete Area '%s'? 

769 

770 WARNING: This cannot be undone! 

771 

772 """ 

773 

774 def __init__(self, parent, owner=None, **kws): 

775 scrolled.ScrolledPanel.__init__(self, parent, -1, 

776 style=wx.GROW|wx.TAB_TRAVERSAL, **kws) 

777 

778 ###################################### 

779 ## GENERAL MAP AREAS 

780 self.owner = owner 

781 pane = wx.Panel(self) 

782 sizer = wx.GridBagSizer(3, 3) 

783 self.choices = {} 

784 bsize = (CWID, -1) 

785 self.choice = Choice(pane, size=(225, -1), action=self.onSelect) 

786 self.desc = wx.TextCtrl(pane, -1, '', size=(225, -1)) 

787 self.info1 = wx.StaticText(pane, -1, '', size=(275, -1)) 

788 self.info2 = wx.StaticText(pane, -1, '', size=(275, -1)) 

789 self.onmap = Button(pane, 'Show on Map', size=bsize, action=self.onShow) 

790 self.clear = Button(pane, 'Clear Map', size=bsize, action=self.onClear) 

791 self.bdelete = Button(pane, 'Delete', size=bsize, action=self.onDelete) 

792 self.update = Button(pane, 'Apply', size=bsize, action=self.onLabel) 

793 self.bexport = Button(pane, 'Export Areas', size=bsize, action=self.onExport) 

794 self.bimport = Button(pane, 'Import Areas', size=bsize, action=self.onImport) 

795 self.bcopy = Button(pane, 'Copy to Other Maps', size=bsize, action=self.onCopy) 

796 self.xrf = Button(pane, 'Show XRF (Fore)', size=bsize, action=self.onXRF) 

797 self.xrf2 = Button(pane, 'Show XRF (Back)', size=bsize, 

798 action=partial(self.onXRF, as_mca2=True)) 

799 

800 self.onstats = Button(pane, 'Calculate XRF Stats', size=bsize, 

801 action=self.onShowStats) 

802 self.onreport = Button(pane, 'Save XRF Stats', size=bsize, 

803 action=self.onReport) 

804 

805 self.xrd1d_plot = Button(pane, 'Show 1D XRD', size=bsize, 

806 action=partial(self.onXRD, show=True, xrd1d=True)) 

807 

808 self.xrd2d_plot = Button(pane, 'Show 2D XRD', size=bsize, 

809 action=partial(self.onXRD, show=True, xrd2d=True)) 

810 

811 legend = wx.StaticText(pane, -1, 'Values in Counts per second', size=(200, -1)) 

812 

813 def txt(s): 

814 return SimpleText(pane, s) 

815 irow = 1 

816 sizer.Add(txt('Map Areas and Saved Points'), ( 0, 0), (1, 5), ALL_CEN, 2) 

817 sizer.Add(txt('Area: '), (irow, 0), (1, 1), ALL_LEFT, 2) 

818 sizer.Add(self.choice, (irow, 1), (1, 2), ALL_LEFT, 2) 

819 sizer.Add(self.bdelete, (irow, 3), (1, 1), ALL_LEFT, 2) 

820 

821 

822 irow += 1 

823 sizer.Add(txt('Info: '), (irow, 0), (1, 1), ALL_LEFT, 2) 

824 sizer.Add(self.info1, (irow, 1), (1, 2), ALL_LEFT, 2) 

825 sizer.Add(self.info2, (irow, 3), (1, 2), ALL_LEFT, 2) 

826 

827 irow += 1 

828 sizer.Add(txt('Rename: '), (irow, 0), (1, 1), ALL_LEFT, 2) 

829 sizer.Add(self.desc, (irow, 1), (1, 2), ALL_LEFT, 2) 

830 sizer.Add(self.update, (irow, 3), (1, 1), ALL_LEFT, 2) 

831 

832 irow += 1 

833 sizer.Add(txt('Show: '), (irow, 0), (1, 1), ALL_LEFT, 2) 

834 sizer.Add(self.onmap, (irow, 1), (1, 1), ALL_LEFT, 2) 

835 sizer.Add(self.clear, (irow, 2), (1, 1), ALL_LEFT, 2) 

836 

837 irow += 1 

838 sizer.Add(txt('Save: '), (irow, 0), (1, 1), ALL_LEFT, 2) 

839 sizer.Add(self.bexport, (irow, 1), (1, 1), ALL_LEFT, 2) 

840 sizer.Add(self.bimport, (irow, 2), (1, 1), ALL_LEFT, 2) 

841 sizer.Add(self.bcopy, (irow, 3), (1, 1), ALL_LEFT, 2) 

842 

843 irow += 1 

844 sizer.Add(txt('XRF: '), (irow, 0), (1, 1), ALL_LEFT, 2) 

845 sizer.Add(self.xrf, (irow, 1), (1, 1), ALL_LEFT, 2) 

846 sizer.Add(self.xrf2, (irow, 2), (1, 1), ALL_LEFT, 2) 

847 sizer.Add(self.onstats, (irow, 3), (1, 1), ALL_LEFT, 2) 

848 sizer.Add(self.onreport, (irow, 4), (1, 1), ALL_LEFT, 2) 

849 

850 

851 irow += 1 

852 sizer.Add(txt('XRD: '), (irow, 0), (1, 1), ALL_LEFT, 2) 

853 sizer.Add(self.xrd1d_plot, (irow, 1), (1, 1), ALL_LEFT, 2) 

854 sizer.Add(self.xrd2d_plot, (irow, 2), (1, 1), ALL_LEFT, 2) 

855 

856 # sizer.Add(self.xrd1d_save, (irow, 0), (1, 2), ALL_LEFT, 2) 

857 # sizer.Add(self.xrd2d_save, (irow, 2), (1, 2), ALL_LEFT, 2) 

858 irow += 1 

859 sizer.Add(legend, (irow, 1), (1, 2), ALL_LEFT, 2) 

860 pack(pane, sizer) 

861 

862 for btn in (self.xrd1d_plot, self.xrd2d_plot): 

863 btn.Disable() 

864 

865 # main sizer 

866 msizer = wx.BoxSizer(wx.VERTICAL) 

867 msizer.Add(pane, 0, wx.ALIGN_LEFT|wx.ALL, 1) 

868 

869 msizer.Add(wx.StaticLine(self, size=(375, 2), style=wx.LI_HORIZONTAL), 

870 0, wx.EXPAND|wx.ALL, 1) 

871 

872 self.report = None 

873 rep = self.report = dv.DataViewListCtrl(self, style=DVSTY) 

874 rep.AppendTextColumn('ROI ', width=150) 

875 rep.AppendTextColumn('Min', width=90) 

876 rep.AppendTextColumn('Max', width=90) 

877 rep.AppendTextColumn('Mean ', width=90) 

878 rep.AppendTextColumn('Sigma', width=90) 

879 rep.AppendTextColumn('Median', width=90) 

880 rep.AppendTextColumn('Mode', width=90) 

881 for col in range(7): 

882 align = wx.ALIGN_RIGHT 

883 if col == 0: align = wx.ALIGN_LEFT 

884 rep.Columns[col].Sortable = False 

885 rep.Columns[col].Renderer.Alignment = align 

886 rep.Columns[col].Alignment = align 

887 

888 rep.SetMinSize((800, 300)) 

889 msizer.Add(rep, 1, wx.ALIGN_LEFT|wx.ALL, 1) 

890 

891 pack(self, msizer) 

892 self.SetupScrolling() 

893 

894 def onCopy(self, event=None): 

895 xrmfile = self.owner.current_file 

896 xrmmap = xrmfile.xrmmap 

897 print("Copy Area : shape", xrmfile, xrmmap.shape) 

898 

899 def show_stats(self): 

900 # self.stats = self.xrmfile.get_area_stats(self.areaname) 

901 if self.report is None: 

902 return 

903 

904 self.report.DeleteAllItems() 

905 self.report_data = [] 

906 

907 def report_info(dname,d): 

908 try: 

909 hmean, gmean = stats.gmean(d), stats.hmean(d) 

910 skew, kurtosis = stats.skew(d), stats.kurtosis(d) 

911 except ValueError: 

912 hmean, gmean, skew, kurtosis = 0, 0, 0, 0 

913 

914 smode = '--' 

915 fmt = '{:,.1f}'.format # use thousands commas, 1 decimal place 

916 mode = stats.mode(d) 

917 if len(mode) > 0: 

918 mode = mode[0] 

919 if len(mode) > 0: 

920 smode = fmt(mode[0]) 

921 dat = (dname, fmt(d.min()), fmt(d.max()), fmt(d.mean()), 

922 fmt(d.std()), fmt(np.median(d)), smode) 

923 self.report_data.append(dat) 

924 self.report.AppendItem(dat) 

925 

926 areaname = self._getarea() 

927 xrmfile = self.owner.current_file 

928 xrmmap = xrmfile.xrmmap 

929 ctime = xrmfile.pixeltime 

930 

931 area = xrmfile.get_area(name=areaname) 

932 amask = area[()] 

933 

934 def match_mask_shape(det, mask): 

935 if mask.shape[1] == det.shape[1] - 2: # hotcols 

936 det = det[:,1:-1] 

937 if mask.shape[0] < det.shape[0]: 

938 det = det[:mask.shape[0]] 

939 return det[mask] 

940 

941 if 'roistats' in area.attrs: 

942 for dat in json.loads(area.attrs.get('roistats','')): 

943 dat = tuple(dat) 

944 self.report_data.append(dat) 

945 self.report.AppendItem(dat) 

946 self.choice.Enable() 

947 return 

948 

949 version = xrmmap.attrs.get('Version','1.0.0') 

950 

951 if version_ge(version, '2.0.0'): 

952 d_pref = 'mca' 

953 d_scas = [d for d in xrmmap['scalars']] 

954 det_list = xrmfile.get_detector_list() 

955 detnames = [x for x in det_list if d_pref in x] 

956 d_rois = xrmfile.get_roi_list(detnames[0]) 

957 

958 else: 

959 d_addrs = [d.lower() for d in xrmmap['roimap/det_address']] 

960 d_names = [d for d in xrmmap['roimap/det_name']] 

961 d_pref = 'det' 

962 

963 # MNREAL 

964 #for i in range(1, xrmfile.nmca+1): 

965 # tname = '%s%i/realtime' % (d_pref, i) 

966 # rtime = xrmmap[tname][()] 

967 # if amask.shape[1] == rtime.shape[1] - 2: # hotcols 

968 # rtime = rtime[:,1:-1] 

969 

970 if version_ge(version, '2.0.0'): 

971 for scalar in d_scas: 

972 d = xrmmap['scalars'][scalar][()] 

973 d = match_mask_shape(d, amask) 

974 report_info(scalar, d/ctime) 

975 

976 for roi in d_rois: 

977 for det in detnames: 

978 d = xrmfile.get_roimap(roi, det=det, dtcorrect=False) 

979 d = match_mask_shape(d, amask) 

980 report_info('%s (%s)' % (roi, det), d/ctime) 

981 

982 else: 

983 for idet, dname in enumerate(d_names): 

984 try: 

985 daddr = h5str(d_addrs[idet]) 

986 except IndexError: 

987 break 

988 if 'mca' in daddr: 

989 det = 1 

990 words = daddr.split('mca') 

991 if len(words) > 1: 

992 det = int(words[1].split('.')[0]) 

993 

994 d = xrmmap['roimap/det_raw'][:,:,idet] 

995 d = match_mask_shape(d, amask) 

996 report_info(dname, d/ctime) 

997 

998 if 'roistats' not in area.attrs: 

999 area.attrs['roistats'] = json.dumps(self.report_data) 

1000 xrmfile.h5root.flush() 

1001 

1002 def update_xrmmap(self, xrmfile=None, set_detectors=None): 

1003 if xrmfile is None: xrmfile = self.owner.current_file 

1004 xrmmap = xrmfile.xrmmap 

1005 self.set_area_choices(xrmmap, show_last=True) 

1006 self.set_enabled_btns(xrmfile=xrmfile) 

1007 self.report.DeleteAllItems() 

1008 self.report_data = [] 

1009 try: 

1010 self.onSelect() 

1011 except: 

1012 pass 

1013 

1014 def set_enabled_btns(self, xrmfile=None): 

1015 if xrmfile is None: 

1016 xrmfile = self.owner.current_file 

1017 

1018 xrmfile.reset_flags() 

1019 self.xrd2d_plot.Enable(xrmfile.has_xrd1d) 

1020 self.xrd1d_plot.Enable(xrmfile.has_xrd1d) 

1021 

1022 def clear_area_choices(self): 

1023 

1024 self.info1.SetLabel('') 

1025 self.info2.SetLabel('') 

1026 self.desc.SetValue('') 

1027 self.choice.Clear() 

1028 

1029 def set_area_choices(self, xrmmap, show_last=False): 

1030 

1031 self.clear_area_choices() 

1032 

1033 areas = xrmmap['areas'] 

1034 

1035 c = self.choice 

1036 c.Clear() 

1037 self.choices = {} 

1038 choice_labels = [] 

1039 for a in areas: 

1040 desc = bytes2str(areas[a].attrs.get('description', a)) 

1041 self.choices[desc] = a 

1042 choice_labels.append(desc) 

1043 

1044 c.AppendItems(choice_labels) 

1045 this_label = '' 

1046 if len(self.choices) > 0: 

1047 idx = 0 

1048 if show_last: 

1049 idx = len(self.choices)-1 

1050 try: 

1051 this_label = choice_labels[idx] 

1052 except: 

1053 return 

1054 c.SetStringSelection(this_label) 

1055 self.desc.SetValue(this_label) 

1056 

1057 

1058 def onReport(self, event=None): 

1059 aname = self._getarea() 

1060 fname = Path(self.owner.current_file.filename).fname 

1061 deffile = f'{fname}_{aname}' 

1062 deffile = deffile.replace('.', '_') + '.dat' 

1063 outfile = FileSave(self, 'Save Area XRF Statistics File', 

1064 default_file=deffile, 

1065 wildcard=FILE_WILDCARDS) 

1066 

1067 if outfile is None: 

1068 return 

1069 

1070 area = self.owner.current_file.xrmmap['areas/%s' % aname] 

1071 npix = area[()].sum() 

1072 pixtime = self.owner.current_file.pixeltime 

1073 

1074 mca = self.owner.current_file.get_mca_area(aname) 

1075 dtime = mca.real_time 

1076 info_fmt = '%i Pixels, %i ms/pixel, %.3f total seconds' 

1077 buff = ['# Map %s, Area %s' % (self.owner.current_file.filename, aname), 

1078 '# %i Pixels' % npix, 

1079 '# %i ms per pixel' % int(round(1000.0*pixtime)), 

1080 '# %.3f total seconds' % dtime, 

1081 '# Time (TSCALER) in ms', 

1082 '# All other values in counts per second', 

1083 '#----------------------------------', 

1084 '# ROI Min Max Mean Sigma Median Mode'] 

1085 for dat in self.report_data: 

1086 buff.append(' '.join(dat)) 

1087 buff.append('') 

1088 try: 

1089 fout = open(outfile, 'w', encoding=sys.getdefaultencoding()) 

1090 fout.write('\n'.join(buff)) 

1091 fout.close() 

1092 except IOError: 

1093 print('could not write %s' % outfile) 

1094 

1095 def _getarea(self): 

1096 return self.choices[self.choice.GetStringSelection()] 

1097 

1098 def onExport(self, event=None): 

1099 ofile = self.owner.current_file.export_areas() 

1100 self.owner.message('Exported Areas to %s' % ofile) 

1101 

1102 def onImport(self, event=None): 

1103 wildcards = 'Area Files (*_Areas.npz)|*_Areas.npz|All files (*.*)|*.*' 

1104 dlg = wx.FileDialog(self, message='Read Areas File', 

1105 defaultDir=get_cwd(), 

1106 wildcard=wildcards, style=wx.FD_OPEN) 

1107 

1108 if dlg.ShowModal() == wx.ID_OK: 

1109 fname = dlg.GetPath().replace('\\', '/') 

1110 self.owner.current_file.import_areas(fname) 

1111 self.owner.message('Imported Areas from %s' % fname) 

1112 self.set_area_choices(self.owner.current_file.xrmmap) 

1113 self.onSelect() 

1114 

1115 def onSelect(self, event=None): 

1116 try: 

1117 aname = self._getarea() 

1118 except: 

1119 return 

1120 area = self.owner.current_file.xrmmap['areas/%s' % aname] 

1121 npix = area[()].sum() 

1122 yvals, xvals = np.where(area[()]) 

1123 pixtime = self.owner.current_file.pixeltime 

1124 dtime = npix*pixtime 

1125 info1_fmt = '%i Pixels, %.3f seconds' 

1126 info2_fmt = ' Range (pixels) X: [%i:%i], Y: [%i:%i] ' 

1127 self.info1.SetLabel(info1_fmt % (npix, dtime)) 

1128 self.info2.SetLabel(info2_fmt % (xvals.min(), xvals.max(), 

1129 yvals.min(), yvals.max())) 

1130 

1131 self.desc.SetValue(area.attrs.get('description', aname)) 

1132 self.report.DeleteAllItems() 

1133 self.report_data = [] 

1134 if 'roistats' in area.attrs: 

1135 self.show_stats() 

1136 

1137 def onShowStats(self, event=None): 

1138 if self.report is None: 

1139 return 

1140 self.show_stats() 

1141 

1142 def onLabel(self, event=None): 

1143 aname = self._getarea() 

1144 area = self.owner.current_file.xrmmap['areas/%s' % aname] 

1145 new_label = str(self.desc.GetValue()) 

1146 area.attrs['description'] = new_label 

1147 self.owner.current_file.h5root.flush() 

1148 self.set_area_choices(self.owner.current_file.xrmmap) 

1149 self.choice.SetStringSelection(new_label) 

1150 self.desc.SetValue(new_label) 

1151 

1152 def onShow(self, event=None): 

1153 aname = self._getarea() 

1154 area = self.owner.current_file.xrmmap['areas'][aname] 

1155 label = bytes2str(area.attrs.get('description', aname)) 

1156 

1157 if len(self.owner.tomo_displays) > 0: 

1158 imd = self.owner.tomo_displays[-1] 

1159 try: 

1160 imd.add_highlight_area(area[()], label=label) 

1161 except: 

1162 pass 

1163 

1164 if len(self.owner.im_displays) > 0: 

1165 imd = self.owner.im_displays[-1] 

1166 h, w = self.owner.current_file.get_shape() 

1167 highlight = np.zeros((h, w)) 

1168 

1169 highlight[np.where(area[()])] = 1 

1170 imd.panel.add_highlight_area(highlight, label=label) 

1171 

1172 def onDone(self, event=None): 

1173 self.Destroy() 

1174 

1175 def onDelete(self, event=None): 

1176 aname = self._getarea() 

1177 erase = (wx.ID_YES == Popup(self.owner, self.delstr % aname, 

1178 'Delete Area?', style=wx.YES_NO)) 

1179 

1180 if erase: 

1181 xrmmap = self.owner.current_file.xrmmap 

1182 del xrmmap['areas/%s' % aname] 

1183 

1184 self.set_area_choices(xrmmap) 

1185 

1186 self.onSelect() 

1187 

1188 def onClear(self, event=None): 

1189 if len(self.owner.im_displays) > 0: 

1190 imd = self.owner.im_displays[-1] 

1191 try: 

1192 for area in imd.panel.conf.highlight_areas: 

1193 for w in area.collections + area.labelTexts: 

1194 w.remove() 

1195 imd.panel.conf.highlight_areas = [] 

1196 imd.panel.redraw() 

1197 except: 

1198 pass 

1199 

1200 if len(self.owner.tomo_displays) > 0: 

1201 imd = self.owner.tomo_displays[-1] 

1202 try: 

1203 imd.clear_highlight_area() 

1204 except: 

1205 pass 

1206 

1207 def onXRF(self, event=None, as_mca2=False): 

1208 aname = self._getarea() 

1209 xrmfile = self.owner.current_file 

1210 area = xrmfile.xrmmap['areas/%s' % aname] 

1211 

1212 label = bytes2str(area.attrs.get('description', aname)) 

1213 self._mca = None 

1214 self.owner.message("Getting XRF Spectra for area '%s'..." % aname) 

1215 def _getmca_area(aname): 

1216 o = self.owner 

1217 self._mca = o.current_file.get_mca_area(aname, 

1218 dtcorrect=o.dtcor) 

1219 mca_thread = Thread(target=_getmca_area, args=(aname,)) 

1220 mca_thread.start() 

1221 self.owner.show_XRFDisplay() 

1222 mca_thread.join() 

1223 

1224 fname = Path(self.owner.current_file.filename).name 

1225 

1226 npix = area[()].sum() 

1227 self._mca.filename = fname 

1228 self._mca.title = label 

1229 self._mca.npixels = npix 

1230 self.owner.message(f"Plotting XRF Spectra for area '{aname}'...") 

1231 self.owner.subframes['xrfdisplay'].add_mca(self._mca, label=f"{fname}:{label}", 

1232 plot=not as_mca2) 

1233 if as_mca2: 

1234 self.owner.subframes['xrfdisplay'].swap_mcas() 

1235 

1236 def onXRD(self, event=None, save=False, show=False, 

1237 xrd1d=False, xrd2d=False, verbose=True): 

1238 try: 

1239 aname = self._getarea() 

1240 xrmfile = self.owner.current_file 

1241 area = xrmfile.xrmmap['areas/%s' % aname] 

1242 

1243 title = area.attrs.get('description', aname) 

1244 

1245 env_names = list(xrmfile.xrmmap['config/environ/name']) 

1246 env_vals = list(xrmfile.xrmmap['config/environ/value']) 

1247 for name, val in zip(env_names, env_vals): 

1248 if 'mono.energy' in str(name).lower(): 

1249 energy = float(val)/1000. 

1250 except: 

1251 if verbose: 

1252 print('No map file and/or areas specified.') 

1253 return 

1254 

1255 xrmfile.reset_flags() 

1256 if not xrmfile.has_xrd1d and not xrmfile.has_xrd2d: 

1257 if verbose: 

1258 print('No XRD data in map file: %s' % self.owner.current_file.filename) 

1259 return 

1260 

1261 ponifile = bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('calfile','')) 

1262 ponifile = ponifile if Path(ponifile).exists() else None 

1263 

1264 if show: 

1265 self.owner.message(f"Plotting XRD pattern for '{title}'") 

1266 if save: 

1267 self.owner.message(f"Saving XRD pattern for '{title}'") 

1268 stem = Path(self.owner.current_file.filename).name 

1269 stem = f"{stem}_{title}" 

1270 

1271 energy = 0.001*xrmfile.get_incident_energy() 

1272 kwargs = dict(filename=self.owner.current_file.filename, 

1273 npixels=area[()].sum(), energy=energy, 

1274 calfile=ponifile, title=title, xrd2d=False) 

1275 

1276 if xrd1d and xrmfile.has_xrd1d: 

1277 self._xrd = xrmfile.get_xrd1d_area(aname, **kwargs) 

1278 

1279 if show: 

1280 label = f'{Path(self._xrd.filename).name}: {title}' 

1281 self.owner.display_xrd1d(self._xrd.data1D, self._xrd.q, 

1282 self._xrd.energy, label=label) 

1283 if save: 

1284 wildcards = '1D XRD file (*.xy)|*.xy|All files (*.*)|*.*' 

1285 dlg = wx.FileDialog(self, 'Save file as...', 

1286 defaultDir=get_cwd(), 

1287 defaultFile='%s.xy' % stem, 

1288 wildcard=wildcards, 

1289 style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 

1290 if dlg.ShowModal() == wx.ID_OK: 

1291 filename = dlg.GetPath().replace('\\', '/') 

1292 

1293 dlg.Destroy() 

1294 

1295 print('\nSaving 1D XRD in file: %s' % (filename)) 

1296 save1D(filename, self._xrd.data1D[0], self._xrd.data1D[1], calfile=ponifile) 

1297 

1298 ## turns off flag since it has already been displayed/saved 

1299 xrd1d = False 

1300 

1301 

1302 if xrd2d: 

1303 print("Looking for 2D XRD Data") 

1304 try: 

1305 _xrd = xrmfile.get_xrd2d_area(aname, **kwargs) 

1306 except: 

1307 _xrd = None 

1308 if _xrd is None: 

1309 print("no 2D XRD Data") 

1310 return 

1311 

1312 label = f'{Path(_xrd.filename).name}: {title}' 

1313 self.owner.display_xrd2d(_xrd.data2D, label=label, xrmfile=xrmfile) 

1314 

1315 wildcards = '2D XRD file (*.tiff)|*.tif;*.tiff;*.edf|All files (*.*)|*.*' 

1316 fname = xrmfile.filename + '_' + aname 

1317 #dlg = wx.FileDialog(self, 'Save file as...', 

1318 # defaultDir=get_cwd(), 

1319 # defaultFile='%s.tiff' % fname, 

1320 # wildcard=wildcards, 

1321 # style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) 

1322 #if dlg.ShowModal() == wx.ID_OK: 

1323 # filename = Path(dlg.GetPath()).absolute().as_posix() 

1324 # _xrd.save_2D(file=filename, verbose=True) 

1325 # dlg.Destroy() 

1326 

1327 

1328class MapViewerFrame(wx.Frame): 

1329 cursor_menulabels = {'lasso': ('Select Points for XRF Spectra\tCtrl+X', 

1330 'Left-Drag to select points for XRF Spectra')} 

1331 

1332 def __init__(self, parent=None, filename=None, _larch=None, title=None, 

1333 use_scandb=False, check_version=True, size=(925, 650), 

1334 **kwds): 

1335 

1336 if check_version: 

1337 def check_version(): 

1338 self.vinfo = check_larchversion() 

1339 version_thread = Thread(target=check_version) 

1340 version_thread.start() 

1341 

1342 kwds['style'] = wx.DEFAULT_FRAME_STYLE 

1343 wx.Frame.__init__(self, parent, -1, size=size, **kwds) 

1344 

1345 self.data = None 

1346 self.use_scandb = use_scandb 

1347 self.filemap = {} 

1348 self.im_displays = [] 

1349 self.tomo_displays = [] 

1350 self.plot_displays = [] 

1351 self.current_file = None 

1352 

1353 self.larch_buffer = parent 

1354 if not isinstance(parent, LarchFrame): 

1355 self.larch_buffer = LarchFrame(_larch=_larch, is_standalone=False, with_raise=False) 

1356 

1357 self.larch = self.larch_buffer.larchshell 

1358 

1359 self.subframes = {'xrfdisplay': None, 

1360 'xrd1d': None} 

1361 self.watch_files = False 

1362 

1363 self.files_in_progress = [] 

1364 

1365 # self.hotcols = False 

1366 self.dtcor = True 

1367 self.showxrd = False 

1368 

1369 if title is None: 

1370 title = "XRF Map Viewing and Analysis" 

1371 self.SetTitle(title) 

1372 

1373 self.createMainPanel() 

1374 self.SetFont(Font(FONTSIZE)) 

1375 

1376 self.createMenus() 

1377 self.statusbar = self.CreateStatusBar(2, 0) 

1378 self.statusbar.SetStatusWidths([-3, -1]) 

1379 statusbar_fields = ['Initializing....', ' '] 

1380 for i in range(len(statusbar_fields)): 

1381 self.statusbar.SetStatusText(statusbar_fields[i], i) 

1382 

1383 self.htimer = wx.Timer(self) 

1384 self.Bind(wx.EVT_TIMER, self.onTimer, self.htimer) 

1385 self.h5convert_done = True 

1386 self.h5convert_irow = 0 

1387 self.h5convert_nrow = 0 

1388 

1389 read_workdir('gsemap.dat') 

1390 self.onFolderSelect() 

1391 self.statusbar.SetStatusText('Set Working Folder', 0) 

1392 

1393 w0, h0 = self.GetSize() 

1394 w1, h1 = self.GetBestSize() 

1395 self.SetSize((max(w0, w1)+5, max(h0, h1)+5)) 

1396 self.SetMinSize((500, 300)) 

1397 self.Show() 

1398 

1399 self.scandb = None 

1400 self.instdb = None 

1401 self.inst_name = None 

1402 self.move_callback = None 

1403 

1404 

1405 self.init_larch() 

1406 self.statusbar.SetStatusText('ready', 0) 

1407 self.Raise() 

1408 

1409 

1410 if filename is not None: 

1411 self.onRead(filename) 

1412 

1413 if check_version: 

1414 version_thread.join() 

1415 if self.vinfo is not None: 

1416 if self.vinfo.update_available: 

1417 self.onCheckforUpdates() 

1418 self.statusbar.SetStatusText(f'Larch Version {self.vinfo.remote_version} is available!', 0) 

1419 self.statusbar.SetStatusText(f'Larch Version {self.vinfo.local_version}', 1) 

1420 else: 

1421 self.statusbar.SetStatusText(f'Larch Version {self.vinfo.local_version} (latest)', 1) 

1422 

1423 

1424 def CloseFile(self, filename, event=None): 

1425 if filename in self.filemap: 

1426 self.filemap[filename].close() 

1427 self.filemap.pop(filename) 

1428 

1429 def createMainPanel(self): 

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

1431 splitter.SetMinimumPaneSize(250) 

1432 

1433 self.filelist = EditableListBox(splitter, self.ShowFile, 

1434 remove_action=self.CloseFile, 

1435 size=(250, -1)) 

1436 

1437 dpanel = self.detailspanel = wx.Panel(splitter) 

1438 self.createNBPanels(dpanel) 

1439 splitter.SplitVertically(self.filelist, self.detailspanel, 1) 

1440 sizer = wx.BoxSizer(wx.VERTICAL) 

1441 sizer.Add(splitter, 1, wx.GROW|wx.ALL, 5) 

1442 pack(self, sizer) 

1443 fico = Path(icondir, XRF_ICON_FILE).absolute().as_posix() 

1444 try: 

1445 self.SetIcon(wx.Icon(fico, wx.BITMAP_TYPE_ICO)) 

1446 except: 

1447 pass 

1448 

1449 def createNBPanels(self, parent): 

1450 self.title = SimpleText(parent, ' ', size=(680, -1)) 

1451 

1452 self.SetBackgroundColour('#F0F0E8') 

1453 

1454 nbpanels = {} 

1455 for panel in (MapPanel, MapInfoPanel, MapAreaPanel, MapMathPanel, 

1456 TomographyPanel, XRFAnalysisPanel): 

1457 nbpanels[panel.label] = panel 

1458 self.nb = flatnotebook(parent, nbpanels, panelkws={'owner':self}, 

1459 on_change=self.onNBChanged) 

1460 self.roimap_panel = self.nb.GetPage(0) 

1461 sizer = wx.BoxSizer(wx.VERTICAL) 

1462 sizer.Add(self.title, 0, ALL_CEN) 

1463 sizer.Add(self.nb, 1, wx.ALL|wx.EXPAND) 

1464 parent.SetSize((700, 400)) 

1465 pack(parent, sizer) 

1466 

1467 def onNBChanged(self, event=None): 

1468 cb = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None) 

1469 if callable(cb): 

1470 cb() 

1471 

1472 def get_mca_area(self, mask, xoff=0, yoff=0, det=None, xrmfile=None): 

1473 if xrmfile is None: 

1474 xrmfile = self.current_file 

1475 

1476 if xrmfile.write_access: 

1477 aname = xrmfile.add_area(mask) 

1478 self.sel_mca = xrmfile.get_mca_area(aname, det=det) 

1479 else: 

1480 dgroup = xrmfile.get_detname(det) 

1481 _ay, _ax = np.where(mask) 

1482 ymin, ymax, xmin, xmax = _ay.min(), _ay.max()+1, _ax.min(), _ax.max()+1 

1483 opts = {'dtcorrect': None, 'det': det} 

1484 counts = xrmfile.get_counts_rect(ymin, ymax, xmin, xmax, det=det) 

1485 ltime, rtime = xrmfile.get_livereal_rect(ymin, ymax, xmin, 

1486 xmax, det=det) 

1487 ltime = ltime[mask[ymin:ymax, xmin:xmax]].sum() 

1488 rtime = rtime[mask[ymin:ymax, xmin:xmax]].sum() 

1489 counts = counts[mask[ymin:ymax, xmin:xmax]] 

1490 while(len(counts.shape) > 1): 

1491 counts = counts.sum(axis=0) 

1492 self.sel_mca = xrmfile._getmca(dgroup, counts, 'selected area', 

1493 npixels=mask.sum(), 

1494 real_time=rtime, live_time=ltime) 

1495 

1496 

1497 def lassoHandler(self, mask=None, xrmfile=None, xoff=0, yoff=0, 

1498 det=None, **kws): 

1499 if xrmfile is None: 

1500 xrmfile = self.current_file 

1501 

1502 ny, nx = xrmfile.get_shape() 

1503 if mask.sum() < 1: 

1504 return 

1505 

1506 if (xoff>0 or yoff>0) or mask.shape != (ny, nx): 

1507 if mask.shape == (nx, ny): ## sinogram 

1508 mask = np.swapaxes(mask,0,1) 

1509 # elif mask.shape == (ny, ny) or mask.shape == (nx, nx): ## tomograph 

1510 # tomo = True 

1511 else: 

1512 ym, xm = mask.shape 

1513 tmask = np.zeros((ny, nx)).astype(bool) 

1514 xmax = min(nx, xm+xoff) 

1515 for iy in range(ym): 

1516 if iy+yoff < ny: 

1517 tmask[iy+yoff, xoff:xmax] = mask[iy] 

1518 mask = tmask 

1519 

1520 kwargs = dict(xrmfile=xrmfile, xoff=xoff, yoff=yoff, det=det) 

1521 mca_thread = Thread(target=self.get_mca_area, 

1522 args=(mask,), kwargs=kwargs) 

1523 mca_thread.start() 

1524 self.show_XRFDisplay() 

1525 mca_thread.join() 

1526 if hasattr(self, 'sel_mca'): 

1527 fname = Path(xrmfile.filename).name 

1528 aname = self.sel_mca.areaname 

1529 if self.sel_mca.npixels is None: 

1530 try: 

1531 area = xrmfile.xrmmap['areas/%s' % aname] 

1532 npix = area[()].sum() 

1533 self.sel_mca.npixels = npix 

1534 except: 

1535 pass 

1536 

1537 if self.sel_mca.npixels is None: 

1538 self.sel_mca.npixels = 0 

1539 self.sel_mca.filename = fname 

1540 self.sel_mca.title = aname 

1541 self.subframes['xrfdisplay'].add_mca(self.sel_mca, label='%s:%s'% (fname, aname), 

1542 plot=True) 

1543 self.subframes['xrfdisplay'].roi_callback = self.UpdateROI 

1544 update_xrmmap = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None) 

1545 if callable(update_xrmmap): 

1546 update_xrmmap(xrmfile=self.current_file) 

1547 

1548 if self.showxrd: 

1549 for page in self.nb.pagelist: 

1550 if hasattr(page, 'onXRD'): 

1551 page.onXRD(show=True, xrd1d=True,verbose=False) 

1552 

1553 def show_subframe(self, name, frameclass, **opts): 

1554 shown = False 

1555 if name in self.subframes: 

1556 try: 

1557 self.subframes[name].Raise() 

1558 shown = True 

1559 except: 

1560 del self.subframes[name] 

1561 if not shown: 

1562 self.subframes[name] = frameclass(self, **opts) 

1563 

1564 def show_XRD1D(self, event=None): 

1565 self.show_subframe('xrd1d', XRD1DFrame, _larch=self.larch) 

1566 

1567 def show_XRFDisplay(self, do_raise=True, clear=True, xrmfile=None): 

1568 'make sure XRF plot frame is enabled and visible' 

1569 if xrmfile is None: 

1570 xrmfile = self.current_file 

1571 self.show_subframe('xrfdisplay', XRFDisplayFrame, 

1572 parent=self.larch_buffer, 

1573 roi_callback=self.UpdateROI) 

1574 

1575 self.subframes['xrfdisplay'].Show() 

1576 if do_raise: 

1577 self.subframes['xrfdisplay'].Raise() 

1578 if clear: 

1579 self.subframes['xrfdisplay'].panel.clear() 

1580 self.subframes['xrfdisplay'].panel.reset_config() 

1581 

1582 def onMoveToPixel(self, xval, yval): 

1583 if not HAS_EPICS: 

1584 return 

1585 

1586 xrmmap = self.current_file.xrmmap 

1587 pos_addrs = [str(x) for x in xrmmap['config/positioners'].keys()] 

1588 pos_label = [str(x[()]) for x in xrmmap['config/positioners'].values()] 

1589 

1590 pos1 = h5str(xrmmap['config/scan/pos1'][()]) 

1591 pos2 = h5str(xrmmap['config/scan/pos2'][()]) 

1592 i1 = pos_addrs.index(pos1) 

1593 i2 = pos_addrs.index(pos2) 

1594 msg = '%s(%s) = %.4f, %s(%s) = %.4f?' % (pos_label[i1], pos_addrs[i1], xval, 

1595 pos_label[i2], pos_addrs[i2], yval) 

1596 

1597 if (wx.ID_YES == Popup(self, 'Really move stages to\n %s?' % msg, 

1598 'move stages to pixel?', style=wx.YES_NO)): 

1599 caput(pos_addrs[i1], xval) 

1600 caput(pos_addrs[i2], yval) 

1601 

1602 def onSavePixel(self, name, ix, iy, x=None, y=None, title=None, xrmfile=None): 

1603 'save pixel as area, and perhaps to scandb' 

1604 if x is None: 

1605 x = float(xrmfile.get_pos(0, mean=True)[ix]) 

1606 if y is None: 

1607 y = float(xrmfile.get_pos(1, mean=True)[iy]) 

1608 

1609 if len(name) < 1: 

1610 return 

1611 if xrmfile is None: 

1612 xrmfile = self.current_file 

1613 

1614 # first, create 1-pixel mask for area, and save that 

1615 ny, nx = xrmfile.get_shape() 

1616 tmask = np.zeros((ny, nx)).astype(bool) 

1617 tmask[int(iy), int(ix)] = True 

1618 xrmfile.add_area(tmask, name=name) 

1619 # for page in self.nb.pagelist: 

1620 # if hasattr(page, 'update_xrmmap'): 

1621 # page.update_xrmmap(xrmfile=xrmfile) 

1622 update_xrmmap = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None) 

1623 if callable(update_xrmmap): 

1624 update_xrmmap(xrmfile=xrmfile) 

1625 

1626 # show position on map 

1627 self.im_displays[-1].panel.add_highlight_area(tmask, label=name) 

1628 

1629 # make sure we can save position into database 

1630 if self.scandb is None or self.instdb is None: 

1631 return 

1632 samplestage = self.instdb.get_instrument(self.inst_name) 

1633 if samplestage is None: 

1634 return 

1635 pvmap = dict([(r.id, r.name) for r in self.scandb.get_rows('pv')]) 

1636 

1637 pv_rows = self.scandb.get_rows('instrument_pv', 

1638 where={'instrument_id': samplestage.id}) 

1639 

1640 allpvs = [] 

1641 for row in pv_rows: 

1642 for pvid, pvname in pvmap.items(): 

1643 if pvid == row.pv_id: 

1644 allpvs.append(pvname) 

1645 

1646 pvn = pv_fullname 

1647 conf = xrmfile.xrmmap['config'] 

1648 pos_addrs = [pvn(h5str(tval)) for tval in conf['positioners']] 

1649 env_addrs = [pvn(h5str(tval)) for tval in conf['environ/address']] 

1650 env_vals = [h5str(tval) for tval in conf['environ/value']] 

1651 

1652 position = {} 

1653 for pv in allpvs: 

1654 position[pv] = None 

1655 

1656 for addr, val in zip(env_addrs, env_vals): 

1657 if addr in allpvs: 

1658 position[addr] = float(val) 

1659 

1660 position[pvn(h5str(conf['scan/pos1'][()]))] = x 

1661 position[pvn(h5str(conf['scan/pos2'][()]))] = y 

1662 

1663 notes = {'source': '%s: %s' % (xrmfile.filename, name)} 

1664 self.instdb.save_position(self.inst_name, name, position, 

1665 notes=json.dumps(notes)) 

1666 

1667 

1668 def add_tomodisplay(self, title, det=None, _lassocallback=True): 

1669 

1670 if _lassocallback: 

1671 lasso_cb = partial(self.lassoHandler, det=det) 

1672 else: 

1673 lasso_cb = None 

1674 

1675 imframe = MapImageFrame(output_title=title, 

1676 lasso_callback=lasso_cb) 

1677 

1678 self.tomo_displays.append(imframe) 

1679 

1680 def display_tomo(self, tomo, title='', info='', x=None, y=None, xoff=0, 

1681 yoff=0, det=None, subtitles=None, xrmfile=None, 

1682 _lassocallback=True): 

1683 

1684 displayed = False 

1685 if _lassocallback: 

1686 lasso_cb = partial(self.lassoHandler, det=det, xrmfile=xrmfile) 

1687 else: 

1688 lasso_cb = None 

1689 

1690 while not displayed: 

1691 try: 

1692 tmd = self.tomo_displays.pop() 

1693 clevel = tmd.panel.conf.contrast_level 

1694 if clevel in (0, None): 

1695 clevel = 0.5 

1696 tmd.display(tomo, title=title, subtitles=subtitles, 

1697 contrast_level=clevel) 

1698 tmd.lasso_callback = lasso_cb 

1699 displayed = True 

1700 except IndexError: 

1701 tmd = MapImageFrame(output_title=title, 

1702 lasso_callback=lasso_cb) 

1703 tmd.display(tomo, title=title, subtitles=subtitles, 

1704 contrast_level=0.5) 

1705 displayed = True 

1706 except: 

1707 displayed = False 

1708 self.tomo_displays.append(tmd) 

1709 tmd.SetStatusText(info, 1) 

1710 tmd.Show() 

1711 tmd.Raise() 

1712 

1713 def add_imdisplay(self, title, det=None): 

1714 imd = MapImageFrame(output_title=title, 

1715 lasso_callback=partial(self.lassoHandler, det=det), 

1716 cursor_labels=self.cursor_menulabels, 

1717 save_callback=self.onSavePixel) 

1718 self.im_displays.append(imd) 

1719 return imd 

1720 

1721 def display_map(self, map, title='', info='', x=None, y=None, xoff=0, yoff=0, 

1722 det=None, subtitles=None, xrmfile=None, with_savepos=True): 

1723 """display a map in an available image display""" 

1724 if xrmfile is None: 

1725 hotcols = False 

1726 else: 

1727 hotcols = xrmfile.hotcols 

1728 

1729 if x is not None: 

1730 zigzag = abs(xrmfile.zigzag) 

1731 if zigzag != 0: 

1732 x = x[zigzag:-zigzag] 

1733 elif hotcols and map.shape[1] != x.shape[0]: 

1734 x = x[1:-1] 

1735 

1736 dopts = dict(title=title, x=x, y=y, xoff=xoff, yoff=yoff, 

1737 det=det, subtitles=subtitles, 

1738 xrmfile=xrmfile, with_savepos=with_savepos) 

1739 displayed = False 

1740 while not displayed: 

1741 if 'contrast_level' not in dopts: 

1742 dopts['contrast_level'] = 0.5 

1743 if len(self.im_displays) == 0: 

1744 imd = self.add_imdisplay(title=title, det=det) 

1745 imd.display(map, **dopts) 

1746 else: 

1747 try: 

1748 imd = self.im_displays[-1] 

1749 if imd.panel.conf.contrast_level not in (0, None): 

1750 dopts['contrast_level'] = imd.panel.conf.contrast_level 

1751 imd.display(map, **dopts) 

1752 displayed = True 

1753 except IndexError: 

1754 pass 

1755 except: 

1756 self.im_displays.pop() 

1757 imd.SetStatusText(info, 1) 

1758 imd.Show() 

1759 imd.Raise() 

1760 

1761 def display_xrd2d(self, map, label='image 0', xrmfile=None, flip=True): 

1762 ''' 

1763 displays 2D XRD pattern in diFFit viewer 

1764 ''' 

1765 if xrmfile is None: 

1766 xrmfile = self.current_file 

1767 calfile = bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('calfile','')) 

1768 energy = xrmfile.get_incident_energy() 

1769 

1770 if len(calfile) < 2 or not Path(calfile).exists(): 

1771 tfile = Path(xrmfile.folder, 'XRD.poni') 

1772 if tfile.exists(): 

1773 calfile = tfile.as_posix() 

1774 if Path(calfile).exists(): 

1775 self.current_file.xrmmap['xrd1d'].attrs['calfile'] = calfile 

1776 

1777 self.show_XRD1D() 

1778 self.subframes['xrd1d'].flip = 'vertical' if flip is True else False 

1779 self.subframes['xrd1d'].set_wavelength(PLANCK_HC/energy) 

1780 self.subframes['xrd1d'].calfile = calfile 

1781 self.subframes['xrd1d'].set_ponifile(calfile) 

1782 self.subframes['xrd1d'].display_xrd_image(map, label=label) 

1783 self.subframes['xrd1d'].Show() 

1784 

1785 def display_xrd1d(self, counts, q, energy, label='dataset 0', xrmfile=None): 

1786 ''' 

1787 displays 1D XRD pattern in diFFit viewer 

1788 ''' 

1789 wavelength = lambda_from_E(energy, E_units='keV') 

1790 xdat = xrd1d(label=label, energy=energy, wavelength=wavelength) 

1791 xdat.set_xy_data(np.array([q, counts]), 'q') 

1792 

1793 xrmfile = self.current_file 

1794 ponidata = json.loads(bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('caldata','{}'))) 

1795 if 'rot1' not in ponidata: # invalid poni data 

1796 ponifile = bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('calfile','')) 

1797 if len(ponifile) < 2 or not Path(ponifile).exists(): 

1798 t_ponifile = Path(xrmfile.folder, 'XRD.poni').absolute() 

1799 if t_ponifile.exists(): 

1800 ponifile = t_ponifile.as_posix() 

1801 if len(ponifile) > 1: 

1802 ponidata = read_poni(ponifile) 

1803 if 'rot1' in ponidata: 

1804 xrmfile.xrmmap['xrd1d'].attrs['caldata'] = json.dumps(ponidata) 

1805 self.show_XRD1D() 

1806 self.subframes['xrd1d'].set_wavelength(wavelength) 

1807 if 'rot1' in ponidata: 

1808 self.subframes['xrd1d'].set_poni(ponidata) 

1809 

1810 self.subframes['xrd1d'].add_data(xdat, label=label) 

1811 self.subframes['xrd1d'].Show() 

1812 

1813 def init_larch(self): 

1814 self.datagroups = self.larch.symtable 

1815 if ESCAN_CRED is not None: 

1816 self.move_callback = self.onMoveToPixel 

1817 try: 

1818 self.scandb = connect_scandb(_larch=self.larch) 

1819 self.instdb = self.larch.symtable._scan._instdb 

1820 self.inst_name = self.scandb.get_info('samplestage_instrument', 

1821 default='SampleStage') 

1822 print(" ScanDB: %s, Instrument=%s" % (self.scandb.engine, self.inst_name)) 

1823 except: 

1824 etype, emsg, tb = sys.exc_info() 

1825 print('Could not connect to ScanDB: %s' % (emsg)) 

1826 self.scandb = self.instdb = None 

1827 

1828 def ShowFile(self, evt=None, filename=None, process_file=True, **kws): 

1829 if filename is None and evt is not None: 

1830 filename = evt.GetString() 

1831 if not self.h5convert_done or filename not in self.filemap: 

1832 return 

1833 self.current_file = self.filemap[filename] 

1834 if (self.check_ownership(filename) and 

1835 self.current_file.folder_has_newdata()): 

1836 if process_file: 

1837 mnew = self.roimap_panel.mapproc_nrows.GetStringSelection() 

1838 try: 

1839 mnew = int(mnew) 

1840 except: 

1841 mnew = None 

1842 self.process_file(filename, max_new_rows=mnew) 

1843 

1844 ny, nx = self.current_file.get_shape() 

1845 self.title.SetLabel('%s: (%i x %i)' % (filename, nx, ny)) 

1846 

1847 fnames = self.filelist.GetItems() 

1848 

1849 cb = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None) 

1850 if callable(cb): 

1851 cb(xrmfile=self.current_file) 

1852 cb = getattr(self.nb.GetCurrentPage(), 'set_file_choices', None) 

1853 if callable(cb): 

1854 cb(fnames) 

1855 

1856 def createMenus(self): 

1857 self.menubar = wx.MenuBar() 

1858 fmenu = wx.Menu() 

1859 

1860 MenuItem(self, fmenu, '&Open XRM Map File\tCtrl+O', 'Read XRM Map File', self.onReadFile) 

1861 MenuItem(self, fmenu, '&Open XRM Map Folder\tCtrl+F', 'Read XRM Map Folder', self.onReadFolder) 

1862 fmenu.AppendSeparator() 

1863 MenuItem(self, fmenu, 'Change &Working Folder', 'Choose working directory', 

1864 self.onFolderSelect) 

1865 MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L', 'Show Larch Programming Buffer', 

1866 self.onShowLarchBuffer) 

1867 

1868 # cmenu = fmenu.Append(-1, '&Watch HDF5 Files\tCtrl+W', 'Watch HDF5 Files', kind=wx.ITEM_CHECK) 

1869 # fmenu.Check(cmenu.Id, self.watch_files) ## False 

1870 # self.Bind(wx.EVT_MENU, self.onWatchFiles, id=cmenu.Id) 

1871 

1872 fmenu.AppendSeparator() 

1873 MenuItem(self, fmenu, '&Quit\tCtrl+Q', 

1874 'Quit program', self.onClose) 

1875 

1876 rmenu = wx.Menu() 

1877 MenuItem(self, rmenu, 'Add / Delete ROIs', 

1878 'Define new ROIs, Remove ROIs', self.manageROIs) 

1879 MenuItem(self, rmenu, 'Load ROI File for 1DXRD', 

1880 'Load ROI File for 1DXRD', self.add1DXRDFile) 

1881 rmenu.AppendSeparator() 

1882 MenuItem(self, rmenu, 'Load XRD calibration file', 

1883 'Load XRD calibration file', self.openPONI) 

1884 MenuItem(self, rmenu, 'Add 1DXRD for HDF5 file', 

1885 'Calculate 1DXRD for HDF5 file', self.add1DXRD) 

1886 

1887 

1888 # cmenu = fmenu.Append(-1, 'Display 1DXRD for areas', 

1889 # 'Display 1DXRD for areas', 

1890 # kind=wx.ITEM_CHECK) 

1891 #fmenu.Check(cmenu.Id, self.showxrd) ## False 

1892 #self.Bind(wx.EVT_MENU, self.onShow1DXRD, id=cmenu.Id) 

1893 

1894 hmenu = wx.Menu() 

1895 MenuItem(self, hmenu, 'About GSE XRM MapViewer', 'About GSE XRM MapViewer', 

1896 self.onAbout) 

1897 MenuItem(self, hmenu, 'Check for Updates', 'Check for Updates', 

1898 self.onCheckforUpdates) 

1899 

1900 self.menubar.Append(fmenu, '&File') 

1901 self.menubar.Append(rmenu, '&ROIs') 

1902 self.menubar.Append(hmenu, '&Help') 

1903 self.SetMenuBar(self.menubar) 

1904 self.Bind(wx.EVT_CLOSE, self.onClose) 

1905 

1906 def onShowLarchBuffer(self, evt=None): 

1907 if self.larch_buffer is None: 

1908 self.larch_buffer = LarchFrame(_larch=self.larch, is_standalone=False) 

1909 

1910 self.larch_buffer.Show() 

1911 self.larch_buffer.Raise() 

1912 

1913 def onFolderSelect(self, evt=None): 

1914 dlg = wx.DirDialog(self, 'Select Working Directory:', 

1915 get_cwd(), 

1916 style=wx.DD_DIR_MUST_EXIST|wx.DD_DEFAULT_STYLE) 

1917 

1918 if dlg.ShowModal() == wx.ID_OK: 

1919 basedir = Path(dlg.GetPath()).absolute().as_posix() 

1920 try: 

1921 if len(basedir) > 0: 

1922 os.chdir(basedir) 

1923 save_workdir(basedir) 

1924 except OSError: 

1925 print( 'Changed folder failed') 

1926 pass 

1927 save_workdir('gsemap.dat') 

1928 dlg.Destroy() 

1929 

1930 def onAbout(self, event=None): 

1931 info = AboutDialogInfo() 

1932 info.SetName('GSE XRM MapViewer') 

1933 info.SetDescription('X-ray Microprobe Mapping Data Visualization and Analysis') 

1934 info.SetVersion(larch.version.__version__) 

1935 info.AddDeveloper('Matthew Newville: newville at cars.uchicago.edu') 

1936 dlg = AboutBox(info) 

1937 

1938 def onCheckforUpdates(self, event=None): 

1939 dlg = LarchUpdaterDialog(self, caller='GSE MapViewer') 

1940 dlg.Raise() 

1941 dlg.SetWindowStyle(wx.STAY_ON_TOP) 

1942 res = dlg.GetResponse() 

1943 dlg.Destroy() 

1944 if res.ok and res.run_updates: 

1945 from larch.apps import update_larch 

1946 update_larch() 

1947 self.onClose(evt=event, prompt=False) 

1948 

1949 def onClose(self, evt=None, prompt=True): 

1950 if prompt: 

1951 dlg = wx.MessageDialog(None, 'Really Quit?', 'Question', 

1952 wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) 

1953 

1954 ret = dlg.ShowModal() 

1955 if ret != wx.ID_YES: 

1956 return 

1957 

1958 save_workdir('gsemap.dat') 

1959 try: 

1960 self.htimer.Stop() 

1961 except: 

1962 pass 

1963 try: 

1964 self.file_timer.Stop() 

1965 except: 

1966 pass 

1967 

1968 

1969 for xrmfile in self.filemap.values(): 

1970 try: 

1971 xrmfile.close() 

1972 except KeyError: 

1973 pass 

1974 

1975 try: 

1976 self.larch.symtable._plotter.close_all_displays() 

1977 except: 

1978 pass 

1979 

1980 ## Closes maps, 2D XRD image 

1981 for disp in self.im_displays + self.plot_displays + self.tomo_displays: 

1982 try: 

1983 disp.Destroy() 

1984 except: 

1985 pass 

1986 

1987 for key, wid in self.subframes.items(): 

1988 if wid is not None: 

1989 try: 

1990 wid.onClose() 

1991 except: 

1992 pass 

1993 if self.larch_buffer is not None: 

1994 self.larch_buffer.exit_on_close = True 

1995 self.larch_buffer.onExit(force=True, with_sysexit=False) 

1996 self.Destroy() 

1997 

1998 def onReadFile(self, evt=None): 

1999 if not self.h5convert_done: 

2000 print('cannot open file while processing a map folder') 

2001 return 

2002 

2003 dlg = wx.FileDialog(self, message='Read XRM Map File', 

2004 defaultDir=get_cwd(), 

2005 wildcard=FILE_WILDCARDS, 

2006 style=wx.FD_OPEN|wx.FD_MULTIPLE) 

2007 path, read = None, False 

2008 if dlg.ShowModal() == wx.ID_OK: 

2009 read = True 

2010 paths = [p.replace('\\', '/') for p in dlg.GetPaths()] 

2011 dlg.Destroy() 

2012 

2013 if not read: 

2014 return 

2015 

2016 for path in paths: 

2017 fname = Path(path).name 

2018 read = True 

2019 if fname in self.filemap: 

2020 read = (wx.ID_YES == Popup(self, f"Re-read file '{path}'?", 

2021 'Re-read file?', style=wx.YES_NO)) 

2022 if read: 

2023 xrmfile = GSEXRM_MapFile(filename=str(path), scandb=self.scandb) 

2024 self.add_xrmfile(xrmfile) 

2025 

2026 def onRead(self, path): 

2027 "simple Read and install XRM Map File" 

2028 xrmfile = GSEXRM_MapFile(filename=str(path), scandb=self.scandb) 

2029 self.add_xrmfile(xrmfile) 

2030 

2031 def onReadFolder(self, evt=None): 

2032 if not self.h5convert_done: 

2033 print( 'cannot open file while processing a map folder') 

2034 return 

2035 

2036 dlg = wx.DirDialog(self, message='Read XRM Map Folder', 

2037 defaultPath=get_cwd(), 

2038 style=wx.DD_DIR_MUST_EXIST|wx.DD_DEFAULT_STYLE) 

2039 

2040 if dlg.ShowModal() == wx.ID_OK: 

2041 folder = Path(dlg.GetPath()).absolute().as_posix() 

2042 dlg.Destroy() 

2043 

2044 xrmfile = GSEXRM_MapFile(folder=folder, scandb=self.scandb) 

2045 self.add_xrmfile(xrmfile) 

2046 

2047 

2048 def add_xrmfile(self, xrmfile): 

2049 fpath = Path(xrmfile.filename) 

2050 fname = fpath.name 

2051 parent = fpath.parent.as_posix() 

2052 # print("Add XRM File ", fname) 

2053 # look for group with this name or for next available group 

2054 for i in range(1000): 

2055 gname = 'map%3.3i' % (i+1) 

2056 xgroup = getattr(self.datagroups, gname, None) 

2057 if xgroup is None: 

2058 break 

2059 gfname = Path(xgroup.filename).name 

2060 if gfname == fname: 

2061 break 

2062 

2063 setattr(self.datagroups, gname, xrmfile) 

2064 xrmfile.groupname = gname 

2065 

2066 if fname not in self.filemap: 

2067 self.filemap[fname] = xrmfile 

2068 if fname not in self.filelist.GetItems(): 

2069 self.filelist.Append(fname) 

2070 self.filelist.SetStringSelection(fname) 

2071 

2072 if self.check_ownership(fname): 

2073 mnew = self.roimap_panel.mapproc_nrows.GetStringSelection() 

2074 try: 

2075 mnew = int(mnew) 

2076 except: 

2077 mnew = None 

2078 self.process_file(fname, max_new_rows=mnew) 

2079 

2080 self.ShowFile(filename=fname) 

2081 if parent is not None and len(parent) > 0: 

2082 try: 

2083 os.chdir(unixpath(parent)) 

2084 save_workdir(unixpath(parent)) 

2085 except: 

2086 pass 

2087 

2088 def openPONI(self, evt=None): 

2089 """ 

2090 Read specified poni file. 

2091 mkak 2016.07.21 

2092 """ 

2093 

2094 if len(self.filemap) > 0: 

2095 myDlg = OpenPoniFile() 

2096 read = False 

2097 if myDlg.ShowModal() == wx.ID_OK: 

2098 read = True 

2099 path = myDlg.XRDInfo[1].GetValue() 

2100 flip = False if myDlg.XRDInfo[0].GetSelection() == 1 else True 

2101 myDlg.Destroy() 

2102 

2103 if read: 

2104 self.current_file.add_XRDfiles(xrdcalfile=path,flip=flip) 

2105 update_xrmmap = getattr(self.nb.GetCurrentPage(), 

2106 'update_xrmmap', None) 

2107 if callable(update_xrmmap): 

2108 update_xrmmap(xrmfile=self.current_file) 

2109 

2110 def UpdateROI(self, name, xrange=None, action='add', units='keV', roitype='XRF'): 

2111 "add or remove an ROI with name, range" 

2112 cfile = self.current_file 

2113 if xrange is None: xrange = [1, 2] 

2114 if roitype == 'XRF': 

2115 if action.startswith('del'): 

2116 cfile.del_xrfroi(name) 

2117 else: 

2118 cfile.add_xrfroi(name, xrange, unit=units) 

2119 

2120 if roitype == '1DXRD': 

2121 if action.startswith('del'): 

2122 cfile.del_xrd1droi(name) 

2123 else: 

2124 cfile.add_xrd1droi(name, xrange, unit=units) 

2125 

2126 self.current_file.get_roi_list('mcasum', force=True) 

2127 for page in self.nb.pagelist: 

2128 if hasattr(page, 'update_xrmmap'): 

2129 page.update_xrmmap(xrmfile=self.current_file) 

2130 if hasattr(page, 'set_roi_choices'): 

2131 page.set_roi_choices() 

2132 

2133 def manageROIs(self, event=None): 

2134 if not self.h5convert_done: 

2135 print( 'cannot open file while processing a map folder') 

2136 elif len(self.filemap) > 0: 

2137 ROIDialog(self, roi_callback=self.UpdateROI).Show() 

2138 

2139 def add1DXRDFile(self, event=None): 

2140 if len(self.filemap) > 0: 

2141 read = False 

2142 wildcards = '1D-XRD ROI file (*.dat)|*.dat|All files (*.*)|*.*' 

2143 dlg = wx.FileDialog(self, message='Select 1D-XRD ROI file', 

2144 defaultDir=get_cwd(), 

2145 wildcard=wildcards, 

2146 style=wx.FD_OPEN) 

2147 

2148 if dlg.ShowModal() == wx.ID_OK: 

2149 read = True 

2150 path = dlg.GetPath().replace('\\', '/') 

2151 dlg.Destroy() 

2152 

2153 if read and Path(path).exists(): 

2154 time.sleep(1) 

2155 self.current_file.read_xrd1D_ROIFile(path) 

2156 

2157 def add1DXRD(self, event=None): 

2158 

2159 if len(self.filemap) > 0: 

2160 xrd1Dgrp = ensure_subgroup('xrd1d',self.current_file.xrmmap) 

2161 poni_path = bytes2str(xrd1Dgrp.attrs.get('calfile','')) 

2162 

2163 if not Path(poni_path).exists(): 

2164 self.openPONI() 

2165 poni_path = bytes2str(xrd1Dgrp.attrs.get('calfile','')) 

2166 

2167 if Path(poni_path).exists(): 

2168 self.current_file.add_xrd1d() 

2169 

2170 def onShow1DXRD(self, event=None): 

2171 self.showxrd = event.IsChecked() 

2172 if self.showxrd: 

2173 msg = 'Show 1DXRD data for area' 

2174 else: 

2175 msg = 'Not displaying 1DXRD for area' 

2176 self.message(msg) 

2177 ##print(msg) 

2178 

2179# def onCorrectDeadtime(self, event=None): 

2180# self.dtcor = event.IsChecked() 

2181# if self.dtcor: 

2182# msg = 'Using deadtime corrected data...' 

2183# else: 

2184# msg = 'Using raw data...' 

2185# self.message(msg) 

2186# ##print(msg) 

2187# 

2188# def onHotColumns(self, event=None): 

2189# self.hotcols = event.IsChecked() 

2190# if self.hotcols: 

2191# msg = 'Ignoring first/last data columns.' 

2192# else: 

2193# msg = 'Using all data columns' 

2194# self.message(msg) 

2195# ##print(msg) 

2196 

2197 def onWatchFiles(self, event=None): 

2198 self.watch_files = event.IsChecked() 

2199 if not self.watch_files: 

2200 self.file_timer.Stop() 

2201 msg = 'Watching Files/Folders for Changes: Off' 

2202 else: 

2203 self.file_timer.Start(10000) 

2204 msg = 'Watching Files/Folders for Changes: On' 

2205 self.message(msg) 

2206 

2207 def onFileWatchTimer(self, event=None): 

2208 if self.current_file is not None and len(self.files_in_progress) == 0: 

2209 if self.current_file.folder_has_newdata(): 

2210 fname = Path(self.current_file.filename).name 

2211 self.process_file(fname, max_new_rows=1e6) 

2212 

2213 def process_file(self, filename, max_new_rows=None, on_complete=None): 

2214 """Request processing of map file. 

2215 This can take awhile, so is done in a separate thread, 

2216 with updates displayed in message bar 

2217 """ 

2218 xrmfile = self.filemap[filename] 

2219 if xrmfile.status == GSEXRM_FileStatus.created: 

2220 xrmfile.initialize_xrmmap(callback=self.updateTimer) 

2221 

2222 if xrmfile.dimension is None and isGSEXRM_MapFolder(self.folder): 

2223 xrmfile.read_master() 

2224 

2225 # print("PROCESS_FILE!!", xrmfile.folder_has_newdata(), self.h5convert_done, 

2226 # filename in self.files_in_progress) 

2227 

2228 if (xrmfile.folder_has_newdata() and self.h5convert_done 

2229 and filename not in self.files_in_progress): 

2230 

2231 self.files_in_progress.append(filename) 

2232 self.h5convert_fname = filename 

2233 self.h5convert_done = False 

2234 self.h5convert_oncomplete = on_complete 

2235 self.htimer.Start(500) 

2236 maxrow = None 

2237 if max_new_rows is not None: 

2238 maxrow = max_new_rows + xrmfile.last_row + 1 

2239 

2240 ## this calls process function of xrm_mapfile class 

2241 self.h5convert_thread = Thread(target=xrmfile.process, 

2242 kwargs={'callback':self.updateTimer, 

2243 'maxrow': maxrow}) 

2244 self.h5convert_thread.start() 

2245 elif callable(on_complete): 

2246 on_complete() 

2247 

2248 def updateTimer(self, row=None, maxrow=None, filename=None, status=None): 

2249 # print("== UPDATE TIMER ", row, maxrow, filename, status) 

2250 if row is not None: self.h5convert_irow = row 

2251 if maxrow is not None: self.h5convert_nrow = maxrow 

2252 if filename is not None: self.h5convert_fname = filename 

2253 self.h5convert_done = True if status == 'complete' else False 

2254 msg = 'processing %s: row %i of %i' % (self.h5convert_fname, 

2255 self.h5convert_irow, 

2256 self.h5convert_nrow) 

2257 wx.CallAfter(self.message, msg) 

2258 

2259 def onTimer(self, event=None): 

2260 if self.h5convert_done: 

2261 # print("h5convert done, stopping timer") 

2262 fname = self.h5convert_fname 

2263 irow, nrow = self.h5convert_irow, self.h5convert_nrow 

2264 self.htimer.Stop() 

2265 self.h5convert_thread.join() 

2266 self.files_in_progress = [] 

2267 self.message(f'MapViewer processing {fname}: complete!') 

2268 _fname = Path(fname).name 

2269 if _fname in self.filemap: 

2270 cfile = self.current_file = self.filemap[_fname] 

2271 ny, nx = cfile.get_shape() 

2272 self.title.SetLabel('%s: (%i x %i)' % (_fname, nx, ny)) 

2273 update_xrmmap = getattr(self.nb.GetCurrentPage(), 

2274 'update_xrmmap', None) 

2275 if callable(update_xrmmap) and _fname in self.filemap: 

2276 update_xrmmap(xrmfile=cfile) 

2277 if self.h5convert_oncomplete is not None: 

2278 self.h5convert_oncomplete() 

2279 

2280 

2281 def message(self, msg, win=0): 

2282 self.statusbar.SetStatusText(msg, win) 

2283 

2284 def check_ownership(self, fname): 

2285 """ 

2286 check whether we're currently owner of the file. 

2287 this is important!! HDF5 files can be corrupted. 

2288 """ 

2289 if not self.filemap[fname].check_hostid(): 

2290 if (wx.ID_YES == Popup(self, NOT_OWNER_MSG % fname, 

2291 'Not Owner of HDF5 File', 

2292 style=wx.YES_NO)): 

2293 self.filemap[fname].take_ownership() 

2294 return self.filemap[fname].check_hostid() 

2295 

2296class OpenPoniFile(wx.Dialog): 

2297 """""" 

2298 

2299 #---------------------------------------------------------------------- 

2300 def __init__(self): 

2301 

2302 """Constructor""" 

2303 dialog = wx.Dialog.__init__(self, None, title='XRD Calibration File', size=(350, 280)) 

2304 

2305 panel = wx.Panel(self) 

2306 

2307 ################################################################################ 

2308 cal_chc = ['Dioptas calibration file:','pyFAI calibration file:'] 

2309 cal_spn = wx.SP_VERTICAL|wx.SP_ARROW_KEYS|wx.SP_WRAP 

2310 self.PoniInfo = [ Choice(panel, choices=cal_chc ), 

2311 wx.TextCtrl(panel, size=(320, 25)), 

2312 Button(panel, label='Browse...')] 

2313 

2314 self.PoniInfo[2].Bind(wx.EVT_BUTTON, self.onBROWSEponi) 

2315 

2316 ponisizer = wx.BoxSizer(wx.VERTICAL) 

2317 ponisizer.Add(self.PoniInfo[0], flag=wx.TOP, border=15) 

2318 ponisizer.Add(self.PoniInfo[1], flag=wx.TOP, border=5) 

2319 ponisizer.Add(self.PoniInfo[2], flag=wx.TOP|wx.BOTTOM, border=5) 

2320 

2321 ################################################################################ 

2322 hlpBtn = wx.Button(panel, wx.ID_HELP ) 

2323 okBtn = wx.Button(panel, wx.ID_OK ) 

2324 canBtn = wx.Button(panel, wx.ID_CANCEL ) 

2325 

2326 minisizer = wx.BoxSizer(wx.HORIZONTAL) 

2327 minisizer.Add(hlpBtn, flag=wx.RIGHT, border=5) 

2328 minisizer.Add(canBtn, flag=wx.RIGHT, border=5) 

2329 minisizer.Add(okBtn, flag=wx.RIGHT, border=5) 

2330 ################################################################################ 

2331 sizer = wx.BoxSizer(wx.VERTICAL) 

2332 sizer.Add((-1, 10)) 

2333 sizer.Add(ponisizer, flag=wx.TOP|wx.LEFT, border=5) 

2334 sizer.Add((-1, 15)) 

2335 sizer.Add(minisizer, flag=wx.ALIGN_RIGHT, border=5) 

2336 

2337 panel.SetSizer(sizer) 

2338 ################################################################################ 

2339 

2340 ## Set defaults 

2341 self.PoniInfo[0].SetSelection(0) 

2342 

2343 self.FindWindowById(wx.ID_OK).Disable() 

2344 

2345 def checkOK(self,event=None): 

2346 

2347 if Path(self.PoniInfo[1].GetValue()).exists(): 

2348 self.FindWindowById(wx.ID_OK).Enable() 

2349 else: 

2350 self.FindWindowById(wx.ID_OK).Disable() 

2351 

2352 def onBROWSEponi(self,event=None): 

2353 wildcards = 'XRD calibration file (*.poni)|*.poni|All files (*.*)|*.*' 

2354 if Path(self.PoniInfo[1].GetValue()).exists(): 

2355 dfltDIR = self.PoniInfo[1].GetValue() 

2356 else: 

2357 dfltDIR = get_cwd() 

2358 

2359 dlg = wx.FileDialog(self, message='Select XRD calibration file', 

2360 defaultDir=dfltDIR, 

2361 wildcard=wildcards, style=wx.FD_OPEN) 

2362 path, read = None, False 

2363 if dlg.ShowModal() == wx.ID_OK: 

2364 read = True 

2365 path = dlg.GetPath().replace('\\', '/') 

2366 dlg.Destroy() 

2367 

2368 if read: 

2369 self.PoniInfo[1].Clear() 

2370 self.PoniInfo[1].SetValue(str(path)) 

2371 self.checkOK() 

2372 

2373###### 

2374class ROIDialog(wx.Dialog): 

2375 """""" 

2376 #---------------------------------------------------------------------- 

2377 def __init__(self, owner, roi_callback=None, **kws): 

2378 """Constructor""" 

2379 print("ROI Dialog owner ", owner) 

2380 wx.Dialog.__init__(self, owner, wx.ID_ANY, title='Add and Delete ROIs', 

2381 size=(450, 350)) 

2382 

2383 self.owner = owner 

2384 self.roi_callback = roi_callback 

2385 self.Bind(wx.EVT_CLOSE, self.onClose) 

2386 

2387 self.gp = gp = GridPanel(self, nrows=8, ncols=4, itemstyle=LEFT, gap=3, **kws) 

2388 

2389 self.roi_name = wx.TextCtrl(gp, -1, 'ROI_001', size=(120, -1)) 

2390 fopts = dict(minval=-1, precision=3, size=(120, -1)) 

2391 self.roi_type = Choice(gp, size=(120, -1)) 

2392 self.roi_lims = [FloatCtrl(gp, value=0, **fopts), 

2393 FloatCtrl(gp, value=-1, **fopts)] 

2394 self.roi_units = Choice(gp, size=(120, -1)) 

2395 

2396 gp.Add(SimpleText(gp, ' Add new ROI: '), dcol=2, style=LEFT) 

2397 gp.Add(SimpleText(gp, ' Name:'), newrow=True) 

2398 gp.Add(self.roi_name, dcol=2) 

2399 gp.Add(SimpleText(gp, ' Type:'), newrow=True) 

2400 gp.Add(self.roi_type, dcol=2) 

2401 

2402 gp.Add(SimpleText(gp, ' Limits:'), newrow=True) 

2403 gp.AddMany((self.roi_lims[0], self.roi_lims[1], self.roi_units), 

2404 dcol=1, style=LEFT) 

2405 gp.Add(SimpleText(gp, ' '), newrow=True) 

2406 gp.Add(Button(gp, 'Add ROI', size=(120, -1), action=self.onCreateROI), 

2407 dcol=2) 

2408 

2409 ############################################################################### 

2410 

2411 self.rm_roi_name = Choice(gp, size=(120, -1)) 

2412 self.rm_roi_det = Choice(gp, size=(120, -1)) 

2413 fopts = dict(minval=-1, precision=3, size=(100, -1)) 

2414 gp.Add(SimpleText(gp, ''),newrow=True) 

2415 gp.Add(HLine(gp, size=(350, 4)), dcol=4, newrow=True) 

2416 gp.Add(SimpleText(gp, ''),newrow=True) 

2417 gp.Add(SimpleText(gp, 'Delete ROI: '), dcol=2, newrow=True) 

2418 

2419 gp.AddMany((SimpleText(gp, 'Detector:'),self.rm_roi_det), newrow=True) 

2420 gp.AddMany((SimpleText(gp, 'ROI:'),self.rm_roi_name), newrow=True) 

2421 

2422 gp.Add(SimpleText(gp, ''), newrow=True) 

2423 gp.Add(Button(gp, 'Remove This ROI', size=(120, -1), action=self.onRemoveROI), 

2424 dcol=2) 

2425 

2426 self.roi_type.Bind(wx.EVT_CHOICE, self.roiUNITS) 

2427 self.rm_roi_name.Bind(wx.EVT_CHOICE, self.roiSELECT) 

2428 

2429 gp.pack() 

2430 fit_dialog_window(self, gp) 

2431 self.owner.current_file.reset_flags() 

2432 self.roiTYPE() 

2433 

2434 def roiTYPE(self, event=None): 

2435 roitype = [] 

2436 cfile = self.owner.current_file 

2437 det_list = cfile.get_detector_list() 

2438 if cfile.has_xrf: 

2439 roitype += ['XRF'] 

2440 if cfile.has_xrd1d: 

2441 roitype += ['1DXRD'] 

2442 if len(roitype) < 1: 

2443 roitype = [''] 

2444 self.roi_type.SetChoices(roitype) 

2445 self.roiUNITS() 

2446 self.rm_roi_det.SetChoices(det_list) 

2447 self.setROI() 

2448 

2449 def onRemoveROI(self,event=None): 

2450 detname = self.rm_roi_det.GetStringSelection() 

2451 roiname = self.rm_roi_name.GetStringSelection() 

2452 

2453 if self.roi_callback is not None: 

2454 self.roi_callback(roiname, action='del') 

2455 self.setROI() 

2456 self.roiTYPE() 

2457 

2458 def setROI(self): 

2459 detname = self.rm_roi_det.GetStringSelection() 

2460 cfile = self.owner.current_file 

2461 try: 

2462 detgrp = cfile.xrmmap['roimap'][detname] 

2463 except: 

2464 return 

2465 

2466 limits = [] 

2467 names = detgrp.keys() 

2468 for name in names: 

2469 limits += [list(detgrp[name]['limits'][:])] 

2470 if len(limits) > 0: 

2471 self.rm_roi_name.SetChoices([x for (y,x) in sorted(zip(limits,names))]) 

2472 self.roiSELECT() 

2473 

2474 def roiSELECT(self, event=None): 

2475 detname = self.rm_roi_det.GetStringSelection() 

2476 cfile = self.owner.current_file 

2477 roinames = cfile.get_roi_list(detname) 

2478 self.rm_roi_name.SetChoices(roinames) 

2479 

2480 def roiUNITS(self,event=None): 

2481 choice = self.roi_type.GetStringSelection() 

2482 roiunit = [''] 

2483 if choice == 'XRF': 

2484 roiunit = ['keV', 'eV', 'channels'] 

2485 elif choice == '1DXRD': 

2486 roiunit = [u'\u212B\u207B\u00B9 (q)',u'\u00B0 (2\u03B8)',u'\u212B (d)'] 

2487 

2488 self.roi_units.SetChoices(roiunit) 

2489 

2490 def onCreateROI(self,event=None): 

2491 rtype = self.roi_type.GetStringSelection() 

2492 name = self.roi_name.GetValue() 

2493 xrange = [float(lims.GetValue()) for lims in self.roi_lims] 

2494 

2495 units = self.roi_units.GetStringSelection() 

2496 if rtype == '1DXRD': 

2497 units = ['q', '2th', 'd'][self.roi_units.GetSelection()] 

2498 

2499 

2500 self.owner.message(f'Building ROI data for: {name:s}') 

2501 if self.roi_callback is not None: 

2502 self.roi_callback(name, xrange=xrange, action='add', units=units, roitype=rtype) 

2503 

2504 self.owner.message(f'Added ROI: {name:s}') 

2505 self.roiTYPE() 

2506 

2507 def onClose(self, event=None): 

2508 self.Destroy() 

2509 

2510##################a 

2511 

2512 

2513 

2514class OpenMapFolder(wx.Dialog): 

2515 """""" 

2516 

2517 #---------------------------------------------------------------------- 

2518 def __init__(self, folder): 

2519 """Constructor""" 

2520 self.folder = folder 

2521 f = Path(folder).name 

2522 title = f"Read XRM Map Folder: {f}" 

2523 wx.Dialog.__init__(self, None, 

2524 title=title, size=(475, 750)) 

2525 

2526 

2527 panel = wx.Panel(self) 

2528 

2529 ChkTtl = SimpleText(panel, label='Build map including data:' ) 

2530 self.ChkBx = [ Check(panel, label='XRF' ), 

2531 Check(panel, label='2DXRD' ), 

2532 Check(panel, label='1DXRD (requires calibration file)' )] 

2533 

2534 for chkbx in self.ChkBx: 

2535 chkbx.Bind(wx.EVT_CHECKBOX, self.checkOK) 

2536 

2537 cbsizer = wx.BoxSizer(wx.HORIZONTAL) 

2538 cbsizer.Add(self.ChkBx[0]) 

2539 cbsizer.Add(self.ChkBx[1]) 

2540 cbsizer.Add(self.ChkBx[2]) 

2541 

2542 ckbxsizer = wx.BoxSizer(wx.VERTICAL) 

2543 ckbxsizer.Add(ChkTtl, flag=wx.BOTTOM|wx.LEFT) 

2544 ckbxsizer.Add(cbsizer) 

2545 ################################################################################ 

2546 infoTtl = [ SimpleText(panel, label='Facility'), 

2547 SimpleText(panel, label='Beamline'), 

2548 SimpleText(panel, label='Run cycle'), 

2549 SimpleText(panel, label='Proposal'), 

2550 SimpleText(panel, label='User group')] 

2551 self.info = [ wx.TextCtrl(panel, size=(100, 25) ), 

2552 wx.TextCtrl(panel, size=(100, 25) ), 

2553 wx.TextCtrl(panel, size=(100, 25) ), 

2554 wx.TextCtrl(panel, size=(100, 25) ), 

2555 wx.TextCtrl(panel, size=(320, 25) )] 

2556 

2557 infosizer0 = wx.BoxSizer(wx.HORIZONTAL) 

2558 infosizer0.Add(infoTtl[0], flag=wx.RIGHT, border=5) 

2559 infosizer0.Add(self.info[0], flag=wx.RIGHT, border=15) 

2560 infosizer0.Add(infoTtl[1], flag=wx.RIGHT, border=5) 

2561 infosizer0.Add(self.info[1], flag=wx.RIGHT, border=15) 

2562 

2563 infosizer1 = wx.BoxSizer(wx.HORIZONTAL) 

2564 infosizer1.Add(infoTtl[2], flag=wx.RIGHT, border=5) 

2565 infosizer1.Add(self.info[2], flag=wx.RIGHT, border=15) 

2566 infosizer1.Add(infoTtl[3], flag=wx.RIGHT, border=5) 

2567 infosizer1.Add(self.info[3], flag=wx.RIGHT, border=15) 

2568 

2569 infosizer2 = wx.BoxSizer(wx.HORIZONTAL) 

2570 infosizer2.Add(infoTtl[4], flag=wx.RIGHT, border=5) 

2571 infosizer2.Add(self.info[4], flag=wx.RIGHT, border=15) 

2572 

2573 infosizer = wx.BoxSizer(wx.VERTICAL) 

2574 infosizer.Add(infosizer0, flag=wx.TOP, border=5) 

2575 infosizer.Add(infosizer1, flag=wx.TOP|wx.BOTTOM, border=5) 

2576 infosizer.Add(infosizer2, flag=wx.BOTTOM, border=15) 

2577 ################################################################################ 

2578 cal_chc = ['Dioptas calibration file:','pyFAI calibration file:'] 

2579 bkgd_chc = ['2DXRD background (optional):','1DXRD background (optional):'] 

2580 cal_spn = wx.SP_VERTICAL|wx.SP_ARROW_KEYS|wx.SP_WRAP 

2581 self.XRDInfo = [ Choice(panel, choices=cal_chc ), 

2582 wx.TextCtrl(panel, size=(320, 25)), 

2583 Button(panel, label='Browse...'), 

2584 SimpleText(panel, label='Steps:'), 

2585 wx.TextCtrl(panel, size=(80, 25)), 

2586 SimpleText(panel, label='Wedges:'), 

2587 wx.SpinCtrl(panel, style=cal_spn, size=(100, -1)), 

2588 Choice(panel, choices=bkgd_chc ), 

2589 wx.TextCtrl(panel, size=(320, 25)), 

2590 Button(panel, label='Browse...'), 

2591 SimpleText(panel, label='Background scale:'), 

2592 wx.TextCtrl(panel, size=(80, 25)), 

2593 SimpleText(panel, label='2DXRD mask file (optional):'), 

2594 wx.TextCtrl(panel, size=(320, 25)), 

2595 Button(panel, label='Browse...'),] 

2596 

2597 for i in [1,8,13]: 

2598 self.XRDInfo[i+1].Bind(wx.EVT_BUTTON, partial(self.onBROWSEfile,i=i)) 

2599 

2600 xrdsizer1 = wx.BoxSizer(wx.HORIZONTAL) 

2601 

2602 xrdsizer1.Add(self.XRDInfo[3], flag=wx.RIGHT, border=5) 

2603 xrdsizer1.Add(self.XRDInfo[4], flag=wx.RIGHT, border=5) 

2604 xrdsizer1.Add(self.XRDInfo[5], flag=wx.RIGHT, border=5) 

2605 xrdsizer1.Add(self.XRDInfo[6], flag=wx.RIGHT, border=5) 

2606 

2607 xrdsizer2 = wx.BoxSizer(wx.HORIZONTAL) 

2608 

2609 xrdsizer2.Add(self.XRDInfo[9], flag=wx.RIGHT, border=30) 

2610 xrdsizer2.Add(self.XRDInfo[10], flag=wx.RIGHT, border=5) 

2611 xrdsizer2.Add(self.XRDInfo[11], flag=wx.RIGHT, border=5) 

2612 

2613 xrdsizer = wx.BoxSizer(wx.VERTICAL) 

2614 xrdsizer.Add(self.XRDInfo[0], flag=wx.TOP, border=5) 

2615 xrdsizer.Add(self.XRDInfo[1], flag=wx.TOP, border=5) 

2616 xrdsizer.Add(self.XRDInfo[2], flag=wx.TOP|wx.BOTTOM, border=5) 

2617 xrdsizer.Add(xrdsizer1, flag=wx.BOTTOM, border=5) 

2618 xrdsizer.Add(self.XRDInfo[7], flag=wx.TOP, border=8) 

2619 xrdsizer.Add(self.XRDInfo[8], flag=wx.TOP, border=5) 

2620# xrdsizer.Add(self.XRDInfo[9], flag=wx.TOP|wx.BOTTOM, border=5) 

2621 xrdsizer.Add(xrdsizer2, flag=wx.TOP|wx.BOTTOM, border=5) 

2622 xrdsizer.Add(self.XRDInfo[12], flag=wx.TOP, border=8) 

2623 xrdsizer.Add(self.XRDInfo[13], flag=wx.TOP, border=5) 

2624 xrdsizer.Add(self.XRDInfo[14], flag=wx.TOP|wx.BOTTOM, border=5) 

2625 

2626 

2627 ################################################################################ 

2628 h5cmpr_chc = ['gzip','lzf'] 

2629 h5cmpr_opt = ['%i' % i for i in np.arange(10)] 

2630 

2631 self.H5cmprInfo = [Choice(panel, choices=h5cmpr_chc), 

2632 Choice(panel, choices=h5cmpr_opt)] 

2633 h5txt = SimpleText(panel, label='H5 File Comppression:') 

2634 

2635 self.H5cmprInfo[0].SetSelection(0) 

2636 self.H5cmprInfo[1].SetSelection(2) 

2637 

2638 self.H5cmprInfo[0].Bind(wx.EVT_CHOICE, self.onH5cmpr) 

2639 

2640 h5cmprsizer = wx.BoxSizer(wx.HORIZONTAL) 

2641 h5cmprsizer.Add(h5txt, flag=wx.RIGHT, border=5) 

2642 h5cmprsizer.Add(self.H5cmprInfo[0], flag=wx.RIGHT, border=5) 

2643 h5cmprsizer.Add(self.H5cmprInfo[1], flag=wx.RIGHT, border=5) 

2644 ################################################################################ 

2645 self.ok_btn = wx.Button(panel, wx.ID_OK) 

2646 self.cancel_btn = wx.Button(panel, wx.ID_CANCEL) 

2647 

2648 minisizer = wx.BoxSizer(wx.HORIZONTAL) 

2649 minisizer.Add(self.cancel_btn, flag=wx.RIGHT, border=5) 

2650 minisizer.Add(self.ok_btn, flag=wx.RIGHT, border=5) 

2651 ################################################################################ 

2652 sizer = wx.BoxSizer(wx.VERTICAL) 

2653 

2654 sizer.Add(ckbxsizer, flag=wx.TOP|wx.LEFT, border=5) 

2655 

2656 sizer.Add(HLine(panel, size=(320, 2)),flag=wx.TOP|wx.LEFT, border=5) 

2657 sizer.Add(infosizer, flag=wx.TOP|wx.LEFT, border=5) 

2658 sizer.Add(HLine(panel, size=(320, 2)),flag=wx.TOP|wx.LEFT, border=5) 

2659 sizer.Add(xrdsizer, flag=wx.TOP|wx.LEFT, border=5) 

2660 sizer.Add(HLine(panel, size=(320, 2)),flag=wx.TOP|wx.LEFT, border=5) 

2661 sizer.Add(h5cmprsizer, flag=wx.TOP|wx.LEFT, border=5) 

2662 sizer.Add(minisizer, flag=wx.ALIGN_RIGHT, border=5) 

2663 

2664 

2665 pack(panel, sizer) 

2666 w, h = panel.GetBestSize() 

2667 w = 25*(2 + int(w*0.04)) 

2668 h = 25*(2 + int(h*0.04)) 

2669 panel.SetSize((w, h)) 

2670 

2671 # HX 

2672 ################################################################################ 

2673 

2674 ## Set defaults 

2675 self.ChkBx[0].SetValue(True) 

2676 self.ChkBx[1].SetValue(False) 

2677 self.ChkBx[2].SetValue(False) 

2678 

2679 self.XRDInfo[0].SetSelection(0) 

2680 self.XRDInfo[7].SetSelection(0) 

2681 

2682 self.XRDInfo[4].SetValue('5001') 

2683 self.XRDInfo[6].SetValue(1) 

2684 self.XRDInfo[6].SetRange(0,36) 

2685 

2686 self.XRDInfo[11].SetValue('1.0') 

2687 

2688 for poniinfo in self.XRDInfo: 

2689 poniinfo.Disable() 

2690 

2691 self.info[0].SetValue(FACILITY) 

2692 self.info[1].SetValue(BEAMLINE) 

2693 for line in open(Path(self.folder, 'Scan.ini'), 'r'): 

2694 if line.split()[0] == 'basedir': 

2695 npath = line.split()[-1].replace('\\', '/').split('/') 

2696 cycle, usr = npath[-2], npath[-1] 

2697 self.info[2].SetValue(cycle) 

2698 self.info[4].SetValue(usr) 

2699 self.checkOK() 

2700 

2701 def checkOK(self, evt=None): 

2702 

2703 if self.ChkBx[2].GetValue(): 

2704 for poniinfo in self.XRDInfo: 

2705 poniinfo.Enable() 

2706 elif self.ChkBx[1].GetValue(): 

2707 for poniinfo in self.XRDInfo[8:]: 

2708 poniinfo.Enable() 

2709 for poniinfo in self.XRDInfo[:8]: 

2710 poniinfo.Disable() 

2711 self.XRDInfo[7].SetSelection(0) 

2712 else: 

2713 for poniinfo in self.XRDInfo: 

2714 poniinfo.Disable() 

2715 

2716 def onH5cmpr(self,event=None): 

2717 

2718 if self.H5cmprInfo[0].GetSelection() == 0: 

2719 self.H5cmprInfo[1].Enable() 

2720 self.H5cmprInfo[1].SetChoices(['%i' % i for i in np.arange(10)]) 

2721 self.H5cmprInfo[1].SetSelection(2) 

2722 else: 

2723 self.H5cmprInfo[1].Disable() 

2724 self.H5cmprInfo[1].SetChoices(['']) 

2725 

2726 def onBROWSEfile(self,event=None,i=1): 

2727 

2728 if i == 8: 

2729 wldcd = '2D XRD background file (*.tiff)|*.tif;*.tiff;*.edf|All files (*.*)|*.*' 

2730 if i == 13: 

2731 wldcd = '1D XRD background file (*.xy)|*.xy|All files (*.*)|*.*' 

2732 else: ## elif i == 1: 

2733 wldcd = 'XRD calibration file (*.poni)|*.poni|All files (*.*)|*.*' 

2734 

2735 if Path(self.XRDInfo[i].GetValue()).exists(): 

2736 dfltDIR = self.XRDInfo[i].GetValue() 

2737 else: 

2738 dfltDIR = get_cwd() 

2739 

2740 dlg = wx.FileDialog(self, message='Select %s' % wldcd.split(' (')[0], 

2741 defaultDir=dfltDIR, 

2742 wildcard=wldcd, style=wx.FD_OPEN) 

2743 path, read = None, False 

2744 if dlg.ShowModal() == wx.ID_OK: 

2745 read = True 

2746 path = dlg.GetPath().replace('\\', '/') 

2747 dlg.Destroy() 

2748 

2749 if read: 

2750 self.XRDInfo[i].Clear() 

2751 self.XRDInfo[i].SetValue(str(path)) 

2752 

2753 

2754class MapViewer(LarchWxApp): 

2755 def __init__(self, use_scandb=False, _larch=None, filename=None, 

2756 title=None, check_version=True, with_inspect=False, **kws): 

2757 

2758 self.filename = filename 

2759 self.title = title 

2760 self.use_scandb = use_scandb 

2761 self.check_version = check_version 

2762 LarchWxApp.__init__(self, _larch=_larch, 

2763 with_inspect=with_inspect, **kws) 

2764 

2765 def createApp(self): 

2766 frame = MapViewerFrame(use_scandb=self.use_scandb, 

2767 title=self.title, 

2768 filename=self.filename, 

2769 check_version=self.check_version, 

2770 _larch=self._larch) 

2771 self.SetTopWindow(frame) 

2772 return True 

2773 

2774 

2775def mapviewer(use_scandb=False, filename=None, _larch=None, 

2776 with_inspect=False, **kws): 

2777 MapViewer(use_scandb=use_scandb, filename=filename, _larch=_larch, 

2778 with_inspect=with_inspect, **kws)