source: trunk/GSASIIimgGUI.py @ 2105

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

Andrey's request: edit/view distance look-up table

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