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

1#!/usr/bin/env python 

2""" 

3XRF Analysis Panel 

4""" 

5import os 

6import json 

7from functools import partial 

8 

9import wx 

10import wx.lib.scrolledpanel as scrolled 

11 

12import numpy as np 

13 

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 

19 

20from ..xrmmap import GSEXRM_MapFile, GSEXRM_FileStatus, h5str, ensure_subgroup 

21 

22from ..wxlib.xrfdisplay_utils import (XRFGROUP, mcaname, 

23 XRFRESULTS_GROUP, 

24 MAKE_XRFRESULTS_GROUP) 

25 

26CEN = wx.ALIGN_CENTER 

27LEFT = wx.ALIGN_LEFT 

28RIGHT = wx.ALIGN_RIGHT 

29ALL_CEN = wx.ALL|CEN 

30ALL_LEFT = wx.ALL|LEFT 

31 

32NOFITS_MSG = "No XRF Fits: Use XRFViewer to fit spectrum." 

33HASFITS_MSG = "Select XRF Fit to build elemental maps" 

34 

35from ..wxlib.xrfdisplay_utils import (XRFGROUP, MAKE_XRFGROUP_CMD, next_mcaname) 

36 

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=[]) 

49 

50 self.use_nnls = Check(self, label='force non-negative (~5x slower)', 

51 default=False) 

52 

53 save_btn = Button(self, 'Calculate Element Maps', size=(200, -1), 

54 action=self.onSaveArrays) 

55 

56 load_btn = Button(self, 'Load Saved XRF Model', size=(200, -1), 

57 action=self.onLoadXRFModel) 

58 

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) 

63 

64 self.fit_status = SimpleText(self, label=NOFITS_MSG) 

65 

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) 

69 

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) 

73 

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) 

78 

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) 

85 

86 ir += 1 

87 sizer.Add(HLine(self, size=(600, 5)), (ir, 0), (1, 4), ALL_LEFT, 2) 

88 

89 pack(self, sizer) 

90 self.SetupScrolling() 

91 

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 

102 

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 

112 

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) 

125 

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 (*.*)|*.*" 

130 

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

149 

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] 

157 

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)