source: trunk/GSASIIimgGUI.py @ 2570

Last change on this file since 2570 was 2570, checked in by vondreele, 5 years ago

more TextCtrl? --> ValidatedTextCtrl?

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