source: trunk/GSASIIimgGUI.py @ 2163

Last change on this file since 2163 was 2149, checked in by toby, 9 years ago

copy thresholds with auto-int table lookup only when changed.

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