source: trunk/GSASIIimgGUI.py @ 2222

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

fix min image default threshold at zero rather than min(image) - avoids problems with corrected images
refactor copy image controls, masks & stress/stran coeff to use G2MultiChoiceDialog
refactor integrateall & fitall stress/strain to use G2MultiChoiceDialog
all much nicer & cleaner code

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