source: trunk/GSASIIimgGUI.py @ 2346

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

fix GUI issues in Image Controls

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