source: trunk/GSASIIimgGUI.py @ 2093

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

autoint: show IMGs to be integrated; replace PWDR when auto-integrated

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