source: trunk/GSASIIimgGUI.py @ 2322

Last change on this file since 2322 was 2322, checked in by vondreele, 7 years ago

(partially) fixed Cancel/Pause? behavior in AutoIntegrate?. Will crash 32-bit if Cancel pressed too soon & if Pause pressed repeatedly during integration. 64-bit seems immune to this.

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