source: trunk/GSASIIimgGUI.py @ 2174

Last change on this file since 2174 was 2174, checked in by vondreele, 9 years ago

fix image integrate and integrate all with dark & background images
trap bad G2frame.PickId? (there may be more!)
fix cleanup after DIFFax crash & other stacking fault fixes

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