Coverage for /Users/Newville/Codes/xraylarch/larch/wxmap/mapviewer.py: 10%
1929 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
1#!/usr/bin/env python
2"""
3GUI for displaying maps from HDF5 files
5"""
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
18import wx
19from wx.adv import AboutBox, AboutDialogInfo
20import wx.lib.scrolledpanel as scrolled
21import wx.lib.mixins.inspection
23import wx.dataview as dv
24DVSTY = dv.DV_SINGLE|dv.DV_VERT_RULES|dv.DV_ROW_LINES
26HAS_EPICS = False
27try:
28 from epics import caput
29 HAS_EPICS = True
30except:
31 pass
33import numpy as np
34import scipy.stats as stats
36#from matplotlib.widgets import Slider, Button, RadioButtons
38from wxmplot import PlotFrame
40import larch
41from larch.larchlib import read_workdir, save_workdir
42from larch.wxlib import (LarchPanel, LarchFrame, EditableListBox, SimpleText,
43 FloatCtrl, Font, pack, Popup, Button, MenuItem,
44 Choice, Check, GridPanel, FileSave, HLine, flatnotebook,
45 HLine, OkCancel, LEFT, LarchUpdaterDialog, LarchWxApp)
46from larch.wxxas.xas_dialogs import fit_dialog_window
47from larch.utils.strutils import bytes2str, version_ge
48from larch.utils import get_cwd
49from larch.io import nativepath
50from larch.site_config import icondir
51from larch.version import check_larchversion
53from ..xrd import lambda_from_E, xrd1d, save1D, calculate_xvalues, read_poni
54from ..xrmmap import GSEXRM_MapFile, GSEXRM_FileStatus, h5str, ensure_subgroup, DEFAULT_XRAY_ENERGY
55from ..apps import check_larchversion, update_larch
56from ..epics import pv_fullname
57from ..wxlib.xrfdisplay import XRFDisplayFrame
59from .mapimageframe import MapImageFrame, CorrelatedMapFrame
60from .mapmathpanel import MapMathPanel
61from .maptomopanel import TomographyPanel
62from .mapxrfpanel import XRFAnalysisPanel
64from ..wxxrd import XRD2DViewerFrame
65from ..wxxrd.xrd1d_display import XRD1DFrame
67def timestring():
68 return datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')
70FONTSIZE = 8
71if platform.system() in ('Windows', 'Darwin'):
72 FONTSIZE = 10
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
82FILE_WILDCARDS = 'X-ray Maps (*.h5)|*.h5|All files (*.*)|*.*'
84XRF_ICON_FILE = 'gse_xrfmap.ico'
86NOT_OWNER_MSG = """The File
87 '%s'
88appears to be open by another process. Having two
89processes writing to the file can cause corruption.
91Do you want to take ownership of the file?
92"""
94NOT_GSEXRM_FILE = """The File
95 '%s'
96doesn't seem to be a Map File
97"""
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"""
108FRAMESTYLE = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL
109BEAMLINE = '13-ID-E'
110FACILITY = 'APS'
112PLOT_TYPES = ('Single ROI Map', 'Three ROI Map', 'Correlation Plot')
113PROCROWS_CHOICES = ('All', '500', '200', '100', '50', '20', '10')
114PLOT_OPERS = ('/', '*', '-', '+')
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
123CWID = 150
124WWID = 100 + CWID*4
126class MapPanel(GridPanel):
127 '''Panel of Controls for viewing maps'''
128 label = 'ROI Map'
129 def __init__(self, parent, owner=None, **kws):
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)
137 self.plot_choice = Choice(self, choices=PLOT_TYPES, size=(CWID, -1))
138 self.plot_choice.Bind(wx.EVT_CHOICE, self.plotSELECT)
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))]
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))
152 for i,roi_chc in enumerate(self.roi_choice):
153 roi_chc.Bind(wx.EVT_CHOICE, partial(self.roiSELECT,i))
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,'')]
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)]
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()
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)
182 self.use_zigzag = Check(self, default=False, label='Fix ZigZag',
183 action=self.onZigZag)
185 self.limrange = Check(self, default=False,
186 label=' Limit Map Range to Pixel Range:',
187 action=self.onLimitRange)
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)
196 map_showxrf = Button(self, 'Show Full XRF', size=(CWID, -1),
197 action=self.onShowXRF)
199 self.mapproc_nrows = Choice(self, choices=PROCROWS_CHOICES, size=(CWID, -1))
200 self.mapproc_nrows.SetStringSelection('100')
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)
209 self.Add(HLine(self, size=(WWID, 5)), dcol=8, style=LEFT, newrow=True)
210 self.Add((5, 5), newrow=True)
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)
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)
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)
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)
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()
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()
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()
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
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()
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()
292 def detSELECT(self, idet, event=None):
293 self.set_roi_choices(idet=idet)
295 def roiSELECT(self,iroi,event=None):
297 detname = self.det_choice[iroi].GetStringSelection()
298 roiname = self.roi_choice[iroi].GetStringSelection()
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 = ''
318 self.roi_label[iroi].SetLabel(roistr)
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()
346 def onClose(self):
347 for p in self.plotframes:
348 try:
349 p.Destroy()
350 except:
351 pass
353 def ShowMap(self, xrmfile=None, new=True):
354 subtitles = None
355 plt3 = 'three' in self.plot_choice.GetStringSelection().lower()
357 if xrmfile is None:
358 xrmfile = self.owner.current_file
360 self.onZigZag()
362 args={'hotcols' : xrmfile.hotcols,
363 'dtcorrect' : xrmfile.dtcorrect}
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])]
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.
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)
384 x = xrmfile.get_pos(0, mean=True)
385 y = xrmfile.get_pos(1, mean=True)
387 pref, fname = os.path.split(xrmfile.filename)
389 if plt3:
390 map = np.array([r_map/mapx, g_map/mapx, b_map/mapx])
391 map = np.einsum('kij->ijk', map)
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])}
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
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)
419 if len(self.owner.im_displays) == 0 or new:
420 iframe = self.owner.add_imdisplay(title, det=det)
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)
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))
441 def ShowCorrel(self, xrmfile=None, new=True):
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 = []
451 xdet = self.det_choice[0].GetStringSelection()
452 xroi = self.roi_choice[0].GetStringSelection()
453 xlab = "%s(%s)" % (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()
459 ylab = "%s(%s)" % (yroi, ydet)
460 if 'scalar' in ydet.lower():
461 ylab = yroi
463 map1 = xrmfile.get_roimap(xroi, det=xdet, **args)
464 map2 = xrmfile.get_roimap(yroi, det=ydet, **args)
466 x = xrmfile.get_pos(0, mean=True)
467 y = xrmfile.get_pos(1, mean=True)
469 pref, fname = os.path.split(xrmfile.filename)
470 title ='%s: %s vs. %s' %(fname, ylab, xlab)
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)
479 def onProcessMap(self, event=None, max_new_rows=None):
480 xrmfile = self.owner.current_file
481 if xrmfile is None:
482 return
483 pref, fname = os.path.split(xrmfile.filename)
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)
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()
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()
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)
518 owner.show_XRFDisplay()
519 self._mca = owner.current_file.get_mca_rect(ymin, ymax, xmin, xmax, det=detname,
520 dtcorrect=owner.dtcor)
521 pref, fname = os.path.split(self.owner.current_file.filename)
522 self._mca.filename = fname
523 self._mca.title = "(%d x %d pixels)" % (mx, my)
524 self._mca.npixels = my*mx
525 self.owner.message("Plotting Full XRF Spectra (%d x %d) for '%s'" % (mx, my, fname))
527 self.owner.subframes['xrfdisplay'].add_mca(self._mca, label=fname, plot=True)
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()
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)
558 def update_roi(self, detname):
559 force = True # not self.detectors_set
560 return self.cfile.get_roi_list(detname, force=force)
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
570 sizer = wx.GridBagSizer(3, 3)
571 self.wids = {}
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'):
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))
589 sizer.Add(thislabel, (ir, 0), (1, 1), 1)
590 sizer.Add(self.wids[label], (ir, 1), (1, 1), 1)
592 pack(self, sizer)
593 self.SetupScrolling()
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
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',''))
609 self.wids['H5 Map Created'].SetLabel(time_str)
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',''))
618 self.wids['Scan Time'].SetLabel( time_str )
619 self.wids['File Compression'].SetLabel(bytes2str(xrmmap.attrs.get('Compression','')))
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)
625 pos_addrs = [str(x) for x in xrmmap['config/positioners'].keys()]
626 pos_label = [h5str(x[()]) for x in xrmmap['config/positioners'].values()]
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)
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'][()])
638 step1 = float(xrmmap['config/scan/step1'][()])
639 step2 = float(xrmmap['config/scan/step2'][()])
641 npts1 = int((abs(stop1 - start1) + 1.1*step1)/step1)
642 npts2 = int((abs(stop2 - start2) + 1.1*step2)/step2)
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)
648 rowtime = float(xrmmap['config/scan/time1'][()])
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)
658 env_names = list(xrmmap['config/environ/name'])
659 env_vals = list(xrmmap['config/environ/value'])
660 env_addrs = list(xrmmap['config/environ/address'])
662 fines = {'X': '?', 'Y': '?'}
663 i0vals = {'flux':'?', 'current':'?'}
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)
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
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
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))
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)
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 os.path.exists(xrd_calibration):
714 xrd_calibration = ''
715 self.wids['XRD Calibration'].SetLabel(os.path.split(xrd_calibration)[-1])
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']
736 for title,note in zip(note_title,note_str):
737 self.wids[title].SetLabel(note)
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 = ''
759 self.wids['Map Data'].SetLabel(datastr)
761 def onClose(self):
762 pass
765class MapAreaPanel(scrolled.ScrolledPanel):
767 label = 'Map Areas'
768 delstr = """ Delete Area '%s'?
770 WARNING: This cannot be undone!
772 """
774 def __init__(self, parent, owner=None, **kws):
775 scrolled.ScrolledPanel.__init__(self, parent, -1,
776 style=wx.GROW|wx.TAB_TRAVERSAL, **kws)
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))
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)
805 self.xrd1d_plot = Button(pane, 'Show 1D XRD', size=bsize,
806 action=partial(self.onXRD, show=True, xrd1d=True))
808 self.xrd2d_plot = Button(pane, 'Show 2D XRD', size=bsize,
809 action=partial(self.onXRD, show=True, xrd2d=True))
811 legend = wx.StaticText(pane, -1, 'Values in Counts per second', size=(200, -1))
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)
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)
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)
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)
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)
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)
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)
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)
862 for btn in (self.xrd1d_plot, self.xrd2d_plot):
863 btn.Disable()
865 # main sizer
866 msizer = wx.BoxSizer(wx.VERTICAL)
867 msizer.Add(pane, 0, wx.ALIGN_LEFT|wx.ALL, 1)
869 msizer.Add(wx.StaticLine(self, size=(375, 2), style=wx.LI_HORIZONTAL),
870 0, wx.EXPAND|wx.ALL, 1)
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
888 rep.SetMinSize((800, 300))
889 msizer.Add(rep, 1, wx.ALIGN_LEFT|wx.ALL, 1)
891 pack(self, msizer)
892 self.SetupScrolling()
894 def onCopy(self, event=None):
895 xrmfile = self.owner.current_file
896 xrmmap = xrmfile.xrmmap
897 print("Copy Area : shape", xrmfile, xrmmap.shape)
899 def show_stats(self):
900 # self.stats = self.xrmfile.get_area_stats(self.areaname)
901 if self.report is None:
902 return
904 self.report.DeleteAllItems()
905 self.report_data = []
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
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)
926 areaname = self._getarea()
927 xrmfile = self.owner.current_file
928 xrmmap = xrmfile.xrmmap
929 ctime = xrmfile.pixeltime
931 area = xrmfile.get_area(name=areaname)
932 amask = area[()]
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]
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
949 version = xrmmap.attrs.get('Version','1.0.0')
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])
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'
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]
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)
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)
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])
994 d = xrmmap['roimap/det_raw'][:,:,idet]
995 d = match_mask_shape(d, amask)
996 report_info(dname, d/ctime)
998 if 'roistats' not in area.attrs:
999 area.attrs['roistats'] = json.dumps(self.report_data)
1000 xrmfile.h5root.flush()
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
1014 def set_enabled_btns(self, xrmfile=None):
1015 if xrmfile is None:
1016 xrmfile = self.owner.current_file
1018 xrmfile.reset_flags()
1019 self.xrd2d_plot.Enable(xrmfile.has_xrd1d)
1020 self.xrd1d_plot.Enable(xrmfile.has_xrd1d)
1022 def clear_area_choices(self):
1024 self.info1.SetLabel('')
1025 self.info2.SetLabel('')
1026 self.desc.SetValue('')
1027 self.choice.Clear()
1029 def set_area_choices(self, xrmmap, show_last=False):
1031 self.clear_area_choices()
1033 areas = xrmmap['areas']
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)
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)
1058 def onReport(self, event=None):
1059 aname = self._getarea()
1060 path, fname = os.path.split(self.owner.current_file.filename)
1061 deffile = '%s_%s' % (fname, aname)
1062 deffile = deffile.replace('.', '_') + '.dat'
1063 outfile = FileSave(self, 'Save Area XRF Statistics File',
1064 default_file=deffile,
1065 wildcard=FILE_WILDCARDS)
1067 if outfile is None:
1068 return
1070 area = self.owner.current_file.xrmmap['areas/%s' % aname]
1071 npix = area[()].sum()
1072 pixtime = self.owner.current_file.pixeltime
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)
1095 def _getarea(self):
1096 return self.choices[self.choice.GetStringSelection()]
1098 def onExport(self, event=None):
1099 ofile = self.owner.current_file.export_areas()
1100 self.owner.message('Exported Areas to %s' % ofile)
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)
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()
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()))
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()
1137 def onShowStats(self, event=None):
1138 if self.report is None:
1139 return
1140 self.show_stats()
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)
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))
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
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))
1169 highlight[np.where(area[()])] = 1
1170 imd.panel.add_highlight_area(highlight, label=label)
1172 def onDone(self, event=None):
1173 self.Destroy()
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))
1180 if erase:
1181 xrmmap = self.owner.current_file.xrmmap
1182 del xrmmap['areas/%s' % aname]
1184 self.set_area_choices(xrmmap)
1186 self.onSelect()
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
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
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]
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()
1224 pref, fname = os.path.split(self.owner.current_file.filename)
1226 npix = area[()].sum()
1227 self._mca.filename = fname
1228 self._mca.title = label
1229 self._mca.npixels = npix
1230 self.owner.message("Plotting XRF Spectra for area '%s'..." % aname)
1231 self.owner.subframes['xrfdisplay'].add_mca(self._mca, label="%s:%s" % (fname, label),
1232 plot=not as_mca2)
1233 if as_mca2:
1234 self.owner.subframes['xrfdisplay'].swap_mcas()
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]
1243 title = area.attrs.get('description', aname)
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
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
1261 ponifile = bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('calfile',''))
1262 ponifile = ponifile if os.path.exists(ponifile) else None
1264 if show:
1265 self.owner.message('Plotting XRD pattern for \'%s\'...' % title)
1266 if save:
1267 self.owner.message('Saving XRD pattern for \'%s\'...' % title)
1268 path,stem = os.path.split(self.owner.current_file.filename)
1269 stem = '%s_%s' % (stem,title)
1271 kwargs = dict(filename=self.owner.current_file.filename,
1272 npixels=area[()].sum(),
1273 energy=0.001*xrmfile.get_incident_energy(),
1274 calfile=ponifile, title=title, xrd2d=False)
1276 if xrd1d and xrmfile.has_xrd1d:
1277 self._xrd = xrmfile.get_xrd1d_area(aname, **kwargs)
1279 if show:
1280 label = '%s: %s' % (os.path.split(self._xrd.filename)[-1], 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('\\', '/')
1293 dlg.Destroy()
1295 print('\nSaving 1D XRD in file: %s' % (filename))
1296 save1D(filename, self._xrd.data1D[0], self._xrd.data1D[1], calfile=ponifile)
1298 ## turns off flag since it has already been displayed/saved
1299 xrd1d = False
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
1312 label = '%s: %s' % (os.path.split(_xrd.filename)[-1], title)
1313 self.owner.display_2Dxrd(_xrd.data2D, label=label, xrmfile=xrmfile)
1314 wildcards = '2D XRD file (*.tiff)|*.tif;*.tiff;*.edf|All files (*.*)|*.*'
1315 fname = xrmfile.filename + '_' + aname
1316 dlg = wx.FileDialog(self, 'Save file as...',
1317 defaultDir=get_cwd(),
1318 defaultFile='%s.tiff' % fname,
1319 wildcard=wildcards,
1320 style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1321 if dlg.ShowModal() == wx.ID_OK:
1322 filename = os.path.abspath(dlg.GetPath().replace('\\', '/'))
1323 _xrd.save_2D(file=filename, verbose=True)
1324 dlg.Destroy()
1327class MapViewerFrame(wx.Frame):
1328 cursor_menulabels = {'lasso': ('Select Points for XRF Spectra\tCtrl+X',
1329 'Left-Drag to select points for XRF Spectra')}
1331 def __init__(self, parent=None, filename=None, _larch=None,
1332 use_scandb=False, check_version=True,
1333 size=(925, 650), **kwds):
1335 if check_version:
1336 def check_version():
1337 self.vinfo = check_larchversion()
1338 version_thread = Thread(target=check_version)
1339 version_thread.start()
1341 kwds['style'] = wx.DEFAULT_FRAME_STYLE
1342 wx.Frame.__init__(self, parent, -1, size=size, **kwds)
1344 self.data = None
1345 self.use_scandb = use_scandb
1346 self.filemap = {}
1347 self.im_displays = []
1348 self.tomo_displays = []
1349 self.plot_displays = []
1350 self.current_file = None
1352 self.larch_buffer = parent
1353 if not isinstance(parent, LarchFrame):
1354 self.larch_buffer = LarchFrame(_larch=_larch, is_standalone=False, with_raise=False)
1356 self.larch = self.larch_buffer.larchshell
1358 self.subframes = {'xrfdisplay': None,
1359 'xrd1d': None,
1360 'xrd2d': None}
1361 self.watch_files = False
1363 self.files_in_progress = []
1365 # self.hotcols = False
1366 self.dtcor = True
1367 self.showxrd = False
1369 self.SetTitle('GSE XRM MapViewer')
1371 self.createMainPanel()
1372 self.SetFont(Font(FONTSIZE))
1374 self.createMenus()
1375 self.statusbar = self.CreateStatusBar(2, 0)
1376 self.statusbar.SetStatusWidths([-3, -1])
1377 statusbar_fields = ['Initializing....', ' ']
1378 for i in range(len(statusbar_fields)):
1379 self.statusbar.SetStatusText(statusbar_fields[i], i)
1381 self.htimer = wx.Timer(self)
1382 self.Bind(wx.EVT_TIMER, self.onTimer, self.htimer)
1383 self.h5convert_done = True
1384 self.h5convert_irow = 0
1385 self.h5convert_nrow = 0
1387 read_workdir('gsemap.dat')
1389 w0, h0 = self.GetSize()
1390 w1, h1 = self.GetBestSize()
1391 self.SetSize((max(w0, w1)+5, max(h0, h1)+5))
1392 self.SetMinSize((500, 300))
1393 self.Show()
1395 self.scandb = None
1396 self.instdb = None
1397 self.inst_name = None
1398 self.move_callback = None
1400 if filename is not None:
1401 wx.CallAfter(self.onRead, filename)
1403 if check_version:
1404 version_thread.join()
1405 if self.vinfo is not None:
1406 if self.vinfo.update_available:
1407 self.onCheckforUpdates()
1408 self.statusbar.SetStatusText(f'Larch Version {self.vinfo.remote_version} is available!', 0)
1409 self.statusbar.SetStatusText(f'Larch Version {self.vinfo.local_version}', 1)
1410 else:
1411 self.statusbar.SetStatusText(f'Larch Version {self.vinfo.local_version} (latest)', 1)
1414 def CloseFile(self, filename, event=None):
1415 if filename in self.filemap:
1416 self.filemap[filename].close()
1417 self.filemap.pop(filename)
1419 def createMainPanel(self):
1420 splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
1421 splitter.SetMinimumPaneSize(250)
1423 self.filelist = EditableListBox(splitter, self.ShowFile,
1424 remove_action=self.CloseFile,
1425 size=(250, -1))
1427 dpanel = self.detailspanel = wx.Panel(splitter)
1428 self.createNBPanels(dpanel)
1429 splitter.SplitVertically(self.filelist, self.detailspanel, 1)
1430 sizer = wx.BoxSizer(wx.VERTICAL)
1431 sizer.Add(splitter, 1, wx.GROW|wx.ALL, 5)
1432 pack(self, sizer)
1433 fico = os.path.join(icondir, XRF_ICON_FILE)
1434 try:
1435 self.SetIcon(wx.Icon(fico, wx.BITMAP_TYPE_ICO))
1436 except:
1437 pass
1440 self.Raise()
1441 wx.CallAfter(self.init_larch)
1443 def createNBPanels(self, parent):
1444 self.title = SimpleText(parent, 'initializing...', size=(680, -1))
1446 self.SetBackgroundColour('#F0F0E8')
1448 nbpanels = {}
1449 for panel in (MapPanel, MapInfoPanel, MapAreaPanel, MapMathPanel,
1450 TomographyPanel, XRFAnalysisPanel):
1451 nbpanels[panel.label] = panel
1452 self.nb = flatnotebook(parent, nbpanels, panelkws={'owner':self},
1453 on_change=self.onNBChanged)
1454 self.roimap_panel = self.nb.GetPage(0)
1455 sizer = wx.BoxSizer(wx.VERTICAL)
1456 sizer.Add(self.title, 0, ALL_CEN)
1457 sizer.Add(self.nb, 1, wx.ALL|wx.EXPAND)
1458 parent.SetSize((700, 400))
1459 pack(parent, sizer)
1461 def onNBChanged(self, event=None):
1462 cb = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None)
1463 if callable(cb):
1464 cb()
1466 def get_mca_area(self, mask, xoff=0, yoff=0, det=None, xrmfile=None):
1467 if xrmfile is None:
1468 xrmfile = self.current_file
1470 if xrmfile.write_access:
1471 aname = xrmfile.add_area(mask)
1472 self.sel_mca = xrmfile.get_mca_area(aname, det=det)
1473 else:
1474 dgroup = xrmfile.get_detname(det)
1475 _ay, _ax = np.where(mask)
1476 ymin, ymax, xmin, xmax = _ay.min(), _ay.max()+1, _ax.min(), _ax.max()+1
1477 opts = {'dtcorrect': None, 'det': det}
1478 counts = xrmfile.get_counts_rect(ymin, ymax, xmin, xmax, det=det)
1479 ltime, rtime = xrmfile.get_livereal_rect(ymin, ymax, xmin,
1480 xmax, det=det)
1481 ltime = ltime[mask[ymin:ymax, xmin:xmax]].sum()
1482 rtime = rtime[mask[ymin:ymax, xmin:xmax]].sum()
1483 counts = counts[mask[ymin:ymax, xmin:xmax]]
1484 while(len(counts.shape) > 1):
1485 counts = counts.sum(axis=0)
1486 self.sel_mca = xrmfile._getmca(dgroup, counts, 'selected area',
1487 npixels=mask.sum(),
1488 real_time=rtime, live_time=ltime)
1491 def lassoHandler(self, mask=None, xrmfile=None, xoff=0, yoff=0,
1492 det=None, **kws):
1493 if xrmfile is None:
1494 xrmfile = self.current_file
1496 ny, nx = xrmfile.get_shape()
1497 if mask.sum() < 1:
1498 return
1500 if (xoff>0 or yoff>0) or mask.shape != (ny, nx):
1501 if mask.shape == (nx, ny): ## sinogram
1502 mask = np.swapaxes(mask,0,1)
1503 # elif mask.shape == (ny, ny) or mask.shape == (nx, nx): ## tomograph
1504 # tomo = True
1505 else:
1506 ym, xm = mask.shape
1507 tmask = np.zeros((ny, nx)).astype(bool)
1508 xmax = min(nx, xm+xoff)
1509 for iy in range(ym):
1510 if iy+yoff < ny:
1511 tmask[iy+yoff, xoff:xmax] = mask[iy]
1512 mask = tmask
1514 kwargs = dict(xrmfile=xrmfile, xoff=xoff, yoff=yoff, det=det)
1515 mca_thread = Thread(target=self.get_mca_area,
1516 args=(mask,), kwargs=kwargs)
1517 mca_thread.start()
1518 self.show_XRFDisplay()
1519 mca_thread.join()
1520 if hasattr(self, 'sel_mca'):
1521 path, fname = os.path.split(xrmfile.filename)
1522 aname = self.sel_mca.areaname
1523 if self.sel_mca.npixels is None:
1524 try:
1525 area = xrmfile.xrmmap['areas/%s' % aname]
1526 npix = area[()].sum()
1527 self.sel_mca.npixels = npix
1528 except:
1529 pass
1531 if self.sel_mca.npixels is None:
1532 self.sel_mca.npixels = 0
1533 self.sel_mca.filename = fname
1534 self.sel_mca.title = aname
1535 self.subframes['xrfdisplay'].add_mca(self.sel_mca, label='%s:%s'% (fname, aname),
1536 plot=True)
1537 self.subframes['xrfdisplay'].roi_callback = self.UpdateROI
1538 update_xrmmap = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None)
1539 if callable(update_xrmmap):
1540 update_xrmmap(xrmfile=self.current_file)
1542 if self.showxrd:
1543 for page in self.nb.pagelist:
1544 if hasattr(page, 'onXRD'):
1545 page.onXRD(show=True, xrd1d=True,verbose=False)
1547 def show_subframe(self, name, frameclass, **opts):
1548 shown = False
1549 if name in self.subframes:
1550 try:
1551 self.subframes[name].Raise()
1552 shown = True
1553 except:
1554 del self.subframes[name]
1555 if not shown:
1556 self.subframes[name] = frameclass(self, **opts)
1558 def show_XRD1D(self, event=None):
1559 self.show_subframe('xrd1d', XRD1DFrame, _larch=self.larch)
1561 def show_XRD2D(self, event=None):
1562 self.show_subframe('xrd2d', XRD1DFrame, _larch=self.larch)
1565 def show_XRFDisplay(self, do_raise=True, clear=True, xrmfile=None):
1566 'make sure XRF plot frame is enabled and visible'
1567 if xrmfile is None:
1568 xrmfile = self.current_file
1569 self.show_subframe('xrfdisplay', XRFDisplayFrame,
1570 parent=self.larch_buffer,
1571 roi_callback=self.UpdateROI)
1573 self.subframes['xrfdisplay'].Show()
1574 if do_raise:
1575 self.subframes['xrfdisplay'].Raise()
1576 if clear:
1577 self.subframes['xrfdisplay'].panel.clear()
1578 self.subframes['xrfdisplay'].panel.reset_config()
1580 def onMoveToPixel(self, xval, yval):
1581 if not HAS_EPICS:
1582 return
1584 xrmmap = self.current_file.xrmmap
1585 pos_addrs = [str(x) for x in xrmmap['config/positioners'].keys()]
1586 pos_label = [str(x[()]) for x in xrmmap['config/positioners'].values()]
1588 pos1 = h5str(xrmmap['config/scan/pos1'][()])
1589 pos2 = h5str(xrmmap['config/scan/pos2'][()])
1590 i1 = pos_addrs.index(pos1)
1591 i2 = pos_addrs.index(pos2)
1592 msg = '%s(%s) = %.4f, %s(%s) = %.4f?' % (pos_label[i1], pos_addrs[i1], xval,
1593 pos_label[i2], pos_addrs[i2], yval)
1595 if (wx.ID_YES == Popup(self, 'Really move stages to\n %s?' % msg,
1596 'move stages to pixel?', style=wx.YES_NO)):
1597 caput(pos_addrs[i1], xval)
1598 caput(pos_addrs[i2], yval)
1600 def onSavePixel(self, name, ix, iy, x=None, y=None, title=None, xrmfile=None):
1601 'save pixel as area, and perhaps to scandb'
1602 if x is None:
1603 x = float(xrmfile.get_pos(0, mean=True)[ix])
1604 if y is None:
1605 y = float(xrmfile.get_pos(1, mean=True)[iy])
1607 if len(name) < 1:
1608 return
1609 if xrmfile is None:
1610 xrmfile = self.current_file
1612 # first, create 1-pixel mask for area, and save that
1613 ny, nx = xrmfile.get_shape()
1614 tmask = np.zeros((ny, nx)).astype(bool)
1615 tmask[int(iy), int(ix)] = True
1616 xrmfile.add_area(tmask, name=name)
1617 # for page in self.nb.pagelist:
1618 # if hasattr(page, 'update_xrmmap'):
1619 # page.update_xrmmap(xrmfile=xrmfile)
1620 update_xrmmap = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None)
1621 if callable(update_xrmmap):
1622 update_xrmmap(xrmfile=xrmfile)
1624 # show position on map
1625 self.im_displays[-1].panel.add_highlight_area(tmask, label=name)
1627 # make sure we can save position into database
1628 if self.scandb is None or self.instdb is None:
1629 return
1630 samplestage = self.instdb.get_instrument(self.inst_name)
1631 if samplestage is None:
1632 return
1633 pvmap = dict([(r.id, r.name) for r in self.scandb.get_rows('pv')])
1635 pv_rows = self.scandb.get_rows('instrument_pv',
1636 where={'instrument_id': samplestage.id})
1638 allpvs = []
1639 for row in pv_rows:
1640 for pvid, pvname in pvmap.items():
1641 if pvid == row.pv_id:
1642 allpvs.append(pvname)
1644 pvn = pv_fullname
1645 conf = xrmfile.xrmmap['config']
1646 pos_addrs = [pvn(h5str(tval)) for tval in conf['positioners']]
1647 env_addrs = [pvn(h5str(tval)) for tval in conf['environ/address']]
1648 env_vals = [h5str(tval) for tval in conf['environ/value']]
1650 position = {}
1651 for pv in allpvs:
1652 position[pv] = None
1654 for addr, val in zip(env_addrs, env_vals):
1655 if addr in allpvs:
1656 position[addr] = float(val)
1658 position[pvn(h5str(conf['scan/pos1'][()]))] = x
1659 position[pvn(h5str(conf['scan/pos2'][()]))] = y
1661 notes = {'source': '%s: %s' % (xrmfile.filename, name)}
1662 self.instdb.save_position(self.inst_name, name, position,
1663 notes=json.dumps(notes))
1666 def add_tomodisplay(self, title, det=None, _lassocallback=True):
1668 if _lassocallback:
1669 lasso_cb = partial(self.lassoHandler, det=det)
1670 else:
1671 lasso_cb = None
1673 imframe = MapImageFrame(output_title=title,
1674 lasso_callback=lasso_cb)
1676 self.tomo_displays.append(imframe)
1678 def display_tomo(self, tomo, title='', info='', x=None, y=None, xoff=0,
1679 yoff=0, det=None, subtitles=None, xrmfile=None,
1680 _lassocallback=True):
1682 displayed = False
1683 if _lassocallback:
1684 lasso_cb = partial(self.lassoHandler, det=det, xrmfile=xrmfile)
1685 else:
1686 lasso_cb = None
1688 while not displayed:
1689 try:
1690 tmd = self.tomo_displays.pop()
1691 clevel = tmd.panel.conf.contrast_level
1692 if clevel in (0, None):
1693 clevel = 0.5
1694 tmd.display(tomo, title=title, subtitles=subtitles,
1695 contrast_level=clevel)
1696 tmd.lasso_callback = lasso_cb
1697 displayed = True
1698 except IndexError:
1699 tmd = MapImageFrame(output_title=title,
1700 lasso_callback=lasso_cb)
1701 tmd.display(tomo, title=title, subtitles=subtitles,
1702 contrast_level=0.5)
1703 displayed = True
1704 except:
1705 displayed = False
1706 self.tomo_displays.append(tmd)
1707 tmd.SetStatusText(info, 1)
1708 tmd.Show()
1709 tmd.Raise()
1711 def add_imdisplay(self, title, det=None):
1712 imd = MapImageFrame(output_title=title,
1713 lasso_callback=partial(self.lassoHandler, det=det),
1714 cursor_labels=self.cursor_menulabels,
1715 save_callback=self.onSavePixel)
1716 self.im_displays.append(imd)
1717 return imd
1719 def display_map(self, map, title='', info='', x=None, y=None, xoff=0, yoff=0,
1720 det=None, subtitles=None, xrmfile=None, with_savepos=True):
1721 """display a map in an available image display"""
1722 if xrmfile is None:
1723 hotcols = False
1724 else:
1725 hotcols = xrmfile.hotcols
1727 if x is not None:
1728 zigzag = abs(xrmfile.zigzag)
1729 if zigzag != 0:
1730 x = x[zigzag:-zigzag]
1731 elif hotcols and map.shape[1] != x.shape[0]:
1732 x = x[1:-1]
1734 dopts = dict(title=title, x=x, y=y, xoff=xoff, yoff=yoff,
1735 det=det, subtitles=subtitles,
1736 xrmfile=xrmfile, with_savepos=with_savepos)
1737 displayed = False
1738 while not displayed:
1739 if 'contrast_level' not in dopts:
1740 dopts['contrast_level'] = 0.5
1741 if len(self.im_displays) == 0:
1742 imd = self.add_imdisplay(title=title, det=det)
1743 imd.display(map, **dopts)
1744 else:
1745 try:
1746 imd = self.im_displays[-1]
1747 if imd.panel.conf.contrast_level not in (0, None):
1748 dopts['contrast_level'] = imd.panel.conf.contrast_level
1749 imd.display(map, **dopts)
1750 displayed = True
1751 except IndexError:
1752 pass
1753 except:
1754 self.im_displays.pop()
1755 imd.SetStatusText(info, 1)
1756 imd.Show()
1757 imd.Raise()
1759 def display_2Dxrd(self, map, label='image 0', xrmfile=None, flip=True):
1760 '''
1761 displays 2D XRD pattern in diFFit viewer
1762 '''
1763 xrmfile = self.current_file
1764 ponifile = bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('calfile',''))
1765 if len(ponifile) < 2 or not os.path.exists(ponifile):
1766 t_ponifile = os.path.join(xrmfile.folder, 'XRD.poni')
1767 if os.path.exists(t_ponifile):
1768 ponifile = t_ponifile
1769 if os.path.exists(ponifile):
1770 self.current_file.xrmmap['xrd1d'].attrs['calfile'] = ponifile
1772 self.show_XRD2D()
1773 self.show_XRD1D()
1774 self.subframes['xrd2d'].flip = 'vertical' if flip is True else False
1775 self.subframes['xrd2d'].calfile = ponifile
1776 self.subframes['xrd2d'].plot2Dxrd(label, map)
1777 self.subframes['xrd2d'].Show()
1779 def display_xrd1d(self, counts, q, energy, label='dataset 0', xrmfile=None):
1780 '''
1781 displays 1D XRD pattern in diFFit viewer
1782 '''
1783 wavelength = lambda_from_E(energy, E_units='keV')
1784 xdat = xrd1d(label=label, energy=energy, wavelength=wavelength)
1785 xdat.set_xy_data(np.array([q, counts]), 'q')
1787 xrmfile = self.current_file
1788 ponidata = json.loads(bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('caldata','{}')))
1789 if 'rot1' not in ponidata: # invalid poni data
1790 ponifile = bytes2str(xrmfile.xrmmap['xrd1d'].attrs.get('calfile',''))
1791 if len(ponifile) < 2 or not os.path.exists(ponifile):
1792 t_ponifile = os.path.join(xrmfile.folder, 'XRD.poni')
1793 if os.path.exists(t_ponifile):
1794 ponifile = t_ponifile
1795 if len(ponifile) > 1:
1796 ponidata = read_poni(ponifile)
1797 if 'rot1' in ponidata:
1798 xrmfile.xrmmap['xrd1d'].attrs['caldata'] = json.dumps(ponidata)
1799 self.show_XRD1D()
1800 self.subframes['xrd1d'].set_wavelength(wavelength)
1801 if 'rot1' in ponidata:
1802 self.subframes['xrd1d'].set_poni(ponidata)
1804 self.subframes['xrd1d'].add_data(xdat, label=label)
1805 self.subframes['xrd1d'].Show()
1807 def init_larch(self):
1808 self.SetStatusText('ready')
1809 self.datagroups = self.larch.symtable
1810 if ESCAN_CRED is not None:
1811 self.move_callback = self.onMoveToPixel
1812 try:
1813 self.scandb = connect_scandb(_larch=self.larch)
1814 self.instdb = self.larch.symtable._scan._instdb
1815 self.inst_name = self.scandb.get_info('samplestage_instrument',
1816 default='SampleStage')
1817 print(" ScanDB: %s, Instrument=%s" % (self.scandb.engine, self.inst_name))
1818 except:
1819 etype, emsg, tb = sys.exc_info()
1820 print('Could not connect to ScanDB: %s' % (emsg))
1821 self.scandb = self.instdb = None
1822 wx.CallAfter(self.onFolderSelect)
1824 def ShowFile(self, evt=None, filename=None, process_file=True, **kws):
1825 if filename is None and evt is not None:
1826 filename = evt.GetString()
1827 if not self.h5convert_done or filename not in self.filemap:
1828 return
1829 self.current_file = self.filemap[filename]
1830 if (self.check_ownership(filename) and
1831 self.current_file.folder_has_newdata()):
1832 if process_file:
1833 mnew = self.roimap_panel.mapproc_nrows.GetStringSelection()
1834 try:
1835 mnew = int(mnew)
1836 except:
1837 mnew = None
1838 self.process_file(filename, max_new_rows=mnew)
1840 ny, nx = self.current_file.get_shape()
1841 self.title.SetLabel('%s: (%i x %i)' % (filename, nx, ny))
1843 fnames = self.filelist.GetItems()
1845 cb = getattr(self.nb.GetCurrentPage(), 'update_xrmmap', None)
1846 if callable(cb):
1847 cb(xrmfile=self.current_file)
1848 cb = getattr(self.nb.GetCurrentPage(), 'set_file_choices', None)
1849 if callable(cb):
1850 cb(fnames)
1852 def createMenus(self):
1853 self.menubar = wx.MenuBar()
1854 fmenu = wx.Menu()
1856 MenuItem(self, fmenu, '&Open XRM Map File\tCtrl+O', 'Read XRM Map File', self.onReadFile)
1857 MenuItem(self, fmenu, '&Open XRM Map Folder\tCtrl+F', 'Read XRM Map Folder', self.onReadFolder)
1858 fmenu.AppendSeparator()
1859 MenuItem(self, fmenu, 'Change &Working Folder', 'Choose working directory',
1860 self.onFolderSelect)
1861 MenuItem(self, fmenu, 'Show Larch Buffer\tCtrl+L', 'Show Larch Programming Buffer',
1862 self.onShowLarchBuffer)
1864 # cmenu = fmenu.Append(-1, '&Watch HDF5 Files\tCtrl+W', 'Watch HDF5 Files', kind=wx.ITEM_CHECK)
1865 # fmenu.Check(cmenu.Id, self.watch_files) ## False
1866 # self.Bind(wx.EVT_MENU, self.onWatchFiles, id=cmenu.Id)
1868 fmenu.AppendSeparator()
1869 MenuItem(self, fmenu, '&Quit\tCtrl+Q',
1870 'Quit program', self.onClose)
1872 rmenu = wx.Menu()
1873 MenuItem(self, rmenu, 'Add / Delete ROIs',
1874 'Define new ROIs, Remove ROIs', self.manageROIs)
1875 MenuItem(self, rmenu, 'Load ROI File for 1DXRD',
1876 'Load ROI File for 1DXRD', self.add1DXRDFile)
1877 rmenu.AppendSeparator()
1878 MenuItem(self, rmenu, 'Load XRD calibration file',
1879 'Load XRD calibration file', self.openPONI)
1880 MenuItem(self, rmenu, 'Add 1DXRD for HDF5 file',
1881 'Calculate 1DXRD for HDF5 file', self.add1DXRD)
1884 # cmenu = fmenu.Append(-1, 'Display 1DXRD for areas',
1885 # 'Display 1DXRD for areas',
1886 # kind=wx.ITEM_CHECK)
1887 #fmenu.Check(cmenu.Id, self.showxrd) ## False
1888 #self.Bind(wx.EVT_MENU, self.onShow1DXRD, id=cmenu.Id)
1890 hmenu = wx.Menu()
1891 MenuItem(self, hmenu, 'About GSE XRM MapViewer', 'About GSE XRM MapViewer',
1892 self.onAbout)
1893 MenuItem(self, hmenu, 'Check for Updates', 'Check for Updates',
1894 self.onCheckforUpdates)
1896 self.menubar.Append(fmenu, '&File')
1897 self.menubar.Append(rmenu, '&ROIs')
1898 self.menubar.Append(hmenu, '&Help')
1899 self.SetMenuBar(self.menubar)
1900 self.Bind(wx.EVT_CLOSE, self.onClose)
1902 def onShowLarchBuffer(self, evt=None):
1903 if self.larch_buffer is None:
1904 self.larch_buffer = LarchFrame(_larch=self.larch, is_standalone=False)
1906 self.larch_buffer.Show()
1907 self.larch_buffer.Raise()
1909 def onFolderSelect(self, evt=None):
1910 dlg = wx.DirDialog(self, 'Select Working Directory:',
1911 get_cwd(),
1912 style=wx.DD_DIR_MUST_EXIST|wx.DD_DEFAULT_STYLE)
1914 if dlg.ShowModal() == wx.ID_OK:
1915 basedir = os.path.abspath(str(dlg.GetPath()))
1916 try:
1917 if len(basedir) > 0:
1918 os.chdir(nativepath(basedir))
1919 save_workdir(nativepath(basedir))
1920 except OSError:
1921 print( 'Changed folder failed')
1922 pass
1923 save_workdir('gsemap.dat')
1924 dlg.Destroy()
1926 def onAbout(self, event=None):
1927 info = AboutDialogInfo()
1928 info.SetName('GSE XRM MapViewer')
1929 info.SetDescription('X-ray Microprobe Mapping Data Visualization and Analysis')
1930 info.SetVersion(larch.version.__version__)
1931 info.AddDeveloper('Matthew Newville: newville at cars.uchicago.edu')
1932 dlg = AboutBox(info)
1934 def onCheckforUpdates(self, event=None):
1935 dlg = LarchUpdaterDialog(self, caller='GSE MapViewer')
1936 dlg.Raise()
1937 dlg.SetWindowStyle(wx.STAY_ON_TOP)
1938 res = dlg.GetResponse()
1939 dlg.Destroy()
1940 if res.ok and res.run_updates:
1941 from larch.apps import update_larch
1942 update_larch()
1943 self.onClose(evt=event, prompt=False)
1945 def onClose(self, evt=None, prompt=True):
1946 if prompt:
1947 dlg = wx.MessageDialog(None, 'Really Quit?', 'Question',
1948 wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
1950 ret = dlg.ShowModal()
1951 if ret != wx.ID_YES:
1952 return
1954 save_workdir('gsemap.dat')
1955 try:
1956 self.htimer.Stop()
1957 except:
1958 pass
1959 try:
1960 self.file_timer.Stop()
1961 except:
1962 pass
1965 for xrmfile in self.filemap.values():
1966 try:
1967 xrmfile.close()
1968 except KeyError:
1969 pass
1971 try:
1972 self.larch.symtable._plotter.close_all_displays()
1973 except:
1974 pass
1976 ## Closes maps, 2D XRD image
1977 for disp in self.im_displays + self.plot_displays + self.tomo_displays:
1978 try:
1979 disp.Destroy()
1980 except:
1981 pass
1983 for key, wid in self.subframes.items():
1984 if wid is not None:
1985 try:
1986 wid.onClose()
1987 except:
1988 pass
1989 if self.larch_buffer is not None:
1990 self.larch_buffer.exit_on_close = True
1991 self.larch_buffer.onExit(force=True, with_sysexit=False)
1992 self.Destroy()
1994 def onReadFile(self, evt=None):
1995 if not self.h5convert_done:
1996 print('cannot open file while processing a map folder')
1997 return
1999 dlg = wx.FileDialog(self, message='Read XRM Map File',
2000 defaultDir=get_cwd(),
2001 wildcard=FILE_WILDCARDS,
2002 style=wx.FD_OPEN|wx.FD_MULTIPLE)
2003 path, read = None, False
2004 if dlg.ShowModal() == wx.ID_OK:
2005 read = True
2006 paths = [p.replace('\\', '/') for p in dlg.GetPaths()]
2007 dlg.Destroy()
2009 if not read:
2010 return
2012 for path in paths:
2013 parent, fname = os.path.split(path)
2014 read = True
2015 if fname in self.filemap:
2016 read = (wx.ID_YES == Popup(self, "Re-read file '%s'?" % path,
2017 'Re-read file?', style=wx.YES_NO))
2018 if read:
2019 xrmfile = GSEXRM_MapFile(filename=str(path), scandb=self.scandb)
2020 self.add_xrmfile(xrmfile)
2022 def onRead(self, path):
2023 "simple Read and install XRM Map File"
2024 xrmfile = GSEXRM_MapFile(filename=str(path), scandb=self.scandb)
2025 self.add_xrmfile(xrmfile)
2027 def onReadFolder(self, evt=None):
2028 if not self.h5convert_done:
2029 print( 'cannot open file while processing a map folder')
2030 return
2032 dlg = wx.DirDialog(self, message='Read XRM Map Folder',
2033 defaultPath=get_cwd(),
2034 style=wx.DD_DIR_MUST_EXIST|wx.DD_DEFAULT_STYLE)
2036 if dlg.ShowModal() == wx.ID_OK:
2037 folder = os.path.abspath(dlg.GetPath())
2038 dlg.Destroy()
2040 xrmfile = GSEXRM_MapFile(folder=folder, scandb=self.scandb)
2041 self.add_xrmfile(xrmfile)
2044 def add_xrmfile(self, xrmfile):
2045 parent, fname = os.path.split(xrmfile.filename)
2046 # print("Add XRM File ", fname)
2047 # look for group with this name or for next available group
2048 for i in range(1000):
2049 gname = 'map%3.3i' % (i+1)
2050 xgroup = getattr(self.datagroups, gname, None)
2051 if xgroup is None:
2052 break
2053 gpar, gfname = os.path.split(xgroup.filename)
2054 if gfname == fname:
2055 break
2057 setattr(self.datagroups, gname, xrmfile)
2058 xrmfile.groupname = gname
2060 if fname not in self.filemap:
2061 self.filemap[fname] = xrmfile
2062 if fname not in self.filelist.GetItems():
2063 self.filelist.Append(fname)
2064 self.filelist.SetStringSelection(fname)
2066 if self.check_ownership(fname):
2067 mnew = self.roimap_panel.mapproc_nrows.GetStringSelection()
2068 try:
2069 mnew = int(mnew)
2070 except:
2071 mnew = None
2072 self.process_file(fname, max_new_rows=mnew)
2074 self.ShowFile(filename=fname)
2075 if parent is not None and len(parent) > 0:
2076 try:
2077 os.chdir(nativepath(parent))
2078 save_workdir(nativepath(parent))
2079 except:
2080 pass
2082 def openPONI(self, evt=None):
2083 """
2084 Read specified poni file.
2085 mkak 2016.07.21
2086 """
2088 if len(self.filemap) > 0:
2089 myDlg = OpenPoniFile()
2090 read = False
2091 if myDlg.ShowModal() == wx.ID_OK:
2092 read = True
2093 path = myDlg.XRDInfo[1].GetValue()
2094 flip = False if myDlg.XRDInfo[0].GetSelection() == 1 else True
2095 myDlg.Destroy()
2097 if read:
2098 self.current_file.add_XRDfiles(xrdcalfile=path,flip=flip)
2099 update_xrmmap = getattr(self.nb.GetCurrentPage(),
2100 'update_xrmmap', None)
2101 if callable(update_xrmmap):
2102 update_xrmmap(xrmfile=self.current_file)
2104 def UpdateROI(self, name, xrange=None, action='add', units='keV', roitype='XRF'):
2105 "add or remove an ROI with name, range"
2106 cfile = self.current_file
2107 if xrange is None: xrange = [1, 2]
2108 if roitype == 'XRF':
2109 if action.startswith('del'):
2110 cfile.del_xrfroi(name)
2111 else:
2112 cfile.add_xrfroi(name, xrange, unit=units)
2114 if roitype == '1DXRD':
2115 if action.startswith('del'):
2116 cfile.del_xrd1droi(name)
2117 else:
2118 cfile.add_xrd1droi(name, xrange, unit=units)
2120 self.current_file.get_roi_list('mcasum', force=True)
2121 for page in self.nb.pagelist:
2122 if hasattr(page, 'update_xrmmap'):
2123 page.update_xrmmap(xrmfile=self.current_file)
2124 if hasattr(page, 'set_roi_choices'):
2125 page.set_roi_choices()
2127 def manageROIs(self, event=None):
2128 if not self.h5convert_done:
2129 print( 'cannot open file while processing a map folder')
2130 elif len(self.filemap) > 0:
2131 ROIDialog(self, roi_callback=self.UpdateROI).Show()
2133 def add1DXRDFile(self, event=None):
2134 if len(self.filemap) > 0:
2135 read = False
2136 wildcards = '1D-XRD ROI file (*.dat)|*.dat|All files (*.*)|*.*'
2137 dlg = wx.FileDialog(self, message='Select 1D-XRD ROI file',
2138 defaultDir=get_cwd(),
2139 wildcard=wildcards,
2140 style=wx.FD_OPEN)
2142 if dlg.ShowModal() == wx.ID_OK:
2143 read = True
2144 path = dlg.GetPath().replace('\\', '/')
2145 dlg.Destroy()
2147 if read and os.path.exists(path):
2148 time.sleep(1) ## will hopefully allow time for dialog window to close
2149 self.current_file.read_xrd1D_ROIFile(path)
2151 def add1DXRD(self, event=None):
2153 if len(self.filemap) > 0:
2154 xrd1Dgrp = ensure_subgroup('xrd1d',self.current_file.xrmmap)
2155 poni_path = bytes2str(xrd1Dgrp.attrs.get('calfile',''))
2157 if not os.path.exists(poni_path):
2158 self.openPONI()
2159 poni_path = bytes2str(xrd1Dgrp.attrs.get('calfile',''))
2161 if os.path.exists(poni_path):
2162 self.current_file.add_xrd1d()
2164 def onShow1DXRD(self, event=None):
2165 self.showxrd = event.IsChecked()
2166 if self.showxrd:
2167 msg = 'Show 1DXRD data for area'
2168 else:
2169 msg = 'Not displaying 1DXRD for area'
2170 self.message(msg)
2171 ##print(msg)
2173# def onCorrectDeadtime(self, event=None):
2174# self.dtcor = event.IsChecked()
2175# if self.dtcor:
2176# msg = 'Using deadtime corrected data...'
2177# else:
2178# msg = 'Using raw data...'
2179# self.message(msg)
2180# ##print(msg)
2181#
2182# def onHotColumns(self, event=None):
2183# self.hotcols = event.IsChecked()
2184# if self.hotcols:
2185# msg = 'Ignoring first/last data columns.'
2186# else:
2187# msg = 'Using all data columns'
2188# self.message(msg)
2189# ##print(msg)
2191 def onWatchFiles(self, event=None):
2192 self.watch_files = event.IsChecked()
2193 if not self.watch_files:
2194 self.file_timer.Stop()
2195 msg = 'Watching Files/Folders for Changes: Off'
2196 else:
2197 self.file_timer.Start(10000)
2198 msg = 'Watching Files/Folders for Changes: On'
2199 self.message(msg)
2201 def onFileWatchTimer(self, event=None):
2202 if self.current_file is not None and len(self.files_in_progress) == 0:
2203 if self.current_file.folder_has_newdata():
2204 path, fname = os.path.split(self.current_file.filename)
2205 self.process_file(fname, max_new_rows=1e6)
2207 def process_file(self, filename, max_new_rows=None, on_complete=None):
2208 """Request processing of map file.
2209 This can take awhile, so is done in a separate thread,
2210 with updates displayed in message bar
2211 """
2212 xrmfile = self.filemap[filename]
2213 if xrmfile.status == GSEXRM_FileStatus.created:
2214 xrmfile.initialize_xrmmap(callback=self.updateTimer)
2216 if xrmfile.dimension is None and isGSEXRM_MapFolder(self.folder):
2217 xrmfile.read_master()
2219 # print("PROCESS_FILE!!", xrmfile.folder_has_newdata(), self.h5convert_done,
2220 # filename in self.files_in_progress)
2222 if (xrmfile.folder_has_newdata() and self.h5convert_done
2223 and filename not in self.files_in_progress):
2225 self.files_in_progress.append(filename)
2226 self.h5convert_fname = filename
2227 self.h5convert_done = False
2228 self.h5convert_oncomplete = on_complete
2229 self.htimer.Start(500)
2230 maxrow = None
2231 if max_new_rows is not None:
2232 maxrow = max_new_rows + xrmfile.last_row + 1
2234 ## this calls process function of xrm_mapfile class
2235 self.h5convert_thread = Thread(target=xrmfile.process,
2236 kwargs={'callback':self.updateTimer,
2237 'maxrow': maxrow})
2238 self.h5convert_thread.start()
2239 elif callable(on_complete):
2240 on_complete()
2242 def updateTimer(self, row=None, maxrow=None, filename=None, status=None):
2243 # print("== UPDATE TIMER ", row, maxrow, filename, status)
2244 if row is not None: self.h5convert_irow = row
2245 if maxrow is not None: self.h5convert_nrow = maxrow
2246 if filename is not None: self.h5convert_fname = filename
2247 self.h5convert_done = True if status == 'complete' else False
2248 msg = 'processing %s: row %i of %i' % (self.h5convert_fname,
2249 self.h5convert_irow,
2250 self.h5convert_nrow)
2251 wx.CallAfter(self.message, msg)
2253 def onTimer(self, event=None):
2254 if self.h5convert_done:
2255 # print("h5convert done, stopping timer")
2256 fname = self.h5convert_fname
2257 irow, nrow = self.h5convert_irow, self.h5convert_nrow
2258 self.htimer.Stop()
2259 self.h5convert_thread.join()
2260 self.files_in_progress = []
2261 self.message('MapViewer processing %s: complete!' % fname)
2262 _path, _fname = os.path.split(fname)
2263 if _fname in self.filemap:
2264 cfile = self.current_file = self.filemap[_fname]
2265 ny, nx = cfile.get_shape()
2266 self.title.SetLabel('%s: (%i x %i)' % (_fname, nx, ny))
2267 update_xrmmap = getattr(self.nb.GetCurrentPage(),
2268 'update_xrmmap', None)
2269 if callable(update_xrmmap) and _fname in self.filemap:
2270 update_xrmmap(xrmfile=cfile)
2271 if self.h5convert_oncomplete is not None:
2272 self.h5convert_oncomplete()
2275 def message(self, msg, win=0):
2276 self.statusbar.SetStatusText(msg, win)
2278 def check_ownership(self, fname):
2279 """
2280 check whether we're currently owner of the file.
2281 this is important!! HDF5 files can be corrupted.
2282 """
2283 if not self.filemap[fname].check_hostid():
2284 if (wx.ID_YES == Popup(self, NOT_OWNER_MSG % fname,
2285 'Not Owner of HDF5 File',
2286 style=wx.YES_NO)):
2287 self.filemap[fname].take_ownership()
2288 return self.filemap[fname].check_hostid()
2290class OpenPoniFile(wx.Dialog):
2291 """"""
2293 #----------------------------------------------------------------------
2294 def __init__(self):
2296 """Constructor"""
2297 dialog = wx.Dialog.__init__(self, None, title='XRD Calibration File', size=(350, 280))
2299 panel = wx.Panel(self)
2301 ################################################################################
2302 cal_chc = ['Dioptas calibration file:','pyFAI calibration file:']
2303 cal_spn = wx.SP_VERTICAL|wx.SP_ARROW_KEYS|wx.SP_WRAP
2304 self.PoniInfo = [ Choice(panel, choices=cal_chc ),
2305 wx.TextCtrl(panel, size=(320, 25)),
2306 Button(panel, label='Browse...')]
2308 self.PoniInfo[2].Bind(wx.EVT_BUTTON, self.onBROWSEponi)
2310 ponisizer = wx.BoxSizer(wx.VERTICAL)
2311 ponisizer.Add(self.PoniInfo[0], flag=wx.TOP, border=15)
2312 ponisizer.Add(self.PoniInfo[1], flag=wx.TOP, border=5)
2313 ponisizer.Add(self.PoniInfo[2], flag=wx.TOP|wx.BOTTOM, border=5)
2315 ################################################################################
2316 hlpBtn = wx.Button(panel, wx.ID_HELP )
2317 okBtn = wx.Button(panel, wx.ID_OK )
2318 canBtn = wx.Button(panel, wx.ID_CANCEL )
2320 minisizer = wx.BoxSizer(wx.HORIZONTAL)
2321 minisizer.Add(hlpBtn, flag=wx.RIGHT, border=5)
2322 minisizer.Add(canBtn, flag=wx.RIGHT, border=5)
2323 minisizer.Add(okBtn, flag=wx.RIGHT, border=5)
2324 ################################################################################
2325 sizer = wx.BoxSizer(wx.VERTICAL)
2326 sizer.Add((-1, 10))
2327 sizer.Add(ponisizer, flag=wx.TOP|wx.LEFT, border=5)
2328 sizer.Add((-1, 15))
2329 sizer.Add(minisizer, flag=wx.ALIGN_RIGHT, border=5)
2331 panel.SetSizer(sizer)
2332 ################################################################################
2334 ## Set defaults
2335 self.PoniInfo[0].SetSelection(0)
2337 self.FindWindowById(wx.ID_OK).Disable()
2339 def checkOK(self,event=None):
2341 if os.path.exists(self.PoniInfo[1].GetValue()):
2342 self.FindWindowById(wx.ID_OK).Enable()
2343 else:
2344 self.FindWindowById(wx.ID_OK).Disable()
2346 def onBROWSEponi(self,event=None):
2347 wildcards = 'XRD calibration file (*.poni)|*.poni|All files (*.*)|*.*'
2348 if os.path.exists(self.PoniInfo[1].GetValue()):
2349 dfltDIR = self.PoniInfo[1].GetValue()
2350 else:
2351 dfltDIR = get_cwd()
2353 dlg = wx.FileDialog(self, message='Select XRD calibration file',
2354 defaultDir=dfltDIR,
2355 wildcard=wildcards, style=wx.FD_OPEN)
2356 path, read = None, False
2357 if dlg.ShowModal() == wx.ID_OK:
2358 read = True
2359 path = dlg.GetPath().replace('\\', '/')
2360 dlg.Destroy()
2362 if read:
2363 self.PoniInfo[1].Clear()
2364 self.PoniInfo[1].SetValue(str(path))
2365 self.checkOK()
2367######
2368class ROIDialog(wx.Dialog):
2369 """"""
2370 #----------------------------------------------------------------------
2371 def __init__(self, owner, roi_callback=None, **kws):
2372 """Constructor"""
2373 print("ROI Dialog owner ", owner)
2374 wx.Dialog.__init__(self, owner, wx.ID_ANY, title='Add and Delete ROIs',
2375 size=(450, 350))
2377 self.owner = owner
2378 self.roi_callback = roi_callback
2379 self.Bind(wx.EVT_CLOSE, self.onClose)
2381 self.gp = gp = GridPanel(self, nrows=8, ncols=4, itemstyle=LEFT, gap=3, **kws)
2383 self.roi_name = wx.TextCtrl(gp, -1, 'ROI_001', size=(120, -1))
2384 fopts = dict(minval=-1, precision=3, size=(120, -1))
2385 self.roi_type = Choice(gp, size=(120, -1))
2386 self.roi_lims = [FloatCtrl(gp, value=0, **fopts),
2387 FloatCtrl(gp, value=-1, **fopts)]
2388 self.roi_units = Choice(gp, size=(120, -1))
2390 gp.Add(SimpleText(gp, ' Add new ROI: '), dcol=2, style=LEFT)
2391 gp.Add(SimpleText(gp, ' Name:'), newrow=True)
2392 gp.Add(self.roi_name, dcol=2)
2393 gp.Add(SimpleText(gp, ' Type:'), newrow=True)
2394 gp.Add(self.roi_type, dcol=2)
2396 gp.Add(SimpleText(gp, ' Limits:'), newrow=True)
2397 gp.AddMany((self.roi_lims[0], self.roi_lims[1], self.roi_units),
2398 dcol=1, style=LEFT)
2399 gp.Add(SimpleText(gp, ' '), newrow=True)
2400 gp.Add(Button(gp, 'Add ROI', size=(120, -1), action=self.onCreateROI),
2401 dcol=2)
2403 ###############################################################################
2405 self.rm_roi_name = Choice(gp, size=(120, -1))
2406 self.rm_roi_det = Choice(gp, size=(120, -1))
2407 fopts = dict(minval=-1, precision=3, size=(100, -1))
2408 gp.Add(SimpleText(gp, ''),newrow=True)
2409 gp.Add(HLine(gp, size=(350, 4)), dcol=4, newrow=True)
2410 gp.Add(SimpleText(gp, ''),newrow=True)
2411 gp.Add(SimpleText(gp, 'Delete ROI: '), dcol=2, newrow=True)
2413 gp.AddMany((SimpleText(gp, 'Detector:'),self.rm_roi_det), newrow=True)
2414 gp.AddMany((SimpleText(gp, 'ROI:'),self.rm_roi_name), newrow=True)
2416 gp.Add(SimpleText(gp, ''), newrow=True)
2417 gp.Add(Button(gp, 'Remove This ROI', size=(120, -1), action=self.onRemoveROI),
2418 dcol=2)
2420 self.roi_type.Bind(wx.EVT_CHOICE, self.roiUNITS)
2421 self.rm_roi_name.Bind(wx.EVT_CHOICE, self.roiSELECT)
2423 gp.pack()
2424 fit_dialog_window(self, gp)
2425 self.owner.current_file.reset_flags()
2426 self.roiTYPE()
2428 def roiTYPE(self, event=None):
2429 roitype = []
2430 cfile = self.owner.current_file
2431 det_list = cfile.get_detector_list()
2432 if cfile.has_xrf:
2433 roitype += ['XRF']
2434 if cfile.has_xrd1d:
2435 roitype += ['1DXRD']
2436 if len(roitype) < 1:
2437 roitype = ['']
2438 self.roi_type.SetChoices(roitype)
2439 self.roiUNITS()
2440 self.rm_roi_det.SetChoices(det_list)
2441 self.setROI()
2443 def onRemoveROI(self,event=None):
2444 detname = self.rm_roi_det.GetStringSelection()
2445 roiname = self.rm_roi_name.GetStringSelection()
2447 if self.roi_callback is not None:
2448 self.roi_callback(roiname, action='del')
2449 self.setROI()
2450 self.roiTYPE()
2452 def setROI(self):
2453 detname = self.rm_roi_det.GetStringSelection()
2454 cfile = self.owner.current_file
2455 try:
2456 detgrp = cfile.xrmmap['roimap'][detname]
2457 except:
2458 return
2460 limits = []
2461 names = detgrp.keys()
2462 for name in names:
2463 limits += [list(detgrp[name]['limits'][:])]
2464 if len(limits) > 0:
2465 self.rm_roi_name.SetChoices([x for (y,x) in sorted(zip(limits,names))])
2466 self.roiSELECT()
2468 def roiSELECT(self, event=None):
2469 detname = self.rm_roi_det.GetStringSelection()
2470 cfile = self.owner.current_file
2471 roinames = cfile.get_roi_list(detname)
2472 self.rm_roi_name.SetChoices(roinames)
2474 def roiUNITS(self,event=None):
2475 choice = self.roi_type.GetStringSelection()
2476 roiunit = ['']
2477 if choice == 'XRF':
2478 roiunit = ['keV', 'eV', 'channels']
2479 elif choice == '1DXRD':
2480 roiunit = [u'\u212B\u207B\u00B9 (q)',u'\u00B0 (2\u03B8)',u'\u212B (d)']
2482 self.roi_units.SetChoices(roiunit)
2484 def onCreateROI(self,event=None):
2485 rtype = self.roi_type.GetStringSelection()
2486 name = self.roi_name.GetValue()
2487 xrange = [float(lims.GetValue()) for lims in self.roi_lims]
2489 units = self.roi_units.GetStringSelection()
2490 if rtype == '1DXRD':
2491 units = ['q', '2th', 'd'][self.roi_units.GetSelection()]
2494 self.owner.message(f'Building ROI data for: {name:s}')
2495 if self.roi_callback is not None:
2496 self.roi_callback(name, xrange=xrange, action='add', units=units, roitype=rtype)
2498 self.owner.message(f'Added ROI: {name:s}')
2499 self.roiTYPE()
2501 def onClose(self, event=None):
2502 self.Destroy()
2504##################a
2508class OpenMapFolder(wx.Dialog):
2509 """"""
2511 #----------------------------------------------------------------------
2512 def __init__(self, folder):
2513 """Constructor"""
2514 self.folder = folder
2515 pref, f = os.path.split(folder)
2516 title = "Read XRM Map Folder: %s" % f
2517 wx.Dialog.__init__(self, None,
2518 title=title, size=(475, 750))
2521 panel = wx.Panel(self)
2523 ChkTtl = SimpleText(panel, label='Build map including data:' )
2524 self.ChkBx = [ Check(panel, label='XRF' ),
2525 Check(panel, label='2DXRD' ),
2526 Check(panel, label='1DXRD (requires calibration file)' )]
2528 for chkbx in self.ChkBx:
2529 chkbx.Bind(wx.EVT_CHECKBOX, self.checkOK)
2531 cbsizer = wx.BoxSizer(wx.HORIZONTAL)
2532 cbsizer.Add(self.ChkBx[0])
2533 cbsizer.Add(self.ChkBx[1])
2534 cbsizer.Add(self.ChkBx[2])
2536 ckbxsizer = wx.BoxSizer(wx.VERTICAL)
2537 ckbxsizer.Add(ChkTtl, flag=wx.BOTTOM|wx.LEFT)
2538 ckbxsizer.Add(cbsizer)
2539 ################################################################################
2540 infoTtl = [ SimpleText(panel, label='Facility'),
2541 SimpleText(panel, label='Beamline'),
2542 SimpleText(panel, label='Run cycle'),
2543 SimpleText(panel, label='Proposal'),
2544 SimpleText(panel, label='User group')]
2545 self.info = [ wx.TextCtrl(panel, size=(100, 25) ),
2546 wx.TextCtrl(panel, size=(100, 25) ),
2547 wx.TextCtrl(panel, size=(100, 25) ),
2548 wx.TextCtrl(panel, size=(100, 25) ),
2549 wx.TextCtrl(panel, size=(320, 25) )]
2551 infosizer0 = wx.BoxSizer(wx.HORIZONTAL)
2552 infosizer0.Add(infoTtl[0], flag=wx.RIGHT, border=5)
2553 infosizer0.Add(self.info[0], flag=wx.RIGHT, border=15)
2554 infosizer0.Add(infoTtl[1], flag=wx.RIGHT, border=5)
2555 infosizer0.Add(self.info[1], flag=wx.RIGHT, border=15)
2557 infosizer1 = wx.BoxSizer(wx.HORIZONTAL)
2558 infosizer1.Add(infoTtl[2], flag=wx.RIGHT, border=5)
2559 infosizer1.Add(self.info[2], flag=wx.RIGHT, border=15)
2560 infosizer1.Add(infoTtl[3], flag=wx.RIGHT, border=5)
2561 infosizer1.Add(self.info[3], flag=wx.RIGHT, border=15)
2563 infosizer2 = wx.BoxSizer(wx.HORIZONTAL)
2564 infosizer2.Add(infoTtl[4], flag=wx.RIGHT, border=5)
2565 infosizer2.Add(self.info[4], flag=wx.RIGHT, border=15)
2567 infosizer = wx.BoxSizer(wx.VERTICAL)
2568 infosizer.Add(infosizer0, flag=wx.TOP, border=5)
2569 infosizer.Add(infosizer1, flag=wx.TOP|wx.BOTTOM, border=5)
2570 infosizer.Add(infosizer2, flag=wx.BOTTOM, border=15)
2571 ################################################################################
2572 cal_chc = ['Dioptas calibration file:','pyFAI calibration file:']
2573 bkgd_chc = ['2DXRD background (optional):','1DXRD background (optional):']
2574 cal_spn = wx.SP_VERTICAL|wx.SP_ARROW_KEYS|wx.SP_WRAP
2575 self.XRDInfo = [ Choice(panel, choices=cal_chc ),
2576 wx.TextCtrl(panel, size=(320, 25)),
2577 Button(panel, label='Browse...'),
2578 SimpleText(panel, label='Steps:'),
2579 wx.TextCtrl(panel, size=(80, 25)),
2580 SimpleText(panel, label='Wedges:'),
2581 wx.SpinCtrl(panel, style=cal_spn, size=(100, -1)),
2582 Choice(panel, choices=bkgd_chc ),
2583 wx.TextCtrl(panel, size=(320, 25)),
2584 Button(panel, label='Browse...'),
2585 SimpleText(panel, label='Background scale:'),
2586 wx.TextCtrl(panel, size=(80, 25)),
2587 SimpleText(panel, label='2DXRD mask file (optional):'),
2588 wx.TextCtrl(panel, size=(320, 25)),
2589 Button(panel, label='Browse...'),]
2591 for i in [1,8,13]:
2592 self.XRDInfo[i+1].Bind(wx.EVT_BUTTON, partial(self.onBROWSEfile,i=i))
2594 xrdsizer1 = wx.BoxSizer(wx.HORIZONTAL)
2596 xrdsizer1.Add(self.XRDInfo[3], flag=wx.RIGHT, border=5)
2597 xrdsizer1.Add(self.XRDInfo[4], flag=wx.RIGHT, border=5)
2598 xrdsizer1.Add(self.XRDInfo[5], flag=wx.RIGHT, border=5)
2599 xrdsizer1.Add(self.XRDInfo[6], flag=wx.RIGHT, border=5)
2601 xrdsizer2 = wx.BoxSizer(wx.HORIZONTAL)
2603 xrdsizer2.Add(self.XRDInfo[9], flag=wx.RIGHT, border=30)
2604 xrdsizer2.Add(self.XRDInfo[10], flag=wx.RIGHT, border=5)
2605 xrdsizer2.Add(self.XRDInfo[11], flag=wx.RIGHT, border=5)
2607 xrdsizer = wx.BoxSizer(wx.VERTICAL)
2608 xrdsizer.Add(self.XRDInfo[0], flag=wx.TOP, border=5)
2609 xrdsizer.Add(self.XRDInfo[1], flag=wx.TOP, border=5)
2610 xrdsizer.Add(self.XRDInfo[2], flag=wx.TOP|wx.BOTTOM, border=5)
2611 xrdsizer.Add(xrdsizer1, flag=wx.BOTTOM, border=5)
2612 xrdsizer.Add(self.XRDInfo[7], flag=wx.TOP, border=8)
2613 xrdsizer.Add(self.XRDInfo[8], flag=wx.TOP, border=5)
2614# xrdsizer.Add(self.XRDInfo[9], flag=wx.TOP|wx.BOTTOM, border=5)
2615 xrdsizer.Add(xrdsizer2, flag=wx.TOP|wx.BOTTOM, border=5)
2616 xrdsizer.Add(self.XRDInfo[12], flag=wx.TOP, border=8)
2617 xrdsizer.Add(self.XRDInfo[13], flag=wx.TOP, border=5)
2618 xrdsizer.Add(self.XRDInfo[14], flag=wx.TOP|wx.BOTTOM, border=5)
2621 ################################################################################
2622 h5cmpr_chc = ['gzip','lzf']
2623 h5cmpr_opt = ['%i' % i for i in np.arange(10)]
2625 self.H5cmprInfo = [Choice(panel, choices=h5cmpr_chc),
2626 Choice(panel, choices=h5cmpr_opt)]
2627 h5txt = SimpleText(panel, label='H5 File Comppression:')
2629 self.H5cmprInfo[0].SetSelection(0)
2630 self.H5cmprInfo[1].SetSelection(2)
2632 self.H5cmprInfo[0].Bind(wx.EVT_CHOICE, self.onH5cmpr)
2634 h5cmprsizer = wx.BoxSizer(wx.HORIZONTAL)
2635 h5cmprsizer.Add(h5txt, flag=wx.RIGHT, border=5)
2636 h5cmprsizer.Add(self.H5cmprInfo[0], flag=wx.RIGHT, border=5)
2637 h5cmprsizer.Add(self.H5cmprInfo[1], flag=wx.RIGHT, border=5)
2638 ################################################################################
2639 self.ok_btn = wx.Button(panel, wx.ID_OK)
2640 self.cancel_btn = wx.Button(panel, wx.ID_CANCEL)
2642 minisizer = wx.BoxSizer(wx.HORIZONTAL)
2643 minisizer.Add(self.cancel_btn, flag=wx.RIGHT, border=5)
2644 minisizer.Add(self.ok_btn, flag=wx.RIGHT, border=5)
2645 ################################################################################
2646 sizer = wx.BoxSizer(wx.VERTICAL)
2648 sizer.Add(ckbxsizer, flag=wx.TOP|wx.LEFT, border=5)
2650 sizer.Add(HLine(panel, size=(320, 2)),flag=wx.TOP|wx.LEFT, border=5)
2651 sizer.Add(infosizer, flag=wx.TOP|wx.LEFT, border=5)
2652 sizer.Add(HLine(panel, size=(320, 2)),flag=wx.TOP|wx.LEFT, border=5)
2653 sizer.Add(xrdsizer, flag=wx.TOP|wx.LEFT, border=5)
2654 sizer.Add(HLine(panel, size=(320, 2)),flag=wx.TOP|wx.LEFT, border=5)
2655 sizer.Add(h5cmprsizer, flag=wx.TOP|wx.LEFT, border=5)
2656 sizer.Add(minisizer, flag=wx.ALIGN_RIGHT, border=5)
2659 pack(panel, sizer)
2660 w, h = panel.GetBestSize()
2661 w = 25*(2 + int(w*0.04))
2662 h = 25*(2 + int(h*0.04))
2663 panel.SetSize((w, h))
2665 # HX
2666 ################################################################################
2668 ## Set defaults
2669 self.ChkBx[0].SetValue(True)
2670 self.ChkBx[1].SetValue(False)
2671 self.ChkBx[2].SetValue(False)
2673 self.XRDInfo[0].SetSelection(0)
2674 self.XRDInfo[7].SetSelection(0)
2676 self.XRDInfo[4].SetValue('5001')
2677 self.XRDInfo[6].SetValue(1)
2678 self.XRDInfo[6].SetRange(0,36)
2680 self.XRDInfo[11].SetValue('1.0')
2682 for poniinfo in self.XRDInfo:
2683 poniinfo.Disable()
2685 self.info[0].SetValue(FACILITY)
2686 self.info[1].SetValue(BEAMLINE)
2687 for line in open(os.path.join(self.folder, 'Scan.ini'), 'r'):
2688 if line.split()[0] == 'basedir':
2689 npath = line.split()[-1].replace('\\', '/').split('/')
2690 cycle, usr = npath[-2], npath[-1]
2691 self.info[2].SetValue(cycle)
2692 self.info[4].SetValue(usr)
2693 self.checkOK()
2695 def checkOK(self, evt=None):
2697 if self.ChkBx[2].GetValue():
2698 for poniinfo in self.XRDInfo:
2699 poniinfo.Enable()
2700 elif self.ChkBx[1].GetValue():
2701 for poniinfo in self.XRDInfo[8:]:
2702 poniinfo.Enable()
2703 for poniinfo in self.XRDInfo[:8]:
2704 poniinfo.Disable()
2705 self.XRDInfo[7].SetSelection(0)
2706 else:
2707 for poniinfo in self.XRDInfo:
2708 poniinfo.Disable()
2710 def onH5cmpr(self,event=None):
2712 if self.H5cmprInfo[0].GetSelection() == 0:
2713 self.H5cmprInfo[1].Enable()
2714 self.H5cmprInfo[1].SetChoices(['%i' % i for i in np.arange(10)])
2715 self.H5cmprInfo[1].SetSelection(2)
2716 else:
2717 self.H5cmprInfo[1].Disable()
2718 self.H5cmprInfo[1].SetChoices([''])
2720 def onBROWSEfile(self,event=None,i=1):
2722 if i == 8:
2723 wldcd = '2D XRD background file (*.tiff)|*.tif;*.tiff;*.edf|All files (*.*)|*.*'
2724 if i == 13:
2725 wldcd = '1D XRD background file (*.xy)|*.xy|All files (*.*)|*.*'
2726 else: ## elif i == 1:
2727 wldcd = 'XRD calibration file (*.poni)|*.poni|All files (*.*)|*.*'
2729 if os.path.exists(self.XRDInfo[i].GetValue()):
2730 dfltDIR = self.XRDInfo[i].GetValue()
2731 else:
2732 dfltDIR = get_cwd()
2734 dlg = wx.FileDialog(self, message='Select %s' % wldcd.split(' (')[0],
2735 defaultDir=dfltDIR,
2736 wildcard=wldcd, style=wx.FD_OPEN)
2737 path, read = None, False
2738 if dlg.ShowModal() == wx.ID_OK:
2739 read = True
2740 path = dlg.GetPath().replace('\\', '/')
2741 dlg.Destroy()
2743 if read:
2744 self.XRDInfo[i].Clear()
2745 self.XRDInfo[i].SetValue(str(path))
2748class MapViewer(LarchWxApp):
2749 def __init__(self, use_scandb=False, _larch=None, filename=None,
2750 check_version=True, with_inspect=False, **kws):
2751 self.filename = filename
2752 self.use_scandb = use_scandb
2753 self.check_version = check_version
2754 LarchWxApp.__init__(self, _larch=_larch,
2755 with_inspect=with_inspect, **kws)
2757 def createApp(self):
2758 frame = MapViewerFrame(use_scandb=self.use_scandb,
2759 filename=self.filename,
2760 check_version=self.check_version,
2761 _larch=self._larch)
2762 self.SetTopWindow(frame)
2763 return True
2766def mapviewer(use_scandb=False, filename=None, _larch=None,
2767 with_inspect=False, **kws):
2768 MapViewer(use_scandb=use_scandb, filename=filename, _larch=_larch,
2769 with_inspect=with_inspect, **kws)