source: trunk/GSASIIimgGUI.py @ 2108

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

Bug fix for Andrey: 5. Allow recalibrate after load controls on new image; fix to load image controls and change to enable of Recalibrate

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