source: trunk/GSASIIimgGUI.py @ 2302

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

fresh binaries for binwin2.7/fellipse.pyd
explicit del for various arrays in ImageIntegrate?
implement one of Andrey's modifications (other covered by RBVD changes)
change order of wildcard in file dialog for integration table input; .imtbl is now default

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