source: trunk/GSASIIimgGUI.py @ 2580

Last change on this file since 2580 was 2580, checked in by toby, 5 years ago

Speed slider on Image Controls

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