source: trunk/GSASIIplot.py @ 289

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