source: trunk/GSASIIimgGUI.py @ 2083

Last change on this file since 2083 was 2083, checked in by toby, 8 years ago

Export multiple masks/controls

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