source: trunk/GSASIIimgGUI.py @ 2223

Last change on this file since 2223 was 2223, checked in by vondreele, 7 years ago

make min Threshold = 0 for images on import; anything else is too confusing
further mods to OnCopyControls? - simplify & prevent image from having self as dark or background
& not allow setting of dark or background to current image

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