Coverage for /Users/Newville/Codes/xraylarch/larch/wxmap/mapxrfpanel.py: 23%
112 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"""
3XRF Analysis Panel
4"""
5import os
6import json
7from functools import partial
9import wx
10import wx.lib.scrolledpanel as scrolled
12import numpy as np
14from ..wxlib import (LarchPanel, LarchFrame, EditableListBox, SimpleText,
15 FloatCtrl, Font, pack, Popup, Button, MenuItem,
16 Choice, Check, GridPanel, FileSave, FileOpen, HLine)
17from ..utils.strutils import bytes2str, version_ge, fix_varname
18from ..utils import get_cwd
20from ..xrmmap import GSEXRM_MapFile, GSEXRM_FileStatus, h5str, ensure_subgroup
22from ..wxlib.xrfdisplay_utils import (XRFGROUP, mcaname,
23 XRFRESULTS_GROUP,
24 MAKE_XRFRESULTS_GROUP)
26CEN = wx.ALIGN_CENTER
27LEFT = wx.ALIGN_LEFT
28RIGHT = wx.ALIGN_RIGHT
29ALL_CEN = wx.ALL|CEN
30ALL_LEFT = wx.ALL|LEFT
32NOFITS_MSG = "No XRF Fits: Use XRFViewer to fit spectrum."
33HASFITS_MSG = "Select XRF Fit to build elemental maps"
35from ..wxlib.xrfdisplay_utils import (XRFGROUP, MAKE_XRFGROUP_CMD, next_mcaname)
37class XRFAnalysisPanel(scrolled.ScrolledPanel):
38 """Panel of XRF Analysis results"""
39 label = 'XRF Analysis'
40 def __init__(self, parent, owner=None, **kws):
41 self.owner = owner
42 self.map = None
43 self.cfile = None
44 scrolled.ScrolledPanel.__init__(self, parent, -1,
45 style=wx.GROW|wx.TAB_TRAVERSAL, **kws)
46 sizer = wx.GridBagSizer(3, 3)
47 self.current_fit = 0
48 self.fit_choice = Choice(self, size=(400, -1), choices=[])
50 self.use_nnls = Check(self, label='force non-negative (~5x slower)',
51 default=False)
53 save_btn = Button(self, 'Calculate Element Maps', size=(200, -1),
54 action=self.onSaveArrays)
56 load_btn = Button(self, 'Load Saved XRF Model', size=(200, -1),
57 action=self.onLoadXRFModel)
59 self.scale = FloatCtrl(self, value=1.0, minval=0, precision=5, size=(100, -1))
60 self.name = wx.TextCtrl(self, value='abundance', size=(200, -1))
61 self.warn_overwrite = Check(self, label='warn about overwriting group?',
62 default=True)
64 self.fit_status = SimpleText(self, label=NOFITS_MSG)
66 ir = 0
67 sizer.Add(self.fit_status, (ir, 0), (1, 2), ALL_LEFT, 2)
68 sizer.Add(load_btn, (ir, 2), (1, 2), ALL_LEFT, 2)
70 ir += 1
71 sizer.Add(SimpleText(self, 'Use Fit Label:'), (ir, 0), (1, 1), ALL_LEFT, 2)
72 sizer.Add(self.fit_choice, (ir, 1), (1, 3), ALL_LEFT, 2)
74 ir += 1
75 sizer.Add(SimpleText(self, 'Scaling Factor:'), (ir, 0), (1, 1), ALL_LEFT, 2)
76 sizer.Add(self.scale, (ir, 1), (1, 1), ALL_LEFT, 2)
77 sizer.Add(self.use_nnls, (ir, 2), (1, 2), ALL_LEFT, 2)
79 ir += 1
80 sizer.Add(SimpleText(self, 'Save to Group:'), (ir, 0), (1, 1), ALL_LEFT, 2)
81 sizer.Add(self.name, (ir, 1), (1, 1), ALL_LEFT, 2)
82 sizer.Add(self.warn_overwrite, (ir, 2), (1, 2), ALL_LEFT, 2)
83 ir += 1
84 sizer.Add(save_btn, (ir, 0), (1, 3), ALL_LEFT, 2)
86 ir += 1
87 sizer.Add(HLine(self, size=(600, 5)), (ir, 0), (1, 4), ALL_LEFT, 2)
89 pack(self, sizer)
90 self.SetupScrolling()
92 def onSaveArrays(self, evt=None):
93 self.current_fit = cfit = self.fit_choice.GetSelection()
94 try:
95 thisfit = self.owner.larch.symtable._xrfresults[cfit]
96 except:
97 thisfit = None
98 if thisfit is None:
99 print("Unknown fit? " , cfit,
100 self.owner.larch.symtable._xrfresults)
101 return
103 scale = self.scale.GetValue()
104 method = 'nnls' if self.use_nnls.IsChecked() else 'lstsq'
105 xrmfile = self.owner.current_file
106 workname = fix_varname(self.name.GetValue())
107 if self.warn_overwrite.IsChecked() and workname in xrmfile.get_detector_list(use_cache=False) :
108 ret = Popup(self,
109 f"A group named '{workname:s}' exists\n overwrite it with new arrays?",
110 f"overwrite group '{workname:s}'?", style=wx.YES_NO)
111 if ret != wx.ID_YES: return
113 cmd = """weights = _xrfresults[{cfit:d}].decompose_map({groupname:s}.xrmmap['mcasum/counts'],
114 scale={scale:.6f}, pixel_time={ptime:.5f},method='{method:s}')
115{groupname:s}.add_work_arrays(weights, parent='{workname:s}')
116 """
117 cmd = cmd.format(cfit=cfit, groupname=xrmfile.groupname, ptime=xrmfile.pixeltime,
118 workname=workname, scale=scale, method=method)
119 self.owner.larch.eval(cmd)
120 dlist = xrmfile.get_detector_list(use_cache=False)
121 for p in self.owner.nb.pagelist:
122 if hasattr(p, 'update_xrmmap'):
123 p.detectors_set = False
124 p.update_xrmmap(xrmfile=xrmfile, set_detectors=True)
126 def onLoadXRFModel(self, evt=None):
127 _larch = self.owner.larch
128 symtab = _larch.symtable
129 FILE_WILDCARDS = "XRF Model Files(*.xrfmodel)|*.xrfmodel|All files (*.*)|*.*"
131 dlg = wx.FileDialog(self, message="Read XRF Model File",
132 defaultDir=get_cwd(),
133 wildcard=FILE_WILDCARDS,
134 style=wx.FD_OPEN)
135 path = None
136 if dlg.ShowModal() == wx.ID_OK:
137 path = dlg.GetPath()
138 dlg.Destroy()
139 if path is not None:
140 _, fname = os.path.split(path)
141 if not symtab.has_group(XRFRESULTS_GROUP):
142 _larch.eval(MAKE_XRFRESULTS_GROUP)
143 _larch.eval("tmp = xrf_fitresult('{:s}')".format(path))
144 _larch.eval("tmp.filename = '{:s}'".format(fname))
145 _larch.eval("_xrfresults.insert(0, tmp)")
146 _larch.eval("del tmp")
147 self.current_fit = 0
148 self.update_xrmmap()
150 def update_xrmmap(self, xrmfile=None, set_detectors=None):
151 if xrmfile is None:
152 xrmfile = self.owner.current_file
153 self.cfile = xrmfile
154 symtab = self.owner.larch.symtable
155 xrfresults = getattr(symtab, '_xrfresults', [])
156 fit_names = ["%s: %s" % (a.label, a.mcalabel) for a in xrfresults]
158 if len(fit_names) > 0:
159 self.fit_status.SetLabel(HASFITS_MSG)
160 self.fit_choice.Clear()
161 self.fit_choice.AppendItems(fit_names)
162 self.fit_choice.SetSelection(self.current_fit)