source: trunk/GSASIIimgGUI.py @ 2212

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

Implement 'abc*' as one of the 'Common' cell transformations.
Transformations now transforms atom positions & Uijs
Fix problem in ImageGUI where load controls didn't update the image plot correctly.

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