source: trunk/GSASIIplot.py @ 425

Last change on this file since 425 was 423, checked in by vondreele, 14 years ago

Add help to all dataDisplay menus
remove ring fit points from integration image - way too slow to plot
slight streamline for building of depDerivDict

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