source: trunk/scanCCD.py @ 578

Last change on this file since 578 was 473, checked in by vondreele, 13 years ago

Add FileDlgFixExt? to fix linux problem in FileDialog? where the extension is not taken from the wildcard choice.

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