source: trunk/GSASIIimgGUI.py @ 2221

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

change text of "Use as default ..." to "use for all new .." on Image Controls page
Use GetImageZ in Stress/strain fitting to get image corrected for dark, etc.

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