source: trunk/GSASIIimgGUI.py @ 2348

Last change on this file since 2348 was 2348, checked in by vondreele, 6 years ago

fix progress bar issues in image integration

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