source: trunk/GSASIIimgGUI.py @ 2107

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

Bug fix: 6. After changing mask input plot is redrawn reseting limits and sometimes with two scale bars.; zoom is fixed, reason for two scale bars is unclear, but I am taking a guess that recursive calls to PlotImage? could be the problem, wx.CallAfter? added to these.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 126.6 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - image data display routines
3########### SVN repository information ###################
4# $Date: 2015-12-24 20:15:40 +0000 (Thu, 24 Dec 2015) $
5# $Author: toby $
6# $Revision: 2107 $
7# $URL: trunk/GSASIIimgGUI.py $
8# $Id: GSASIIimgGUI.py 2107 2015-12-24 20:15:40Z 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: 2107 $")
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        G2plt.PlotExposedImage(G2frame) # remove newPlot=True to prevent zoom-out
1132
1133    def onDeleteMask(event):
1134        Obj = event.GetEventObject()
1135        typ = Obj.locationcode.split('+')[1]
1136        num = int(Obj.locationcode.split('+')[2])
1137        del(data[typ][num])
1138        wx.CallAfter(UpdateMasks,G2frame,data)
1139        G2plt.PlotExposedImage(G2frame,event=event)
1140
1141    def onDeleteFrame(event):
1142        data['Frames'] = []
1143        wx.CallAfter(UpdateMasks,G2frame,data)
1144        G2plt.PlotExposedImage(G2frame,event=event)
1145
1146    def OnCopyMask(event):
1147        TextList = [[False,'All IMG',0]]
1148#        Names = []
1149        if G2frame.PatternTree.GetCount():
1150            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1151            while id:
1152                name = G2frame.PatternTree.GetItemText(id)
1153#                Names.append(name)
1154                if 'IMG' in name:
1155                    if id == G2frame.Image:
1156                        Source = name
1157                        Mask = copy.deepcopy(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks')))
1158                        Thresh = Mask.pop('Thresholds')  #remove Thresholds from source mask & save it for later
1159                    else:
1160                        TextList.append([False,name,id])
1161                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1162            if len(TextList) == 1:
1163                G2frame.ErrorDialog('Nothing to copy mask to','There must be more than one "IMG" pattern')
1164                return
1165            dlg = G2frame.CopyDialog(G2frame,'Copy mask information','Copy mask from '+Source+' to:',TextList)
1166            try:
1167                if dlg.ShowModal() == wx.ID_OK:
1168                    result = dlg.GetData()
1169                    if result[0][0]:
1170                        result = TextList[1:]
1171                        for item in result: item[0] = True
1172                    for i,item in enumerate(result):
1173                        ifcopy,name,id = item
1174                        if ifcopy:
1175                            mask = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'))
1176#                            Mask['Thresholds'][0] = mask['Thresholds'][0]
1177#                            Mask['Thresholds'][1][1] = min(mask['Thresholds'][1][1],Mask['Thresholds'][1][1])
1178                            mask.update(Mask)
1179                            mask['Thresholds'][1][0] = Thresh[1][0]  #copy only lower threshold                             
1180                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Masks'),copy.deepcopy(mask))
1181            finally:
1182                dlg.Destroy()
1183               
1184    def OnSaveMask(event):
1185        CleanupMasks(data)
1186        dlg = wx.FileDialog(G2frame, 'Choose image mask file', '.', '', 
1187            'image mask files (*.immask)|*.immask',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1188        try:
1189            if dlg.ShowModal() == wx.ID_OK:
1190                filename = dlg.GetPath()
1191                filename = os.path.splitext(filename)[0]+'.immask'
1192                File = open(filename,'w')
1193                keys = ['Points','Rings','Arcs','Polygons','Frames','Thresholds']
1194                for key in keys:
1195                    File.write(key+':'+str(data[key])+'\n')
1196                File.close()
1197        finally:
1198            dlg.Destroy()
1199       
1200    def OnLoadMask(event):
1201        if event.Id == G2gd.wxID_MASKLOADNOT:
1202            ignoreThreshold = True
1203        else:
1204            ignoreThreshold = False
1205        dlg = wx.FileDialog(G2frame, 'Choose image mask file', '.', '', 
1206            'image mask files (*.immask)|*.immask',wx.OPEN|wx.CHANGE_DIR)
1207        try:
1208            if dlg.ShowModal() == wx.ID_OK:
1209                filename = dlg.GetPath()
1210                File = open(filename,'r')
1211                save = {}
1212                oldThreshold = data['Thresholds'][0]
1213                S = File.readline()
1214                while S:
1215                    if S[0] == '#':
1216                        S = File.readline()
1217                        continue
1218                    [key,val] = S[:-1].split(':')
1219                    if key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']:
1220                        if ignoreThreshold and key == 'Thresholds':
1221                            S = File.readline() 
1222                            continue
1223                        save[key] = eval(val)
1224                        if key == 'Thresholds':
1225                            save[key][0] = oldThreshold
1226                            save[key][1][1] = min(oldThreshold[1],save[key][1][1])
1227                    S = File.readline()
1228                File.close()
1229                data.update(save)
1230                CleanupMasks(data)
1231                wx.CallAfter(UpdateMasks,G2frame,data)
1232                G2plt.PlotExposedImage(G2frame,event=event)               
1233        finally:
1234            dlg.Destroy()
1235           
1236    def OnNewSpotMask(event):
1237        'Start a new spot mask'
1238        G2frame.MaskKey = 's'
1239        G2plt.OnStartMask(G2frame)
1240       
1241    def OnNewArcMask(event):
1242        'Start a new arc mask'
1243        G2frame.MaskKey = 'a'
1244        G2plt.OnStartMask(G2frame)
1245       
1246    def OnNewRingMask(event):
1247        'Start a new ring mask'
1248        G2frame.MaskKey = 'r'
1249        G2plt.OnStartMask(G2frame)
1250       
1251    def OnNewPolyMask(event):
1252        'Start a new polygon mask'
1253        G2frame.MaskKey = 'p'
1254        G2plt.OnStartMask(G2frame)
1255       
1256    def OnNewFrameMask(event):
1257        'Start a new Frame mask'
1258        G2frame.MaskKey = 'f'
1259        G2plt.OnStartMask(G2frame)
1260
1261    startScroll = None
1262    if G2frame.dataDisplay:
1263        startScroll = G2frame.dataDisplay.GetScrollPos(wx.VERTICAL) # save scroll position
1264        G2frame.dataDisplay.Destroy()
1265    else:
1266        CleanupMasks(data) # posting page for 1st time; clean out anything unfinished
1267    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.MaskMenu)
1268    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyMask, id=G2gd.wxID_MASKCOPY)
1269    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadMask, id=G2gd.wxID_MASKLOAD)
1270    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadMask, id=G2gd.wxID_MASKLOADNOT)
1271    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveMask, id=G2gd.wxID_MASKSAVE)
1272    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewSpotMask, id=G2gd.wxID_NEWMASKSPOT)
1273    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewArcMask, id=G2gd.wxID_NEWMASKARC)
1274    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewRingMask, id=G2gd.wxID_NEWMASKRING)
1275    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewPolyMask, id=G2gd.wxID_NEWMASKPOLY)
1276    G2frame.dataFrame.Bind(wx.EVT_MENU, OnNewFrameMask, id=G2gd.wxID_NEWMASKFRAME)
1277    if not G2frame.dataFrame.GetStatusBar():
1278        Status = G2frame.dataFrame.CreateStatusBar()
1279    if G2frame.MaskKey == 'f':
1280        G2frame.dataFrame.GetStatusBar().SetStatusText('Frame mask active - LB pick next point, RB close polygon')
1281    elif G2frame.MaskKey == 'p':
1282        G2frame.dataFrame.GetStatusBar().SetStatusText('Polygon mask active - LB pick next point, RB close polygon')
1283    elif G2frame.MaskKey == 's':
1284        G2frame.dataFrame.GetStatusBar().SetStatusText('Spot mask active - LB pick spot location')
1285    elif G2frame.MaskKey == 'a':
1286        G2frame.dataFrame.GetStatusBar().SetStatusText('Arc mask active - LB pick arc location')
1287    elif G2frame.MaskKey == 'r':
1288        G2frame.dataFrame.GetStatusBar().SetStatusText('Ring mask active - LB pick ring location')
1289    else:
1290        G2frame.dataFrame.GetStatusBar().SetStatusText("To add mask: press a,r,s,p or f on 2D image for arc/ring/spot/polygon/frame")
1291    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
1292    mainSizer = wx.BoxSizer(wx.VERTICAL)
1293    mainSizer.Add((5,10),0)
1294
1295    thresh = data['Thresholds']         #min/max intensity range
1296    Spots = data['Points']               #x,y,radius in mm
1297    Rings = data['Rings']               #radius, thickness
1298    Polygons = data['Polygons']         #3+ x,y pairs
1299    if 'Frames' not in data:
1300        data['Frames'] = []
1301    frame = data['Frames']             #3+ x,y pairs
1302    Arcs = data['Arcs']                 #radius, start/end azimuth, thickness
1303   
1304    littleSizer = wx.FlexGridSizer(0,3,0,5)
1305    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Lower/Upper limits '),0,WACV)
1306    Text = wx.TextCtrl(G2frame.dataDisplay,value=str(thresh[0][0]),style=wx.TE_READONLY)
1307    littleSizer.Add(Text,0,WACV)
1308    Text.SetBackgroundColour(VERY_LIGHT_GREY)
1309    Text = wx.TextCtrl(G2frame.dataDisplay,value=str(thresh[0][1]),style=wx.TE_READONLY)
1310    littleSizer.Add(Text,0,WACV)
1311    Text.SetBackgroundColour(VERY_LIGHT_GREY)
1312    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Lower/Upper thresholds '),0,WACV)
1313    lowerThreshold = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=0,
1314                                           min=thresh[0][0],OnLeave=Replot,typeHint=int)
1315    littleSizer.Add(lowerThreshold,0,WACV)
1316    upperThreshold = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=1,
1317                                           max=thresh[0][1],OnLeave=Replot,typeHint=int)
1318    littleSizer.Add(upperThreshold,0,WACV)
1319    mainSizer.Add(littleSizer,0,)
1320    if Spots:
1321        lbl = wx.StaticText(parent=G2frame.dataDisplay,label=' Spot masks')
1322        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1323        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1324        littleSizer = wx.FlexGridSizer(0,3,0,5)
1325        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' position, mm'),0,WACV)
1326        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' diameter, mm'),0,WACV)
1327        littleSizer.Add((5,0),0)
1328        for i in range(len(Spots)):
1329            if Spots[i]:
1330                x,y,d = Spots[i]
1331                spotText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.2f,%.2f" % (x,y)),
1332                    style=wx.TE_READONLY)
1333                spotText.SetBackgroundColour(VERY_LIGHT_GREY)
1334                littleSizer.Add(spotText,0,WACV)
1335                spotText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1336                spotDiameter = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Spots[i],key=2,
1337                                           max=100.,OnLeave=Replot,nDig=[8,2])
1338                littleSizer.Add(spotDiameter,0,WACV)
1339                spotDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1340                                            locationcode='Delete+Points+'+str(i),
1341                                            handler=onDeleteMask)
1342                littleSizer.Add(spotDelete,0,WACV)
1343        mainSizer.Add(littleSizer,0,)
1344    if Rings:
1345        lbl = wx.StaticText(parent=G2frame.dataDisplay,label=' Ring masks')
1346        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1347        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1348        littleSizer = wx.FlexGridSizer(0,3,0,5)
1349        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' 2-theta,deg'),0,WACV)
1350        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' thickness, deg'),0,WACV)
1351        littleSizer.Add((5,0),0)
1352        for i in range(len(Rings)):
1353            if Rings[i]:
1354                ringText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (Rings[i][0])),
1355                    style=wx.TE_READONLY)
1356                ringText.SetBackgroundColour(VERY_LIGHT_GREY)
1357                ringText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1358                littleSizer.Add(ringText,0,WACV)
1359                ringThick = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Rings[i],key=1,
1360                                           min=0.001,max=1.,OnLeave=Replot,nDig=[8,3])
1361                littleSizer.Add(ringThick,0,WACV)
1362                ringDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1363                                            locationcode='Delete+Rings+'+str(i),
1364                                            handler=onDeleteMask)
1365                littleSizer.Add(ringDelete,0,WACV)
1366        mainSizer.Add(littleSizer,0,)
1367    if Arcs:
1368        lbl = wx.StaticText(parent=G2frame.dataDisplay,label=' Arc masks')
1369        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1370        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1371        littleSizer = wx.FlexGridSizer(0,4,0,5)
1372        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' 2-theta,deg'),0,WACV)
1373        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' azimuth, deg'),0,WACV)
1374        littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' thickness, deg'),0,WACV)
1375        littleSizer.Add((5,0),0)
1376        for i in range(len(Arcs)):
1377            if Arcs[i]:
1378                tth,azimuth,thick = Arcs[i]
1379                arcText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.3f" % (tth)),
1380                    style=wx.TE_READONLY)
1381                arcText.SetBackgroundColour(VERY_LIGHT_GREY)
1382                arcText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1383                littleSizer.Add(arcText,0,WACV)
1384                azmText = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%d,%d" % (azimuth[0],azimuth[1])),
1385                    style=wx.TE_READONLY)
1386                azmText.SetBackgroundColour(VERY_LIGHT_GREY)
1387                azmText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
1388                littleSizer.Add(azmText,0,WACV)
1389                arcThick = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Arcs[i],key=2,
1390                                           min=0.001,max=20.,OnLeave=Replot,nDig=[8,3])
1391                littleSizer.Add(arcThick,0,WACV)
1392                arcDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1393                                            locationcode='Delete+Arcs+'+str(i),
1394                                            handler=onDeleteMask)
1395                littleSizer.Add(arcDelete,0,WACV)
1396        mainSizer.Add(littleSizer,0,)
1397    if Polygons:
1398        lbl = wx.StaticText(parent=G2frame.dataDisplay,
1399            label=' Polygon masks (on plot RB vertex drag to move,\nLB vertex drag to insert)')
1400        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1401        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1402        littleSizer = wx.FlexGridSizer(0,2,0,5)
1403        for i in range(len(Polygons)):
1404            if Polygons[i]:
1405                polyList = []
1406                for x,y in Polygons[i]:
1407                    polyList.append("%.2f, %.2f"%(x,y))
1408                polyText = wx.ComboBox(G2frame.dataDisplay,value=polyList[0],choices=polyList,style=wx.CB_READONLY)
1409                littleSizer.Add(polyText,0,WACV)
1410                polyDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1411                                            locationcode='Delete+Polygons+'+str(i),
1412                                            handler=onDeleteMask)
1413                littleSizer.Add(polyDelete,0,WACV)
1414        mainSizer.Add(littleSizer,0,)
1415    if frame:
1416        lbl = wx.StaticText(parent=G2frame.dataDisplay,
1417            label=' Frame mask (on plot RB vertex drag to move,LB vertex drag to insert)')
1418        lbl.SetBackgroundColour(wx.Colour(200,200,210))
1419        mainSizer.Add(lbl,0,wx.EXPAND|wx.ALIGN_CENTER,0)
1420        littleSizer = wx.FlexGridSizer(0,2,0,5)
1421        frameList = []
1422        for x,y in frame:
1423            frameList.append("%.2f, %.2f"%(x,y))
1424        frameText = wx.ComboBox(G2frame.dataDisplay,value=frameList[0],choices=frameList,style=wx.CB_READONLY)
1425        littleSizer.Add(frameText,0,WACV)
1426        frameDelete = G2G.G2LoggedButton(G2frame.dataDisplay,label='delete?',
1427                                            locationcode='Delete+Frame',
1428                                            handler=onDeleteFrame)
1429        littleSizer.Add(frameDelete,0,WACV)
1430        mainSizer.Add(littleSizer,0,)
1431    mainSizer.Layout()   
1432    G2frame.dataDisplay.SetSizer(mainSizer)
1433    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
1434    G2frame.dataDisplay.SetupScrolling()
1435    Size = mainSizer.Fit(G2frame.dataFrame)
1436    Size[0] += 50 # room for scrollbar & status msg
1437    Size[1] = min(Size[1],500)
1438    G2frame.dataDisplay.SetSize(Size)
1439    G2frame.dataFrame.setSizePosLeft(Size)   
1440    wx.Yield()
1441    if startScroll: # reset scroll to saved position
1442        G2frame.dataDisplay.Scroll(0,startScroll) # set to saved scroll position
1443        wx.Yield()
1444
1445################################################################################
1446##### Stress/Strain
1447################################################################################
1448
1449def UpdateStressStrain(G2frame,data):
1450    '''Shows and handles the controls on the "Stress/Strain"
1451    data tree entry
1452    '''
1453   
1454    def OnAppendDzero(event):
1455        data['d-zero'].append({'Dset':1.0,'Dcalc':0.0,'pixLimit':10,'cutoff':1.0,
1456            'ImxyObs':[[],[]],'ImtaObs':[[],[]],'ImtaCalc':[[],[]],'Emat':[1.0,1.0,1.0]})
1457        UpdateStressStrain(G2frame,data)
1458       
1459    def OnUpdateDzero(event):
1460        for item in data['d-zero']:
1461            if item['Dcalc']:   #skip unrefined ones
1462                item['Dset'] = item['Dcalc']
1463        UpdateStressStrain(G2frame,data)
1464           
1465    def OnCopyStrSta(event):
1466        TextList = [[False,'All IMG',0,0]]
1467#        Names = []
1468        if G2frame.PatternTree.GetCount():
1469            id, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1470            while id:
1471                name = G2frame.PatternTree.GetItemText(id)
1472#                Names.append(name)
1473                if 'IMG' in name:
1474                    Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Stress/Strain'))
1475                    if id == G2frame.Image:
1476                        Source = name
1477                    else:
1478                        TextList.append([False,name,id,Data.get('Sample load',0.0)])
1479                id, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1480            if len(TextList) == 1:
1481                G2frame.ErrorDialog('Nothing to copy controls to','There must be more than one "IMG" pattern')
1482                return
1483            dlg = G2frame.CopyDialog(G2frame,'Copy stress/strain controls','Copy controls from '+Source+' to:',TextList)
1484            try:
1485                if dlg.ShowModal() == wx.ID_OK:
1486                    result = dlg.GetData()
1487                    if result[0][0]:
1488                        result = TextList[1:]
1489                        for item in result: item[0] = True
1490                    for i,item in enumerate(result):
1491                        ifcopy,name,id,load = item
1492                        if ifcopy:
1493                            Data = copy.deepcopy(data)
1494                            Data['Sample load'] = load
1495                            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,id, 'Stress/Strain'),Data)
1496            finally:
1497                dlg.Destroy()
1498
1499    def OnLoadStrSta(event):
1500        dlg = wx.FileDialog(G2frame, 'Choose stress/strain file', '.', '', 
1501            'image control files (*.strsta)|*.strsta',wx.OPEN|wx.CHANGE_DIR)
1502        try:
1503            if dlg.ShowModal() == wx.ID_OK:
1504                filename = dlg.GetPath()
1505                File = open(filename,'r')
1506                S = File.read()
1507                data = eval(S)
1508                Controls = G2frame.PatternTree.GetItemPyData(
1509                    G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
1510                G2img.FitStrSta(G2frame.ImageZ,data,Controls)
1511                UpdateStressStrain(G2frame,data)
1512                G2plt.PlotExposedImage(G2frame,event=event)
1513                G2plt.PlotStrain(G2frame,data,newPlot=True)
1514                File.close()
1515        finally:
1516            dlg.Destroy()
1517
1518    def OnSaveStrSta(event):
1519        dlg = wx.FileDialog(G2frame, 'Choose stress/strain file', '.', '', 
1520            'image control files (*.strsta)|*.strsta',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1521        try:
1522            if dlg.ShowModal() == wx.ID_OK:
1523                filename = dlg.GetPath()
1524                File = open(filename,'w')
1525                save = {}
1526                keys = ['Type','Sample phi','Sample z','Sample load']
1527                keys2 = ['Dset','Dcalc','pixLimit','cutoff','Emat']
1528                File.write('{\n\t')
1529                for key in keys:
1530                    if key in 'Type':
1531                        File.write("'"+key+"':'"+data[key]+"',")
1532                    else:
1533                        File.write("'"+key+"':"+str(data[key])+',')
1534                File.write('\n\t'+"'d-zero':[\n")
1535                for data2 in data['d-zero']:
1536                    File.write('\t\t{')
1537                    for key in keys2:
1538                        File.write("'"+key+"':"+str(data2[key])+',')
1539                    File.write("'ImxyObs':[[],[]],'ImtaObs':[[],[]],'ImtaCalc':[[],[]]},\n")
1540                File.write('\t]\n}')
1541                File.close()
1542        finally:
1543            dlg.Destroy()
1544           
1545    def OnStrStaSample(event):
1546        filename = ''
1547        dlg = wx.FileDialog(G2frame, 'Choose multihistogram metadata text file', '.', '', 
1548            'metadata file (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
1549        try:
1550            if dlg.ShowModal() == wx.ID_OK:
1551                filename = dlg.GetPath()
1552                File = open(filename,'r')
1553                S = File.readline()
1554                newItems = []
1555                itemNames = []
1556                Comments = []
1557                while S:
1558                    if S[0] == '#':
1559                        Comments.append(S)
1560                        S = File.readline()
1561                        continue
1562                    S = S.replace(',',' ').replace('\t',' ')
1563                    Stuff = S[:-1].split()
1564                    itemNames.append(Stuff[0])
1565                    newItems.append(Stuff[1:])
1566                    S = File.readline()               
1567                File.close()
1568        finally:
1569            dlg.Destroy()
1570        if not filename:
1571            G2frame.ErrorDialog('Nothing to do','No file selected')
1572            return
1573        dataDict = dict(zip(itemNames,newItems))
1574        ifany = False
1575        Names = [' ','Sample phi','Sample z','Sample load']
1576        dlg = G2G.G2ColumnIDDialog( G2frame,' Choose multihistogram metadata columns:',
1577            'Select columns',Comments,Names,np.array(newItems).T)
1578        try:
1579            if dlg.ShowModal() == wx.ID_OK:
1580                colNames,newData = dlg.GetSelection()
1581                dataDict = dict(zip(itemNames,newData.T))
1582                for item in colNames:
1583                    if item != ' ':
1584                        ifany = True
1585        finally:
1586            dlg.Destroy()
1587        if not ifany:
1588            G2frame.ErrorDialog('Nothing to do','No columns identified')
1589            return
1590        histList = []
1591        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
1592        while item:
1593            name = G2frame.PatternTree.GetItemText(item)
1594            if name.startswith('IMG'):
1595                histList.append(name)
1596            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1597        colIds = {}
1598        for i,name in enumerate(colNames):
1599            if name != ' ':
1600                colIds[name] = i
1601        for hist in histList:
1602            name = hist.split()[1]  #this is file name
1603            if name in dataDict:
1604                newItems = {}
1605                for item in colIds:
1606                    newItems[item] = float(dataDict[name][colIds[item]])
1607                Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
1608                stsrData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Stress/Strain'))
1609                stsrData.update(newItems)       
1610        UpdateStressStrain(G2frame,data)       
1611   
1612    def OnFitStrSta(event):
1613        Controls = G2frame.PatternTree.GetItemPyData(
1614            G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
1615        G2img.FitStrSta(G2frame.ImageZ,data,Controls)
1616        print 'Strain fitting finished'
1617        UpdateStressStrain(G2frame,data)
1618        G2plt.PlotExposedImage(G2frame,event=event)
1619        G2plt.PlotStrain(G2frame,data,newPlot=True)
1620       
1621    def OnFitAllStrSta(event):
1622        TextList = [[False,'All IMG',0]]
1623#        Names = []
1624        if G2frame.PatternTree.GetCount():
1625            choices = G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
1626            if len(choices) == 1:
1627                G2frame.ErrorDialog('Nothing to fit','There must some "IMG" patterns')
1628                return
1629            sel = []
1630            dlg = G2G.G2MultiChoiceDialog(G2frame,'Stress/Strain fitting','Select images to fit:',choices)
1631            dlg.SetSelections(sel)
1632            names = []
1633            if dlg.ShowModal() == wx.ID_OK:
1634                for sel in dlg.GetSelections():
1635                    names.append(choices[sel])
1636            dlg.Destroy()
1637            SeqResult = {}
1638            dlg = wx.ProgressDialog('Sequential IMG Strain fit','Data set name = '+names[0],len(names), 
1639                style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)         
1640            wx.BeginBusyCursor()
1641            goodnames = []
1642            try:
1643                for i,name in enumerate(names):
1644                    print ' Sequential strain fit for ',name
1645                    GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
1646                    if not GoOn:
1647                        break
1648                    Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
1649                    Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Image Controls'))
1650                    StaCtrls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Stress/Strain'))
1651                    if not len(StaCtrls['d-zero']):
1652                        continue
1653                    goodnames.append(name)
1654                    id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, name)
1655                    Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Id)
1656                    image = G2IO.GetImageData(G2frame,imagefile,True,ImageTag=imagetag)
1657                    dark = Controls['dark image']
1658                    if dark[0]:
1659                        id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root,dark[0])
1660                        Npix,darkfile,imagetag = G2frame.PatternTree.GetImageLoc(id)
1661                        darkImg = G2IO.GetImageData(G2frame,darkfile,True,ImageTag=imagetag)
1662                        image += dark[1]*darkImg
1663                    G2img.FitStrSta(image,StaCtrls,Controls)
1664                    G2plt.PlotStrain(G2frame,StaCtrls,newPlot=True)
1665                    parmDict = {'Sample load':StaCtrls['Sample load'],}
1666                    varyNames = ['e11','e12','e22']
1667                    sig = []
1668                    varyList = []
1669                    variables = []
1670                    for i,item in enumerate(StaCtrls['d-zero']):
1671                        variables += item['Emat']
1672                        sig += item['Esig']
1673                        varylist = ['%d%s%s'%(i,';',Name) for Name in varyNames]
1674                        varyList += varylist
1675                        parmDict.update(dict(zip(varylist,item['Emat'])))
1676                        parmDict['%d:Dcalc'%(i)] = item['Dcalc']
1677                    SeqResult[name] = {'variables':variables,'varyList':varyList,'sig':sig,'Rvals':[],
1678                        'covMatrix':np.eye(len(variables)),'title':name,'parmDict':parmDict}
1679                else:
1680                    SeqResult['histNames'] = goodnames
1681                    dlg.Destroy()
1682                    print ' ***** Sequential strain refinement successful *****'
1683            finally:
1684                wx.EndBusyCursor()   
1685            Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
1686            if Id:
1687                G2frame.PatternTree.SetItemPyData(Id,SeqResult)
1688            else:
1689                Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
1690                G2frame.PatternTree.SetItemPyData(Id,SeqResult)
1691            G2frame.PatternTree.SelectItem(Id)
1692            print 'All images fitted'
1693       
1694    def SamSizer():
1695       
1696        def OnStrainType(event):
1697            data['Type'] = strType.GetValue()
1698       
1699        def OnSamPhi(event):
1700            try:
1701                value = float(samPhi.GetValue())
1702            except ValueError:
1703                value = data['Sample phi']
1704            data['Sample phi'] = value
1705            samPhi.SetValue("%.3f" % (data['Sample phi']))
1706               
1707        def OnSamZ(event):
1708            try:
1709                value = float(samZ.GetValue())
1710            except ValueError:
1711                value = data['Sample z']
1712            data['Sample z'] = value
1713            samZ.SetValue("%.3f" % (data['Sample z']))
1714               
1715        def OnSamLoad(event):
1716            try:
1717                value = float(samLoad.GetValue())
1718            except ValueError:
1719                value = data['Sample load']
1720            data['Sample load'] = value
1721            samLoad.SetValue("%.3f" % (data['Sample load']))
1722               
1723        samSizer = wx.BoxSizer(wx.HORIZONTAL)
1724        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Strain type: '),0,WACV)
1725        strType = wx.ComboBox(G2frame.dataDisplay,value=data['Type'],choices=['True','Conventional'],
1726            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1727        strType.SetValue(data['Type'])
1728        strType.Bind(wx.EVT_COMBOBOX, OnStrainType)
1729        samSizer.Add(strType,0,WACV)
1730       
1731        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Sample phi: '),0,WACV)
1732        samPhi = wx.TextCtrl(G2frame.dataDisplay,-1,value=("%.3f" % (data['Sample phi'])),
1733            style=wx.TE_PROCESS_ENTER)
1734        samSizer.Add(samPhi,0,WACV)
1735        samPhi.Bind(wx.EVT_TEXT_ENTER,OnSamPhi)
1736        samPhi.Bind(wx.EVT_KILL_FOCUS,OnSamPhi)
1737        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Sample delta-z(mm): '),0,WACV)
1738        samZ = wx.TextCtrl(G2frame.dataDisplay,-1,value=("%.3f" % (data['Sample z'])),
1739            style=wx.TE_PROCESS_ENTER)
1740        samSizer.Add(samZ,0,WACV)
1741        samZ.Bind(wx.EVT_TEXT_ENTER,OnSamZ)
1742        samZ.Bind(wx.EVT_KILL_FOCUS,OnSamZ)
1743        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Sample load(MPa): '),0,WACV)
1744        samLoad = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'Sample load',
1745                nDig=[8,3],typeHint=float,)
1746        samSizer.Add(samLoad,0,WACV)
1747
1748        return samSizer
1749       
1750    def DzeroSizer():
1751   
1752        def OnDzero(event):
1753            Obj = event.GetEventObject()
1754            try:
1755                value = min(20.0,max(0.25,float(Obj.GetValue())))
1756            except ValueError:
1757                value = 1.0
1758            Obj.SetValue("%.5f"%(value))
1759            data['d-zero'][Indx[Obj.GetId()]]['Dset'] = value
1760            data['d-zero'] = G2mth.sortArray(data['d-zero'],'Dset',reverse=True)
1761            Ring,R = G2img.MakeStrStaRing(data['d-zero'][Indx[Obj.GetId()]],G2frame.ImageZ,Controls)
1762            if len(Ring):
1763                data['d-zero'][Indx[Obj.GetId()]].update(R)
1764            else:
1765                G2frame.ErrorDialog('Strain peak selection','WARNING - No points found for this ring selection')
1766               
1767            UpdateStressStrain(G2frame,data)
1768            G2plt.PlotExposedImage(G2frame,event=event,newPlot=False)
1769            G2plt.PlotStrain(G2frame,data,newPlot=True)
1770           
1771        def OnDeleteDzero(event):
1772            Obj = event.GetEventObject()
1773            del(data['d-zero'][delIndx.index(Obj)])
1774            UpdateStressStrain(G2frame,data)
1775            G2plt.PlotExposedImage(G2frame,event=event,newPlot=True)
1776            G2plt.PlotStrain(G2frame,data,newPlot=True)
1777       
1778        def OnCutOff(event):
1779            Obj = event.GetEventObject()
1780            try:
1781                value = min(10.0,max(0.5,float(Obj.GetValue())))
1782            except ValueError:
1783                value = 1.0
1784            Obj.SetValue("%.1f"%(value))
1785            data['d-zero'][Indx[Obj.GetId()]]['cutoff'] = value
1786            Ring,R = G2img.MakeStrStaRing(data['d-zero'][Indx[Obj.GetId()]],G2frame.ImageZ,Controls)
1787            G2plt.PlotExposedImage(G2frame,event=event)
1788            G2plt.PlotStrain(G2frame,data,newPlot=True)
1789       
1790        def OnPixLimit(event):
1791            Obj = event.GetEventObject()
1792            data['d-zero'][Indx[Obj.GetId()]]['pixLimit'] = int(Obj.GetValue())
1793            Ring,R = G2img.MakeStrStaRing(data['d-zero'][Indx[Obj.GetId()]],G2frame.ImageZ,Controls)
1794            G2plt.PlotExposedImage(G2frame,event=event)
1795            G2plt.PlotStrain(G2frame,data,newPlot=True)
1796           
1797        Indx = {}
1798        delIndx = []   
1799        dzeroSizer = wx.FlexGridSizer(0,8,5,5)
1800        for id,dzero in enumerate(data['d-zero']):
1801            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=(' d-zero #%d: '%(id))),0,WACV)
1802            dZero = wx.TextCtrl(G2frame.dataDisplay,-1,value=('%.5f'%(dzero['Dset'])),
1803                style=wx.TE_PROCESS_ENTER)
1804            dzeroSizer.Add(dZero,0,WACV)
1805            dZero.Bind(wx.EVT_TEXT_ENTER,OnDzero)
1806            dZero.Bind(wx.EVT_KILL_FOCUS,OnDzero)
1807            Indx[dZero.GetId()] = id
1808            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=(' d-zero ave: %.5f'%(dzero['Dcalc']))),0,WACV)
1809               
1810            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min ring I/Ib '),0,WACV)
1811            cutOff = wx.TextCtrl(parent=G2frame.dataDisplay,value=("%.1f" % (dzero['cutoff'])),
1812                style=wx.TE_PROCESS_ENTER)
1813            cutOff.Bind(wx.EVT_TEXT_ENTER,OnCutOff)
1814            cutOff.Bind(wx.EVT_KILL_FOCUS,OnCutOff)
1815            Indx[cutOff.GetId()] = id
1816            dzeroSizer.Add(cutOff,0,WACV)
1817       
1818            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Pixel search range '),0,WACV)
1819            pixLimit = wx.ComboBox(parent=G2frame.dataDisplay,value=str(dzero['pixLimit']),choices=['1','2','5','10','15','20'],
1820                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1821            pixLimit.Bind(wx.EVT_COMBOBOX, OnPixLimit)
1822            Indx[pixLimit.GetId()] = id
1823            dzeroSizer.Add(pixLimit,0,WACV)               
1824               
1825            dzeroDelete = wx.CheckBox(parent=G2frame.dataDisplay,label='delete?')
1826            dzeroDelete.Bind(wx.EVT_CHECKBOX,OnDeleteDzero)
1827            delIndx.append(dzeroDelete)
1828            dzeroSizer.Add(dzeroDelete,0,WACV)
1829           
1830            dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=(' Strain tensor:')),WACV)
1831            names = ['e11','e12','e22']
1832            for i in range(3):
1833                dzeroSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=names[i]),0,WACV)
1834                tensorElem = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(dzero['Emat'][i]),style=wx.TE_READONLY)
1835                tensorElem.SetBackgroundColour(VERY_LIGHT_GREY)
1836                dzeroSizer.Add(tensorElem,0,WACV)
1837            dzeroSizer.Add((5,5),0)             
1838        return dzeroSizer
1839       
1840# patches
1841    if 'Sample load' not in data:
1842        data['Sample load'] = 0.0
1843# end patches
1844   
1845    if G2frame.dataDisplay:
1846        G2frame.dataDisplay.Destroy()
1847    Controls = G2frame.PatternTree.GetItemPyData(
1848        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))       
1849    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.StrStaMenu)
1850    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAppendDzero, id=G2gd.wxID_APPENDDZERO)
1851    G2frame.dataFrame.Bind(wx.EVT_MENU, OnUpdateDzero, id=G2gd.wxID_UPDATEDZERO)
1852    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitStrSta, id=G2gd.wxID_STRSTAFIT)
1853    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitAllStrSta, id=G2gd.wxID_STRSTAALLFIT)
1854    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyStrSta, id=G2gd.wxID_STRSTACOPY)
1855    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadStrSta, id=G2gd.wxID_STRSTALOAD)
1856    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveStrSta, id=G2gd.wxID_STRSTASAVE)
1857    G2frame.dataFrame.Bind(wx.EVT_MENU, OnStrStaSample, id=G2gd.wxID_STRSTSAMPLE)       
1858    if not G2frame.dataFrame.GetStatusBar():
1859        Status = G2frame.dataFrame.CreateStatusBar()
1860    if G2frame.StrainKey == 'a':    #probably doesn't happen
1861        G2frame.dataFrame.GetStatusBar().SetStatusText('Add strain ring active - LB pick d-zero value')
1862    else:
1863        G2frame.dataFrame.GetStatusBar().SetStatusText("To add strain data: On 2D Powder Image, key a:add ring")
1864       
1865    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
1866    mainSizer = wx.BoxSizer(wx.VERTICAL)
1867    mainSizer.Add((5,10),0)
1868    mainSizer.Add(SamSizer())
1869    mainSizer.Add((5,10),0)
1870    mainSizer.Add(DzeroSizer())
1871   
1872    mainSizer.Layout()   
1873    G2frame.dataDisplay.SetSizer(mainSizer)
1874    G2frame.dataDisplay.SetAutoLayout(1)
1875    G2frame.dataDisplay.SetupScrolling()
1876    Size = mainSizer.Fit(G2frame.dataFrame)
1877    Size[0] += 25
1878    G2frame.dataDisplay.SetSize(Size)
1879    G2frame.dataFrame.setSizePosLeft(Size)   
1880
1881###########################################################################
1882# Autointegration follows
1883def ReadMask(filename):
1884    'Read a mask (.immask) file'
1885    File = open(filename,'r')
1886    save = {}
1887    S = File.readline()
1888    while S:
1889        if S[0] == '#':
1890            S = File.readline()
1891            continue
1892        [key,val] = S[:-1].split(':')
1893        if key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']:
1894            save[key] = eval(val)
1895        S = File.readline()
1896    File.close()
1897    CleanupMasks(save)
1898    return save
1899
1900def ReadControls(filename):
1901    'read an image controls (.imctrl) file'
1902    cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type',
1903            'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth',
1904            'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
1905            'PolaVal','SampleAbs','dark image','background image']
1906    File = open(filename,'r')
1907    save = {}
1908    S = File.readline()
1909    while S:
1910        if S[0] == '#':
1911            S = File.readline()
1912            continue
1913        [key,val] = S[:-1].split(':')
1914        if key in ['type','calibrant','binType','SampleShape',]:    #strings
1915            save[key] = val
1916        elif key in ['rotation']:
1917            save[key] = float(val)
1918        elif key in ['center',]:
1919            if ',' in val:
1920                save[key] = eval(val)
1921            else:
1922                vals = val.strip('[] ').split()
1923                save[key] = [float(vals[0]),float(vals[1])] 
1924        elif key in cntlList:
1925            save[key] = eval(val)
1926        S = File.readline()
1927    File.close()
1928    return save
1929
1930def Read_imctrl(imctrl_file):
1931    '''Read an image control file and record control parms into a dict, with some simple
1932    type conversions
1933    '''
1934    file_opt = options = {}
1935    save = {'filename':imctrl_file}
1936    immask_file = os.path.splitext(imctrl_file)[0]+'.immask'
1937    if os.path.exists(immask_file):
1938        save['maskfile'] = immask_file
1939    else:
1940        save['maskfile'] = '(none)'
1941    cntlList = ['wavelength','distance','tilt','invert_x','invert_y','type',
1942                        'fullIntegrate','outChannels','outAzimuths','LRazimuth','IOtth','azmthOff','DetDepth',
1943                        'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
1944                        'PolaVal','SampleAbs','dark image','background image']
1945    File = open(imctrl_file,'r')
1946    fullIntegrate = False
1947    try:
1948        S = File.readline()
1949        while S:
1950            if S[0] == '#':
1951                S = File.readline()
1952                continue
1953            [key,val] = S[:-1].split(':')
1954            if key in ['type','calibrant','binType','SampleShape',]:    #strings
1955                save[key] = val
1956            elif key == 'rotation':
1957                save[key] = float(val)
1958            elif key == 'fullIntegrate':
1959                fullIntegrate = eval(val)
1960            elif key == 'LRazimuth':
1961                save['LRazimuth_min'],save['LRazimuth_max'] = eval(val)[0:2]
1962            elif key == 'IOtth':
1963                save['IOtth_min'],save['IOtth_max'] = eval(val)[0:2]
1964            elif key == 'center':
1965                if ',' in val:
1966                    vals = eval(val)
1967                else:
1968                    vals = val.strip('[] ').split()
1969                    vals = [float(vals[0]),float(vals[1])] 
1970                save['center_x'],save['center_y'] = vals[0:2]
1971            elif key in cntlList:
1972                save[key] = eval(val)
1973            S = File.readline()
1974    finally:
1975        File.close()
1976        if fullIntegrate: save['LRazimuth_min'],save['LRazimuth_max'] = 0,0
1977    return save
1978   
1979class AutoIntFrame(wx.Frame):
1980    '''Creates a wx.Frame window for the Image AutoIntegration.
1981    The intent is that this will be used as a non-modal dialog window.
1982   
1983    Implements a Start button that morphs into a pause and resume button.
1984    This button starts a processing loop that is repeated every
1985    :meth:`PollTime` seconds.
1986
1987    :param wx.Frame G2frame: main GSAS-II frame
1988    :param float PollTime: frequency in seconds to repeat calling the
1989      processing loop. (Default is 3.0 seconds.)
1990    '''
1991
1992    def __init__(self,G2frame,PollTime=60.0):
1993        def OnStart(event):
1994            '''Called when the start button is pressed. Changes button label
1995            to Pause. When Pause is pressed the label changes to Resume.
1996            When either Start or Resume is pressed, the processing loop
1997            is started. When Pause is pressed, the loop is stopped.
1998            '''
1999            # check inputs for errors before starting
2000            #err = ''
2001            #if not any([self.params[fmt] for fmt in self.fmtlist]):
2002            #    err += '\nPlease select at least one output format\n'
2003            #if err:
2004            #    G2G.G2MessageBox(self,err)
2005            #    return
2006            self.Pause = False
2007            # change button label
2008            if btnstart.GetLabel() != 'Pause':
2009                btnstart.SetLabel('Pause')
2010                if self.timer.IsRunning(): self.timer.Stop()
2011                self.PreventReEntryTimer = False
2012                self.StartLoop()
2013                self.OnTimerLoop(None) # run once immediately and again after delay
2014                self.timer.Start(int(1000*PollTime),oneShot=False)
2015                self.Status.SetStatusText('Press Pause to delay integration or Reset to prepare to reintegrate all images')
2016            else:
2017                btnstart.SetLabel('Resume')
2018                if self.timer.IsRunning(): self.timer.Stop()
2019                print('\nPausing autointegration\n')
2020                self.Status.SetStatusText('Press Resume to continue integration or Reset to prepare to reintegrate all images')
2021                self.Pause = True
2022
2023        def OnReset(event):
2024            '''Called when Reset button is pressed. This stops the
2025            processing loop and resets the list of integrated files so
2026            all images can be reintegrated.
2027            '''
2028            btnstart.SetLabel('Restart')
2029            self.Status.SetStatusText('Press Restart to reload and re-integrate images matching filter')
2030            if self.timer.IsRunning(): self.timer.Stop()
2031            self.Reset = True
2032            self.Pause = True
2033           
2034        def OnQuit(event):
2035            '''Stop the processing loop and close the Frame
2036            '''
2037            if self.timer.IsRunning(): self.timer.Stop() # make sure we stop first
2038            wx.CallAfter(self.Destroy)
2039           
2040        def OnBrowse(event):
2041            '''Responds when the Browse button is pressed to load a file.
2042            The routine determines which button was pressed and gets the
2043            appropriate file type and loads it into the appropriate place
2044            in the dict.
2045            '''
2046            if btn3 == event.GetEventObject():
2047                dlg = wx.DirDialog(
2048                    self, 'Select directory for output files',
2049                    self.params['outdir'],wx.DD_DEFAULT_STYLE)
2050                dlg.CenterOnParent()
2051                try:
2052                    if dlg.ShowModal() == wx.ID_OK:
2053                        self.params['outdir'] = dlg.GetPath()
2054                        fInp3.SetValue(self.params['outdir'])
2055                finally:
2056                    dlg.Destroy()
2057                return
2058               
2059        def OnRadioSelect(event):
2060            '''Respond to a radiobutton selection and when in table
2061            mode, get distance-dependent parameters from user.
2062            '''
2063            self.Evaluator = None
2064            if r2.GetValue():
2065                try:
2066                    dlg = IntegParmTable(self.G2frame) # create the dialog
2067                    dlg.CenterOnParent()
2068                    if dlg.ShowModal() == wx.ID_OK:
2069                        self.ImgTblParms = dlg.parms
2070                        self.IMfileList = dlg.IMfileList
2071                        self.Evaluator = DefineEvaluator(dlg)
2072                        self.params['Mode'] = 'table'
2073                        r2E.Enable(True)
2074                    else:
2075                        self.useActive.SetValue(True)
2076                finally:
2077                    dlg.Destroy()
2078            if self.useActive.GetValue():
2079                self.params['Mode'] = 'active'
2080                self.imageBase = G2frame.Image
2081                self.useActive.SetLabel("Active Image: "+
2082                        G2frame.PatternTree.GetItemText(self.imageBase))
2083                r2E.Enable(False)
2084
2085        def OnEditTable(event):
2086            '''Called to edit the distance-dependent parameter look-up table.
2087            Should be called only when table is defined and active.
2088            '''
2089            try:
2090                dlg = IntegParmTable(self.G2frame,self.ImgTblParms,self.IMfileList)
2091                dlg.CenterOnParent()
2092                if dlg.ShowModal() == wx.ID_OK:
2093                    self.ImgTblParms = dlg.parms
2094                    self.IMfileList = dlg.IMfileList
2095                    self.Evaluator = DefineEvaluator(dlg)
2096                    self.params['Mode'] = 'table'
2097                    r2E.Enable(True)
2098                else:
2099                    self.useActive.SetValue(True)
2100                    self.params['Mode'] = 'active'
2101                    self.imageBase = G2frame.Image
2102                    self.useActive.SetLabel("Active Image: "+
2103                            G2frame.PatternTree.GetItemText(self.imageBase))
2104                    r2E.Enable(False)
2105            finally:
2106                dlg.Destroy()
2107
2108        ##################################################
2109        # beginning of __init__ processing
2110        ##################################################
2111        self.G2frame = G2frame
2112        self.ImgTblParms = None
2113        self.IMfileList = None
2114        self.Evaluator = None
2115        self.params = {}
2116        self.Reset = False
2117        self.Pause = False
2118        self.PreventReEntryShowMatch = False
2119        self.PreventReEntryTimer = False
2120        self.params['IMGfile'] = ''
2121        self.params['MaskFile'] = ''
2122        self.params['IgnoreMask'] = True
2123        self.fmtlist = G2IO.ExportPowderList(G2frame)
2124        self.timer = wx.Timer()
2125        self.timer.Bind(wx.EVT_TIMER,self.OnTimerLoop)
2126        self.imageBase = G2frame.Image
2127
2128        controlsId = G2frame.PatternTree.GetSelection()
2129        size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(self.imageBase)       
2130        self.imagedir,fileroot = os.path.split(imagefile)
2131        self.params['filter'] = '*'+os.path.splitext(fileroot)[1]
2132        self.params['outdir'] = os.path.abspath(self.imagedir)
2133        wx.Frame.__init__(self, G2frame, title='Automatic Integration',
2134                          style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
2135        self.Status = self.CreateStatusBar()
2136        self.Status.SetStatusText('Press Start to load and integrate images matching filter')
2137        mnpnl = wx.Panel(self)
2138        mnsizer = wx.BoxSizer(wx.VERTICAL)
2139        # box for integration controls & masks input
2140        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Integration Control")
2141        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
2142        lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Use integration parameters from:'))
2143        self.useActive = wx.RadioButton(mnpnl, wx.ID_ANY, 
2144                            style = wx.RB_GROUP)
2145        self.useActive.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
2146        self.useActive.SetLabel("Active Image: "+
2147                                G2frame.PatternTree.GetItemText(self.imageBase))
2148        lblsizr.Add(self.useActive,1,wx.EXPAND,1)
2149        self.useActive.SetValue(True)
2150        minisizer = wx.BoxSizer(wx.HORIZONTAL)
2151        r2 = wx.RadioButton(mnpnl, wx.ID_ANY, "From distance look-up table")
2152        minisizer.Add(r2,0,wx.ALIGN_LEFT|wx.ALL,1)
2153        r2.Bind(wx.EVT_RADIOBUTTON, OnRadioSelect)
2154        r2E = wx.Button(mnpnl,  wx.ID_ANY, "Edit table")
2155        minisizer.Add(r2E,0,wx.ALIGN_LEFT,10)
2156        r2E.Enable(False)
2157        r2E.Bind(wx.EVT_BUTTON, OnEditTable)
2158        # bind button and deactivate be default
2159        lblsizr.Add(minisizer)
2160        mnsizer.Add(lblsizr,1,wx.EXPAND,1)
2161
2162        # file filter stuff
2163        sizer = wx.BoxSizer(wx.HORIZONTAL)
2164        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Image filter'))
2165        flterInp = G2G.ValidatedTxtCtrl(mnpnl,self.params,'filter',
2166                                        OnLeave=self.ShowMatchingFiles)
2167        sizer.Add(flterInp)
2168        mnsizer.Add(sizer,0,wx.ALIGN_RIGHT,1)
2169        self.ListBox = wx.ListBox(mnpnl,size=(-1,100))
2170        mnsizer.Add(self.ListBox,0,wx.EXPAND,1)
2171        self.ShowMatchingFiles(self.params['filter'])
2172        # box for output selections
2173        lbl = wx.StaticBox(mnpnl, wx.ID_ANY, "Output settings")
2174        lblsizr = wx.StaticBoxSizer(lbl, wx.VERTICAL)
2175        sizer = wx.BoxSizer(wx.HORIZONTAL)
2176        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Write to: '))
2177        fInp3 = G2G.ValidatedTxtCtrl(mnpnl,self.params,'outdir',
2178                                       notBlank=False,size=(300,-1))
2179        sizer.Add(fInp3)
2180        btn3 = wx.Button(mnpnl,  wx.ID_ANY, "Browse")
2181        btn3.Bind(wx.EVT_BUTTON, OnBrowse)
2182        sizer.Add(btn3)
2183        lblsizr.Add(sizer)
2184        #lblsizr.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
2185        sizer = wx.BoxSizer(wx.HORIZONTAL)
2186        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Select format(s): '))
2187        for dfmt in self.fmtlist:
2188            fmt = dfmt[1:]
2189            self.params[fmt] = False
2190            btn = G2G.G2CheckBox(mnpnl,dfmt,self.params,fmt)
2191            sizer.Add(btn)
2192        lblsizr.Add(sizer)
2193        sizer = wx.BoxSizer(wx.HORIZONTAL)
2194        sizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'Separate dir for each format: '))
2195        self.params['SeparateDir'] = False
2196        sizer.Add(G2G.G2CheckBox(mnpnl,'',self.params,'SeparateDir'))
2197        lblsizr.Add(sizer)
2198        mnsizer.Add(lblsizr,0,wx.ALIGN_CENTER,1)
2199
2200        # buttons on bottom
2201        mnsizer.Add(wx.StaticText(mnpnl, wx.ID_ANY,'AutoIntegration controls'),0,wx.TOP,5)
2202        sizer = wx.BoxSizer(wx.HORIZONTAL)
2203        sizer.Add((20,-1))
2204        btnstart = wx.Button(mnpnl,  wx.ID_ANY, "Start")
2205        btnstart.Bind(wx.EVT_BUTTON, OnStart)
2206        sizer.Add(btnstart)
2207        btnstop = wx.Button(mnpnl,  wx.ID_ANY, "Reset")
2208        btnstop.Bind(wx.EVT_BUTTON, OnReset)
2209        sizer.Add(btnstop)
2210        sizer.Add((20,-1),wx.EXPAND,1)
2211        btnquit = wx.Button(mnpnl,  wx.ID_ANY, "Close")
2212        btnquit.Bind(wx.EVT_BUTTON, OnQuit)
2213        sizer.Add(btnquit)
2214        sizer.Add((20,-1))
2215        mnsizer.Add(sizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP,5)
2216       
2217        # finish up window
2218        mnpnl.SetSizer(mnsizer)
2219        OnRadioSelect(None) # disable widgets
2220        mnsizer.Fit(self)
2221        self.CenterOnParent()
2222        self.Show()
2223
2224    def ShowMatchingFiles(self,value,invalid=False,**kwargs):
2225        G2frame = self.G2frame
2226        if invalid: return
2227        msg = ''
2228        if self.PreventReEntryShowMatch: return
2229        self.PreventReEntryShowMatch = True
2230        imageFileList = []
2231        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2232            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2233            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2234            if imagefile not in imageFileList: imageFileList.append(imagefile)
2235            if img not in G2frame.IntegratedList:
2236                if msg: msg += '\n'
2237                msg += '  ' + img
2238        if msg: msg = "Loaded images to integrate:\n" + msg + "\n"
2239        msg1 = ""
2240        try:
2241            imageList = sorted(
2242                glob.glob(os.path.join(self.imagedir,value)))
2243            if not imageList:
2244                msg1 = 'Warning: No files match search string '+os.path.join(self.imagedir,value)
2245            else:
2246                for fil in imageList:
2247                    if fil not in imageFileList: msg1 += '\n  '+fil
2248                if msg1:
2249                    msg += 'Files to integrate from '+os.path.join(self.imagedir,value)+msg1
2250                else:
2251                    msg += 'All files integrated'
2252        except IndexError:
2253            msg += 'Error searching for files named '+os.path.join(self.imagedir,value)
2254        self.ListBox.Clear()
2255        self.ListBox.AppendItems(msg.split('\n'))
2256        self.PreventReEntryShowMatch = False
2257        return
2258       
2259    def IntegrateImage(self,img):
2260        '''Integrates a single image'''
2261        G2frame = self.G2frame
2262        imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2263        G2frame.Image = imgId
2264        G2frame.PickId = G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls')
2265        # do integration
2266        size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2267        G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,True,imagetag)
2268        masks = G2frame.PatternTree.GetItemPyData(
2269                G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2270        data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
2271        # simulate a Image Controls press, since that is where the
2272        # integration is hidden
2273        UpdateImageControls(G2frame,data,masks,IntegrateOnly=True)
2274        G2frame.IntegratedList.append(img) # note this as integrated
2275        # split name and control number
2276        s = re.split(r'(\d+)\Z',os.path.split(os.path.splitext(imagefile)[0])[1])
2277        namepre = s[0]
2278        if len(s) > 1:
2279            namenum = s[1]
2280        else:
2281            namenum = ''
2282        for Id in G2frame.IntgOutList: # loop over newly created PDWR entry(ies)
2283            # save the created PWDR tree names so that a reset can delete them
2284            treename = G2frame.PatternTree.GetItemText(Id)
2285            G2frame.AutointPWDRnames.append(treename)
2286            # write out the images in the selected formats
2287            Sdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
2288            # determine the name for the current file
2289            fileroot = namepre
2290            if len(G2frame.IntgOutList) > 1:
2291                fileroot += "_AZM"
2292                if 'Azimuth' in Sdata:
2293                    fileroot += str(int(10*Sdata['Azimuth']))
2294                fileroot += "_" 
2295            fileroot += namenum
2296            # loop over selected formats
2297            for dfmt in self.fmtlist:
2298                if not self.params[dfmt[1:]]: continue
2299                if self.params['SeparateDir']:
2300                    subdir = dfmt[1:]
2301                else:
2302                    subdir = ''
2303                fil = os.path.join(self.params['outdir'],subdir,fileroot)
2304                print('writing file '+fil+dfmt)
2305                G2IO.ExportPowder(G2frame,treename,fil,dfmt)
2306               
2307    def ResetFromTable(self,dist):
2308        '''Sets integration parameters based on values from
2309        the lookup table
2310        '''
2311        #dist = self.controlsDict['distance']
2312        interpDict,imgctrl,immask = self.Evaluator(dist) # interpolated calibration values
2313        #if GSASIIpath.GetConfigValue('debug'):
2314        if GSASIIpath.GetConfigValue('debug'):
2315            print 'interpolated values: ',interpDict
2316        self.ImageControls = ReadControls(imgctrl)
2317        self.ImageControls.update(interpDict)
2318        self.ImageControls['showLines'] = True
2319        self.ImageControls['ring'] = []
2320        self.ImageControls['rings'] = []
2321        self.ImageControls['ellipses'] = []
2322        self.ImageControls['setDefault'] = False
2323        for i in 'range','size','GonioAngles':
2324            if i in self.ImageControls:
2325                del self.ImageControls[i]
2326        # load copy of Image Masks
2327        if immask:
2328            self.ImageMasks = ReadMask(immask)
2329            del self.Thresholds['Thresholds']
2330        else:
2331            self.ImageMasks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[]}
2332       
2333    def StartLoop(self):
2334        '''Save current Image params for use in future integrations
2335        also label the window so users understand what is being used
2336        '''
2337        print '\nStarting new autointegration\n'
2338        G2frame = self.G2frame
2339        # show current IMG base
2340        if self.params['Mode'] != 'table':
2341            self.useActive.SetLabel("Active Image: "+
2342                                    G2frame.PatternTree.GetItemText(self.imageBase))
2343            # load copy of Image Controls from current image and clean up
2344            # items that should not be copied
2345            self.ImageControls = copy.deepcopy(
2346                G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
2347                    G2frame,self.imageBase, 'Image Controls')))
2348            self.ImageControls['showLines'] = True
2349            self.ImageControls['ring'] = []
2350            self.ImageControls['rings'] = []
2351            self.ImageControls['ellipses'] = []
2352            self.ImageControls['setDefault'] = False
2353            del self.ImageControls['range']
2354            del self.ImageControls['size']
2355            del self.ImageControls['GonioAngles']
2356            # load copy of Image Masks, keep thresholds
2357            self.ImageMasks = copy.deepcopy(
2358                G2frame.PatternTree.GetItemPyData(
2359                    G2gd.GetPatternTreeItemId(G2frame,self.imageBase, 'Masks')))
2360            self.Thresholds = self.ImageMasks['Thresholds'][:]
2361        # make sure all output directories exist
2362        if self.params['SeparateDir']:
2363            for dfmt in self.fmtlist:
2364                if not self.params[dfmt[1:]]: continue
2365                dir = os.path.join(self.params['outdir'],dfmt[1:])
2366                if not os.path.exists(dir): os.makedirs(dir)
2367        else:
2368            if not os.path.exists(self.params['outdir']):
2369                os.makedirs(self.params['outdir'])
2370        if self.Reset: # special things to do after Reset has been pressed
2371            self.G2frame.IntegratedList = []
2372           
2373            if self.params['Mode'] != 'table': # reset controls and masks for all IMG items in tree to master
2374                for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2375                    # update controls from master
2376                    controlsDict = G2frame.PatternTree.GetItemPyData(
2377                        G2gd.GetPatternTreeItemId(G2frame,self.imageBase, 'Image Controls'))
2378                    controlsDict.update(self.ImageControls)
2379                    # update masks from master
2380                    ImageMasks = G2frame.PatternTree.GetItemPyData(
2381                        G2gd.GetPatternTreeItemId(G2frame,self.imageBase, 'Masks'))
2382                    ImageMasks.update(self.ImageMasks)
2383            # delete all PWDR items created after last Start was pressed
2384            idlist = []
2385            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2386            while item:
2387                itemName = G2frame.PatternTree.GetItemText(item)
2388                if itemName in G2frame.AutointPWDRnames:
2389                    idlist.append(item)
2390                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2391            for item in idlist:
2392                G2frame.PatternTree.Delete(item)
2393            wx.Yield()
2394            self.Reset = False
2395        G2frame.AutointPWDRnames = [] # list of created PWDR tree item names
2396
2397    def OnTimerLoop(self,event):
2398        '''A method that is called every :meth:`PollTime` seconds that is
2399        used to check for new files and process them. This is called only
2400        after the "Start" button is pressed (when its label reads "Pause").
2401        '''
2402        G2frame = self.G2frame
2403        try:
2404            self.currImageList = sorted(
2405                glob.glob(os.path.join(self.imagedir,self.params['filter'])))
2406            self.ShowMatchingFiles(self.params['filter'])
2407        except IndexError:
2408            self.currImageList = []
2409            return
2410
2411        if self.PreventReEntryTimer: return
2412        self.PreventReEntryTimer = True
2413        imageFileList = []
2414        # integrate the images that have already been read in, but
2415        # have not yet been processed
2416        for img in G2gd.GetPatternTreeDataNames(G2frame,['IMG ']):
2417            imgId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,img)
2418            size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(imgId)
2419            # Create a list of image files that have been read in
2420            if imagefile not in imageFileList: imageFileList.append(imagefile)
2421            # skip if already integrated
2422            if img in G2frame.IntegratedList: continue
2423            if self.params['Mode'] == 'table': # look up parameter values from table
2424                controlsDict = G2frame.PatternTree.GetItemPyData(
2425                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls'))
2426                ImageMasks = G2frame.PatternTree.GetItemPyData(
2427                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks'))
2428                self.ResetFromTable(controlsDict['distance'])
2429                # update controls from master
2430                controlsDict.update(self.ImageControls)
2431                # update masks from master w/o Thresholds
2432                ImageMasks.update(self.ImageMasks)
2433            self.IntegrateImage(img)
2434            self.G2frame.oldImagefile = '' # mark image as changed; reread as needed
2435            wx.Yield()
2436            self.ShowMatchingFiles(self.params['filter'])
2437            wx.Yield()
2438            if self.Pause: return
2439
2440        # loop over image files matching glob, reading in any new ones
2441        for newImage in self.currImageList:
2442            if newImage in imageFileList: continue # already read?
2443            for imgId in G2IO.ReadImages(G2frame,newImage):
2444                controlsDict = G2frame.PatternTree.GetItemPyData(
2445                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Image Controls'))
2446                ImageMasks = G2frame.PatternTree.GetItemPyData(
2447                    G2gd.GetPatternTreeItemId(G2frame,imgId, 'Masks'))
2448                if self.params['Mode'] == 'table': # look up parameter values from table
2449                    self.ResetFromTable(controlsDict['distance'])
2450                # update controls from master
2451                controlsDict.update(self.ImageControls)
2452                # update masks from master w/o Thresholds
2453                ImageMasks.update(self.ImageMasks)
2454                # now integrate the image
2455                img = G2frame.PatternTree.GetItemText(imgId)
2456                self.IntegrateImage(img)
2457                self.G2frame.oldImagefile = '' # mark image as changed; reread as needed
2458                wx.Yield()
2459                self.ShowMatchingFiles(self.params['filter'])
2460                wx.Yield()
2461            if self.Pause: return
2462       
2463        if GSASIIpath.GetConfigValue('debug'):
2464            import datetime
2465            print ("Timer tick at {:%d %b %Y %H:%M:%S}\n".format(datetime.datetime.now()))
2466        self.PreventReEntryTimer = False
2467
2468def DefineEvaluator(dlg):
2469    '''Creates a function that provides interpolated values for a given distance value
2470    '''
2471    def Evaluator(dist):
2472        '''Interpolate image parameters for a supplied distance value
2473
2474        :param float dist: distance to use for interpolation
2475        :returns: a list with 3 items:
2476
2477          * a dict with parameter values,
2478          * the closest imctrl and
2479          * the closest maskfile (or None)
2480        '''           
2481        x = np.array([float(i) for i in parms[0]])
2482        closest = abs(x-dist).argmin()
2483        closeX = x[closest]
2484        D = {'distance':dist}
2485        imctfile = IMfileList[closest]
2486        if parms[-1][closest].lower() != '(none)':
2487            maskfile = parms[-1][closest]
2488        else:
2489            maskfile = None
2490        for c in range(1,cols-1):
2491            lbl = ParmList[c]
2492            if lbl in nonInterpVars:
2493                D[lbl] = float(parms[c][closest])
2494            else:
2495                y = np.array([float(i) for i in parms[c]])
2496                D[lbl] = np.interp(dist,x,y)
2497        # full integration when angular range is 0
2498        D['fullIntegrate'] = (D['LRazimuth_min'] == D['LRazimuth_max'])
2499        # conversion for paired values
2500        for a,b in ('center_x','center_y'),('LRazimuth_min','LRazimuth_max'),('IOtth_min','IOtth_max'):
2501            r = a.split('_')[0]
2502            D[r] = [D[a],D[b]]
2503            del D[a]
2504            del D[b]
2505        return D,imctfile,maskfile
2506    # save local copies of values needed in Evaluator
2507    parms = dlg.ReadImageParmTable()
2508    IMfileList = dlg.IMfileList
2509    cols = dlg.list.GetColumnCount()
2510    ParmList = dlg.ParmList
2511    nonInterpVars = dlg.nonInterpVars
2512    return Evaluator
2513
2514class IntegParmTable(wx.Dialog):
2515    '''Creates a dialog window with a table of integration parameters.
2516    :meth:`ShowModal` will return wx.ID_OK if the process has been successful.
2517    In this case, :func:`DefineEvaluator` should be called to obtain a function that
2518    creates a dictionary with interpolated parameter values.
2519    '''
2520    ParmList = ('distance','center_x','center_y','wavelength','tilt','rotation','DetDepth',
2521            'LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max','outChannels',
2522            'maskfile',
2523            )
2524    nonInterpVars = ('tilt','rotation','LRazimuth_min','LRazimuth_max','IOtth_min','IOtth_max',
2525                     'outChannels')  # values in this list are taken from nearest rather than interpolated
2526    HeaderList = ('Det Dist','X cntr','Y cntr','wavelength','tilt','rotation','DetDepth',
2527            'Azimuth min','Azimuth max','2Th min','2Th max','Int. pts',
2528            'Mask File',
2529            )
2530    def __init__(self,G2frame,parms=None,IMfileList=None):
2531        self.G2frame = G2frame
2532        wx.Dialog.__init__(self,G2frame,style=wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE)
2533        if parms:
2534            self.parms = parms # list of values by column
2535            self.IMfileList = IMfileList # list of .imctrl file names for each entry in table
2536        else:
2537            self.parms = [] # list of values by column
2538            self.IMfileList = [] # list of .imctrl file names for each entry in table
2539            files = []
2540            try:
2541                dlg = wx.FileDialog(self, 'Select image control files or previous table', 
2542                                    style=wx.OPEN| wx.MULTIPLE,
2543                                    wildcard='image control files (.imctrl)|*.imctrl|Integration table (*.imtbl)|*.imtbl')
2544                dlg.CenterOnParent()
2545                if dlg.ShowModal() == wx.ID_OK:
2546                    files = dlg.GetPaths()
2547                    self.parms,self.IMfileList = self.ReadFiles(files)
2548            finally:
2549                dlg.Destroy()
2550            if not files:
2551                wx.CallAfter(self.EndModal,wx.ID_CANCEL)
2552                return
2553        mainSizer = wx.BoxSizer(wx.VERTICAL)
2554        self.list = ImgIntLstCtrl(self, wx.ID_ANY,
2555                      style=wx.LC_REPORT
2556                          | wx.BORDER_SUNKEN
2557                         #| wx.BORDER_NONE
2558                         )
2559        mainSizer.Add(self.list,1,wx.EXPAND,1)
2560        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
2561        btn = wx.Button(self, wx.ID_OK)
2562        btnsizer.Add(btn)
2563        btn = wx.Button(self, wx.ID_ANY,'Save as file')
2564        btn.Bind(wx.EVT_BUTTON,self._onSave)
2565        btnsizer.Add(btn)
2566        btn = wx.Button(self, wx.ID_CLOSE,'Quit')
2567        btn.Bind(wx.EVT_BUTTON,self._onClose)
2568        btnsizer.Add(btn)
2569        mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)   
2570        self.SetSizer(mainSizer)
2571        self.list.FillList(self.parms)
2572        mainSizer.Layout()
2573        mainSizer.Fit(self)
2574       
2575    def ReadFiles(self,files):
2576        '''Reads a list of .imctrl files or a single .imtbl file
2577        '''
2578        tmpDict = {}
2579        if not files: return
2580        # option 1, a dump from a previous save
2581        if os.path.splitext(files[0])[1] == '.imtbl':
2582            fp = open(files[0],'r')
2583            S = fp.readline()
2584            while S:
2585                if S[0] != '#':
2586                    [key,val] = S[:-1].split(':',1)
2587                    tmpDict[key] = eval(val)
2588                S = fp.readline()
2589            fp.close()
2590            # delete entries
2591            m1 = [i for i,f in enumerate(tmpDict['filenames']) if not os.path.exists(f)]
2592            if m1:
2593                print('\nimctrl file not found:')
2594                for i in m1: print('\t#'+str(i)+': '+tmpDict['filenames'][i])
2595            m2 = [i for i,f in enumerate(tmpDict['maskfile']) if not (os.path.exists(f) or f.startswith('('))]
2596            if m2:
2597                print('\nmask file not found')
2598                for i in m2: print('\t#'+str(i)+': '+tmpDict['maskfile'][i])
2599            m3 = [i for i,d in enumerate(tmpDict['distance']) if d < 0]
2600            if m3:
2601                print('\nDropping entries due to negative distance: '+str(m3))
2602            m = sorted(set(m1 + m2 + m3))
2603            m.reverse()
2604            for c in m:
2605                for key in tmpDict:
2606                    del tmpDict[key][c]
2607            fileList = tmpDict.get('filenames','[]')
2608            parms = []
2609            for key in self.ParmList:
2610                try:
2611                    float(tmpDict[key][0])
2612                    parms.append([str(G2py3.FormatSigFigs(val,sigfigs=5)) for val in tmpDict[key]])
2613                except ValueError:
2614                    parms.append(tmpDict[key])
2615            return parms,fileList
2616        # option 2, read in a list of files
2617        for file in files: # read all files; place in dict by distance
2618            imgDict = Read_imctrl(file)
2619            tmpDict[imgDict.get('distance')] = imgDict
2620        parms = [[] for key in self.ParmList]
2621        fileList = []
2622        for d in sorted(tmpDict):
2623            fileList.append(tmpDict[d].get('filename'))
2624            if d is None: continue
2625            if d < 0: continue
2626            for i,key in enumerate(self.ParmList):
2627                val = tmpDict[d].get(key)
2628                try:
2629                    val = str(G2py3.FormatSigFigs(val,sigfigs=5))
2630                except:
2631                    val = str(val)
2632                parms[i].append(val)
2633        return parms,fileList
2634   
2635    def ReadImageParmTable(self):
2636        '''Reads possibly edited values from the ListCtrl table and returns a list
2637        of values for each column.
2638        '''
2639        rows = self.list.GetItemCount()
2640        cols = self.list.GetColumnCount()
2641        parms = []
2642        for c in range(cols):
2643            lbl = self.ParmList[c]
2644            parms.append([])
2645            for r in range(rows):
2646                parms[c].append(self.list.GetItem(r,c).GetText())
2647        return parms
2648
2649    def _onClose(self,event):
2650        'Called when Cancel button is pressed'
2651        self.EndModal(wx.ID_CANCEL)
2652       
2653    def _onSave(self,event):
2654        'Called when save button is pressed; creates a .imtbl file'
2655        fil = ''
2656        if self.G2frame.GSASprojectfile:
2657            fil = os.path.splitext(self.G2frame.GSASprojectfile)[0]+'.imtbl'
2658        dir,f = os.path.split(fil)
2659        try:
2660            dlg = wx.FileDialog(self, 'Save table data as',
2661                        defaultDir=dir, defaultFile=f, style=wx.SAVE,
2662                        wildcard='G2 Image Param Table file (*.imtbl)|*.imtbl')
2663            dlg.CenterOnParent()
2664            if dlg.ShowModal() != wx.ID_OK: return
2665            fil = dlg.GetPath()
2666            fil = os.path.splitext(fil)[0]+'.imtbl'
2667        finally:
2668            dlg.Destroy()       
2669        parms = self.ReadImageParmTable()
2670        print('Writing image parameter table as '+fil)
2671        fp = open(fil,'w')
2672        for c in range(len(parms)-1):
2673            lbl = self.ParmList[c]
2674            fp.write(lbl+': '+str([eval(i) for i in parms[c]])+'\n')
2675        lbl = self.ParmList[c+1]
2676        fp.write(lbl+': '+str(parms[c+1])+'\n')
2677        lbl = 'filenames'
2678        fp.write(lbl+': '+str(self.IMfileList)+'\n')
2679        fp.close()
2680   
2681class ImgIntLstCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,listmix.TextEditMixin):
2682    '''Creates a custom ListCtrl for editing Image Integration parameters
2683    '''
2684    def __init__(self, parent, ID, pos=wx.DefaultPosition,
2685                 size=(1000,200), style=0):
2686        self.parent=parent
2687        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
2688        listmix.ListCtrlAutoWidthMixin.__init__(self)
2689        listmix.TextEditMixin.__init__(self)
2690        self.Bind(wx.EVT_LEFT_DCLICK, self.OnDouble)
2691        #self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
2692    def FillList(self,parms):
2693        'Places the current parms into the table'
2694        self.ClearAll()
2695        self.rowlen = len(self.parent.ParmList)
2696        for i,lbl in enumerate(self.parent.HeaderList):
2697            self.InsertColumn(i, lbl)
2698        for r,d in enumerate(parms[0]):
2699            if float(d) < 0: continue
2700            index = self.InsertStringItem(sys.maxint, d)
2701            for j in range(1,len(parms)):
2702                self.SetStringItem(index, j, parms[j][r])
2703        for i,lbl in enumerate(self.parent.ParmList):
2704            self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
2705
2706    def OnDouble(self,evt):
2707        'respond to a double-click'
2708        self.CloseEditor()
2709        fil = '(none)'
2710        try:
2711            dlg = wx.FileDialog(self, 'Select mask or control file to add (Press cancel if none)', 
2712                                style=wx.OPEN,
2713                                wildcard='Add GSAS-II mask file (.immask)|*.immask|add image control file (.imctrl)|*.imctrl')
2714            dlg.CenterOnParent()
2715            if dlg.ShowModal() == wx.ID_OK:
2716                fil = dlg.GetPath()
2717        finally:
2718            dlg.Destroy()
2719        if os.path.splitext(fil)[1] != '.imctrl':
2720            self.SetStringItem(self.curRow, self.rowlen-1, fil)
2721            self.SetColumnWidth(self.rowlen-1, wx.LIST_AUTOSIZE)
2722        else:
2723            # insert or overwrite an instrument parameter set
2724            if not os.path.exists(fil):
2725                print('Does not exist: '+fil)
2726                return
2727            imgDict = Read_imctrl(fil)
2728            dist = imgDict['distance']
2729            parms = self.parent.ReadImageParmTable()
2730            x = np.array([float(i) for i in parms[0]])
2731            closest = abs(x-dist).argmin()
2732            closeX = x[closest]
2733            # fix IMfileList
2734            for c,lbl in enumerate(self.parent.ParmList):
2735                try:
2736                    vali = G2py3.FormatSigFigs(float(imgDict[lbl]),sigfigs=5)
2737                except ValueError:
2738                    vali = imgDict[lbl]
2739                if abs(closeX-dist) < 1.: # distance is within 1 mm, replace
2740                    parms[c][closest] = vali
2741                elif dist > closeX: # insert after
2742                    parms[c].insert(closest+1,vali)
2743                else:
2744                    parms[c].insert(closest,vali)
2745            if abs(closeX-dist) < 1.: # distance is within 1 mm, replace
2746                self.parent.IMfileList[closest] = fil
2747            elif dist > closeX: # insert after
2748                self.parent.IMfileList.insert(closest+1,fil)
2749            else:
2750                self.parent.IMfileList.insert(closest,fil)
2751            self.FillList(parms)
2752# Autointegration end
2753###########################################################################
Note: See TracBrowser for help on using the repository browser.