source: trunk/GSASIIimgGUI.py @ 2227

Last change on this file since 2227 was 2227, checked in by vondreele, 6 years ago

avoid divide by zero effect if a zero image
refactor LoadImage2Tree
add new importer for summing GE images

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