source: trunk/GSASIIimgGUI.py @ 2288

Last change on this file since 2288 was 2288, checked in by vondreele, 6 years ago

fix problem with incompatible arrays in dark correction

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