source: trunk/scanCCD.py @ 4850

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

fix future problem with wx.NewId? --> wx.NewIdRef?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 30.8 KB
Line 
1#scanCCD data processing
2'''
3*scanCCD: reduce data from scanning CCD*
4========================================
5
6Quickly prototyped routine for reduction of data from detector described in
7B.H. Toby, T.J. Madden, M.R. Suchomel, J.D. Baldwin, and R.B. Von Dreele,
8"A Scanning CCD Detector for Powder Diffraction Measurements".
9Journal of Applied Crystallography. 46(4): p. 1058-63 (2013).
10
11'''
12import os
13import os.path as ospath
14import sys
15import math
16import time
17import numpy as np
18import numpy.linalg as nl
19import numpy.ma as ma
20import wx
21import matplotlib as mpl
22import GSASIIpath
23import GSASIIIO as G2IO
24import GSASIIimage as G2img
25import GSASIIplot as G2plt
26
27npsind = lambda x: np.sin(x*np.pi/180.)
28npcosd = lambda x: np.cos(x*np.pi/180.)
29npacosd = lambda x: 180.*np.arccos(x)/np.pi
30npasind = lambda x: 180.*np.arcsin(x)/np.pi
31
32try:
33    wx.NewIdRef
34    wx.NewId = wx.NewIdRef
35except AttributeError:
36    pass
37
38def create(parent):
39    return scanCCD(parent)
40   
41[wxID_FILEEXIT, wxID_FILEOPEN, wxID_INTEGRATE, wxID_OUTPUT,
42] = [wx.NewId() for _init_coll_File_Items in range(4)]
43
44def FileDlgFixExt(dlg,file):            #this is needed to fix a problem in linux wx.FileDialog
45    ext = dlg.GetWildcard().split('|')[2*dlg.GetFilterIndex()+1].strip('*')
46    if ext not in file:
47        file += ext
48    return file
49   
50class scanCCD(wx.Frame):
51
52    def _init_ctrls(self, parent):
53        wx.Frame.__init__(self, name='scanCCD', parent=parent,
54            size=wx.Size(460, 250),style=wx.DEFAULT_FRAME_STYLE, title='scanCCD')
55        self.scanCCDMenu = wx.MenuBar()
56        self.File = wx.Menu(title='')
57        self.File.Append(help='Open scanCCD image files (*.tif)', id=wxID_FILEOPEN,
58             kind=wx.ITEM_NORMAL,text='Open scanCCD files')
59        self.File.Append(help='Integrate scanCCD images',id=wxID_INTEGRATE,
60             kind=wx.ITEM_NORMAL,text='Integrate scanCCD images')
61        self.File.Append(help='Output fxye file from integration',id=wxID_OUTPUT,
62             kind=wx.ITEM_NORMAL,text='Output pattern')
63        self.File.Append(help='Exit from scanCCD', id=wxID_FILEEXIT, kind=wx.ITEM_NORMAL,
64            text='Exit')
65        self.Bind(wx.EVT_MENU, self.OnImageRead, id=wxID_FILEOPEN)
66        self.Bind(wx.EVT_MENU,self.OnImageIntegrate,id=wxID_INTEGRATE)
67        self.Bind(wx.EVT_MENU,self.OnOutput,id=wxID_OUTPUT)
68        self.Bind(wx.EVT_MENU, self.OnFileExit, id=wxID_FILEEXIT)
69        self.scanCCDMenu.Append(menu=self.File, title='File')
70        self.SetMenuBar(self.scanCCDMenu)
71        self.SCCDPanel = wx.Panel(self)       
72        plotFrame = wx.Frame(None,-1,'scanCCD Plots',size=wx.Size(700,600), \
73            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
74        self.plotNB = G2plt.G2PlotNoteBook(plotFrame)
75        plotFrame.Show()
76
77    def __init__(self, parent):
78        self._init_ctrls(parent)
79        self.Bind(wx.EVT_CLOSE, self.ExitMain)   
80        self.dirname = ''
81        self.imagefiles = []
82        self.dataFrame = None
83        self.itemPicked = None
84        self.Image = []
85        self.Hxyw = []
86        self.data = {'color':'Paired','range':[[0,1000],[0,1000]]}
87
88    def ExitMain(self, event):
89        sys.exit()
90       
91    def OnFileExit(self,event):
92        if self.dataFrame:
93            self.dataFrame.Clear() 
94            self.dataFrame.Destroy()
95        self.Close()
96       
97    def OnImageRead(self,event):
98        dlg = wx.FileDialog(self, 'Choose scanCCD image files', '.', '',\
99        'Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|\
100        All files (*.*)|*.*',
101        wx.FD_OPEN | wx.FD_MULTIPLE)
102        if self.dirname:
103            dlg.SetDirectory(self.dirname)
104        try:
105            self.imagefiles = []
106            if dlg.ShowModal() == wx.ID_OK:
107                self.dirname = dlg.GetDirectory()
108                self.imagefiles = dlg.GetPaths()
109                self.imagefiles.sort()
110                self.data['imScale'] = 8
111                self.Image = []
112                for imagefile in self.imagefiles:
113                    Comments,Data,Npix,image = G2IO.GetImageData(self,imagefile)
114                    if Comments:
115                        A = G2img.ImageCompress(image,self.data['imScale'])
116                        if len(self.Image):
117                            self.Image = np.concatenate((self.Image,A))
118                        else:
119                            self.Image = A
120                self.data['range'][0] = self.data['range'][1] = np.max(self.Image)
121                self.data['pixel'] = Data['pixelSize']
122                self.data['size'] = self.Image.shape
123                self.data['Zmin'] = np.min(self.Image)
124                self.data['Zmax'] = np.max(self.Image)
125                self.data['Zeros'] = [-15.3096,16.4]        #for bob1-3 files
126                self.data['mm/deg'] = 15.56012              #from bob1 fit to 2333 peak positions
127                self.data['radius'] = 180.0*self.data['mm/deg']/math.pi
128                self.data['TBlimits'] = [0,len(image)]
129                self.data['LRlimits'] = [0,len(image)*len(self.imagefiles)]
130                self.data['PtScan'] = len(image)/2
131                self.data['2thScan'] = [0.0,90.0,0.001]
132                self.data['showBlk'] = False
133                self.data['skip'] = 1               #default - skip ramp block
134                if len(self.imagefiles) == 1:
135                    self.data['skip'] = 0
136                self.UpdateControls(event)
137                self.PlotImage()
138        finally:
139            dlg.Destroy()
140           
141    def OnImageIntegrate(self,event):
142       
143        def Make2ThetaMap(data,iLim,jLim):
144            #transforms scanCCD image from x,y space to 2-theta,y space
145            pixelSize = data['pixel']
146            scalex = pixelSize[0]/1000.
147            scaley = pixelSize[1]/1000.
148            vecA = np.asfarray([1.,0.,0.],dtype=np.float32)
149           
150            tay,tax = np.mgrid[jLim[0]+.5:jLim[1]+.5,iLim[0]+.5:iLim[1]+.5]        #bin centers not corners
151            tax = np.asfarray((tax*scalex-data['Zeros'][0])/data['mm/deg'],dtype=np.float32)  #scanCCD 2-thetas
152            tay = np.asfarray(tay*scaley-data['Zeros'][1],dtype=np.float32)
153            vecB = np.array([npcosd(tax)*data['radius'],npsind(tax)*data['radius'],tay])
154            norm = np.sqrt(np.sum((vecB.T*vecB.T),axis=2))
155            vecB /= norm.T
156            tax = npacosd(np.dot(vecB.T,vecA))*tax/np.abs(tax)      #to get sign of 2-theta
157            tay += data['Zeros'][1]
158            return tax,tay.T           #2-theta arrays & turn y array around!!
159
160   
161        def Fill2ThetaMap(data,TA,image):
162            import numpy.ma as ma
163            Zmin = data['Zmin']
164            Zmax = data['Zmax']
165            tax,tay = TA    # 2-theta & yaxis
166            taz = ma.masked_outside(image.flatten()-Zmin,0,Zmax-Zmin)
167            tam = ma.getmask(taz)
168            tax = ma.compressed(ma.array(tax.flatten(),mask=tam))
169            tay = ma.compressed(ma.array(tay.flatten(),mask=tam))
170            taz = ma.compressed(ma.array(taz.flatten(),mask=tam))
171            del(tam)
172            return tax,tay,taz
173       
174        import histosigma2d as h2d
175        print('Begin image integration')
176        scaley = self.data['pixel'][1]/1000.
177        tthStart,tthEnd,tthStep = self.data['2thScan']
178        LUtth = [tthStart,tthEnd]
179        TBlim = np.array(self.data['TBlimits'],dtype=np.float32)
180        nYpix = TBlim[1]-TBlim[0]
181        TBlim *= scaley
182        TBdelt = TBlim[1]-TBlim[0]
183        nTB = 1
184        numChans = (tthEnd-tthStart)/tthStep
185        NST = np.zeros(shape=(numChans,1),order='F',dtype=np.float32)
186        H0 = np.zeros(shape=(numChans,1),order='F',dtype=np.float32)
187        Amat = np.zeros(shape=(numChans,1),order='F',dtype=np.float32)
188        Qmat = np.zeros(shape=(numChans,1),order='F',dtype=np.float32)
189        imSize = np.array(self.data['size'])*self.data['imScale']
190        H1 = [tth for tth in np.linspace(LUtth[0],LUtth[1],numChans)]
191        blkSize = 2048
192        N = 4096/blkSize
193        nBlk = N**2*len(self.imagefiles)       #assume 4Kx4K CCD images - done in 1Kx1K blocks
194        t0 = time.time()
195        dlg = wx.ProgressDialog("Elapsed time","2D image integration",nBlk,
196            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
197        try:
198            nBlk = 0
199            iBegi = 0
200            iFin = 0
201            GoOn = True
202            for ifile,imagefile in enumerate(self.imagefiles):
203                if ifile >= self.data['skip']:
204                    image = G2IO.GetImageData(self,imagefile)[3]
205                    image = np.fliplr(image)
206                    for iBlk in range(N):
207                        iBeg = iBegi+iBlk*blkSize
208                        iFin = iBeg+blkSize
209                        for jBlk in range(N):
210                            jBeg = jBlk*blkSize
211                            jFin = jBeg+blkSize               
212                            print('Process map block:',nBlk,iBlk,jBlk,' offset:',iBegi,' limits:',iBeg,iFin,jBeg,jFin)
213                            TA = Make2ThetaMap(self.data,(iBeg,iFin),(jBeg,jFin))           #2-theta & Y arrays & create position mask                       
214                            Block = image[iBeg-iBegi:iFin-iBegi,jBeg:jFin]
215                            tax,tay,taz = Fill2ThetaMap(self.data,TA,Block)                 #and apply masks
216                            NST,H0,Amat,Qmat = h2d.histosigma2d(len(tax),tax,tay,taz,numChans,nTB,LUtth,TBlim,tthStep,TBdelt,NST,H0,Amat,Qmat)
217                            H0temp = np.nan_to_num(np.divide(H0,NST))
218                            Qtemp = np.nan_to_num(np.divide(Qmat,NST))
219                            if self.data['showBlk']:
220                                self.PlotBlock(Block.T,'%s %d %d'%('Block',iBlk,jBlk))
221                                OKdlg = wx.MessageDialog(self,'','Continue',wx.OK)
222                                try:
223                                    result = OKdlg.ShowModal()
224                                finally:
225                                    OKdlg.Destroy()
226                            del tax,tay,taz
227                            nBlk += 1
228                            GoOn = dlg.Update(nBlk)[0]
229                            if not GoOn:
230                                break
231                else:
232                    print('file '+imagefile+' skipped')
233                    nBlk += N*N
234                    GoOn = dlg.Update(nBlk)[0]
235                    iFin += N*blkSize
236                if not GoOn:
237                    break
238                iBegi = iFin
239            H0 = np.divide(H0,NST)
240            H0 = np.nan_to_num(H0)
241            Qmat = np.divide(Qmat,NST)
242            Qmat = np.nan_to_num(Qmat)
243            del NST
244            t1 = time.time()
245        finally:
246            dlg.Destroy()
247        Scale = np.sum(Qmat)/np.sum(H0)
248        print('SumI: ',np.sum(H0),' SumV: ',np.sum(Qmat),' Scale:',Scale)
249        print('Integration complete')
250        print("Elapsed time:","%8.3f"%(t1-t0), "s")
251        self.Hxyw = [H1,Scale*H0.T[0],np.sqrt(Qmat.T[0])]
252        print()
253        self.PlotXY(self.Hxyw,True,type='Integration result')
254       
255    def OnOutput(self,event):
256
257        def powderSave(self,powderfile,Fxye=False):
258            file = open(powderfile,'w')
259            file.write('#%s\n'%('from scanCCD image '+self.imagefiles[0]))
260            print('save powder pattern to file: ',powderfile)
261            wx.BeginBusyCursor()
262            try:
263                x,y,e = self.Hxyw
264                if Fxye:
265                    file.write(powderfile+'\n')
266                    file.write('BANK 1 %d %d CONS %.2f %.2f 0 0 FXYE\n'%(len(x),len(x),\
267                        100.*x[0],100.*(x[1]-x[0])))                   
268                XYE = zip(x,y,e)
269                for X,Y,E in XYE:
270                    if Fxye:
271                        file.write("%15.6g %15.6g %15.6g\n" % (100.*X,Y,max(E,1.0)))                       
272                    else:
273                        file.write("%15.6g %15.6g %15.6g\n" % (X,Y,max(E,1.0)))
274                file.close()
275            finally:
276                wx.EndBusyCursor()
277            print('powder pattern file written')
278       
279        if not self.Hxyw:
280            return
281        dlg = wx.FileDialog(self, 'Choose output powder file name', '.', '', 
282            'GSAS fxye file (*.fxye)|*.fxye|xye file (*.xye)|*.xye',
283            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
284        if self.dirname:
285            dlg.SetDirectory(self.dirname)
286        try:
287            if dlg.ShowModal() == wx.ID_OK:
288                print(dlg.GetFilename())
289                powderfile = dlg.GetPath()
290                if 'fxye' in powderfile:
291                    powderSave(self,powderfile,Fxye=True)
292                else:       #just xye
293                    powderSave(self,powderfile)
294                self.dirname = dlg.GetDirectory()
295        finally:
296            dlg.Destroy()
297
298    def UpdateControls(self,event):
299        ObjIndx = {}
300        self.SCCDPanel.DestroyChildren()
301       
302        def ColorSizer(data):
303           
304            def OnNewColorBar(event):
305                colSel = event.GetEventObject()
306                data['color'] = colSel.GetValue()
307                self.PlotImage()
308               
309            def OnShowBlk(event):
310                data['showBlk'] = shoBlk.GetValue()
311               
312            def OnSkipFiles(event):
313                data['skip'] = int(skipFile.GetValue())
314                           
315            colorList = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
316            colorSizer = wx.FlexGridSizer(0,5,5,5)
317            colorSizer.Add(wx.StaticText(self.SCCDPanel,label=' Color bar '),0,wx.ALIGN_CENTER_VERTICAL)
318            colSel = wx.ComboBox(self.SCCDPanel,value=data['color'],choices=colorList,
319                style=wx.CB_READONLY|wx.CB_DROPDOWN|wx.CB_SORT)
320            colSel.Bind(wx.EVT_COMBOBOX, OnNewColorBar)
321            colorSizer.Add(colSel,0,wx.ALIGN_CENTER_VERTICAL)
322            colorSizer.Add(wx.StaticText(self.SCCDPanel,label='image files to skip:'),0,wx.ALIGN_CENTER_VERTICAL)
323            skipFile = wx.ComboBox(self.SCCDPanel,value=str(data['skip']),
324                choices=[str(i) for i in range(len(self.imagefiles))],
325                style=wx.CB_READONLY|wx.CB_DROPDOWN)
326            skipFile.Bind(wx.EVT_COMBOBOX,OnSkipFiles)
327            colorSizer.Add(skipFile,0,wx.ALIGN_CENTER_VERTICAL)
328            shoBlk = wx.CheckBox(self.SCCDPanel,-1,label='Show image blocks?')
329            shoBlk.SetValue(data['showBlk'])
330            shoBlk.Bind(wx.EVT_CHECKBOX, OnShowBlk)
331            colorSizer.Add(shoBlk,0,wx.ALIGN_CENTER_VERTICAL)
332            return colorSizer                   
333           
334        def MaxSizer(data):
335           
336            def OnMaxSlider(event):           
337                imax = int(self.maxSel.GetValue())*data['range'][0]/100.
338                data['range'][1] = imax
339                self.maxVal.SetValue('%d'%(data['range'][1]))
340                self.PlotImage()
341               
342            def OnMaxValue(event):
343                try:
344                    value = int(self.maxVal.GetValue())
345                    if value < 0 or value > data['range'][0]:
346                        raise ValueError
347                except ValueError:
348                    value = data['range'][1]
349                data['range'][1] = value
350                self.maxSel.SetValue(int(100*value/data['range'][0]))
351                self.PlotImage()
352           
353            maxSizer = wx.FlexGridSizer(0,3,0,5)
354            maxSizer.AddGrowableCol(1,1)
355            maxSizer.SetFlexibleDirection(wx.HORIZONTAL)
356            maxSizer.Add(wx.StaticText(parent=self.SCCDPanel,label=' Max intensity'),0,
357                wx.ALIGN_CENTER_VERTICAL)
358            self.maxSel = wx.Slider(parent=self.SCCDPanel,style=wx.SL_HORIZONTAL,
359                value=int(100*data['range'][1]/data['range'][0]))
360            maxSizer.Add(self.maxSel,1,wx.EXPAND)
361            self.maxSel.Bind(wx.EVT_SLIDER, OnMaxSlider)
362            self.maxVal = wx.TextCtrl(parent=self.SCCDPanel,value='%d'%(data['range'][1]))
363            self.maxVal.Bind(wx.EVT_TEXT_ENTER,OnMaxValue)
364            self.maxVal.Bind(wx.EVT_KILL_FOCUS,OnMaxValue)
365            maxSizer.Add(self.maxVal,0,wx.ALIGN_CENTER_VERTICAL)   
366            return maxSizer   
367                   
368        def ZSizer(data):
369           
370            def OnZValue(event):
371                Obj = event.GetEventObject()
372                try:
373                    value = int(Obj.GetValue())
374                except ValueError:
375                    value = data[ObjIndx[Obj.GetId()]]
376                data[ObjIndx[Obj.GetId()]] = value
377                self.PlotImage()
378           
379            zSizer = wx.FlexGridSizer(0,4,5,5)
380            zSizer.Add(wx.StaticText(self.SCCDPanel,label='Upper intensity mask:'),0,wx.ALIGN_CENTER_VERTICAL)
381            zMax = wx.TextCtrl(self.SCCDPanel,value='%d'%(data['Zmax']))
382            zMax.Bind(wx.EVT_TEXT_ENTER,OnZValue)
383            zMax.Bind(wx.EVT_KILL_FOCUS,OnZValue)
384            ObjIndx[zMax.GetId()] = 'Zmax'
385            zSizer.Add(zMax)
386            zSizer.Add(wx.StaticText(self.SCCDPanel,label='Intensity subtraction:'),0,wx.ALIGN_CENTER_VERTICAL)
387            zMin = wx.TextCtrl(self.SCCDPanel,value='%d'%(data['Zmin']))
388            ObjIndx[zMin.GetId()] = 'Zmin'
389            zMin.Bind(wx.EVT_TEXT_ENTER,OnZValue)
390            zMin.Bind(wx.EVT_KILL_FOCUS,OnZValue)
391            zSizer.Add(zMin)
392            return zSizer
393                       
394        def ZeroSizer(data):
395           
396            def OnZeroValue(event):
397                Obj = event.GetEventObject()
398                item = ObjIndx[Obj.GetId()]
399                try:
400                    value = float(Obj.GetValue())
401                except ValueError:
402                    value = data[item[0]][item[1]]
403                data[item[0]][item[1]] = value
404                Obj.SetValue('%.3f'%(value))
405                self.PlotImage()
406               
407            def OnZpdgValue(event):
408                Obj = event.GetEventObject()
409                item = ObjIndx[Obj.GetId()]
410                try:
411                    value = float(Obj.GetValue())
412                except ValueError:
413                    value = self.data[item[0]]
414                self.data[item[0]] = value
415                self.data['radius'] = 180.0*value/math.pi
416                Obj.SetValue('%.3f'%(value))
417                self.PlotImage()
418           
419            zeroSizer = wx.FlexGridSizer(0,6,5,5)
420            zeroSizer.Add(wx.StaticText(self.SCCDPanel,label='X-zero:'),0,wx.ALIGN_CENTER_VERTICAL)
421            zMax = wx.TextCtrl(self.SCCDPanel,value='%.3f'%(data['Zeros'][0]))
422            zMax.Bind(wx.EVT_TEXT_ENTER,OnZeroValue)
423            zMax.Bind(wx.EVT_KILL_FOCUS,OnZeroValue)
424            ObjIndx[zMax.GetId()] = ['Zeros',0]
425            zeroSizer.Add(zMax)
426            zeroSizer.Add(wx.StaticText(self.SCCDPanel,label='Y-zero:'),0,wx.ALIGN_CENTER_VERTICAL)
427            zMin = wx.TextCtrl(self.SCCDPanel,value='%.3f'%(data['Zeros'][1]))
428            ObjIndx[zMin.GetId()] = ['Zeros',1]
429            zMin.Bind(wx.EVT_TEXT_ENTER,OnZeroValue)
430            zMin.Bind(wx.EVT_KILL_FOCUS,OnZeroValue)
431            zeroSizer.Add(zMin)
432            zeroSizer.Add(wx.StaticText(self.SCCDPanel,label='mm per deg:'),0,wx.ALIGN_CENTER_VERTICAL)
433            zpdeg = wx.TextCtrl(self.SCCDPanel,value='%.3f'%(data['mm/deg']))
434            ObjIndx[zpdeg.GetId()] = ['mm/deg']
435            zpdeg.Bind(wx.EVT_TEXT_ENTER,OnZpdgValue)
436            zpdeg.Bind(wx.EVT_KILL_FOCUS,OnZpdgValue)
437            zeroSizer.Add(zpdeg)
438            return zeroSizer
439                       
440        def TBLRSizer(data):
441           
442            def OnTBLRValue(event):
443                Obj = event.GetEventObject()
444                item = ObjIndx[Obj.GetId()]
445                try:
446                    value = int(Obj.GetValue())
447                except ValueError:
448                    value = data[item[0]][item[1]]
449                data[item[0]][item[1]] = value
450                Obj.SetValue('%d'%(value))
451                self.PlotImage()
452           
453            TBLRsizer = wx.FlexGridSizer(0,4,5,5)
454            for i,item in enumerate(['Bottom','Top']): 
455                TBLRsizer.Add(wx.StaticText(self.SCCDPanel,label=item+' limit, pixels:'),0,wx.ALIGN_CENTER_VERTICAL)
456                TBlim = wx.TextCtrl(self.SCCDPanel,value='%d'%(data['TBlimits'][i]))
457                TBlim.Bind(wx.EVT_TEXT_ENTER,OnTBLRValue)
458                TBlim.Bind(wx.EVT_KILL_FOCUS,OnTBLRValue)
459                ObjIndx[TBlim.GetId()] = ['TBlimits',i]
460                TBLRsizer.Add(TBlim)
461            return TBLRsizer
462           
463        def ScanSizer(data):
464           
465            def OnScanValue(event):
466                Obj = event.GetEventObject()
467                item = ObjIndx[Obj.GetId()][0]
468                try:
469                    value = float(Obj.GetValue())
470                except ValueError:
471                    value = self.data['2thScan'][item]
472                data['2thScan'][item] = value
473                Obj.SetValue('%.3f'%(value))
474                if item in [0,1]:
475                    pixel = data['pixel']
476                    zero = data['Zeros'][0]
477                    tthscale = data['mm/deg']
478                    npixel = (value*tthscale+zero)*1000/pixel[0]
479                    data['LRlimits'][item] = npixel
480                self.PlotImage()
481           
482            scanSizer = wx.FlexGridSizer(0,6,5,5)
483            for i,item in enumerate(['Lower 2-th','Upper 2-th','2-th step']):
484                scanSizer.Add(wx.StaticText(self.SCCDPanel,label=item+':'),0,wx.ALIGN_CENTER_VERTICAL)
485                scanParm = wx.TextCtrl(self.SCCDPanel,value='%.3f'%(data['2thScan'][i]))
486                scanParm.Bind(wx.EVT_TEXT_ENTER,OnScanValue)
487                scanParm.Bind(wx.EVT_KILL_FOCUS,OnScanValue)
488                ObjIndx[scanParm.GetId()] = [i]
489                scanSizer.Add(scanParm)
490            return scanSizer               
491                       
492        mainSizer = wx.BoxSizer(wx.VERTICAL)
493        mainSizer.Add(ColorSizer(self.data),0,wx.ALIGN_CENTER_VERTICAL)       
494        mainSizer.Add(MaxSizer(self.data),0,wx.ALIGN_LEFT|wx.EXPAND)
495        mainSizer.Add(ZSizer(self.data),0,wx.ALIGN_CENTER_VERTICAL)
496        mainSizer.Add(ZeroSizer(self.data),0,wx.ALIGN_CENTER_VERTICAL)
497        mainSizer.Add(ScanSizer(self.data),0,wx.ALIGN_CENTER_VERTICAL)
498        mainSizer.Add(TBLRSizer(self.data),0,wx.ALIGN_CENTER_VERTICAL)
499        self.SCCDPanel.SetSizer(mainSizer)
500        mainSizer.Layout()   
501        fitSize = mainSizer.Fit(self.SCCDPanel)
502#        self.SCCDPanel.GetParent().SetSize(fitSize)
503           
504    def PlotImage(self):
505        pixel = self.data['pixel']
506        scalex = pixel[0]/1000.
507        scaley = pixel[1]/1000.
508
509       
510        def OnMotion(event):
511            Page.canvas.SetToolTipString('')
512            sizexy = self.data['size']
513            if event.xdata and event.ydata:                 #avoid out of frame errors
514                Page.canvas.SetCursor(wx.CROSS_CURSOR)
515                item = self.itemPicked
516                if item:
517                    if 'Line' in str(item):
518                        Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
519                else:
520                    xpos = event.xdata
521                    ypos = event.ydata
522                    xpix = xpos/(self.data['imScale']*scalex)
523                    ypix = sizexy[1]-ypos/(self.data['imScale']*scaley)
524                    Int = 0
525                    if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
526                        Int = self.Image[xpix][ypix]-self.data['Zmin']
527                        tth = (xpos-self.data['Zeros'][0])/self.data['mm/deg']
528                        vecA = np.array([1.0,0,0])
529                        vecB = np.array([npcosd(tth)*self.data['radius'],npsind(tth)*self.data['radius'],(ypos-self.data['Zeros'][1])])
530                        vecB /= nl.norm(vecB)
531                        tth2 = npacosd(np.dot(vecA,vecB))*tth/abs(tth)
532                        self.plotNB.status.SetFields(\
533                            ['','Detector x,y =%9.3fmm %9.3fmm, 2-th =%9.3f I = %6d'%(xpos,ypos,tth2,Int)])
534                           
535        def OnPick(event):
536            if self.itemPicked is not None: return
537            self.itemPicked = event.artist
538            self.mousePicked = event.mouseevent
539           
540        def OnRelease(event):
541            if self.itemPicked is None: return
542            xpos,ypos = [event.xdata,event.ydata]
543            if '_line0' in str(self.itemPicked):    #X-zero
544                self.data['Zeros'][0] = xpos               
545            elif '_line1' in str(self.itemPicked):  #Y-zero
546                self.data['Zeros'][1] = ypos
547            elif '_line2' in str(self.itemPicked): #Y-lower limit
548                self.data['TBlimits'][0] = int(ypos/scaley)
549            elif '_line3' in str(self.itemPicked): #Y-upper limit
550                self.data['TBlimits'][1] = int(ypos/scaley)
551            elif '_line4' in str(self.itemPicked): #X-lower limit
552                self.data['LRlimits'][0] = int(xpos/scalex)
553            elif '_line5' in str(self.itemPicked): #X-upper limit
554                self.data['LRlimits'][1] = int(xpos/scalex)
555            self.itemPicked = None   
556            self.PlotImage()
557            self.UpdateControls(event)
558       
559        try:
560            plotNum = self.plotNB.plotList.index('scanCCD image')
561            Page = self.plotNB.nb.GetPage(plotNum)
562            Plot = Page.figure.gca()          #get previous powder plot & get limits
563            xylim = Plot.get_xlim(),Plot.get_ylim()
564            Page.figure.clf()
565            Plot = Page.figure.gca()
566            if not Page.IsShown():
567                Page.Show()
568        except ValueError:
569            Plot = self.plotNB.addMpl('scanCCD image').gca()
570            plotNum = self.plotNB.plotList.index('scanCCD image')
571            Page = self.plotNB.nb.GetPage(plotNum)
572            Page.canvas.mpl_connect('motion_notify_event', OnMotion)
573            Page.canvas.mpl_connect('pick_event', OnPick)
574            Page.canvas.mpl_connect('button_release_event', OnRelease)
575            xylim = []
576        xlim,ylim = self.data['size']
577        Imin,Imax = [0,self.data['range'][1]]
578        Xmax = scalex*xlim*self.data['imScale']
579        Ymax = scaley*ylim*self.data['imScale']
580        TBlimit = np.array(self.data['TBlimits'])*scalex
581        LRlimit = np.array(self.data['LRlimits'])*scaley
582
583        self.plotNB.status.SetFields(['',''])
584        Zmin = self.data['Zmin']
585        Zmax = self.data['Zmax']
586        Zeros = self.data['Zeros']
587        Lines = []
588           
589#        MA = ma.masked_greater(ma.masked_less(self.Image.T,Zmin),Zmax)
590#        MaskA = ma.getmaskarray(MA)
591#        ImgM = Plot.imshow(MaskA,aspect='auto',cmap='Reds',
592#            interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,0,Ymax])
593        Img = Plot.imshow(self.Image.T-Zmin,interpolation='nearest',vmin=Imin,vmax=Imax,
594            aspect='auto',cmap=self.data['color'],extent=[0,Xmax,0,Ymax])
595        Lines.append(Plot.axvline(Zeros[0],color='b',dashes=(5,5),picker=3.))   
596        Lines.append(Plot.axhline(Zeros[1],color='b',dashes=(5,5),picker=3.))   
597        Lines.append(Plot.axhline(TBlimit[0],color='g',dashes=(5,5),picker=3.))   
598        Lines.append(Plot.axhline(TBlimit[1],color='r',dashes=(5,5),picker=3.))   
599        Lines.append(Plot.axvline(LRlimit[0],color='g',dashes=(5,5),picker=3.))   
600        Lines.append(Plot.axvline(LRlimit[1],color='r',dashes=(5,5),picker=3.))
601        for blk in range(len(self.imagefiles)):
602            Lines.append(Plot.axvline(blk*4096*scalex,color='k'))   
603        Plot.set_title('')
604        Plot.set_xlabel('Scan, mm')
605        Plot.set_ylabel('Detector Y, mm')
606        if xylim:
607            Page.toolbar.push_current()
608            Plot.set_xlim(xylim[0])
609            Plot.set_ylim(xylim[1])
610            xylim = []
611            Page.toolbar.push_current()
612            Page.toolbar.draw()
613        else:
614            Page.canvas.draw()
615           
616    def PlotBlock(self,block,title):
617        try:
618            plotNum = self.plotNB.plotList.index('Block')
619            Page = self.plotNB.nb.GetPage(plotNum)
620            Plot = Page.figure.gca()          #get previous powder plot & get limits
621            xylim = Plot.get_xlim(),Plot.get_ylim()
622            Page.figure.clf()
623            Plot = Page.figure.gca()
624            if not Page.IsShown():
625                Page.Show()
626        except ValueError:
627            Plot = self.plotNB.addMpl('Block').gca()
628            plotNum = self.plotNB.plotList.index('Block')
629            Page = self.plotNB.nb.GetPage(plotNum)
630            xylim = []
631        Img = Plot.imshow(block,interpolation='nearest',aspect='equal',cmap=self.data['color'])
632        Plot.invert_yaxis()
633        Plot.set_title(title)
634        if xylim:
635            Page.toolbar.push_current()
636            Plot.set_xlim(xylim[0])
637            Plot.set_ylim(xylim[1])
638            xylim = []
639            Page.toolbar.push_current()
640            Page.toolbar.draw()
641        else:
642            Page.canvas.draw()
643                   
644    def PlotXY(self,XY,newPlot=False,type=''):
645        '''simple plot of xy data, used for diagnostic purposes
646        '''
647        def OnMotion(event):
648            xpos = event.xdata
649            if xpos:                                        #avoid out of frame mouse position
650                ypos = event.ydata
651                Page.canvas.SetCursor(wx.CROSS_CURSOR)
652                try:
653                    self.plotNB.status.SetStatusText('X =%9.3f %s =%9.3f'%(xpos,type,ypos),1)                   
654                except TypeError:
655                    self.plotNB.status.SetStatusText('Select '+type+' pattern first',1)
656   
657        try:
658            plotNum = self.plotNB.plotList.index(type)
659            Page = self.plotNB.nb.GetPage(plotNum)
660            if not newPlot:
661                Plot = Page.figure.gca()
662                xylim = Plot.get_xlim(),Plot.get_ylim()
663            Page.figure.clf()
664            Plot = Page.figure.gca()
665        except ValueError:
666            newPlot = True
667            Plot = self.plotNB.addMpl(type).gca()
668            plotNum = self.plotNB.plotList.index(type)
669            Page = self.plotNB.nb.GetPage(plotNum)
670            Page.canvas.mpl_connect('motion_notify_event', OnMotion)
671       
672        Page.SetFocus()
673        self.plotNB.status.DestroyChildren()
674        Plot.set_title(type)
675        if type == 'line scan':
676            Plot.set_xlabel(r'image x, mm',fontsize=14)
677        else:
678            Plot.set_xlabel(r'2-theta, deg',fontsize=14)           
679        Plot.set_ylabel(r''+type,fontsize=14)
680        colors=['b','g','r','c','m','k']
681        lenX = 0
682        X,Y,S = XY
683        Plot.plot(X,Y,'k',picker=False)
684        Plot.plot(X,S,'r',picker=False)
685        if not newPlot:
686            Page.toolbar.push_current()
687            Plot.set_xlim(xylim[0])
688            Plot.set_ylim(xylim[1])
689            xylim = []
690            Page.toolbar.push_current()
691            Page.toolbar.draw()
692        else:
693            Page.canvas.draw()
694
695class scanCCDmain(wx.App):
696    def OnInit(self):
697        self.main = scanCCD(None)
698        self.main.Show()
699        self.SetTopWindow(self.main)
700        return True
701
702def main():
703    'starts main application to merge data from scanning CCD'
704    application = scanCCDmain(0)
705    application.MainLoop()
706   
707if __name__ == '__main__':
708    main()
Note: See TracBrowser for help on using the repository browser.