Coverage for larch/epics/xrfcontrol.py: 14%
490 statements
« prev ^ index » next coverage.py v7.6.0, created at 2024-10-16 21:04 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2024-10-16 21:04 +0000
1#!/usr/bin/env python
2"""
3Epics XRF Display App
4"""
6import sys
7import os
9import time
10import copy
11from functools import partial
13import wx
14import wx.lib.mixins.inspection
15import wx.lib.scrolledpanel as scrolled
16import wx.dataview as dv
18import numpy as np
19import matplotlib
21from wxmplot import PlotPanel
22from wxutils import (SimpleText, EditableListBox, Font, FloatCtrl,
23 pack, Popup, Button, get_icon, Check, MenuItem,
24 Choice, FileOpen, FileSave, fix_filename, HLine,
25 GridPanel, CEN, LEFT, RIGHT)
27import larch
28from larch.site_config import icondir
29from larch.wxlib import PeriodicTablePanel, LarchWxApp
30from larch.wxlib.xrfdisplay import (XRFDisplayFrame, XRFCalibrationFrame,
31 FILE_WILDCARDS)
32from larch.utils import get_cwd
34ROI_WILDCARD = 'Data files (*.dat)|*.dat|ROI files (*.roi)|*.roi|All files (*.*)|*.*'
35try:
36 from epics import caget
37 from .xrf_detectors import Epics_MultiXMAP, Epics_Xspress3
38except:
39 pass
41class DetectorSelectDialog(wx.Dialog):
42 """Connect to an Epics MCA detector
43 Can be either XIA xMAP or Quantum XSPress3
44 """
45 msg = '''Select XIA xMAP or Quantum XSPress3 MultiElement MCA detector'''
46 det_types = ('SXD-7', 'ME-7', 'ME-4', 'other')
47 ioc_types = ('Xspress3.1', 'xMAP', 'Xspress3.0')
48 def_prefix = '13QX7:' # SDD1:'
49 def_nelem = 4
51 def __init__(self, parent=None, prefix=None, det_type='ME-4',
52 ioc_type='Xspress3', nmca=4,
53 title='Select Epics MCA Detector'):
54 if prefix is None:
55 prefix = self.def_prefix
56 if det_type not in self.det_types:
57 det_type = self.det_types[0]
59 wx.Dialog.__init__(self, parent, wx.ID_ANY, title=title)
61 self.SetBackgroundColour((240, 240, 230))
62 self.SetFont(Font(9))
63 if parent is not None:
64 self.SetFont(parent.GetFont())
66 self.ioctype = Choice(self,size=(120, -1), choices=self.ioc_types)
67 self.ioctype.SetStringSelection(ioc_type)
69 self.dettype = Choice(self,size=(120, -1), choices=self.det_types)
70 self.dettype.SetStringSelection(det_type)
72 self.prefix = wx.TextCtrl(self, -1, prefix, size=(120, -1))
73 self.nelem = FloatCtrl(self, value=nmca, precision=0, minval=1,
74 size=(120, -1))
76 btnsizer = wx.StdDialogButtonSizer()
78 if wx.Platform != "__WXMSW__":
79 btn = wx.ContextHelpButton(self)
80 btnsizer.AddButton(btn)
82 btn = wx.Button(self, wx.ID_OK)
83 btn.SetHelpText("Use this detector")
84 btn.SetDefault()
85 btnsizer.AddButton(btn)
87 btn = wx.Button(self, wx.ID_CANCEL)
88 btnsizer.AddButton(btn)
89 btnsizer.Realize()
91 hline = wx.StaticLine(self, size=(225, 3), style=wx.LI_HORIZONTAL)
92 sty = LEFT
93 sizer = wx.GridBagSizer(5, 2)
94 def txt(label):
95 return SimpleText(self, label, size=(120, -1), style=LEFT)
97 sizer.Add(txt(' Detector Type'), (0, 0), (1, 1), sty, 2)
98 sizer.Add(txt(' Uses Xspress3?'), (1, 0), (1, 1), sty, 2)
99 sizer.Add(txt(' Epics Prefix'), (2, 0), (1, 1), sty, 2)
100 sizer.Add(txt(' # Elements'), (3, 0), (1, 1), sty, 2)
101 sizer.Add(self.dettype, (0, 1), (1, 1), sty, 2)
102 sizer.Add(self.ioctype, (1, 1), (1, 1), sty, 2)
103 sizer.Add(self.prefix, (2, 1), (1, 1), sty, 2)
104 sizer.Add(self.nelem, (3, 1), (1, 1), sty, 2)
106 sizer.Add(hline, (4, 0), (1, 2), sty, 2)
107 sizer.Add(btnsizer, (5, 0), (1, 2), sty, 2)
108 self.SetSizer(sizer)
109 sizer.Fit(self)
112class EpicsXRFDisplayFrame(XRFDisplayFrame):
113 _about = """Epics XRF Spectra Display
114 Matt Newville <newville @ cars.uchicago.edu>
115 """
116 me4_layout = ((0, 0), (1, 0), (1, 1), (0, 1))
117 main_title = 'Epics XRF Control'
119 def __init__(self, parent=None, _larch=None, prefix=None,
120 det_type='ME-4', ioc_type='Xspress3', nmca=4,
121 size=(725, 580), environ_file=None,
122 title='Epics XRF Display', output_title='XRF', **kws):
124 self.det_type = det_type
125 self.ioc_type = ioc_type
126 self.nmca = nmca
127 self.det_fore = 1
128 self.det_back = 0
129 self.environ = []
130 if environ_file is not None:
131 self.read_environfile(environ_file)
133 self.onConnectEpics(event=None, prefix=prefix)
135 self.icon_file = os.path.join(icondir, 'ptable.ico')
137 XRFDisplayFrame.__init__(self, parent=parent, _larch=_larch,
138 title=title, size=size, **kws)
140 def read_environfile(self, filename):
141 """read environmnet file"""
142 if os.path.exists(filename):
143 textlines = []
144 try:
145 with open(filename, 'r') as fh:
146 textlines = fh.readlines()
147 except IOError:
148 return
149 self.environ = []
150 for line in textlines:
151 line = line[:-1].replace('\t', ' ')
152 pvname, desc = line.split(None, 1)
153 desc = desc.strip()
154 self.environ.append((pvname, desc))
156 def onConnectEpics(self, event=None, prefix=None, **kws):
157 if prefix is None:
158 res = self.prompt_for_detector(prefix=prefix,
159 ioc_type=self.ioc_type,
160 nmca=self.nmca)
161 self.prefix, self.det_type, self.ioc_type, self.nmca = res
162 else:
163 self.prefix = prefix
164 self.det_fore = 1
165 self.det_back = 0
166 self.clear_mcas()
167 self.connect_to_detector(prefix=self.prefix, ioc_type=self.ioc_type,
168 det_type=self.det_type, nmca=self.nmca)
170 def onSaveMCAFile(self, event=None, **kws):
171 tmp = '''
172 # print('SaveMCA File')
173 deffile = ''
174 if hasattr(self.mca, 'sourcefile'):
175 deffile = "%s%s" % (deffile, getattr(self.mca, 'sourcefile'))
176 if hasattr(self.mca, 'areaname'):
177 deffile = "%s%s" % (deffile, getattr(self.mca, 'areaname'))
178 if deffile == '':
179 deffile ='test'
180 if not deffile.endswith('.mca'):
181 deffile = deffile + '.mca'
182 '''
184 deffile = 'save.mca' # fix_filename(str(deffile))
185 outfile = FileSave(self, "Save MCA File",
186 default_file=deffile,
187 wildcard=FILE_WILDCARDS)
189 env = []
190 if len(self.environ) > 0:
191 for pvname, desc in self.environ:
192 val = caget(pvname, as_string=True)
193 env.append((pvname, val, desc))
195 if outfile is not None:
196 self.det.save_mcafile(outfile, environ=env)
198 def onSaveColumnFile(self, event=None, **kws):
199 print( ' EPICS-XRFDisplay onSaveColumnFile not yet implemented ')
200 pass
202 def prompt_for_detector(self, prefix=None, ioc_type='Xspress3', nmca=4):
203 dlg = DetectorSelectDialog(prefix=prefix, ioc_type=ioc_type, nmca=nmca)
204 dlg.Raise()
205 if dlg.ShowModal() == wx.ID_OK:
206 dpref = dlg.prefix.GetValue()
207 atype = dlg.ioctype.GetStringSelection()
208 dtype = dlg.dettype.GetStringSelection()
209 nmca = dlg.nelem.GetValue()
210 dlg.Destroy()
211 return dpref, dtype, atype, nmca
213 def connect_to_detector(self, prefix=None, ioc_type='Xspress3',
214 det_type=None, nmca=4):
215 self.det = None
216 ioc_type = ioc_type.lower()
217 if ioc_type.startswith('xspress3'):
218 version = 2
219 if 'old' in ioc_type:
220 version = 1
221 self.det = Epics_Xspress3(prefix=prefix, nmca=nmca, version=version)
222 self.det.connect()
223 time.sleep(0.5)
224 self.det.get_mca(mca=1)
225 self.needs_newplot=True
226 else:
227 self.det = Epics_MultiXMAP(prefix=prefix, nmca=nmca)
228 time.sleep(0.05)
230 def show_mca(self, init=False):
231 self.needs_newplot = False
232 if self.mca is None or self.needs_newplot:
233 self.mca = self.det.get_mca(mca=self.det_fore)
235 self.plotmca(self.mca, set_title=False, init=init)
236 title = "Foreground: MCA{:d}".format(self.det_fore)
237 if self.det_back > 0:
238 if self.mca2 is None:
239 self.mca2 = self.det.get_mca(mca=self.det_back)
241 c2 = self.det.get_array(mca=self.det_back)
242 e2 = self.det.get_energy(mca=self.det_back)
243 title = "{:s} Background: MCA{:d}".format(title, self.det_back)
244 try:
245 self.oplot(e2, c2)
246 except ValueError:
247 pass
249 roiname = self.get_roiname()
251 if roiname in self.wids['roilist'].GetStrings():
252 i = self.wids['roilist'].GetStrings().index(roiname)
253 self.wids['roilist'].EnsureVisible(i)
254 self.onROI(label=roiname)
255 deadtime = self.det.get_deadtime(mca=self.det_fore)
256 if deadtime is not None:
257 self.wids['deadtime'].SetLabel("%.1f" % deadtime)
258 self.SetTitle("%s: %s" % (self.main_title, title))
259 self.needs_newplot = False
261 def onSaveROIs(self, event=None, **kws):
262 dlg = wx.FileDialog(self, message="Save ROI File",
263 defaultDir=get_cwd(),
264 wildcard=ROI_WILDCARD,
265 style = wx.FD_SAVE|wx.FD_CHANGE_DIR)
267 if dlg.ShowModal() == wx.ID_OK:
268 roifile = dlg.GetPath()
270 self.det.save_rois(roifile)
272 def onRestoreROIs(self, event=None, **kws):
273 dlg = wx.FileDialog(self, message="Read ROI File",
274 defaultDir=get_cwd(),
275 wildcard=ROI_WILDCARD,
276 style = wx.FD_OPEN|wx.FD_CHANGE_DIR)
278 if dlg.ShowModal() == wx.ID_OK:
279 roifile = dlg.GetPath()
280 self.det.restore_rois(roifile)
281 self.set_roilist(mca=self.mca)
282 self.show_mca()
283 self.onSelectDet(event=None, index=0)
285 def createCustomMenus(self):
286 menu = wx.Menu()
287 MenuItem(self, menu, "Connect to Detector\tCtrl+D",
288 "Connect to MCA or XSPress3 Detector",
289 self.onConnectEpics)
290 menu.AppendSeparator()
291 self._menus.insert(1, (menu, 'Detector'))
293 def createMainPanel(self):
294 epicspanel = self.createEpicsPanel()
295 ctrlpanel = self.createControlPanel()
296 plotpanel = self.panel = self.createPlotPanel()
297 self.panel.SetName('plotpanel')
298 tx, ty = self.wids['ptable'].GetBestSize()
299 cx, cy = ctrlpanel.GetBestSize()
300 px, py = plotpanel.GetBestSize()
302 self.SetSize((950, 625))
303 self.SetMinSize((450, 350))
305 style = wx.ALIGN_LEFT|wx.EXPAND|wx.ALL
307 bsizer = wx.BoxSizer(wx.HORIZONTAL)
308 bsizer.Add(ctrlpanel, 0, style, 1)
309 bsizer.Add(plotpanel, 1, style, 1)
310 hline = wx.StaticLine(self, size=(425, 2), style=wx.LI_HORIZONTAL|style)
312 sizer = wx.BoxSizer(wx.VERTICAL)
313 sizer.Add(epicspanel, 0, style, 1)
314 sizer.Add(hline, 0, style, 1)
315 sizer.Add(bsizer, 1, style, 1)
316 pack(self, sizer)
318 try:
319 self.SetIcon(wx.Icon(self.icon_file, wx.BITMAP_TYPE_ICO))
320 except:
321 pass
322 self.set_roilist(mca=None)
324 def create_detbuttons(self, pane):
325 btnpanel = wx.Panel(pane, name='buttons')
326 btnsizer = wx.GridBagSizer(1, 1)
327 btns = {}
328 sx = 36
329 sy = int(sx/2)
330 for i in range(1, self.nmca+1):
331 b = Button(btnpanel, f'{i}', size=(sx, sx),
332 action=partial(self.onSelectDet, index=i))
333 b.SetFont(Font(9))
334 self.wids['det%i' % i] = b
335 btns[i] = b
336 dtype = self.det_type.lower().replace('-', '').replace(' ', '').replace('_', '')
337 if dtype.startswith('sxd7') and self.nmca == 7:
338 btnsizer.Add((sx, sy), (0, 0), (1, 2), wx.ALIGN_LEFT, 1)
339 btnsizer.Add(btns[6], (1, 0), (2, 2), wx.ALIGN_LEFT, 1)
340 btnsizer.Add(btns[7], (3, 0), (2, 2), wx.ALIGN_LEFT, 1)
341 btnsizer.Add((sx, sy), (5, 0), (1, 2), wx.ALIGN_LEFT, 1)
342 btnsizer.Add(btns[5], (0, 2), (2, 2), wx.ALIGN_LEFT, 1)
343 btnsizer.Add(btns[4], (2, 2), (2, 2), wx.ALIGN_LEFT, 1)
344 btnsizer.Add(btns[1], (4, 2), (2, 2), wx.ALIGN_LEFT, 1)
345 btnsizer.Add((sx, sy), (0, 4), (1, 2), wx.ALIGN_LEFT, 1)
346 btnsizer.Add(btns[3], (1, 4), (2, 2), wx.ALIGN_LEFT, 1)
347 btnsizer.Add(btns[2], (3, 4), (2, 2), wx.ALIGN_LEFT, 1)
348 btnsizer.Add((sx, sy), (5, 4), (1, 2), wx.ALIGN_LEFT, 1)
349 elif dtype.startswith('me7') and self.nmca == 7:
350 btnsizer.Add((sx, sy), (0, 0), (1, 2), wx.ALIGN_LEFT, 1)
351 btnsizer.Add(btns[7], (1, 0), (2, 2), wx.ALIGN_LEFT, 1)
352 btnsizer.Add(btns[6], (3, 0), (2, 2), wx.ALIGN_LEFT, 1)
353 btnsizer.Add((sx, sy), (5, 0), (1, 2), wx.ALIGN_LEFT, 1)
354 btnsizer.Add(btns[2], (0, 2), (2, 2), wx.ALIGN_LEFT, 1)
355 btnsizer.Add(btns[1], (2, 2), (2, 2), wx.ALIGN_LEFT, 1)
356 btnsizer.Add(btns[5], (4, 2), (2, 2), wx.ALIGN_LEFT, 1)
357 btnsizer.Add((sx, sy), (0, 4), (1, 2), wx.ALIGN_LEFT, 1)
358 btnsizer.Add(btns[3], (1, 4), (2, 2), wx.ALIGN_LEFT, 1)
359 btnsizer.Add(btns[4], (3, 4), (2, 2), wx.ALIGN_LEFT, 1)
360 btnsizer.Add((sx, sy), (5, 4), (1, 2), wx.ALIGN_LEFT, 1)
361 elif dtype.startswith('me4') and self.nmca == 4:
362 btnsizer.Add(btns[1], (0, 0), (1, 1), wx.ALIGN_LEFT, 1)
363 btnsizer.Add(btns[2], (1, 0), (1, 1), wx.ALIGN_LEFT, 1)
364 btnsizer.Add(btns[3], (1, 1), (1, 1), wx.ALIGN_LEFT, 1)
365 btnsizer.Add(btns[4], (0, 1), (1, 1), wx.ALIGN_LEFT, 1)
366 else:
367 NPERROW = 4
368 icol, irow = 0, 0
369 for nmca in range(1, self.nmca+1):
370 btnsizer.Add(btns[nmca], (irow, icol), (1, 1), wx.ALIGN_LEFT, 1)
371 icol += 1
372 if icol > NPERROW-1:
373 icol = 0
374 irow += 1
376 pack(btnpanel, btnsizer)
377 return btnpanel
379 def createEpicsPanel(self):
380 pane = wx.Panel(self, name='epics panel')
381 style = wx.ALIGN_LEFT
382 rstyle = wx.ALIGN_RIGHT
384 det_btnpanel = self.create_detbuttons(pane)
386 bkg_choices = ['None'] + ["%d" % (i+1) for i in range(self.nmca)]
388 self.wids['det_status'] = SimpleText(pane, ' ', size=(120, -1), style=style)
389 self.wids['deadtime'] = SimpleText(pane, ' ', size=(120, -1), style=style)
391 self.wids['bkg_det'] = Choice(pane, size=(100, -1), choices=bkg_choices,
392 action=self.onSelectDet)
394 self.wids['dwelltime'] = FloatCtrl(pane, value=0.0, precision=1, minval=0,
395 size=(80, -1), act_on_losefocus=True,
396 action=self.onSetDwelltime)
397 self.wids['elapsed'] = SimpleText(pane, ' ', size=(80, -1), style=style)
399 self.wids['mca_sum'] = Choice(pane, size=(100, -1),
400 choices=['Single', 'Accumulate'],
401 action=self.onMcaSumChoice,
402 default=1 )
404 b1 = Button(pane, 'Start', size=(90, -1), action=self.onStart)
405 b2 = Button(pane, 'Stop', size=(90, -1), action=self.onStop)
406 b3 = Button(pane, 'Erase', size=(90, -1), action=self.onErase)
407 b4 = Button(pane, 'Continuous', size=(90, -1), action=partial(self.onStart,
408 dtime=0.0))
410 sum_lab = SimpleText(pane, 'Accumulate Mode:', size=(150, -1))
411 bkg_lab = SimpleText(pane, 'Background MCA:', size=(150, -1))
412 pre_lab = SimpleText(pane, 'Dwell Time (s):', size=(125, -1))
413 ela_lab = SimpleText(pane, 'Elapsed Time (s):', size=(125, -1))
414 sta_lab = SimpleText(pane, 'Status :', size=(100, -1))
415 dea_lab = SimpleText(pane, '% Deadtime:', size=(100, -1))
417 psizer = wx.GridBagSizer(5, 5)
418 psizer.Add(SimpleText(pane, ' MCAs: '), (0, 0), (1, 1), style, 1)
419 psizer.Add(det_btnpanel, (0, 1), (2, 1), style, 1)
420 psizer.Add(bkg_lab, (0, 2), (1, 1), style, 1)
421 psizer.Add(self.wids['bkg_det'], (0, 3), (1, 1), style, 1)
422 psizer.Add(sum_lab, (1, 2), (1, 1), style, 1)
423 psizer.Add(self.wids['mca_sum'], (1, 3), (1, 1), style, 1)
424 psizer.Add(pre_lab, (0, 4), (1, 1), style, 1)
425 psizer.Add(ela_lab, (1, 4), (1, 1), style, 1)
426 psizer.Add(self.wids['dwelltime'], (0, 5), (1, 1), style, 1)
427 psizer.Add(self.wids['elapsed'], (1, 5), (1, 1), style, 1)
429 psizer.Add(b1, (0, 6), (1, 1), style, 1)
430 psizer.Add(b4, (0, 7), (1, 1), style, 1)
431 psizer.Add(b2, (1, 6), (1, 1), style, 1)
432 psizer.Add(b3, (1, 7), (1, 1), style, 1)
434 psizer.Add(sta_lab, (0, 8), (1, 1), style, 1)
435 psizer.Add(self.wids['det_status'], (0, 9), (1, 1), style, 1)
436 psizer.Add(dea_lab, (1, 8), (1, 1), style, 1)
437 psizer.Add(self.wids['deadtime'], (1, 9), (1, 1), style, 1)
438 pack(pane, psizer)
439 # pane.SetMinSize((500, 53))
440 self.det.connect_displays(status=self.wids['det_status'],
441 elapsed=self.wids['elapsed'])
443 wx.CallAfter(self.onSelectDet, index=1, init=True)
444 self.timer_counter = 0
445 self.mca_timer = wx.Timer(self)
446 self.Bind(wx.EVT_TIMER, self.UpdateData, self.mca_timer)
447 self.mca_timer.Start(250)
448 return pane
450 def UpdateData(self, event=None, force=False):
451 self.timer_counter += 1
452 if self.mca is None or self.needs_newplot:
453 self.show_mca()
454 # self.elapsed_real = self.det.elapsed_real
455 self.mca.real_time = self.det.elapsed_real
456 # print("Update Data ", force, self.det.needs_refresh)
458 if force or self.det.needs_refresh:
459 self.det.needs_refresh = False
460 if self.det_back > 0:
461 if self.mca2 is None:
462 self.mca2 = self.det.get_mca(mca=self.det_back)
464 counts = self.det.get_array(mca=self.det_back)
465 energy = self.det.get_energy(mca=self.det_back)
466 try:
467 self.update_mca(counts, energy=energy, is_mca2=True, draw=False)
468 except ValueError:
469 pass
471 if self.mca is None:
472 self.mca = self.det.get_mca(mca=self.det_fore)
474 dtime = self.det.get_deadtime(mca=self.det_fore)
475 if dtime is not None:
476 self.wids['deadtime'].SetLabel("%.1f" % dtime)
478 counts = self.det.get_array(mca=self.det_fore)*1.0
479 energy = self.det.get_energy(mca=self.det_fore)
480 if max(counts) < 1.0:
481 counts = 1e-4*np.ones(len(counts))
482 counts[0] = 2.0
483 self.update_mca(counts, energy=energy)
485 def ShowROIStatus(self, left, right, name='', panel=0):
486 if left > right:
487 return
488 sum = self.ydata[left:right].sum()
490 try:
491 ftime, nframes = self.det.get_frametime()
492 except:
493 ftime = self.det.frametime
494 nframes = self.det.nframes
495 self.det.elapsed_real = nframes * ftime
497 mca_counts = self.det.mcas[self.det_fore-1].get('VAL')
498 sum = mca_counts[left:right].sum()
499 # print("ROI STATUS ", name, ftime, nframes, sum, cps, mca_counts.sum(), mca_counts)
500 if name in (None, ''):
501 name = 'Selected'
502 else:
503 for roi in self.det.mcas[self.det_fore-1].rois:
504 if name.lower() == roi.name.lower():
505 try:
506 sum = roi.sum
507 except:
508 pass
509 cps = sum/ftime
510 if cps < 0: cps = 0
511 # print("ROI STATUS ", name, _counts, cps)
512 fmt = " {:s}: Cts={:10,.0f} :{:10,.1f} Hz"
513 self.write_message(fmt.format(name, sum, cps), panel=panel)
515 def onSelectDet(self, event=None, index=0, init=False, **kws):
516 if index > 0:
517 self.det_fore = index
518 self.det_back = self.wids['bkg_det'].GetSelection()
519 if self.det_fore == self.det_back:
520 self.det_back = 0
522 for i in range(1, self.nmca+1):
523 dname = 'det%i' % i
524 bcol = (210, 210, 210)
525 fcol = (0, 0, 0)
526 if i == self.det_fore:
527 fcol = (200, 20, 20)
528 bcol = (250, 250, 250)
529 self.wids[dname].SetBackgroundColour(bcol)
530 self.wids[dname].SetForegroundColour(fcol)
531 self.clear_mcas()
532 self.show_mca(init=init)
533 self.Refresh()
535 def swap_mcas(self, event=None):
536 if self.mca2 is None:
537 return
538 self.mca, self.mca2 = self.mca2, self.mca
539 fore, back = self.det_fore, self.det_back
540 self.wids['bkg_det'].SetSelection(fore)
541 self.onSelectDet(index=back)
543 def onMcaSumChoice(self, event=None):
544 wid = self.wids['mca_sum']
545 self.det.set_usesum('accum' in wid.GetStringSelection().lower())
547 def onSetDwelltime(self, event=None, **kws):
548 if 'dwelltime' in self.wids:
549 self.det.set_dwelltime(dtime=self.wids['dwelltime'].GetValue())
551 def clear_mcas(self):
552 self.mca = self.mca2 = None
553 self.x2data = self.y2data = None
554 self.needs_newplot = True
556 def onStart(self, event=None, dtime=None, **kws):
557 if dtime is not None:
558 self.wids['dwelltime'].SetValue("%.1f" % dtime)
559 self.det.set_dwelltime(dtime=dtime)
560 else:
561 self.det.set_dwelltime(dtime=self.wids['dwelltime'].GetValue())
562 self.det.start()
564 def onStop(self, event=None, **kws):
565 self.det.stop()
566 self.det.needs_refresh = True
567 time.sleep(0.05)
568 self.UpdateData(event=None, force=True)
570 def onErase(self, event=None, **kws):
571 self.needs_newplot = True
572 self.det.erase()
574 def onDelROI(self, event=None):
575 roiname = self.get_roiname()
576 errmsg = None
577 t0 = time.time()
578 if self.roilist_sel is None:
579 errmsg = 'No ROI selected to delete.'
580 if errmsg is not None:
581 return Popup(self, errmsg, 'Cannot Delete ROI')
583 self.det.del_roi(roiname)
584 XRFDisplayFrame.onDelROI(self)
587 def onNewROI(self, event=None):
588 roiname = self.get_roiname()
589 errmsg = None
590 if self.xmarker_left is None or self.xmarker_right is None:
591 errmsg = 'Must select right and left markers to define ROI'
592 elif roiname in self.wids['roilist'].GetStrings():
593 errmsg = '%s is already in ROI list - use a unique name.' % roiname
594 if errmsg is not None:
595 return Popup(self, errmsg, 'Cannot Define ROI')
597 confirmed = XRFDisplayFrame.onNewROI(self)
598 if confirmed:
599 self.det.add_roi(roiname, lo=self.xmarker_left,
600 hi=self.xmarker_right)
602 def onRenameROI(self, event=None):
603 roiname = self.get_roiname()
604 errmsg = None
605 if roiname in self.wids['roilist'].GetStrings():
606 errmsg = '%s is already in ROI list - use a unique name.' % roiname
607 elif self.roilist_sel is None:
608 errmsg = 'No ROI selected to rename.'
609 if errmsg is not None:
610 return Popup(self, errmsg, 'Cannot Rename ROI')
612 if self.roilist_sel < len(self.det.mcas[0].rois):
613 self.det.rename_roi(self.roilist_sel, roiname)
614 names = self.wids['roilist'].GetStrings()
615 names[self.roilist_sel] = roiname
616 self.wids['roilist'].Clear()
617 for sname in names:
618 self.wids['roilist'].Append(sname)
619 self.wids['roilist'].SetSelection(self.roilist_sel)
621 def onCalibrateEnergy(self, event=None, **kws):
622 try:
623 self.win_calib.Raise()
624 except:
625 self.win_calib = XRFCalibrationFrame(self, mca=self.mca,
626 larch=self.larch,
627 callback=self.onSetCalib)
629 def onSetCalib(self, offset, slope, mca=None):
630 print('XRFControl Set Energy Calibratione' , offset, slope, mca)
632 def onClose(self, event=None):
633 self.onStop()
634 XRFDisplayFrame.onClose(self)
636 def onExit(self, event=None):
637 self.onStop()
638 XRFDisplayFrame.onExit(self)
640class EpicsXRFApp(LarchWxApp):
641 def __init__(self, _larch=None, prefix=None,
642 det_type='ME-4', ioc_type='Xspress3', nmca=4,
643 size=(725, 580), environ_file=None,
644 title='Epics XRF Display', output_title='XRF', **kws):
645 self.prefix = prefix
646 self.det_type = det_type
647 self.ioc_type = ioc_type
648 self.nmca = nmca
649 self.size = size
650 self.environ_file = environ_file
651 self.title = title
652 self.output_title = output_title
653 LarchWxApp.__init__(self, _larch=_larch, **kws)
655 def createApp(self):
656 frame = EpicsXRFDisplayFrame(prefix=self.prefix,
657 det_type=self.det_type,
658 ioc_type=self.ioc_type,
659 nmca=self.nmca, size=self.size,
660 environ_file=self.environ_file,
661 title=self.title,
662 output_title=self.output_title,
663 _larch=self._larch)
664 frame.Show()
665 self.SetTopWindow(frame)
666 return True
668if __name__ == "__main__":
669 EpicsXRFApp().MainLoop()