source: trunk/GSASIIimgGUI.py @ 2104

Last change on this file since 2104 was 2104, checked in by toby, 7 years ago

fix integration table bugs; start on int table edit

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 124.8 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - image data display routines
3########### SVN repository information ###################
4# $Date: 2015-12-23 20:44:11 +0000 (Wed, 23 Dec 2015) $
5# $Author: toby $
6# $Revision: 2104 $
7# $URL: trunk/GSASIIimgGUI.py $
8# $Id: GSASIIimgGUI.py 2104 2015-12-23 20:44:11Z toby $
9########### SVN repository information ###################
10'''
11*GSASIIimgGUI: Image GUI*
12-------------------------
13
14Control image display and processing
15
16'''
17import os
18import copy
19import glob
20import re
21import bisect
22import math
23import time
24import copy
25import sys
26import wx
27import wx.lib.scrolledpanel as wxscroll
28import wx.lib.mixins.listctrl  as  listmix
29import matplotlib as mpl
30import numpy as np
31import GSASIIpath
32GSASIIpath.SetVersionNumber("$Revision: 2104 $")
33import GSASIIimage as G2img
34import GSASIImath as G2mth
35import GSASIIplot as G2plt
36import GSASIIIO as G2IO
37import GSASIIgrid as G2gd
38import GSASIIctrls as G2G
39import GSASIIpy3 as G2py3
40
41VERY_LIGHT_GREY = wx.Colour(235,235,235)
42WACV = wx.ALIGN_CENTER_VERTICAL
43
44# trig functions in degrees
45sind = lambda x: math.sin(x*math.pi/180.)
46tand = lambda x: math.tan(x*math.pi/180.)
47cosd = lambda x: math.cos(x*math.pi/180.)
48asind = lambda x: 180.*math.asin(x)/math.pi
49   
50################################################################################
51##### Image Data
52################################################################################
53
54def UpdateImageData(G2frame,data):
55   
56    def OnPixVal(event):
57        Obj = event.GetEventObject()
58        id = Indx[Obj.GetId()]
59        try:
60            data['pixelSize'][id] = min(500,max(10,float(Obj.GetValue())))
61        except ValueError:
62            pass
63        Obj.SetValue('%.3f'%(data['pixelSize'][id]))
64        G2plt.PlotExposedImage(G2frame,newPlot=True,event=event)
65       
66    if G2frame.dataDisplay:
67        G2frame.dataDisplay.Destroy()
68    if not G2frame.dataFrame.GetStatusBar():
69        G2frame.dataFrame.CreateStatusBar()
70    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
71    mainSizer = wx.BoxSizer(wx.VERTICAL)
72    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,
73        label='Do not change anything here unless you are absolutely sure!'),0,WACV)
74    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Image size: %d by %d'%(data['size'][0],data['size'][1])),0,WACV)
75    pixSize = wx.FlexGridSizer(0,4,5,5)
76    pixLabels = [u' Pixel X-dimension (\xb5m)',u' Pixel Y-dimension (\xb5m)']
77    Indx = {}
78    for i,[pixLabel,pix] in enumerate(zip(pixLabels,data['pixelSize'])):
79        pixSize.Add(wx.StaticText(G2frame.dataDisplay,label=pixLabel),0,WACV)
80        pixVal = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(pix),style=wx.TE_PROCESS_ENTER)
81        Indx[pixVal.GetId()] = i
82        pixVal.Bind(wx.EVT_TEXT_ENTER,OnPixVal)
83        pixVal.Bind(wx.EVT_KILL_FOCUS,OnPixVal)
84        pixSize.Add(pixVal,0,WACV)
85    mainSizer.Add(pixSize,0)
86   
87    mainSizer.Layout()   
88    G2frame.dataDisplay.SetSizer(mainSizer)
89    fitSize = mainSizer.Fit(G2frame.dataFrame)
90    G2frame.dataFrame.setSizePosLeft(fitSize)
91    G2frame.dataDisplay.SetSize(fitSize)
92
93################################################################################
94##### Image Controls
95################################################################################                   
96def UpdateImageControls(G2frame,data,masks,IntegrateOnly=False):
97    '''Shows and handles the controls on the "Image Controls"
98    data tree entry
99    '''
100    import ImageCalibrants as calFile
101#patch
102    if 'Flat Bkg' not in data:
103        data['Flat Bkg'] = 0.0
104    if 'GonioAngles' not in data:
105        data['GonioAngles'] = [0.,0.,0.]
106    if 'DetDepth' not in data:
107        data['DetDepth'] = 0.
108    if 'SampleAbs' not in data:
109        data['SampleShape'] = 'Cylinder'
110        data['SampleAbs'] = [0.0,False]
111    if 'binType' not in data:
112        if 'PWDR' in data['type']:
113            data['binType'] = '2-theta'
114        elif 'SASD' in data['type']:
115            data['binType'] = 'log(q)'
116    if 'varyList' not in data:
117        data['varyList'] = {'dist':True,'det-X':True,'det-Y':True,'tilt':True,'phi':True,'dep':False,'wave':False}
118#end patch
119
120# Menu items
121           
122    def OnCalibrate(event):       
123        G2frame.dataFrame.ImageEdit.Enable(id=G2gd.wxID_IMRECALIBRATE,enable=True)   
124        G2frame.dataFrame.GetStatusBar().SetStatusText('Select > 4 points on 1st used ring; LB to pick, RB on point to delete else RB to finish')
125        G2frame.ifGetRing = True
126               
127    def OnRecalibrate(event):
128        G2img.ImageRecalibrate(G2frame,data,masks)
129        wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
130       
131    def OnClearCalib(event):
132        data['ring'] = []
133        data['rings'] = []
134        data['ellipses'] = []
135#        G2frame.dataFrame.ImageEdit.Enable(id=G2gd.wxID_IMRECALIBRATE,enable=False)   
136        G2plt.PlotExposedImage(G2frame,event=event)
137           
138    def OnIntegrate(event):
139        '''Integrate image in response to a menu event or from the AutoIntegrate
140        dialog. In the latter case, event=None.
141        '''
142        CleanupMasks(masks)
143        blkSize = 128   #this seems to be optimal; will break in polymask if >1024
144        Nx,Ny = data['size']
145        nXBlks = (Nx-1)/blkSize+1
146        nYBlks = (Ny-1)/blkSize+1
147        Nup = nXBlks*nYBlks*3+3
148        dlg = wx.ProgressDialog("Elapsed time","2D image integration",Nup,
149            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
150        try:
151            sumImg = G2frame.ImageZ
152            darkImg,darkScale = data['dark image']
153            if darkImg:
154                Did = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, darkImg)
155                Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Did)
156                darkImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
157                sumImg += darkImage*darkScale
158            backImg,backScale = data['background image']           
159            if backImg:     #ignores any transmission effect in the background image
160                Bid = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, backImg)
161                Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Bid)
162                backImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
163                Bdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Bid,'Image Controls'))
164                BdarkImg,BdarkScale = Bdata['dark image']
165                if BdarkImg:
166                    BDid = G2gd.GetPatternTreeItemId(G2frame, G2frame.root,BdarkImg)
167                    Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(BDid)
168                    BdarkImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
169                    backImage += BdarkImage*BdarkScale               
170                sumImg += backImage*backScale
171            G2frame.Integrate = G2img.ImageIntegrate(sumImg-data['Flat Bkg'],data,masks,blkSize,dlg)
172#            G2plt.PlotIntegration(G2frame,newPlot=True)
173            Id = G2IO.SaveIntegration(G2frame,G2frame.PickId,data,(event is None))
174            G2frame.PatternId = Id
175            G2frame.PatternTree.SelectItem(Id)
176            G2frame.PatternTree.Expand(Id)
177        finally:
178            dlg.Destroy()
179        for item in G2frame.MakePDF: item.Enable(True)
180       
181    def OnIntegrateAll(event):
182        TextList = [[False,'All IMG',0]]
183#        Names = []
184        if G2frame.PatternTree.GetCount():
185            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
186            while id:
187                name = G2frame.PatternTree.GetItemText(id)
188#                Names.append(name)
189                if 'IMG' in name:
190                    TextList.append([False,name,id])
191                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
192            if len(TextList) == 1:
193                G2frame.ErrorDialog('Nothing to integrate','There must some "IMG" patterns')
194                return
195            dlg = G2frame.CopyDialog(G2frame,'Image integration controls','Select images to integrate:',TextList)
196            try:
197                if dlg.ShowModal() == wx.ID_OK:
198                    result = dlg.GetData()
199                    if result[0][0]:                    #the 'All IMG' is True
200                        result = TextList[1:]
201                        for item in result: item[0] = True
202                    G2frame.EnablePlot = False
203                    for item in result:
204                        ifintegrate,name,id = item
205                        if ifintegrate:
206                            Id = G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls')
207                            Data = G2frame.PatternTree.GetItemPyData(Id)
208                            blkSize = 128   #this seems to be optimal; will break in polymask if >1024
209                            Nx,Ny = Data['size']
210                            nXBlks = (Nx-1)/blkSize+1
211                            nYBlks = (Ny-1)/blkSize+1
212                            Nup = nXBlks*nYBlks*3+3
213                            dlgp = wx.ProgressDialog("Elapsed time","2D image integration",Nup,
214                                style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
215                            try:
216                                id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, name)
217                                Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(id)
218                                image = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
219                                backImage = []
220                                if Data['background image'][0]:
221                                    backImg = Data['background image'][0]
222                                    backScale = Data['background image'][1]
223                                    id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, backImg)
224                                    Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(id)
225                                    backImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)*backScale
226                                FlatBkg = Data.get('Flat Bkg',0.0)
227                                try:
228                                    Masks = G2frame.PatternTree.GetItemPyData(
229                                        G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'))
230                                except TypeError:       #missing Masks
231                                    # I think the next line should be 'range'! (BHT)
232                                    Imin,Imax = Data['Range']
233                                    Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
234                                    G2frame.PatternTree.SetItemPyData(
235                                        G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'),Masks)
236                                CleanupMasks(Masks)
237                                if len(backImage):                               
238                                    G2frame.Integrate = G2img.ImageIntegrate(image+backImage-FlatBkg,Data,Masks,blkSize,dlgp)
239                                else:
240                                    G2frame.Integrate = G2img.ImageIntegrate(image-FlatBkg,Data,Masks,blkSize,dlgp)
241                                pId = G2IO.SaveIntegration(G2frame,Id,Data)
242                            finally:
243                                dlgp.Destroy()
244                    else:
245                        G2frame.EnablePlot = True
246                        G2frame.PatternTree.SelectItem(pId)
247                        G2frame.PatternTree.Expand(pId)
248                        G2frame.PatternId = pId
249                       
250            finally:
251                dlg.Destroy()
252       
253    def OnCopyControls(event):
254        TextList = [[False,'All IMG',0]]
255#        Names = []
256        if G2frame.PatternTree.GetCount():
257            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
258            while id:
259                name = G2frame.PatternTree.GetItemText(id)
260#                Names.append(name)
261                if 'IMG' in name:
262                    if id == G2frame.Image:
263                        Source = name
264                        Data = copy.deepcopy(data)
265#                        Data = copy.deepcopy(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls')))
266                        Data['showLines'] = True
267                        Data['ring'] = []
268                        Data['rings'] = []
269                        Data['ellipses'] = []
270                        Data['setDefault'] = False
271                    else:
272                        TextList.append([False,name,id])
273                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
274            if len(TextList) == 1:
275                G2frame.ErrorDialog('Nothing to copy controls to','There must be more than one "IMG" pattern')
276                return
277            dlg = G2frame.CopyDialog(G2frame,'Copy image controls','Copy controls from '+Source+' to:',TextList)
278            try:
279                if dlg.ShowModal() == wx.ID_OK:
280                    result = dlg.GetData()
281                    if result[0][0]:
282                        result = TextList[1:]
283                        for item in result: item[0] = True
284                    for i,item in enumerate(result):
285                        ifcopy,name,id = item
286                        if ifcopy:
287                            oldData = copy.deepcopy(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls')))
288                            Data['range'] = oldData['range']
289                            Data['size'] = oldData['size']
290                            Data['GonioAngles'] = oldData.get('GonioAngles', [0.,0.,0.])
291                            Data['ring'] = []
292                            Data['rings'] = []
293                            Data['ellipses'] = []
294                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls'),copy.deepcopy(Data))
295            finally:
296                dlg.Destroy()
297                G2frame.PatternTree.SelectItem(G2frame.PickId)
298               
299    def OnSaveControls(event):
300        dlg = wx.FileDialog(G2frame, 'Choose image controls file', '.', '', 
301            'image control files (*.imctrl)|*.imctrl',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
302        try:
303            if dlg.ShowModal() == wx.ID_OK:
304                filename = dlg.GetPath()
305                # make sure extension is .imctrl
306                filename = os.path.splitext(filename)[0]+'.imctrl'
307                File = open(filename,'w')
308                keys = ['type','wavelength','calibrant','distance','center',
309                    'tilt','rotation','azmthOff','fullIntegrate','LRazimuth',
310                    'IOtth','outChannels','outAzimuths','invert_x','invert_y','DetDepth',
311                    'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
312                    'binType','SampleShape','PolaVal','SampleAbs','dark image','background image']
313                for key in keys:
314                    if key not in data:     #uncalibrated!
315                        continue
316                    File.write(key+':'+str(data[key])+'\n')
317                File.close()
318        finally:
319            dlg.Destroy()
320       
321    def OnLoadControls(event):
322        cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type',
323            'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth',
324            'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
325            'PolaVal','SampleAbs','dark image','background image']
326        dlg = wx.FileDialog(G2frame, 'Choose image controls file', '.', '', 
327            'image control files (*.imctrl)|*.imctrl',wx.OPEN|wx.CHANGE_DIR)
328        try:
329            if dlg.ShowModal() == wx.ID_OK:
330                filename = dlg.GetPath()
331                File = open(filename,'r')
332                save = {}
333                S = File.readline()
334                while S:
335                    if S[0] == '#':
336                        S = File.readline()
337                        continue
338                    [key,val] = S[:-1].split(':')
339                    if key in ['type','calibrant','binType','SampleShape',]:    #strings
340                        save[key] = val
341                    elif key in ['rotation']:
342                        save[key] = float(val)
343                    elif key in ['center',]:
344                        if ',' in val:
345                            save[key] = eval(val)
346                        else:
347                            vals = val.strip('[] ').split()
348                            save[key] = [float(vals[0]),float(vals[1])] 
349                    elif key in cntlList:
350                        save[key] = eval(val)
351                    S = File.readline()
352                data.update(save)
353                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'),copy.deepcopy(data))
354                wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
355                G2plt.PlotExposedImage(G2frame,event=event)
356               
357                File.close()
358        finally:
359            dlg.Destroy()
360           
361# Sizers
362                                       
363    def ComboSizer():
364
365        def OnDataType(event):
366            data['type'] = typeSel.GetValue()[:4]
367            if 'SASD' in data['type']:
368                data['SampleAbs'][0] = np.exp(-data['SampleAbs'][0]) #switch from muT to trans!
369                if data['binType'] == '2-theta': data['binType'] = 'log(q)'  #switch default bin type
370            elif 'PWDR' in data['type']:
371                data['SampleAbs'][0] = -np.log(data['SampleAbs'][0])  #switch from trans to muT!
372                if data['binType'] == 'log(q)': data['binType'] = '2-theta'  #switch default bin type                 
373            wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
374   
375        def OnNewColorBar(event):
376            data['color'] = colSel.GetValue()
377            G2plt.PlotExposedImage(G2frame,event=event)
378       
379        def OnAzmthOff(event):
380            try:
381                azmthoff = float(azmthOff.GetValue())
382                data['azmthOff'] = azmthoff
383            except ValueError:
384                pass
385            azmthOff.SetValue("%.2f"%(data['azmthOff']))          #reset in case of error 
386            G2plt.PlotExposedImage(G2frame,event=event)
387       
388        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
389        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Type of image data: '),0,WACV)
390        typeSel = wx.ComboBox(parent=G2frame.dataDisplay,value=typeDict[data['type']],choices=typeList,
391            style=wx.CB_READONLY|wx.CB_DROPDOWN)
392        typeSel.SetValue(data['type'])
393        typeSel.Bind(wx.EVT_COMBOBOX, OnDataType)
394        comboSizer.Add(typeSel,0,WACV)
395        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Color bar '),0,WACV)
396        colSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['color'],choices=colorList,
397            style=wx.CB_READONLY|wx.CB_DROPDOWN)
398        colSel.Bind(wx.EVT_COMBOBOX, OnNewColorBar)
399        comboSizer.Add(colSel,0,WACV)
400        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Azimuth offset '),0,WACV)
401        azmthOff = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.2f" % (data['azmthOff'])),
402            style=wx.TE_PROCESS_ENTER)
403        azmthOff.Bind(wx.EVT_TEXT_ENTER,OnAzmthOff)
404        azmthOff.Bind(wx.EVT_KILL_FOCUS,OnAzmthOff)
405        comboSizer.Add(azmthOff,0,WACV)
406        return comboSizer
407       
408    def MaxSizer():
409               
410        def OnMaxVal(event):
411            try:
412                value = min(data['range'][0][1],int(maxVal.GetValue()))
413                if value < data['range'][1][0]+1:
414                    raise ValueError
415                data['range'][1][1] = value
416            except ValueError:
417                pass
418            maxVal.SetValue('%.0f'%(data['range'][1][1]))
419            DeltOne = data['range'][1][1]-max(0.0,data['range'][0][0])
420            sqrtDeltOne = math.sqrt(DeltOne)
421            maxSel.SetValue(int(100*sqrtDeltOne/sqrtDeltZero))
422            minSel.SetValue(int(100*(data['range'][1][0]/DeltOne)))
423            G2plt.PlotExposedImage(G2frame,event=event)
424           
425        def OnMinVal(event):
426            try:
427                value = int(minVal.GetValue())
428                if value > data['range'][1][1]-1:
429                    raise ValueError
430                data['range'][1][0] = value
431            except ValueError:
432                pass
433            minVal.SetValue('%.0f'%(data['range'][1][0]))
434            minSel.SetValue(int(100*(data['range'][1][0]-max(0.0,data['range'][0][0]))/DeltOne))
435            G2plt.PlotExposedImage(G2frame,event=event)
436           
437        def OnMaxSlider(event):
438            sqrtDeltZero = math.sqrt(data['range'][0][1])
439            imax = int(maxSel.GetValue())*sqrtDeltZero/100.
440            data['range'][1][1] = imax**2
441            data['range'][1][0] = max(0.0,min(data['range'][1][1]-1,data['range'][1][0]))
442            DeltOne = max(1.0,data['range'][1][1]-data['range'][1][0])
443            minSel.SetValue(int(100*(data['range'][1][0]/DeltOne)))
444            maxVal.SetValue('%.0f'%(data['range'][1][1]))
445            G2plt.PlotExposedImage(G2frame,event=event)
446           
447        def OnMinSlider(event):
448            DeltOne = data['range'][1][1]-data['range'][1][0]
449            imin = int(minSel.GetValue())*DeltOne/100.
450            data['range'][1][0] = max(0.0,min(data['range'][1][1]-1,imin))
451            minVal.SetValue('%.0f'%(data['range'][1][0]))
452            G2plt.PlotExposedImage(G2frame,event=event)
453           
454        maxSizer = wx.FlexGridSizer(0,3,0,5)
455        maxSizer.AddGrowableCol(1,1)
456        maxSizer.SetFlexibleDirection(wx.HORIZONTAL)
457        sqrtDeltZero = math.sqrt(data['range'][0][1]-max(0.0,data['range'][0][0]))
458        DeltOne = data['range'][1][1]-max(0.0,data['range'][0][0])
459        sqrtDeltOne = math.sqrt(DeltOne)
460        maxSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max intensity'),0,WACV)
461        maxSel = wx.Slider(parent=G2frame.dataDisplay,style=wx.SL_HORIZONTAL,
462            value=int(100*sqrtDeltOne/sqrtDeltZero))
463        maxSizer.Add(maxSel,1,wx.EXPAND)
464        maxSel.Bind(wx.EVT_SLIDER, OnMaxSlider)
465        maxVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.0f'%(data['range'][1][1]))
466        maxVal.Bind(wx.EVT_TEXT_ENTER,OnMaxVal)   
467        maxVal.Bind(wx.EVT_KILL_FOCUS,OnMaxVal)
468        maxSizer.Add(maxVal,0,WACV)   
469        maxSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Min intensity'),0,WACV)
470        minSel = wx.Slider(parent=G2frame.dataDisplay,style=wx.SL_HORIZONTAL,
471            value=int(100*(data['range'][1][0]-max(0.0,data['range'][0][0]))/DeltOne))
472        maxSizer.Add(minSel,1,wx.EXPAND)
473        minSel.Bind(wx.EVT_SLIDER, OnMinSlider)
474        minVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.0f'%(data['range'][1][0]))
475        minVal.Bind(wx.EVT_TEXT_ENTER,OnMinVal)   
476        minVal.Bind(wx.EVT_KILL_FOCUS,OnMinVal)
477        maxSizer.Add(minVal,0,WACV)
478        return maxSizer
479       
480    def CalibCoeffSizer():
481       
482        def OnCalRef(event):
483            Obj = event.GetEventObject()
484            name = Indx[Obj]
485            data['varyList'][name] = Obj.GetValue()
486           
487        def OnCalVal(event):
488            Obj = event.GetEventObject()
489            name = Indx[Obj]
490            try:
491                value = float(Obj.GetValue())
492                if name == 'wave' and value < 0.01:
493                    raise ValueError
494            except ValueError:
495                value = Parms[name][2]
496            if name == 'dist':
497                data['distance'] = value
498            elif name == 'det-X':
499                data['center'][0] = value
500            elif name == 'det-Y':
501                data['center'][1] = value
502            elif name == 'tilt':
503                data['tilt'] = value
504            elif name == 'phi':
505                data['rotation'] = value
506            elif name == 'wave':
507                data['wavelength'] = value
508            elif name == 'dep':
509                data['DetDepth'] = value                               
510            Parms[name][2] = value
511            Obj.SetValue(Parms[name][1]%(value))
512           
513        calibSizer = wx.FlexGridSizer(0,2,5,5)
514        calibSizer.SetFlexibleDirection(wx.HORIZONTAL)
515        calibSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calibration coefficients'),0,WACV)   
516        calibSizer.Add((5,0),0)
517        cent = data['center']
518        Names = ['det-X','det-Y','wave','dist','tilt','phi']
519        if 'PWDR' in data['type']:
520            Names.append('dep') 
521        Parms = {'dist':['Distance','%.3f',data['distance']],'det-X':['Beam center X','%.3f',data['center'][0]],
522            'det-Y':['Beam center Y','%.3f',data['center'][1]],'tilt':['Tilt angle','%.3f',data['tilt']],
523            'phi':['Tilt rotation','%.2f',data['rotation']],'dep':['Penetration','%.2f',data['DetDepth']],
524            'wave':['Wavelength','%.6f',data['wavelength']]}
525        Indx = {}
526        for name in Names:
527            calSel = wx.CheckBox(parent=G2frame.dataDisplay,label=Parms[name][0])
528            calibSizer.Add(calSel,0,WACV)
529            calSel.Bind(wx.EVT_CHECKBOX, OnCalRef)
530            calSel.SetValue(data['varyList'][name])
531            Indx[calSel] = name
532            calVal = wx.TextCtrl(G2frame.dataDisplay,value=(Parms[name][1]%(Parms[name][2])),style=wx.TE_PROCESS_ENTER)
533            calVal.Bind(wx.EVT_TEXT_ENTER,OnCalVal)
534            calVal.Bind(wx.EVT_KILL_FOCUS,OnCalVal)
535            Indx[calVal] = name
536            calibSizer.Add(calVal,0,WACV)
537        return calibSizer
538   
539    def IntegrateSizer():
540       
541        def OnNewBinType(event):
542            data['binType'] = binSel.GetValue()
543            wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
544       
545        def OnIOtth(event):
546            Ltth = max(float(G2frame.InnerTth.GetValue()),0.001)
547            Utth = float(G2frame.OuterTth.GetValue())
548            if Ltth > Utth:
549                Ltth,Utth = Utth,Ltth
550            if 'Q' in data['binType']:
551                data['IOtth'] = [2.*asind(Ltth*wave/(4.*math.pi)),2.*asind(Utth*wave/(4.*math.pi))]
552            else:
553                data['IOtth'] = [Ltth,Utth]
554            G2frame.InnerTth.SetValue("%8.3f" % (Ltth))
555            G2frame.OuterTth.SetValue("%8.3f" % (Utth))
556            G2plt.PlotExposedImage(G2frame,event=event)
557       
558        def OnLRazim(event):
559            Lazm = int(G2frame.Lazim.GetValue())%360
560            Razm = int(G2frame.Razim.GetValue())%360
561            if Lazm > Razm:
562                Razm += 360
563            if data['fullIntegrate']:
564                Razm = Lazm+360
565            G2frame.Lazim.SetValue("%6d" % (Lazm))
566            G2frame.Razim.SetValue("%6d" % (Razm))
567            data['LRazimuth'] = [Lazm,Razm]
568            G2plt.PlotExposedImage(G2frame,event=event)
569       
570        def OnNumOutChans(event):
571            try:
572                numChans = int(outChan.GetValue())
573                if numChans < 10:
574                    raise ValueError
575                data['outChannels'] = numChans
576            except ValueError:
577                pass
578            outChan.SetValue(str(data['outChannels']))          #reset in case of error       
579       
580        def OnNumOutAzms(event):
581            try:
582                numAzms = int(outAzim.GetValue())
583                if numAzms < 1:
584                    raise ValueError
585                data['outAzimuths'] = numAzms           
586            except ValueError:
587                pass
588            outAzim.SetValue(str(data['outAzimuths']))          #reset in case of error       
589            G2plt.PlotExposedImage(G2frame,event=event)
590       
591        def OnOblique(event):
592            if data['Oblique'][1]:
593                data['Oblique'][1] = False
594            else:
595                data['Oblique'][1] = True
596               
597        def OnObliqVal(event):
598            try:
599                value = float(obliqVal.GetValue())
600                if 0.01 <= value <= 0.99:
601                    data['Oblique'][0] = value
602                else:
603                    raise ValueError
604            except ValueError:
605                pass
606            obliqVal.SetValue('%.3f'%(data['Oblique'][0]))
607                           
608        def OnSamAbs(event):
609            if data['SampleAbs'][1]:
610                data['SampleAbs'][1] = False
611            else:
612                data['SampleAbs'][1] = True
613               
614        def OnSamAbsVal(event):
615            try:
616                value = float(samabsVal.GetValue())
617                minmax = [0.,2.]
618                if 'SASD' in data['type']:
619                    minmax = [.05,1.0]
620                if minmax[0] <= value <= minmax[1]:
621                    data['SampleAbs'][0] = value
622                else:
623                    raise ValueError
624            except ValueError:
625                pass
626            samabsVal.SetValue('%.3f'%(data['SampleAbs'][0]))
627                           
628        def OnShowLines(event):
629            if data['showLines']:
630                data['showLines'] = False
631            else:
632                data['showLines'] = True
633            G2plt.PlotExposedImage(G2frame,event=event)
634           
635        def OnFullIntegrate(event):
636            Lazm =int(G2frame.Lazim.GetValue())
637            if data['fullIntegrate']:
638                data['fullIntegrate'] = False
639                data['LRazimuth'] = [Lazm,Lazm+20]
640            else:
641                data['fullIntegrate'] = True
642                data['LRazimuth'] = [Lazm,Lazm+360]
643            wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
644            G2plt.PlotExposedImage(G2frame,event=event)
645           
646        def OnSetDefault(event):
647            if data['setDefault']:
648                G2frame.imageDefault = {}
649                data['setDefault'] = False
650            else:
651                G2frame.imageDefault = copy.copy(data)
652                data['setDefault'] = True
653               
654        def OnCenterAzm(event):
655            if data['centerAzm']:
656                data['centerAzm'] = False
657            else:
658                data['centerAzm'] = True
659            G2plt.PlotExposedImage(G2frame,event=event)
660               
661        def OnApplyPola(event):
662            if data['PolaVal'][1]:
663                data['PolaVal'][1] = False
664            else:
665                data['PolaVal'][1] = True
666               
667        def OnPolaVal(event):
668            try:
669                value = float(polaVal.GetValue())
670                if 0.001 <= value <= 0.999:
671                    data['PolaVal'][0] = value
672                else:
673                    raise ValueError
674            except ValueError:
675                pass
676            polaVal.SetValue('%.3f'%(data['PolaVal'][0]))
677                           
678        dataSizer = wx.FlexGridSizer(0,2,5,3)
679        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Integration coefficients'),0,WACV)   
680        dataSizer.Add((5,0),0)
681        if 'PWDR' in data['type']:
682            binChoice = ['2-theta','Q']
683        elif 'SASD' in data['type']:
684            binChoice = ['2-theta','Q','log(q)']
685        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Bin style: Constant step bins in'),0,WACV)           
686        binSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['binType'],choices=binChoice,
687            style=wx.CB_READONLY|wx.CB_DROPDOWN)
688        binSel.Bind(wx.EVT_COMBOBOX, OnNewBinType)
689        dataSizer.Add(binSel,0,WACV)
690        binType = '2-theta'
691        if 'q' in data['binType'].lower():
692            binType = 'Q'
693        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Inner/Outer '+binType),0,WACV)           
694        IOtth = data['IOtth'][:]
695        if 'Q' in data['binType']:
696            wave = data['wavelength']
697            IOtth = [4.*math.pi*sind(IOtth[0]/2.)/wave,4.*math.pi*sind(IOtth[1]/2.)/wave]
698        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
699        G2frame.InnerTth = wx.TextCtrl(parent=G2frame.dataDisplay,
700            value=("%8.3f" % (IOtth[0])),style=wx.TE_PROCESS_ENTER)
701        G2frame.InnerTth.Bind(wx.EVT_TEXT_ENTER,OnIOtth)
702        G2frame.InnerTth.Bind(wx.EVT_KILL_FOCUS,OnIOtth)
703        littleSizer.Add(G2frame.InnerTth,0,WACV)
704        G2frame.OuterTth = wx.TextCtrl(parent=G2frame.dataDisplay,
705            value=("%8.2f" % (IOtth[1])),style=wx.TE_PROCESS_ENTER)
706        G2frame.OuterTth.Bind(wx.EVT_TEXT_ENTER,OnIOtth)
707        G2frame.OuterTth.Bind(wx.EVT_KILL_FOCUS,OnIOtth)
708        littleSizer.Add(G2frame.OuterTth,0,WACV)
709        dataSizer.Add(littleSizer,0,)
710        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start/End azimuth'),0,WACV)
711        LRazim = data['LRazimuth']
712        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
713        G2frame.Lazim = wx.TextCtrl(parent=G2frame.dataDisplay,
714            value=("%6d" % (LRazim[0])),style=wx.TE_PROCESS_ENTER)
715        G2frame.Lazim.Bind(wx.EVT_TEXT_ENTER,OnLRazim)
716        G2frame.Lazim.Bind(wx.EVT_KILL_FOCUS,OnLRazim)
717        littleSizer.Add(G2frame.Lazim,0,WACV)
718        G2frame.Razim = wx.TextCtrl(parent=G2frame.dataDisplay,
719            value=("%6d" % (LRazim[1])),style=wx.TE_PROCESS_ENTER)
720        G2frame.Razim.Bind(wx.EVT_TEXT_ENTER,OnLRazim)
721        G2frame.Razim.Bind(wx.EVT_KILL_FOCUS,OnLRazim)
722        if data['fullIntegrate']:
723            G2frame.Razim.Enable(False)
724            G2frame.Razim.SetBackgroundColour(VERY_LIGHT_GREY)
725            G2frame.Razim.SetValue("%6d" % (LRazim[0]+360))
726        littleSizer.Add(G2frame.Razim,0,WACV)
727        dataSizer.Add(littleSizer,0,)
728        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' No. 2-theta/azimuth bins'),0,WACV)
729        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
730        outChan = wx.TextCtrl(parent=G2frame.dataDisplay,value=str(data['outChannels']),style=wx.TE_PROCESS_ENTER)
731        outChan.Bind(wx.EVT_TEXT_ENTER,OnNumOutChans)
732        outChan.Bind(wx.EVT_KILL_FOCUS,OnNumOutChans)
733        littleSizer.Add(outChan,0,WACV)
734        outAzim = wx.TextCtrl(parent=G2frame.dataDisplay,value=str(data['outAzimuths']),style=wx.TE_PROCESS_ENTER)
735        outAzim.Bind(wx.EVT_TEXT_ENTER,OnNumOutAzms)
736        outAzim.Bind(wx.EVT_KILL_FOCUS,OnNumOutAzms)
737        littleSizer.Add(outAzim,0,WACV)
738        dataSizer.Add(littleSizer,0,)
739        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
740        samabs = wx.CheckBox(parent=G2frame.dataDisplay,label='Apply sample absorption?')
741        dataSizer.Add(samabs,0,WACV)
742        samabs.Bind(wx.EVT_CHECKBOX, OnSamAbs)
743        samabs.SetValue(data['SampleAbs'][1])
744        if 'PWDR' in data['type']:
745            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='mu/R (0.00-2.0) '),0,WACV)
746        elif 'SASD' in data['type']:
747            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='transmission '),0,WACV)
748        samabsVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.3f'%(data['SampleAbs'][0]),style=wx.TE_PROCESS_ENTER)           
749        samabsVal.Bind(wx.EVT_TEXT_ENTER,OnSamAbsVal)
750        samabsVal.Bind(wx.EVT_KILL_FOCUS,OnSamAbsVal)
751        littleSizer.Add(samabsVal,0,WACV)
752        dataSizer.Add(littleSizer,0,)
753        if 'PWDR' in data['type']:
754            littleSizer = wx.BoxSizer(wx.HORIZONTAL)
755            oblique = wx.CheckBox(parent=G2frame.dataDisplay,label='Apply detector absorption?')
756            dataSizer.Add(oblique,0,WACV)
757            oblique.Bind(wx.EVT_CHECKBOX, OnOblique)
758            oblique.SetValue(data['Oblique'][1])
759            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Value (0.01-0.99)  '),0,WACV)
760            obliqVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.3f'%(data['Oblique'][0]),style=wx.TE_PROCESS_ENTER)
761            obliqVal.Bind(wx.EVT_TEXT_ENTER,OnObliqVal)
762            obliqVal.Bind(wx.EVT_KILL_FOCUS,OnObliqVal)
763            littleSizer.Add(obliqVal,0,WACV)
764            dataSizer.Add(littleSizer,0,)
765        if 'SASD' in data['type']:
766            littleSizer = wx.BoxSizer(wx.HORIZONTAL)
767            setPolariz = wx.CheckBox(parent=G2frame.dataDisplay,label='Apply polarization?')
768            dataSizer.Add(setPolariz,0,WACV)
769            setPolariz.Bind(wx.EVT_CHECKBOX, OnApplyPola)
770            setPolariz.SetValue(data['PolaVal'][1])
771            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Value (0.001-0.999)  '),0,WACV)
772            polaVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.3f'%(data['PolaVal'][0]),
773                style=wx.TE_PROCESS_ENTER)
774            polaVal.Bind(wx.EVT_TEXT_ENTER,OnPolaVal)
775            polaVal.Bind(wx.EVT_KILL_FOCUS,OnPolaVal)
776            littleSizer.Add(polaVal,0,WACV)
777            dataSizer.Add(littleSizer,0,)
778       
779        showLines = wx.CheckBox(parent=G2frame.dataDisplay,label='Show integration limits?')
780        dataSizer.Add(showLines,0,WACV)
781        showLines.Bind(wx.EVT_CHECKBOX, OnShowLines)
782        showLines.SetValue(data['showLines'])
783        fullIntegrate = wx.CheckBox(parent=G2frame.dataDisplay,label='Do full integration?')
784        dataSizer.Add(fullIntegrate,0,WACV)
785        fullIntegrate.Bind(wx.EVT_CHECKBOX, OnFullIntegrate)
786        fullIntegrate.SetValue(data['fullIntegrate'])
787        setDefault = wx.CheckBox(parent=G2frame.dataDisplay,label='Use as default for all images?')
788        dataSizer.Add(setDefault,0,WACV)
789        setDefault.Bind(wx.EVT_CHECKBOX, OnSetDefault)
790        setDefault.SetValue(data['setDefault'])
791        centerAzm = wx.CheckBox(parent=G2frame.dataDisplay,label='Azimuth at bin center?')
792        dataSizer.Add(centerAzm,0,WACV)
793        centerAzm.Bind(wx.EVT_CHECKBOX, OnCenterAzm)
794        centerAzm.SetValue(data['centerAzm'])
795        return dataSizer
796       
797    def BackSizer():
798       
799        def OnBackImage(event):
800            data['background image'][0] = backImage.GetValue()
801           
802        def OnDarkImage(event):
803            data['dark image'][0] = darkImage.GetValue()
804            G2plt.PlotExposedImage(G2frame,event=event)
805           
806        def OnFlatBkg(event):
807            try:
808                value = float(flatbkg.GetValue())
809                data['Flat Bkg'] = value
810            except ValueError:
811                pass
812            flatbkg.SetValue("%.0f"%(data['Flat Bkg']))   
813            G2plt.PlotExposedImage(G2frame,event=event)
814
815        def OnBackMult(event):
816            try:
817                mult = float(backMult.GetValue())
818                data['background image'][1] = mult
819            except ValueError:
820                pass
821            backMult.SetValue("%.3f" % (data['background image'][1]))          #reset in case of error
822       
823        def OnDarkMult(event):
824            try:
825                mult = float(darkMult.GetValue())
826                data['dark image'][1] = mult
827            except ValueError:
828                pass
829            darkMult.SetValue("%.3f" % (data['dark image'][1]))          #reset in case of error
830            G2plt.PlotExposedImage(G2frame,event=event)
831       
832        backSizer = wx.FlexGridSizer(0,6,5,5)
833
834        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Dark image'),0,WACV)
835        Choices = ['',]+G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
836        darkImage = wx.ComboBox(parent=G2frame.dataDisplay,value=data['dark image'][0],choices=Choices,
837            style=wx.CB_READONLY|wx.CB_DROPDOWN)
838        darkImage.Bind(wx.EVT_COMBOBOX,OnDarkImage)
839        backSizer.Add(darkImage)
840        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' multiplier'),0,WACV)
841        darkMult =  wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (data['dark image'][1])),
842            style=wx.TE_PROCESS_ENTER)
843        darkMult.Bind(wx.EVT_TEXT_ENTER,OnDarkMult)
844        darkMult.Bind(wx.EVT_KILL_FOCUS,OnDarkMult)
845        backSizer.Add(darkMult,0,WACV)
846        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Flat Bkg: '),0,WACV)
847        flatbkg = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.0f" % (data['Flat Bkg'])),
848            style=wx.TE_PROCESS_ENTER)
849        flatbkg.Bind(wx.EVT_TEXT_ENTER,OnFlatBkg)
850        flatbkg.Bind(wx.EVT_KILL_FOCUS,OnFlatBkg)
851        backSizer.Add(flatbkg,0,WACV)
852
853        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background image'),0,WACV)
854        Choices = ['',]+G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
855        backImage = wx.ComboBox(parent=G2frame.dataDisplay,value=data['background image'][0],choices=Choices,
856            style=wx.CB_READONLY|wx.CB_DROPDOWN)
857        backImage.Bind(wx.EVT_COMBOBOX,OnBackImage)
858        backSizer.Add(backImage)
859        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' multiplier'),0,WACV)
860        backMult =  wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (data['background image'][1])),
861            style=wx.TE_PROCESS_ENTER)
862        backMult.Bind(wx.EVT_TEXT_ENTER,OnBackMult)
863        backMult.Bind(wx.EVT_KILL_FOCUS,OnBackMult)
864        backSizer.Add(backMult,0,WACV)
865        return backSizer
866                       
867    def CalibSizer():
868               
869        def OnNewCalibrant(event):
870            data['calibrant'] = calSel.GetValue()
871            data['calibskip'] = calFile.Calibrants[data['calibrant']][3]
872            limits = calFile.Calibrants[data['calibrant']][4]
873            data['calibdmin'],data['pixLimit'],data['cutoff'] = limits
874            pixLimit.SetValue(str(limits[1]))
875            cutOff.SetValue('%.1f'%(limits[2]))
876            calibSkip.SetValue(str(data['calibskip']))
877            calibDmin.SetValue('%.1f'%(limits[0]))
878           
879        def OnCalibSkip(event):
880            data['calibskip'] = int(calibSkip.GetValue())
881           
882        def OnCalibDmin(event):
883            try:
884                dmin = float(calibDmin.GetValue())
885                if dmin < 0.25:
886                    raise ValueError
887                data['calibdmin'] = dmin
888            except ValueError:
889                pass
890            calibDmin.SetValue("%.2f"%(data['calibdmin']))          #reset in case of error 
891                   
892        def OnCutOff(event):
893            try:
894                cutoff = float(cutOff.GetValue())
895                if cutoff < 0.1:
896                    raise ValueError
897                data['cutoff'] = cutoff
898            except ValueError:
899                pass
900            cutOff.SetValue("%.1f"%(data['cutoff']))          #reset in case of error 
901       
902        def OnPixLimit(event):
903            data['pixLimit'] = int(pixLimit.GetValue())
904           
905        def OnSetRings(event):
906            if data['setRings']:
907                data['setRings'] = False
908            else:
909                data['setRings'] = True
910            G2plt.PlotExposedImage(G2frame,event=event)
911   
912        calibSizer = wx.FlexGridSizer(0,3,5,5)
913        comboSizer = wx.BoxSizer(wx.HORIZONTAL)   
914        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calibrant '),0,WACV)
915        calSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['calibrant'],choices=calList,
916            style=wx.CB_READONLY|wx.CB_DROPDOWN)
917        calSel.Bind(wx.EVT_COMBOBOX, OnNewCalibrant)
918        comboSizer.Add(calSel,0,WACV)
919        calibSizer.Add(comboSizer,0)
920       
921        comboSizer = wx.BoxSizer(wx.HORIZONTAL)   
922        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calib lines to skip   '),0,WACV)
923        calibSkip  = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['calibskip']),choices=[str(i) for i in range(25)],
924            style=wx.CB_READONLY|wx.CB_DROPDOWN)
925        calibSkip.Bind(wx.EVT_COMBOBOX, OnCalibSkip)
926        comboSizer.Add(calibSkip,0,WACV)
927        calibSizer.Add(comboSizer,0)
928       
929        comboSizer = wx.BoxSizer(wx.HORIZONTAL)       
930        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Min calib d-spacing '),0,WACV)
931        calibDmin = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.2f" % (data['calibdmin'])),
932            style=wx.TE_PROCESS_ENTER)
933        calibDmin.Bind(wx.EVT_TEXT_ENTER,OnCalibDmin)
934        calibDmin.Bind(wx.EVT_KILL_FOCUS,OnCalibDmin)
935        comboSizer.Add(calibDmin,0,WACV)
936        calibSizer.Add(comboSizer,0)
937       
938        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
939        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Min ring I/Ib '),0,WACV)
940        cutOff = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.1f" % (data['cutoff'])),
941            style=wx.TE_PROCESS_ENTER)
942        cutOff.Bind(wx.EVT_TEXT_ENTER,OnCutOff)
943        cutOff.Bind(wx.EVT_KILL_FOCUS,OnCutOff)
944        comboSizer.Add(cutOff,0,WACV)
945        calibSizer.Add(comboSizer,0)
946       
947        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
948        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Pixel search range '),0,WACV)
949        pixLimit = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['pixLimit']),choices=['1','2','5','10','15','20'],
950            style=wx.CB_READONLY|wx.CB_DROPDOWN)
951        pixLimit.Bind(wx.EVT_COMBOBOX, OnPixLimit)
952        comboSizer.Add(pixLimit,0,WACV)
953        calibSizer.Add(comboSizer,0)
954       
955        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
956        setRings = wx.CheckBox(parent=G2frame.dataDisplay,label='Show ring picks?')
957        comboSizer.Add(setRings,0)
958        setRings.Bind(wx.EVT_CHECKBOX, OnSetRings)
959        setRings.SetValue(data['setRings'])
960        calibSizer.Add(comboSizer,0)
961        return calibSizer
962       
963    def GonioSizer():
964       
965        ValObj = {}
966       
967        def OnGonioAngle(event):
968            Obj = event.GetEventObject()
969            item = ValObj[Obj.GetId()]
970            try:
971                value = float(Obj.GetValue())
972            except ValueError:
973                value = data['GonioAngles'][item]
974            data['GonioAngles'][item] = value
975            Obj.SetValue('%8.2f'%(value))
976           
977        def OnGlobalEdit(event):
978            Names = []
979            Items = []
980            if G2frame.PatternTree.GetCount():
981                id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
982                while id:
983                    name = G2frame.PatternTree.GetItemText(id)
984                    if 'IMG' in name:
985                        ctrls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id,'Image Controls'))
986                        Names.append(name)
987                        Items.append(ctrls['GonioAngles'])
988                    id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
989                if len(Names) == 1:
990                    G2frame.ErrorDialog('Nothing for global editing','There must be more than one "IMG" pattern')
991                    return
992                dlg = G2G.G2HistoDataDialog(G2frame,' Edit sample goniometer data:',
993                    'Edit data',['Omega','Chi','Phi'],['%.2f','%.2f','%.2f'],Names,Items)
994            try:
995                if dlg.ShowModal() == wx.ID_OK:
996                    result = dlg.GetData()
997                    id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
998                    while id:
999                        name = G2frame.PatternTree.GetItemText(id)
1000                        if 'IMG' in name:
1001                            ctrls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id,'Image Controls'))
1002                            vals = Items[Names.index(name)]
1003                            ctrls['GonioAngles'] = vals
1004#                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls'),ctrls)
1005                        id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1006            finally:
1007                dlg.Destroy()
1008                G2frame.PatternTree.SelectItem(G2frame.PickId)
1009       
1010        gonioSizer = wx.BoxSizer(wx.HORIZONTAL)
1011        names = ['Omega','Chi','Phi']
1012        gonioSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'Sample goniometer angles: '),0,WACV)
1013        for i,name in enumerate(names):
1014            gonioSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,name),0,WACV)
1015            angle = wx.TextCtrl(G2frame.dataDisplay,-1,value='%8.2f'%(data['GonioAngles'][i]),
1016                style=wx.TE_PROCESS_ENTER)
1017            angle.Bind(wx.EVT_TEXT_ENTER,OnGonioAngle)
1018            angle.Bind(wx.EVT_KILL_FOCUS,OnGonioAngle)
1019            ValObj[angle.GetId()] = i
1020            gonioSizer.Add(angle,0,WACV)
1021        globEdit = wx.Button(G2frame.dataDisplay,-1,'Global edit')
1022        globEdit.Bind(wx.EVT_BUTTON,OnGlobalEdit)
1023        gonioSizer.Add(globEdit,0,WACV)
1024        return gonioSizer
1025       
1026# Image Controls main code             
1027                           
1028    #fix for old files:
1029    if 'azmthOff' not in data:
1030        data['azmthOff'] = 0.0
1031    if 'background image' not in data:
1032        data['background image'] = ['',-1.0]
1033    if 'dark image' not in data:
1034        data['dark image'] = ['',-1.0]
1035    if 'centerAzm' not in data:
1036        data['centerAzm'] = False
1037    if 'Oblique' not in data:
1038        data['Oblique'] = [0.5,False]
1039    if 'PolaVal' not in data:
1040        data['PolaVal'] = [0.99,False]
1041    #end fix
1042   
1043    if IntegrateOnly:
1044        OnIntegrate(None)
1045        return
1046   
1047    colorList = sorted([m for m in mpl.cm.datad.keys() if not m.endswith("_r")],key=lambda s: s.lower())
1048    calList = sorted([m for m in calFile.Calibrants.keys()],key=lambda s: s.lower())
1049    typeList = ['PWDR - powder diffraction data','SASD - small angle scattering data',
1050        'REFL - reflectometry data']
1051    if not data.get('type'):                        #patch for old project files
1052        data['type'] = 'PWDR'
1053    typeDict = {'PWDR':typeList[0],'SASD':typeList[1],'REFL':typeList[2]}
1054    if G2frame.dataDisplay:
1055        G2frame.dataDisplay.Destroy()
1056    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ImageMenu)
1057    if not G2frame.dataFrame.GetStatusBar():
1058        G2frame.dataFrame.CreateStatusBar()
1059    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCalibrate, id=G2gd.wxID_IMCALIBRATE)
1060    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRecalibrate, id=G2gd.wxID_IMRECALIBRATE)
1061    G2frame.dataFrame.Bind(wx.EVT_MENU, OnClearCalib, id=G2gd.wxID_IMCLEARCALIB)
1062    if 'chisq' not in data:
1063        G2frame.dataFrame.ImageEdit.Enable(id=G2gd.wxID_IMRECALIBRATE,enable=False)   
1064    G2frame.dataFrame.Bind(wx.EVT_MENU, OnIntegrate, id=G2gd.wxID_IMINTEGRATE)
1065    G2frame.dataFrame.Bind(wx.EVT_MENU, OnIntegrateAll, id=G2gd.wxID_INTEGRATEALL)
1066    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyControls, id=G2gd.wxID_IMCOPYCONTROLS)
1067    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveControls, id=G2gd.wxID_IMSAVECONTROLS)
1068    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadControls, id=G2gd.wxID_IMLOADCONTROLS)
1069    def OnDestroy(event):
1070        G2frame.autoIntFrame = None
1071    def OnAutoInt(event):
1072        if G2frame.autoIntFrame: # ensure only one open at a time
1073            G2frame.autoIntFrame.Raise()
1074            return
1075        G2frame.autoIntFrame = AutoIntFrame(G2frame,PollTime=10.0)
1076        G2frame.autoIntFrame.Bind(wx.EVT_WINDOW_DESTROY,OnDestroy) # clean up name on window close
1077    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAutoInt, id=G2gd.wxID_IMAUTOINTEG)
1078    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1079
1080    mainSizer = wx.BoxSizer(wx.VERTICAL)
1081    mainSizer.Add((5,10),0)   
1082    mainSizer.Add(ComboSizer(),0,wx.ALIGN_LEFT)
1083    mainSizer.Add((5,5),0)           
1084    mainSizer.Add(MaxSizer(),0,wx.ALIGN_LEFT|wx.EXPAND)
1085   
1086    mainSizer.Add((5,5),0)
1087    DataSizer = wx.FlexGridSizer(0,2,5,5)
1088    DataSizer.Add(CalibCoeffSizer(),0)
1089    DataSizer.Add(IntegrateSizer(),0)       
1090    mainSizer.Add(DataSizer,0)
1091    mainSizer.Add((5,5),0)           
1092    mainSizer.Add(BackSizer(),0)
1093    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calibration controls:'),0,WACV)
1094    mainSizer.Add((5,5),0)
1095    mainSizer.Add(CalibSizer(),0,WACV)
1096    mainSizer.Add((5,5),0)
1097    mainSizer.Add(GonioSizer(),0,WACV)   
1098       
1099    mainSizer.Layout()   
1100    G2frame.dataDisplay.SetSizer(mainSizer)
1101    fitSize = mainSizer.Fit(G2frame.dataFrame)
1102    G2frame.dataFrame.setSizePosLeft(fitSize)
1103    G2frame.dataDisplay.SetSize(fitSize)
1104   
1105################################################################################
1106##### Masks
1107################################################################################
1108def CleanupMasks(data):
1109    '''If a mask creation is not completed, an empty mask entry is created in the
1110    masks array. This cleans them out. It is called when the masks page is first loaded
1111    and before saving them or after reading them in. This should also probably be done
1112    before they are used for integration.
1113    '''
1114    for key in ['Points','Rings','Arcs','Polygons']:
1115        data[key] = data.get(key,[])
1116        l1 = len(data[key])
1117        data[key] = [i for i in data[key] if i]
1118        l2 = len(data[key])
1119        if GSASIIpath.GetConfigValue('debug') and l1 != l2:
1120            print 'Mask Cleanup:',key,'was',l1,'entries','now',l2
1121   
1122def UpdateMasks(G2frame,data):
1123    '''Shows and handles the controls on the "Masks" data tree entry
1124    '''
1125   
1126    def OnTextMsg(event):
1127        Obj = event.GetEventObject()
1128        Obj.SetToolTipString('Drag this mask on 2D Powder Image with mouse to change ')
1129
1130    def Replot(*args,**kwargs):
1131        G2plt.PlotExposedImage(G2frame,newPlot=True)       
1132
1133    def onDeleteMask(event):
1134        Obj = event.GetEventObject()
1135        typ = Obj.locationcode.split('+')[1]
1136        num = int(Obj.locationcode.split('+')[2])
1137        del(data[typ][num])
1138        wx.CallAfter(UpdateMasks,G2frame,data)
1139        G2plt.PlotExposedImage(G2frame,event=event)
1140
1141    def onDeleteFrame(event):
1142        data['Frames'] = []
1143        wx.CallAfter(UpdateMasks,G2frame,data)
1144        G2plt.PlotExposedImage(G2frame,event=event)
1145
1146    def OnCopyMask(event):
1147        TextList = [[False,'All IMG',0]]
1148#        Names = []
1149        if G2frame.PatternTree.GetCount():
1150            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1151            while id:
1152                name = G2frame.PatternTree.GetItemText(id)
1153#                Names.append(name)
1154                if 'IMG' in name:
1155                    if id == G2frame.Image:
1156                        Source = name
1157                        Mask = copy.deepcopy(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks')))
1158                        Thresh = Mask.pop('Thresholds')  #remove Thresholds from source mask & save it for later
1159                    else:
1160                        TextList.append([False,name,id])
1161                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1162            if len(TextList) == 1:
1163                G2frame.ErrorDialog('Nothing to copy mask to','There must be more than one "IMG" pattern')
1164                return
1165            dlg = G2frame.CopyDialog(G2frame,'Copy mask information','Copy mask from '+Source+' to:',TextList)
1166            try:
1167                if dlg.ShowModal() == wx.ID_OK:
1168                    result = dlg.GetData()
1169                    if result[0][0]:
1170                        result = TextList[1:]
1171                        for item in result: item[0] = True
1172                    for i,item in enumerate(result):
1173                        ifcopy,name,id = item
1174                        if ifcopy:
1175                            mask = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'))
1176#                            Mask['Thresholds'][0] = mask['Thresholds'][0]
1177#                            Mask['Thresholds'][1][1] = min(mask['Thresholds'][1][1],Mask['Thresholds'][1][1])
1178                            mask.update(Mask)
1179                            mask['Thresholds'][1][0] = Thresh[1][0]  #copy only lower threshold                             
1180                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'),copy.deepcopy(mask))
1181            finally:
1182                dlg.Destroy()
1183               
1184    def OnSaveMask(event):
1185        CleanupMasks(data)
1186        dlg = wx.FileDialog(G2frame, 'Choose image mask file', '.', '', 
1187            'image mask files (*.immask)|*.immask',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1188        try:
1189            if dlg.ShowModal() == wx.ID_OK:
1190                filename = dlg.GetPath()
1191                filename = os.path.splitext(filename)[0]+'.immask'
1192                File = open(filename,'w')
1193                keys = ['Points','Rings','Arcs','Polygons','Frames','Thresholds']
1194                for key in keys:
1195                    File.write(key+':'+str(data[key])+'\n')
1196                File.close()
1197        finally:
1198            dlg.Destroy()
1199       
1200    def OnLoadMask(event):
1201        if event.Id == G2gd.wxID_MASKLOADNOT:
1202            ignoreThreshold = True
1203        else:
1204            ignoreThreshold = False
1205        dlg = wx.FileDialog(G2frame, 'Choose image mask file', '.', '', 
1206            'image mask files (*.immask)|*.immask',wx.OPEN|wx.CHANGE_DIR)
1207        try:
1208            if dlg.ShowModal() == wx.ID_OK:
1209                filename = dlg.GetPath()
1210                File = open(filename,'r')
1211                save = {}
1212                oldThreshold = data['Thresholds'][0]
1213                S = File.readline()
1214                while S:
1215                    if S[0] == '#':
1216                        S = File.readline()
1217                        continue
1218                    [key,val] = S[:-1].split(':')
1219                    if key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']:
1220                        if ignoreThreshold and key == 'Thresholds':
1221                            S = File.readline() 
1222                            continue
1223                        save[key] = eval(val)
1224                        if key == 'Thresholds':
1225                            save[key][0] = oldThreshold
1226                            save[key][1][1] = min(oldThreshold[1],save[key][1][1])
1227                    S = File.readline()
1228                File.close()
1229                data.update(save)
1230                CleanupMasks(data)
1231                wx.CallAfter(UpdateMasks,G2frame,data)
1232                G2plt.PlotExposedImage(G2frame,event=event)               
1233        finally:
1234            dlg.Destroy()
1235           
1236    def OnNewSpotMask(event):
1237        'Start a new spot mask'
1238        G2frame.MaskKey = 's'
1239        G2plt.OnStartMask(G2frame)
1240       
1241    def OnNewArcMask(event):
1242        'Start a new arc mask'
1243        G2frame.MaskKey = 'a'
1244        G2plt.OnStartMask(G2frame)
1245       
1246    def OnNewRingMask(event):
1247        'Start a new ring mask'
1248        G2frame.MaskKey = 'r'
1249        G2plt.OnStartMask(G2frame)
1250       
1251    def OnNewPolyMask(event):
1252        'Start a new polygon mask'
1253        G2frame.MaskKey = 'p'
1254        G2plt.OnStartMask(G2frame)
1255       
1256    def OnNewFrameMask(event):
1257        'Start a new Frame mask'
1258        G2frame.MaskKey = 'f'
1259        G2plt.OnStartMask(G2frame)
1260
1261    startScroll = None
1262    if G2frame.dataDisplay:
1263        startScroll = G2frame.dataDisplay.GetScrollPos(wx.VERTICAL) # save scroll position
1264        G2frame.dataDisplay.Destroy()
1265    else:
1266        CleanupMasks(data) # posting page for 1st time; clean out anything unfinished
1267    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.MaskMenu)
1268    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyMask, id=G2gd.wxID_MASKCOPY)
1269    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadMask, id=G2gd.wxID_MASKLOAD)
1270    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadMask, id=G2gd.wxID_MASKLOADNOT)
1271    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveMask, id=G2gd.wxID_MASKSAVE)
1272    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewSpotMask, id=G2gd.wxID_NEWMASKSPOT)
1273    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewArcMask, id=G2gd.wxID_NEWMASKARC)
1274    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewRingMask, id=G2gd.wxID_NEWMASKRING)
1275    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewPolyMask, id=G2gd.wxID_NEWMASKPOLY)
1276    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewFrameMask, id=G2gd.wxID_NEWMASKFRAME)
1277    if not G2frame.dataFrame.GetStatusBar():
1278        Status = G2frame.dataFrame.CreateStatusBar()
1279    if G2frame.MaskKey == 'f':
1280        G2frame.dataFrame.GetStatusBar().SetStatusText('Frame mask active - LB pick next point, RB close polygon')
1281    elif G2frame.MaskKey == 'p':
1282        G2frame.dataFrame.GetStatusBar().SetStatusText('Polygon mask active - LB pick next point, RB close polygon')
1283    elif G2frame.MaskKey == 's':
1284        G2frame.dataFrame.GetStatusBar().SetStatusText('Spot mask active - LB pick spot location')
1285    elif G2frame.MaskKey == 'a':
1286        G2frame.dataFrame.GetStatusBar().SetStatusText('Arc mask active - LB pick arc location')
1287    elif G2frame.MaskKey == 'r':
1288        G2frame.dataFrame.GetStatusBar().SetStatusText('Ring mask active - LB pick ring location')
1289    else:
1290        G2frame.dataFrame.GetStatusBar().SetStatusText("To add mask: press a,r,s,p or f on 2D image for arc/ring/spot/polygon/frame")
1291    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
1292    mainSizer = wx.BoxSizer(wx.VERTICAL)
1293    mainSizer.Add((5,10),0)
1294
1295    thresh = data['Thresholds']         #min/max intensity range
1296    Spots = data['Points']               #x,y,radius in mm
1297    Rings = data['Rings']               #radius, thickness
1298    Polygons = data['Polygons']         #3+ x,y pairs
1299    if 'Frames' not in data:
1300        data['Frames'] = []
1301    frame = data['Frames']             #3+ x,y pairs
1302    Arcs = data['Arcs']                 #radius, start/end azimuth, thickness
1303   
1304    littleSizer = wx.FlexGridSizer(0,3,0,5)
1305    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Lower/Upper limits '),0,WACV)
1306    Text = wx.TextCtrl(G2frame.dataDisplay,value=str(thresh[0][0]),style=wx.TE_READONLY)
1307    littleSizer.Add(Text,0,WACV)
1308    Text.SetBackgroundColour(VERY_LIGHT_GREY)
1309    Text = wx.TextCtrl(G2frame.dataDisplay,value=str(thresh[0][1]),style=wx.TE_READONLY)
1310    littleSizer.Add(Text,0,WACV)
1311    Text.SetBackgroundColour(VERY_LIGHT_GREY)
1312    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Lower/Upper thresholds '),0,WACV)
1313    lowerThreshold = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=0,
1314                                           min=thresh[0][0],OnLeave=Replot,typeHint=int)
1315    littleSizer.Add(lowerThreshold,0,WACV)
1316    upperThreshold = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=1,
1317                                           max=thresh[0][1],OnLeave=Replot,typeHint=int)
1318    littleSizer.Add(upperThreshold,0,WACV)
1319    mainSizer.Add(littleSizer,0,)
1320    if Spots:
1321        lbl = wx.StaticText(parent=G2frame.dataDisplay,label=' Spot masks')
1322        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1323        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1324        littleSizer = wx.FlexGridSizer(0,3,0,5)
1325        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' position, mm'),0,WACV)
1326        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' diameter, mm'),0,WACV)
1327        littleSizer.Add((5,0),0)
1328        for i in range(len(Spots)):
1329            if Spots[i]:
1330                x,y,d = Spots[i]
1331                spotText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.2f,%.2f" % (x,y)),
1332                    style=wx.TE_READONLY)
1333                spotText.SetBackgroundColour(VERY_LIGHT_GREY)
1334                littleSizer.Add(spotText,0,WACV)
1335                spotText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1336                spotDiameter = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Spots[i],key=2,
1337                                           max=100.,OnLeave=Replot,nDig=[8,2])
1338                littleSizer.Add(spotDiameter,0,WACV)
1339                spotDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1340                                            locationcode='Delete+Points+'+str(i),
1341                                            handler=onDeleteMask)
1342                littleSizer.Add(spotDelete,0,WACV)
1343        mainSizer.Add(littleSizer,0,)
1344    if Rings:
1345        lbl = wx.StaticText(parent=G2frame.dataDisplay,label=' Ring masks')
1346        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1347        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1348        littleSizer = wx.FlexGridSizer(0,3,0,5)
1349        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' 2-theta,deg'),0,WACV)
1350        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' thickness, deg'),0,WACV)
1351        littleSizer.Add((5,0),0)
1352        for i in range(len(Rings)):
1353            if Rings[i]:
1354                ringText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (Rings[i][0])),
1355                    style=wx.TE_READONLY)
1356                ringText.SetBackgroundColour(VERY_LIGHT_GREY)
1357                ringText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1358                littleSizer.Add(ringText,0,WACV)
1359                ringThick = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Rings[i],key=1,
1360                                           min=0.001,max=1.,OnLeave=Replot,nDig=[8,3])
1361                littleSizer.Add(ringThick,0,WACV)
1362                ringDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1363                                            locationcode='Delete+Rings+'+str(i),
1364                                            handler=onDeleteMask)
1365                littleSizer.Add(ringDelete,0,WACV)
1366        mainSizer.Add(littleSizer,0,)
1367    if Arcs:
1368        lbl = wx.StaticText(parent=G2frame.dataDisplay,label=' Arc masks')
1369        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1370        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1371        littleSizer = wx.FlexGridSizer(0,4,0,5)
1372        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' 2-theta,deg'),0,WACV)
1373        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' azimuth, deg'),0,WACV)
1374        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' thickness, deg'),0,WACV)
1375        littleSizer.Add((5,0),0)
1376        for i in range(len(Arcs)):
1377            if Arcs[i]:
1378                tth,azimuth,thick = Arcs[i]
1379                arcText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (tth)),
1380                    style=wx.TE_READONLY)
1381                arcText.SetBackgroundColour(VERY_LIGHT_GREY)
1382                arcText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1383                littleSizer.Add(arcText,0,WACV)
1384                azmText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%d,%d" % (azimuth[0],azimuth[1])),
1385                    style=wx.TE_READONLY)
1386                azmText.SetBackgroundColour(VERY_LIGHT_GREY)
1387                azmText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1388                littleSizer.Add(azmText,0,WACV)
1389                arcThick = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Arcs[i],key=2,
1390                                           min=0.001,max=20.,OnLeave=Replot,nDig=[8,3])
1391                littleSizer.Add(arcThick,0,WACV)
1392                arcDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1393                                            locationcode='Delete+Arcs+'+str(i),
1394                                            handler=onDeleteMask)
1395                littleSizer.Add(arcDelete,0,WACV)
1396        mainSizer.Add(littleSizer,0,)
1397    if Polygons:
1398        lbl = wx.StaticText(parent=G2frame.dataDisplay,
1399            label=' Polygon masks (on plot RB vertex drag to move,\nLB vertex drag to insert)')
1400        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1401        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1402        littleSizer = wx.FlexGridSizer(0,2,0,5)
1403        for i in range(len(Polygons)):
1404            if Polygons[i]:
1405                polyList = []
1406                for x,y in Polygons[i]:
1407                    polyList.append("%.2f, %.2f"%(x,y))
1408                polyText = wx.ComboBox(G2frame.dataDisplay,value=polyList[0],choices=polyList,style=wx.CB_READONLY)
1409                littleSizer.Add(polyText,0,WACV)
1410                polyDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1411                                            locationcode='Delete+Polygons+'+str(i),
1412                                            handler=onDeleteMask)
1413                littleSizer.Add(polyDelete,0,WACV)
1414        mainSizer.Add(littleSizer,0,)
1415    if frame:
1416        lbl = wx.StaticText(parent=G2frame.dataDisplay,
1417            label=' Frame mask (on plot RB vertex drag to move,LB vertex drag to insert)')
1418        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1419        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1420        littleSizer = wx.FlexGridSizer(0,2,0,5)
1421        frameList = []
1422        for x,y in frame:
1423            frameList.append("%.2f, %.2f"%(x,y))
1424        frameText = wx.ComboBox(G2frame.dataDisplay,value=frameList[0],choices=frameList,style=wx.CB_READONLY)
1425        littleSizer.Add(frameText,0,WACV)
1426        frameDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1427                                            locationcode='Delete+Frame',
1428                                            handler=onDeleteFrame)
1429        littleSizer.Add(frameDelete,0,WACV)
1430        mainSizer.Add(littleSizer,0,)
1431    mainSizer.Layout()   
1432    G2frame.dataDisplay.SetSizer(mainSizer)
1433    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
1434    G2frame.dataDisplay.SetupScrolling()
1435    Size = mainSizer.Fit(G2frame.dataFrame)
1436    Size[0] += 50 # room for scrollbar & status msg
1437    Size[1] = min(Size[1],500)
1438    G2frame.dataDisplay.SetSize(Size)
1439    G2frame.dataFrame.setSizePosLeft(Size)   
1440    wx.Yield()
1441    if startScroll: # reset scroll to saved position
1442        G2frame.dataDisplay.Scroll(0,startScroll) # set to saved scroll position
1443        wx.Yield()
1444
1445################################################################################
1446##### Stress/Strain
1447################################################################################
1448
1449def UpdateStressStrain(G2frame,data):
1450    '''Shows and handles the controls on the "Stress/Strain"
1451    data tree entry
1452    '''
1453   
1454    def OnAppendDzero(event):
1455        data['d-zero'].append({'Dset':1.0,'Dcalc':0.0,'pixLimit':10,'cutoff':1.0,
1456            'ImxyObs':[[],[]],'ImtaObs':[[],[]],'ImtaCalc':[[],[]],'Emat':[1.0,1.0,1.0]})
1457        UpdateStressStrain(G2frame,data)
1458       
1459    def OnUpdateDzero(event):
1460        for item in data['d-zero']:
1461            if item['Dcalc']:   #skip unrefined ones
1462                item['Dset'] = item['Dcalc']
1463        UpdateStressStrain(G2frame,data)
1464           
1465    def OnCopyStrSta(event):
1466        TextList = [[False,'All IMG',0,0]]
1467#        Names = []
1468        if G2frame.PatternTree.GetCount():
1469            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1470            while id:
1471                name = G2frame.PatternTree.GetItemText(id)
1472#                Names.append(name)
1473                if 'IMG' in name:
1474                    Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Stress/Strain'))
1475                    if id == G2frame.Image:
1476                        Source = name
1477                    else:
1478                        TextList.append([False,name,id,Data.get('Sample load',0.0)])
1479                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1480            if len(TextList) == 1:
1481                G2frame.ErrorDialog('Nothing to copy controls to','There must be more than one "IMG" pattern')
1482                return
1483            dlg = G2frame.CopyDialog(G2frame,'Copy stress/strain controls','Copy controls from '+Source+' to:',TextList)
1484            try:
1485                if dlg.ShowModal() == wx.ID_OK:
1486                    result = dlg.GetData()
1487                    if result[0][0]:
1488                        result = TextList[1:]
1489                        for item in result: item[0] = True
1490                    for i,item in enumerate(result):
1491                        ifcopy,name,id,load = item
1492                        if ifcopy:
1493                            Data = copy.deepcopy(data)
1494                            Data['Sample load'] = load
1495                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Stress/Strain'),Data)
1496            finally:
1497                dlg.Destroy()
1498
1499    def OnLoadStrSta(event):
1500        dlg = wx.FileDialog(G2frame, 'Choose stress/strain file', '.', '', 
1501            'image control files (*.strsta)|*.strsta',wx.OPEN|wx.CHANGE_DIR)
1502        try:
1503            if dlg.ShowModal() == wx.ID_OK:
1504                filename = dlg.GetPath()
1505                File = open(filename,'r')
1506                S = File.read()
1507                data = eval(S)
1508                Controls = G2frame.PatternTree.GetItemPyData(
1509                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
1510                G2img.FitStrSta(G2frame.ImageZ,data,Controls)
1511                UpdateStressStrain(G2frame,data)
1512                G2plt.PlotExposedImage(G2frame,event=event)
1513                G2plt.PlotStrain(G2frame,data,newPlot=True)
1514                File.close()
1515        finally:
1516            dlg.Destroy()
1517
1518    def OnSaveStrSta(event):
1519        dlg = wx.FileDialog(G2frame, 'Choose stress/strain file', '.', '', 
1520            'image control files (*.strsta)|*.strsta',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1521        try:
1522            if dlg.ShowModal() == wx.ID_OK:
1523                filename = dlg.GetPath()
1524                File = open(filename,'w')
1525                save = {}
1526                keys = ['Type','Sample phi','Sample z','Sample load']
1527                keys2 = ['Dset','Dcalc','pixLimit','cutoff','Emat']
1528                File.write('{\n\t')
1529                for key in keys:
1530                    if key in 'Type':
1531                        File.write("'"+key+"':'"+data[key]+"',")
1532                    else:
1533                        File.write("'"+key+"':"+str(data[key])+',')
1534                File.write('\n\t'+"'d-zero':[\n")
1535                for data2 in data['d-zero']:
1536                    File.write('\t\t{')
1537                    for key in keys2:
1538                        File.write("'"+key+"':"+str(data2[key])+',')
1539                    File.write("'ImxyObs':[[],[]],'ImtaObs':[[],[]],'ImtaCalc':[[],[]]},\n")
1540                File.write('\t]\n}')
1541                File.close()
1542        finally:
1543            dlg.Destroy()
1544           
1545    def OnStrStaSample(event):
1546        filename = ''
1547        dlg = wx.FileDialog(G2frame, 'Choose multihistogram metadata text file', '.', '', 
1548            'metadata file (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
1549        try:
1550            if dlg.ShowModal() == wx.ID_OK:
1551                filename = dlg.GetPath()
1552                File = open(filename,'r')
1553                S = File.readline()
1554                newItems = []
1555                itemNames = []
1556                Comments = []
1557                while S:
1558                    if S[0] == '#':
1559                        Comments.append(S)
1560                        S = File.readline()
1561                        continue
1562                    S = S.replace(',',' ').replace('\t',' ')
1563                    Stuff = S[:-1].split()
1564                    itemNames.append(Stuff[0])
1565                    newItems.append(Stuff[1:])
1566                    S = File.readline()               
1567                File.close()
1568        finally:
1569            dlg.Destroy()
1570        if not filename:
1571            G2frame.ErrorDialog('Nothing to do','No file selected')
1572            return
1573        dataDict = dict(zip(itemNames,newItems))
1574        ifany = False
1575        Names = [' ','Sample phi','Sample z','Sample load']
1576        dlg = G2G.G2ColumnIDDialog( G2frame,' Choose multihistogram metadata columns:',
1577            'Select columns',Comments,Names,np.array(newItems).T)
1578        try:
1579            if dlg.ShowModal() == wx.ID_OK:
1580                colNames,newData = dlg.GetSelection()
1581                dataDict = dict(zip(itemNames,newData.T))
1582                for item in colNames:
1583                    if item != ' ':
1584                        ifany = True
1585        finally:
1586            dlg.Destroy()
1587        if not ifany:
1588            G2frame.ErrorDialog('Nothing to do','No columns identified')
1589            return
1590        histList = []
1591        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
1592        while item:
1593            name = G2frame.PatternTree.GetItemText(item)
1594            if name.startswith('IMG'):
1595                histList.append(name)
1596            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1597        colIds = {}
1598        for i,name in enumerate(colNames):
1599            if name != ' ':
1600                colIds[name] = i
1601        for hist in histList:
1602            name = hist.split()[1]  #this is file name
1603            if name in dataDict:
1604                newItems = {}
1605                for item in colIds:
1606                    newItems[item] = float(dataDict[name][colIds[item]])
1607                Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
1608                stsrData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Stress/Strain'))
1609                stsrData.update(newItems)       
1610        UpdateStressStrain(G2frame,data)       
1611   
1612    def OnFitStrSta(event):
1613        Controls = G2frame.PatternTree.GetItemPyData(
1614            G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
1615        G2img.FitStrSta(G2frame.ImageZ,data,Controls)
1616        print 'Strain fitting finished'
1617        UpdateStressStrain(G2frame,data)
1618        G2plt.PlotExposedImage(G2frame,event=event)
1619        G2plt.PlotStrain(G2frame,data,newPlot=True)
1620       
1621    def OnFitAllStrSta(event):
1622        TextList = [[False,'All IMG',0]]
1623#        Names = []
1624        if G2frame.PatternTree.GetCount():
1625            choices = G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
1626            if len(choices) == 1:
1627                G2frame.ErrorDialog('Nothing to fit','There must some "IMG" patterns')
1628                return
1629            sel = []
1630            dlg = G2G.G2MultiChoiceDialog(G2frame,'Stress/Strain fitting','Select images to fit:',choices)
1631            dlg.SetSelections(sel)
1632            names = []
1633            if dlg.ShowModal() == wx.ID_OK:
1634                for sel in dlg.GetSelections():
1635                    names.append(choices[sel])
1636            dlg.Destroy()
1637            SeqResult = {}
1638            dlg = wx.ProgressDialog('Sequential IMG Strain fit','Data set name = '+names[0],len(names), 
1639                style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)         
1640            wx.BeginBusyCursor()
1641            goodnames = []
1642            try:
1643                for i,name in enumerate(names):
1644                    print ' Sequential strain fit for ',name
1645                    GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
1646                    if not GoOn:
1647                        break
1648                    Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
1649                    Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Image Controls'))
1650                    StaCtrls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Stress/Strain'))
1651                    if not len(StaCtrls['d-zero']):
1652                        continue
1653                    goodnames.append(name)
1654                    id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, name)
1655                    Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Id)
1656                    image = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
1657                    dark = Controls['dark image']
1658                    if dark[0]:
1659                        id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root,dark[0])
1660                        Npix,darkfile,imagetag = G2frame.PatternTree.GetImageLoc(id)
1661                        darkImg = G2IO.GetImageData(G2frame,darkfile,True,ImageTag=imagetag)
1662                        image += dark[1]*darkImg
1663                    G2img.FitStrSta(image,StaCtrls,Controls)
1664                    G2plt.PlotStrain(G2frame,StaCtrls,newPlot=True)
1665                    parmDict = {'Sample load':StaCtrls['Sample load'],}
1666                    varyNames = ['e11','e12','e22']
1667                    sig = []
1668                    varyList = []
1669                    variables = []
1670                    for i,item in enumerate(StaCtrls['d-zero']):
1671                        variables += item['Emat']
1672                        sig += item['Esig']
1673                        varylist = ['%d%s%s'%(i,';',Name) for Name in varyNames]
1674                        varyList += varylist
1675                        parmDict.update(dict(zip(varylist,item['Emat'])))
1676                        parmDict['%d:Dcalc'%(i)] = item['Dcalc']
1677                    SeqResult[name] = {'variables':variables,'varyList':varyList,'sig':sig,'Rvals':[],
1678                        'covMatrix':np.eye(len(variables)),'title':name,'parmDict':parmDict}
1679                else:
1680                    SeqResult['histNames'] = goodnames
1681                    dlg.Destroy()
1682                    print ' ***** Sequential strain refinement successful *****'
1683            finally:
1684                wx.EndBusyCursor()   
1685            Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
1686            if Id:
1687                G2frame.PatternTree.SetItemPyData(Id,SeqResult)
1688            else:
1689                Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
1690                G2frame.PatternTree.SetItemPyData(Id,SeqResult)
1691            G2frame.PatternTree.SelectItem(Id)
1692            print 'All images fitted'
1693       
1694    def SamSizer():
1695       
1696        def OnStrainType(event):
1697            data['Type'] = strType.GetValue()
1698       
1699        def OnSamPhi(event):
1700            try:
1701                value = float(samPhi.GetValue())
1702            except ValueError:
1703                value = data['Sample phi']
1704            data['Sample phi'] = value
1705            samPhi.SetValue("%.3f" % (data['Sample phi']))
1706               
1707        def OnSamZ(event):
1708            try:
1709                value = float(samZ.GetValue())
1710            except ValueError:
1711                value = data['Sample z']
1712            data['Sample z'] = value
1713            samZ.SetValue("%.3f" % (data['Sample z']))
1714               
1715        def OnSamLoad(event):
1716            try:
1717                value = float(samLoad.GetValue())
1718            except ValueError:
1719                value = data['Sample load']
1720            data['Sample load'] = value
1721            samLoad.SetValue("%.3f" % (data['Sample load']))
1722               
1723        samSizer = wx.BoxSizer(wx.HORIZONTAL)
1724        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Strain type: '),0,WACV)
1725        strType = wx.ComboBox(G2frame.dataDisplay,value=data['Type'],choices=['True','Conventional'],
1726            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1727        strType.SetValue(data['Type'])
1728        strType.Bind(wx.EVT_COMBOBOX, OnStrainType)
1729        samSizer.Add(strType,0,WACV)
1730       
1731        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Sample phi: '),0,WACV)
1732        samPhi = wx.TextCtrl(G2frame.dataDisplay,-1,value=("%.3f" % (data['Sample phi'])),
1733            style=wx.TE_PROCESS_ENTER)
1734        samSizer.Add(samPhi,0,WACV)
1735        samPhi.Bind(wx.EVT_TEXT_ENTER,OnSamPhi)
1736        samPhi.Bind(wx.EVT_KILL_FOCUS,OnSamPhi)
1737        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Sample delta-z(mm): '),0,WACV)
1738        samZ = wx.TextCtrl(G2frame.dataDisplay,-1,value=("%.3f" % (data['Sample z'])),
1739            style=wx.TE_PROCESS_ENTER)
1740        samSizer.Add(samZ,0,WACV)
1741        samZ.Bind(wx.EVT_TEXT_ENTER,OnSamZ)
1742        samZ.Bind(wx.EVT_KILL_FOCUS,OnSamZ)
1743        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Sample load(MPa): '),0,WACV)
1744        samLoad = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'Sample load',
1745                nDig=[8,3],typeHint=float,)
1746        samSizer.Add(samLoad,0,WACV)
1747
1748        return samSizer
1749       
1750    def DzeroSizer():
1751   
1752        def OnDzero(event):
1753            Obj = event.GetEventObject()
1754            try:
1755                value = min(20.0,max(0.25,float(Obj.GetValue())))
1756            except ValueError:
1757                value = 1.0
1758            Obj.SetValue("%.5f"%(value))
1759            data['d-zero'][Indx[Obj.GetId()]]['Dset'] = value
1760            data['d-zero'] = G2mth.sortArray(data['d-zero'],'Dset',reverse=True)
1761            Ring,R = G2img.MakeStrStaRing(data['d-zero'][Indx[Obj.GetId()]],G2frame.ImageZ,Controls)
1762            if len(Ring):
1763                data['d-zero'][Indx[Obj.GetId()]].update(R)
1764            else:
1765                G2frame.ErrorDialog('Strain peak selection','WARNING - No points found for this ring selection')
1766               
1767            UpdateStressStrain(G2frame,data)
1768            G2plt.PlotExposedImage(G2frame,event=event,newPlot=False)
1769            G2plt.PlotStrain(G2frame,data,newPlot=True)
1770           
1771        def OnDeleteDzero(event):
1772            Obj = event.GetEventObject()
1773            del(data['d-zero'][delIndx.index(Obj)])
1774            UpdateStressStrain(G2frame,data)
1775            G2plt.PlotExposedImage(G2frame,event=event,newPlot=True)
1776            G2plt.PlotStrain(G2frame,data,newPlot=True)
1777       
1778        def OnCutOff(event):
1779            Obj = event.GetEventObject()
1780            try:
1781                value = min(10.0,max(0.5,float(Obj.GetValue())))
1782            except ValueError:
1783                value = 1.0
1784            Obj.SetValue("%.1f"%(value))
1785            data['d-zero'][Indx[Obj.GetId()]]['cutoff'] = value
1786            Ring,R = G2img.MakeStrStaRing(data['d-zero'][Indx[Obj.GetId()]],G2frame.ImageZ,Controls)
1787            G2plt.PlotExposedImage(G2frame,event=event)
1788            G2plt.PlotStrain(G2frame,data,newPlot=True)
1789       
1790        def OnPixLimit(event):
1791            Obj = event.GetEventObject()
1792            data['d-zero'][Indx[Obj.GetId()]]['pixLimit'] = int(Obj.GetValue())
1793            Ring,R = G2img.MakeStrStaRing(data['d-zero'][Indx[Obj.GetId()]],G2frame.ImageZ,Controls)
1794            G2plt.PlotExposedImage(G2frame,event=event)
1795            G2plt.PlotStrain(G2frame,data,newPlot=True)
1796           
1797        Indx = {}
1798        delIndx = []   
1799        dzeroSizer = wx.FlexGridSizer(0,8,5,5)
1800        for id,dzero in enumerate(data['d-zero']):
1801            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=(' d-zero #%d: '%(id))),0,WACV)
1802            dZero = wx.TextCtrl(G2frame.dataDisplay,-1,value=('%.5f'%(dzero['Dset'])),
1803                style=wx.TE_PROCESS_ENTER)
1804            dzeroSizer.Add(dZero,0,WACV)
1805            dZero.Bind(wx.EVT_TEXT_ENTER,OnDzero)
1806            dZero.Bind(wx.EVT_KILL_FOCUS,OnDzero)
1807            Indx[dZero.GetId()] = id
1808            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=(' d-zero ave: %.5f'%(dzero['Dcalc']))),0,WACV)
1809               
1810            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min ring I/Ib '),0,WACV)
1811            cutOff = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.1f" % (dzero['cutoff'])),
1812                style=wx.TE_PROCESS_ENTER)
1813            cutOff.Bind(wx.EVT_TEXT_ENTER,OnCutOff)
1814            cutOff.Bind(wx.EVT_KILL_FOCUS,OnCutOff)
1815            Indx[cutOff.GetId()] = id
1816            dzeroSizer.Add(cutOff,0,WACV)
1817       
1818            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Pixel search range '),0,WACV)
1819            pixLimit = wx.ComboBox(parent=G2frame.dataDisplay,value=str(dzero['pixLimit']),choices=['1','2','5','10','15','20'],
1820                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1821            pixLimit.Bind(wx.EVT_COMBOBOX, OnPixLimit)
1822            Indx[pixLimit.GetId()] = id
1823            dzeroSizer.Add(pixLimit,0,WACV)               
1824               
1825            dzeroDelete = wx.CheckBox(parent=G2frame.dataDisplay,label='delete?')
1826            dzeroDelete.Bind(wx.EVT_CHECKBOX,OnDeleteDzero)
1827            delIndx.append(dzeroDelete)
1828            dzeroSizer.Add(dzeroDelete,0,WACV)
1829           
1830            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=(' Strain tensor:')),WACV)
1831            names = ['e11','e12','e22']
1832            for i in range(3):
1833                dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=names[i]),0,WACV)
1834                tensorElem = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(dzero['Emat'][i]),style=wx.TE_READONLY)
1835                tensorElem.SetBackgroundColour(VERY_LIGHT_GREY)
1836                dzeroSizer.Add(tensorElem,0,WACV)
1837            dzeroSizer.Add((5,5),0)             
1838        return dzeroSizer
1839       
1840# patches
1841    if 'Sample load' not in data:
1842        data['Sample load'] = 0.0
1843# end patches
1844   
1845    if G2frame.dataDisplay:
1846        G2frame.dataDisplay.Destroy()
1847    Controls = G2frame.PatternTree.GetItemPyData(
1848        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))       
1849    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.StrStaMenu)
1850    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAppendDzero, id=G2gd.wxID_APPENDDZERO)
1851    G2frame.dataFrame.Bind(wx.EVT_MENU, OnUpdateDzero, id=G2gd.wxID_UPDATEDZERO)
1852    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitStrSta, id=G2gd.wxID_STRSTAFIT)
1853    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitAllStrSta, id=G2gd.wxID_STRSTAALLFIT)
1854    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyStrSta, id=G2gd.wxID_STRSTACOPY)
1855    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadStrSta, id=G2gd.wxID_STRSTALOAD)
1856    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveStrSta, id=G2gd.wxID_STRSTASAVE)
1857    G2frame.dataFrame.Bind(wx.EVT_MENU, OnStrStaSample, id=G2gd.wxID_STRSTSAMPLE)       
1858    if not G2frame.dataFrame.GetStatusBar():
1859        Status = G2frame.dataFrame.CreateStatusBar()
1860    if G2frame.StrainKey == 'a':    #probably doesn't happen
1861        G2frame.dataFrame.GetStatusBar().SetStatusText('Add strain ring active - LB pick d-zero value')
1862    else:
1863        G2frame.dataFrame.GetStatusBar().SetStatusText("To add strain data: On 2D Powder Image, key a:add ring")
1864       
1865    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
1866    mainSizer = wx.BoxSizer(wx.VERTICAL)
1867    mainSizer.Add((5,10),0)
1868    mainSizer.Add(SamSizer())
1869    mainSizer.Add((5,10),0)
1870    mainSizer.Add(DzeroSizer())
1871   
1872    mainSizer.Layout()   
1873    G2frame.dataDisplay.SetSizer(mainSizer)
1874    G2frame.dataDisplay.SetAutoLayout(1)
1875    G2frame.dataDisplay.SetupScrolling()
1876    Size = mainSizer.Fit(G2frame.dataFrame)
1877    Size[0] += 25
1878    G2frame.dataDisplay.SetSize(Size)
1879    G2frame.dataFrame.setSizePosLeft(Size)   
1880
1881###########################################################################
1882# Autointegration follows
1883def 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
1900def 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
1930def 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   
1979class 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
1992    def __init__(self,G2frame,PollTime=60.0):
1993        def OnStart(event):
1994            '''Called when the start button is pressed. Changes button label
1995            to Pause. When Pause is pressed the label changes to Resume.
1996            When either Start or Resume is pressed, the processing loop
1997            is started. When Pause is pressed, the loop is stopped.
1998            '''
1999            # check inputs for errors before starting
2000            #err = ''
2001            #if not any([self.params[fmt] for fmt in self.fmtlist]):
2002            #    err += '\nPlease select at least one output format\n'
2003            #if err:
2004            #    G2G.G2MessageBox(self,err)
2005            #    return
2006            self.Pause = False
2007            # change button label
2008            if btnstart.GetLabel() != 'Pause':
2009                btnstart.SetLabel('Pause')
2010                if self.timer.IsRunning(): self.timer.Stop()
2011                self.PreventReEntryTimer = False
2012                self.StartLoop()
2013                self.OnTimerLoop(None) # run once immediately and again after delay
2014                self.timer.Start(int(1000*PollTime),oneShot=False)
2015                self.Status.SetStatusText('Press Pause to delay integration or Reset to prepare to reintegrate all images')
2016            else:
2017                btnstart.SetLabel('Resume')
2018                if self.timer.IsRunning(): self.timer.Stop()
2019                print('\nPausing autointegration\n')
2020                self.Status.SetStatusText('Press Resume to continue integration or Reset to prepare to reintegrate all images')
2021                self.Pause = True
2022
2023        def OnReset(event):
2024            '''Called when Reset button is pressed. This stops the
2025            processing loop and resets the list of integrated files so
2026            all images can be reintegrated.
2027            '''
2028            btnstart.SetLabel('Restart')
2029            self.Status.SetStatusText('Press Restart to reload and re-integrate images matching filter')
2030            if self.timer.IsRunning(): self.timer.Stop()
2031            self.Reset = True
2032            self.Pause = True
2033           
2034        def OnQuit(event):
2035            '''Stop the processing loop and close the Frame
2036            '''
2037            if self.timer.IsRunning(): self.timer.Stop() # make sure we stop first
2038            wx.CallAfter(self.Destroy)
2039           
2040        def OnBrowse(event):
2041            '''Responds when the Browse button is pressed to load a file.
2042            The routine determines which button was pressed and gets the
2043            appropriate file type and loads it into the appropriate place
2044            in the dict.
2045            '''
2046            if btn3 == event.GetEventObject():
2047                dlg = wx.DirDialog(
2048                    self, 'Select directory for output files',
2049                    self.params['outdir'],wx.DD_DEFAULT_STYLE)
2050                dlg.CenterOnParent()
2051                try:
2052                    if dlg.ShowModal() == wx.ID_OK:
2053                        self.params['outdir'] = dlg.GetPath()
2054                        fInp3.SetValue(self.params['outdir'])
2055                finally:
2056                    dlg.Destroy()
2057                return
2058               
2059        def OnRadioSelect(event):
2060            '''Respond to a radiobutton selection and when in table
2061            mode, get parameters from user.
2062            '''
2063            self.Evaluator = None
2064            if r2.GetValue():
2065                try:
2066                    dlg = IntegParmTable(self.G2frame) # create the dialog
2067                    if dlg.ShowModal() == wx.ID_OK:
2068                        self.Evaluator = DefineEvaluator(dlg)
2069                        self.params['Mode'] = 'table'
2070                        r2E.Enable(True)
2071                    else:
2072                        self.useActive.SetValue(True)
2073                finally:
2074                    dlg.Destroy()
2075            if self.useActive.GetValue():
2076                self.params['Mode'] = 'active'
2077                self.imageBase = G2frame.Image
2078                self.useActive.SetLabel("Active Image: "+
2079                        G2frame.PatternTree.GetItemText(self.imageBase))
2080
2081        def OnEditTable(event): 
2082            raise Exception
2083
2084        ##################################################
2085        # beginning of __init__ processing
2086        ##################################################
2087        self.G2frame = G2frame
2088        self.Evaluator = None
2089        self.params = {}
2090        self.Reset = False
2091        self.Pause = False
2092        self.PreventReEntryShowMatch = False
2093        self.PreventReEntryTimer = False
2094        self.params['IMGfile'] = ''
2095        self.params['MaskFile'] = ''
2096        self.params['IgnoreMask'] = True
2097        self.fmtlist = G2IO.ExportPowderList(G2frame)
2098        self.timer = wx.Timer()
2099        self.timer.Bind(wx.EVT_TIMER,self.OnTimerLoop)
2100        self.imageBase = G2frame.Image
2101
2102        controlsId = G2frame.PatternTree.GetSelection()
2103        size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(self.imageBase)       
2104        self.imagedir,fileroot = os.path.split(imagefile)
2105        self.params['filter'] = '*'+os.path.splitext(fileroot)[1]
2106        self.params['outdir'] = os.path.abspath(self.imagedir)
2107        wx.Frame.__init__(self, G2frame,title='Automatic Integration')
2108        self.Status = self.CreateStatusBar()
2109        self.Status.SetStatusText('Press Start to load and integrate images matching filter')
2110        mnpnl = wx.Panel(self)
2111        mnsizer = wx.BoxSizer(wx.VERTICAL)
2112        # box for integration controls & masks input
2113        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Integration Control")
2114        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
2115        lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Use integration parameters from:'))
2116        self.useActive = wx.RadioButton(mnpnl, wx.ID_ANY, 
2117                            style = wx.RB_GROUP)
2118        self.useActive.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
2119        self.useActive.SetLabel("Active Image: "+
2120                                G2frame.PatternTree.GetItemText(self.imageBase))
2121        lblsizr.Add(self.useActive,1,wx.EXPAND,1)
2122        self.useActive.SetValue(True)
2123        minisizer = wx.BoxSizer(wx.HORIZONTAL)
2124        r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "From look-up table")
2125        minisizer.Add(r2,1,wx.ALIGN_LEFT,1)
2126        r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
2127        r2E = wx.Button(mnpnl,  wx.ID_ANY, "Edit table")
2128        minisizer.Add(r2E,1,wx.ALIGN_LEFT,1)
2129        r2E.Enable(False)
2130        r2E.Bind(wx.EVT_BUTTON, OnEditTable)
2131        # bind button and deactivate be default
2132        lblsizr.Add(minisizer)
2133        mnsizer.Add(lblsizr,1,wx.EXPAND,1)
2134
2135        # file filter stuff
2136        sizer = wx.BoxSizer(wx.HORIZONTAL)
2137        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Image filter'))
2138        flterInp = G2G.ValidatedTxtCtrl(mnpnl,self.params,'filter',
2139                                        OnLeave=self.ShowMatchingFiles)
2140        sizer.Add(flterInp)
2141        mnsizer.Add(sizer,0,wx.ALIGN_RIGHT,1)
2142        self.ListBox = wx.ListBox(mnpnl,size=(-1,100))
2143        mnsizer.Add(self.ListBox,0,wx.EXPAND,1)
2144        self.ShowMatchingFiles(self.params['filter'])
2145        # box for output selections
2146        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Output settings")
2147        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
2148        sizer = wx.BoxSizer(wx.HORIZONTAL)
2149        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Write to: '))
2150        fInp3 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'outdir',
2151                                       notBlank=False,size=(300,-1))
2152        sizer.Add(fInp3)
2153        btn3 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
2154        btn3.Bind(wx.EVT_BUTTON, OnBrowse)
2155        sizer.Add(btn3)
2156        lblsizr.Add(sizer)
2157        #lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
2158        sizer = wx.BoxSizer(wx.HORIZONTAL)
2159        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
2160        for dfmt in self.fmtlist:
2161            fmt = dfmt[1:]
2162            self.params[fmt] = False
2163            btn = G2G.G2CheckBox(mnpnl,dfmt,self.params,fmt)
2164            sizer.Add(btn)
2165        lblsizr.Add(sizer)
2166        sizer = wx.BoxSizer(wx.HORIZONTAL)
2167        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Separate dir for each format: '))
2168        self.params['SeparateDir'] = False
2169        sizer.Add(G2G.G2CheckBox(mnpnl,'',self.params,'SeparateDir'))
2170        lblsizr.Add(sizer)
2171        mnsizer.Add(lblsizr,0,wx.ALIGN_CENTER,1)
2172
2173        # buttons on bottom
2174        mnsizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'AutoIntegration controls'),0,wx.TOP,5)
2175        sizer = wx.BoxSizer(wx.HORIZONTAL)
2176        sizer.Add((20,-1))
2177        btnstart = wx.Button(mnpnl,  wx.ID_ANY, "Start")
2178        btnstart.Bind(wx.EVT_BUTTON, OnStart)
2179        sizer.Add(btnstart)
2180        btnstop = wx.Button(mnpnl,  wx.ID_ANY, "Reset")
2181        btnstop.Bind(wx.EVT_BUTTON, OnReset)
2182        sizer.Add(btnstop)
2183        sizer.Add((20,-1),wx.EXPAND,1)
2184        btnquit = wx.Button(mnpnl,  wx.ID_ANY, "Close")
2185        btnquit.Bind(wx.EVT_BUTTON, OnQuit)
2186        sizer.Add(btnquit)
2187        sizer.Add((20,-1))
2188        mnsizer.Add(sizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP,5)
2189       
2190        # finish up window
2191        mnpnl.SetSizer(mnsizer)
2192        OnRadioSelect(None) # disable widgets
2193        mnsizer.Fit(self)
2194        self.CenterOnParent()
2195        self.Show()
2196
2197    def ShowMatchingFiles(self,value,invalid=False,**kwargs):
2198        G2frame = self.G2frame
2199        if invalid: return
2200        msg = ''
2201        if self.PreventReEntryShowMatch: return
2202        self.PreventReEntryShowMatch = True
2203        imageFileList = []
2204        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2205            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2206            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2207            if imagefile not in imageFileList: imageFileList.append(imagefile)
2208            if img not in G2frame.IntegratedList:
2209                if msg: msg += '\n'
2210                msg += '  ' + img
2211        if msg: msg = "Loaded images to integrate:\n" + msg + "\n"
2212        msg1 = ""
2213        try:
2214            imageList = sorted(
2215                glob.glob(os.path.join(self.imagedir,value)))
2216            if not imageList:
2217                msg1 = 'Warning: No files match search string '+os.path.join(self.imagedir,value)
2218            else:
2219                for fil in imageList:
2220                    if fil not in imageFileList: msg1 += '\n  '+fil
2221                if msg1:
2222                    msg += 'Files to integrate from '+os.path.join(self.imagedir,value)+msg1
2223                else:
2224                    msg += 'All files integrated'
2225        except IndexError:
2226            msg += 'Error searching for files named '+os.path.join(self.imagedir,value)
2227        self.ListBox.Clear()
2228        self.ListBox.AppendItems(msg.split('\n'))
2229        self.PreventReEntryShowMatch = False
2230        return
2231       
2232    def IntegrateImage(self,img):
2233        '''Integrates a single image'''
2234        G2frame = self.G2frame
2235        imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2236        G2frame.Image = imgId
2237        G2frame.PickId = G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls')
2238        # do integration
2239        size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2240        G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,True,imagetag)
2241        masks = G2frame.PatternTree.GetItemPyData(
2242                G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2243        data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
2244        # simulate a Image Controls press, since that is where the
2245        # integration is hidden
2246        UpdateImageControls(G2frame,data,masks,IntegrateOnly=True)
2247        G2frame.IntegratedList.append(img) # note this as integrated
2248        # split name and control number
2249        s = re.split(r'(\d+)\Z',os.path.split(os.path.splitext(imagefile)[0])[1])
2250        namepre = s[0]
2251        if len(s) > 1:
2252            namenum = s[1]
2253        else:
2254            namenum = ''
2255        for Id in G2frame.IntgOutList: # loop over newly created PDWR entry(ies)
2256            # save the created PWDR tree names so that a reset can delete them
2257            treename = G2frame.PatternTree.GetItemText(Id)
2258            G2frame.AutointPWDRnames.append(treename)
2259            # write out the images in the selected formats
2260            Sdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
2261            # determine the name for the current file
2262            fileroot = namepre
2263            if len(G2frame.IntgOutList) > 1:
2264                fileroot += "_AZM"
2265                if 'Azimuth' in Sdata:
2266                    fileroot += str(int(10*Sdata['Azimuth']))
2267                fileroot += "_" 
2268            fileroot += namenum
2269            # loop over selected formats
2270            for dfmt in self.fmtlist:
2271                if not self.params[dfmt[1:]]: continue
2272                if self.params['SeparateDir']:
2273                    subdir = dfmt[1:]
2274                else:
2275                    subdir = ''
2276                fil = os.path.join(self.params['outdir'],subdir,fileroot)
2277                print('writing file '+fil+dfmt)
2278                G2IO.ExportPowder(G2frame,treename,fil,dfmt)
2279               
2280    def ResetFromTable(self,dist):
2281        '''Sets integration parameters based on values from
2282        the lookup table
2283        '''
2284        #dist = self.controlsDict['distance']
2285        interpDict,imgctrl,immask = self.Evaluator(dist) # interpolated calibration values
2286        #if GSASIIpath.GetConfigValue('debug'):
2287        if GSASIIpath.GetConfigValue('debug'):
2288            print 'interpolated values: ',interpDict
2289        self.ImageControls = ReadControls(imgctrl)
2290        self.ImageControls.update(interpDict)
2291        self.ImageControls['showLines'] = True
2292        self.ImageControls['ring'] = []
2293        self.ImageControls['rings'] = []
2294        self.ImageControls['ellipses'] = []
2295        self.ImageControls['setDefault'] = False
2296        for i in 'range','size','GonioAngles':
2297            if i in self.ImageControls:
2298                del self.ImageControls[i]
2299        # load copy of Image Masks
2300        if immask:
2301            self.ImageMasks = ReadMask(immask)
2302            del self.Thresholds['Thresholds']
2303        else:
2304            self.ImageMasks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[]}
2305       
2306    def StartLoop(self):
2307        '''Save current Image params for use in future integrations
2308        also label the window so users understand what is being used
2309        '''
2310        print '\nStarting new autointegration\n'
2311        G2frame = self.G2frame
2312        # show current IMG base
2313        if self.params['Mode'] != 'table':
2314            self.useActive.SetLabel("Active Image: "+
2315                                    G2frame.PatternTree.GetItemText(self.imageBase))
2316            # load copy of Image Controls from current image and clean up
2317            # items that should not be copied
2318            self.ImageControls = copy.deepcopy(
2319                G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
2320                    G2frame,self.imageBase, 'Image Controls')))
2321            self.ImageControls['showLines'] = True
2322            self.ImageControls['ring'] = []
2323            self.ImageControls['rings'] = []
2324            self.ImageControls['ellipses'] = []
2325            self.ImageControls['setDefault'] = False
2326            del self.ImageControls['range']
2327            del self.ImageControls['size']
2328            del self.ImageControls['GonioAngles']
2329            # load copy of Image Masks, keep thresholds
2330            self.ImageMasks = copy.deepcopy(
2331                G2frame.PatternTree.GetItemPyData(
2332                    G2gd.GetPatternTreeItemId(G2frame,self.imageBase, 'Masks')))
2333            self.Thresholds = self.ImageMasks['Thresholds'][:]
2334        # make sure all output directories exist
2335        if self.params['SeparateDir']:
2336            for dfmt in self.fmtlist:
2337                if not self.params[dfmt[1:]]: continue
2338                dir = os.path.join(self.params['outdir'],dfmt[1:])
2339                if not os.path.exists(dir): os.makedirs(dir)
2340        else:
2341            if not os.path.exists(self.params['outdir']):
2342                os.makedirs(self.params['outdir'])
2343        if self.Reset: # special things to do after Reset has been pressed
2344            self.G2frame.IntegratedList = []
2345           
2346            if self.params['Mode'] != 'table': # reset controls and masks for all IMG items in tree to master
2347                for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2348                    # update controls from master
2349                    controlsDict = G2frame.PatternTree.GetItemPyData(
2350                        G2gd.GetPatternTreeItemId(G2frame,self.imageBase, 'Image Controls'))
2351                    controlsDict.update(self.ImageControls)
2352                    # update masks from master
2353                    ImageMasks = G2frame.PatternTree.GetItemPyData(
2354                        G2gd.GetPatternTreeItemId(G2frame,self.imageBase, 'Masks'))
2355                    ImageMasks.update(self.ImageMasks)
2356            # delete all PWDR items created after last Start was pressed
2357            idlist = []
2358            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2359            while item:
2360                itemName = G2frame.PatternTree.GetItemText(item)
2361                if itemName in G2frame.AutointPWDRnames:
2362                    idlist.append(item)
2363                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2364            for item in idlist:
2365                G2frame.PatternTree.Delete(item)
2366            wx.Yield()
2367            self.Reset = False
2368        G2frame.AutointPWDRnames = [] # list of created PWDR tree item names
2369
2370    def OnTimerLoop(self,event):
2371        '''A method that is called every :meth:`PollTime` seconds that is
2372        used to check for new files and process them. This is called only
2373        after the "Start" button is pressed (when its label reads "Pause").
2374        '''
2375        G2frame = self.G2frame
2376        try:
2377            self.currImageList = sorted(
2378                glob.glob(os.path.join(self.imagedir,self.params['filter'])))
2379            self.ShowMatchingFiles(self.params['filter'])
2380        except IndexError:
2381            self.currImageList = []
2382            return
2383
2384        if self.PreventReEntryTimer: return
2385        self.PreventReEntryTimer = True
2386        imageFileList = []
2387        # integrate the images that have already been read in, but
2388        # have not yet been processed
2389        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2390            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2391            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2392            # Create a list of image files that have been read in
2393            if imagefile not in imageFileList: imageFileList.append(imagefile)
2394            # skip if already integrated
2395            if img in G2frame.IntegratedList: continue
2396            if self.params['Mode'] == 'table': # look up parameter values from table
2397                controlsDict = G2frame.PatternTree.GetItemPyData(
2398                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls'))
2399                ImageMasks = G2frame.PatternTree.GetItemPyData(
2400                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks'))
2401                self.ResetFromTable(controlsDict['distance'])
2402                # update controls from master
2403                controlsDict.update(self.ImageControls)
2404                # update masks from master w/o Thresholds
2405                ImageMasks.update(self.ImageMasks)
2406            self.IntegrateImage(img)
2407            self.G2frame.oldImagefile = '' # mark image as changed; reread as needed
2408            wx.Yield()
2409            self.ShowMatchingFiles(self.params['filter'])
2410            wx.Yield()
2411            if self.Pause: return
2412
2413        # loop over image files matching glob, reading in any new ones
2414        for newImage in self.currImageList:
2415            if newImage in imageFileList: continue # already read?
2416            for imgId in G2IO.ReadImages(G2frame,newImage):
2417                controlsDict = G2frame.PatternTree.GetItemPyData(
2418                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls'))
2419                ImageMasks = G2frame.PatternTree.GetItemPyData(
2420                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks'))
2421                if self.params['Mode'] == 'table': # look up parameter values from table
2422                    self.ResetFromTable(controlsDict['distance'])
2423                # update controls from master
2424                controlsDict.update(self.ImageControls)
2425                # update masks from master w/o Thresholds
2426                ImageMasks.update(self.ImageMasks)
2427                # now integrate the image
2428                img = G2frame.PatternTree.GetItemText(imgId)
2429                self.IntegrateImage(img)
2430                self.G2frame.oldImagefile = '' # mark image as changed; reread as needed
2431                wx.Yield()
2432                self.ShowMatchingFiles(self.params['filter'])
2433                wx.Yield()
2434            if self.Pause: return
2435       
2436        if GSASIIpath.GetConfigValue('debug'):
2437            import datetime
2438            print ("Timer tick at {:%d %b %Y %H:%M:%S}\n".format(datetime.datetime.now()))
2439        self.PreventReEntryTimer = False
2440
2441def DefineEvaluator(dlg):
2442    '''Creates a function that provides interpolated values for a given distance value
2443    '''
2444    def Evaluator(dist):
2445        '''Interpolate image parameters for a supplied distance value
2446
2447        :param float dist: distance to use for interpolation
2448        :returns: a list with 3 items:
2449
2450          * a dict with parameter values,
2451          * the closest imctrl and
2452          * the closest maskfile (or None)
2453        '''           
2454        x = np.array([float(i) for i in parms[0]])
2455        closest = abs(x-dist).argmin()
2456        closeX = x[closest]
2457        D = {'distance':dist}
2458        imctfile = IMfileList[closest]
2459        if parms[-1][closest].lower() != '(none)':
2460            maskfile = parms[-1][closest]
2461        else:
2462            maskfile = None
2463        for c in range(1,cols-1):
2464            lbl = ParmList[c]
2465            if lbl in nonInterpVars:
2466                D[lbl] = float(parms[c][closest])
2467            else:
2468                y = np.array([float(i) for i in parms[c]])
2469                D[lbl] = np.interp(dist,x,y)
2470        # full integration when angular range is 0
2471        D['fullIntegrate'] = (D['LRazimuth_min'] == D['LRazimuth_max'])
2472        # conversion for paired values
2473        for a,b in ('center_x','center_y'),('LRazimuth_min','LRazimuth_max'),('IOtth_min','IOtth_max'):
2474            r = a.split('_')[0]
2475            D[r] = [D[a],D[b]]
2476            del D[a]
2477            del D[b]
2478        return D,imctfile,maskfile
2479    # save local copies of values needed in Evaluator
2480    parms = dlg.ReadImageParmTable()
2481    IMfileList = dlg.IMfileList
2482    cols = dlg.list.GetColumnCount()
2483    ParmList = dlg.ParmList
2484    nonInterpVars = dlg.nonInterpVars
2485    return Evaluator
2486
2487class IntegParmTable(wx.Dialog):
2488    '''Creates a dialog window with a table of integration parameters.
2489    :meth:`ShowModal` will return wx.ID_OK if the process has been successful.
2490    In this case, :func:`DefineEvaluator` should be called to obtain a function that
2491    creates a dictionary with interpolated parameter values.
2492    '''
2493    ParmList = ('distance','center_x','center_y','wavelength','tilt','rotation','DetDepth',
2494            'LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max','outChannels',
2495            'maskfile',
2496            )
2497    nonInterpVars = ('tilt','rotation','LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max',
2498                     'outChannels')  # values in this list are taken from nearest rather than interpolated
2499    HeaderList = ('Det Dist','X cntr','Y cntr','wavelength','tilt','rotation','DetDepth',
2500            'Azimuth min','Azimuth max','2Th min','2Th max','Int. pts',
2501            'Mask File',
2502            )
2503    def __init__(self,G2frame):
2504        self.G2frame = G2frame
2505        self.parms = [] # list of values by column
2506        self.IMfileList = [] # list of .imctrl file names for each entry in table
2507        wx.Dialog.__init__(self,G2frame,style=wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE)
2508        files = []
2509        try:
2510            dlg = wx.FileDialog(self, 'Select image control files or previous table', 
2511                                style=wx.OPEN| wx.MULTIPLE,
2512                                wildcard='image control files (.imctrl)|*.imctrl|Integration table (*.imtbl)|*.imtbl')
2513            if dlg.ShowModal() == wx.ID_OK:
2514                files = dlg.GetPaths()
2515                self.parms,self.IMfileList = self.ReadFiles(files)
2516        finally:
2517            dlg.Destroy()
2518        if not files:
2519            wx.CallAfter(self.EndModal,wx.ID_CANCEL)
2520            return
2521        mainSizer = wx.BoxSizer(wx.VERTICAL)
2522        self.list = ImgIntLstCtrl(self, wx.ID_ANY,
2523                      style=wx.LC_REPORT
2524                          | wx.BORDER_SUNKEN
2525                         #| wx.BORDER_NONE
2526                         )
2527        mainSizer.Add(self.list,1,wx.EXPAND,1)
2528        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
2529        btn = wx.Button(self, wx.ID_OK)
2530        btnsizer.Add(btn)
2531        btn = wx.Button(self, wx.ID_ANY,'Save')
2532        btn.Bind(wx.EVT_BUTTON,self._onSave)
2533        btnsizer.Add(btn)
2534        btn = wx.Button(self, wx.ID_CLOSE,'Quit')
2535        btn.Bind(wx.EVT_BUTTON,self._onClose)
2536        btnsizer.Add(btn)
2537        mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)   
2538        self.SetSizer(mainSizer)
2539        self.list.FillList(self.parms)
2540        mainSizer.Layout()
2541        mainSizer.Fit(self)
2542       
2543    def ReadFiles(self,files):
2544        '''Reads a list of .imctrl files or a single .imtbl file
2545        '''
2546        tmpDict = {}
2547        if not files: return
2548        # option 1, a dump from a previous save
2549        if os.path.splitext(files[0])[1] == '.imtbl':
2550            fp = open(files[0],'r')
2551            S = fp.readline()
2552            while S:
2553                if S[0] != '#':
2554                    [key,val] = S[:-1].split(':',1)
2555                    tmpDict[key] = eval(val)
2556                S = fp.readline()
2557            fp.close()
2558            # delete entries
2559            m1 = [i for i,f in enumerate(tmpDict['filenames']) if not os.path.exists(f)]
2560            if m1:
2561                print('\nimctrl file not found:')
2562                for i in m1: print('\t#'+str(i)+': '+tmpDict['filenames'][i])
2563            m2 = [i for i,f in enumerate(tmpDict['maskfile']) if not (os.path.exists(f) or f.startswith('('))]
2564            if m2:
2565                print('\nmask file not found')
2566                for i in m2: print('\t#'+str(i)+': '+tmpDict['maskfile'][i])
2567            m3 = [i for i,d in enumerate(tmpDict['distance']) if d < 0]
2568            if m3:
2569                print('\nDropping entries due to negative distance: '+str(m3))
2570            m = sorted(set(m1 + m2 + m3))
2571            m.reverse()
2572            for c in m:
2573                for key in tmpDict:
2574                    del tmpDict[key][c]
2575            fileList = tmpDict.get('filenames','[]')
2576            parms = []
2577            for key in self.ParmList:
2578                try:
2579                    float(tmpDict[key][0])
2580                    parms.append([str(G2py3.FormatSigFigs(val,sigfigs=5)) for val in tmpDict[key]])
2581                except ValueError:
2582                    parms.append(tmpDict[key])
2583            return parms,fileList
2584        # option 2, read in a list of files
2585        for file in files: # read all files; place in dict by distance
2586            imgDict = Read_imctrl(file)
2587            tmpDict[imgDict.get('distance')] = imgDict
2588        parms = [[] for key in self.ParmList]
2589        fileList = []
2590        for d in sorted(tmpDict):
2591            fileList.append(tmpDict[d].get('filename'))
2592            if d is None: continue
2593            if d < 0: continue
2594            for i,key in enumerate(self.ParmList):
2595                val = tmpDict[d].get(key)
2596                try:
2597                    val = str(G2py3.FormatSigFigs(val,sigfigs=5))
2598                except:
2599                    val = str(val)
2600                parms[i].append(val)
2601        return parms,fileList
2602   
2603    def ReadImageParmTable(self):
2604        '''Reads possibly edited values from the ListCtrl table and returns a list
2605        of values for each column.
2606        '''
2607        rows = self.list.GetItemCount()
2608        cols = self.list.GetColumnCount()
2609        parms = []
2610        for c in range(cols):
2611            lbl = self.ParmList[c]
2612            parms.append([])
2613            for r in range(rows):
2614                parms[c].append(self.list.GetItem(r,c).GetText())
2615        return parms
2616
2617    def _onClose(self,event):
2618        'Called when Cancel button is pressed'
2619        self.EndModal(wx.ID_CANCEL)
2620       
2621    def _onSave(self,event):
2622        'Called when save button is pressed; creates a .imtbl file'
2623        fil = ''
2624        if self.G2frame.GSASprojectfile:
2625            fil = os.path.splitext(self.G2frame.GSASprojectfile)[0]+'.imtbl'
2626        dir,f = os.path.split(fil)
2627        try:
2628            dlg = wx.FileDialog(self, 'Save table data as',
2629                        defaultDir=dir, defaultFile=f, style=wx.SAVE,
2630                        wildcard='G2 Image Param Table file (*.imtbl)|*.imtbl')
2631            if dlg.ShowModal() != wx.ID_OK: return
2632            fil = dlg.GetPath()
2633            fil = os.path.splitext(fil)[0]+'.imtbl'
2634        finally:
2635            dlg.Destroy()       
2636        parms = self.ReadImageParmTable()
2637        print('Writing image parameter table as '+fil)
2638        fp = open(fil,'w')
2639        for c in range(len(parms)-1):
2640            lbl = self.ParmList[c]
2641            fp.write(lbl+': '+str([eval(i) for i in parms[c]])+'\n')
2642        lbl = self.ParmList[c+1]
2643        fp.write(lbl+': '+str(parms[c+1])+'\n')
2644        lbl = 'filenames'
2645        fp.write(lbl+': '+str(self.IMfileList)+'\n')
2646        fp.close()
2647   
2648class ImgIntLstCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,listmix.TextEditMixin):
2649    '''Creates a custom ListCtrl for editing Image Integration parameters
2650    '''
2651    def __init__(self, parent, ID, pos=wx.DefaultPosition,
2652                 size=(1000,200), style=0):
2653        self.parent=parent
2654        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
2655        listmix.ListCtrlAutoWidthMixin.__init__(self)
2656        listmix.TextEditMixin.__init__(self)
2657        self.Bind(wx.EVT_LEFT_DCLICK, self.OnDouble)
2658        #self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
2659    def FillList(self,parms):
2660        'Places the current parms into the table'
2661        self.ClearAll()
2662        self.rowlen = len(self.parent.ParmList)
2663        for i,lbl in enumerate(self.parent.HeaderList):
2664            self.InsertColumn(i, lbl)
2665        for r,d in enumerate(parms[0]):
2666            if float(d) < 0: continue
2667            index = self.InsertStringItem(sys.maxint, d)
2668            for j in range(1,len(parms)):
2669                self.SetStringItem(index, j, parms[j][r])
2670        for i,lbl in enumerate(self.parent.ParmList):
2671            self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
2672
2673    def OnDouble(self,evt):
2674        'respond to a double-click'
2675        self.CloseEditor()
2676        fil = '(none)'
2677        try:
2678            dlg = wx.FileDialog(self, 'Select mask or control file to add (Press cancel if none)', 
2679                                style=wx.OPEN,
2680                                wildcard='Add GSAS-II mask file (.immask)|*.immask|add image control file (.imctrl)|*.imctrl')
2681            if dlg.ShowModal() == wx.ID_OK:
2682                fil = dlg.GetPath()
2683        finally:
2684            dlg.Destroy()
2685        if os.path.splitext(fil)[1] != '.imctrl':
2686            self.SetStringItem(self.curRow, self.rowlen-1, fil)
2687            self.SetColumnWidth(self.rowlen-1, wx.LIST_AUTOSIZE)
2688        else:
2689            # insert or overwrite an instrument parameter set
2690            if not os.path.exists(fil):
2691                print('Does not exist: '+fil)
2692                return
2693            imgDict = Read_imctrl(fil)
2694            dist = imgDict['distance']
2695            parms = self.parent.ReadImageParmTable()
2696            x = np.array([float(i) for i in parms[0]])
2697            closest = abs(x-dist).argmin()
2698            closeX = x[closest]
2699            # fix IMfileList
2700            for c,lbl in enumerate(self.parent.ParmList):
2701                try:
2702                    vali = G2py3.FormatSigFigs(float(imgDict[lbl]),sigfigs=5)
2703                except ValueError:
2704                    vali = imgDict[lbl]
2705                if abs(closeX-dist) < 1.: # distance is within 1 mm, replace
2706                    parms[c][closest] = vali
2707                elif dist > closeX: # insert after
2708                    parms[c].insert(closest+1,vali)
2709                else:
2710                    parms[c].insert(closest,vali)
2711            if abs(closeX-dist) < 1.: # distance is within 1 mm, replace
2712                self.parent.IMfileList[closest] = fil
2713            elif dist > closeX: # insert after
2714                self.parent.IMfileList.insert(closest+1,fil)
2715            else:
2716                self.parent.IMfileList.insert(closest,fil)
2717            self.FillList(parms)
2718# Autointegration end
2719###########################################################################
Note: See TracBrowser for help on using the repository browser.