source: trunk/GSASIIimgGUI.py @ 2569

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

add 'f' or 'g' to maxdigits in FormatValue? in G2py3 - should be revised some more
do a lot of TextCtrl? --> ValidatedTextCtrl? replacements
note that ValidatedTextCtrl? only checks val <= max & not val < max
added tc.event to ValidatedTextCtrl? as some things needed that
G2imgGui - mostly done
G2restrGUI - done
G2pwdGUI - started

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