source: trunk/GSASIIimgGUI.py @ 2106

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

more for Andrey: 3. no update on contour plot (change so y-axis is expanded); give up on 2. Load Controls” menu entry messes up plot redraw.

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