source: trunk/GSASIIimgGUI.py @ 2340

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

write multiple control files

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