Changeset 2082
- Timestamp:
- Dec 4, 2015 10:50:58 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/GSASIIgrid.py
r2036 r2082 1110 1110 self.ImageEdit.Append(help='Load image controls from file', 1111 1111 id=wxID_IMLOADCONTROLS, kind=wx.ITEM_NORMAL,text='Load Controls') 1112 if GSASIIpath.GetConfigValue('debug'): 1113 import autoint 1114 self.ImageEdit.Append(help='Open Auto-integration window to integrate a series of images', 1115 id=wxID_IMAUTOINTEG, kind=wx.ITEM_NORMAL,text='Auto Integrate') 1112 self.ImageEdit.Append(help='Open Auto-integration window to integrate a series of images', 1113 id=wxID_IMAUTOINTEG, kind=wx.ITEM_NORMAL,text='Auto Integrate') 1116 1114 self.PostfillDataMenu() 1117 1115 -
trunk/GSASIIimgGUI.py
r2065 r2082 15 15 16 16 ''' 17 import os.path 18 import wx 19 import wx.lib.scrolledpanel as wxscroll 20 import matplotlib as mpl 17 import os 18 import copy 19 import glob 20 import re 21 import bisect 21 22 import math 22 23 import time 23 24 import copy 25 import sys 26 import wx 27 import wx.lib.scrolledpanel as wxscroll 28 import wx.lib.mixins.listctrl as listmix 29 import matplotlib as mpl 30 import numpy as np 24 31 import GSASIIpath 25 32 GSASIIpath.SetVersionNumber("$Revision$") … … 30 37 import GSASIIgrid as G2gd 31 38 import GSASIIctrls as G2G 32 import numpy as np39 import GSASIIpy3 as G2py3 33 40 34 41 VERY_LIGHT_GREY = wx.Colour(235,235,235) … … 220 227 G2gd.GetPatternTreeItemId(G2frame,id, 'Masks')) 221 228 except TypeError: #missing Masks 229 # I think the next line should be 'range'! (BHT) 222 230 Imin,Imax = Data['Range'] 223 231 Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]} … … 1058 1066 G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveControls, id=G2gd.wxID_IMSAVECONTROLS) 1059 1067 G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadControls, id=G2gd.wxID_IMLOADCONTROLS) 1060 if GSASIIpath.GetConfigValue('debug'): 1061 import autoint 1062 def OnDestroy(event): 1063 G2frame.autoIntFrame = None 1064 def OnAutoInt(event): 1065 reload(autoint) 1066 if G2frame.autoIntFrame: # ensure only one open at a time 1067 G2frame.autoIntFrame.Raise() 1068 return 1069 G2frame.autoIntFrame = autoint.AutoIntFrame(G2frame,PollTime=5.0) 1070 G2frame.autoIntFrame.Bind(wx.EVT_WINDOW_DESTROY,OnDestroy) # clean up name on window close 1071 G2frame.dataFrame.Bind(wx.EVT_MENU, OnAutoInt, id=G2gd.wxID_IMAUTOINTEG) 1068 def OnDestroy(event): 1069 G2frame.autoIntFrame = None 1070 def OnAutoInt(event): 1071 if G2frame.autoIntFrame: # ensure only one open at a time 1072 G2frame.autoIntFrame.Raise() 1073 return 1074 G2frame.autoIntFrame = AutoIntFrame(G2frame,PollTime=10.0) 1075 G2frame.autoIntFrame.Bind(wx.EVT_WINDOW_DESTROY,OnDestroy) # clean up name on window close 1076 G2frame.dataFrame.Bind(wx.EVT_MENU, OnAutoInt, id=G2gd.wxID_IMAUTOINTEG) 1072 1077 G2frame.dataDisplay = wx.Panel(G2frame.dataFrame) 1073 1078 … … 1183 1188 if dlg.ShowModal() == wx.ID_OK: 1184 1189 filename = dlg.GetPath() 1190 filename = os.path.splitext(filename)[0]+'.immask' 1185 1191 File = open(filename,'w') 1186 1192 save = {} … … 1872 1878 G2frame.dataDisplay.SetSize(Size) 1873 1879 G2frame.dataFrame.setSizePosLeft(Size) 1880 1881 ########################################################################### 1882 # Autointegration follows 1883 def ReadMask(filename): 1884 'Read a mask (.immask) file' 1885 File = open(filename,'r') 1886 save = {} 1887 S = File.readline() 1888 while S: 1889 if S[0] == '#': 1890 S = File.readline() 1891 continue 1892 [key,val] = S[:-1].split(':') 1893 if key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']: 1894 save[key] = eval(val) 1895 S = File.readline() 1896 File.close() 1897 CleanupMasks(save) 1898 return save 1899 1900 def ReadControls(filename): 1901 'read an image controls (.imctrl) file' 1902 cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type', 1903 'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth', 1904 'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg', 1905 'PolaVal','SampleAbs','dark image','background image'] 1906 File = open(filename,'r') 1907 save = {} 1908 S = File.readline() 1909 while S: 1910 if S[0] == '#': 1911 S = File.readline() 1912 continue 1913 [key,val] = S[:-1].split(':') 1914 if key in ['type','calibrant','binType','SampleShape',]: #strings 1915 save[key] = val 1916 elif key in ['rotation']: 1917 save[key] = float(val) 1918 elif key in ['center',]: 1919 if ',' in val: 1920 save[key] = eval(val) 1921 else: 1922 vals = val.strip('[] ').split() 1923 save[key] = [float(vals[0]),float(vals[1])] 1924 elif key in cntlList: 1925 save[key] = eval(val) 1926 S = File.readline() 1927 File.close() 1928 return save 1929 1930 def Read_imctrl(imctrl_file): 1931 '''Read an image control file and record control parms into a dict, with some simple 1932 type conversions 1933 ''' 1934 file_opt = options = {} 1935 save = {'filename':imctrl_file} 1936 immask_file = os.path.splitext(imctrl_file)[0]+'.immask' 1937 if os.path.exists(immask_file): 1938 save['maskfile'] = immask_file 1939 else: 1940 save['maskfile'] = '(none)' 1941 cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type', 1942 'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth', 1943 'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg', 1944 'PolaVal','SampleAbs','dark image','background image'] 1945 File = open(imctrl_file,'r') 1946 fullIntegrate = False 1947 try: 1948 S = File.readline() 1949 while S: 1950 if S[0] == '#': 1951 S = File.readline() 1952 continue 1953 [key,val] = S[:-1].split(':') 1954 if key in ['type','calibrant','binType','SampleShape',]: #strings 1955 save[key] = val 1956 elif key == 'rotation': 1957 save[key] = float(val) 1958 elif key == 'fullIntegrate': 1959 fullIntegrate = eval(val) 1960 elif key == 'LRazimuth': 1961 save['LRazimuth_min'],save['LRazimuth_max'] = eval(val)[0:2] 1962 elif key == 'IOtth': 1963 save['IOtth_min'],save['IOtth_max'] = eval(val)[0:2] 1964 elif key == 'center': 1965 if ',' in val: 1966 vals = eval(val) 1967 else: 1968 vals = val.strip('[] ').split() 1969 vals = [float(vals[0]),float(vals[1])] 1970 save['center_x'],save['center_y'] = vals[0:2] 1971 elif key in cntlList: 1972 save[key] = eval(val) 1973 S = File.readline() 1974 finally: 1975 File.close() 1976 if fullIntegrate: save['LRazimuth_min'],save['LRazimuth_max'] = 0,0 1977 return save 1978 1979 class AutoIntFrame(wx.Frame): 1980 '''Creates a wx.Frame window for the Image AutoIntegration. 1981 The intent is that this will be used as a non-modal dialog window. 1982 1983 Implements a Start button that morphs into a pause and resume button. 1984 This button starts a processing loop that is repeated every 1985 :meth:`PollTime` seconds. 1986 1987 :param wx.Frame G2frame: main GSAS-II frame 1988 :param float PollTime: frequency in seconds to repeat calling the 1989 processing loop. (Default is 3.0 seconds.) 1990 ''' 1991 def OnTimerLoop(self,event): 1992 '''A method that is called every :meth:`PollTime` seconds that is 1993 used to check for new files and process them. This is called only 1994 after the "Start" button is pressed (when its label reads "Pause"). 1995 ''' 1996 G2frame = self.G2frame 1997 try: 1998 self.currImageList = sorted( 1999 glob.glob(os.path.join(self.imagedir,self.params['filter']))) 2000 except IndexError: 2001 self.currImageList = [] 2002 return 2003 2004 # Create a list of image files that have already been read 2005 imageFileList = [] 2006 for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']): 2007 imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img) 2008 size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId) 2009 if imagefile not in imageFileList: imageFileList.append(imagefile) 2010 # loop over image files matching glob, reading in new ones 2011 for newImage in self.currImageList: 2012 if newImage in imageFileList: continue # already read 2013 for imgId in G2IO.ReadImages(G2frame,newImage): 2014 controlsDict = G2frame.PatternTree.GetItemPyData( 2015 G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls')) 2016 ImageMasks = G2frame.PatternTree.GetItemPyData( 2017 G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks')) 2018 if self.params['Mode'] == 'table': 2019 dist = controlsDict['distance'] 2020 interpDict,imgctrl,immask = self.Evaluator(dist) # interpolated calibration values 2021 if GSASIIpath.GetConfigValue('debug'): 2022 print 'interpolated: ',interpDict 2023 self.ImageControls = ReadControls(imgctrl) 2024 self.ImageControls.update(interpDict) 2025 self.ImageControls['showLines'] = True 2026 self.ImageControls['ring'] = [] 2027 self.ImageControls['rings'] = [] 2028 self.ImageControls['ellipses'] = [] 2029 self.ImageControls['setDefault'] = False 2030 for i in 'range','size','GonioAngles': 2031 if i in self.ImageControls: 2032 del self.ImageControls[i] 2033 # load copy of Image Masks 2034 if immask: 2035 self.ImageMasks = ReadMask(immask) 2036 del self.Thresholds['Thresholds'] 2037 else: 2038 self.ImageMasks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[]} 2039 # update controls from master 2040 controlsDict.update(self.ImageControls) 2041 # update masks from master w/o Thresholds 2042 ImageMasks.update(self.ImageMasks) 2043 # now integrate the images that have not already been processed before 2044 for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']): 2045 if img in G2frame.IntegratedList: continue 2046 G2frame.IntegratedList.append(img) 2047 imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img) 2048 G2frame.Image = imgId 2049 G2frame.PickId = G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls') 2050 # integrate in this entry 2051 size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId) 2052 G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,True,imagetag) 2053 masks = G2frame.PatternTree.GetItemPyData( 2054 G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks')) 2055 data = G2frame.PatternTree.GetItemPyData(G2frame.PickId) 2056 self.oldImagefile = '' # mark image as changed; reread as needed 2057 # simulate a Image Controls press, since that is where the 2058 # integration is hidden 2059 UpdateImageControls(G2frame,data,masks,IntegrateOnly=True) 2060 # split name and control number 2061 s = re.split(r'(\d+)\Z',os.path.split(os.path.splitext(imagefile)[0])[1]) 2062 namepre = s[0] 2063 if len(s) > 1: 2064 namenum = s[1] 2065 else: 2066 namenum = '' 2067 # write out the images in the selected formats and save the names, 2068 # reset will delete them 2069 for Id in G2frame.IntgOutList: 2070 treename = G2frame.PatternTree.GetItemText(Id) 2071 G2frame.AutointPWDRnames.append(treename) 2072 Sdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters')) 2073 # determine the name for the current file 2074 fileroot = namepre 2075 if len(G2frame.IntgOutList) > 1: 2076 fileroot += "_AZM" 2077 if 'Azimuth' in Sdata: 2078 fileroot += str(int(10*Sdata['Azimuth'])) 2079 fileroot += "_" 2080 fileroot += namenum 2081 # loop over selected formats 2082 for dfmt in self.fmtlist: 2083 if not self.params[dfmt[1:]]: continue 2084 if self.params['SeparateDir']: 2085 subdir = dfmt[1:] 2086 else: 2087 subdir = '' 2088 fil = os.path.join(self.params['outdir'],subdir,fileroot) 2089 print('writing file '+fil+dfmt) 2090 G2IO.ExportPowder(G2frame,treename,fil,dfmt) 2091 2092 if GSASIIpath.GetConfigValue('debug'): 2093 import datetime 2094 print ("Timer tick at {:%d %b %Y %H:%M:%S}\n".format(datetime.datetime.now())) 2095 2096 def StartLoop(self): 2097 '''Save current Image params for use in future integrations 2098 also label the window so users understand whatis being used 2099 ''' 2100 print '\nStarting new autointegration\n' 2101 G2frame = self.G2frame 2102 # show current IMG base 2103 self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image)) 2104 if self.params['Mode'] != 'table': 2105 # load copy of Image Controls from current image and clean up 2106 # items that should not be copied 2107 self.ImageControls = copy.deepcopy( 2108 G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId( 2109 G2frame,G2frame.Image, 'Image Controls'))) 2110 self.ImageControls['showLines'] = True 2111 self.ImageControls['ring'] = [] 2112 self.ImageControls['rings'] = [] 2113 self.ImageControls['ellipses'] = [] 2114 self.ImageControls['setDefault'] = False 2115 del self.ImageControls['range'] 2116 del self.ImageControls['size'] 2117 del self.ImageControls['GonioAngles'] 2118 # load copy of Image Masks, keep thresholds 2119 self.ImageMasks = copy.deepcopy( 2120 G2frame.PatternTree.GetItemPyData( 2121 G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))) 2122 self.Thresholds = self.ImageMasks['Thresholds'][:] 2123 # make sure all output directories exist 2124 if self.params['SeparateDir']: 2125 for dfmt in self.fmtlist: 2126 if not self.params[dfmt[1:]]: continue 2127 dir = os.path.join(self.params['outdir'],dfmt[1:]) 2128 if not os.path.exists(dir): os.makedirs(dir) 2129 else: 2130 if not os.path.exists(self.params['outdir']): 2131 os.makedirs(self.params['outdir']) 2132 if self.Reset: # special things to do after Reset has been pressed 2133 # reset controls and masks for all IMG items in tree to master 2134 for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']): 2135 # update controls from master 2136 controlsDict = G2frame.PatternTree.GetItemPyData( 2137 G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls')) 2138 controlsDict.update(self.ImageControls) 2139 # update masks from master 2140 ImageMasks = G2frame.PatternTree.GetItemPyData( 2141 G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks')) 2142 ImageMasks.update(self.ImageMasks) 2143 # delete all PWDR items created after last Start was pressed 2144 idlist = [] 2145 item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root) 2146 while item: 2147 itemName = G2frame.PatternTree.GetItemText(item) 2148 if itemName in G2frame.AutointPWDRnames: 2149 idlist.append(item) 2150 item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie) 2151 for item in idlist: 2152 G2frame.PatternTree.Delete(item) 2153 self.Reset = False 2154 G2frame.AutointPWDRnames = [] # list of created PWDR tree item names 2155 2156 def __init__(self,G2frame,PollTime=60.0): 2157 def OnStart(event): 2158 '''Called when the start button is pressed. Changes button label 2159 to Pause. When Pause is pressed the label changes to Resume. 2160 When either Start or Resume is pressed, the processing loop 2161 is started. When Pause is pressed, the loop is stopped. 2162 ''' 2163 # check inputs for errors before starting 2164 #err = '' 2165 #if not any([self.params[fmt] for fmt in self.fmtlist]): 2166 # err += '\nPlease select at least one output format\n' 2167 #if err: 2168 # G2G.G2MessageBox(self,err) 2169 # return 2170 # change button label 2171 if btnstart.GetLabel() != 'Pause': 2172 btnstart.SetLabel('Pause') 2173 if self.timer.IsRunning(): self.timer.Stop() 2174 self.StartLoop() 2175 self.OnTimerLoop(None) # run once immediately and again after delay 2176 self.timer.Start(int(1000*PollTime),oneShot=False) 2177 self.Status.SetStatusText('Press Pause to delay integration or Reset to prepare to reintegrate all images') 2178 else: 2179 btnstart.SetLabel('Resume') 2180 if self.timer.IsRunning(): self.timer.Stop() 2181 print('\nPausing autointegration\n') 2182 self.Status.SetStatusText('Press Resume to continue integration or Reset to prepare to reintegrate all images') 2183 2184 def OnReset(event): 2185 '''Called when Reset button is pressed. This stops the 2186 processing loop and resets the list of integrated files so 2187 all images can be reintegrated. 2188 ''' 2189 btnstart.SetLabel('Restart') 2190 self.Status.SetStatusText('Press Restart to reload and re-integrate images matching filter') 2191 if self.timer.IsRunning(): self.timer.Stop() 2192 self.Reset = True 2193 self.G2frame.IntegratedList = [] 2194 2195 def OnQuit(event): 2196 '''Stop the processing loop and close the Frame 2197 ''' 2198 if self.timer.IsRunning(): self.timer.Stop() # make sure we stop first 2199 wx.CallAfter(self.Destroy) 2200 2201 def OnBrowse(event): 2202 '''Responds when the Browse button is pressed to load a file. 2203 The routine determines which button was pressed and gets the 2204 appropriate file type and loads it into the appropriate place 2205 in the dict. 2206 ''' 2207 if btn3 == event.GetEventObject(): 2208 dlg = wx.DirDialog( 2209 self, 'Select directory for output files', 2210 self.params['outdir'],wx.DD_DEFAULT_STYLE) 2211 dlg.CenterOnParent() 2212 try: 2213 if dlg.ShowModal() == wx.ID_OK: 2214 self.params['outdir'] = dlg.GetPath() 2215 fInp3.SetValue(self.params['outdir']) 2216 finally: 2217 dlg.Destroy() 2218 return 2219 2220 def OnRadioSelect(event): 2221 '''Respond to a radiobutton selection and when in table 2222 mode, get parameters from user. 2223 ''' 2224 self.Evaluator = None 2225 if r2.GetValue(): 2226 self.params['Mode'] = 'table' 2227 try: 2228 dlg = IntegParmTable(self.G2frame) # create the dialog 2229 if dlg.ShowModal() == wx.ID_OK: 2230 self.Evaluator = DefineEvaluator(dlg) 2231 else: 2232 r1.SetValue(True) 2233 finally: 2234 dlg.Destroy() 2235 else: 2236 self.params['Mode'] = 'active' 2237 ################################################## 2238 # beginning of __init__ processing 2239 ################################################## 2240 self.G2frame = G2frame 2241 self.Evaluator = None 2242 self.params = {} 2243 self.Reset = False 2244 self.params['IMGfile'] = '' 2245 self.params['MaskFile'] = '' 2246 self.params['IgnoreMask'] = True 2247 self.fmtlist = G2IO.ExportPowderList(G2frame) 2248 self.timer = wx.Timer() 2249 self.timer.Bind(wx.EVT_TIMER,self.OnTimerLoop) 2250 2251 controlsId = G2frame.PatternTree.GetSelection() 2252 size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(G2frame.Image) 2253 self.imagedir,fileroot = os.path.split(imagefile) 2254 self.params['filter'] = '*'+os.path.splitext(fileroot)[1] 2255 self.params['outdir'] = os.path.abspath(self.imagedir) 2256 wx.Frame.__init__(self, G2frame,title='Automatic Integration') 2257 self.Status = self.CreateStatusBar() 2258 self.Status.SetStatusText('Press Start to load and integrate images matching filter') 2259 mnpnl = wx.Panel(self) 2260 mnsizer = wx.BoxSizer(wx.VERTICAL) 2261 sizer = wx.BoxSizer(wx.HORIZONTAL) 2262 sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Integration based on: ')) 2263 self.ControlBaseLbl = wx.StaticText(mnpnl, wx.ID_ANY,'?') 2264 self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image)) 2265 sizer.Add(self.ControlBaseLbl) 2266 mnsizer.Add(sizer,0,wx.ALIGN_LEFT,1) 2267 # file filter stuff 2268 sizer = wx.BoxSizer(wx.HORIZONTAL) 2269 sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Image filter')) 2270 flterInp = G2G.ValidatedTxtCtrl(mnpnl,self.params,'filter') 2271 sizer.Add(flterInp) 2272 mnsizer.Add(sizer,0,wx.ALIGN_RIGHT,1) 2273 # box for integration controls & masks input 2274 lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Integration Controls/Masks source") 2275 lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL) 2276 r1 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use Active Image", 2277 style = wx.RB_GROUP) 2278 r1.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect) 2279 lblsizr.Add(r1) 2280 r1.SetValue(True) 2281 r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use from table") 2282 lblsizr.Add(r2) 2283 r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect) 2284 mnsizer.Add(lblsizr) 2285 2286 # box for output selections 2287 lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Output settings") 2288 lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL) 2289 sizer = wx.BoxSizer(wx.HORIZONTAL) 2290 sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Write to: ')) 2291 fInp3 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'outdir', 2292 notBlank=False,size=(300,-1)) 2293 sizer.Add(fInp3) 2294 btn3 = wx.Button(mnpnl, wx.ID_ANY, "Browse") 2295 btn3.Bind(wx.EVT_BUTTON, OnBrowse) 2296 sizer.Add(btn3) 2297 lblsizr.Add(sizer) 2298 #lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): ')) 2299 sizer = wx.BoxSizer(wx.HORIZONTAL) 2300 sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): ')) 2301 for dfmt in self.fmtlist: 2302 fmt = dfmt[1:] 2303 self.params[fmt] = False 2304 btn = G2G.G2CheckBox(mnpnl,dfmt,self.params,fmt) 2305 sizer.Add(btn) 2306 lblsizr.Add(sizer) 2307 sizer = wx.BoxSizer(wx.HORIZONTAL) 2308 sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Separate dir for each format: ')) 2309 self.params['SeparateDir'] = False 2310 sizer.Add(G2G.G2CheckBox(mnpnl,'',self.params,'SeparateDir')) 2311 lblsizr.Add(sizer) 2312 mnsizer.Add(lblsizr,0,wx.ALIGN_CENTER,1) 2313 2314 # buttons on bottom 2315 mnsizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'AutoIntegration controls'),0,wx.TOP,5) 2316 sizer = wx.BoxSizer(wx.HORIZONTAL) 2317 sizer.Add((20,-1)) 2318 btnstart = wx.Button(mnpnl, wx.ID_ANY, "Start") 2319 btnstart.Bind(wx.EVT_BUTTON, OnStart) 2320 sizer.Add(btnstart) 2321 btnstop = wx.Button(mnpnl, wx.ID_ANY, "Reset") 2322 btnstop.Bind(wx.EVT_BUTTON, OnReset) 2323 sizer.Add(btnstop) 2324 sizer.Add((20,-1),wx.EXPAND,1) 2325 btnquit = wx.Button(mnpnl, wx.ID_ANY, "Close") 2326 btnquit.Bind(wx.EVT_BUTTON, OnQuit) 2327 sizer.Add(btnquit) 2328 sizer.Add((20,-1)) 2329 mnsizer.Add(sizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP,5) 2330 2331 # finish up window 2332 mnpnl.SetSizer(mnsizer) 2333 OnRadioSelect(None) # disable widgets 2334 mnsizer.Fit(self) 2335 self.CenterOnParent() 2336 self.Show() 2337 2338 def DefineEvaluator(dlg): 2339 '''Creates a function that provides interpolated values for a given distance value 2340 ''' 2341 def Evaluator(dist): 2342 '''Interpolate image parameters for a supplied distance value 2343 2344 :param float dist: distance to use for interpolation 2345 :returns: a list with 3 items: 2346 2347 * a dict with parameter values, 2348 * the closest imctrl and 2349 * the closest maskfile (or None) 2350 ''' 2351 x = np.array([float(i) for i in parms[0]]) 2352 closest = abs(x-dist).argmin() 2353 closeX = x[closest] 2354 D = {'distance':dist} 2355 imctfile = IMfileList[closest] 2356 if parms[-1][closest].lower() != '(none)': 2357 maskfile = parms[-1][closest] 2358 else: 2359 maskfile = None 2360 for c in range(1,cols-1): 2361 lbl = ParmList[c] 2362 if lbl in nonInterpVars: 2363 D[lbl] = float(parms[c][closest]) 2364 else: 2365 y = np.array([float(i) for i in parms[c]]) 2366 D[lbl] = np.interp(dist,x,y) 2367 # full integration when angular range is 0 2368 D['fullIntegrate'] = (D['LRazimuth_min'] == D['LRazimuth_max']) 2369 # conversion for paired values 2370 for a,b in ('center_x','center_y'),('LRazimuth_min','LRazimuth_max'),('IOtth_min','IOtth_max'): 2371 r = a.split('_')[0] 2372 D[r] = [D[a],D[b]] 2373 del D[a] 2374 del D[b] 2375 return D,imctfile,maskfile 2376 # save local copies of values needed in Evaluator 2377 parms = dlg.ReadImageParmTable() 2378 IMfileList = dlg.IMfileList 2379 cols = dlg.list.GetColumnCount() 2380 ParmList = dlg.ParmList 2381 nonInterpVars = dlg.nonInterpVars 2382 return Evaluator 2383 2384 class IntegParmTable(wx.Dialog): 2385 '''Creates a dialog window with a table of integration parameters. 2386 :meth:`ShowModal` will return wx.ID_OK if the process has been successful. 2387 In this case, :func:`DefineEvaluator` should be called to obtain a function that 2388 creates a dictionary with interpolated parameter values. 2389 ''' 2390 ParmList = ('distance','center_x','center_y','wavelength','tilt','rotation','DetDepth', 2391 'LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max','outChannels', 2392 'maskfile', 2393 ) 2394 nonInterpVars = ('tilt','rotation','LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max', 2395 'outChannels') # values in this list are taken from nearest rather than interpolated 2396 HeaderList = ('Det Dist','X cntr','Y cntr','wavelength','tilt','rotation','DetDepth', 2397 'Azimuth min','Azimuth max','2Th min','2Th max','Int. pts', 2398 'Mask File', 2399 ) 2400 def __init__(self,G2frame): 2401 self.G2frame = G2frame 2402 self.parms = [] # list of values by column 2403 self.IMfileList = [] # list of .imctrl file names for each entry in table 2404 wx.Dialog.__init__(self,G2frame,style=wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE) 2405 files = [] 2406 try: 2407 dlg = wx.FileDialog(self, 'Select image control files or previous table', 2408 style=wx.OPEN| wx.MULTIPLE, 2409 wildcard='image control files (.imctrl)|*.imctrl|Integration table (*.imtbl)|*.imtbl') 2410 if dlg.ShowModal() == wx.ID_OK: 2411 files = dlg.GetPaths() 2412 self.parms,self.IMfileList = self.ReadFiles(files) 2413 finally: 2414 dlg.Destroy() 2415 if not files: 2416 wx.CallAfter(self.EndModal,wx.ID_CANCEL) 2417 return 2418 mainSizer = wx.BoxSizer(wx.VERTICAL) 2419 self.list = ImgIntLstCtrl(self, wx.ID_ANY, 2420 style=wx.LC_REPORT 2421 | wx.BORDER_SUNKEN 2422 #| wx.BORDER_NONE 2423 ) 2424 mainSizer.Add(self.list,1,wx.EXPAND,1) 2425 btnsizer = wx.BoxSizer(wx.HORIZONTAL) 2426 btn = wx.Button(self, wx.ID_OK) 2427 btnsizer.Add(btn) 2428 btn = wx.Button(self, wx.ID_ANY,'Save') 2429 btn.Bind(wx.EVT_BUTTON,self._onSave) 2430 btnsizer.Add(btn) 2431 btn = wx.Button(self, wx.ID_CLOSE,'Quit') 2432 btn.Bind(wx.EVT_BUTTON,self._onClose) 2433 btnsizer.Add(btn) 2434 mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5) 2435 self.SetSizer(mainSizer) 2436 self.list.FillList(self.parms) 2437 mainSizer.Layout() 2438 mainSizer.Fit(self) 2439 2440 def ReadFiles(self,files): 2441 '''Reads a list of .imctrl files or a single .imtbl file 2442 ''' 2443 tmpDict = {} 2444 if not files: return 2445 # option 1, a dump from a previous save 2446 if os.path.splitext(files[0])[1] == '.imtbl': 2447 fp = open(files[0],'r') 2448 S = fp.readline() 2449 while S: 2450 if S[0] != '#': 2451 [key,val] = S[:-1].split(':') 2452 tmpDict[key] = eval(val) 2453 S = fp.readline() 2454 fp.close() 2455 # delete entries 2456 m1 = [i for i,f in enumerate(tmpDict['filenames']) if not os.path.exists(f)] 2457 if m1: 2458 print('\nimctrl file not found:') 2459 for i in m1: print('\t#'+str(i)+': '+tmpDict['filenames'][i]) 2460 m2 = [i for i,f in enumerate(tmpDict['maskfile']) if not (os.path.exists(f) or f.startswith('('))] 2461 if m2: 2462 print('\nmask file not found') 2463 for i in m2: print('\t#'+str(i)+': '+tmpDict['maskfile'][i]) 2464 m3 = [i for i,d in enumerate(tmpDict['distance']) if d < 0] 2465 if m3: 2466 print('\nDropping entries due to negative distance: '+str(m3)) 2467 m = sorted(set(m1 + m2 + m3)) 2468 m.reverse() 2469 for c in m: 2470 for key in tmpDict: 2471 del tmpDict[key][c] 2472 fileList = tmpDict.get('filenames','[]') 2473 parms = [] 2474 for key in self.ParmList: 2475 try: 2476 float(tmpDict[key][0]) 2477 parms.append([str(G2py3.FormatSigFigs(val,sigfigs=5)) for val in tmpDict[key]]) 2478 except ValueError: 2479 parms.append(tmpDict[key]) 2480 return parms,fileList 2481 # option 2, read in a list of files 2482 for file in files: # read all files; place in dict by distance 2483 imgDict = Read_imctrl(file) 2484 tmpDict[imgDict.get('distance')] = imgDict 2485 parms = [[] for key in self.ParmList] 2486 fileList = [] 2487 for d in sorted(tmpDict): 2488 fileList.append(tmpDict[d].get('filename')) 2489 if d is None: continue 2490 if d < 0: continue 2491 for i,key in enumerate(self.ParmList): 2492 val = tmpDict[d].get(key) 2493 try: 2494 val = str(G2py3.FormatSigFigs(val,sigfigs=5)) 2495 except: 2496 val = str(val) 2497 parms[i].append(val) 2498 return parms,fileList 2499 2500 def ReadImageParmTable(self): 2501 '''Reads possibly edited values from the ListCtrl table and returns a list 2502 of values for each column. 2503 ''' 2504 rows = self.list.GetItemCount() 2505 cols = self.list.GetColumnCount() 2506 parms = [] 2507 for c in range(cols): 2508 lbl = self.ParmList[c] 2509 parms.append([]) 2510 for r in range(rows): 2511 parms[c].append(self.list.GetItem(r,c).GetText()) 2512 return parms 2513 2514 def _onClose(self,event): 2515 'Called when Cancel button is pressed' 2516 self.EndModal(wx.ID_CANCEL) 2517 2518 def _onSave(self,event): 2519 'Called when save button is pressed; creates a .imtbl file' 2520 fil = '' 2521 if self.G2frame.GSASprojectfile: 2522 fil = os.path.splitext(self.G2frame.GSASprojectfile)[0]+'.imtbl' 2523 dir,f = os.path.split(fil) 2524 try: 2525 dlg = wx.FileDialog(self, 'Save table data as', 2526 defaultDir=dir, defaultFile=f, style=wx.SAVE) 2527 if dlg.ShowModal() != wx.ID_OK: return 2528 fil = dlg.GetPath() 2529 fil = os.path.splitext(fil)[0]+'.imtbl' 2530 finally: 2531 dlg.Destroy() 2532 parms = self.ReadImageParmTable() 2533 print('Writing image parameter table as '+fil) 2534 fp = open(fil,'w') 2535 for c in range(len(parms)-1): 2536 lbl = self.ParmList[c] 2537 fp.write(lbl+': '+str([eval(i) for i in parms[c]])+'\n') 2538 lbl = self.ParmList[c+1] 2539 fp.write(lbl+': '+str(parms[c+1])+'\n') 2540 lbl = 'filenames' 2541 fp.write(lbl+': '+str(self.IMfileList)+'\n') 2542 fp.close() 2543 2544 class ImgIntLstCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,listmix.TextEditMixin): 2545 '''Creates a custom ListCtrl for editing Image Integration parameters 2546 ''' 2547 def __init__(self, parent, ID, pos=wx.DefaultPosition, 2548 size=(1000,200), style=0): 2549 self.parent=parent 2550 wx.ListCtrl.__init__(self, parent, ID, pos, size, style) 2551 listmix.ListCtrlAutoWidthMixin.__init__(self) 2552 listmix.TextEditMixin.__init__(self) 2553 self.Bind(wx.EVT_LEFT_DCLICK, self.OnDouble) 2554 #self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick) 2555 def FillList(self,parms): 2556 'Places the current parms into the table' 2557 self.ClearAll() 2558 self.rowlen = len(self.parent.ParmList) 2559 for i,lbl in enumerate(self.parent.HeaderList): 2560 self.InsertColumn(i, lbl) 2561 for r,d in enumerate(parms[0]): 2562 if float(d) < 0: continue 2563 index = self.InsertStringItem(sys.maxint, d) 2564 for j in range(1,len(parms)): 2565 self.SetStringItem(index, j, parms[j][r]) 2566 for i,lbl in enumerate(self.parent.ParmList): 2567 self.SetColumnWidth(i, wx.LIST_AUTOSIZE) 2568 2569 def OnDouble(self,evt): 2570 'respond to a double-click' 2571 self.CloseEditor() 2572 fil = '(none)' 2573 try: 2574 dlg = wx.FileDialog(G2frame, 'Select mask or control file to add (Press cancel if none)', 2575 style=wx.OPEN, 2576 wildcard='Add GSAS-II mask file (.immask)|*.immask|add image control file (.imctrl)|*.imctrl') 2577 if dlg.ShowModal() == wx.ID_OK: 2578 fil = dlg.GetPath() 2579 finally: 2580 dlg.Destroy() 2581 if os.path.splitext(fil)[1] != '.imctrl': 2582 self.SetStringItem(self.curRow, self.rowlen-1, fil) 2583 self.SetColumnWidth(self.rowlen-1, wx.LIST_AUTOSIZE) 2584 else: 2585 # insert or overwrite an instrument parameter set 2586 if not os.path.exists(fil): 2587 print('Does not exist: '+fil) 2588 return 2589 imgDict = Read_imctrl(fil) 2590 dist = imgDict['distance'] 2591 parms = self.parent.ReadImageParmTable() 2592 x = np.array([float(i) for i in parms[0]]) 2593 closest = abs(x-dist).argmin() 2594 closeX = x[closest] 2595 # fix IMfileList 2596 for c,lbl in enumerate(self.parent.ParmList): 2597 try: 2598 vali = G2py3.FormatSigFigs(float(imgDict[lbl]),sigfigs=5) 2599 except ValueError: 2600 vali = imgDict[lbl] 2601 if abs(closeX-dist) < 1.: # distance is within 1 mm, replace 2602 parms[c][closest] = vali 2603 elif dist > closeX: # insert after 2604 parms[c].insert(closest+1,vali) 2605 else: 2606 parms[c].insert(closest,vali) 2607 if abs(closeX-dist) < 1.: # distance is within 1 mm, replace 2608 self.parent.IMfileList[closest] = fil 2609 elif dist > closeX: # insert after 2610 self.parent.IMfileList.insert(closest+1,fil) 2611 else: 2612 self.parent.IMfileList.insert(closest,fil) 2613 self.FillList(parms) 2614 # Autointegration end 2615 ########################################################################### -
trunk/autoint.py
r2065 r2082 1 1 import os 2 import wx2 import sys 3 3 import copy 4 4 import glob 5 5 import re 6 import bisect 7 import numpy as np 8 import wx 9 import wx.lib.mixins.listctrl as listmix 6 10 import GSASIIpath 7 11 import GSASIIIO as G2IO … … 9 13 import GSASIIgrid as G2gd 10 14 import GSASIIimgGUI as G2imG 11 ''' 12 Define a class to be used for Andrey's AutoIntegration process 13 ''' 14 15 import GSASIIpy3 as G2py3 16 17 print 'loading autoint' 18 19 def ReadMask(filename): 20 'Read a mask (.immask) file' 21 File = open(filename,'r') 22 save = {} 23 S = File.readline() 24 while S: 25 if S[0] == '#': 26 S = File.readline() 27 continue 28 [key,val] = S[:-1].split(':') 29 if key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']: 30 save[key] = eval(val) 31 S = File.readline() 32 File.close() 33 G2imG.CleanupMasks(save) 34 return save 35 36 def ReadControls(filename): 37 'read an image controls (.imctrl) file' 38 cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type', 39 'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth', 40 'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg', 41 'PolaVal','SampleAbs','dark image','background image'] 42 File = open(filename,'r') 43 save = {} 44 S = File.readline() 45 while S: 46 if S[0] == '#': 47 S = File.readline() 48 continue 49 [key,val] = S[:-1].split(':') 50 if key in ['type','calibrant','binType','SampleShape',]: #strings 51 save[key] = val 52 elif key in ['rotation']: 53 save[key] = float(val) 54 elif key in ['center',]: 55 if ',' in val: 56 save[key] = eval(val) 57 else: 58 vals = val.strip('[] ').split() 59 save[key] = [float(vals[0]),float(vals[1])] 60 elif key in cntlList: 61 save[key] = eval(val) 62 S = File.readline() 63 File.close() 64 return save 65 66 def Read_imctrl(imctrl_file): 67 '''Read an image control file and record control parms into a dict, with some simple 68 type conversions 69 ''' 70 file_opt = options = {} 71 save = {'filename':imctrl_file} 72 immask_file = os.path.splitext(imctrl_file)[0]+'.immask' 73 if os.path.exists(immask_file): 74 save['maskfile'] = immask_file 75 else: 76 save['maskfile'] = '(none)' 77 cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type', 78 'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth', 79 'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg', 80 'PolaVal','SampleAbs','dark image','background image'] 81 File = open(imctrl_file,'r') 82 fullIntegrate = False 83 try: 84 S = File.readline() 85 while S: 86 if S[0] == '#': 87 S = File.readline() 88 continue 89 [key,val] = S[:-1].split(':') 90 if key in ['type','calibrant','binType','SampleShape',]: #strings 91 save[key] = val 92 elif key == 'rotation': 93 save[key] = float(val) 94 elif key == 'fullIntegrate': 95 fullIntegrate = eval(val) 96 elif key == 'LRazimuth': 97 save['LRazimuth_min'],save['LRazimuth_max'] = eval(val)[0:2] 98 elif key == 'IOtth': 99 save['IOtth_min'],save['IOtth_max'] = eval(val)[0:2] 100 elif key == 'center': 101 if ',' in val: 102 vals = eval(val) 103 else: 104 vals = val.strip('[] ').split() 105 vals = [float(vals[0]),float(vals[1])] 106 save['center_x'],save['center_y'] = vals[0:2] 107 elif key in cntlList: 108 save[key] = eval(val) 109 S = File.readline() 110 finally: 111 File.close() 112 if fullIntegrate: save['LRazimuth_min'],save['LRazimuth_max'] = 0,0 113 return save 114 15 115 class AutoIntFrame(wx.Frame): 16 116 '''Creates a wx.Frame window for the Image AutoIntegration. … … 48 148 if newImage in imageFileList: continue # already read 49 149 for imgId in G2IO.ReadImages(G2frame,newImage): 50 # update controls from master51 150 controlsDict = G2frame.PatternTree.GetItemPyData( 52 151 G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls')) 53 controlsDict.update(self.ImageControls)54 # update masks from master55 152 ImageMasks = G2frame.PatternTree.GetItemPyData( 56 153 G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks')) 154 if self.params['Mode'] == 'table': 155 dist = controlsDict['distance'] 156 interpDict,imgctrl,immask = self.Evaluator(dist) # interpolated calibration values 157 self.ImageControls = ReadControls(imgctrl) 158 self.ImageControls.update(interpDict) 159 self.ImageControls['showLines'] = True 160 self.ImageControls['ring'] = [] 161 self.ImageControls['rings'] = [] 162 self.ImageControls['ellipses'] = [] 163 self.ImageControls['setDefault'] = False 164 for i in 'range','size','GonioAngles': 165 if i in self.ImageControls: 166 del self.ImageControls[i] 167 # load copy of Image Masks 168 if immask: 169 self.ImageMasks = ReadMask(immask) 170 del self.Thresholds['Thresholds'] 171 else: 172 self.ImageMasks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[]} 173 # update controls from master 174 controlsDict.update(self.ImageControls) 175 # update masks from master w/o Thresholds 57 176 ImageMasks.update(self.ImageMasks) 58 177 # now integrate the images that have not already been processed before … … 117 236 # show current IMG base 118 237 self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image)) 119 if self.params['Mode'] == 'file': 120 'get file info' 121 GSASIIpath.IPyBreak() 122 else: 238 if self.params['Mode'] != 'table': 123 239 # load copy of Image Controls from current image and clean up 124 240 # items that should not be copied … … 179 295 is started. When Pause is pressed, the loop is stopped. 180 296 ''' 181 #print self.params # for debug 182 183 # check inputs before starting 184 err = '' 297 # check inputs for errors before starting 298 #err = '' 185 299 #if not any([self.params[fmt] for fmt in self.fmtlist]): 186 300 # err += '\nPlease select at least one output format\n' 187 if (self.params['Mode'] == 'file' and not 188 os.path.exists(self.params['IMGfile'])): 189 err += '\nThe image controls file could not be found\n' 190 if (self.params['Mode'] == 'file' and 191 not self.params['IgnoreMask'] 192 ) and not os.path.exists(self.params['MaskFile']): 193 err += '\nThe mask file could not be found\n' 194 if err: 195 G2G.G2MessageBox(self,err) 196 return 301 #if err: 302 # G2G.G2MessageBox(self,err) 303 # return 197 304 # change button label 198 305 if btnstart.GetLabel() != 'Pause': … … 244 351 dlg.Destroy() 245 352 return 246 if btn1 == event.GetEventObject():247 ext = '.imctrl'248 title = 'Image control'249 else:250 ext = '.immask'251 title = 'Image masks'252 dlg = wx.FileDialog(253 self, 'Select name for '+title+' file to read',254 '.', '',255 title+'file (*'+ext+')|*'+ext,256 wx.OPEN|wx.CHANGE_DIR)257 dlg.CenterOnParent()258 try:259 if dlg.ShowModal() == wx.ID_OK:260 filename = dlg.GetPath()261 # make sure extension is correct262 #filename = os.path.splitext(filename)[0]+ext263 if btn1 == event.GetEventObject():264 fInp1.SetValue(filename)265 else:266 fInp2.SetValue(filename)267 else:268 filename = None269 finally:270 dlg.Destroy()271 353 272 354 def OnRadioSelect(event): 273 '''Respond to a radiobutton selection and enable or 274 disable widgets accordingly. Also gets called when the 275 "Don't Use" flag for Mask use is called. 355 '''Respond to a radiobutton selection and when in table 356 mode, get parameters from user. 276 357 ''' 277 lbl1.Disable() 278 fInp1.Disable() 279 btn1.Disable() 280 lbl2.Disable() 281 fInp2.Disable() 282 ign2.Disable() 283 btn2.Disable() 358 self.Evaluator = None 284 359 if r2.GetValue(): 285 self.params['Mode'] = ' file'286 fInp1.Enable()287 btn1.Enable()288 lbl1.Enable()289 ign2.Enable()290 if not self.params['IgnoreMask']:291 fInp2.Enable()292 btn2.Enable()293 lbl2.Enable()360 self.params['Mode'] = 'table' 361 try: 362 dlg = IntegParmTable(self.G2frame) # create the dialog 363 if dlg.ShowModal() == wx.ID_OK: 364 self.Evaluator = DefineEvaluator(dlg) 365 else: 366 r1.SetValue(True) 367 finally: 368 dlg.Destroy() 294 369 else: 295 370 self.params['Mode'] = 'active' … … 298 373 ################################################## 299 374 self.G2frame = G2frame 375 self.Evaluator = None 300 376 self.params = {} 301 377 self.Reset = False … … 337 413 lblsizr.Add(r1) 338 414 r1.SetValue(True) 339 r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use from file(s)")415 r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use from table") 340 416 lblsizr.Add(r2) 341 417 r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect) 342 r2.Disable() # deactivate this until implemented343 # Image controls file344 sizer = wx.BoxSizer(wx.HORIZONTAL)345 sizer.Add((20,-1))346 lbl1 = wx.StaticText(mnpnl, wx.ID_ANY,'IMG control file: ')347 sizer.Add(lbl1)348 fInp1 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'IMGfile',349 notBlank=False,size=(300,-1))350 sizer.Add(fInp1)351 btn1 = wx.Button(mnpnl, wx.ID_ANY, "Browse")352 btn1.Bind(wx.EVT_BUTTON, OnBrowse)353 sizer.Add(btn1)354 lblsizr.Add(sizer)355 # Masks input file356 sizer = wx.BoxSizer(wx.HORIZONTAL)357 sizer.Add((20,-1))358 lbl2 = wx.StaticText(mnpnl, wx.ID_ANY,'Mask file: ')359 sizer.Add(lbl2)360 fInp2 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'MaskFile',361 notBlank=False,size=(300,-1))362 sizer.Add(fInp2)363 ign2 = G2G.G2CheckBox(mnpnl,"Don't use",self.params,'IgnoreMask',364 OnChange=OnRadioSelect)365 sizer.Add(ign2)366 btn2 = wx.Button(mnpnl, wx.ID_ANY, "Browse")367 btn2.Bind(wx.EVT_BUTTON, OnBrowse)368 sizer.Add(btn2)369 lblsizr.Add(sizer)370 418 mnsizer.Add(lblsizr) 371 419 … … 420 468 mnsizer.Fit(self) 421 469 self.CenterOnParent() 422 self.Show() 470 self.Show() 471 472 def DefineEvaluator(dlg): 473 '''Creates a function that provides interpolated values for a given distance value 474 ''' 475 def Evaluator(dist): 476 '''Interpolate image parameters for a supplied distance value 477 478 :param float dist: distance to use for interpolation 479 :returns: a list with 3 items: 480 481 * a dict with parameter values, 482 * the closest imctrl and 483 * the closest maskfile (or None) 484 ''' 485 x = np.array([float(i) for i in parms[0]]) 486 closest = abs(x-dist).argmin() 487 closeX = x[closest] 488 D = {'distance':dist} 489 imctfile = IMfileList[closest] 490 if parms[-1][closest].lower() != '(none)': 491 maskfile = parms[-1][closest] 492 else: 493 maskfile = None 494 for c in range(1,cols-1): 495 lbl = ParmList[c] 496 if lbl in nonInterpVars: 497 D[lbl] = float(parms[c][closest]) 498 else: 499 y = np.array([float(i) for i in parms[c]]) 500 D[lbl] = np.interp(dist,x,y) 501 # full integration when angular range is 0 502 D['fullIntegrate'] = (D['LRazimuth_min'] == D['LRazimuth_max']) 503 # conversion for paired values 504 for a,b in ('center_x','center_y'),('LRazimuth_min','LRazimuth_max'),('IOtth_min','IOtth_max'): 505 r = a.split('_')[0] 506 D[r] = [D[a],D[b]] 507 del D[a] 508 del D[b] 509 return D,imctfile,maskfile 510 # save local copies of values needed in Evaluator 511 parms = dlg.ReadImageParmTable() 512 IMfileList = dlg.IMfileList 513 cols = dlg.list.GetColumnCount() 514 ParmList = dlg.ParmList 515 nonInterpVars = dlg.nonInterpVars 516 return Evaluator 517 518 class IntegParmTable(wx.Dialog): 519 '''Creates a dialog window with a table of integration parameters. 520 :meth:`ShowModal` will return wx.ID_OK if the process has been successful. 521 In this case, :func:`DefineEvaluator` should be called to obtain a function that 522 creates a dictionary with interpolated parameter values. 523 ''' 524 ParmList = ('distance','center_x','center_y','wavelength','tilt','rotation','DetDepth', 525 'LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max','outChannels', 526 'maskfile', 527 ) 528 nonInterpVars = ('tilt','rotation','LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max', 529 'outChannels') # values in this list are taken from nearest rather than interpolated 530 HeaderList = ('Det Dist','X cntr','Y cntr','wavelength','tilt','rotation','DetDepth', 531 'Azimuth min','Azimuth max','2Th min','2Th max','Int. pts', 532 'Mask File', 533 ) 534 def __init__(self,G2frame): 535 self.G2frame = G2frame 536 self.parms = [] # list of values by column 537 self.IMfileList = [] # list of .imctrl file names for each entry in table 538 wx.Dialog.__init__(self,G2frame,style=wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE) 539 files = [] 540 try: 541 dlg = wx.FileDialog(self, 'Select image control files or previous table', 542 style=wx.OPEN| wx.MULTIPLE, 543 wildcard='image control files (.imctrl)|*.imctrl|Integration table (*.imtbl)|*.imtbl') 544 if dlg.ShowModal() == wx.ID_OK: 545 files = dlg.GetPaths() 546 self.parms,self.IMfileList = self.ReadFiles(files) 547 finally: 548 dlg.Destroy() 549 if not files: 550 wx.CallAfter(self.EndModal,wx.ID_CANCEL) 551 return 552 mainSizer = wx.BoxSizer(wx.VERTICAL) 553 self.list = ImgIntLstCtrl(self, wx.ID_ANY, 554 style=wx.LC_REPORT 555 | wx.BORDER_SUNKEN 556 #| wx.BORDER_NONE 557 ) 558 mainSizer.Add(self.list,1,wx.EXPAND,1) 559 btnsizer = wx.BoxSizer(wx.HORIZONTAL) 560 btn = wx.Button(self, wx.ID_OK) 561 btnsizer.Add(btn) 562 btn = wx.Button(self, wx.ID_ANY,'Save') 563 btn.Bind(wx.EVT_BUTTON,self._onSave) 564 btnsizer.Add(btn) 565 btn = wx.Button(self, wx.ID_CLOSE,'Quit') 566 btn.Bind(wx.EVT_BUTTON,self._onClose) 567 btnsizer.Add(btn) 568 mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5) 569 self.SetSizer(mainSizer) 570 self.list.FillList(self.parms) 571 mainSizer.Layout() 572 mainSizer.Fit(self) 573 574 def ReadFiles(self,files): 575 '''Reads a list of .imctrl files or a single .imtbl file 576 ''' 577 tmpDict = {} 578 if not files: return 579 # option 1, a dump from a previous save 580 if os.path.splitext(files[0])[1] == '.imtbl': 581 fp = open(files[0],'r') 582 S = fp.readline() 583 while S: 584 if S[0] != '#': 585 [key,val] = S[:-1].split(':') 586 tmpDict[key] = eval(val) 587 S = fp.readline() 588 fp.close() 589 # delete entries 590 m1 = [i for i,f in enumerate(tmpDict['filenames']) if not os.path.exists(f)] 591 if m1: 592 print('\nimctrl file not found:') 593 for i in m1: print('\t#'+str(i)+': '+tmpDict['filenames'][i]) 594 m2 = [i for i,f in enumerate(tmpDict['maskfile']) if not (os.path.exists(f) or f.startswith('('))] 595 if m2: 596 print('\nmask file not found') 597 for i in m2: print('\t#'+str(i)+': '+tmpDict['maskfile'][i]) 598 m3 = [i for i,d in enumerate(tmpDict['distance']) if d < 0] 599 if m3: 600 print('\nDropping entries due to negative distance: '+str(m3)) 601 m = sorted(set(m1 + m2 + m3)) 602 m.reverse() 603 for c in m: 604 for key in tmpDict: 605 del tmpDict[key][c] 606 fileList = tmpDict.get('filenames','[]') 607 parms = [] 608 for key in self.ParmList: 609 try: 610 float(tmpDict[key][0]) 611 parms.append([str(G2py3.FormatSigFigs(val,sigfigs=5)) for val in tmpDict[key]]) 612 except ValueError: 613 parms.append(tmpDict[key]) 614 return parms,fileList 615 # option 2, read in a list of files 616 for file in files: # read all files; place in dict by distance 617 imgDict = Read_imctrl(file) 618 tmpDict[imgDict.get('distance')] = imgDict 619 parms = [[] for key in self.ParmList] 620 fileList = [] 621 for d in sorted(tmpDict): 622 fileList.append(tmpDict[d].get('filename')) 623 if d is None: continue 624 if d < 0: continue 625 for i,key in enumerate(self.ParmList): 626 val = tmpDict[d].get(key) 627 try: 628 val = str(G2py3.FormatSigFigs(val,sigfigs=5)) 629 except: 630 val = str(val) 631 parms[i].append(val) 632 return parms,fileList 633 634 def ReadImageParmTable(self): 635 '''Reads possibly edited values from the ListCtrl table and returns a list 636 of values for each column. 637 ''' 638 rows = self.list.GetItemCount() 639 cols = self.list.GetColumnCount() 640 parms = [] 641 for c in range(cols): 642 lbl = self.ParmList[c] 643 parms.append([]) 644 for r in range(rows): 645 parms[c].append(self.list.GetItem(r,c).GetText()) 646 return parms 647 648 def _onClose(self,event): 649 'Called when Cancel button is pressed' 650 self.EndModal(wx.ID_CANCEL) 651 652 def _onSave(self,event): 653 'Called when save button is pressed; creates a .imtbl file' 654 fil = '' 655 if self.G2frame.GSASprojectfile: 656 fil = os.path.splitext(self.G2frame.GSASprojectfile)[0]+'.imtbl' 657 dir,f = os.path.split(fil) 658 try: 659 dlg = wx.FileDialog(self, 'Save table data as', 660 defaultDir=dir, defaultFile=f, style=wx.SAVE) 661 if dlg.ShowModal() != wx.ID_OK: return 662 fil = dlg.GetPath() 663 fil = os.path.splitext(fil)[0]+'.imtbl' 664 finally: 665 dlg.Destroy() 666 parms = self.ReadImageParmTable() 667 print('Writing image parameter table as '+fil) 668 fp = open(fil,'w') 669 for c in range(len(parms)-1): 670 lbl = self.ParmList[c] 671 fp.write(lbl+': '+str([eval(i) for i in parms[c]])+'\n') 672 lbl = self.ParmList[c+1] 673 fp.write(lbl+': '+str(parms[c+1])+'\n') 674 lbl = 'filenames' 675 fp.write(lbl+': '+str(self.IMfileList)+'\n') 676 fp.close() 677 678 class ImgIntLstCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,listmix.TextEditMixin): 679 '''Creates a custom ListCtrl for editing Image Integration parameters 680 ''' 681 def __init__(self, parent, ID, pos=wx.DefaultPosition, 682 size=(1000,200), style=0): 683 self.parent=parent 684 wx.ListCtrl.__init__(self, parent, ID, pos, size, style) 685 listmix.ListCtrlAutoWidthMixin.__init__(self) 686 listmix.TextEditMixin.__init__(self) 687 self.Bind(wx.EVT_LEFT_DCLICK, self.OnDouble) 688 #self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick) 689 def FillList(self,parms): 690 'Places the current parms into the table' 691 self.ClearAll() 692 self.rowlen = len(self.parent.ParmList) 693 for i,lbl in enumerate(self.parent.HeaderList): 694 self.InsertColumn(i, lbl) 695 for r,d in enumerate(parms[0]): 696 if float(d) < 0: continue 697 index = self.InsertStringItem(sys.maxint, d) 698 for j in range(1,len(parms)): 699 self.SetStringItem(index, j, parms[j][r]) 700 for i,lbl in enumerate(self.parent.ParmList): 701 self.SetColumnWidth(i, wx.LIST_AUTOSIZE) 702 703 def OnDouble(self,evt): 704 'respond to a double-click' 705 self.CloseEditor() 706 fil = '(none)' 707 try: 708 dlg = wx.FileDialog(G2frame, 'Select mask or control file to add (Press cancel if none)', 709 style=wx.OPEN, 710 wildcard='Add GSAS-II mask file (.immask)|*.immask|add image control file (.imctrl)|*.imctrl') 711 if dlg.ShowModal() == wx.ID_OK: 712 fil = dlg.GetPath() 713 finally: 714 dlg.Destroy() 715 if os.path.splitext(fil)[1] != '.imctrl': 716 self.SetStringItem(self.curRow, self.rowlen-1, fil) 717 self.SetColumnWidth(self.rowlen-1, wx.LIST_AUTOSIZE) 718 else: 719 # insert or overwrite an instrument parameter set 720 if not os.path.exists(fil): 721 print('Does not exist: '+fil) 722 return 723 imgDict = Read_imctrl(fil) 724 dist = imgDict['distance'] 725 parms = self.parent.ReadImageParmTable() 726 x = np.array([float(i) for i in parms[0]]) 727 closest = abs(x-dist).argmin() 728 closeX = x[closest] 729 # fix IMfileList 730 for c,lbl in enumerate(self.parent.ParmList): 731 try: 732 vali = G2py3.FormatSigFigs(float(imgDict[lbl]),sigfigs=5) 733 except ValueError: 734 vali = imgDict[lbl] 735 if abs(closeX-dist) < 1.: # distance is within 1 mm, replace 736 parms[c][closest] = vali 737 elif dist > closeX: # insert after 738 parms[c].insert(closest+1,vali) 739 else: 740 parms[c].insert(closest,vali) 741 if abs(closeX-dist) < 1.: # distance is within 1 mm, replace 742 self.parent.IMfileList[closest] = fil 743 elif dist > closeX: # insert after 744 self.parent.IMfileList.insert(closest+1,fil) 745 else: 746 self.parent.IMfileList.insert(closest,fil) 747 self.FillList(parms) 423 748 424 749 if __name__ == '__main__':
Note: See TracChangeset
for help on using the changeset viewer.