source: trunk/scanCCD.py @ 1378

Last change on this file since 1378 was 1378, checked in by toby, 7 years ago

wxPython 2.9 fixes: FlexGridSizer?, wx.Colour, MacOpenFile?; move bind to prevent Rigid body crash

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