source: trunk/GSASIIimgGUI.py @ 2082

Last change on this file since 2082 was 2082, checked in by toby, 6 years ago

provide autoint interpolation table; merge into std GSAS-II version

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 120.5 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - image data display routines
3########### SVN repository information ###################
4# $Date: 2015-12-05 04:50:58 +0000 (Sat, 05 Dec 2015) $
5# $Author: toby $
6# $Revision: 2082 $
7# $URL: trunk/GSASIIimgGUI.py $
8# $Id: GSASIIimgGUI.py 2082 2015-12-05 04:50:58Z 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: 2082 $")
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        CleanupMasks(masks)
140        blkSize = 128   #this seems to be optimal; will break in polymask if >1024
141        Nx,Ny = data['size']
142        nXBlks = (Nx-1)/blkSize+1
143        nYBlks = (Ny-1)/blkSize+1
144        Nup = nXBlks*nYBlks*3+3
145        dlg = wx.ProgressDialog("Elapsed time","2D image integration",Nup,
146            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
147        try:
148            sumImg = G2frame.ImageZ
149            darkImg,darkScale = data['dark image']
150            if darkImg:
151                Did = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, darkImg)
152                Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Did)
153                darkImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
154                sumImg += darkImage*darkScale
155            backImg,backScale = data['background image']           
156            if backImg:     #ignores any transmission effect in the background image
157                Bid = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, backImg)
158                Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Bid)
159                backImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
160                Bdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Bid,'Image Controls'))
161                BdarkImg,BdarkScale = Bdata['dark image']
162                if BdarkImg:
163                    BDid = G2gd.GetPatternTreeItemId(G2frame, G2frame.root,BdarkImg)
164                    Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(BDid)
165                    BdarkImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
166                    backImage += BdarkImage*BdarkScale               
167                sumImg += backImage*backScale
168            G2frame.Integrate = G2img.ImageIntegrate(sumImg-data['Flat Bkg'],data,masks,blkSize,dlg)
169#            G2plt.PlotIntegration(G2frame,newPlot=True)
170            Id = G2IO.SaveIntegration(G2frame,G2frame.PickId,data)
171            G2frame.PatternId = Id
172            G2frame.PatternTree.SelectItem(Id)
173            G2frame.PatternTree.Expand(Id)
174        finally:
175            dlg.Destroy()
176        for item in G2frame.MakePDF: item.Enable(True)
177       
178    def OnIntegrateAll(event):
179        print 'integrate all'
180        TextList = [[False,'All IMG',0]]
181        Names = []
182        if G2frame.PatternTree.GetCount():
183            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
184            while id:
185                name = G2frame.PatternTree.GetItemText(id)
186                Names.append(name)
187                if 'IMG' in name:
188                    TextList.append([False,name,id])
189                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
190            if len(TextList) == 1:
191                G2frame.ErrorDialog('Nothing to integrate','There must some "IMG" patterns')
192                return
193            dlg = G2frame.CopyDialog(G2frame,'Image integration controls','Select images to integrate:',TextList)
194            try:
195                if dlg.ShowModal() == wx.ID_OK:
196                    result = dlg.GetData()
197                    if result[0][0]:                    #the 'All IMG' is True
198                        result = TextList[1:]
199                        for item in result: item[0] = True
200                    G2frame.EnablePlot = False
201                    for item in result:
202                        ifintegrate,name,id = item
203                        if ifintegrate:
204                            Id = G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls')
205                            Data = G2frame.PatternTree.GetItemPyData(Id)
206                            blkSize = 128   #this seems to be optimal; will break in polymask if >1024
207                            Nx,Ny = Data['size']
208                            nXBlks = (Nx-1)/blkSize+1
209                            nYBlks = (Ny-1)/blkSize+1
210                            Nup = nXBlks*nYBlks*3+3
211                            dlgp = wx.ProgressDialog("Elapsed time","2D image integration",Nup,
212                                style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
213                            try:
214                                id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, name)
215                                Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(id)
216                                image = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
217                                backImage = []
218                                if Data['background image'][0]:
219                                    backImg = Data['background image'][0]
220                                    backScale = Data['background image'][1]
221                                    id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, backImg)
222                                    Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(id)
223                                    backImage = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)*backScale
224                                FlatBkg = Data.get('Flat Bkg',0.0)
225                                try:
226                                    Masks = G2frame.PatternTree.GetItemPyData(
227                                        G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'))
228                                except TypeError:       #missing Masks
229                                    # I think the next line should be 'range'! (BHT)
230                                    Imin,Imax = Data['Range']
231                                    Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
232                                    G2frame.PatternTree.SetItemPyData(
233                                        G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'),Masks)
234                                CleanupMasks(Masks)
235                                if len(backImage):                               
236                                    G2frame.Integrate = G2img.ImageIntegrate(image+backImage-FlatBkg,Data,Masks,blkSize,dlgp)
237                                else:
238                                    G2frame.Integrate = G2img.ImageIntegrate(image-FlatBkg,Data,Masks,blkSize,dlgp)
239                                pId = G2IO.SaveIntegration(G2frame,Id,Data)
240                            finally:
241                                dlgp.Destroy()
242                    else:
243                        G2frame.EnablePlot = True
244                        G2frame.PatternTree.SelectItem(pId)
245                        G2frame.PatternTree.Expand(pId)
246                        G2frame.PatternId = pId
247                       
248            finally:
249                dlg.Destroy()
250       
251    def OnCopyControls(event):
252        TextList = [[False,'All IMG',0]]
253        Names = []
254        if G2frame.PatternTree.GetCount():
255            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
256            while id:
257                name = G2frame.PatternTree.GetItemText(id)
258                Names.append(name)
259                if 'IMG' in name:
260                    if id == G2frame.Image:
261                        Source = name
262                        Data = copy.deepcopy(data)
263#                        Data = copy.deepcopy(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls')))
264                        Data['showLines'] = True
265                        Data['ring'] = []
266                        Data['rings'] = []
267                        Data['ellipses'] = []
268                        Data['setDefault'] = False
269                    else:
270                        TextList.append([False,name,id])
271                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
272            if len(TextList) == 1:
273                G2frame.ErrorDialog('Nothing to copy controls to','There must be more than one "IMG" pattern')
274                return
275            dlg = G2frame.CopyDialog(G2frame,'Copy image controls','Copy controls from '+Source+' to:',TextList)
276            try:
277                if dlg.ShowModal() == wx.ID_OK:
278                    result = dlg.GetData()
279                    if result[0][0]:
280                        result = TextList[1:]
281                        for item in result: item[0] = True
282                    for i,item in enumerate(result):
283                        ifcopy,name,id = item
284                        if ifcopy:
285                            oldData = copy.deepcopy(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls')))
286                            Data['range'] = oldData['range']
287                            Data['size'] = oldData['size']
288                            Data['GonioAngles'] = oldData.get('GonioAngles', [0.,0.,0.])
289                            Data['ring'] = []
290                            Data['rings'] = []
291                            Data['ellipses'] = []
292                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls'),copy.deepcopy(Data))
293            finally:
294                dlg.Destroy()
295                G2frame.PatternTree.SelectItem(G2frame.PickId)
296               
297    def OnSaveControls(event):
298        dlg = wx.FileDialog(G2frame, 'Choose image controls file', '.', '', 
299            'image control files (*.imctrl)|*.imctrl',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
300        try:
301            if dlg.ShowModal() == wx.ID_OK:
302                filename = dlg.GetPath()
303                # make sure extension is .imctrl
304                filename = os.path.splitext(filename)[0]+'.imctrl'
305                File = open(filename,'w')
306                save = {}
307                keys = ['type','wavelength','calibrant','distance','center',
308                    'tilt','rotation','azmthOff','fullIntegrate','LRazimuth',
309                    'IOtth','outChannels','outAzimuths','invert_x','invert_y','DetDepth',
310                    'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
311                    'binType','SampleShape','PolaVal','SampleAbs','dark image','background image']
312                for key in keys:
313                    if key not in data:     #uncalibrated!
314                        continue
315                    File.write(key+':'+str(data[key])+'\n')
316                File.close()
317        finally:
318            dlg.Destroy()
319       
320    def OnLoadControls(event):
321        cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type',
322            'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth',
323            'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
324            'PolaVal','SampleAbs','dark image','background image']
325        dlg = wx.FileDialog(G2frame, 'Choose image controls file', '.', '', 
326            'image control files (*.imctrl)|*.imctrl',wx.OPEN|wx.CHANGE_DIR)
327        try:
328            if dlg.ShowModal() == wx.ID_OK:
329                filename = dlg.GetPath()
330                File = open(filename,'r')
331                save = {}
332                S = File.readline()
333                while S:
334                    if S[0] == '#':
335                        S = File.readline()
336                        continue
337                    [key,val] = S[:-1].split(':')
338                    if key in ['type','calibrant','binType','SampleShape',]:    #strings
339                        save[key] = val
340                    elif key in ['rotation']:
341                        save[key] = float(val)
342                    elif key in ['center',]:
343                        if ',' in val:
344                            save[key] = eval(val)
345                        else:
346                            vals = val.strip('[] ').split()
347                            save[key] = [float(vals[0]),float(vals[1])] 
348                    elif key in cntlList:
349                        save[key] = eval(val)
350                    S = File.readline()
351                data.update(save)
352                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'),copy.deepcopy(data))
353                wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
354                G2plt.PlotExposedImage(G2frame,event=event)
355               
356                File.close()
357        finally:
358            dlg.Destroy()
359           
360# Sizers
361                                       
362    def ComboSizer():
363
364        def OnDataType(event):
365            data['type'] = typeSel.GetValue()[:4]
366            if 'SASD' in data['type']:
367                data['SampleAbs'][0] = np.exp(-data['SampleAbs'][0]) #switch from muT to trans!
368                if data['binType'] == '2-theta': data['binType'] = 'log(q)'  #switch default bin type
369            elif 'PWDR' in data['type']:
370                data['SampleAbs'][0] = -np.log(data['SampleAbs'][0])  #switch from trans to muT!
371                if data['binType'] == 'log(q)': data['binType'] = '2-theta'  #switch default bin type                 
372            wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
373   
374        def OnNewColorBar(event):
375            data['color'] = colSel.GetValue()
376            G2plt.PlotExposedImage(G2frame,event=event)
377       
378        def OnAzmthOff(event):
379            try:
380                azmthoff = float(azmthOff.GetValue())
381                data['azmthOff'] = azmthoff
382            except ValueError:
383                pass
384            azmthOff.SetValue("%.2f"%(data['azmthOff']))          #reset in case of error 
385            G2plt.PlotExposedImage(G2frame,event=event)
386       
387        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
388        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Type of image data: '),0,WACV)
389        typeSel = wx.ComboBox(parent=G2frame.dataDisplay,value=typeDict[data['type']],choices=typeList,
390            style=wx.CB_READONLY|wx.CB_DROPDOWN)
391        typeSel.SetValue(data['type'])
392        typeSel.Bind(wx.EVT_COMBOBOX, OnDataType)
393        comboSizer.Add(typeSel,0,WACV)
394        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Color bar '),0,WACV)
395        colSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['color'],choices=colorList,
396            style=wx.CB_READONLY|wx.CB_DROPDOWN)
397        colSel.Bind(wx.EVT_COMBOBOX, OnNewColorBar)
398        comboSizer.Add(colSel,0,WACV)
399        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Azimuth offset '),0,WACV)
400        azmthOff = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.2f" % (data['azmthOff'])),
401            style=wx.TE_PROCESS_ENTER)
402        azmthOff.Bind(wx.EVT_TEXT_ENTER,OnAzmthOff)
403        azmthOff.Bind(wx.EVT_KILL_FOCUS,OnAzmthOff)
404        comboSizer.Add(azmthOff,0,WACV)
405        return comboSizer
406       
407    def MaxSizer():
408               
409        def OnMaxVal(event):
410            try:
411                value = min(data['range'][0][1],int(maxVal.GetValue()))
412                if value < data['range'][1][0]+1:
413                    raise ValueError
414                data['range'][1][1] = value
415            except ValueError:
416                pass
417            maxVal.SetValue('%.0f'%(data['range'][1][1]))
418            DeltOne = data['range'][1][1]-max(0.0,data['range'][0][0])
419            sqrtDeltOne = math.sqrt(DeltOne)
420            maxSel.SetValue(int(100*sqrtDeltOne/sqrtDeltZero))
421            minSel.SetValue(int(100*(data['range'][1][0]/DeltOne)))
422            G2plt.PlotExposedImage(G2frame,event=event)
423           
424        def OnMinVal(event):
425            try:
426                value = int(minVal.GetValue())
427                if value > data['range'][1][1]-1:
428                    raise ValueError
429                data['range'][1][0] = value
430            except ValueError:
431                pass
432            minVal.SetValue('%.0f'%(data['range'][1][0]))
433            minSel.SetValue(int(100*(data['range'][1][0]-max(0.0,data['range'][0][0]))/DeltOne))
434            G2plt.PlotExposedImage(G2frame,event=event)
435           
436        def OnMaxSlider(event):
437            sqrtDeltZero = math.sqrt(data['range'][0][1])
438            imax = int(maxSel.GetValue())*sqrtDeltZero/100.
439            data['range'][1][1] = imax**2
440            data['range'][1][0] = max(0.0,min(data['range'][1][1]-1,data['range'][1][0]))
441            DeltOne = max(1.0,data['range'][1][1]-data['range'][1][0])
442            minSel.SetValue(int(100*(data['range'][1][0]/DeltOne)))
443            maxVal.SetValue('%.0f'%(data['range'][1][1]))
444            G2plt.PlotExposedImage(G2frame,event=event)
445           
446        def OnMinSlider(event):
447            DeltOne = data['range'][1][1]-data['range'][1][0]
448            imin = int(minSel.GetValue())*DeltOne/100.
449            data['range'][1][0] = max(0.0,min(data['range'][1][1]-1,imin))
450            minVal.SetValue('%.0f'%(data['range'][1][0]))
451            G2plt.PlotExposedImage(G2frame,event=event)
452           
453        maxSizer = wx.FlexGridSizer(0,3,0,5)
454        maxSizer.AddGrowableCol(1,1)
455        maxSizer.SetFlexibleDirection(wx.HORIZONTAL)
456        sqrtDeltZero = math.sqrt(data['range'][0][1]-max(0.0,data['range'][0][0]))
457        DeltOne = data['range'][1][1]-max(0.0,data['range'][0][0])
458        sqrtDeltOne = math.sqrt(DeltOne)
459        maxSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max intensity'),0,WACV)
460        maxSel = wx.Slider(parent=G2frame.dataDisplay,style=wx.SL_HORIZONTAL,
461            value=int(100*sqrtDeltOne/sqrtDeltZero))
462        maxSizer.Add(maxSel,1,wx.EXPAND)
463        maxSel.Bind(wx.EVT_SLIDER, OnMaxSlider)
464        maxVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.0f'%(data['range'][1][1]))
465        maxVal.Bind(wx.EVT_TEXT_ENTER,OnMaxVal)   
466        maxVal.Bind(wx.EVT_KILL_FOCUS,OnMaxVal)
467        maxSizer.Add(maxVal,0,WACV)   
468        maxSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Min intensity'),0,WACV)
469        minSel = wx.Slider(parent=G2frame.dataDisplay,style=wx.SL_HORIZONTAL,
470            value=int(100*(data['range'][1][0]-max(0.0,data['range'][0][0]))/DeltOne))
471        maxSizer.Add(minSel,1,wx.EXPAND)
472        minSel.Bind(wx.EVT_SLIDER, OnMinSlider)
473        minVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.0f'%(data['range'][1][0]))
474        minVal.Bind(wx.EVT_TEXT_ENTER,OnMinVal)   
475        minVal.Bind(wx.EVT_KILL_FOCUS,OnMinVal)
476        maxSizer.Add(minVal,0,WACV)
477        return maxSizer
478       
479    def CalibCoeffSizer():
480       
481        def OnCalRef(event):
482            Obj = event.GetEventObject()
483            name = Indx[Obj]
484            data['varyList'][name] = Obj.GetValue()
485           
486        def OnCalVal(event):
487            Obj = event.GetEventObject()
488            name = Indx[Obj]
489            try:
490                value = float(Obj.GetValue())
491                if name == 'wave' and value < 0.01:
492                    raise ValueError
493            except ValueError:
494                value = Parms[name][2]
495            if name == 'dist':
496                data['distance'] = value
497            elif name == 'det-X':
498                data['center'][0] = value
499            elif name == 'det-Y':
500                data['center'][1] = value
501            elif name == 'tilt':
502                data['tilt'] = value
503            elif name == 'phi':
504                data['rotation'] = value
505            elif name == 'wave':
506                data['wavelength'] = value
507            elif name == 'dep':
508                data['DetDepth'] = value                               
509            Parms[name][2] = value
510            Obj.SetValue(Parms[name][1]%(value))
511           
512        calibSizer = wx.FlexGridSizer(0,2,5,5)
513        calibSizer.SetFlexibleDirection(wx.HORIZONTAL)
514        calibSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calibration coefficients'),0,WACV)   
515        calibSizer.Add((5,0),0)
516        cent = data['center']
517        Names = ['det-X','det-Y','wave','dist','tilt','phi']
518        if 'PWDR' in data['type']:
519            Names.append('dep') 
520        Parms = {'dist':['Distance','%.3f',data['distance']],'det-X':['Beam center X','%.3f',data['center'][0]],
521            'det-Y':['Beam center Y','%.3f',data['center'][1]],'tilt':['Tilt angle','%.3f',data['tilt']],
522            'phi':['Tilt rotation','%.2f',data['rotation']],'dep':['Penetration','%.2f',data['DetDepth']],
523            'wave':['Wavelength','%.6f',data['wavelength']]}
524        Indx = {}
525        for name in Names:
526            calSel = wx.CheckBox(parent=G2frame.dataDisplay,label=Parms[name][0])
527            calibSizer.Add(calSel,0,WACV)
528            calSel.Bind(wx.EVT_CHECKBOX, OnCalRef)
529            calSel.SetValue(data['varyList'][name])
530            Indx[calSel] = name
531            calVal = wx.TextCtrl(G2frame.dataDisplay,value=(Parms[name][1]%(Parms[name][2])),style=wx.TE_PROCESS_ENTER)
532            calVal.Bind(wx.EVT_TEXT_ENTER,OnCalVal)
533            calVal.Bind(wx.EVT_KILL_FOCUS,OnCalVal)
534            Indx[calVal] = name
535            calibSizer.Add(calVal,0,WACV)
536        return calibSizer
537   
538    def IntegrateSizer():
539       
540        def OnNewBinType(event):
541            data['binType'] = binSel.GetValue()
542            wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
543       
544        def OnIOtth(event):
545            Ltth = max(float(G2frame.InnerTth.GetValue()),0.001)
546            Utth = float(G2frame.OuterTth.GetValue())
547            if Ltth > Utth:
548                Ltth,Utth = Utth,Ltth
549            if 'Q' in data['binType']:
550                data['IOtth'] = [2.*asind(Ltth*wave/(4.*math.pi)),2.*asind(Utth*wave/(4.*math.pi))]
551            else:
552                data['IOtth'] = [Ltth,Utth]
553            G2frame.InnerTth.SetValue("%8.3f" % (Ltth))
554            G2frame.OuterTth.SetValue("%8.3f" % (Utth))
555            G2plt.PlotExposedImage(G2frame,event=event)
556       
557        def OnLRazim(event):
558            Lazm = int(G2frame.Lazim.GetValue())%360
559            Razm = int(G2frame.Razim.GetValue())%360
560            if Lazm > Razm:
561                Razm += 360
562            if data['fullIntegrate']:
563                Razm = Lazm+360
564            G2frame.Lazim.SetValue("%6d" % (Lazm))
565            G2frame.Razim.SetValue("%6d" % (Razm))
566            data['LRazimuth'] = [Lazm,Razm]
567            G2plt.PlotExposedImage(G2frame,event=event)
568       
569        def OnNumOutChans(event):
570            try:
571                numChans = int(outChan.GetValue())
572                if numChans < 10:
573                    raise ValueError
574                data['outChannels'] = numChans
575            except ValueError:
576                pass
577            outChan.SetValue(str(data['outChannels']))          #reset in case of error       
578       
579        def OnNumOutAzms(event):
580            try:
581                numAzms = int(outAzim.GetValue())
582                if numAzms < 1:
583                    raise ValueError
584                data['outAzimuths'] = numAzms           
585            except ValueError:
586                pass
587            outAzim.SetValue(str(data['outAzimuths']))          #reset in case of error       
588            G2plt.PlotExposedImage(G2frame,event=event)
589       
590        def OnOblique(event):
591            if data['Oblique'][1]:
592                data['Oblique'][1] = False
593            else:
594                data['Oblique'][1] = True
595               
596        def OnObliqVal(event):
597            try:
598                value = float(obliqVal.GetValue())
599                if 0.01 <= value <= 0.99:
600                    data['Oblique'][0] = value
601                else:
602                    raise ValueError
603            except ValueError:
604                pass
605            obliqVal.SetValue('%.3f'%(data['Oblique'][0]))
606                           
607        def OnSamAbs(event):
608            if data['SampleAbs'][1]:
609                data['SampleAbs'][1] = False
610            else:
611                data['SampleAbs'][1] = True
612               
613        def OnSamAbsVal(event):
614            try:
615                value = float(samabsVal.GetValue())
616                minmax = [0.,2.]
617                if 'SASD' in data['type']:
618                    minmax = [.05,1.0]
619                if minmax[0] <= value <= minmax[1]:
620                    data['SampleAbs'][0] = value
621                else:
622                    raise ValueError
623            except ValueError:
624                pass
625            samabsVal.SetValue('%.3f'%(data['SampleAbs'][0]))
626                           
627        def OnShowLines(event):
628            if data['showLines']:
629                data['showLines'] = False
630            else:
631                data['showLines'] = True
632            G2plt.PlotExposedImage(G2frame,event=event)
633           
634        def OnFullIntegrate(event):
635            Lazm =int(G2frame.Lazim.GetValue())
636            if data['fullIntegrate']:
637                data['fullIntegrate'] = False
638                data['LRazimuth'] = [Lazm,Lazm+20]
639            else:
640                data['fullIntegrate'] = True
641                data['LRazimuth'] = [Lazm,Lazm+360]
642            wx.CallLater(100,UpdateImageControls,G2frame,data,masks)
643            G2plt.PlotExposedImage(G2frame,event=event)
644           
645        def OnSetDefault(event):
646            if data['setDefault']:
647                G2frame.imageDefault = {}
648                data['setDefault'] = False
649            else:
650                G2frame.imageDefault = copy.copy(data)
651                data['setDefault'] = True
652               
653        def OnCenterAzm(event):
654            if data['centerAzm']:
655                data['centerAzm'] = False
656            else:
657                data['centerAzm'] = True
658            G2plt.PlotExposedImage(G2frame,event=event)
659               
660        def OnApplyPola(event):
661            if data['PolaVal'][1]:
662                data['PolaVal'][1] = False
663            else:
664                data['PolaVal'][1] = True
665               
666        def OnPolaVal(event):
667            try:
668                value = float(polaVal.GetValue())
669                if 0.001 <= value <= 0.999:
670                    data['PolaVal'][0] = value
671                else:
672                    raise ValueError
673            except ValueError:
674                pass
675            polaVal.SetValue('%.3f'%(data['PolaVal'][0]))
676                           
677        dataSizer = wx.FlexGridSizer(0,2,5,3)
678        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Integration coefficients'),0,WACV)   
679        dataSizer.Add((5,0),0)
680        if 'PWDR' in data['type']:
681            binChoice = ['2-theta','Q']
682        elif 'SASD' in data['type']:
683            binChoice = ['2-theta','Q','log(q)']
684        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Bin style: Constant step bins in'),0,WACV)           
685        binSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['binType'],choices=binChoice,
686            style=wx.CB_READONLY|wx.CB_DROPDOWN)
687        binSel.Bind(wx.EVT_COMBOBOX, OnNewBinType)
688        dataSizer.Add(binSel,0,WACV)
689        binType = '2-theta'
690        if 'q' in data['binType'].lower():
691            binType = 'Q'
692        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Inner/Outer '+binType),0,WACV)           
693        IOtth = data['IOtth'][:]
694        if 'Q' in data['binType']:
695            wave = data['wavelength']
696            IOtth = [4.*math.pi*sind(IOtth[0]/2.)/wave,4.*math.pi*sind(IOtth[1]/2.)/wave]
697        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
698        G2frame.InnerTth = wx.TextCtrl(parent=G2frame.dataDisplay,
699            value=("%8.3f" % (IOtth[0])),style=wx.TE_PROCESS_ENTER)
700        G2frame.InnerTth.Bind(wx.EVT_TEXT_ENTER,OnIOtth)
701        G2frame.InnerTth.Bind(wx.EVT_KILL_FOCUS,OnIOtth)
702        littleSizer.Add(G2frame.InnerTth,0,WACV)
703        G2frame.OuterTth = wx.TextCtrl(parent=G2frame.dataDisplay,
704            value=("%8.2f" % (IOtth[1])),style=wx.TE_PROCESS_ENTER)
705        G2frame.OuterTth.Bind(wx.EVT_TEXT_ENTER,OnIOtth)
706        G2frame.OuterTth.Bind(wx.EVT_KILL_FOCUS,OnIOtth)
707        littleSizer.Add(G2frame.OuterTth,0,WACV)
708        dataSizer.Add(littleSizer,0,)
709        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start/End azimuth'),0,WACV)
710        LRazim = data['LRazimuth']
711        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
712        G2frame.Lazim = wx.TextCtrl(parent=G2frame.dataDisplay,
713            value=("%6d" % (LRazim[0])),style=wx.TE_PROCESS_ENTER)
714        G2frame.Lazim.Bind(wx.EVT_TEXT_ENTER,OnLRazim)
715        G2frame.Lazim.Bind(wx.EVT_KILL_FOCUS,OnLRazim)
716        littleSizer.Add(G2frame.Lazim,0,WACV)
717        G2frame.Razim = wx.TextCtrl(parent=G2frame.dataDisplay,
718            value=("%6d" % (LRazim[1])),style=wx.TE_PROCESS_ENTER)
719        G2frame.Razim.Bind(wx.EVT_TEXT_ENTER,OnLRazim)
720        G2frame.Razim.Bind(wx.EVT_KILL_FOCUS,OnLRazim)
721        if data['fullIntegrate']:
722            G2frame.Razim.Enable(False)
723            G2frame.Razim.SetBackgroundColour(VERY_LIGHT_GREY)
724            G2frame.Razim.SetValue("%6d" % (LRazim[0]+360))
725        littleSizer.Add(G2frame.Razim,0,WACV)
726        dataSizer.Add(littleSizer,0,)
727        dataSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' No. 2-theta/azimuth bins'),0,WACV)
728        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
729        outChan = wx.TextCtrl(parent=G2frame.dataDisplay,value=str(data['outChannels']),style=wx.TE_PROCESS_ENTER)
730        outChan.Bind(wx.EVT_TEXT_ENTER,OnNumOutChans)
731        outChan.Bind(wx.EVT_KILL_FOCUS,OnNumOutChans)
732        littleSizer.Add(outChan,0,WACV)
733        outAzim = wx.TextCtrl(parent=G2frame.dataDisplay,value=str(data['outAzimuths']),style=wx.TE_PROCESS_ENTER)
734        outAzim.Bind(wx.EVT_TEXT_ENTER,OnNumOutAzms)
735        outAzim.Bind(wx.EVT_KILL_FOCUS,OnNumOutAzms)
736        littleSizer.Add(outAzim,0,WACV)
737        dataSizer.Add(littleSizer,0,)
738        littleSizer = wx.BoxSizer(wx.HORIZONTAL)
739        samabs = wx.CheckBox(parent=G2frame.dataDisplay,label='Apply sample absorption?')
740        dataSizer.Add(samabs,0,WACV)
741        samabs.Bind(wx.EVT_CHECKBOX, OnSamAbs)
742        samabs.SetValue(data['SampleAbs'][1])
743        if 'PWDR' in data['type']:
744            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='mu/R (0.00-2.0) '),0,WACV)
745        elif 'SASD' in data['type']:
746            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='transmission '),0,WACV)
747        samabsVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.3f'%(data['SampleAbs'][0]),style=wx.TE_PROCESS_ENTER)           
748        samabsVal.Bind(wx.EVT_TEXT_ENTER,OnSamAbsVal)
749        samabsVal.Bind(wx.EVT_KILL_FOCUS,OnSamAbsVal)
750        littleSizer.Add(samabsVal,0,WACV)
751        dataSizer.Add(littleSizer,0,)
752        if 'PWDR' in data['type']:
753            littleSizer = wx.BoxSizer(wx.HORIZONTAL)
754            oblique = wx.CheckBox(parent=G2frame.dataDisplay,label='Apply detector absorption?')
755            dataSizer.Add(oblique,0,WACV)
756            oblique.Bind(wx.EVT_CHECKBOX, OnOblique)
757            oblique.SetValue(data['Oblique'][1])
758            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Value (0.01-0.99)  '),0,WACV)
759            obliqVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.3f'%(data['Oblique'][0]),style=wx.TE_PROCESS_ENTER)
760            obliqVal.Bind(wx.EVT_TEXT_ENTER,OnObliqVal)
761            obliqVal.Bind(wx.EVT_KILL_FOCUS,OnObliqVal)
762            littleSizer.Add(obliqVal,0,WACV)
763            dataSizer.Add(littleSizer,0,)
764        if 'SASD' in data['type']:
765            littleSizer = wx.BoxSizer(wx.HORIZONTAL)
766            setPolariz = wx.CheckBox(parent=G2frame.dataDisplay,label='Apply polarization?')
767            dataSizer.Add(setPolariz,0,WACV)
768            setPolariz.Bind(wx.EVT_CHECKBOX, OnApplyPola)
769            setPolariz.SetValue(data['PolaVal'][1])
770            littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Value (0.001-0.999)  '),0,WACV)
771            polaVal = wx.TextCtrl(parent=G2frame.dataDisplay,value='%.3f'%(data['PolaVal'][0]),
772                style=wx.TE_PROCESS_ENTER)
773            polaVal.Bind(wx.EVT_TEXT_ENTER,OnPolaVal)
774            polaVal.Bind(wx.EVT_KILL_FOCUS,OnPolaVal)
775            littleSizer.Add(polaVal,0,WACV)
776            dataSizer.Add(littleSizer,0,)
777       
778        showLines = wx.CheckBox(parent=G2frame.dataDisplay,label='Show integration limits?')
779        dataSizer.Add(showLines,0,WACV)
780        showLines.Bind(wx.EVT_CHECKBOX, OnShowLines)
781        showLines.SetValue(data['showLines'])
782        fullIntegrate = wx.CheckBox(parent=G2frame.dataDisplay,label='Do full integration?')
783        dataSizer.Add(fullIntegrate,0,WACV)
784        fullIntegrate.Bind(wx.EVT_CHECKBOX, OnFullIntegrate)
785        fullIntegrate.SetValue(data['fullIntegrate'])
786        setDefault = wx.CheckBox(parent=G2frame.dataDisplay,label='Use as default for all images?')
787        dataSizer.Add(setDefault,0,WACV)
788        setDefault.Bind(wx.EVT_CHECKBOX, OnSetDefault)
789        setDefault.SetValue(data['setDefault'])
790        centerAzm = wx.CheckBox(parent=G2frame.dataDisplay,label='Azimuth at bin center?')
791        dataSizer.Add(centerAzm,0,WACV)
792        centerAzm.Bind(wx.EVT_CHECKBOX, OnCenterAzm)
793        centerAzm.SetValue(data['centerAzm'])
794        return dataSizer
795       
796    def BackSizer():
797       
798        def OnBackImage(event):
799            data['background image'][0] = backImage.GetValue()
800           
801        def OnDarkImage(event):
802            data['dark image'][0] = darkImage.GetValue()
803            G2plt.PlotExposedImage(G2frame,event=event)
804           
805        def OnFlatBkg(event):
806            try:
807                value = float(flatbkg.GetValue())
808                data['Flat Bkg'] = value
809            except ValueError:
810                pass
811            flatbkg.SetValue("%.0f"%(data['Flat Bkg']))   
812            G2plt.PlotExposedImage(G2frame,event=event)
813
814        def OnBackMult(event):
815            try:
816                mult = float(backMult.GetValue())
817                data['background image'][1] = mult
818            except ValueError:
819                pass
820            backMult.SetValue("%.3f" % (data['background image'][1]))          #reset in case of error
821       
822        def OnDarkMult(event):
823            try:
824                mult = float(darkMult.GetValue())
825                data['dark image'][1] = mult
826            except ValueError:
827                pass
828            darkMult.SetValue("%.3f" % (data['dark image'][1]))          #reset in case of error
829            G2plt.PlotExposedImage(G2frame,event=event)
830       
831        backSizer = wx.FlexGridSizer(0,6,5,5)
832
833        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Dark image'),0,WACV)
834        Choices = ['',]+G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
835        darkImage = wx.ComboBox(parent=G2frame.dataDisplay,value=data['dark image'][0],choices=Choices,
836            style=wx.CB_READONLY|wx.CB_DROPDOWN)
837        darkImage.Bind(wx.EVT_COMBOBOX,OnDarkImage)
838        backSizer.Add(darkImage)
839        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' multiplier'),0,WACV)
840        darkMult =  wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (data['dark image'][1])),
841            style=wx.TE_PROCESS_ENTER)
842        darkMult.Bind(wx.EVT_TEXT_ENTER,OnDarkMult)
843        darkMult.Bind(wx.EVT_KILL_FOCUS,OnDarkMult)
844        backSizer.Add(darkMult,0,WACV)
845        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Flat Bkg: '),0,WACV)
846        flatbkg = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.0f" % (data['Flat Bkg'])),
847            style=wx.TE_PROCESS_ENTER)
848        flatbkg.Bind(wx.EVT_TEXT_ENTER,OnFlatBkg)
849        flatbkg.Bind(wx.EVT_KILL_FOCUS,OnFlatBkg)
850        backSizer.Add(flatbkg,0,WACV)
851
852        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background image'),0,WACV)
853        Choices = ['',]+G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
854        backImage = wx.ComboBox(parent=G2frame.dataDisplay,value=data['background image'][0],choices=Choices,
855            style=wx.CB_READONLY|wx.CB_DROPDOWN)
856        backImage.Bind(wx.EVT_COMBOBOX,OnBackImage)
857        backSizer.Add(backImage)
858        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' multiplier'),0,WACV)
859        backMult =  wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (data['background image'][1])),
860            style=wx.TE_PROCESS_ENTER)
861        backMult.Bind(wx.EVT_TEXT_ENTER,OnBackMult)
862        backMult.Bind(wx.EVT_KILL_FOCUS,OnBackMult)
863        backSizer.Add(backMult,0,WACV)
864        return backSizer
865                       
866    def CalibSizer():
867               
868        def OnNewCalibrant(event):
869            data['calibrant'] = calSel.GetValue()
870            data['calibskip'] = calFile.Calibrants[data['calibrant']][3]
871            limits = calFile.Calibrants[data['calibrant']][4]
872            data['calibdmin'],data['pixLimit'],data['cutoff'] = limits
873            pixLimit.SetValue(str(limits[1]))
874            cutOff.SetValue('%.1f'%(limits[2]))
875            calibSkip.SetValue(str(data['calibskip']))
876            calibDmin.SetValue('%.1f'%(limits[0]))
877           
878        def OnCalibSkip(event):
879            data['calibskip'] = int(calibSkip.GetValue())
880           
881        def OnCalibDmin(event):
882            try:
883                dmin = float(calibDmin.GetValue())
884                if dmin < 0.25:
885                    raise ValueError
886                data['calibdmin'] = dmin
887            except ValueError:
888                pass
889            calibDmin.SetValue("%.2f"%(data['calibdmin']))          #reset in case of error 
890                   
891        def OnCutOff(event):
892            try:
893                cutoff = float(cutOff.GetValue())
894                if cutoff < 0.1:
895                    raise ValueError
896                data['cutoff'] = cutoff
897            except ValueError:
898                pass
899            cutOff.SetValue("%.1f"%(data['cutoff']))          #reset in case of error 
900       
901        def OnPixLimit(event):
902            data['pixLimit'] = int(pixLimit.GetValue())
903           
904        def OnSetRings(event):
905            if data['setRings']:
906                data['setRings'] = False
907            else:
908                data['setRings'] = True
909            G2plt.PlotExposedImage(G2frame,event=event)
910   
911        calibSizer = wx.FlexGridSizer(0,3,5,5)
912        comboSizer = wx.BoxSizer(wx.HORIZONTAL)   
913        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calibrant '),0,WACV)
914        calSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['calibrant'],choices=calList,
915            style=wx.CB_READONLY|wx.CB_DROPDOWN)
916        calSel.Bind(wx.EVT_COMBOBOX, OnNewCalibrant)
917        comboSizer.Add(calSel,0,WACV)
918        calibSizer.Add(comboSizer,0)
919       
920        comboSizer = wx.BoxSizer(wx.HORIZONTAL)   
921        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calib lines to skip   '),0,WACV)
922        calibSkip  = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['calibskip']),choices=[str(i) for i in range(25)],
923            style=wx.CB_READONLY|wx.CB_DROPDOWN)
924        calibSkip.Bind(wx.EVT_COMBOBOX, OnCalibSkip)
925        comboSizer.Add(calibSkip,0,WACV)
926        calibSizer.Add(comboSizer,0)
927       
928        comboSizer = wx.BoxSizer(wx.HORIZONTAL)       
929        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Min calib d-spacing '),0,WACV)
930        calibDmin = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.2f" % (data['calibdmin'])),
931            style=wx.TE_PROCESS_ENTER)
932        calibDmin.Bind(wx.EVT_TEXT_ENTER,OnCalibDmin)
933        calibDmin.Bind(wx.EVT_KILL_FOCUS,OnCalibDmin)
934        comboSizer.Add(calibDmin,0,WACV)
935        calibSizer.Add(comboSizer,0)
936       
937        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
938        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Min ring I/Ib '),0,WACV)
939        cutOff = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.1f" % (data['cutoff'])),
940            style=wx.TE_PROCESS_ENTER)
941        cutOff.Bind(wx.EVT_TEXT_ENTER,OnCutOff)
942        cutOff.Bind(wx.EVT_KILL_FOCUS,OnCutOff)
943        comboSizer.Add(cutOff,0,WACV)
944        calibSizer.Add(comboSizer,0)
945       
946        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
947        comboSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Pixel search range '),0,WACV)
948        pixLimit = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['pixLimit']),choices=['1','2','5','10','15','20'],
949            style=wx.CB_READONLY|wx.CB_DROPDOWN)
950        pixLimit.Bind(wx.EVT_COMBOBOX, OnPixLimit)
951        comboSizer.Add(pixLimit,0,WACV)
952        calibSizer.Add(comboSizer,0)
953       
954        comboSizer = wx.BoxSizer(wx.HORIZONTAL)
955        setRings = wx.CheckBox(parent=G2frame.dataDisplay,label='Show ring picks?')
956        comboSizer.Add(setRings,0)
957        setRings.Bind(wx.EVT_CHECKBOX, OnSetRings)
958        setRings.SetValue(data['setRings'])
959        calibSizer.Add(comboSizer,0)
960        return calibSizer
961       
962    def GonioSizer():
963       
964        ValObj = {}
965       
966        def OnGonioAngle(event):
967            Obj = event.GetEventObject()
968            item = ValObj[Obj.GetId()]
969            try:
970                value = float(Obj.GetValue())
971            except ValueError:
972                value = data['GonioAngles'][item]
973            data['GonioAngles'][item] = value
974            Obj.SetValue('%8.2f'%(value))
975           
976        def OnGlobalEdit(event):
977            Names = []
978            Items = []
979            if G2frame.PatternTree.GetCount():
980                id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
981                while id:
982                    name = G2frame.PatternTree.GetItemText(id)
983                    if 'IMG' in name:
984                        ctrls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id,'Image Controls'))
985                        Names.append(name)
986                        Items.append(ctrls['GonioAngles'])
987                    id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
988                if len(Names) == 1:
989                    G2frame.ErrorDialog('Nothing for global editing','There must be more than one "IMG" pattern')
990                    return
991                dlg = G2G.G2HistoDataDialog(G2frame,' Edit sample goniometer data:',
992                    'Edit data',['Omega','Chi','Phi'],['%.2f','%.2f','%.2f'],Names,Items)
993            try:
994                if dlg.ShowModal() == wx.ID_OK:
995                    result = dlg.GetData()
996                    id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
997                    while id:
998                        name = G2frame.PatternTree.GetItemText(id)
999                        if 'IMG' in name:
1000                            ctrls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id,'Image Controls'))
1001                            vals = Items[Names.index(name)]
1002                            ctrls['GonioAngles'] = vals
1003#                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Image Controls'),ctrls)
1004                        id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1005            finally:
1006                dlg.Destroy()
1007                G2frame.PatternTree.SelectItem(G2frame.PickId)
1008       
1009        gonioSizer = wx.BoxSizer(wx.HORIZONTAL)
1010        names = ['Omega','Chi','Phi']
1011        gonioSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'Sample goniometer angles: '),0,WACV)
1012        for i,name in enumerate(names):
1013            gonioSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,name),0,WACV)
1014            angle = wx.TextCtrl(G2frame.dataDisplay,-1,value='%8.2f'%(data['GonioAngles'][i]),
1015                style=wx.TE_PROCESS_ENTER)
1016            angle.Bind(wx.EVT_TEXT_ENTER,OnGonioAngle)
1017            angle.Bind(wx.EVT_KILL_FOCUS,OnGonioAngle)
1018            ValObj[angle.GetId()] = i
1019            gonioSizer.Add(angle,0,WACV)
1020        globEdit = wx.Button(G2frame.dataDisplay,-1,'Global edit')
1021        globEdit.Bind(wx.EVT_BUTTON,OnGlobalEdit)
1022        gonioSizer.Add(globEdit,0,WACV)
1023        return gonioSizer
1024       
1025# Image Controls main code             
1026                           
1027    #fix for old files:
1028    if 'azmthOff' not in data:
1029        data['azmthOff'] = 0.0
1030    if 'background image' not in data:
1031        data['background image'] = ['',-1.0]
1032    if 'dark image' not in data:
1033        data['dark image'] = ['',-1.0]
1034    if 'centerAzm' not in data:
1035        data['centerAzm'] = False
1036    if 'Oblique' not in data:
1037        data['Oblique'] = [0.5,False]
1038    if 'PolaVal' not in data:
1039        data['PolaVal'] = [0.99,False]
1040    #end fix
1041   
1042    if IntegrateOnly:
1043        OnIntegrate(None)
1044        return
1045   
1046    colorList = sorted([m for m in mpl.cm.datad.keys() if not m.endswith("_r")],key=lambda s: s.lower())
1047    calList = sorted([m for m in calFile.Calibrants.keys()],key=lambda s: s.lower())
1048    typeList = ['PWDR - powder diffraction data','SASD - small angle scattering data',
1049        'REFL - reflectometry data']
1050    if not data.get('type'):                        #patch for old project files
1051        data['type'] = 'PWDR'
1052    typeDict = {'PWDR':typeList[0],'SASD':typeList[1],'REFL':typeList[2]}
1053    if G2frame.dataDisplay:
1054        G2frame.dataDisplay.Destroy()
1055    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ImageMenu)
1056    if not G2frame.dataFrame.GetStatusBar():
1057        G2frame.dataFrame.CreateStatusBar()
1058    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCalibrate, id=G2gd.wxID_IMCALIBRATE)
1059    G2frame.dataFrame.Bind(wx.EVT_MENU, OnRecalibrate, id=G2gd.wxID_IMRECALIBRATE)
1060    G2frame.dataFrame.Bind(wx.EVT_MENU, OnClearCalib, id=G2gd.wxID_IMCLEARCALIB)
1061    if 'chisq' not in data:
1062        G2frame.dataFrame.ImageEdit.Enable(id=G2gd.wxID_IMRECALIBRATE,enable=False)   
1063    G2frame.dataFrame.Bind(wx.EVT_MENU, OnIntegrate, id=G2gd.wxID_IMINTEGRATE)
1064    G2frame.dataFrame.Bind(wx.EVT_MENU, OnIntegrateAll, id=G2gd.wxID_INTEGRATEALL)
1065    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyControls, id=G2gd.wxID_IMCOPYCONTROLS)
1066    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveControls, id=G2gd.wxID_IMSAVECONTROLS)
1067    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadControls, id=G2gd.wxID_IMLOADCONTROLS)
1068    def OnDestroy(event):
1069        G2frame.autoIntFrame = None
1070    def OnAutoInt(event):
1071        if G2frame.autoIntFrame: # ensure only one open at a time
1072            G2frame.autoIntFrame.Raise()
1073            return
1074        G2frame.autoIntFrame = AutoIntFrame(G2frame,PollTime=10.0)
1075        G2frame.autoIntFrame.Bind(wx.EVT_WINDOW_DESTROY,OnDestroy) # clean up name on window close
1076    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAutoInt, id=G2gd.wxID_IMAUTOINTEG)
1077    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1078
1079    mainSizer = wx.BoxSizer(wx.VERTICAL)
1080    mainSizer.Add((5,10),0)   
1081    mainSizer.Add(ComboSizer(),0,wx.ALIGN_LEFT)
1082    mainSizer.Add((5,5),0)           
1083    mainSizer.Add(MaxSizer(),0,wx.ALIGN_LEFT|wx.EXPAND)
1084   
1085    mainSizer.Add((5,5),0)
1086    DataSizer = wx.FlexGridSizer(0,2,5,5)
1087    DataSizer.Add(CalibCoeffSizer(),0)
1088    DataSizer.Add(IntegrateSizer(),0)       
1089    mainSizer.Add(DataSizer,0)
1090    mainSizer.Add((5,5),0)           
1091    mainSizer.Add(BackSizer(),0)
1092    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Calibration controls:'),0,WACV)
1093    mainSizer.Add((5,5),0)
1094    mainSizer.Add(CalibSizer(),0,WACV)
1095    mainSizer.Add((5,5),0)
1096    mainSizer.Add(GonioSizer(),0,WACV)   
1097       
1098    mainSizer.Layout()   
1099    G2frame.dataDisplay.SetSizer(mainSizer)
1100    fitSize = mainSizer.Fit(G2frame.dataFrame)
1101    G2frame.dataFrame.setSizePosLeft(fitSize)
1102    G2frame.dataDisplay.SetSize(fitSize)
1103   
1104################################################################################
1105##### Masks
1106################################################################################
1107def CleanupMasks(data):
1108    '''If a mask creation is not completed, an empty mask entry is created in the
1109    masks array. This cleans them out. It is called when the masks page is first loaded
1110    and before saving them or after reading them in. This should also probably be done
1111    before they are used for integration.
1112    '''
1113    for key in ['Points','Rings','Arcs','Polygons']:
1114        data[key] = data.get(key,[])
1115        l1 = len(data[key])
1116        data[key] = [i for i in data[key] if i]
1117        l2 = len(data[key])
1118        if GSASIIpath.GetConfigValue('debug') and l1 != l2:
1119            print 'Mask Cleanup:',key,'was',l1,'entries','now',l2
1120   
1121def UpdateMasks(G2frame,data):
1122    '''Shows and handles the controls on the "Masks" data tree entry
1123    '''
1124   
1125    def OnTextMsg(event):
1126        Obj = event.GetEventObject()
1127        Obj.SetToolTipString('Drag this mask on 2D Powder Image with mouse to change ')
1128
1129    def Replot(*args,**kwargs):
1130        G2plt.PlotExposedImage(G2frame,newPlot=True)       
1131
1132    def onDeleteMask(event):
1133        Obj = event.GetEventObject()
1134        typ = Obj.locationcode.split('+')[1]
1135        num = int(Obj.locationcode.split('+')[2])
1136        del(data[typ][num])
1137        wx.CallAfter(UpdateMasks,G2frame,data)
1138        G2plt.PlotExposedImage(G2frame,event=event)
1139
1140    def onDeleteFrame(event):
1141        data['Frames'] = []
1142        wx.CallAfter(UpdateMasks,G2frame,data)
1143        G2plt.PlotExposedImage(G2frame,event=event)
1144
1145    def OnCopyMask(event):
1146        TextList = [[False,'All IMG',0]]
1147        Names = []
1148        if G2frame.PatternTree.GetCount():
1149            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1150            while id:
1151                name = G2frame.PatternTree.GetItemText(id)
1152                Names.append(name)
1153                if 'IMG' in name:
1154                    if id == G2frame.Image:
1155                        Source = name
1156                        Mask = copy.deepcopy(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks')))
1157                        Thresh = Mask.pop('Thresholds')  #remove Thresholds from source mask & save it for later
1158                    else:
1159                        TextList.append([False,name,id])
1160                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1161            if len(TextList) == 1:
1162                G2frame.ErrorDialog('Nothing to copy mask to','There must be more than one "IMG" pattern')
1163                return
1164            dlg = G2frame.CopyDialog(G2frame,'Copy mask information','Copy mask from '+Source+' to:',TextList)
1165            try:
1166                if dlg.ShowModal() == wx.ID_OK:
1167                    result = dlg.GetData()
1168                    if result[0][0]:
1169                        result = TextList[1:]
1170                        for item in result: item[0] = True
1171                    for i,item in enumerate(result):
1172                        ifcopy,name,id = item
1173                        if ifcopy:
1174                            mask = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'))
1175#                            Mask['Thresholds'][0] = mask['Thresholds'][0]
1176#                            Mask['Thresholds'][1][1] = min(mask['Thresholds'][1][1],Mask['Thresholds'][1][1])
1177                            mask.update(Mask)
1178                            mask['Thresholds'][1][0] = Thresh[1][0]  #copy only lower threshold                             
1179                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'),copy.deepcopy(mask))
1180            finally:
1181                dlg.Destroy()
1182               
1183    def OnSaveMask(event):
1184        CleanupMasks(data)
1185        dlg = wx.FileDialog(G2frame, 'Choose image mask file', '.', '', 
1186            'image mask files (*.immask)|*.immask',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1187        try:
1188            if dlg.ShowModal() == wx.ID_OK:
1189                filename = dlg.GetPath()
1190                filename = os.path.splitext(filename)[0]+'.immask'
1191                File = open(filename,'w')
1192                save = {}
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    def OnTimerLoop(self,event):
1992        '''A method that is called every :meth:`PollTime` seconds that is
1993        used to check for new files and process them. This is called only
1994        after the "Start" button is pressed (when its label reads "Pause").
1995        '''
1996        G2frame = self.G2frame
1997        try:
1998            self.currImageList = sorted(
1999                glob.glob(os.path.join(self.imagedir,self.params['filter'])))
2000        except IndexError:
2001            self.currImageList = []
2002            return
2003
2004        # Create a list of image files that have already been read
2005        imageFileList = []
2006        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2007            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2008            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2009            if imagefile not in imageFileList: imageFileList.append(imagefile)
2010        # loop over image files matching glob, reading in new ones
2011        for newImage in self.currImageList:
2012            if newImage in imageFileList: continue # already read
2013            for imgId in G2IO.ReadImages(G2frame,newImage):
2014                controlsDict = G2frame.PatternTree.GetItemPyData(
2015                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls'))
2016                ImageMasks = G2frame.PatternTree.GetItemPyData(
2017                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks'))
2018                if self.params['Mode'] == 'table':
2019                    dist = controlsDict['distance']
2020                    interpDict,imgctrl,immask = self.Evaluator(dist) # interpolated calibration values
2021                    if GSASIIpath.GetConfigValue('debug'):
2022                        print 'interpolated: ',interpDict
2023                    self.ImageControls = ReadControls(imgctrl)
2024                    self.ImageControls.update(interpDict)
2025                    self.ImageControls['showLines'] = True
2026                    self.ImageControls['ring'] = []
2027                    self.ImageControls['rings'] = []
2028                    self.ImageControls['ellipses'] = []
2029                    self.ImageControls['setDefault'] = False
2030                    for i in 'range','size','GonioAngles':
2031                        if i in self.ImageControls:
2032                            del self.ImageControls[i]
2033                    # load copy of Image Masks
2034                    if immask:
2035                        self.ImageMasks = ReadMask(immask)
2036                        del self.Thresholds['Thresholds']
2037                    else:
2038                        self.ImageMasks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[]}
2039                # update controls from master
2040                controlsDict.update(self.ImageControls)
2041                # update masks from master w/o Thresholds
2042                ImageMasks.update(self.ImageMasks)
2043        # now integrate the images that have not already been processed before
2044        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2045            if img in G2frame.IntegratedList: continue
2046            G2frame.IntegratedList.append(img)
2047            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2048            G2frame.Image = imgId
2049            G2frame.PickId = G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls')
2050            #  integrate in this entry
2051            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2052            G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,True,imagetag)
2053            masks = G2frame.PatternTree.GetItemPyData(
2054                G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2055            data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
2056            self.oldImagefile = '' # mark image as changed; reread as needed
2057            # simulate a Image Controls press, since that is where the
2058            # integration is hidden
2059            UpdateImageControls(G2frame,data,masks,IntegrateOnly=True)
2060            # split name and control number
2061            s = re.split(r'(\d+)\Z',os.path.split(os.path.splitext(imagefile)[0])[1])
2062            namepre = s[0]
2063            if len(s) > 1:
2064                namenum = s[1]
2065            else:
2066                namenum = ''
2067            # write out the images in the selected formats and save the names,
2068            # reset will delete them
2069            for Id in G2frame.IntgOutList:
2070                treename = G2frame.PatternTree.GetItemText(Id)
2071                G2frame.AutointPWDRnames.append(treename)
2072                Sdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
2073                # determine the name for the current file
2074                fileroot = namepre
2075                if len(G2frame.IntgOutList) > 1:
2076                    fileroot += "_AZM"
2077                    if 'Azimuth' in Sdata:
2078                        fileroot += str(int(10*Sdata['Azimuth']))
2079                    fileroot += "_" 
2080                fileroot += namenum
2081                # loop over selected formats
2082                for dfmt in self.fmtlist:
2083                    if not self.params[dfmt[1:]]: continue
2084                    if self.params['SeparateDir']:
2085                        subdir = dfmt[1:]
2086                    else:
2087                        subdir = ''
2088                    fil = os.path.join(self.params['outdir'],subdir,fileroot)
2089                    print('writing file '+fil+dfmt)
2090                    G2IO.ExportPowder(G2frame,treename,fil,dfmt)
2091       
2092        if GSASIIpath.GetConfigValue('debug'):
2093            import datetime
2094            print ("Timer tick at {:%d %b %Y %H:%M:%S}\n".format(datetime.datetime.now()))
2095
2096    def StartLoop(self):
2097        '''Save current Image params for use in future integrations
2098        also label the window so users understand whatis being used
2099        '''
2100        print '\nStarting new autointegration\n'
2101        G2frame = self.G2frame
2102        # show current IMG base
2103        self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image))
2104        if self.params['Mode'] != 'table':
2105            # load copy of Image Controls from current image and clean up
2106            # items that should not be copied
2107            self.ImageControls = copy.deepcopy(
2108                G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
2109                    G2frame,G2frame.Image, 'Image Controls')))
2110            self.ImageControls['showLines'] = True
2111            self.ImageControls['ring'] = []
2112            self.ImageControls['rings'] = []
2113            self.ImageControls['ellipses'] = []
2114            self.ImageControls['setDefault'] = False
2115            del self.ImageControls['range']
2116            del self.ImageControls['size']
2117            del self.ImageControls['GonioAngles']
2118            # load copy of Image Masks, keep thresholds
2119            self.ImageMasks = copy.deepcopy(
2120                G2frame.PatternTree.GetItemPyData(
2121                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks')))
2122            self.Thresholds = self.ImageMasks['Thresholds'][:]
2123        # make sure all output directories exist
2124        if self.params['SeparateDir']:
2125            for dfmt in self.fmtlist:
2126                if not self.params[dfmt[1:]]: continue
2127                dir = os.path.join(self.params['outdir'],dfmt[1:])
2128                if not os.path.exists(dir): os.makedirs(dir)
2129        else:
2130            if not os.path.exists(self.params['outdir']):
2131                os.makedirs(self.params['outdir'])
2132        if self.Reset: # special things to do after Reset has been pressed
2133            # reset controls and masks for all IMG items in tree to master
2134            for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2135                # update controls from master
2136                controlsDict = G2frame.PatternTree.GetItemPyData(
2137                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
2138                controlsDict.update(self.ImageControls)
2139                # update masks from master
2140                ImageMasks = G2frame.PatternTree.GetItemPyData(
2141                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2142                ImageMasks.update(self.ImageMasks)
2143            # delete all PWDR items created after last Start was pressed
2144            idlist = []
2145            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2146            while item:
2147                itemName = G2frame.PatternTree.GetItemText(item)
2148                if itemName in G2frame.AutointPWDRnames:
2149                    idlist.append(item)
2150                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2151            for item in idlist:
2152                G2frame.PatternTree.Delete(item)
2153            self.Reset = False
2154        G2frame.AutointPWDRnames = [] # list of created PWDR tree item names
2155
2156    def __init__(self,G2frame,PollTime=60.0):
2157        def OnStart(event):
2158            '''Called when the start button is pressed. Changes button label
2159            to Pause. When Pause is pressed the label changes to Resume.
2160            When either Start or Resume is pressed, the processing loop
2161            is started. When Pause is pressed, the loop is stopped.
2162            '''
2163            # check inputs for errors before starting
2164            #err = ''
2165            #if not any([self.params[fmt] for fmt in self.fmtlist]):
2166            #    err += '\nPlease select at least one output format\n'
2167            #if err:
2168            #    G2G.G2MessageBox(self,err)
2169            #    return
2170            # change button label
2171            if btnstart.GetLabel() != 'Pause':
2172                btnstart.SetLabel('Pause')
2173                if self.timer.IsRunning(): self.timer.Stop()
2174                self.StartLoop()
2175                self.OnTimerLoop(None) # run once immediately and again after delay
2176                self.timer.Start(int(1000*PollTime),oneShot=False)
2177                self.Status.SetStatusText('Press Pause to delay integration or Reset to prepare to reintegrate all images')
2178            else:
2179                btnstart.SetLabel('Resume')
2180                if self.timer.IsRunning(): self.timer.Stop()
2181                print('\nPausing autointegration\n')
2182                self.Status.SetStatusText('Press Resume to continue integration or Reset to prepare to reintegrate all images')
2183
2184        def OnReset(event):
2185            '''Called when Reset button is pressed. This stops the
2186            processing loop and resets the list of integrated files so
2187            all images can be reintegrated.
2188            '''
2189            btnstart.SetLabel('Restart')
2190            self.Status.SetStatusText('Press Restart to reload and re-integrate images matching filter')
2191            if self.timer.IsRunning(): self.timer.Stop()
2192            self.Reset = True
2193            self.G2frame.IntegratedList = []
2194           
2195        def OnQuit(event):
2196            '''Stop the processing loop and close the Frame
2197            '''
2198            if self.timer.IsRunning(): self.timer.Stop() # make sure we stop first
2199            wx.CallAfter(self.Destroy)
2200           
2201        def OnBrowse(event):
2202            '''Responds when the Browse button is pressed to load a file.
2203            The routine determines which button was pressed and gets the
2204            appropriate file type and loads it into the appropriate place
2205            in the dict.
2206            '''
2207            if btn3 == event.GetEventObject():
2208                dlg = wx.DirDialog(
2209                    self, 'Select directory for output files',
2210                    self.params['outdir'],wx.DD_DEFAULT_STYLE)
2211                dlg.CenterOnParent()
2212                try:
2213                    if dlg.ShowModal() == wx.ID_OK:
2214                        self.params['outdir'] = dlg.GetPath()
2215                        fInp3.SetValue(self.params['outdir'])
2216                finally:
2217                    dlg.Destroy()
2218                return
2219               
2220        def OnRadioSelect(event):
2221            '''Respond to a radiobutton selection and when in table
2222            mode, get parameters from user.
2223            '''
2224            self.Evaluator = None
2225            if r2.GetValue():
2226                self.params['Mode'] = 'table'
2227                try:
2228                    dlg = IntegParmTable(self.G2frame) # create the dialog
2229                    if dlg.ShowModal() == wx.ID_OK:
2230                        self.Evaluator = DefineEvaluator(dlg)
2231                    else:
2232                        r1.SetValue(True)
2233                finally:
2234                    dlg.Destroy()
2235            else:
2236                self.params['Mode'] = 'active'
2237        ##################################################
2238        # beginning of __init__ processing
2239        ##################################################
2240        self.G2frame = G2frame
2241        self.Evaluator = None
2242        self.params = {}
2243        self.Reset = False
2244        self.params['IMGfile'] = ''
2245        self.params['MaskFile'] = ''
2246        self.params['IgnoreMask'] = True
2247        self.fmtlist = G2IO.ExportPowderList(G2frame)
2248        self.timer = wx.Timer()
2249        self.timer.Bind(wx.EVT_TIMER,self.OnTimerLoop)
2250
2251        controlsId = G2frame.PatternTree.GetSelection()
2252        size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(G2frame.Image)       
2253        self.imagedir,fileroot = os.path.split(imagefile)
2254        self.params['filter'] = '*'+os.path.splitext(fileroot)[1]
2255        self.params['outdir'] = os.path.abspath(self.imagedir)
2256        wx.Frame.__init__(self, G2frame,title='Automatic Integration')
2257        self.Status = self.CreateStatusBar()
2258        self.Status.SetStatusText('Press Start to load and integrate images matching filter')
2259        mnpnl = wx.Panel(self)
2260        mnsizer = wx.BoxSizer(wx.VERTICAL)
2261        sizer = wx.BoxSizer(wx.HORIZONTAL)
2262        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Integration based on: '))
2263        self.ControlBaseLbl = wx.StaticText(mnpnl, wx.ID_ANY,'?')
2264        self.ControlBaseLbl.SetLabel(G2frame.PatternTree.GetItemText(G2frame.Image))
2265        sizer.Add(self.ControlBaseLbl)
2266        mnsizer.Add(sizer,0,wx.ALIGN_LEFT,1)
2267        # file filter stuff
2268        sizer = wx.BoxSizer(wx.HORIZONTAL)
2269        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Image filter'))
2270        flterInp = G2G.ValidatedTxtCtrl(mnpnl,self.params,'filter')
2271        sizer.Add(flterInp)
2272        mnsizer.Add(sizer,0,wx.ALIGN_RIGHT,1)
2273        # box for integration controls & masks input
2274        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Integration Controls/Masks source")
2275        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
2276        r1 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use Active Image",
2277                            style = wx.RB_GROUP)
2278        r1.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
2279        lblsizr.Add(r1)
2280        r1.SetValue(True)
2281        r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "Use from table")
2282        lblsizr.Add(r2)
2283        r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
2284        mnsizer.Add(lblsizr)
2285
2286        # box for output selections
2287        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Output settings")
2288        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
2289        sizer = wx.BoxSizer(wx.HORIZONTAL)
2290        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Write to: '))
2291        fInp3 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'outdir',
2292                                       notBlank=False,size=(300,-1))
2293        sizer.Add(fInp3)
2294        btn3 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
2295        btn3.Bind(wx.EVT_BUTTON, OnBrowse)
2296        sizer.Add(btn3)
2297        lblsizr.Add(sizer)
2298        #lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
2299        sizer = wx.BoxSizer(wx.HORIZONTAL)
2300        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
2301        for dfmt in self.fmtlist:
2302            fmt = dfmt[1:]
2303            self.params[fmt] = False
2304            btn = G2G.G2CheckBox(mnpnl,dfmt,self.params,fmt)
2305            sizer.Add(btn)
2306        lblsizr.Add(sizer)
2307        sizer = wx.BoxSizer(wx.HORIZONTAL)
2308        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Separate dir for each format: '))
2309        self.params['SeparateDir'] = False
2310        sizer.Add(G2G.G2CheckBox(mnpnl,'',self.params,'SeparateDir'))
2311        lblsizr.Add(sizer)
2312        mnsizer.Add(lblsizr,0,wx.ALIGN_CENTER,1)
2313
2314        # buttons on bottom
2315        mnsizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'AutoIntegration controls'),0,wx.TOP,5)
2316        sizer = wx.BoxSizer(wx.HORIZONTAL)
2317        sizer.Add((20,-1))
2318        btnstart = wx.Button(mnpnl,  wx.ID_ANY, "Start")
2319        btnstart.Bind(wx.EVT_BUTTON, OnStart)
2320        sizer.Add(btnstart)
2321        btnstop = wx.Button(mnpnl,  wx.ID_ANY, "Reset")
2322        btnstop.Bind(wx.EVT_BUTTON, OnReset)
2323        sizer.Add(btnstop)
2324        sizer.Add((20,-1),wx.EXPAND,1)
2325        btnquit = wx.Button(mnpnl,  wx.ID_ANY, "Close")
2326        btnquit.Bind(wx.EVT_BUTTON, OnQuit)
2327        sizer.Add(btnquit)
2328        sizer.Add((20,-1))
2329        mnsizer.Add(sizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP,5)
2330       
2331        # finish up window
2332        mnpnl.SetSizer(mnsizer)
2333        OnRadioSelect(None) # disable widgets
2334        mnsizer.Fit(self)
2335        self.CenterOnParent()
2336        self.Show()
2337
2338def DefineEvaluator(dlg):
2339    '''Creates a function that provides interpolated values for a given distance value
2340    '''
2341    def Evaluator(dist):
2342        '''Interpolate image parameters for a supplied distance value
2343
2344        :param float dist: distance to use for interpolation
2345        :returns: a list with 3 items:
2346
2347          * a dict with parameter values,
2348          * the closest imctrl and
2349          * the closest maskfile (or None)
2350        '''           
2351        x = np.array([float(i) for i in parms[0]])
2352        closest = abs(x-dist).argmin()
2353        closeX = x[closest]
2354        D = {'distance':dist}
2355        imctfile = IMfileList[closest]
2356        if parms[-1][closest].lower() != '(none)':
2357            maskfile = parms[-1][closest]
2358        else:
2359            maskfile = None
2360        for c in range(1,cols-1):
2361            lbl = ParmList[c]
2362            if lbl in nonInterpVars:
2363                D[lbl] = float(parms[c][closest])
2364            else:
2365                y = np.array([float(i) for i in parms[c]])
2366                D[lbl] = np.interp(dist,x,y)
2367        # full integration when angular range is 0
2368        D['fullIntegrate'] = (D['LRazimuth_min'] == D['LRazimuth_max'])
2369        # conversion for paired values
2370        for a,b in ('center_x','center_y'),('LRazimuth_min','LRazimuth_max'),('IOtth_min','IOtth_max'):
2371            r = a.split('_')[0]
2372            D[r] = [D[a],D[b]]
2373            del D[a]
2374            del D[b]
2375        return D,imctfile,maskfile
2376    # save local copies of values needed in Evaluator
2377    parms = dlg.ReadImageParmTable()
2378    IMfileList = dlg.IMfileList
2379    cols = dlg.list.GetColumnCount()
2380    ParmList = dlg.ParmList
2381    nonInterpVars = dlg.nonInterpVars
2382    return Evaluator
2383
2384class IntegParmTable(wx.Dialog):
2385    '''Creates a dialog window with a table of integration parameters.
2386    :meth:`ShowModal` will return wx.ID_OK if the process has been successful.
2387    In this case, :func:`DefineEvaluator` should be called to obtain a function that
2388    creates a dictionary with interpolated parameter values.
2389    '''
2390    ParmList = ('distance','center_x','center_y','wavelength','tilt','rotation','DetDepth',
2391            'LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max','outChannels',
2392            'maskfile',
2393            )
2394    nonInterpVars = ('tilt','rotation','LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max',
2395                     'outChannels')  # values in this list are taken from nearest rather than interpolated
2396    HeaderList = ('Det Dist','X cntr','Y cntr','wavelength','tilt','rotation','DetDepth',
2397            'Azimuth min','Azimuth max','2Th min','2Th max','Int. pts',
2398            'Mask File',
2399            )
2400    def __init__(self,G2frame):
2401        self.G2frame = G2frame
2402        self.parms = [] # list of values by column
2403        self.IMfileList = [] # list of .imctrl file names for each entry in table
2404        wx.Dialog.__init__(self,G2frame,style=wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE)
2405        files = []
2406        try:
2407            dlg = wx.FileDialog(self, 'Select image control files or previous table', 
2408                                style=wx.OPEN| wx.MULTIPLE,
2409                                wildcard='image control files (.imctrl)|*.imctrl|Integration table (*.imtbl)|*.imtbl')
2410            if dlg.ShowModal() == wx.ID_OK:
2411                files = dlg.GetPaths()
2412                self.parms,self.IMfileList = self.ReadFiles(files)
2413        finally:
2414            dlg.Destroy()
2415        if not files:
2416            wx.CallAfter(self.EndModal,wx.ID_CANCEL)
2417            return
2418        mainSizer = wx.BoxSizer(wx.VERTICAL)
2419        self.list = ImgIntLstCtrl(self, wx.ID_ANY,
2420                      style=wx.LC_REPORT
2421                          | wx.BORDER_SUNKEN
2422                         #| wx.BORDER_NONE
2423                         )
2424        mainSizer.Add(self.list,1,wx.EXPAND,1)
2425        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
2426        btn = wx.Button(self, wx.ID_OK)
2427        btnsizer.Add(btn)
2428        btn = wx.Button(self, wx.ID_ANY,'Save')
2429        btn.Bind(wx.EVT_BUTTON,self._onSave)
2430        btnsizer.Add(btn)
2431        btn = wx.Button(self, wx.ID_CLOSE,'Quit')
2432        btn.Bind(wx.EVT_BUTTON,self._onClose)
2433        btnsizer.Add(btn)
2434        mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)   
2435        self.SetSizer(mainSizer)
2436        self.list.FillList(self.parms)
2437        mainSizer.Layout()
2438        mainSizer.Fit(self)
2439       
2440    def ReadFiles(self,files):
2441        '''Reads a list of .imctrl files or a single .imtbl file
2442        '''
2443        tmpDict = {}
2444        if not files: return
2445        # option 1, a dump from a previous save
2446        if os.path.splitext(files[0])[1] == '.imtbl':
2447            fp = open(files[0],'r')
2448            S = fp.readline()
2449            while S:
2450                if S[0] != '#':
2451                    [key,val] = S[:-1].split(':')
2452                    tmpDict[key] = eval(val)
2453                S = fp.readline()
2454            fp.close()
2455            # delete entries
2456            m1 = [i for i,f in enumerate(tmpDict['filenames']) if not os.path.exists(f)]
2457            if m1:
2458                print('\nimctrl file not found:')
2459                for i in m1: print('\t#'+str(i)+': '+tmpDict['filenames'][i])
2460            m2 = [i for i,f in enumerate(tmpDict['maskfile']) if not (os.path.exists(f) or f.startswith('('))]
2461            if m2:
2462                print('\nmask file not found')
2463                for i in m2: print('\t#'+str(i)+': '+tmpDict['maskfile'][i])
2464            m3 = [i for i,d in enumerate(tmpDict['distance']) if d < 0]
2465            if m3:
2466                print('\nDropping entries due to negative distance: '+str(m3))
2467            m = sorted(set(m1 + m2 + m3))
2468            m.reverse()
2469            for c in m:
2470                for key in tmpDict:
2471                    del tmpDict[key][c]
2472            fileList = tmpDict.get('filenames','[]')
2473            parms = []
2474            for key in self.ParmList:
2475                try:
2476                    float(tmpDict[key][0])
2477                    parms.append([str(G2py3.FormatSigFigs(val,sigfigs=5)) for val in tmpDict[key]])
2478                except ValueError:
2479                    parms.append(tmpDict[key])
2480            return parms,fileList
2481        # option 2, read in a list of files
2482        for file in files: # read all files; place in dict by distance
2483            imgDict = Read_imctrl(file)
2484            tmpDict[imgDict.get('distance')] = imgDict
2485        parms = [[] for key in self.ParmList]
2486        fileList = []
2487        for d in sorted(tmpDict):
2488            fileList.append(tmpDict[d].get('filename'))
2489            if d is None: continue
2490            if d < 0: continue
2491            for i,key in enumerate(self.ParmList):
2492                val = tmpDict[d].get(key)
2493                try:
2494                    val = str(G2py3.FormatSigFigs(val,sigfigs=5))
2495                except:
2496                    val = str(val)
2497                parms[i].append(val)
2498        return parms,fileList
2499   
2500    def ReadImageParmTable(self):
2501        '''Reads possibly edited values from the ListCtrl table and returns a list
2502        of values for each column.
2503        '''
2504        rows = self.list.GetItemCount()
2505        cols = self.list.GetColumnCount()
2506        parms = []
2507        for c in range(cols):
2508            lbl = self.ParmList[c]
2509            parms.append([])
2510            for r in range(rows):
2511                parms[c].append(self.list.GetItem(r,c).GetText())
2512        return parms
2513
2514    def _onClose(self,event):
2515        'Called when Cancel button is pressed'
2516        self.EndModal(wx.ID_CANCEL)
2517       
2518    def _onSave(self,event):
2519        'Called when save button is pressed; creates a .imtbl file'
2520        fil = ''
2521        if self.G2frame.GSASprojectfile:
2522            fil = os.path.splitext(self.G2frame.GSASprojectfile)[0]+'.imtbl'
2523        dir,f = os.path.split(fil)
2524        try:
2525            dlg = wx.FileDialog(self, 'Save table data as',
2526                        defaultDir=dir, defaultFile=f, style=wx.SAVE)
2527            if dlg.ShowModal() != wx.ID_OK: return
2528            fil = dlg.GetPath()
2529            fil = os.path.splitext(fil)[0]+'.imtbl'
2530        finally:
2531            dlg.Destroy()       
2532        parms = self.ReadImageParmTable()
2533        print('Writing image parameter table as '+fil)
2534        fp = open(fil,'w')
2535        for c in range(len(parms)-1):
2536            lbl = self.ParmList[c]
2537            fp.write(lbl+': '+str([eval(i) for i in parms[c]])+'\n')
2538        lbl = self.ParmList[c+1]
2539        fp.write(lbl+': '+str(parms[c+1])+'\n')
2540        lbl = 'filenames'
2541        fp.write(lbl+': '+str(self.IMfileList)+'\n')
2542        fp.close()
2543   
2544class ImgIntLstCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,listmix.TextEditMixin):
2545    '''Creates a custom ListCtrl for editing Image Integration parameters
2546    '''
2547    def __init__(self, parent, ID, pos=wx.DefaultPosition,
2548                 size=(1000,200), style=0):
2549        self.parent=parent
2550        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
2551        listmix.ListCtrlAutoWidthMixin.__init__(self)
2552        listmix.TextEditMixin.__init__(self)
2553        self.Bind(wx.EVT_LEFT_DCLICK, self.OnDouble)
2554        #self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
2555    def FillList(self,parms):
2556        'Places the current parms into the table'
2557        self.ClearAll()
2558        self.rowlen = len(self.parent.ParmList)
2559        for i,lbl in enumerate(self.parent.HeaderList):
2560            self.InsertColumn(i, lbl)
2561        for r,d in enumerate(parms[0]):
2562            if float(d) < 0: continue
2563            index = self.InsertStringItem(sys.maxint, d)
2564            for j in range(1,len(parms)):
2565                self.SetStringItem(index, j, parms[j][r])
2566        for i,lbl in enumerate(self.parent.ParmList):
2567            self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
2568
2569    def OnDouble(self,evt):
2570        'respond to a double-click'
2571        self.CloseEditor()
2572        fil = '(none)'
2573        try:
2574            dlg = wx.FileDialog(G2frame, 'Select mask or control file to add (Press cancel if none)', 
2575                                style=wx.OPEN,
2576                                wildcard='Add GSAS-II mask file (.immask)|*.immask|add image control file (.imctrl)|*.imctrl')
2577            if dlg.ShowModal() == wx.ID_OK:
2578                fil = dlg.GetPath()
2579        finally:
2580            dlg.Destroy()
2581        if os.path.splitext(fil)[1] != '.imctrl':
2582            self.SetStringItem(self.curRow, self.rowlen-1, fil)
2583            self.SetColumnWidth(self.rowlen-1, wx.LIST_AUTOSIZE)
2584        else:
2585            # insert or overwrite an instrument parameter set
2586            if not os.path.exists(fil):
2587                print('Does not exist: '+fil)
2588                return
2589            imgDict = Read_imctrl(fil)
2590            dist = imgDict['distance']
2591            parms = self.parent.ReadImageParmTable()
2592            x = np.array([float(i) for i in parms[0]])
2593            closest = abs(x-dist).argmin()
2594            closeX = x[closest]
2595            # fix IMfileList
2596            for c,lbl in enumerate(self.parent.ParmList):
2597                try:
2598                    vali = G2py3.FormatSigFigs(float(imgDict[lbl]),sigfigs=5)
2599                except ValueError:
2600                    vali = imgDict[lbl]
2601                if abs(closeX-dist) < 1.: # distance is within 1 mm, replace
2602                    parms[c][closest] = vali
2603                elif dist > closeX: # insert after
2604                    parms[c].insert(closest+1,vali)
2605                else:
2606                    parms[c].insert(closest,vali)
2607            if abs(closeX-dist) < 1.: # distance is within 1 mm, replace
2608                self.parent.IMfileList[closest] = fil
2609            elif dist > closeX: # insert after
2610                self.parent.IMfileList.insert(closest+1,fil)
2611            else:
2612                self.parent.IMfileList.insert(closest,fil)
2613            self.FillList(parms)
2614# Autointegration end
2615###########################################################################
Note: See TracBrowser for help on using the repository browser.