source: trunk/GSASIIimgGUI.py @ 2109

Last change on this file since 2109 was 2109, checked in by toby, 7 years ago

Andrey's enhancement: keep track of last GPX, import & export directories; optionally save the 1st two

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