source: trunk/GSASIIimgGUI.py @ 2338

Last change on this file since 2338 was 2338, checked in by toby, 6 years ago

restore missing help files, fix import of new .imgctrl to table

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