source: trunk/GSASIIplot.py @ 273

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

output of S(Q) and G(R) as files for other use
some effort to fix graphics tab behavior

  • Property svn:keywords set to Date Author Revision URL Id
File size: 96.8 KB
Line 
1#GSASII plotting routines
2########### SVN repository information ###################
3# $Date: 2011-05-02 22:16:06 +0000 (Mon, 02 May 2011) $
4# $Author: vondreele $
5# $Revision: 273 $
6# $URL: trunk/GSASIIplot.py $
7# $Id: GSASIIplot.py 273 2011-05-02 22:16:06Z vondreele $
8########### SVN repository information ###################
9import math
10import time
11import copy
12import os.path
13import numpy as np
14import numpy.linalg as nl
15import wx
16import wx.aui
17import wx.glcanvas
18import matplotlib as mpl
19import mpl_toolkits.mplot3d.axes3d as mp3d
20import GSASIIpath
21import GSASIIgrid as G2gd
22import GSASIIimage as G2img
23import GSASIIpwd as G2pwd
24import GSASIIIO as G2IO
25import GSASIIpwdGUI as G2pdG
26import GSASIIimgGUI as G2imG
27import GSASIIphsGUI as G2phG
28import GSASIIlattice as G2lat
29import GSASIIspc as G2spc
30from  OpenGL.GL import *
31from OpenGL.GLU import *
32from OpenGL.GLUT import *
33from OpenGL.GLE import *
34from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
35from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
36
37# useful degree trig functions
38sind = lambda x: math.sin(x*math.pi/180.)
39cosd = lambda x: math.cos(x*math.pi/180.)
40tand = lambda x: math.tan(x*math.pi/180.)
41asind = lambda x: 180.*math.asin(x)/math.pi
42acosd = lambda x: 180.*math.acos(x)/math.pi
43atan2d = lambda x,y: 180.*math.atan2(y,x)/math.pi
44atand = lambda x: 180.*math.atan(x)/math.pi
45# numpy versions
46npsind = lambda x: np.sin(x*np.pi/180.)
47npcosd = lambda x: np.cos(x*np.pi/180.)
48npacosd = lambda x: 180.*np.arccos(x)/np.pi
49   
50class G2PlotMpl(wx.Panel):   
51    def __init__(self,parent,id=-1,dpi=None,**kwargs):
52        wx.Panel.__init__(self,parent,id=id,**kwargs)
53        mpl.rcParams['legend.fontsize'] = 8
54        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(5,7))
55        self.canvas = Canvas(self,-1,self.figure)
56        self.toolbar = Toolbar(self.canvas)
57
58        self.toolbar.Realize()
59       
60        sizer=wx.BoxSizer(wx.VERTICAL)
61        sizer.Add(self.canvas,1,wx.EXPAND)
62        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
63        self.SetSizer(sizer)
64       
65class G2PlotOgl(wx.Panel):
66    def __init__(self,parent,id=-1,dpi=None,**kwargs):
67        self.figure = wx.Panel.__init__(self,parent,id=id,**kwargs)
68        self.canvas = wx.glcanvas.GLCanvas(self,-1,**kwargs)
69        self.camera = {}
70        sizer=wx.BoxSizer(wx.VERTICAL)
71        sizer.Add(self.canvas,1,wx.EXPAND)
72        self.SetSizer(sizer)
73       
74class G2Plot3D(wx.Panel):
75    def __init__(self,parent,id=-1,dpi=None,**kwargs):
76        wx.Panel.__init__(self,parent,id=id,**kwargs)
77        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(6,6))
78        self.canvas = Canvas(self,-1,self.figure)
79        self.toolbar = Toolbar(self.canvas)
80
81        self.toolbar.Realize()
82       
83        sizer=wx.BoxSizer(wx.VERTICAL)
84        sizer.Add(self.canvas,1,wx.EXPAND)
85        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
86        self.SetSizer(sizer)
87                             
88class G2PlotNoteBook(wx.Panel):
89    def __init__(self,parent,id=-1):
90        wx.Panel.__init__(self,parent,id=id)
91        #so one can't delete a plot page!!
92        self.nb = wx.aui.AuiNotebook(self, \
93            style=wx.aui.AUI_NB_DEFAULT_STYLE ^ wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
94        sizer = wx.BoxSizer()
95        sizer.Add(self.nb,1,wx.EXPAND)
96        self.SetSizer(sizer)
97        self.status = parent.CreateStatusBar()
98        self.status.SetFieldsCount(2)
99        self.status.SetStatusWidths([150,-1])
100        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
101       
102        self.plotList = []
103           
104    def addMpl(self,name=""):
105        page = G2PlotMpl(self.nb)
106        self.nb.AddPage(page,name)
107       
108        self.plotList.append(name)
109       
110        return page.figure
111       
112    def add3D(self,name=""):
113        page = G2Plot3D(self.nb)
114        self.nb.AddPage(page,name)
115       
116        self.plotList.append(name)
117       
118        return page.figure
119       
120    def addOgl(self,name=""):
121        page = G2PlotOgl(self.nb)
122        self.nb.AddPage(page,name)
123       
124        self.plotList.append(name)
125       
126        return page.figure
127       
128    def Delete(self,name):
129        try:
130            item = self.plotList.index(name)
131            del self.plotList[item]
132            self.nb.DeletePage(item)
133        except ValueError:          #no plot of this name - do nothing
134            return     
135               
136    def clear(self):
137        while self.nb.GetPageCount():
138            self.nb.DeletePage(0)
139        self.plotList = []
140        self.status.DestroyChildren()
141       
142    def Rename(self,oldName,newName):
143        try:
144            item = self.plotList.index(oldName)
145            self.plotList[item] = newName
146            self.nb.SetPageText(item,newName)
147        except ValueError:          #no plot of this name - do nothing
148            return     
149       
150    def OnPageChanged(self,event):       
151        if self.plotList:
152            self.status.SetStatusText('Better to select this from GSAS-II data tree',1)
153        self.status.DestroyChildren()                           #get rid of special stuff on status bar
154       
155def PlotSngl(self,newPlot=False):
156    from matplotlib.patches import Circle
157    global HKL,HKLF
158
159    def OnSCMotion(event):
160        xpos = event.xdata
161        if xpos:
162            xpos = round(xpos)                                        #avoid out of frame mouse position
163            ypos = round(event.ydata)
164            zpos = Data['Layer']
165            if '100' in Data['Zone']:
166                HKLtxt = '(%3d,%3d,%3d)'%(zpos,xpos,ypos)
167            elif '010' in Data['Zone']:
168                HKLtxt = '(%3d,%3d,%3d)'%(xpos,zpos,ypos)
169            elif '001' in Data['Zone']:
170                HKLtxt = '(%3d,%3d,%3d)'%(xpos,ypos,zpos)
171            Page.canvas.SetToolTipString(HKLtxt)
172            self.G2plotNB.status.SetFields(['HKL = '+HKLtxt,''])
173               
174    def OnSCPick(event):
175        zpos = Data['Layer']
176        pos = event.artist.center
177        if '100' in Data['Zone']:
178            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(zpos,pos[0],pos[1]))
179            hkl = np.array([zpos,pos[0],pos[1]])
180        elif '010' in Data['Zone']:
181            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],zpos,pos[1]))
182            hkl = np.array([pos[0],zpos,pos[1]])
183        elif '001' in Data['Zone']:
184            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],pos[1],zpos))
185            hkl = np.array([pos[0],pos[1],zpos])
186        h,k,l = hkl
187        hklf = HKLF[np.where(np.all(HKL-hkl == [0,0,0],axis=1))]
188        if len(hklf):
189            Fosq,sig,Fcsq = hklf[0]
190            HKLtxt = '(%3d,%3d,%3d %.2f %.3f %.2f %.2f)'%(h,k,l,Fosq,sig,Fcsq,(Fosq-Fcsq)/(scale*sig))
191            self.G2plotNB.status.SetFields(['','HKL, Fosq, sig, Fcsq, delFsq/sig = '+HKLtxt])
192                                 
193    def OnSCKeyPress(event):
194        print event.key
195
196    try:
197        plotNum = self.G2plotNB.plotList.index('Structure Factors')
198        Page = self.G2plotNB.nb.GetPage(plotNum)
199        if not newPlot:
200            Plot = Page.figure.gca()          #get previous powder plot & get limits
201            xylim = Plot.get_xlim(),Plot.get_ylim()
202        Page.figure.clf()
203        Plot = Page.figure.gca()          #get a fresh plot after clf()
204    except ValueError:
205        Plot = self.G2plotNB.addMpl('Structure Factors').gca()
206        plotNum = self.G2plotNB.plotList.index('Structure Factors')
207        Page = self.G2plotNB.nb.GetPage(plotNum)
208#        Page.canvas.mpl_connect('key_press_event', OnSCKeyPress)
209        Page.canvas.mpl_connect('pick_event', OnSCPick)
210        Page.canvas.mpl_connect('motion_notify_event', OnSCMotion)
211    Page.SetFocus()
212   
213    Plot.set_aspect(aspect='equal')
214    HKLref = self.PatternTree.GetItemPyData(self.Sngl)
215    Data = self.PatternTree.GetItemPyData( \
216        G2gd.GetPatternTreeItemId(self,self.Sngl, 'HKL Plot Controls'))
217    Type = Data['Type']           
218    scale = Data['Scale']
219    HKLmax = Data['HKLmax']
220    HKLmin = Data['HKLmin']
221    FosqMax = Data['FoMax']
222    FoMax = math.sqrt(FosqMax)
223    ifFc = Data['ifFc']
224    xlabel = ['k, h=','h, k=','h, l=']
225    ylabel = ['l','l','k']
226    zones = ['100','010','001']
227    pzone = [[1,2],[0,2],[0,1]]
228    izone = zones.index(Data['Zone'])
229    Plot.set_title(self.PatternTree.GetItemText(self.Sngl)[5:])
230    HKL = []
231    HKLF = []
232    for H,Fosq,sig,Fcsq,x,x,x in HKLref:
233        HKL.append(H)
234        HKLF.append([Fosq,sig,Fcsq])
235        if H[izone] == Data['Layer']:
236            B = 0
237            if Type == 'Fosq':
238                A = scale*Fosq/FosqMax
239                B = scale*Fcsq/FosqMax
240                C = abs(A-B)
241            elif Type == 'Fo':
242                A = scale*math.sqrt(max(0,Fosq))/FoMax
243                B = scale*math.sqrt(max(0,Fcsq))/FoMax
244                C = abs(A-B)
245            elif Type == '|DFsq|/sig':
246                A = abs(Fosq-Fcsq)/(scale*sig)
247            elif Type == '|DFsq|>sig':
248                A = abs(Fosq-Fcsq)/(scale*sig)
249                if A < 1.0: A = 0                   
250            elif Type == '|DFsq|>3sig':
251                A = abs(Fosq-Fcsq)/(scale*sig)
252                if A < 3.0: A = 0                   
253            xy = (H[pzone[izone][0]],H[pzone[izone][1]])
254            if A > 0.0:
255                Plot.add_artist(Circle(xy,radius=A,ec='g',fc='w',picker=3))
256            if B:
257                Plot.add_artist(Circle(xy,radius=B,ec='b',fc='w'))
258                radius = C
259                if radius > 0:
260                    if A > B:
261                        Plot.add_artist(Circle(xy,radius=radius,ec='g',fc='g'))
262                    else:                   
263                        Plot.add_artist(Circle(xy,radius=radius,ec='r',fc='r'))
264    HKL = np.array(HKL,dtype=np.int)
265    HKLF = np.array(HKLF)
266    Plot.set_xlabel(xlabel[izone]+str(Data['Layer']),fontsize=12)
267    Plot.set_ylabel(ylabel[izone],fontsize=12)
268    Plot.set_xlim((HKLmin[pzone[izone][0]],HKLmax[pzone[izone][0]]))
269    Plot.set_ylim((HKLmin[pzone[izone][1]],HKLmax[pzone[izone][1]]))
270    if not newPlot:
271        Page.toolbar.push_current()
272        Plot.set_xlim(xylim[0])
273        Plot.set_ylim(xylim[1])
274        xylim = []
275        Page.toolbar.push_current()
276        Page.toolbar.draw()
277    else:
278        Page.canvas.draw()
279       
280def PlotPatterns(self,newPlot=False):
281    global HKL
282   
283    def OnPick(event):
284        if self.itemPicked is not None: return
285        PatternId = self.PatternId
286        try:
287            Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.PatternId, 'Instrument Parameters'))[1::2]
288        except TypeError:
289            return
290        Parms = dict(zip(Names,Values))
291        try:
292            wave = Parms['Lam']
293        except KeyError:
294            wave = Parms['Lam1']
295        PickId = self.PickId
296        pick = event.artist
297        mouse = event.mouseevent       
298        xpos = pick.get_xdata()
299        ypos = pick.get_ydata()
300        ind = event.ind
301        xy = list(zip(np.take(xpos,ind),np.take(ypos,ind))[0])
302        if self.PatternTree.GetItemText(PickId) == 'Peak List':
303            if ind.all() != [0]:                                    #picked a data point
304                ins = [Parms[x] for x in ['U','V','W','X','Y','SH/L']]
305                if self.qPlot:                              #qplot - convert back to 2-theta
306                    xy[0] = 2.0*asind(xy[0]*wave/(4*math.pi))
307                sig = ins[0]*tand(xy[0]/2.0)**2+ins[1]*tand(xy[0]/2.0)+ins[2]
308                gam = ins[3]/cosd(xy[0]/2.0)+ins[4]*tand(xy[0]/2.0)           
309                data = self.PatternTree.GetItemPyData(self.PickId)
310                XY = [xy[0],0, xy[1],1, sig,0, gam,0]       #default refine intensity 1st
311                data.append(XY)
312                G2pdG.UpdatePeakGrid(self,data)
313                PlotPatterns(self)
314            else:                                                   #picked a peak list line
315                self.itemPicked = pick
316        elif self.PatternTree.GetItemText(PickId) == 'Limits':
317            if ind.all() != [0]:                                    #picked a data point
318                LimitId = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
319                data = self.PatternTree.GetItemPyData(LimitId)
320                if self.qPlot:                              #qplot - convert back to 2-theta
321                    xy[0] = 2.0*asind(xy[0]*wave/(4*math.pi))
322                if mouse.button==1:
323                    data[1][0] = min(xy[0],data[1][1])
324                if mouse.button==3:
325                    data[1][1] = max(xy[0],data[1][0])
326                self.PatternTree.SetItemPyData(LimitId,data)
327                G2pdG.UpdateLimitsGrid(self,data)
328                PlotPatterns(self)
329            else:                                                   #picked a limit line
330                self.itemPicked = pick
331       
332    def OnPlotKeyPress(event):
333        newPlot = False
334        if event.key == 'w':
335            if self.Weight:
336                self.Weight = False
337            else:
338                self.Weight = True
339            print 'plot weighting:',self.Weight
340        elif event.key == 'n':
341            if self.Contour:
342                pass
343            else:
344                if self.logPlot:
345                    self.logPlot = False
346                else:
347                    self.Offset[0] = 0
348                    self.logPlot = True
349        elif event.key == 'u':
350            if self.Contour:
351                self.Cmax = min(1.0,self.Cmax*1.2)
352            elif self.logPlot:
353                pass
354            elif self.Offset[0] < 100.:
355                self.Offset[0] += 1.
356        elif event.key == 'd':
357            if self.Contour:
358                self.Cmax = max(0.0,self.Cmax*0.8)
359            elif self.logPlot:
360                pass
361            elif self.Offset[0] > 0.:
362                self.Offset[0] -= 1.
363        elif event.key == 'l':
364            self.Offset[1] -= 1.
365        elif event.key == 'r':
366            self.Offset[1] += 1.
367        elif event.key == 'o':
368            self.Offset = [0,0]
369        elif event.key == 'c':
370            newPlot = True
371            if self.Contour:
372                self.Contour = False
373            else:
374                self.Contour = True
375                self.SinglePlot = False
376                self.Offset = [0.,0.]
377        elif event.key == 'q':
378            newPlot = True
379            if self.qPlot:
380                self.qPlot = False
381            else:
382                self.qPlot = True
383        elif event.key == 's':
384            if self.Contour:
385                choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
386                dlg = wx.SingleChoiceDialog(self,'Select','Color scheme',choice)
387                if dlg.ShowModal() == wx.ID_OK:
388                    sel = dlg.GetSelection()
389                    self.ContourColor = choice[sel]
390                else:
391                    self.ContourColor = 'Paired'
392                dlg.Destroy()
393            else:               
394                if self.SinglePlot:
395                    self.SinglePlot = False
396                else:
397                    self.SinglePlot = True
398        elif event.key == '+':
399            if self.PickId:
400                self.PickId = False
401        elif event.key == 'i':                  #for smoothing contour plot
402            choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
403               'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
404               'mitchell','sinc','lanczos']
405            dlg = wx.SingleChoiceDialog(self,'Select','Interpolation',choice)
406            if dlg.ShowModal() == wx.ID_OK:
407                sel = dlg.GetSelection()
408                self.Interpolate = choice[sel]
409            else:
410                self.Interpolate = 'nearest'
411            dlg.Destroy()
412           
413        PlotPatterns(self,newPlot=newPlot)
414       
415    def OnKeyBox(event):
416        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index('Powder Patterns'):
417            event.key = cb.GetValue()[0]
418            cb.SetValue(' key press')
419            OnPlotKeyPress(event)
420                       
421    def OnMotion(event):
422        xpos = event.xdata
423        if xpos:                                        #avoid out of frame mouse position
424            ypos = event.ydata
425            Page.canvas.SetCursor(wx.CROSS_CURSOR)
426            try:
427                Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.PatternId, 'Instrument Parameters'))[1::2]
428                Parms = dict(zip(Names,Values))
429                try:
430                    wave = Parms['Lam']
431                except KeyError:
432                    wave = Parms['Lam1']
433                if self.qPlot:
434                    xpos = 2.0*asind(xpos*wave/(4*math.pi))
435                dsp = 0.0
436                if abs(xpos) > 0.:                  #avoid possible singularity at beam center
437                    dsp = wave/(2.*sind(abs(xpos)/2.0))
438                if self.Contour:
439                    self.G2plotNB.status.SetStatusText('2-theta =%9.3f d =%9.5f pattern ID =%5d'%(xpos,dsp,int(ypos)),1)
440                else:
441                    self.G2plotNB.status.SetStatusText('2-theta =%9.3f d =%9.5f Intensity =%9.1f'%(xpos,dsp,ypos),1)
442                if self.itemPicked:
443                    Page.canvas.SetToolTipString('%9.3f'%(xpos))
444                if self.PickId and self.PatternTree.GetItemText(self.PickId) in ['Index Peak List','Unit Cells List']:
445                    found = []
446                    if len(HKL):
447                        view = Page.toolbar._views.forward()[0][:2]
448                        wid = view[1]-view[0]
449                        found = HKL[np.where(np.fabs(HKL.T[5]-xpos) < 0.002*wid)]
450                    if len(found):
451                        h,k,l = found[0][:3] 
452                        Page.canvas.SetToolTipString('%d,%d,%d'%(int(h),int(k),int(l)))
453                    else:
454                        Page.canvas.SetToolTipString('')
455
456            except TypeError:
457                self.G2plotNB.status.SetStatusText('Select PWDR powder pattern first',1)
458                                                   
459    def OnRelease(event):
460        if self.itemPicked is None: return
461        Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.PatternId, 'Instrument Parameters'))[1::2]
462        Parms = dict(zip(Names,Values))
463        try:
464            wave = Parms['Lam']
465        except KeyError:
466            wave = Parms['Lam1']
467        xpos = event.xdata
468        if xpos:                                        #avoid out of frame mouse position
469            lines = []
470            for line in self.Lines: lines.append(line.get_xdata()[0])
471            lineNo = lines.index(self.itemPicked.get_xdata()[0])
472            if  lineNo in [0,1]:
473                LimitId = G2gd.GetPatternTreeItemId(self,self.PatternId, 'Limits')
474                data = self.PatternTree.GetItemPyData(LimitId)
475#                print 'limits',xpos
476                if self.qPlot:
477                    data[1][lineNo] = 2.0*asind(wave*xpos/(4*math.pi))
478                else:
479                    data[1][lineNo] = xpos
480                self.PatternTree.SetItemPyData(LimitId,data)
481                if self.PatternTree.GetItemText(self.PickId) == 'Limits':
482                    G2pdG.UpdateLimitsGrid(self,data)
483            else:
484                PeakId = G2gd.GetPatternTreeItemId(self,self.PatternId, 'Peak List')
485                data = self.PatternTree.GetItemPyData(PeakId)
486#                print 'peaks',xpos
487                if event.button == 3:
488                    del data[lineNo-2]
489                else:
490                    if self.qPlot:
491                        data[lineNo-2][0] = 2.0*asind(wave*xpos/(4*math.pi))
492                    else:
493                        data[lineNo-2][0] = xpos
494                self.PatternTree.SetItemPyData(PeakId,data)
495                G2pdG.UpdatePeakGrid(self,data)
496        PlotPatterns(self)
497        self.itemPicked = None   
498
499    xylim = []
500    try:
501        plotNum = self.G2plotNB.plotList.index('Powder Patterns')
502        Page = self.G2plotNB.nb.GetPage(plotNum)
503        if not newPlot:
504            Plot = Page.figure.gca()          #get previous powder plot & get limits
505            xylim = Plot.get_xlim(),Plot.get_ylim()
506        Page.figure.clf()
507        Plot = Page.figure.gca()          #get a fresh plot after clf()
508    except ValueError:
509        newPlot = True
510        self.Cmax = 1.0
511        Plot = self.G2plotNB.addMpl('Powder Patterns').gca()
512        plotNum = self.G2plotNB.plotList.index('Powder Patterns')
513        Page = self.G2plotNB.nb.GetPage(plotNum)
514        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
515        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
516        Page.canvas.mpl_connect('pick_event', OnPick)
517        Page.canvas.mpl_connect('button_release_event', OnRelease)
518    Page.SetFocus()
519    self.G2plotNB.status.DestroyChildren()
520    if self.Contour:
521        Choice = (' key press','d: lower contour max','u: raise contour max',
522            'i: interpolation method','s: color scheme','c: contour off')
523    else:
524        if self.logPlot:
525            Choice = (' key press','n: log(I) off','l: offset left','r: offset right',
526                'c: contour on','q: toggle q plot','s: toggle single plot','+: no selection')
527        else:
528            Choice = (' key press','l: offset left','r: offset right','d: offset down',
529                'u: offset up','0: reset offset','n: log(I) on','c: contour on',
530                'q: toggle q plot','s: toggle single plot','+: no selection')
531    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
532        choices=Choice)
533    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
534    cb.SetValue(' key press')
535   
536    PickId = self.PickId
537    PatternId = self.PatternId
538    colors=['b','g','r','c','m','k']
539    Lines = []
540    if self.SinglePlot:
541        Pattern = self.PatternTree.GetItemPyData(PatternId)
542        Pattern.append(self.PatternTree.GetItemText(PatternId))
543        PlotList = [Pattern,]
544        ParmList = [self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,
545            self.PatternId, 'Instrument Parameters'))[1],]
546    else:       
547        PlotList = []
548        ParmList = []
549        item, cookie = self.PatternTree.GetFirstChild(self.root)
550        while item:
551            if 'PWDR' in self.PatternTree.GetItemText(item):
552                Pattern = self.PatternTree.GetItemPyData(item)
553                if len(Pattern) < 3:                    # put name on end if needed
554                    Pattern.append(self.PatternTree.GetItemText(item))
555                PlotList.append(Pattern)
556                ParmList.append(self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,
557                    item,'Instrument Parameters'))[1])
558            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
559    Ymax = 1.0
560    lenX = 0
561    HKL = np.array(self.HKL)
562    for Pattern in PlotList:
563        xye = Pattern[1]
564        Ymax = max(Ymax,max(xye[1]))
565    offset = self.Offset[0]*Ymax/100.0
566    Title = 'Powder Patterns: '+os.path.split(self.GSASprojectfile)[1]
567    if self.logPlot:
568        Title = 'log('+Title+')'
569    Plot.set_title(Title)
570    if self.qPlot:
571        Plot.set_xlabel(r'$q, \AA^{-1}$',fontsize=14)
572    else:       
573        Plot.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
574    Plot.set_ylabel('Intensity',fontsize=12)
575    if self.Contour:
576        ContourZ = []
577        ContourY = []
578        Nseq = 0
579    for N,Pattern in enumerate(PlotList):
580        Parms = ParmList[N]
581        ifpicked = False
582        LimitId = 0
583        xye = np.array(Pattern[1])
584        if PickId:
585            ifpicked = Pattern[2] == self.PatternTree.GetItemText(PatternId)
586            LimitId = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
587        if self.qPlot:
588            Id = G2gd.GetPatternTreeItemId(self,self.root, Pattern[2])
589            X = 4*np.pi*npsind(xye[0]/2.0)/Parms[1]
590        else:
591            X = xye[0]
592        if not lenX:
593            lenX = len(X)           
594        Y = xye[1]+offset*N
595        if LimitId:
596            limits = np.array(self.PatternTree.GetItemPyData(LimitId))
597            if self.qPlot:
598                limits = 4*np.pi*npsind(limits/2.0)/Parms[1]
599            Lines.append(Plot.axvline(limits[1][0],color='g',dashes=(5,5),picker=3.))   
600            Lines.append(Plot.axvline(limits[1][1],color='r',dashes=(5,5),picker=3.))                   
601        if self.Contour:
602           
603            if lenX == len(X):
604                ContourY.append(N)
605                ContourZ.append(Y)
606                ContourX = X
607                Nseq += 1
608                Plot.set_ylabel('Data sequence',fontsize=12)
609        else:
610            X += self.Offset[1]*.005*N
611            if ifpicked:
612                Z = xye[3]+offset*N
613                W = xye[4]+offset*N
614                D = xye[5]+offset*N-Ymax*.02
615                if self.Weight:
616                    W2 = np.sqrt(xye[2])
617                    D *= W2-Ymax*.02
618                if self.logPlot:
619                    Plot.semilogy(X,Y,colors[N%6]+'+',picker=3.,clip_on=False,nonposy='mask')
620                    Plot.semilogy(X,Z,colors[(N+1)%6],picker=False,nonposy='mask')
621                    Plot.semilogy(X,W,colors[(N+2)%6],picker=False,nonposy='mask')
622                else:
623                    Plot.plot(X,Y,colors[N%6]+'+',picker=3.,clip_on=False)
624                    Plot.plot(X,Z,colors[(N+1)%6],picker=False)
625                    Plot.plot(X,W,colors[(N+2)%6],picker=False)
626                    Plot.plot(X,D,colors[(N+3)%6],picker=False)
627                    Plot.axhline(0.,color=wx.BLACK)
628                Page.canvas.SetToolTipString('')
629                if self.PatternTree.GetItemText(PickId) == 'Peak List':
630                    tip = 'On data point: Pick peak - L or R MB. On line: L-move, R-delete'
631                    Page.canvas.SetToolTipString(tip)
632                    data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Peak List'))
633                    for item in data:
634                        if self.qPlot:
635                            Lines.append(Plot.axvline(4*math.pi*sind(item[0]/2.)/Parms[1],color=colors[N%6],picker=2.))
636                        else:
637                            Lines.append(Plot.axvline(item[0],color=colors[N%6],picker=2.))
638                if self.PatternTree.GetItemText(PickId) == 'Limits':
639                    tip = 'On data point: Lower limit - L MB; Upper limit - R MB. On limit: MB down to move'
640                    Page.canvas.SetToolTipString(tip)
641                    data = self.LimitsTable.GetData()
642            else:
643                if self.logPlot:
644                    Plot.semilogy(X,Y,colors[N%6],picker=False,nonposy='clip')
645                else:
646                    Plot.plot(X,Y,colors[N%6],picker=False)
647    if PickId and self.PatternTree.GetItemText(PickId) in ['Index Peak List','Unit Cells List']:
648        Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Instrument Parameters'))[1::2]
649        Parms = dict(zip(Names,Values))
650        try:
651            wave = Parms['Lam']
652        except KeyError:
653            wave = Parms['Lam1']
654        peaks = np.array((self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Index Peak List'))))
655        for peak in peaks:
656            if self.qPlot:
657                Plot.axvline(4*np.pi*sind(peak[0]/2.0)/wave,color='b')
658            else:
659                Plot.axvline(peak[0],color='b')
660        for hkl in self.HKL:
661            if self.qPlot:
662                Plot.axvline(4*np.pi*sind(hkl[5]/2.0)/wave,color='r',dashes=(5,5))
663            else:
664                Plot.axvline(hkl[5],color='r',dashes=(5,5))
665    if self.Contour:
666        acolor = mpl.cm.get_cmap(self.ContourColor)
667        Img = Plot.imshow(ContourZ,cmap=acolor,vmin=0,vmax=Ymax*self.Cmax,interpolation=self.Interpolate, 
668            extent=[ContourX[0],ContourX[-1],ContourY[0],ContourY[-1]],aspect='auto',origin='lower')
669        Page.figure.colorbar(Img)
670    else:
671        self.Lines = Lines
672    if not newPlot:
673        Page.toolbar.push_current()
674        Plot.set_xlim(xylim[0])
675        Plot.set_ylim(xylim[1])
676        xylim = []
677        Page.toolbar.push_current()
678        Page.toolbar.draw()
679    else:
680        Page.canvas.draw()
681    self.Pwdr = True
682   
683def PlotISFG(self,newPlot=False,type=''):
684    if not type:
685        type = self.G2plotNB.plotList[self.G2plotNB.nb.GetSelection()]
686    if type not in ['I(Q)','S(Q)','F(Q)','G(R)']:
687        return
688    superMinusOne = unichr(0xaf)+unichr(0xb9)
689   
690    def OnPlotKeyPress(event):
691        newPlot = False
692        if event.key == 'u':
693            if self.Contour:
694                self.Cmax = min(1.0,self.Cmax*1.2)
695            elif self.Offset[0] < 100.:
696                self.Offset[0] += 1.
697        elif event.key == 'd':
698            if self.Contour:
699                self.Cmax = max(0.0,self.Cmax*0.8)
700            elif self.Offset[0] > 0.:
701                self.Offset[0] -= 1.
702        elif event.key == 'l':
703            self.Offset[1] -= 1.
704        elif event.key == 'r':
705            self.Offset[1] += 1.
706        elif event.key == 'o':
707            self.Offset = [0,0]
708        elif event.key == 'c':
709            newPlot = True
710            if self.Contour:
711                self.Contour = False
712            else:
713                self.Contour = True
714                self.SinglePlot = False
715                self.Offset = [0.,0.]
716        elif event.key == 's':
717            if self.Contour:
718                choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
719                dlg = wx.SingleChoiceDialog(self,'Select','Color scheme',choice)
720                if dlg.ShowModal() == wx.ID_OK:
721                    sel = dlg.GetSelection()
722                    self.ContourColor = choice[sel]
723                else:
724                    self.ContourColor = 'Paired'
725                dlg.Destroy()
726            else:               
727                if self.SinglePlot:
728                    self.SinglePlot = False
729                else:
730                    self.SinglePlot = True
731        elif event.key == 'i':                  #for smoothing contour plot
732            choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
733               'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
734               'mitchell','sinc','lanczos']
735            dlg = wx.SingleChoiceDialog(self,'Select','Interpolation',choice)
736            if dlg.ShowModal() == wx.ID_OK:
737                sel = dlg.GetSelection()
738                self.Interpolate = choice[sel]
739            else:
740                self.Interpolate = 'nearest'
741            dlg.Destroy()
742        elif event.key == 't' and not self.Contour:
743            if self.Legend:
744                self.Legend = False
745            else:
746                self.Legend = True
747           
748           
749        PlotISFG(self,newPlot=newPlot,type=type)
750       
751    def OnKeyBox(event):
752        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index(type):
753            event.key = cb.GetValue()[0]
754            cb.SetValue(' key press')
755            OnPlotKeyPress(event)
756                       
757    def OnMotion(event):
758        xpos = event.xdata
759        if xpos:                                        #avoid out of frame mouse position
760            ypos = event.ydata
761            Page.canvas.SetCursor(wx.CROSS_CURSOR)
762            try:
763                if self.Contour:
764                    self.G2plotNB.status.SetStatusText('R =%.3fA pattern ID =%5d'%(xpos,int(ypos)),1)
765                else:
766                    self.G2plotNB.status.SetStatusText('R =%.3fA %s =%.2f'%(xpos,type,ypos),1)                   
767            except TypeError:
768                self.G2plotNB.status.SetStatusText('Select '+type+' pattern first',1)
769   
770    xylim = []
771    try:
772        plotNum = self.G2plotNB.plotList.index(type)
773        Page = self.G2plotNB.nb.GetPage(plotNum)
774        if not newPlot:
775            Plot = Page.figure.gca()          #get previous plot & get limits
776            xylim = Plot.get_xlim(),Plot.get_ylim()
777        Page.figure.clf()
778        Plot = Page.figure.gca()
779    except ValueError:
780        newPlot = True
781        self.Cmax = 1.0
782        Plot = self.G2plotNB.addMpl(type).gca()
783        plotNum = self.G2plotNB.plotList.index(type)
784        Page = self.G2plotNB.nb.GetPage(plotNum)
785        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
786        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
787   
788    Page.SetFocus()
789    self.G2plotNB.status.DestroyChildren()
790    if self.Contour:
791        Choice = (' key press','d: lower contour max','u: raise contour max',
792            'i: interpolation method','s: color scheme','c: contour off')
793    else:
794        Choice = (' key press','l: offset left','r: offset right','d: offset down','u: offset up',
795            'o: reset offset','t: toggle legend','c: contour on','s: toggle single plot')
796    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
797        choices=Choice)
798    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
799    cb.SetValue(' key press')
800    PatternId = self.PatternId
801    PickId = self.PickId
802    Plot.set_title(type)
803    if type == 'G(R)':
804        Plot.set_xlabel(r'$R,\AA$',fontsize=14)
805    else:
806        Plot.set_xlabel(r'$Q,\AA$'+superMinusOne,fontsize=14)
807    Plot.set_ylabel(r''+type,fontsize=14)
808    colors=['b','g','r','c','m','k']
809    name = self.PatternTree.GetItemText(PatternId)[4:]
810    Pattern = []   
811    if self.SinglePlot:
812        name = self.PatternTree.GetItemText(PatternId)
813        name = type+name[4:]
814        Id = G2gd.GetPatternTreeItemId(self,PatternId,name)
815        Pattern = self.PatternTree.GetItemPyData(Id)
816        if Pattern:
817            Pattern.append(name)
818        PlotList = [Pattern,]
819    else:
820        PlotList = []
821        item, cookie = self.PatternTree.GetFirstChild(self.root)
822        while item:
823            if 'PDF' in self.PatternTree.GetItemText(item):
824                name = type+self.PatternTree.GetItemText(item)[4:]
825                Id = G2gd.GetPatternTreeItemId(self,item,name)
826                Pattern = self.PatternTree.GetItemPyData(Id)
827                if Pattern:
828                    Pattern.append(name)
829                    PlotList.append(Pattern)
830            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
831    PDFdata = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'PDF Controls'))
832    numbDen = G2pwd.GetNumDensity(PDFdata['ElList'],PDFdata['Form Vol'])
833    Xb = [0.,10.]
834    Yb = [0.,-40.*np.pi*numbDen]
835    Ymax = 1.0
836    lenX = 0
837    for Pattern in PlotList:
838        xye = Pattern[1]
839        Ymax = max(Ymax,max(xye[1]))
840    offset = self.Offset[0]*Ymax/100.0
841    if self.Contour:
842        ContourZ = []
843        ContourY = []
844        Nseq = 0
845    for N,Pattern in enumerate(PlotList):
846        xye = Pattern[1]
847        if PickId:
848            ifpicked = Pattern[2] == self.PatternTree.GetItemText(PatternId)
849        X = xye[0]
850        if not lenX:
851            lenX = len(X)           
852        Y = xye[1]+offset*N
853        if self.Contour:
854            if lenX == len(X):
855                ContourY.append(N)
856                ContourZ.append(Y)
857                ContourX = X
858                Nseq += 1
859                Plot.set_ylabel('Data sequence',fontsize=12)
860        else:
861            X = xye[0]+self.Offset[1]*.005*N
862            if ifpicked:
863                Plot.plot(X,Y,colors[N%6]+'+',picker=3.,clip_on=False)
864                Page.canvas.SetToolTipString('')
865            else:
866                if self.Legend:
867                    Plot.plot(X,Y,colors[N%6],picker=False,label='Azm:'+Pattern[2].split('=')[1])
868                else:
869                    Plot.plot(X,Y,colors[N%6],picker=False)
870            if type == 'G(R)':
871                Plot.plot(Xb,Yb,color='k',dashes=(5,5))
872            elif type == 'F(Q)':
873                Plot.axhline(0.,color=wx.BLACK)
874            elif type == 'S(Q)':
875                Plot.axhline(1.,color=wx.BLACK)
876    if self.Contour:
877        acolor = mpl.cm.get_cmap(self.ContourColor)
878        Img = Plot.imshow(ContourZ,cmap=acolor,vmin=0,vmax=Ymax*self.Cmax,interpolation=self.Interpolate, 
879            extent=[ContourX[0],ContourX[-1],ContourY[0],ContourY[-1]],aspect='auto',origin='lower')
880        Page.figure.colorbar(Img)
881    elif self.Legend:
882        Plot.legend(loc='best')
883    if not newPlot:
884        Page.toolbar.push_current()
885        Plot.set_xlim(xylim[0])
886        Plot.set_ylim(xylim[1])
887        xylim = []
888        Page.toolbar.push_current()
889        Page.toolbar.draw()
890    else:
891        Page.canvas.draw()
892       
893def PlotXY(self,XY,newPlot=False,type=''):
894    #simple plot of xy data
895
896    def OnMotion(event):
897        xpos = event.xdata
898        if xpos:                                        #avoid out of frame mouse position
899            ypos = event.ydata
900            Page.canvas.SetCursor(wx.CROSS_CURSOR)
901            try:
902                self.G2plotNB.status.SetStatusText('X =%9.3f %s =%9.3f'%(xpos,type,ypos),1)                   
903            except TypeError:
904                self.G2plotNB.status.SetStatusText('Select '+type+' pattern first',1)
905
906    try:
907        plotNum = self.G2plotNB.plotList.index(type)
908        Page = self.G2plotNB.nb.GetPage(plotNum)
909        if not newPlot:
910            Plot = Page.figure.gca()
911            xylim = Plot.get_xlim(),Plot.get_ylim()
912        Page.figure.clf()
913        Plot = Page.figure.gca()
914    except ValueError:
915        newPlot = True
916        Plot = self.G2plotNB.addMpl(type).gca()
917        plotNum = self.G2plotNB.plotList.index(type)
918        Page = self.G2plotNB.nb.GetPage(plotNum)
919        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
920   
921    Page.SetFocus()
922    self.G2plotNB.status.DestroyChildren()
923    Plot.set_title(type)
924    Plot.set_xlabel(r'X',fontsize=14)
925    Plot.set_ylabel(r''+type,fontsize=14)
926    colors=['b','g','r','c','m','k']
927    Ymax = 1.0
928    lenX = 0
929    X,Y = XY[:2]
930    Ymax = max(Ymax,max(Y))
931    Plot.plot(X,Y,'k',picker=False)
932    if not newPlot:
933        Page.toolbar.push_current()
934        Plot.set_xlim(xylim[0])
935        Plot.set_ylim(xylim[1])
936        xylim = []
937        Page.toolbar.push_current()
938        Page.toolbar.draw()
939    else:
940        Page.canvas.draw()
941
942def PlotPowderLines(self):
943    global HKL
944
945    def OnMotion(event):
946        xpos = event.xdata
947        if xpos:                                        #avoid out of frame mouse position
948            Page.canvas.SetCursor(wx.CROSS_CURSOR)
949            self.G2plotNB.status.SetFields(['','2-theta =%9.3f '%(xpos,)])
950            if self.PickId and self.PatternTree.GetItemText(self.PickId) in ['Index Peak List','Unit Cells List']:
951                found = []
952                if len(HKL):
953                    view = Page.toolbar._views.forward()[0][:2]
954                    wid = view[1]-view[0]
955                    found = HKL[np.where(np.fabs(HKL.T[5]-xpos) < 0.002*wid)]
956                if len(found):
957                    h,k,l = found[0][:3] 
958                    Page.canvas.SetToolTipString('%d,%d,%d'%(int(h),int(k),int(l)))
959                else:
960                    Page.canvas.SetToolTipString('')
961
962    try:
963        plotNum = self.G2plotNB.plotList.index('Powder Lines')
964        Page = self.G2plotNB.nb.GetPage(plotNum)
965        Page.figure.clf()
966        Plot = Page.figure.gca()
967    except ValueError:
968        Plot = self.G2plotNB.addMpl('Powder Lines').gca()
969        plotNum = self.G2plotNB.plotList.index('Powder Lines')
970        Page = self.G2plotNB.nb.GetPage(plotNum)
971        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
972       
973    Page.SetFocus()
974    Plot.set_title('Powder Pattern Lines')
975    Plot.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
976    PickId = self.PickId
977    PatternId = self.PatternId
978    peaks = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Index Peak List'))
979    for peak in peaks:
980        Plot.axvline(peak[0],color='b')
981    HKL = np.array(self.HKL)
982    for hkl in self.HKL:
983        Plot.axvline(hkl[5],color='r',dashes=(5,5))
984    xmin = peaks[0][0]
985    xmax = peaks[-1][0]
986    delt = xmax-xmin
987    xlim = [max(0,xmin-delt/20.),min(180.,xmax+delt/20.)]
988    Plot.set_xlim(xlim)
989    Page.canvas.draw()
990
991def PlotPeakWidths(self):
992    PatternId = self.PatternId
993    limitID = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
994    if limitID:
995        limits = self.PatternTree.GetItemPyData(limitID)
996    else:
997        return
998    instParms = self.PatternTree.GetItemPyData( \
999        G2gd.GetPatternTreeItemId(self,PatternId, 'Instrument Parameters'))
1000    if instParms[0][0] == 'PXC':
1001        lam = instParms[1][1]
1002        if len(instParms[1]) == 13:
1003            GU,GV,GW,LX,LY = instParms[0][6:11]
1004        else:
1005            GU,GV,GW,LX,LY = instParms[0][4:9]
1006    peakID = G2gd.GetPatternTreeItemId(self,PatternId, 'Peak List')
1007    if peakID:
1008        peaks = self.PatternTree.GetItemPyData(peakID)
1009    else:
1010        peaks = []
1011   
1012    try:
1013        plotNum = self.G2plotNB.plotList.index('Peak Widths')
1014        Page = self.G2plotNB.nb.GetPage(plotNum)
1015        Page.figure.clf()
1016        Plot = Page.figure.gca()
1017    except ValueError:
1018        Plot = self.G2plotNB.addMpl('Peak Widths').gca()
1019        plotNum = self.G2plotNB.plotList.index('Peak Widths')
1020        Page = self.G2plotNB.nb.GetPage(plotNum)
1021    Page.SetFocus()
1022   
1023    Page.canvas.SetToolTipString('')
1024    colors=['b','g','r','c','m','k']
1025    Xmin,Xmax = limits[1]
1026    Xmin = min(0.5,max(Xmin,1))
1027    Xmin /= 2
1028    Xmax /= 2
1029    nPts = 100
1030    delt = (Xmax-Xmin)/nPts
1031    thetas = []
1032    for i in range(nPts):
1033        thetas.append(Xmin+i*delt)
1034    X = []
1035    Y = []
1036    Z = []
1037    W = []
1038    V = []
1039    sig = lambda Th,U,V,W: 1.17741*math.sqrt(U*tand(Th)**2+V*tand(Th)+W)*math.pi/18000.
1040    gam = lambda Th,X,Y: (X/cosd(Th)+Y*tand(Th))*math.pi/18000.
1041    gamFW = lambda s,g: math.exp(math.log(s**5+2.69269*s**4*g+2.42843*s**3*g**2+4.47163*s**2*g**3+0.07842*s*g**4+g**5)/5.)
1042    gamFW2 = lambda s,g: math.sqrt(s**2+(0.4654996*g)**2)+.5345004*#Ubaldo Bafile - private communication
1043    for theta in thetas:
1044        X.append(4.0*math.pi*sind(theta)/lam)              #q
1045        s = sig(theta,GU,GV,GW)
1046        g = gam(theta,LX,LY)
1047        G = gamFW(g,s)
1048        H = gamFW2(g,s)
1049        Y.append(s/tand(theta))
1050        Z.append(g/tand(theta))
1051        W.append(G/tand(theta))
1052        V.append(H/tand(theta))
1053    Plot.set_title('Instrument and sample peak widths')
1054    Plot.set_ylabel(r'$\Delta q/q, \Delta d/d$',fontsize=14)
1055    Plot.set_xlabel(r'$q, \AA^{-1}$',fontsize=14)
1056    Plot.plot(X,Y,color='r',label='Gaussian')
1057    Plot.plot(X,Z,color='g',label='Lorentzian')
1058    Plot.plot(X,W,color='b',label='G+L')
1059    Plot.plot(X,V,color='k',label='G+L2')
1060    X = []
1061    Y = []
1062    Z = []
1063    W = []
1064    V = []
1065    for peak in peaks:
1066        X.append(4.0*math.pi*sind(peak[0]/2.0)/lam)
1067        s = 1.17741*math.sqrt(peak[4])*math.pi/18000.
1068        g = peak[6]*math.pi/18000.
1069        G = gamFW(g,s)
1070        H = gamFW2(g,s)
1071        Y.append(s/tand(peak[0]/2.))
1072        Z.append(g/tand(peak[0]/2.))
1073        W.append(G/tand(peak[0]/2.))
1074        V.append(H/tand(peak[0]/2.))
1075    Plot.plot(X,Y,'+',color='r',label='G peak')
1076    Plot.plot(X,Z,'+',color='g',label='L peak')
1077    Plot.plot(X,W,'+',color='b',label='G+L peak')
1078    Plot.plot(X,V,'+',color='k',label='G+L2 peak')
1079    Plot.legend(loc='best')
1080    Page.canvas.draw()
1081   
1082def PlotStrain(self,data):
1083    # in this instance data is for a phase
1084    PatternId = self.PatternId
1085    generalData = data['General']
1086    SGData = generalData['SGData']
1087    MuStrKeys = G2spc.MustrainNames(SGData)
1088    cell = generalData['Cell'][1:]
1089    A,B = G2lat.cell2AB(cell[:6])
1090    Vol = cell[6]
1091    useList = data['Histograms']
1092    numPlots = len(useList)
1093   
1094    try:
1095        plotNum = self.G2plotNB.plotList.index('Microstrain')
1096        Page = self.G2plotNB.nb.GetPage(plotNum)
1097        Page.figure.clf()
1098        Plot = mp3d.Axes3D(Page.figure)
1099    except ValueError:
1100        Plot = mp3d.Axes3D(self.G2plotNB.add3D('Microstrain'))
1101        plotNum = self.G2plotNB.plotList.index('Microstrain')
1102        Page = self.G2plotNB.nb.GetPage(plotNum)
1103    Page.SetFocus()
1104    self.G2plotNB.status.SetStatusText('Adjust frame size to get desired aspect ratio',1)
1105   
1106    for item in useList:
1107        if useList[item]['Show']:
1108            muStrain = useList[item]['Mustrain']
1109            PHI = np.linspace(0.,360.,30,True)
1110            PSI = np.linspace(0.,180.,30,True)
1111            X = np.outer(npsind(PHI),npsind(PSI))
1112            Y = np.outer(npcosd(PHI),npsind(PSI))
1113            Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
1114            if muStrain[0] == 'isotropic':
1115                muiso = muStrain[1][0]*math.pi/0.018      #centidegrees to radians!
1116                X *= muiso
1117                Y *= muiso
1118                Z *= muiso               
1119               
1120            elif muStrain[0] == 'uniaxial':
1121                def uniaxMustrain(xyz,muiso,muaniso,axes):
1122                    cp = abs(np.dot(xyz,axes))
1123                    S = muiso+muaniso*cp
1124                    return S*xyz*math.pi/0.018      #centidegrees to radians!
1125                muiso,muaniso = muStrain[1][:2]
1126                axes = np.inner(A,np.array(muStrain[3]))
1127                axes /= nl.norm(axes)
1128                Shkl = np.array(muStrain[1])
1129                Shape = X.shape[0]
1130                XYZ = np.dstack((X,Y,Z))
1131                XYZ = np.nan_to_num(np.apply_along_axis(uniaxMustrain,2,XYZ,muiso,muaniso,axes))
1132                X,Y,Z = np.dsplit(XYZ,3)
1133                X = X[:,:,0]
1134                Y = Y[:,:,0]
1135                Z = Z[:,:,0]
1136               
1137            elif muStrain[0] == 'generalized':
1138                def genMustrain(xyz,SGData,A,Shkl):
1139                    uvw = np.inner(A.T,xyz)
1140                    Strm = np.array(G2spc.MustrainCoeff(uvw,SGData))
1141                    sum = np.sqrt(np.sum(np.multiply(Shkl,Strm)))*math.pi/0.018      #centidegrees to radians!
1142                    return sum*xyz
1143                Shkl = np.array(muStrain[4])
1144                if np.any(Shkl):
1145                    Shape = X.shape[0]
1146                    XYZ = np.dstack((X,Y,Z))
1147                    XYZ = np.nan_to_num(np.apply_along_axis(genMustrain,2,XYZ,SGData,A,Shkl))
1148                    X,Y,Z = np.dsplit(XYZ,3)
1149                    X = X[:,:,0]
1150                    Y = Y[:,:,0]
1151                    Z = Z[:,:,0]
1152                   
1153            if np.any(X) and np.any(Y) and np.any(Z):
1154                Plot.plot_surface(X,Y,Z,rstride=1,cstride=1,color='g')
1155               
1156            Plot.set_xlabel('X')
1157            Plot.set_ylabel('Y')
1158            Plot.set_zlabel('Z')
1159    Page.canvas.draw()
1160           
1161def PlotExposedImage(self,newPlot=False,event=None):
1162    plotNo = self.G2plotNB.nb.GetSelection()
1163    if self.G2plotNB.nb.GetPageText(plotNo) == '2D Powder Image':
1164        PlotImage(self,newPlot,event,newImage=True)
1165    elif self.G2plotNB.nb.GetPageText(plotNo) == '2D Integration':
1166        PlotIntegration(self,newPlot,event)
1167
1168def PlotImage(self,newPlot=False,event=None,newImage=True):
1169    from matplotlib.patches import Ellipse,Arc,Circle,Polygon
1170    import numpy.ma as ma
1171    Dsp = lambda tth,wave: wave/(2.*sind(tth/2.))
1172    global Data,Masks
1173    colors=['b','g','r','c','m','k']
1174    Data = self.PatternTree.GetItemPyData(
1175        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1176    Masks = self.PatternTree.GetItemPyData(
1177        G2gd.GetPatternTreeItemId(self,self.Image, 'Masks'))
1178
1179    def OnImMotion(event):
1180        Page.canvas.SetToolTipString('')
1181        sizexy = Data['size']
1182        if event.xdata and event.ydata:                 #avoid out of frame errors
1183            Page.canvas.SetCursor(wx.CROSS_CURSOR)
1184            item = self.itemPicked
1185            pixelSize = Data['pixelSize']
1186            scalex = 1000./pixelSize[0]
1187            scaley = 1000./pixelSize[1]
1188            if item and self.PatternTree.GetItemText(self.PickId) == 'Image Controls':
1189                if 'Text' in str(item):
1190                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
1191                else:
1192                    xcent,ycent = Data['center']
1193                    xpos = event.xdata-xcent
1194                    ypos = event.ydata-ycent
1195                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
1196                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
1197                        Page.canvas.SetToolTipString('%6d deg'%(azm))
1198                    elif 'line1' in  str(item) or 'line2' in str(item):
1199                        Page.canvas.SetToolTipString('%8.3fdeg'%(tth))                           
1200            else:
1201                xpos = event.xdata
1202                ypos = event.ydata
1203                xpix = xpos*scalex
1204                ypix = ypos*scaley
1205                Int = 0
1206                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
1207                    Int = self.ImageZ[ypix][xpix]
1208                tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1209                Q = 2.*math.pi/dsp
1210                if self.setPoly:
1211                    self.G2plotNB.status.SetFields(['','Polygon mask pick - LB next point, RB close polygon'])
1212                else:
1213                    self.G2plotNB.status.SetFields(\
1214                        ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)])
1215
1216    def OnImPlotKeyPress(event):
1217        try:
1218            PickName = self.PatternTree.GetItemText(self.PickId)
1219        except TypeError:
1220            return
1221        if PickName == 'Masks':
1222            Xpos = event.xdata
1223            if not Xpos:            #got point out of frame
1224                return
1225            Ypos = event.ydata
1226            if event.key == 's':
1227                Masks['Points'].append([Xpos,Ypos,1.])
1228            elif event.key == 'r':
1229                tth = G2img.GetTth(Xpos,Ypos,Data)
1230                Masks['Rings'].append([tth,0.1])
1231            elif event.key == 'a':
1232                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
1233                azm = int(azm)               
1234                Masks['Arcs'].append([tth,[azm-5,azm+5],0.1])
1235            elif event.key == 'p':
1236                self.setPoly = True
1237                Masks['Polygons'].append([])
1238                self.G2plotNB.status.SetFields(['','Polygon mask active - LB pick next point, RB close polygon'])
1239            G2imG.UpdateMasks(self,Masks)
1240        elif PickName == 'Image Controls':
1241            if event.key == 'c':
1242                Xpos = event.xdata
1243                if not Xpos:            #got point out of frame
1244                    return
1245                Ypos = event.ydata
1246                dlg = wx.MessageDialog(self,'Are you sure you want to change the center?',
1247                    'Center change',style=wx.OK|wx.CANCEL)
1248                try:
1249                    if dlg.ShowModal() == wx.ID_OK:
1250                        print 'move center to: ',Xpos,Ypos
1251                        Data['center'] = [Xpos,Ypos]
1252                        G2imG.UpdateImageControls(self,Data,Masks)
1253                finally:
1254                    dlg.Destroy()
1255            elif event.key == 'l':
1256                if self.logPlot:
1257                    self.logPlot = False
1258                else:
1259                    self.logPlot = True
1260        PlotImage(self,newImage=True)
1261           
1262    def OnKeyBox(event):
1263        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index('2D Powder Image'):
1264            event.key = cb.GetValue()[0]
1265            cb.SetValue(' key press')
1266            if event.key in 'l':
1267                OnImPlotKeyPress(event)
1268                       
1269    def OnImPick(event):
1270        if self.PatternTree.GetItemText(self.PickId) not in ['Image Controls','Masks']:
1271            return
1272        if self.setPoly:
1273            polygon = Masks['Polygons'][-1]
1274            xpos,ypos = event.mouseevent.xdata,event.mouseevent.ydata
1275            if xpos and ypos:                       #point inside image
1276                if len(polygon) > 2 and event.mouseevent.button == 3:
1277                    x0,y0 = polygon[0]
1278                    polygon.append([x0,y0])
1279                    self.setPoly = False
1280                    self.G2plotNB.status.SetFields(['','Polygon closed - RB drag a vertex to change shape'])
1281                else:
1282                    self.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(xpos,ypos)])
1283                    polygon.append([xpos,ypos])
1284                G2imG.UpdateMasks(self,Masks)
1285        else:
1286            if self.itemPicked is not None: return
1287            self.itemPicked = event.artist
1288            self.mousePicked = event.mouseevent
1289       
1290    def OnImRelease(event):
1291        try:
1292            PickName = self.PatternTree.GetItemText(self.PickId)
1293        except TypeError:
1294            return
1295        if PickName not in ['Image Controls','Masks']:
1296            return
1297        pixelSize = Data['pixelSize']
1298        scalex = 1000./pixelSize[0]
1299        scaley = 1000./pixelSize[1]
1300        pixLimit = Data['pixLimit']
1301        if self.itemPicked is None and PickName == 'Image Controls':
1302#            sizexy = Data['size']
1303            Xpos = event.xdata
1304            if not (Xpos and self.ifGetRing):                   #got point out of frame
1305                return
1306            Ypos = event.ydata
1307            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
1308                if event.button == 1:
1309                    Xpix = Xpos*scalex
1310                    Ypix = Ypos*scaley
1311                    xpos,ypos,I,J = G2img.ImageLocalMax(self.ImageZ,pixLimit,Xpix,Ypix)
1312                    if I and J:
1313                        xpos += .5                              #shift to pixel center
1314                        ypos += .5
1315                        xpos /= scalex                          #convert to mm
1316                        ypos /= scaley
1317                        Data['ring'].append([xpos,ypos])
1318                elif event.button == 3:
1319                    print 'LB shift'
1320                    self.dataFrame.GetStatusBar().SetStatusText('Calibrating...')
1321                    if G2img.ImageCalibrate(self,Data):
1322                        self.dataFrame.GetStatusBar().SetStatusText('Calibration successful - Show ring picks to check')
1323                        print 'Calibration successful'
1324                    else:
1325                        self.dataFrame.GetStatusBar().SetStatusText('Calibration failed - Show ring picks to diagnose')
1326                        print 'Calibration failed'
1327                    self.ifGetRing = False
1328                    G2imG.UpdateImageControls(self,Data,Masks)
1329                    return
1330                PlotImage(self,newImage=False)
1331            return
1332        else:
1333            xpos = event.xdata
1334            if xpos:                                        #avoid out of frame mouse position
1335                ypos = event.ydata
1336                if self.ifGetRing:                          #delete a calibration ring pick
1337                    xypos = [xpos,ypos]
1338                    rings = Data['ring']
1339                    for ring in rings:
1340                        if np.allclose(ring,xypos,.01,0):
1341                            rings.remove(ring)                                                                       
1342                else:
1343                    tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1344                    itemPicked = str(self.itemPicked)
1345                    if 'Line2D' in itemPicked and PickName == 'Image Controls':
1346                        if 'line1' in itemPicked:
1347                            Data['IOtth'][0] = max(tth,0.001)
1348                        elif 'line2' in itemPicked:
1349                            Data['IOtth'][1] = tth
1350                        elif 'line3' in itemPicked:
1351                            Data['LRazimuth'][0] = int(azm)
1352                            if Data['fullIntegrate']:
1353                                Data['LRazimuth'][1] = Data['LRazimuth'][0]+360
1354                        elif 'line4' in itemPicked and not Data['fullIntegrate']:
1355                            Data['LRazimuth'][1] = int(azm)
1356                           
1357                        if Data['LRazimuth'][0] > Data['LRazimuth'][1]:
1358                            Data['LRazimuth'][0] -= 360
1359                           
1360                        azLim = np.array(Data['LRazimuth'])   
1361                        if np.any(azLim>360):
1362                            azLim -= 360
1363                            Data['LRazimuth'] = list(azLim)
1364                           
1365                        if  Data['IOtth'][0] > Data['IOtth'][1]:
1366                            Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
1367                           
1368                        self.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
1369                        self.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
1370                        self.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
1371                        self.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
1372                    elif 'Circle' in itemPicked and PickName == 'Masks':
1373                        spots = Masks['Points']
1374                        newPos = itemPicked.split(')')[0].split('(')[2].split(',')
1375                        newPos = np.array([float(newPos[0]),float(newPos[1])])
1376                        for spot in spots:
1377                            if np.allclose(np.array([spot[:2]]),newPos):
1378                                spot[:2] = xpos,ypos
1379                        G2imG.UpdateMasks(self,Masks)
1380                    elif 'Line2D' in itemPicked and PickName == 'Masks':
1381                        Obj = self.itemPicked.findobj()
1382                        rings = Masks['Rings']
1383                        arcs = Masks['Arcs']
1384                        polygons = Masks['Polygons']
1385                        for ring in self.ringList:
1386                            if Obj == ring[0]:
1387                                rN = ring[1]
1388                                if ring[2] == 'o':
1389                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)-rings[rN][1]/2.
1390                                else:
1391                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)+rings[rN][1]/2.
1392                        for arc in self.arcList:
1393                            if Obj == arc[0]:
1394                                aN = arc[1]
1395                                if arc[2] == 'o':
1396                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)-arcs[aN][2]/2
1397                                elif arc[2] == 'i':
1398                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)+arcs[aN][2]/2
1399                                elif arc[2] == 'l':
1400                                    arcs[aN][1][0] = int(G2img.GetAzm(xpos,ypos,Data))
1401                                else:
1402                                    arcs[aN][1][1] = int(G2img.GetAzm(xpos,ypos,Data))
1403                        for poly in self.polyList:
1404                            if Obj == poly[0]:
1405                                ind = self.itemPicked.contains(self.mousePicked)[1]['ind'][0]
1406                                oldPos = np.array([self.mousePicked.xdata,self.mousePicked.ydata])
1407                                pN = poly[1]
1408                                for i,xy in enumerate(polygons[pN]):
1409                                    if np.allclose(np.array([xy]),oldPos,atol=1.0):
1410                                        polygons[pN][i] = xpos,ypos
1411                        G2imG.UpdateMasks(self,Masks)
1412#                    else:                  #keep for future debugging
1413#                        print str(self.itemPicked),event.xdata,event.ydata,event.button
1414                PlotImage(self,newImage=True)
1415            self.itemPicked = None
1416           
1417    try:
1418        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1419        Page = self.G2plotNB.nb.GetPage(plotNum)
1420        if not newPlot:
1421            Plot = Page.figure.gca()          #get previous powder plot & get limits
1422            xylim = Plot.get_xlim(),Plot.get_ylim()
1423        if newImage:
1424            Page.figure.clf()
1425            Plot = Page.figure.gca()          #get a fresh plot after clf()
1426       
1427    except ValueError:
1428        Plot = self.G2plotNB.addMpl('2D Powder Image').gca()
1429        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1430        Page = self.G2plotNB.nb.GetPage(plotNum)
1431        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
1432        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
1433        Page.canvas.mpl_connect('pick_event', OnImPick)
1434        Page.canvas.mpl_connect('button_release_event', OnImRelease)
1435        xylim = []
1436    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
1437        Page.SetFocus()
1438    Title = self.PatternTree.GetItemText(self.Image)[4:]
1439    self.G2plotNB.status.DestroyChildren()
1440    if self.logPlot:
1441        Title = 'log('+Title+')'
1442    Plot.set_title(Title)
1443    try:
1444        if self.PatternTree.GetItemText(self.PickId) in ['Image Controls',]:
1445            if self.logPlot:
1446                Choice = (' key press','l: log(I) off')
1447            else:
1448                Choice = (' key press','l: log(I) on')
1449            cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
1450                choices=Choice)
1451            cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
1452            cb.SetValue(' key press')
1453    except TypeError:
1454        pass
1455    size,imagefile = self.PatternTree.GetItemPyData(self.Image)
1456    if imagefile != self.oldImagefile:
1457        imagefile = G2IO.CheckImageFile(self,imagefile)
1458        if not imagefile:
1459            self.G2plotNB.Delete('2D Powder Image')
1460            return
1461        self.PatternTree.SetItemPyData(self.Image,[size,imagefile])
1462        self.ImageZ = G2IO.GetImageData(self,imagefile,imageOnly=True)
1463#        print self.ImageZ.shape,self.ImageZ.size,Data['size'] #might be useful debugging line
1464        self.oldImagefile = imagefile
1465
1466    imScale = 1
1467    if len(self.ImageZ) > 1024:
1468        imScale = len(self.ImageZ)/1024
1469    sizexy = Data['size']
1470    pixelSize = Data['pixelSize']
1471    scalex = 1000./pixelSize[0]
1472    scaley = 1000./pixelSize[1]
1473    Xmax = sizexy[0]*pixelSize[0]/1000.
1474    Ymax = sizexy[1]*pixelSize[1]/1000.
1475    xlim = (0,Xmax)
1476    ylim = (Ymax,0)
1477    Imin,Imax = Data['range'][1]
1478    acolor = mpl.cm.get_cmap(Data['color'])
1479    xcent,ycent = Data['center']
1480    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
1481    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
1482    #do threshold mask - "real" mask - others are just bondaries
1483    Zlim = Masks['Thresholds'][1]
1484    wx.BeginBusyCursor()
1485    try:
1486           
1487        if newImage:                   
1488            MA = ma.masked_greater(ma.masked_less(self.ImageZ,Zlim[0]),Zlim[1])
1489            MaskA = ma.getmaskarray(MA)
1490            A = G2img.ImageCompress(MA,imScale)
1491            AM = G2img.ImageCompress(MaskA,imScale)
1492            if self.logPlot:
1493                A = np.log(A)
1494                AM = np.log(AM)
1495                Imin,Imax = [np.amin(A),np.amax(A)]
1496            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
1497                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Xmax,0])
1498            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
1499                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
1500            if self.setPoly:
1501                Img.set_picker(True)
1502   
1503        Plot.plot(xcent,ycent,'x')
1504        if Data['showLines']:
1505            LRAzim = Data['LRazimuth']                  #NB: integers
1506            Nazm = Data['outAzimuths']
1507            delAzm = float(LRAzim[1]-LRAzim[0])/Nazm
1508            AzmthOff = Data['azmthOff']
1509            IOtth = Data['IOtth']
1510            wave = Data['wavelength']
1511            dspI = wave/(2.0*sind(IOtth[0]/2.0))
1512            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
1513            dspO = wave/(2.0*sind(IOtth[1]/2.0))
1514            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
1515            Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
1516            if ellI:
1517                xyI = []
1518                for azm in Azm:
1519                    xyI.append(G2img.GetDetectorXY(dspI,azm-90.,Data))
1520                xyI = np.array(xyI)
1521                arcxI,arcyI = xyI.T
1522                Plot.plot(arcxI,arcyI,picker=3)
1523            if ellO:
1524                xyO = []
1525                for azm in Azm:
1526                    xyO.append(G2img.GetDetectorXY(dspO,azm-90.,Data))
1527                xyO = np.array(xyO)
1528                arcxO,arcyO = xyO.T
1529                Plot.plot(arcxO,arcyO,picker=3)
1530            if ellO and ellI:
1531                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
1532                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
1533            for i in range(Nazm):
1534                cake = LRAzim[0]+i*delAzm
1535                ind = np.searchsorted(Azm,cake)
1536                Plot.plot([arcxI[ind],arcxO[ind]],[arcyI[ind],arcyO[ind]],color='k',dashes=(5,5))
1537                   
1538        for xring,yring in Data['ring']:
1539            Plot.plot(xring,yring,'r+',picker=3)
1540        if Data['setRings']:
1541#            rings = np.concatenate((Data['rings']),axis=0)
1542            N = 0
1543            for ring in Data['rings']:
1544                xring,yring = np.array(ring).T[:2]
1545                Plot.plot(xring,yring,'+',color=colors[N%6])
1546                N += 1           
1547        for ellipse in Data['ellipses']:
1548            cent,phi,[width,height],col = ellipse
1549            Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
1550            Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
1551        #masks - mask lines numbered after integration limit lines
1552        spots = Masks['Points']
1553        rings = Masks['Rings']
1554        arcs = Masks['Arcs']
1555        polygons = Masks['Polygons']
1556        for x,y,d in spots:
1557            Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
1558        self.ringList = []
1559        for iring,(tth,thick) in enumerate(rings):
1560            wave = Data['wavelength']
1561            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data))),2)
1562            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth-thick/2.,wave),Data))),2)
1563            self.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
1564            self.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
1565        self.arcList = []
1566        for iarc,(tth,azm,thick) in enumerate(arcs):           
1567            wave = Data['wavelength']
1568            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data),azm)),2)
1569            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(max(0.01,tth-thick/2.),wave),Data),azm)),2)
1570            self.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
1571            self.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
1572            self.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
1573            self.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
1574        self.polyList = []
1575        for ipoly,polygon in enumerate(polygons):
1576            x,y = np.hsplit(np.array(polygon),2)
1577            self.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
1578            Plot.plot(x,y,'r')           
1579        if newImage:
1580            colorBar = Page.figure.colorbar(Img)
1581        Plot.set_xlim(xlim)
1582        Plot.set_ylim(ylim)
1583        if not newPlot and xylim:
1584            Page.toolbar.push_current()
1585            Plot.set_xlim(xylim[0])
1586            Plot.set_ylim(xylim[1])
1587            xylim = []
1588            Page.toolbar.push_current()
1589            Page.toolbar.draw()
1590        else:
1591            Page.canvas.draw()
1592    finally:
1593        wx.EndBusyCursor()
1594       
1595def PlotIntegration(self,newPlot=False,event=None):
1596           
1597    def OnMotion(event):
1598        Page.canvas.SetToolTipString('')
1599        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1600        azm = event.ydata
1601        tth = event.xdata
1602        if azm and tth:
1603            self.G2plotNB.status.SetFields(\
1604                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1605                               
1606    try:
1607        plotNum = self.G2plotNB.plotList.index('2D Integration')
1608        Page = self.G2plotNB.nb.GetPage(plotNum)
1609        if not newPlot:
1610            Plot = Page.figure.gca()          #get previous plot & get limits
1611            xylim = Plot.get_xlim(),Plot.get_ylim()
1612        Page.figure.clf()
1613        Plot = Page.figure.gca()          #get a fresh plot after clf()
1614       
1615    except ValueError:
1616        Plot = self.G2plotNB.addMpl('2D Integration').gca()
1617        plotNum = self.G2plotNB.plotList.index('2D Integration')
1618        Page = self.G2plotNB.nb.GetPage(plotNum)
1619        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1620        Page.views = False
1621        view = False
1622    if not event:
1623        Page.SetFocus()
1624       
1625    Data = self.PatternTree.GetItemPyData(
1626        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1627    image = self.Integrate[0]
1628    xsc = self.Integrate[1]
1629    ysc = self.Integrate[2]
1630    Imin,Imax = Data['range'][1]
1631    acolor = mpl.cm.get_cmap(Data['color'])
1632    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1633    Plot.set_ylabel('azimuth',fontsize=12)
1634    Plot.set_xlabel('2-theta',fontsize=12)
1635    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
1636        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
1637    colorBar = Page.figure.colorbar(Img)
1638    if Data['setRings'] and Data['rings']:
1639        rings = np.concatenate((Data['rings']),axis=0)
1640        for xring,yring,dsp in rings:
1641            x,y = G2img.GetTthAzm(xring,yring,Data)
1642            Plot.plot(x,y,'r+')
1643    if Data['ellipses']:           
1644        for ellipse in Data['ellipses']:
1645            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1646            x,y = np.hsplit(ring,2)
1647            tth,azm = G2img.GetTthAzm(x,y,Data)
1648            Plot.plot(tth,azm,'b,')
1649    if not newPlot:
1650        Page.toolbar.push_current()
1651        Plot.set_xlim(xylim[0])
1652        Plot.set_ylim(xylim[1])
1653        xylim = []
1654        Page.toolbar.push_current()
1655        Page.toolbar.draw()
1656    else:
1657        Page.canvas.draw()
1658               
1659def PlotTRImage(self,tax,tay,taz,newPlot=False):
1660    #a test plot routine - not normally used
1661           
1662    def OnMotion(event):
1663        Page.canvas.SetToolTipString('')
1664        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1665        azm = event.xdata
1666        tth = event.ydata
1667        if azm and tth:
1668            self.G2plotNB.status.SetFields(\
1669                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1670                               
1671    try:
1672        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1673        Page = self.G2plotNB.nb.GetPage(plotNum)
1674        if not newPlot:
1675            Plot = Page.figure.gca()          #get previous plot & get limits
1676            xylim = Plot.get_xlim(),Plot.get_ylim()
1677        Page.figure.clf()
1678        Plot = Page.figure.gca()          #get a fresh plot after clf()
1679       
1680    except ValueError:
1681        Plot = self.G2plotNB.addMpl('2D Transformed Powder Image').gca()
1682        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1683        Page = self.G2plotNB.nb.GetPage(plotNum)
1684        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1685        Page.views = False
1686        view = False
1687    Page.SetFocus()
1688       
1689    Data = self.PatternTree.GetItemPyData(
1690        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1691    Imin,Imax = Data['range'][1]
1692    step = (Imax-Imin)/5.
1693    V = np.arange(Imin,Imax,step)
1694    acolor = mpl.cm.get_cmap(Data['color'])
1695    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1696    Plot.set_xlabel('azimuth',fontsize=12)
1697    Plot.set_ylabel('2-theta',fontsize=12)
1698    Plot.contour(tax,tay,taz,V,cmap=acolor)
1699    if Data['showLines']:
1700        IOtth = Data['IOtth']
1701        if Data['fullIntegrate']:
1702            LRAzim = [-180,180]
1703        else:
1704            LRAzim = Data['LRazimuth']                  #NB: integers
1705        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[0],IOtth[0]],picker=True)
1706        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[1],IOtth[1]],picker=True)
1707        if not Data['fullIntegrate']:
1708            Plot.plot([LRAzim[0],LRAzim[0]],[IOtth[0],IOtth[1]],picker=True)
1709            Plot.plot([LRAzim[1],LRAzim[1]],[IOtth[0],IOtth[1]],picker=True)
1710    if Data['setRings']:
1711        rings = np.concatenate((Data['rings']),axis=0)
1712        for xring,yring,dsp in rings:
1713            x,y = G2img.GetTthAzm(xring,yring,Data)
1714            Plot.plot(y,x,'r+')           
1715    if Data['ellipses']:           
1716        for ellipse in Data['ellipses']:
1717            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1718            x,y = np.hsplit(ring,2)
1719            tth,azm = G2img.GetTthAzm(x,y,Data)
1720            Plot.plot(azm,tth,'b,')
1721    if not newPlot:
1722        Page.toolbar.push_current()
1723        Plot.set_xlim(xylim[0])
1724        Plot.set_ylim(xylim[1])
1725        xylim = []
1726        Page.toolbar.push_current()
1727        Page.toolbar.draw()
1728    else:
1729        Page.canvas.draw()
1730       
1731def PlotStructure(self,data):
1732    generalData = data['General']
1733    cell = generalData['Cell'][1:7]
1734    Amat,Bmat = G2lat.cell2AB(cell)         #Amat - crystal to cartesian, Bmat - inverse
1735    A4mat = np.concatenate((np.concatenate((Amat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1736    B4mat = np.concatenate((np.concatenate((Bmat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1737    Mydir = generalData['Mydir']
1738    atomData = data['Atoms']
1739    drawingData = data['Drawing']
1740    drawAtoms = drawingData['Atoms']
1741    cx,ct,cs = drawingData['atomPtrs']
1742    Wt = [255,255,255]
1743    Rd = [255,0,0]
1744    Gr = [0,255,0]
1745    Bl = [0,0,255]
1746    uBox = np.array([[0,0,0],[1,0,0],[1,1,0],[0,1,0],[0,0,1],[1,0,1],[1,1,1],[0,1,1]])
1747    uEdges = np.array([
1748        [uBox[0],uBox[1]],[uBox[0],uBox[3]],[uBox[0],uBox[4]],[uBox[1],uBox[2]], 
1749        [uBox[2],uBox[3]],[uBox[1],uBox[5]],[uBox[2],uBox[6]],[uBox[3],uBox[7]], 
1750        [uBox[4],uBox[5]],[uBox[5],uBox[6]],[uBox[6],uBox[7]],[uBox[7],uBox[4]]])
1751    uColors = [Rd,Gr,Bl,Wt, Wt,Wt,Wt,Wt, Wt,Wt,Wt,Wt]
1752    altDown = False
1753    shiftDown = False
1754    ctrlDown = False
1755   
1756    def OnKeyBox(event):
1757        import Image
1758        Draw()                          #make sure plot is fresh!!
1759        mode = cb.GetValue()
1760        Fname = Mydir+'\\'+generalData['Name']+'.'+mode
1761        size = Page.canvas.GetSize()
1762        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
1763        if mode in ['jpeg',]:
1764            Pix = glReadPixels(0,0,size[0],size[1],GL_RGBA, GL_UNSIGNED_BYTE)
1765            im = Image.new("RGBA", (size[0],size[1]))
1766        else:
1767            Pix = glReadPixels(0,0,size[0],size[1],GL_RGB, GL_UNSIGNED_BYTE)
1768            im = Image.new("RGB", (size[0],size[1]))
1769        im.fromstring(Pix)
1770        im.save(Fname,mode)
1771        cb.SetValue(' Save as:')
1772        self.G2plotNB.status.SetStatusText('Drawing saved to: '+Fname,1)
1773   
1774    def GetTruePosition(xy):
1775        View = glGetIntegerv(GL_VIEWPORT)
1776        Proj = glGetDoublev(GL_PROJECTION_MATRIX)
1777        Model = glGetDoublev(GL_MODELVIEW_MATRIX)
1778        Zmax = 1.
1779        for i,atom in enumerate(drawAtoms):
1780            x,y,z = atom[cx:cx+3]
1781            X,Y,Z = gluProject(x,y,z,Model,Proj,View)
1782            XY = [int(X),int(View[3]-Y)]
1783            if np.allclose(xy,XY,atol=10) and Z < Zmax:
1784                Zmax = Z
1785                SetSelectedAtoms(i)
1786                   
1787    def OnMouseDown(event):
1788        xy = event.GetPosition()
1789        if event.ShiftDown():
1790            GetTruePosition(xy)
1791        else:
1792            drawingData['Rotation'][3] = xy
1793        Draw()
1794       
1795    def OnMouseMove(event):
1796        newxy = event.GetPosition()
1797        page = getSelection()
1798        if event.ControlDown() and drawingData['showABC']:
1799            if event.LeftIsDown():
1800                SetTestRot(newxy)
1801            elif event.RightIsDown():
1802                SetTestPos(newxy)
1803            elif event.MiddleIsDown():
1804                SetTestRotZ(newxy)
1805            x,y,z = drawingData['testPos'][0]
1806            self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
1807               
1808               
1809        if event.Dragging() and not event.ControlDown():
1810            if event.LeftIsDown():
1811                SetRotation(newxy)
1812                angX,angY,angZ = drawingData['Rotation'][:3]
1813                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f ,%.2f'%(angX,angY,angZ),1)
1814            elif event.RightIsDown():
1815                SetTranslation(newxy)
1816                Tx,Ty,Tz = drawingData['viewPoint'][0]
1817                self.G2plotNB.status.SetStatusText('New view point: %.4f, %.4f, %.4f'%(Tx,Ty,Tz),1)
1818            elif event.MiddleIsDown():
1819                SetRotationZ(newxy)
1820                angX,angY,angZ = drawingData['Rotation'][:3]
1821                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f, %.2f'%(angX,angY,angZ),1)
1822        Draw()
1823       
1824    def OnMouseWheel(event):
1825        drawingData['cameraPos'] += event.GetWheelRotation()/24
1826        drawingData['cameraPos'] = max(10,min(500,drawingData['cameraPos']))
1827        self.G2plotNB.status.SetStatusText('New camera distance: %.2f'%(drawingData['cameraPos']),1)
1828        page = getSelection()
1829        if page:
1830            if self.dataDisplay.GetPageText(page) == 'Draw Options':
1831                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
1832                names = [child.GetName() for child in panel]
1833                panel[names.index('cameraPos')].SetLabel('Camera Position: '+'%.2f'%(drawingData['cameraPos']))
1834                panel[names.index('cameraSlider')].SetValue(drawingData['cameraPos'])
1835        Draw()
1836       
1837    def getSelection():
1838        try:
1839            return self.dataDisplay.GetSelection()
1840        except AttributeError:
1841            print self.dataDisplay.GetLabel()
1842            self.G2plotNB.status.SetStatusText('Select this from Phase data window!')
1843            return 0
1844           
1845    def SetViewPointText(VP):
1846        page = getSelection()
1847        if page:
1848            if self.dataDisplay.GetPageText(page) == 'Draw Options':
1849                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
1850                names = [child.GetName() for child in panel]
1851                panel[names.index('viewPoint')].SetValue('%.3f, %.3f, %.3f'%(VP[0],VP[1],VP[2]))
1852           
1853    def ClearSelectedAtoms():
1854        page = getSelection()
1855        if page:
1856            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
1857                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Draw Atoms
1858            elif self.dataDisplay.GetPageText(page) == 'Atoms':
1859                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Atoms
1860                   
1861    def SetSelectedAtoms(ind):
1862        page = getSelection()
1863        if page:
1864            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
1865                self.dataDisplay.GetPage(page).SelectRow(ind)      #this is the Atoms grid in Draw Atoms
1866            elif self.dataDisplay.GetPageText(page) == 'Atoms':
1867                Id = drawAtoms[ind][-2]
1868                for i,atom in enumerate(atomData):
1869                    if atom[-1] == Id:
1870                        self.dataDisplay.GetPage(page).SelectRow(i)      #this is the Atoms grid in Atoms
1871                 
1872    def GetSelectedAtoms():
1873        page = getSelection()
1874        Ind = []
1875        if page:
1876            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
1877                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Draw Atoms
1878            elif self.dataDisplay.GetPageText(page) == 'Atoms':
1879                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Atoms
1880        return Ind
1881                                       
1882    def OnKey(event):           #on key UP!!
1883        keyCode = event.GetKeyCode()
1884        if keyCode > 255:
1885            keyCode = 0
1886        key,xyz = chr(keyCode),event.GetPosition()
1887        indx = drawingData['selectedAtoms']
1888        if key in ['c','C']:
1889            drawingData['viewPoint'] = [[.5,.5,.5],[0,0]]
1890            drawingData['testPos'] = [[-.1,-.1,-.1],[0.0,0.0,0.0],[0,0]]
1891            drawingData['Rotation'] = [0.0,0.0,0.0,[]]
1892            SetViewPointText(drawingData['viewPoint'][0])
1893        elif key in ['n','N']:
1894            drawAtoms = drawingData['Atoms']
1895            pI = drawingData['viewPoint'][1]
1896            if indx:
1897                pI[0] = indx[pI[1]]
1898                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
1899                pI[1] += 1
1900                if pI[1] >= len(indx):
1901                    pI[1] = 0
1902            else:
1903                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
1904                pI[0] += 1
1905                if pI[0] >= len(drawAtoms):
1906                    pI[0] = 0
1907            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
1908            SetViewPointText(drawingData['viewPoint'][0])
1909               
1910        elif key in ['p','P']:
1911            drawAtoms = drawingData['Atoms']
1912            pI = drawingData['viewPoint'][1]
1913            if indx:
1914                pI[0] = indx[pI[1]]
1915                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
1916                pI[1] -= 1
1917                if pI[1] < 0:
1918                    pI[1] = len(indx)-1
1919            else:
1920                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
1921                pI[0] -= 1
1922                if pI[0] < 0:
1923                    pI[0] = len(drawAtoms)-1
1924            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
1925            SetViewPointText(drawingData['viewPoint'][0])           
1926        Draw()
1927           
1928    def SetBackground():
1929        R,G,B,A = Page.camera['backColor']
1930        glClearColor(R,G,B,A)
1931        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
1932       
1933    def SetLights():
1934        glEnable(GL_DEPTH_TEST)
1935        glShadeModel(GL_SMOOTH)
1936        glEnable(GL_LIGHTING)
1937        glEnable(GL_LIGHT0)
1938        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0)
1939        glLightfv(GL_LIGHT0,GL_AMBIENT,[1,1,1,.8])
1940        glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
1941       
1942    def SetTranslation(newxy):
1943        Tx,Ty,Tz = drawingData['viewPoint'][0]
1944        anglex,angley,anglez,oldxy = drawingData['Rotation']
1945        Rx = G2lat.rotdMat(anglex,0)
1946        Ry = G2lat.rotdMat(angley,1)
1947        Rz = G2lat.rotdMat(anglez,2)
1948        dxy = list(newxy-oldxy)+[0,]
1949        dxy = np.inner(Bmat,np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy))))
1950        Tx -= dxy[0]*0.01
1951        Ty += dxy[1]*0.01
1952        Tz -= dxy[2]*0.01
1953        drawingData['Rotation'][3] = newxy
1954        drawingData['viewPoint'][0] =  Tx,Ty,Tz
1955        SetViewPointText([Tx,Ty,Tz])
1956       
1957    def SetTestPos(newxy):
1958        Tx,Ty,Tz = drawingData['testPos'][0]
1959        anglex,angley,anglez,oldxy = drawingData['Rotation']
1960        Rx = G2lat.rotdMat(anglex,0)
1961        Ry = G2lat.rotdMat(angley,1)
1962        Rz = G2lat.rotdMat(anglez,2)
1963        dxy = list(newxy-oldxy)+[0,]
1964        dxy = np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy)))
1965        Tx += dxy[0]*0.001
1966        Ty -= dxy[1]*0.001
1967        Tz += dxy[2]*0.001
1968        drawingData['Rotation'][3] = newxy
1969        drawingData['testPos'][0] =  Tx,Ty,Tz
1970       
1971    def SetTestRot(newxy):
1972        Txyz = np.array(drawingData['testPos'][0])
1973        oldxy = drawingData['testPos'][2]
1974        Ax,Ay,Az = drawingData['testPos'][1]
1975        Vxyz = np.array(drawingData['viewPoint'][0])
1976        Dxyz = np.inner(Amat,Txyz-Vxyz)
1977        dxy = list(newxy-oldxy)+[0,]
1978        Ax += dxy[1]*0.01
1979        Ay += dxy[0]*0.01
1980        Rx = G2lat.rotdMat(Ax,0)
1981        Ry = G2lat.rotdMat(Ay,1)
1982        Dxyz = np.inner(Ry,np.inner(Rx,Dxyz))       
1983        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
1984        drawingData['testPos'][1] = [Ax,Ay,Az]
1985        drawingData['testPos'][2] = newxy
1986        drawingData['testPos'][0] = Dxyz
1987       
1988    def SetTestRotZ(newxy):
1989        Txyz = np.array(drawingData['testPos'][0])
1990        oldxy = drawingData['testPos'][2]
1991        Ax,Ay,Az = drawingData['testPos'][1]
1992        Vxyz = np.array(drawingData['viewPoint'][0])
1993        Dxyz = np.inner(Amat,Txyz-Vxyz)       
1994        dxy = list(newxy-oldxy)+[0,]
1995        Az += (dxy[0]+dxy[1])*.01
1996        Rz = G2lat.rotdMat(Az,2)
1997        Dxyz = np.inner(Rz,Dxyz)       
1998        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
1999        drawingData['testPos'][1] = [Ax,Ay,Az]
2000        drawingData['testPos'][2] = newxy
2001        drawingData['testPos'][0] = Dxyz
2002                             
2003    def SetRotation(newxy):       
2004        anglex,angley,anglez,oldxy = drawingData['Rotation']
2005        dxy = newxy-oldxy
2006        anglex += dxy[1]*.25
2007        angley += dxy[0]*.25
2008        oldxy = newxy
2009        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2010       
2011    def SetRotationZ(newxy):                       
2012        anglex,angley,anglez,oldxy = drawingData['Rotation']
2013        dxy = newxy-oldxy
2014        anglez += (dxy[0]+dxy[1])*.25
2015        oldxy = newxy
2016        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2017       
2018    def RenderBox():
2019        glEnable(GL_COLOR_MATERIAL)
2020        glLineWidth(2)
2021        glEnable(GL_BLEND)
2022        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
2023        glEnable(GL_LINE_SMOOTH)
2024        glBegin(GL_LINES)
2025        for line,color in zip(uEdges,uColors):
2026            glColor3ubv(color)
2027            glVertex3fv(line[0])
2028            glVertex3fv(line[1])
2029        glEnd()
2030        glColor4ubv([0,0,0,0])
2031        glDisable(GL_LINE_SMOOTH)
2032        glDisable(GL_BLEND)
2033        glDisable(GL_COLOR_MATERIAL)
2034       
2035    def RenderUnitVectors(x,y,z):
2036        xyz = np.array([x,y,z])
2037        glEnable(GL_COLOR_MATERIAL)
2038        glLineWidth(1)
2039        glPushMatrix()
2040        glTranslate(x,y,z)
2041        glScalef(1/cell[0],1/cell[1],1/cell[2])
2042        glBegin(GL_LINES)
2043        for line,color in zip(uEdges,uColors)[:3]:
2044            glColor3ubv(color)
2045            glVertex3fv(line[0])
2046            glVertex3fv(line[1])
2047        glEnd()
2048        glPopMatrix()
2049        glColor4ubv([0,0,0,0])
2050        glDisable(GL_COLOR_MATERIAL)
2051               
2052    def RenderSphere(x,y,z,radius,color):
2053        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2054        glPushMatrix()
2055        glTranslate(x,y,z)
2056        glMultMatrixf(B4mat.T)
2057        q = gluNewQuadric()
2058        gluSphere(q,radius,20,10)
2059        glPopMatrix()
2060       
2061    def RenderEllipsoid(x,y,z,ellipseProb,E,R4,color):
2062        s1,s2,s3 = E
2063        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2064        glPushMatrix()
2065        glTranslate(x,y,z)
2066        glMultMatrixf(B4mat.T)
2067        glMultMatrixf(R4.T)
2068        glEnable(GL_NORMALIZE)
2069        glScale(s1,s2,s3)
2070        q = gluNewQuadric()
2071        gluSphere(q,ellipseProb,20,10)
2072        glDisable(GL_NORMALIZE)
2073        glPopMatrix()
2074       
2075    def RenderBonds(x,y,z,Bonds,radius,color,slice=20):
2076        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2077        glPushMatrix()
2078        glTranslate(x,y,z)
2079        glMultMatrixf(B4mat.T)
2080        for bond in Bonds:
2081            glPushMatrix()
2082            Dx = np.inner(Amat,bond)
2083            Z = np.sqrt(np.sum(Dx**2))
2084            azm = atan2d(-Dx[1],-Dx[0])
2085            phi = acosd(Dx[2]/Z)
2086            glRotate(-azm,0,0,1)
2087            glRotate(phi,1,0,0)
2088            q = gluNewQuadric()
2089            gluCylinder(q,radius,radius,Z,slice,2)
2090            glPopMatrix()           
2091        glPopMatrix()
2092               
2093    def RenderLines(x,y,z,Bonds,color):
2094        xyz = np.array([x,y,z])
2095        glEnable(GL_COLOR_MATERIAL)
2096        glLineWidth(1)
2097        glColor3fv(color)
2098        glPushMatrix()
2099        glBegin(GL_LINES)
2100        for bond in Bonds:
2101            glVertex3fv(xyz)
2102            glVertex3fv(xyz+bond)
2103        glEnd()
2104        glColor4ubv([0,0,0,0])
2105        glPopMatrix()
2106        glDisable(GL_COLOR_MATERIAL)
2107       
2108    def RenderPolyhedra(x,y,z,Faces,color):
2109        glPushMatrix()
2110        glTranslate(x,y,z)
2111        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2112        glShadeModel(GL_SMOOTH)
2113        glMultMatrixf(B4mat.T)
2114        for face,norm in Faces:
2115            glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
2116            glFrontFace(GL_CW)
2117            glNormal3fv(norm)
2118            glBegin(GL_TRIANGLES)
2119            for vert in face:
2120                glVertex3fv(vert)
2121            glEnd()
2122        glPopMatrix()
2123       
2124    def RenderBackbone(Backbone,BackboneColor,radius):
2125        glPushMatrix()
2126        glMultMatrixf(B4mat.T)
2127        glEnable(GL_COLOR_MATERIAL)
2128        glShadeModel(GL_SMOOTH)
2129        gleSetJoinStyle(TUBE_NORM_EDGE | TUBE_JN_ANGLE | TUBE_JN_CAP)
2130        glePolyCylinder(Backbone,BackboneColor,radius)
2131        glPopMatrix()       
2132        glDisable(GL_COLOR_MATERIAL)
2133       
2134    def RenderLabel(x,y,z,label,r):       
2135        glPushMatrix()
2136        glTranslate(x,y,z)
2137        glMultMatrixf(B4mat.T)
2138        glDisable(GL_LIGHTING)
2139        glColor3f(0,1.,0)
2140        glRasterPos3f(r,r,r)
2141        for c in list(label):
2142            glutBitmapCharacter(GLUT_BITMAP_8_BY_13,ord(c))
2143        glEnable(GL_LIGHTING)
2144        glPopMatrix()
2145                           
2146    def Draw():
2147        import numpy.linalg as nl
2148        Ind = GetSelectedAtoms()
2149        VS = np.array(Page.canvas.GetSize())
2150        aspect = float(VS[0])/float(VS[1])
2151        cPos = drawingData['cameraPos']
2152        Zclip = drawingData['Zclip']*cPos/200.
2153        anglex,angley,anglez = drawingData['Rotation'][:3]
2154        Tx,Ty,Tz = drawingData['viewPoint'][0]
2155        cx,ct,cs = drawingData['atomPtrs']
2156        bondR = drawingData['bondRadius']
2157        G,g = G2lat.cell2Gmat(cell)
2158        GS = G
2159        GS[0][1] = GS[1][0] = math.sqrt(GS[0][0]*GS[1][1])
2160        GS[0][2] = GS[2][0] = math.sqrt(GS[0][0]*GS[2][2])
2161        GS[1][2] = GS[2][1] = math.sqrt(GS[1][1]*GS[2][2])
2162        ellipseProb = G2lat.criticalEllipse(drawingData['ellipseProb']/100.)
2163       
2164        SetBackground()
2165        glInitNames()
2166        glPushName(0)
2167       
2168        glMatrixMode(GL_PROJECTION)
2169        glLoadIdentity()
2170        glViewport(0,0,VS[0],VS[1])
2171        gluPerspective(20.,aspect,cPos-Zclip,cPos+Zclip)
2172        gluLookAt(0,0,cPos,0,0,0,0,1,0)
2173        SetLights()           
2174           
2175        glMatrixMode(GL_MODELVIEW)
2176        glLoadIdentity()
2177        glRotate(anglez,0,0,1)
2178        glRotate(anglex,cosd(anglez),-sind(anglez),0)
2179        glRotate(angley,sind(anglez),cosd(anglez),0)
2180        glMultMatrixf(A4mat.T)
2181        glTranslate(-Tx,-Ty,-Tz)
2182        if drawingData['unitCellBox']:
2183            RenderBox()
2184        if drawingData['showABC']:
2185            x,y,z = drawingData['testPos'][0]
2186#            if altDown:
2187#                self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
2188#            else:
2189#                self.G2plotNB.status.SetStatusText('test point %.4f,%.4f,%.4f'%(x,y,z),1)           
2190            RenderUnitVectors(x,y,z)
2191        Backbone = []
2192        BackboneColor = []
2193        time0 = time.time()
2194        for iat,atom in enumerate(drawingData['Atoms']):
2195            x,y,z = atom[cx:cx+3]
2196            Bonds = atom[-2]
2197            Faces = atom[-1]
2198            try:
2199                atNum = generalData['AtomTypes'].index(atom[ct])
2200            except ValueError:
2201                atNum = -1
2202            CL = atom[cs+2]
2203            color = np.array(CL)/255.
2204            if iat in Ind:
2205                color = np.array(Gr)/255.
2206            radius = 0.5
2207            if atom[cs] != '':
2208                glLoadName(atom[-3])                   
2209            if 'balls' in atom[cs]:
2210                vdwScale = drawingData['vdwScale']
2211                ballScale = drawingData['ballScale']
2212                if atNum < 0:
2213                    radius = 0.2
2214                elif 'H' == atom[ct]:
2215                    if drawingData['showHydrogen']:
2216                        if 'vdW' in atom[cs] and atNum >= 0:
2217                            radius = vdwScale*generalData['vdWRadii'][atNum]
2218                        else:
2219                            radius = ballScale*drawingData['sizeH']
2220                    else:
2221                        radius = 0.0
2222                else:
2223                    if 'vdW' in atom[cs]:
2224                        radius = vdwScale*generalData['vdWRadii'][atNum]
2225                    else:
2226                        radius = ballScale*generalData['BondRadii'][atNum]
2227                RenderSphere(x,y,z,radius,color)
2228                if 'sticks' in atom[cs]:
2229                    RenderBonds(x,y,z,Bonds,bondR,color)
2230            elif 'ellipsoids' in atom[cs]:
2231                RenderBonds(x,y,z,Bonds,bondR,color)
2232                if atom[cs+3] == 'A':                   
2233                    Uij = atom[cs+5:cs+11]
2234                    U = np.multiply(G2spc.Uij2U(Uij),GS)
2235                    U = np.inner(Amat,np.inner(U,Amat).T)
2236                    E,R = nl.eigh(U)
2237                    R4 = np.concatenate((np.concatenate((R,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
2238                    E = np.sqrt(E)
2239                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2240                        pass
2241                    else:
2242                        RenderEllipsoid(x,y,z,ellipseProb,E,R4,color)                   
2243                else:
2244                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2245                        pass
2246                    else:
2247                        radius = ellipseProb*math.sqrt(abs(atom[cs+4]))
2248                        RenderSphere(x,y,z,radius,color)
2249            elif 'lines' in atom[cs]:
2250                radius = 0.1
2251                RenderLines(x,y,z,Bonds,color)
2252#                RenderBonds(x,y,z,Bonds,0.05,color,6)
2253            elif atom[cs] == 'sticks':
2254                radius = 0.1
2255                RenderBonds(x,y,z,Bonds,bondR,color)
2256            elif atom[cs] == 'polyhedra':
2257                RenderPolyhedra(x,y,z,Faces,color)
2258            elif atom[cs] == 'backbone':
2259                if atom[ct-1].split()[0] in ['C','N']:
2260                    Backbone.append(list(np.inner(Amat,np.array([x,y,z]))))
2261                    BackboneColor.append(list(color))
2262                   
2263            if atom[cs+1] == 'type':
2264                RenderLabel(x,y,z,atom[ct],radius)
2265            elif atom[cs+1] == 'name':
2266                RenderLabel(x,y,z,atom[ct-1],radius)
2267            elif atom[cs+1] == 'number':
2268                RenderLabel(x,y,z,str(iat+1),radius)
2269            elif atom[cs+1] == 'residue' and atom[ct-1] == 'CA':
2270                RenderLabel(x,y,z,atom[ct-4],radius)
2271            elif atom[cs+1] == '1-letter' and atom[ct-1] == 'CA':
2272                RenderLabel(x,y,z,atom[ct-3],radius)
2273            elif atom[cs+1] == 'chain' and atom[ct-1] == 'CA':
2274                RenderLabel(x,y,z,atom[ct-2],radius)
2275        if Backbone:
2276            RenderBackbone(Backbone,BackboneColor,bondR)
2277#        print time.time()-time0
2278        Page.canvas.SwapBuffers()
2279       
2280    def OnSize(event):
2281        Draw()
2282       
2283    def OnFocus(event):
2284        Draw()
2285       
2286    try:
2287        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2288        Page = self.G2plotNB.nb.GetPage(plotNum)       
2289    except ValueError:
2290        Plot = self.G2plotNB.addOgl(generalData['Name'])
2291        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2292        Page = self.G2plotNB.nb.GetPage(plotNum)
2293        Page.views = False
2294        view = False
2295        altDown = False
2296    Page.SetFocus()
2297    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
2298        choices=(' save as:','jpeg','tiff','bmp'))
2299    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
2300    cb.SetValue(' save as:')
2301    Page.canvas.Bind(wx.EVT_MOUSEWHEEL, OnMouseWheel)
2302    Page.canvas.Bind(wx.EVT_LEFT_DOWN, OnMouseDown)
2303    Page.canvas.Bind(wx.EVT_RIGHT_DOWN, OnMouseDown)
2304    Page.canvas.Bind(wx.EVT_MIDDLE_DOWN, OnMouseDown)
2305    Page.canvas.Bind(wx.EVT_KEY_UP, OnKey)
2306    Page.canvas.Bind(wx.EVT_MOTION, OnMouseMove)
2307    Page.canvas.Bind(wx.EVT_SIZE, OnSize)
2308    Page.canvas.Bind(wx.EVT_SET_FOCUS, OnFocus)
2309    Page.camera['position'] = drawingData['cameraPos']
2310    Page.camera['viewPoint'] = np.inner(Amat,drawingData['viewPoint'][0])
2311    Page.camera['backColor'] = np.array(list(drawingData['backColor'])+[0,])/255.
2312    Page.canvas.SetCurrent()
2313    Draw()
2314       
Note: See TracBrowser for help on using the repository browser.