source: trunk/GSASIIplot.py @ 265

Last change on this file since 265 was 265, checked in by vondreele, 11 years ago

further progress on implementing pdf calculations
optionally put legends on the pdf plots
attempt implementation of a rotation of the azimuth ranges for multiazimuth integrations -not fully successful

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