source: trunk/GSASIIimgGUI.py @ 2310

Last change on this file since 2310 was 2310, checked in by vondreele, 7 years ago

Add two new image control menu items:
1) Recalibrate all - does a global recalibration of all/selected images
2) Copy Selected - copies selected Image Controls to all/selected images

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