source: trunk/GSASIIplot.py @ 1151

Last change on this file since 1151 was 1151, checked in by vondreele, 8 years ago

fix ring & arc masks

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 165.4 KB
Line 
1# -*- coding: utf-8 -*-
2'''
3*GSASIIplot: plotting routines*
4===============================
5
6'''
7########### SVN repository information ###################
8# $Date: 2013-11-25 20:01:08 +0000 (Mon, 25 Nov 2013) $
9# $Author: vondreele $
10# $Revision: 1151 $
11# $URL: trunk/GSASIIplot.py $
12# $Id: GSASIIplot.py 1151 2013-11-25 20:01:08Z vondreele $
13########### SVN repository information ###################
14import math
15import time
16import copy
17import sys
18import os.path
19import numpy as np
20import numpy.ma as ma
21import numpy.linalg as nl
22import wx
23import wx.aui
24import wx.glcanvas
25import matplotlib as mpl
26import mpl_toolkits.mplot3d.axes3d as mp3d
27import GSASIIpath
28GSASIIpath.SetVersionNumber("$Revision: 1151 $")
29import GSASIIgrid as G2gd
30import GSASIIimage as G2img
31import GSASIIpwd as G2pwd
32import GSASIIIO as G2IO
33import GSASIIpwdGUI as G2pdG
34import GSASIIimgGUI as G2imG
35import GSASIIphsGUI as G2phG
36import GSASIIlattice as G2lat
37import GSASIIspc as G2spc
38import GSASIImath as G2mth
39import pytexture as ptx
40from  OpenGL.GL import *
41from OpenGL.GLU import *
42from OpenGL.GLE import *
43import gltext
44from matplotlib.backends.backend_wx import _load_bitmap
45from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
46from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
47
48# useful degree trig functions
49sind = lambda x: math.sin(x*math.pi/180.)
50cosd = lambda x: math.cos(x*math.pi/180.)
51tand = lambda x: math.tan(x*math.pi/180.)
52asind = lambda x: 180.*math.asin(x)/math.pi
53acosd = lambda x: 180.*math.acos(x)/math.pi
54atan2d = lambda x,y: 180.*math.atan2(y,x)/math.pi
55atand = lambda x: 180.*math.atan(x)/math.pi
56# numpy versions
57npsind = lambda x: np.sin(x*np.pi/180.)
58npcosd = lambda x: np.cos(x*np.pi/180.)
59nptand = lambda x: np.tan(x*np.pi/180.)
60npacosd = lambda x: 180.*np.arccos(x)/np.pi
61npasind = lambda x: 180.*np.arcsin(x)/np.pi
62npatand = lambda x: 180.*np.arctan(x)/np.pi
63npatan2d = lambda x,y: 180.*np.arctan2(x,y)/np.pi
64   
65class G2PlotMpl(wx.Panel):   
66    'needs a doc string'
67    def __init__(self,parent,id=-1,dpi=None,**kwargs):
68        wx.Panel.__init__(self,parent,id=id,**kwargs)
69        mpl.rcParams['legend.fontsize'] = 10
70        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(5,6))
71        self.canvas = Canvas(self,-1,self.figure)
72        self.toolbar = GSASIItoolbar(self.canvas)
73
74        self.toolbar.Realize()
75       
76        sizer=wx.BoxSizer(wx.VERTICAL)
77        sizer.Add(self.canvas,1,wx.EXPAND)
78        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
79        self.SetSizer(sizer)
80       
81class G2PlotOgl(wx.Panel):
82    'needs a doc string'
83    def __init__(self,parent,id=-1,dpi=None,**kwargs):
84        self.figure = wx.Panel.__init__(self,parent,id=id,**kwargs)
85        if 'win' in sys.platform:           #Windows already double buffered
86            self.canvas = wx.glcanvas.GLCanvas(self,-1,**kwargs)
87        else:                               #fix from Jim Hester for X systems
88            attribs = (wx.glcanvas.WX_GL_DOUBLEBUFFER,)         
89            self.canvas = wx.glcanvas.GLCanvas(self,-1,attribList=attribs,**kwargs)
90        self.camera = {}
91        sizer=wx.BoxSizer(wx.VERTICAL)
92        sizer.Add(self.canvas,1,wx.EXPAND)
93        self.SetSizer(sizer)
94       
95class G2Plot3D(wx.Panel):
96    'needs a doc string'
97    def __init__(self,parent,id=-1,dpi=None,**kwargs):
98        wx.Panel.__init__(self,parent,id=id,**kwargs)
99        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(6,6))
100        self.canvas = Canvas(self,-1,self.figure)
101        self.toolbar = GSASIItoolbar(self.canvas)
102
103        self.toolbar.Realize()
104       
105        sizer=wx.BoxSizer(wx.VERTICAL)
106        sizer.Add(self.canvas,1,wx.EXPAND)
107        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
108        self.SetSizer(sizer)
109                             
110class G2PlotNoteBook(wx.Panel):
111    'create a tabbed window for plotting'
112    def __init__(self,parent,id=-1):
113        wx.Panel.__init__(self,parent,id=id)
114        #so one can't delete a plot page!!
115        self.nb = wx.aui.AuiNotebook(self, \
116            style=wx.aui.AUI_NB_DEFAULT_STYLE ^ wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
117        sizer = wx.BoxSizer()
118        sizer.Add(self.nb,1,wx.EXPAND)
119        self.SetSizer(sizer)
120        self.status = parent.CreateStatusBar()
121        self.status.SetFieldsCount(2)
122        self.status.SetStatusWidths([150,-1])
123        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
124        self.nb.Bind(wx.EVT_KEY_UP,self.OnNotebookKey)
125       
126        self.plotList = []
127           
128    def OnNotebookKey(self,event):
129        '''Called when a keystroke event gets picked up by the notebook window
130        rather the child. This is not expected, but somehow it does sometimes
131        on the Mac and perhaps Linux.
132
133        Assume that the page associated with the currently displayed tab
134        has a child, .canvas; give that child the focus and pass it the event.
135        '''
136        try:
137            Page = self.nb.GetPage(self.nb.GetSelection())
138        except ValueError: # occurs with no plot tabs
139            return
140        try:
141            Page.canvas.SetFocus()
142            wx.PostEvent(Page.canvas,event)
143        except AttributeError:
144            pass
145
146    def addMpl(self,name=""):
147        'Add a tabbed page with a matplotlib plot'
148        page = G2PlotMpl(self.nb)
149        self.nb.AddPage(page,name)
150       
151        self.plotList.append(name)
152       
153        return page.figure
154       
155    def add3D(self,name=""):
156        'Add a tabbed page with a 3D plot'
157        page = G2Plot3D(self.nb)
158        self.nb.AddPage(page,name)
159       
160        self.plotList.append(name)
161       
162        return page.figure
163       
164    def addOgl(self,name=""):
165        'Add a tabbed page with an openGL plot'
166        page = G2PlotOgl(self.nb)
167        self.nb.AddPage(page,name)
168       
169        self.plotList.append(name)
170       
171        return page.figure
172       
173    def Delete(self,name):
174        'delete a tabbed page'
175        try:
176            item = self.plotList.index(name)
177            del self.plotList[item]
178            self.nb.DeletePage(item)
179        except ValueError:          #no plot of this name - do nothing
180            return     
181               
182    def clear(self):
183        'clear all pages from plot window'
184        while self.nb.GetPageCount():
185            self.nb.DeletePage(0)
186        self.plotList = []
187        self.status.DestroyChildren()
188       
189    def Rename(self,oldName,newName):
190        'rename a tab'
191        try:
192            item = self.plotList.index(oldName)
193            self.plotList[item] = newName
194            self.nb.SetPageText(item,newName)
195        except ValueError:          #no plot of this name - do nothing
196            return     
197       
198    def OnPageChanged(self,event):
199        'respond to someone pressing a tab on the plot window'
200        if self.plotList:
201            self.status.SetStatusText('Better to select this from GSAS-II data tree',1)
202        self.status.DestroyChildren()                           #get rid of special stuff on status bar
203       
204class GSASIItoolbar(Toolbar):
205    'needs a doc string'
206    ON_MPL_HELP = wx.NewId()
207    ON_MPL_KEY = wx.NewId()
208    def __init__(self,plotCanvas):
209        Toolbar.__init__(self,plotCanvas)
210        POSITION_OF_CONFIGURE_SUBPLOTS_BTN = 6
211        self.DeleteToolByPos(POSITION_OF_CONFIGURE_SUBPLOTS_BTN)
212        parent = self.GetParent()
213        key = os.path.join(os.path.split(__file__)[0],'key.ico')
214        self.AddSimpleTool(self.ON_MPL_KEY,_load_bitmap(key),'Key press','Select key press')
215        wx.EVT_TOOL(self,self.ON_MPL_KEY,self.OnKey)
216        help = os.path.join(os.path.split(__file__)[0],'help.ico')
217        self.AddSimpleTool(self.ON_MPL_HELP,_load_bitmap(help),'Help on','Show help on')
218        wx.EVT_TOOL(self,self.ON_MPL_HELP,self.OnHelp)
219    def OnHelp(self,event):
220        'needs a doc string'
221        Page = self.GetParent().GetParent()
222        pageNo = Page.GetSelection()
223        bookmark = Page.GetPageText(pageNo)
224        bookmark = bookmark.strip(')').replace('(','_')
225        G2gd.ShowHelp(bookmark,self.TopLevelParent)
226    def OnKey(self,event):
227        'needs a doc string'
228        parent = self.GetParent()
229        if parent.Choice:
230            dlg = wx.SingleChoiceDialog(parent,'Select','Key press',list(parent.Choice))
231            if dlg.ShowModal() == wx.ID_OK:
232                sel = dlg.GetSelection()
233                event.key = parent.Choice[sel][0]
234                parent.keyPress(event)
235            dlg.Destroy()
236           
237################################################################################
238##### PlotSngl
239################################################################################
240           
241def PlotSngl(self,newPlot=False):
242    '''Single crystal structure factor plotting package - displays zone of reflections as rings proportional
243        to F, F**2, etc. as requested
244    '''
245    from matplotlib.patches import Circle,CirclePolygon
246    global HKL,HKLF
247
248    def OnSCMotion(event):
249        xpos = event.xdata
250        if xpos:
251            xpos = round(xpos)                                        #avoid out of frame mouse position
252            ypos = round(event.ydata)
253            zpos = Data['Layer']
254            if '100' in Data['Zone']:
255                HKLtxt = '(%3d,%3d,%3d)'%(zpos,xpos,ypos)
256            elif '010' in Data['Zone']:
257                HKLtxt = '(%3d,%3d,%3d)'%(xpos,zpos,ypos)
258            elif '001' in Data['Zone']:
259                HKLtxt = '(%3d,%3d,%3d)'%(xpos,ypos,zpos)
260            Page.canvas.SetToolTipString(HKLtxt)
261            self.G2plotNB.status.SetFields(['HKL = '+HKLtxt,''])
262               
263    def OnSCPick(event):
264        zpos = Data['Layer']
265        pos = event.artist.center
266        if '100' in Data['Zone']:
267            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(zpos,pos[0],pos[1]))
268            hkl = np.array([zpos,pos[0],pos[1]])
269        elif '010' in Data['Zone']:
270            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],zpos,pos[1]))
271            hkl = np.array([pos[0],zpos,pos[1]])
272        elif '001' in Data['Zone']:
273            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],pos[1],zpos))
274            hkl = np.array([pos[0],pos[1],zpos])
275        h,k,l = hkl
276        hklf = HKLF[np.where(np.all(HKL-hkl == [0,0,0],axis=1))]
277        if len(hklf):
278            Fosq,sig,Fcsq = hklf[0]
279            HKLtxt = '(%3d,%3d,%3d %.2f %.3f %.2f %.2f)'%(h,k,l,Fosq,sig,Fcsq,(Fosq-Fcsq)/(scale*sig))
280            self.G2plotNB.status.SetFields(['','HKL, Fosq, sig, Fcsq, delFsq/sig = '+HKLtxt])
281                                 
282    try:
283        plotNum = self.G2plotNB.plotList.index('Structure Factors')
284        Page = self.G2plotNB.nb.GetPage(plotNum)
285        if not newPlot:
286            Plot = Page.figure.gca()          #get previous powder plot & get limits
287            xylim = Plot.get_xlim(),Plot.get_ylim()
288        Page.figure.clf()
289        Page.Choice = None
290        Plot = Page.figure.gca()          #get a fresh plot after clf()
291    except ValueError:
292        Plot = self.G2plotNB.addMpl('Structure Factors').gca()
293        plotNum = self.G2plotNB.plotList.index('Structure Factors')
294        Page = self.G2plotNB.nb.GetPage(plotNum)
295        Page.canvas.mpl_connect('pick_event', OnSCPick)
296        Page.canvas.mpl_connect('motion_notify_event', OnSCMotion)
297    Page.Choice = None
298    Page.SetFocus()
299   
300    Plot.set_aspect(aspect='equal')
301    HKLref = self.PatternTree.GetItemPyData(self.Sngl)[1]['RefList']
302    Data = self.PatternTree.GetItemPyData( 
303        G2gd.GetPatternTreeItemId(self,self.Sngl, 'HKL Plot Controls'))
304    Type = Data['Type']           
305    scale = Data['Scale']
306    HKLmax = Data['HKLmax']
307    HKLmin = Data['HKLmin']
308    FosqMax = Data['FoMax']
309    FoMax = math.sqrt(FosqMax)
310    xlabel = ['k, h=','h, k=','h, l=']
311    ylabel = ['l','l','k']
312    zones = ['100','010','001']
313    pzone = [[1,2],[0,2],[0,1]]
314    izone = zones.index(Data['Zone'])
315    Plot.set_title(self.PatternTree.GetItemText(self.Sngl)[5:])
316    HKL = []
317    HKLF = []
318    time0 = time.time()
319    for refl in HKLref:
320        H = np.array(refl[:3])
321        Fosq,sig,Fcsq = refl[5:8]
322        HKL.append(H)
323        HKLF.append([Fosq,sig,Fcsq])
324        if H[izone] == Data['Layer']:
325            A = 0
326            B = 0
327            if Type == 'Fosq':
328                A = scale*Fosq/FosqMax
329                B = scale*Fcsq/FosqMax
330                C = abs(A-B)
331            elif Type == 'Fo':
332                A = scale*math.sqrt(max(0,Fosq))/FoMax
333                B = scale*math.sqrt(max(0,Fcsq))/FoMax
334                C = abs(A-B)
335            elif Type == '|DFsq|/sig':
336                if sig > 0.:
337                    A = scale*(Fosq-Fcsq)/(sig)
338                B = 0
339            elif Type == '|DFsq|>sig':
340                if sig > 0.:
341                    A = (Fosq-Fcsq)/sig
342                if abs(A) < 1.0: A = 0
343                A *= scale
344                B = 0                   
345            elif Type == '|DFsq|>3sig':
346                if sig > 0.:
347                    A = (Fosq-Fcsq)/sig
348                if abs(A) < 3.0: A = 0
349                A *= scale
350                B = 0                   
351            xy = (H[pzone[izone][0]],H[pzone[izone][1]])
352            if Type in ['|DFsq|/sig','|DFsq|>sig','|DFsq|>3sig']:
353                if A > 0.0:
354                    Plot.add_artist(Circle(xy,radius=A,ec='g',fc='w',picker=3))
355                else:
356                    Plot.add_artist(Circle(xy,radius=-A,ec='r',fc='w',picker=3))
357            else:
358                if A > 0.0 and A > B:
359                    Plot.add_artist(Circle(xy,radius=A,ec='g',fc='w',picker=3))
360                if B:
361                    Plot.add_artist(Circle(xy,radius=B,ec='b',fc='w'))
362                    if A < B:
363                        Plot.add_artist(Circle(xy,radius=A,ec='g',fc='w',picker=3))
364                    radius = C
365                    if radius > 0:
366                        if A > B:
367                            Plot.add_artist(Circle(xy,radius=radius,ec='g',fc='g'))
368                        else:                   
369                            Plot.add_artist(Circle(xy,radius=radius,ec='r',fc='r'))
370#    print 'plot time: %.3f'%(time.time()-time0)
371    HKL = np.array(HKL,dtype=np.int)
372    HKLF = np.array(HKLF)
373    Plot.set_xlabel(xlabel[izone]+str(Data['Layer']),fontsize=12)
374    Plot.set_ylabel(ylabel[izone],fontsize=12)
375    Plot.set_xlim((HKLmin[pzone[izone][0]],HKLmax[pzone[izone][0]]))
376    Plot.set_ylim((HKLmin[pzone[izone][1]],HKLmax[pzone[izone][1]]))
377    Page.canvas.draw()
378#    if not newPlot:
379#        Page.toolbar.push_current()
380#        Plot.set_xlim(xylim[0])
381#        Plot.set_ylim(xylim[1])
382#        xylim = []
383#        Page.toolbar.push_current()
384#        Page.toolbar.draw()
385#    else:
386#        Page.canvas.draw()
387       
388################################################################################
389##### PlotPatterns
390################################################################################
391           
392def PlotPatterns(G2frame,newPlot=False):
393    '''Powder pattern plotting package - displays single or multiple powder patterns as intensity vs
394    2-theta, q or TOF. Can display multiple patterns as "waterfall plots" or contour plots. Log I
395    plotting available.
396    '''
397    global HKL
398    global exclLines
399    def OnPlotKeyPress(event):
400        newPlot = False
401        if event.key == 'w':
402            if G2frame.Weight:
403                G2frame.Weight = False
404            else:
405                G2frame.Weight = True
406                G2frame.SinglePlot = True
407            newPlot = True
408        elif event.key == 'b':
409            if G2frame.SubBack:
410                G2frame.SubBack = False
411            else:
412                G2frame.SubBack = True
413                G2frame.SinglePlot = True               
414        elif event.key == 'n':
415            if G2frame.Contour:
416                pass
417            else:
418                if G2frame.logPlot:
419                    G2frame.logPlot = False
420                else:
421                    G2frame.Offset[0] = 0
422                    G2frame.logPlot = True
423                newPlot = True
424        elif event.key == 'u':
425            if G2frame.Contour:
426                G2frame.Cmax = min(1.0,G2frame.Cmax*1.2)
427            elif G2frame.logPlot:
428                pass
429            elif G2frame.Offset[0] < 100.:
430                G2frame.Offset[0] += 1.
431        elif event.key == 'd':
432            if G2frame.Contour:
433                G2frame.Cmax = max(0.0,G2frame.Cmax*0.8)
434            elif G2frame.logPlot:
435                pass
436            elif G2frame.Offset[0] > 0.:
437                G2frame.Offset[0] -= 1.
438        elif event.key == 'l':
439            G2frame.Offset[1] -= 1.
440        elif event.key == 'r':
441            G2frame.Offset[1] += 1.
442        elif event.key == 'o':
443            G2frame.Offset = [0,0]
444        elif event.key == 'c':
445            newPlot = True
446            if G2frame.Contour:
447                G2frame.Contour = False
448            else:
449                G2frame.Contour = True
450                G2frame.SinglePlot = False
451                G2frame.Offset = [0.,0.]
452        elif event.key == 'q':
453            newPlot = True
454            if G2frame.qPlot:
455                G2frame.qPlot = False
456            else:
457                G2frame.qPlot = True
458        elif event.key == 's':
459            if G2frame.Contour:
460                choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
461                choice.sort()
462                dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
463                if dlg.ShowModal() == wx.ID_OK:
464                    sel = dlg.GetSelection()
465                    G2frame.ContourColor = choice[sel]
466                else:
467                    G2frame.ContourColor = 'Paired'
468                dlg.Destroy()
469            else:               
470                if G2frame.SinglePlot:
471                    G2frame.SinglePlot = False
472                else:
473                    G2frame.SinglePlot = True
474            newPlot = True
475        elif event.key == '+':
476            if G2frame.PickId:
477                G2frame.PickId = False
478        elif event.key == 'i':                  #for smoothing contour plot
479            choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
480               'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
481               'mitchell','sinc','lanczos']
482            dlg = wx.SingleChoiceDialog(G2frame,'Select','Interpolation',choice)
483            if dlg.ShowModal() == wx.ID_OK:
484                sel = dlg.GetSelection()
485                G2frame.Interpolate = choice[sel]
486            else:
487                G2frame.Interpolate = 'nearest'
488            dlg.Destroy()
489           
490        PlotPatterns(G2frame,newPlot=newPlot)
491       
492    def OnMotion(event):
493        xpos = event.xdata
494        if xpos:                                        #avoid out of frame mouse position
495            ypos = event.ydata
496            Page.canvas.SetCursor(wx.CROSS_CURSOR)
497            try:
498                Parms,Parms2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
499                if 'C' in Parms['Type'][0]:
500                    wave = G2mth.getWave(Parms)
501                    if G2frame.qPlot:
502                        try:
503                            xpos = 2.0*asind(xpos*wave/(4*math.pi))
504                        except ValueError:      #avoid bad value in asin beyond upper limit
505                            pass
506                    dsp = 0.0
507                    if abs(xpos) > 0.:                  #avoid possible singularity at beam center
508                        dsp = wave/(2.*sind(abs(xpos)/2.0))
509                    if G2frame.Contour:
510                        G2frame.G2plotNB.status.SetStatusText('2-theta =%9.3f d =%9.5f pattern ID =%5d'%(xpos,dsp,int(ypos)),1)
511                    else:
512                        G2frame.G2plotNB.status.SetStatusText('2-theta =%9.3f d =%9.5f Intensity =%9.1f'%(xpos,dsp,ypos),1)
513                else:       #TOF neutrons
514                    dsp = 0.0
515                    difC = Parms['difC'][1]
516                    dsp = xpos/difC             #rough approx.!
517                    if G2frame.Contour:
518                        G2frame.G2plotNB.status.SetStatusText('TOF =%9.3f d =%9.5f pattern ID =%5d'%(xpos,dsp,int(ypos)),1)
519                    else:
520                        G2frame.G2plotNB.status.SetStatusText('TOF =%9.3f d =%9.5f Intensity =%9.1f'%(xpos,dsp,ypos),1)
521                if G2frame.itemPicked:
522                    Page.canvas.SetToolTipString('%9.3f'%(xpos))
523                if G2frame.PickId:
524                    found = []
525                    if G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Index Peak List','Unit Cells List','Reflection Lists'] or \
526                        'PWDR' in G2frame.PatternTree.GetItemText(PickId):
527                        if len(HKL):
528                            view = Page.toolbar._views.forward()[0][:2]
529                            wid = view[1]-view[0]
530                            found = HKL[np.where(np.fabs(HKL.T[5]-xpos) < 0.002*wid)]
531                        if len(found):
532                            h,k,l = found[0][:3] 
533                            Page.canvas.SetToolTipString('%d,%d,%d'%(int(h),int(k),int(l)))
534                        else:
535                            Page.canvas.SetToolTipString('')
536
537            except TypeError:
538                G2frame.G2plotNB.status.SetStatusText('Select PWDR powder pattern first',1)
539                                                   
540    def OnPick(event):
541        if G2frame.itemPicked is not None: return
542        PatternId = G2frame.PatternId
543        try:
544            Parms,Parms2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
545        except TypeError:
546            return
547        if 'C' in Parms['Type'][0]:
548            wave = G2mth.getWave(Parms)
549        else:
550            difC = Parms['difC'][1]
551        PickId = G2frame.PickId
552        pick = event.artist
553        mouse = event.mouseevent       
554        xpos = pick.get_xdata()
555        ypos = pick.get_ydata()
556        ind = event.ind
557        xy = list(zip(np.take(xpos,ind),np.take(ypos,ind))[0])
558        if G2frame.PatternTree.GetItemText(PickId) == 'Peak List':
559            if ind.all() != [0]:                                    #picked a data point
560                data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
561                XY = G2mth.setPeakparms(Parms,Parms2,xy[0],xy[1])           #what happens for a q-plot???
562                data.append(XY)
563                G2pdG.UpdatePeakGrid(G2frame,data)
564                PlotPatterns(G2frame)
565            else:                                                   #picked a peak list line
566                G2frame.itemPicked = pick
567        elif G2frame.PatternTree.GetItemText(PickId) == 'Limits':
568            if ind.all() != [0]:                                    #picked a data point
569                LimitId = G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits')
570                data = G2frame.PatternTree.GetItemPyData(LimitId)
571                if 'C' in Parms['Type'][0]:                            #CW data - TOF later in an elif
572                    if G2frame.qPlot:                              #qplot - convert back to 2-theta
573                        xy[0] = 2.0*asind(xy[0]*wave/(4*math.pi))
574                if G2frame.ifGetExclude:
575                    excl = [0,0]
576                    excl[0] = max(data[1][0],min(xy[0],data[1][1]))
577                    excl[1] = excl[0]+0.1
578                    data.append(excl)
579                    G2frame.ifGetExclude = False
580                else:
581                    if mouse.button==1:
582                        data[1][0] = min(xy[0],data[1][1])
583                    if mouse.button==3:
584                        data[1][1] = max(xy[0],data[1][0])
585                G2frame.PatternTree.SetItemPyData(LimitId,data)
586                G2pdG.UpdateLimitsGrid(G2frame,data)
587                wx.CallAfter(PlotPatterns,G2frame)
588            else:                                                   #picked a limit line
589                G2frame.itemPicked = pick
590        elif G2frame.PatternTree.GetItemText(PickId) == 'Reflection Lists' or \
591            'PWDR' in G2frame.PatternTree.GetItemText(PickId):
592            G2frame.itemPicked = pick
593            pick = str(pick)
594       
595    def OnRelease(event):
596        if G2frame.itemPicked is None: return
597        Parms,Parms2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
598        if 'C' in Parms['Type'][0]:
599            wave = G2mth.getWave(Parms)
600        else:
601            difC = Parms['difC'][1]
602        xpos = event.xdata
603        PickId = G2frame.PickId
604        if G2frame.PatternTree.GetItemText(PickId) in ['Peak List','Limits'] and xpos:
605            lines = []
606            for line in G2frame.Lines: 
607                lines.append(line.get_xdata()[0])
608#            print G2frame.itemPicked.get_xdata()
609            lineNo = lines.index(G2frame.itemPicked.get_xdata()[0])
610            if  lineNo in [0,1] or lineNo in exclLines:
611                LimitId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits')
612                data = G2frame.PatternTree.GetItemPyData(LimitId)
613                id = lineNo/2+1
614                id2 = lineNo%2
615                if G2frame.qPlot:
616                    if 'C' in Parms['Type'][0]:
617                        data[id][id2] = 2.0*asind(wave*xpos/(4*math.pi))
618                    else:
619                        data[id][id2] = 2*math.pi*Parms['difC'][1]/xpos
620                else:
621                    data[id][id2] = xpos
622                if id > 1 and data[id][0] > data[id][1]:
623                        data[id].reverse()
624                G2frame.PatternTree.SetItemPyData(LimitId,data)
625                if G2frame.PatternTree.GetItemText(G2frame.PickId) == 'Limits':
626                    G2pdG.UpdateLimitsGrid(G2frame,data)
627            else:
628                PeakId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List')
629                data = G2frame.PatternTree.GetItemPyData(PeakId)
630                if event.button == 3:
631                    del data[lineNo-2]
632                else:
633                    if G2frame.qPlot:
634                        data[lineNo-2][0] = 2.0*asind(wave*xpos/(4*math.pi))
635                    else:
636                        data[lineNo-2][0] = xpos
637                G2frame.PatternTree.SetItemPyData(PeakId,data)
638                G2pdG.UpdatePeakGrid(G2frame,data)
639        elif (G2frame.PatternTree.GetItemText(PickId) == 'Reflection Lists' or \
640            'PWDR' in G2frame.PatternTree.GetItemText(PickId)) and xpos:
641            Phases = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))
642            pick = str(G2frame.itemPicked).split('(')[1].strip(')')
643            if 'line' not in pick:       #avoid data points, etc.
644                num = Phases.keys().index(pick)
645                if num:
646                    G2frame.refDelt = -(event.ydata-G2frame.refOffset)/(num*Ymax)
647                else:       #1st row of refl ticks
648                    G2frame.refOffset = event.ydata
649        PlotPatterns(G2frame)
650        G2frame.itemPicked = None   
651
652    xylim = []
653    try:
654        plotNum = G2frame.G2plotNB.plotList.index('Powder Patterns')
655        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
656        if not newPlot:
657            Plot = Page.figure.gca()          #get previous powder plot & get limits
658            xylim = Plot.get_xlim(),Plot.get_ylim()
659        Page.figure.clf()
660        Plot = Page.figure.gca()          #get a fresh plot after clf()
661    except ValueError:
662        newPlot = True
663        G2frame.Cmax = 1.0
664        Plot = G2frame.G2plotNB.addMpl('Powder Patterns').gca()
665        plotNum = G2frame.G2plotNB.plotList.index('Powder Patterns')
666        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
667        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
668        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
669        Page.canvas.mpl_connect('pick_event', OnPick)
670        Page.canvas.mpl_connect('button_release_event', OnRelease)
671    Page.SetFocus()
672    G2frame.G2plotNB.status.DestroyChildren()
673    if G2frame.Contour:
674        Page.Choice = (' key press','d: lower contour max','u: raise contour max',
675            'i: interpolation method','s: color scheme','c: contour off')
676    else:
677        if G2frame.logPlot:
678            Page.Choice = (' key press','n: log(I) off','l: offset left','r: offset right',
679                'c: contour on','q: toggle q plot','s: toggle single plot','+: no selection')
680        else:
681            Page.Choice = (' key press','l: offset left','r: offset right','d: offset down',
682                'u: offset up','o: reset offset','b: toggle subtract background','n: log(I) on','c: contour on',
683                'q: toggle q plot','s: toggle single plot','w: toggle divide by sig','+: no selection')
684    Page.keyPress = OnPlotKeyPress
685   
686    PickId = G2frame.PickId
687    PatternId = G2frame.PatternId
688    colors=['b','g','r','c','m','k']
689    Lines = []
690    exclLines = []
691    if G2frame.SinglePlot:
692        Pattern = G2frame.PatternTree.GetItemPyData(PatternId)
693        Pattern.append(G2frame.PatternTree.GetItemText(PatternId))
694        PlotList = [Pattern,]
695        Parms,Parms2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
696            G2frame.PatternId, 'Instrument Parameters'))
697        ParmList = [Parms,]
698        Title = Pattern[-1]
699    else:       
700        Title = os.path.split(G2frame.GSASprojectfile)[1]
701        PlotList = []
702        ParmList = []
703        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
704        while item:
705            if 'PWDR' in G2frame.PatternTree.GetItemText(item):
706                Pattern = G2frame.PatternTree.GetItemPyData(item)
707                if len(Pattern) < 3:                    # put name on end if needed
708                    Pattern.append(G2frame.PatternTree.GetItemText(item))
709                PlotList.append(Pattern)
710                ParmList.append(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
711                    item,'Instrument Parameters'))[0])
712            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)               
713    lenX = 0
714    if PickId:
715        if G2frame.PatternTree.GetItemText(PickId) in ['Reflection Lists']:
716            Phases = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))
717            HKL = []
718            if Phases:
719                try:
720                    for peak in Phases[G2frame.RefList]['RefList']:
721                        HKL.append(peak[:6])
722                except TypeError:
723                    for peak in Phases[G2frame.RefList]:
724                        HKL.append(peak[:6])                   
725                HKL = np.array(HKL)
726        else:
727            HKL = np.array(G2frame.HKL)
728    Ymax = None
729    for Pattern in PlotList:
730        xye = Pattern[1]
731        if xye[1] is None: continue
732        if Ymax is None: Ymax = max(xye[1])
733        Ymax = max(Ymax,max(xye[1]))
734    if Ymax is None: return # nothing to plot
735    offset = G2frame.Offset[0]*Ymax/100.0
736    if G2frame.logPlot:
737        Title = 'log('+Title+')'
738    Plot.set_title(Title)
739    if G2frame.qPlot:
740        Plot.set_xlabel(r'$Q, \AA^{-1}$',fontsize=14)
741    else:
742        if 'C' in ParmList[0]['Type'][0]:       
743            Plot.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
744        else:
745            Plot.set_xlabel(r'TOF, $\mathsf{\mu}$s',fontsize=14)           
746    if G2frame.Weight:
747        Plot.set_ylabel(r'$\mathsf{I/\sigma(I)}$',fontsize=14)
748    else:
749        if 'C' in ParmList[0]['Type'][0]:
750            Plot.set_ylabel('Intensity',fontsize=14)
751        else:
752            Plot.set_ylabel('Normalized intensity',fontsize=14)
753    if G2frame.Contour:
754        ContourZ = []
755        ContourY = []
756        Nseq = 0
757    if len(PlotList) < 2:
758        G2frame.Contour = False
759    for N,Pattern in enumerate(PlotList):
760        Parms = ParmList[N]
761        if 'C' in Parms['Type'][0]:
762            wave = G2mth.getWave(Parms)
763        else:
764            difC = Parms['difC'][1]
765        ifpicked = False
766        LimitId = 0
767        if Pattern[1] is None: continue # skip over uncomputed simulations
768        xye = ma.array(ma.getdata(Pattern[1]))
769        if PickId:
770            ifpicked = Pattern[2] == G2frame.PatternTree.GetItemText(PatternId)
771            LimitId = G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits')
772            limits = np.array(G2frame.PatternTree.GetItemPyData(LimitId))
773            excls = limits[2:]
774            for excl in excls:
775                xye[0] = ma.masked_inside(xye[0],excl[0],excl[1])
776        if G2frame.qPlot:
777            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, Pattern[2])
778            if 'C' in Parms['Type'][0]:
779                X = 4*np.pi*npsind((xye[0]-Parms['Zero'][1])/2.0)/wave
780            else:
781                X = 2*np.pi*Parms['difC'][1]/(xye[0]-Parms['Zero'][1])
782        else:
783            X = xye[0]-Parms['Zero'][1]
784        if not lenX:
785            lenX = len(X)
786        Y = xye[1]+offset*N
787        if LimitId:
788            limits = np.array(G2frame.PatternTree.GetItemPyData(LimitId))
789            if G2frame.qPlot:
790                if 'C' in Parms['Type'][0]:
791                    limits = 4*np.pi*npsind(limits/2.0)/wave
792                else:
793                    limits = 2*np.pi*difC/limits
794            Lines.append(Plot.axvline(limits[1][0],color='g',dashes=(5,5),picker=3.))   
795            Lines.append(Plot.axvline(limits[1][1],color='r',dashes=(5,5),picker=3.))
796            for i,item in enumerate(limits[2:]):
797                Lines.append(Plot.axvline(item[0],color='m',dashes=(5,5),picker=3.))   
798                Lines.append(Plot.axvline(item[1],color='m',dashes=(5,5),picker=3.))
799                exclLines += [2*i+2,2*i+3]
800        if G2frame.Contour:
801           
802            if lenX == len(X):
803                ContourY.append(N)
804                ContourZ.append(Y)
805                ContourX = X
806                Nseq += 1
807                Plot.set_ylabel('Data sequence',fontsize=12)
808        else:
809            X += G2frame.Offset[1]*.005*N
810            Xum = ma.getdata(X)
811            if ifpicked:
812                Z = xye[3]+offset*N
813                W = xye[4]+offset*N
814                D = xye[5]-Ymax*G2frame.delOffset
815                if G2frame.logPlot:
816                    Plot.semilogy(X,Y,colors[N%6]+'+',picker=3.,clip_on=False,nonposy='mask')
817                    Plot.semilogy(X,Z,colors[(N+1)%6],picker=False,nonposy='mask')
818                    Plot.semilogy(X,W,colors[(N+2)%6],picker=False,nonposy='mask')
819                elif G2frame.Weight:
820                    DY = xye[1]*np.sqrt(xye[2])
821                    DYmax = max(DY)
822                    DZ = xye[3]*np.sqrt(xye[2])
823                    DS = xye[5]*np.sqrt(xye[2])-DYmax*G2frame.delOffset
824                    Plot.plot(X,DY,colors[N%6]+'+',picker=3.,clip_on=False)
825                    Plot.plot(X,DZ,colors[(N+1)%6],picker=False)
826                    Plot.plot(X,DS,colors[(N+3)%6],picker=False)
827                    Plot.axhline(0.,color=wx.BLACK)
828                else:
829                    if G2frame.SubBack:
830                        Plot.plot(Xum,Y-W,colors[N%6]+'+',picker=3.,clip_on=False)
831                        Plot.plot(X,Z-W,colors[(N+1)%6],picker=False)
832                    else:
833                        Plot.plot(Xum,Y,colors[N%6]+'+',picker=3.,clip_on=False)
834                        Plot.plot(X,Z,colors[(N+1)%6],picker=False)
835                    Plot.plot(X,W,colors[(N+2)%6],picker=False)
836                    Plot.plot(X,D,colors[(N+3)%6],picker=False)
837                    Plot.axhline(0.,color=wx.BLACK)
838                Page.canvas.SetToolTipString('')
839                if G2frame.PatternTree.GetItemText(PickId) == 'Peak List':
840                    tip = 'On data point: Pick peak - L or R MB. On line: L-move, R-delete'
841                    Page.canvas.SetToolTipString(tip)
842                    data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
843                    for item in data:
844                        if G2frame.qPlot:
845                            if 'C' in Parms['Type'][0]:
846                                Lines.append(Plot.axvline(4*math.pi*sind(item[0]/2.)/wave,color=colors[N%6],picker=2.))
847                            else:
848                                Lines.append(Plot.axvline(2*math.pi*difC/item[0],color=colors[N%6],picker=2.))                               
849                        else:
850                            Lines.append(Plot.axvline(item[0],color=colors[N%6],picker=2.))
851                if G2frame.PatternTree.GetItemText(PickId) == 'Limits':
852                    tip = 'On data point: Lower limit - L MB; Upper limit - R MB. On limit: MB down to move'
853                    Page.canvas.SetToolTipString(tip)
854                    data = G2frame.LimitsTable.GetData()
855            else:
856                if G2frame.logPlot:
857                    Plot.semilogy(X,Y,colors[N%6],picker=False,nonposy='clip')
858                else:
859                    Plot.plot(X,Y,colors[N%6],picker=False)
860    if PickId and not G2frame.Contour:
861        Parms,Parms2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
862        if 'C' in Parms['Type'][0]:
863            wave = G2mth.getWave(Parms)
864        else:
865            difC = Parms['difC'][1]
866        if G2frame.PatternTree.GetItemText(PickId) in ['Index Peak List','Unit Cells List']:
867            peaks = np.array((G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))))
868            for peak in peaks:
869                if G2frame.qPlot:
870                    Plot.axvline(4*np.pi*sind(peak[0]/2.0)/wave,color='b')
871                else:
872                    Plot.axvline(peak[0],color='b')
873            for hkl in G2frame.HKL:
874                if G2frame.qPlot:
875                    Plot.axvline(4*np.pi*sind(hkl[5]/2.0)/wave,color='r',dashes=(5,5))
876                else:
877                    Plot.axvline(hkl[5],color='r',dashes=(5,5))
878        elif G2frame.PatternTree.GetItemText(PickId) in ['Reflection Lists'] or \
879            'PWDR' in G2frame.PatternTree.GetItemText(PickId):
880            refColors=['b','r','c','g','m','k']
881            Phases = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))
882            for pId,phase in enumerate(Phases):
883                try:    #patch for old style reflection lists
884                    peaks = Phases[phase]['RefList']
885                except TypeError:
886                    peaks = Phases[phase]
887                if not len(peaks):
888                    continue
889                peak = np.array([[peak[4],peak[5]] for peak in peaks])
890                pos = G2frame.refOffset-pId*Ymax*G2frame.refDelt*np.ones_like(peak)
891                if G2frame.qPlot:
892                    Plot.plot(2*np.pi/peak.T[0],pos,refColors[pId%6]+'|',mew=1,ms=8,picker=3.,label=phase)
893                else:
894                    Plot.plot(peak.T[1],pos,refColors[pId%6]+'|',mew=1,ms=8,picker=3.,label=phase)
895            if len(Phases):
896                handles,legends = Plot.get_legend_handles_labels()  #got double entries in the legends for some reason
897                if handles:
898                    Plot.legend(handles[::2],legends[::2],title='Phases',loc='best')    #skip every other one
899           
900    if G2frame.Contour:
901        acolor = mpl.cm.get_cmap(G2frame.ContourColor)
902        Img = Plot.imshow(ContourZ,cmap=acolor,vmin=0,vmax=Ymax*G2frame.Cmax,interpolation=G2frame.Interpolate, 
903            extent=[ContourX[0],ContourX[-1],ContourY[0],ContourY[-1]],aspect='auto',origin='lower')
904        Page.figure.colorbar(Img)
905    else:
906        G2frame.Lines = Lines
907    if not newPlot:
908        Page.toolbar.push_current()
909        Plot.set_xlim(xylim[0])
910        Plot.set_ylim(xylim[1])
911        xylim = []
912        Page.toolbar.push_current()
913        Page.toolbar.draw()
914    else:
915        Page.canvas.draw()
916#    G2frame.Pwdr = True
917   
918################################################################################
919##### PlotDeltSig
920################################################################################
921           
922def PlotDeltSig(G2frame,kind):
923    'needs a doc string'
924    try:
925        plotNum = G2frame.G2plotNB.plotList.index('Error analysis')
926        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
927        Page.figure.clf()
928        Plot = Page.figure.gca()          #get a fresh plot after clf()
929    except ValueError:
930        newPlot = True
931        G2frame.Cmax = 1.0
932        Plot = G2frame.G2plotNB.addMpl('Error analysis').gca()
933        plotNum = G2frame.G2plotNB.plotList.index('Error analysis')
934        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
935    Page.Choice = None
936    PatternId = G2frame.PatternId
937    Pattern = G2frame.PatternTree.GetItemPyData(PatternId)
938    Pattern.append(G2frame.PatternTree.GetItemText(PatternId))
939    wtFactor = Pattern[0]['wtFactor']
940    if kind == 'PWDR':
941        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
942        xye = np.array(Pattern[1])
943        xmin = np.searchsorted(xye[0],limits[0])
944        xmax = np.searchsorted(xye[0],limits[1])
945        DS = xye[5][xmin:xmax]*np.sqrt(wtFactor*xye[2][xmin:xmax])
946    elif kind == 'HKLF':
947        refl = Pattern[1]
948        DS = []
949        for ref in refl:
950            if ref[6] > 0.:
951                DS.append((ref[5]-ref[7])/ref[6])
952    Page.SetFocus()
953    G2frame.G2plotNB.status.DestroyChildren()
954    DS.sort()
955    EDS = np.zeros_like(DS)
956    DX = np.linspace(0.,1.,num=len(DS),endpoint=True)
957    oldErr = np.seterr(invalid='ignore')    #avoid problem at DX==0
958    T = np.sqrt(np.log(1.0/DX**2))
959    top = 2.515517+0.802853*T+0.010328*T**2
960    bot = 1.0+1.432788*T+0.189269*T**2+0.001308*T**3
961    EDS = np.where(DX>0,-(T-top/bot),(T-top/bot))
962    low1 = np.searchsorted(EDS,-1.)
963    hi1 = np.searchsorted(EDS,1.)
964    slp,intcp = np.polyfit(EDS[low1:hi1],DS[low1:hi1],deg=1)
965    frac = 100.*(hi1-low1)/len(DS)
966    G2frame.G2plotNB.status.SetStatusText(  \
967        'Over range -1. to 1. :'+' slope = %.3f, intercept = %.3f for %.2f%% of the fitted data'%(slp,intcp,frac),1)
968    Plot.set_title('Normal probability for '+Pattern[-1])
969    Plot.set_xlabel(r'expected $\mathsf{\Delta/\sigma}$',fontsize=14)
970    Plot.set_ylabel(r'observed $\mathsf{\Delta/\sigma}$',fontsize=14)
971    Plot.plot(EDS,DS,'r+',label='result')
972    Plot.plot([-2,2],[-2,2],'k',dashes=(5,5),label='ideal')
973    Plot.legend(loc='upper left')
974    np.seterr(invalid='warn')
975    Page.canvas.draw()
976       
977################################################################################
978##### PlotISFG
979################################################################################
980           
981def PlotISFG(G2frame,newPlot=False,type=''):
982    ''' PLotting package for PDF analysis; displays I(q), S(q), F(q) and G(r) as single
983    or multiple plots with waterfall and contour plots as options
984    '''
985    if not type:
986        type = G2frame.G2plotNB.plotList[G2frame.G2plotNB.nb.GetSelection()]
987    if type not in ['I(Q)','S(Q)','F(Q)','G(R)']:
988        return
989    superMinusOne = unichr(0xaf)+unichr(0xb9)
990   
991    def OnPlotKeyPress(event):
992        newPlot = False
993        if event.key == 'u':
994            if G2frame.Contour:
995                G2frame.Cmax = min(1.0,G2frame.Cmax*1.2)
996            elif G2frame.Offset[0] < 100.:
997                G2frame.Offset[0] += 1.
998        elif event.key == 'd':
999            if G2frame.Contour:
1000                G2frame.Cmax = max(0.0,G2frame.Cmax*0.8)
1001            elif G2frame.Offset[0] > 0.:
1002                G2frame.Offset[0] -= 1.
1003        elif event.key == 'l':
1004            G2frame.Offset[1] -= 1.
1005        elif event.key == 'r':
1006            G2frame.Offset[1] += 1.
1007        elif event.key == 'o':
1008            G2frame.Offset = [0,0]
1009        elif event.key == 'c':
1010            newPlot = True
1011            if G2frame.Contour:
1012                G2frame.Contour = False
1013            else:
1014                G2frame.Contour = True
1015                G2frame.SinglePlot = False
1016                G2frame.Offset = [0.,0.]
1017        elif event.key == 's':
1018            if G2frame.Contour:
1019                choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
1020                choice.sort()
1021                dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
1022                if dlg.ShowModal() == wx.ID_OK:
1023                    sel = dlg.GetSelection()
1024                    G2frame.ContourColor = choice[sel]
1025                else:
1026                    G2frame.ContourColor = 'Paired'
1027                dlg.Destroy()
1028            else:               
1029                if G2frame.SinglePlot:
1030                    G2frame.SinglePlot = False
1031                else:
1032                    G2frame.SinglePlot = True
1033        elif event.key == 'i':                  #for smoothing contour plot
1034            choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
1035               'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
1036               'mitchell','sinc','lanczos']
1037            dlg = wx.SingleChoiceDialog(G2frame,'Select','Interpolation',choice)
1038            if dlg.ShowModal() == wx.ID_OK:
1039                sel = dlg.GetSelection()
1040                G2frame.Interpolate = choice[sel]
1041            else:
1042                G2frame.Interpolate = 'nearest'
1043            dlg.Destroy()
1044        elif event.key == 't' and not G2frame.Contour:
1045            if G2frame.Legend:
1046                G2frame.Legend = False
1047            else:
1048                G2frame.Legend = True
1049        PlotISFG(G2frame,newPlot=newPlot,type=type)
1050       
1051    def OnKeyBox(event):
1052        if G2frame.G2plotNB.nb.GetSelection() == G2frame.G2plotNB.plotList.index(type):
1053            event.key = cb.GetValue()[0]
1054            cb.SetValue(' key press')
1055            wx.CallAfter(OnPlotKeyPress,event)
1056        Page.canvas.SetFocus() # redirect the Focus from the button back to the plot
1057                       
1058    def OnMotion(event):
1059        xpos = event.xdata
1060        if xpos:                                        #avoid out of frame mouse position
1061            ypos = event.ydata
1062            Page.canvas.SetCursor(wx.CROSS_CURSOR)
1063            try:
1064                if G2frame.Contour:
1065                    G2frame.G2plotNB.status.SetStatusText('R =%.3fA pattern ID =%5d'%(xpos,int(ypos)),1)
1066                else:
1067                    G2frame.G2plotNB.status.SetStatusText('R =%.3fA %s =%.2f'%(xpos,type,ypos),1)                   
1068            except TypeError:
1069                G2frame.G2plotNB.status.SetStatusText('Select '+type+' pattern first',1)
1070   
1071    xylim = []
1072    try:
1073        plotNum = G2frame.G2plotNB.plotList.index(type)
1074        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1075        if not newPlot:
1076            Plot = Page.figure.gca()          #get previous plot & get limits
1077            xylim = Plot.get_xlim(),Plot.get_ylim()
1078        Page.figure.clf()
1079        Plot = Page.figure.gca()
1080    except ValueError:
1081        newPlot = True
1082        G2frame.Cmax = 1.0
1083        Plot = G2frame.G2plotNB.addMpl(type).gca()
1084        plotNum = G2frame.G2plotNB.plotList.index(type)
1085        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1086        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
1087        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1088   
1089    Page.SetFocus()
1090    G2frame.G2plotNB.status.DestroyChildren()
1091    if G2frame.Contour:
1092        Page.Choice = (' key press','d: lower contour max','u: raise contour max',
1093            'i: interpolation method','s: color scheme','c: contour off')
1094    else:
1095        Page.Choice = (' key press','l: offset left','r: offset right','d: offset down','u: offset up',
1096            'o: reset offset','t: toggle legend','c: contour on','s: toggle single plot')
1097    Page.keyPress = OnPlotKeyPress
1098    PatternId = G2frame.PatternId
1099    PickId = G2frame.PickId
1100    Plot.set_title(type)
1101    if type == 'G(R)':
1102        Plot.set_xlabel(r'$R,\AA$',fontsize=14)
1103    else:
1104        Plot.set_xlabel(r'$Q,\AA$'+superMinusOne,fontsize=14)
1105    Plot.set_ylabel(r''+type,fontsize=14)
1106    colors=['b','g','r','c','m','k']
1107    name = G2frame.PatternTree.GetItemText(PatternId)[4:]
1108    Pattern = []   
1109    if G2frame.SinglePlot:
1110        name = G2frame.PatternTree.GetItemText(PatternId)
1111        name = type+name[4:]
1112        Id = G2gd.GetPatternTreeItemId(G2frame,PatternId,name)
1113        Pattern = G2frame.PatternTree.GetItemPyData(Id)
1114        if Pattern:
1115            Pattern.append(name)
1116        PlotList = [Pattern,]
1117    else:
1118        PlotList = []
1119        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1120        while item:
1121            if 'PDF' in G2frame.PatternTree.GetItemText(item):
1122                name = type+G2frame.PatternTree.GetItemText(item)[4:]
1123                Id = G2gd.GetPatternTreeItemId(G2frame,item,name)
1124                Pattern = G2frame.PatternTree.GetItemPyData(Id)
1125                if Pattern:
1126                    Pattern.append(name)
1127                    PlotList.append(Pattern)
1128            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1129    PDFdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'PDF Controls'))
1130    numbDen = G2pwd.GetNumDensity(PDFdata['ElList'],PDFdata['Form Vol'])
1131    Xb = [0.,10.]
1132    Yb = [0.,-40.*np.pi*numbDen]
1133    Ymax = 1.0
1134    lenX = 0
1135    for Pattern in PlotList:
1136        xye = Pattern[1]
1137        Ymax = max(Ymax,max(xye[1]))
1138    offset = G2frame.Offset[0]*Ymax/100.0
1139    if G2frame.Contour:
1140        ContourZ = []
1141        ContourY = []
1142        Nseq = 0
1143    for N,Pattern in enumerate(PlotList):
1144        xye = Pattern[1]
1145        if PickId:
1146            ifpicked = Pattern[2] == G2frame.PatternTree.GetItemText(PatternId)
1147        X = xye[0]
1148        if not lenX:
1149            lenX = len(X)           
1150        Y = xye[1]+offset*N
1151        if G2frame.Contour:
1152            if lenX == len(X):
1153                ContourY.append(N)
1154                ContourZ.append(Y)
1155                ContourX = X
1156                Nseq += 1
1157                Plot.set_ylabel('Data sequence',fontsize=12)
1158        else:
1159            X = xye[0]+G2frame.Offset[1]*.005*N
1160            if ifpicked:
1161                Plot.plot(X,Y,colors[N%6]+'+',picker=3.,clip_on=False)
1162                Page.canvas.SetToolTipString('')
1163            else:
1164                if G2frame.Legend:
1165                    Plot.plot(X,Y,colors[N%6],picker=False,label='Azm:'+Pattern[2].split('=')[1])
1166                else:
1167                    Plot.plot(X,Y,colors[N%6],picker=False)
1168            if type == 'G(R)':
1169                Plot.plot(Xb,Yb,color='k',dashes=(5,5))
1170            elif type == 'F(Q)':
1171                Plot.axhline(0.,color=wx.BLACK)
1172            elif type == 'S(Q)':
1173                Plot.axhline(1.,color=wx.BLACK)
1174    if G2frame.Contour:
1175        acolor = mpl.cm.get_cmap(G2frame.ContourColor)
1176        Img = Plot.imshow(ContourZ,cmap=acolor,vmin=0,vmax=Ymax*G2frame.Cmax,interpolation=G2frame.Interpolate, 
1177            extent=[ContourX[0],ContourX[-1],ContourY[0],ContourY[-1]],aspect='auto',origin='lower')
1178        Page.figure.colorbar(Img)
1179    elif G2frame.Legend:
1180        Plot.legend(loc='best')
1181    if not newPlot:
1182        Page.toolbar.push_current()
1183        Plot.set_xlim(xylim[0])
1184        Plot.set_ylim(xylim[1])
1185        xylim = []
1186        Page.toolbar.push_current()
1187        Page.toolbar.draw()
1188    else:
1189        Page.canvas.draw()
1190       
1191################################################################################
1192##### PlotXY
1193################################################################################
1194           
1195def PlotXY(G2frame,XY,newPlot=False,type=''):
1196    '''simple plot of xy data, used for diagnostic purposes
1197    '''
1198    def OnMotion(event):
1199        xpos = event.xdata
1200        if xpos:                                        #avoid out of frame mouse position
1201            ypos = event.ydata
1202            Page.canvas.SetCursor(wx.CROSS_CURSOR)
1203            try:
1204                G2frame.G2plotNB.status.SetStatusText('X =%9.3f %s =%9.3f'%(xpos,type,ypos),1)                   
1205            except TypeError:
1206                G2frame.G2plotNB.status.SetStatusText('Select '+type+' pattern first',1)
1207
1208    try:
1209        plotNum = G2frame.G2plotNB.plotList.index(type)
1210        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1211        if not newPlot:
1212            Plot = Page.figure.gca()
1213            xylim = Plot.get_xlim(),Plot.get_ylim()
1214        Page.figure.clf()
1215        Plot = Page.figure.gca()
1216    except ValueError:
1217        newPlot = True
1218        Plot = G2frame.G2plotNB.addMpl(type).gca()
1219        plotNum = G2frame.G2plotNB.plotList.index(type)
1220        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1221        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1222   
1223    Page.Choice = None
1224    Page.SetFocus()
1225    G2frame.G2plotNB.status.DestroyChildren()
1226    Plot.set_title(type)
1227    Plot.set_xlabel(r'X',fontsize=14)
1228    Plot.set_ylabel(r''+type,fontsize=14)
1229    colors=['b','g','r','c','m','k']
1230    Ymax = 1.0
1231    lenX = 0
1232    X,Y = XY[:2]
1233    Ymax = max(Ymax,max(Y))
1234    Plot.plot(X,Y,'k',picker=False)
1235    if not newPlot:
1236        Page.toolbar.push_current()
1237        Plot.set_xlim(xylim[0])
1238        Plot.set_ylim(xylim[1])
1239        xylim = []
1240        Page.toolbar.push_current()
1241        Page.toolbar.draw()
1242    else:
1243        Page.canvas.draw()
1244
1245################################################################################
1246##### PlotPowderLines
1247################################################################################
1248           
1249def PlotPowderLines(G2frame):
1250    ''' plotting of powder lines (i.e. no powder pattern) as sticks
1251    '''
1252    global HKL
1253
1254    def OnMotion(event):
1255        xpos = event.xdata
1256        if xpos:                                        #avoid out of frame mouse position
1257            Page.canvas.SetCursor(wx.CROSS_CURSOR)
1258            G2frame.G2plotNB.status.SetFields(['','2-theta =%9.3f '%(xpos,)])
1259            if G2frame.PickId and G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Index Peak List','Unit Cells List']:
1260                found = []
1261                if len(HKL):
1262                    view = Page.toolbar._views.forward()[0][:2]
1263                    wid = view[1]-view[0]
1264                    found = HKL[np.where(np.fabs(HKL.T[5]-xpos) < 0.002*wid)]
1265                if len(found):
1266                    h,k,l = found[0][:3] 
1267                    Page.canvas.SetToolTipString('%d,%d,%d'%(int(h),int(k),int(l)))
1268                else:
1269                    Page.canvas.SetToolTipString('')
1270
1271    try:
1272        plotNum = G2frame.G2plotNB.plotList.index('Powder Lines')
1273        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1274        Page.figure.clf()
1275        Plot = Page.figure.gca()
1276    except ValueError:
1277        Plot = G2frame.G2plotNB.addMpl('Powder Lines').gca()
1278        plotNum = G2frame.G2plotNB.plotList.index('Powder Lines')
1279        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1280        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1281       
1282    Page.Choice = None
1283    Page.SetFocus()
1284    Plot.set_title('Powder Pattern Lines')
1285    Plot.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
1286    PickId = G2frame.PickId
1287    PatternId = G2frame.PatternId
1288    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
1289    for peak in peaks:
1290        Plot.axvline(peak[0],color='b')
1291    HKL = np.array(G2frame.HKL)
1292    for hkl in G2frame.HKL:
1293        Plot.axvline(hkl[5],color='r',dashes=(5,5))
1294    xmin = peaks[0][0]
1295    xmax = peaks[-1][0]
1296    delt = xmax-xmin
1297    xlim = [max(0,xmin-delt/20.),min(180.,xmax+delt/20.)]
1298    Plot.set_xlim(xlim)
1299    Page.canvas.draw()
1300    Page.toolbar.push_current()
1301
1302################################################################################
1303##### PlotPeakWidths
1304################################################################################
1305           
1306def PlotPeakWidths(G2frame):
1307    ''' Plotting of instrument broadening terms as function of 2-theta
1308    Seen when "Instrument Parameters" chosen from powder pattern data tree
1309    '''
1310#    sig = lambda Th,U,V,W: 1.17741*math.sqrt(U*tand(Th)**2+V*tand(Th)+W)*math.pi/18000.
1311#    gam = lambda Th,X,Y: (X/cosd(Th)+Y*tand(Th))*math.pi/18000.
1312    gamFW = lambda s,g: np.exp(np.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.)
1313#    gamFW2 = lambda s,g: math.sqrt(s**2+(0.4654996*g)**2)+.5345004*g  #Ubaldo Bafile - private communication
1314    PatternId = G2frame.PatternId
1315    limitID = G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits')
1316    if limitID:
1317        limits = G2frame.PatternTree.GetItemPyData(limitID)[:2]
1318    else:
1319        return
1320    Parms,Parms2 = G2frame.PatternTree.GetItemPyData( \
1321        G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
1322    if 'C' in Parms['Type'][0]:
1323        lam = G2mth.getWave(Parms)
1324    else:
1325        difC = Parms['difC'][0]
1326    peakID = G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List')
1327    if peakID:
1328        peaks = G2frame.PatternTree.GetItemPyData(peakID)
1329    else:
1330        peaks = []
1331   
1332    try:
1333        plotNum = G2frame.G2plotNB.plotList.index('Peak Widths')
1334        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1335        Page.figure.clf()
1336        Plot = Page.figure.gca()
1337    except ValueError:
1338        Plot = G2frame.G2plotNB.addMpl('Peak Widths').gca()
1339        plotNum = G2frame.G2plotNB.plotList.index('Peak Widths')
1340        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1341    Page.Choice = None
1342    Page.SetFocus()
1343   
1344    Page.canvas.SetToolTipString('')
1345    colors=['b','g','r','c','m','k']
1346    X = []
1347    Y = []
1348    Z = []
1349    W = []
1350    if 'C' in Parms['Type'][0]:
1351        Plot.set_title('Instrument and sample peak widths')
1352        Plot.set_xlabel(r'$Q, \AA^{-1}$',fontsize=14)
1353        Plot.set_ylabel(r'$\Delta Q/Q, \Delta d/d$',fontsize=14)
1354        try:
1355            Xmin,Xmax = limits[1]
1356            X = np.linspace(Xmin,Xmax,num=101,endpoint=True)
1357            Q = 4.*np.pi*npsind(X/2.)/lam
1358            Z = np.ones_like(X)
1359            data = G2mth.setPeakparms(Parms,Parms2,X,Z)
1360            s = 1.17741*np.sqrt(data[4])*np.pi/18000.
1361            g = data[6]*np.pi/18000.
1362            G = G2pwd.getgamFW(g,s)
1363            Y = s/nptand(X/2.)
1364            Z = g/nptand(X/2.)
1365            W = G/nptand(X/2.)
1366            Plot.plot(Q,Y,color='r',label='Gaussian')
1367            Plot.plot(Q,Z,color='g',label='Lorentzian')
1368            Plot.plot(Q,W,color='b',label='G+L')
1369           
1370            fit = G2mth.setPeakparms(Parms,Parms2,X,Z,useFit=True)
1371            sf = 1.17741*np.sqrt(fit[4])*np.pi/18000.
1372            gf = fit[6]*np.pi/18000.
1373            Gf = G2pwd.getgamFW(gf,sf)
1374            Yf = sf/nptand(X/2.)
1375            Zf = gf/nptand(X/2.)
1376            Wf = Gf/nptand(X/2.)
1377            Plot.plot(Q,Yf,color='r',dashes=(5,5),label='Gaussian fit')
1378            Plot.plot(Q,Zf,color='g',dashes=(5,5),label='Lorentzian fit')
1379            Plot.plot(Q,Wf,color='b',dashes=(5,5),label='G+L fit')
1380           
1381            X = []
1382            Y = []
1383            Z = []
1384            W = []
1385            V = []
1386            for peak in peaks:
1387                X.append(4.0*math.pi*sind(peak[0]/2.0)/lam)
1388                try:
1389                    s = 1.17741*math.sqrt(peak[4])*math.pi/18000.
1390                except ValueError:
1391                    s = 0.01
1392                g = peak[6]*math.pi/18000.
1393                G = G2pwd.getgamFW(g,s)
1394                Y.append(s/tand(peak[0]/2.))
1395                Z.append(g/tand(peak[0]/2.))
1396                W.append(G/tand(peak[0]/2.))
1397            if len(peaks):
1398                Plot.plot(X,Y,'+',color='r',label='G peak')
1399                Plot.plot(X,Z,'+',color='g',label='L peak')
1400                Plot.plot(X,W,'+',color='b',label='G+L peak')
1401            Plot.legend(loc='best')
1402            Page.canvas.draw()
1403        except ValueError:
1404            print '**** ERROR - default U,V,W profile coefficients yield sqrt of negative value at 2theta =', \
1405                '%.3f'%(2*theta)
1406            G2frame.G2plotNB.Delete('Peak Widths')
1407    else:
1408        Plot.set_title('Instrument and sample peak coefficients')
1409        Plot.set_xlabel(r'$Q, \AA^{-1}$',fontsize=14)
1410        Plot.set_ylabel(r'$\alpha, \beta, \Delta Q/Q, \Delta d/d$',fontsize=14)
1411        Xmin,Xmax = limits[1]
1412        T = np.linspace(Xmin,Xmax,num=101,endpoint=True)
1413        Z = np.ones_like(T)
1414        data = G2mth.setPeakparms(Parms,Parms2,T,Z)
1415        ds = T/difC
1416        Q = 2.*np.pi/ds
1417        A = data[4]
1418        B = data[6]
1419        S = 1.17741*np.sqrt(data[8])/T
1420        G = data[10]/T
1421        Plot.plot(Q,A,color='r',label='Alpha')
1422        Plot.plot(Q,B,color='g',label='Beta')
1423        Plot.plot(Q,S,color='b',label='Gaussian')
1424        Plot.plot(Q,G,color='m',label='Lorentzian')
1425
1426        fit = G2mth.setPeakparms(Parms,Parms2,T,Z)
1427        ds = T/difC
1428        Q = 2.*np.pi/ds
1429        Af = fit[4]
1430        Bf = fit[6]
1431        Sf = 1.17741*np.sqrt(fit[8])/T
1432        Gf = fit[10]/T
1433        Plot.plot(Q,Af,color='r',dashes=(5,5),label='Alpha fit')
1434        Plot.plot(Q,Bf,color='g',dashes=(5,5),label='Beta fit')
1435        Plot.plot(Q,Sf,color='b',dashes=(5,5),label='Gaussian fit')
1436        Plot.plot(Q,Gf,color='m',dashes=(5,5),label='Lorentzian fit')
1437       
1438        T = []
1439        A = []
1440        B = []
1441        S = []
1442        G = []
1443        W = []
1444        Q = []
1445        V = []
1446        for peak in peaks:
1447            T.append(peak[0])
1448            A.append(peak[4])
1449            B.append(peak[6])
1450            Q.append(2.*np.pi*difC/peak[0])
1451            S.append(1.17741*np.sqrt(peak[8])/peak[0])
1452            G.append(peak[10]/peak[0])
1453           
1454       
1455        Plot.plot(Q,A,'+',color='r',label='Alpha peak')
1456        Plot.plot(Q,B,'+',color='g',label='Beta peak')
1457        Plot.plot(Q,S,'+',color='b',label='Gaussian peak')
1458        Plot.plot(Q,G,'+',color='m',label='Lorentzian peak')
1459        Plot.legend(loc='best')
1460        Page.canvas.draw()
1461
1462   
1463################################################################################
1464##### PlotSizeStrainPO
1465################################################################################
1466           
1467def PlotSizeStrainPO(G2frame,data,Start=False):
1468    '''Plot 3D mustrain/size/preferred orientation figure. In this instance data is for a phase
1469    '''
1470   
1471    PatternId = G2frame.PatternId
1472    generalData = data['General']
1473    SGData = generalData['SGData']
1474    SGLaue = SGData['SGLaue']
1475    if Start:                   #initialize the spherical harmonics qlmn arrays
1476        ptx.pyqlmninit()
1477        Start = False
1478#    MuStrKeys = G2spc.MustrainNames(SGData)
1479    cell = generalData['Cell'][1:]
1480    A,B = G2lat.cell2AB(cell[:6])
1481    Vol = cell[6]
1482    useList = data['Histograms']
1483    phase = generalData['Name']
1484    plotType = generalData['Data plot type']
1485    plotDict = {'Mustrain':'Mustrain','Size':'Size','Preferred orientation':'Pref.Ori.'}
1486    for ptype in plotDict:
1487        G2frame.G2plotNB.Delete(ptype)
1488    if plotType in ['None']:
1489        return       
1490
1491    for item in useList:
1492        if useList[item]['Show']:
1493            break
1494    else:
1495        return            #nothing to show!!
1496   
1497    numPlots = len(useList)
1498
1499    if plotType in ['Mustrain','Size']:
1500        Plot = mp3d.Axes3D(G2frame.G2plotNB.add3D(plotType))
1501    else:
1502        Plot = G2frame.G2plotNB.addMpl(plotType).gca()       
1503    plotNum = G2frame.G2plotNB.plotList.index(plotType)
1504    Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1505    Page.Choice = None
1506    Page.SetFocus()
1507    G2frame.G2plotNB.status.SetStatusText('',1)
1508    if not Page.IsShown():
1509        Page.Show()
1510   
1511    for item in useList:
1512        if useList[item]['Show']:
1513            PHI = np.linspace(0.,360.,30,True)
1514            PSI = np.linspace(0.,180.,30,True)
1515            X = np.outer(npsind(PHI),npsind(PSI))
1516            Y = np.outer(npcosd(PHI),npsind(PSI))
1517            Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
1518            try:        #temp patch instead of 'mustrain' for old files with 'microstrain'
1519                coeff = useList[item][plotDict[plotType]]
1520            except KeyError:
1521                break
1522            if plotType in ['Mustrain','Size']:
1523                if coeff[0] == 'isotropic':
1524                    X *= coeff[1][0]
1525                    Y *= coeff[1][0]
1526                    Z *= coeff[1][0]                               
1527                elif coeff[0] == 'uniaxial':
1528                   
1529                    def uniaxCalc(xyz,iso,aniso,axes):
1530                        Z = np.array(axes)
1531                        cp = abs(np.dot(xyz,Z))
1532                        sp = np.sqrt(1.-cp**2)
1533                        R = iso*aniso/np.sqrt((iso*cp)**2+(aniso*sp)**2)
1534                        return R*xyz
1535                       
1536                    iso,aniso = coeff[1][:2]
1537                    axes = np.inner(A,np.array(coeff[3]))
1538                    axes /= nl.norm(axes)
1539                    Shkl = np.array(coeff[1])
1540                    XYZ = np.dstack((X,Y,Z))
1541                    XYZ = np.nan_to_num(np.apply_along_axis(uniaxCalc,2,XYZ,iso,aniso,axes))
1542                    X,Y,Z = np.dsplit(XYZ,3)
1543                    X = X[:,:,0]
1544                    Y = Y[:,:,0]
1545                    Z = Z[:,:,0]
1546               
1547                elif coeff[0] == 'ellipsoidal':
1548                   
1549                    def ellipseCalc(xyz,E,R):
1550                        XYZ = xyz*E.T
1551                        return np.inner(XYZ.T,R)
1552                       
1553                    S6 = coeff[4]
1554                    Sij = G2lat.U6toUij(S6)
1555                    E,R = nl.eigh(Sij)
1556                    XYZ = np.dstack((X,Y,Z))
1557                    XYZ = np.nan_to_num(np.apply_along_axis(ellipseCalc,2,XYZ,E,R))
1558                    X,Y,Z = np.dsplit(XYZ,3)
1559                    X = X[:,:,0]
1560                    Y = Y[:,:,0]
1561                    Z = Z[:,:,0]
1562                   
1563                elif coeff[0] == 'generalized':
1564                   
1565                    def genMustrain(xyz,SGData,A,Shkl):
1566                        uvw = np.inner(A.T,xyz)
1567                        Strm = np.array(G2spc.MustrainCoeff(uvw,SGData))
1568                        sum = np.sum(np.multiply(Shkl,Strm))
1569                        sum = np.where(sum > 0.01,sum,0.01)
1570                        sum = np.sqrt(sum)*math.pi/.18      #centidegrees to radians!
1571                        return sum*xyz
1572                       
1573                    Shkl = np.array(coeff[4])
1574                    if np.any(Shkl):
1575                        XYZ = np.dstack((X,Y,Z))
1576                        XYZ = np.nan_to_num(np.apply_along_axis(genMustrain,2,XYZ,SGData,A,Shkl))
1577                        X,Y,Z = np.dsplit(XYZ,3)
1578                        X = X[:,:,0]
1579                        Y = Y[:,:,0]
1580                        Z = Z[:,:,0]
1581                           
1582                if np.any(X) and np.any(Y) and np.any(Z):
1583                    errFlags = np.seterr(all='ignore')
1584                    Plot.plot_surface(X,Y,Z,rstride=1,cstride=1,color='g',linewidth=1)
1585                    np.seterr(all='ignore')
1586                    xyzlim = np.array([Plot.get_xlim3d(),Plot.get_ylim3d(),Plot.get_zlim3d()]).T
1587                    XYZlim = [min(xyzlim[0]),max(xyzlim[1])]
1588                    Plot.set_xlim3d(XYZlim)
1589                    Plot.set_ylim3d(XYZlim)
1590                    Plot.set_zlim3d(XYZlim)
1591                    Plot.set_aspect('equal')
1592                if plotType == 'Size':
1593                    Plot.set_title('Crystallite size for '+phase+'\n'+coeff[0]+' model')
1594                    Plot.set_xlabel(r'X, $\mu$m')
1595                    Plot.set_ylabel(r'Y, $\mu$m')
1596                    Plot.set_zlabel(r'Z, $\mu$m')
1597                else:   
1598                    Plot.set_title(r'$\mu$strain for '+phase+'\n'+coeff[0]+' model')
1599                    Plot.set_xlabel(r'X, $\mu$strain')
1600                    Plot.set_ylabel(r'Y, $\mu$strain')
1601                    Plot.set_zlabel(r'Z, $\mu$strain')
1602            else:
1603                h,k,l = generalData['POhkl']
1604                if coeff[0] == 'MD':
1605                    print 'March-Dollase preferred orientation plot'
1606               
1607                else:
1608                    PH = np.array(generalData['POhkl'])
1609                    phi,beta = G2lat.CrsAng(PH,cell[:6],SGData)
1610                    SHCoef = {}
1611                    for item in coeff[5]:
1612                        L,N = eval(item.strip('C'))
1613                        SHCoef['C%d,0,%d'%(L,N)] = coeff[5][item]                       
1614                    ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
1615                    X = np.linspace(0,90.0,26)
1616                    Y = G2lat.polfcal(ODFln,'0',X,0.0)
1617                    Plot.plot(X,Y,color='k',label=str(PH))
1618                    Plot.legend(loc='best')
1619                    Plot.set_title('Axial distribution for HKL='+str(PH)+' in '+phase)
1620                    Plot.set_xlabel(r'$\psi$',fontsize=16)
1621                    Plot.set_ylabel('MRD',fontsize=14)
1622    Page.canvas.draw()
1623   
1624################################################################################
1625##### PlotTexture
1626################################################################################
1627           
1628def PlotTexture(G2frame,data,Start=False):
1629    '''Pole figure, inverse pole figure, 3D pole distribution and 3D inverse pole distribution
1630    plotting.
1631    dict generalData contains all phase info needed which is in data
1632    '''
1633
1634    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
1635    SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
1636    PatternId = G2frame.PatternId
1637    generalData = data['General']
1638    SGData = generalData['SGData']
1639    textureData = generalData['SH Texture']
1640    G2frame.G2plotNB.Delete('Texture')
1641    if not textureData['Order']:
1642        return                  #no plot!!
1643    SHData = generalData['SH Texture']
1644    SHCoef = SHData['SH Coeff'][1]
1645    cell = generalData['Cell'][1:7]
1646    Amat,Bmat = G2lat.cell2AB(cell)
1647    sq2 = 1.0/math.sqrt(2.0)
1648   
1649    def rp2xyz(r,p):
1650        z = npcosd(r)
1651        xy = np.sqrt(1.-z**2)
1652        return xy*npsind(p),xy*npcosd(p),z
1653           
1654    def OnMotion(event):
1655        SHData = data['General']['SH Texture']
1656        if event.xdata and event.ydata:                 #avoid out of frame errors
1657            xpos = event.xdata
1658            ypos = event.ydata
1659            if 'Inverse' in SHData['PlotType']:
1660                r = xpos**2+ypos**2
1661                if r <= 1.0:
1662                    if 'equal' in G2frame.Projection: 
1663                        r,p = 2.*npasind(np.sqrt(r)*sq2),npatan2d(ypos,xpos)
1664                    else:
1665                        r,p = 2.*npatand(np.sqrt(r)),npatan2d(ypos,xpos)
1666                    ipf = G2lat.invpolfcal(IODFln,SGData,np.array([r,]),np.array([p,]))
1667                    xyz = np.inner(Amat.T,np.array([rp2xyz(r,p)]))
1668                    y,x,z = list(xyz/np.max(np.abs(xyz)))
1669                   
1670                    G2frame.G2plotNB.status.SetFields(['',
1671                        'psi =%9.3f, beta =%9.3f, MRD =%9.3f hkl=%5.2f,%5.2f,%5.2f'%(r,p,ipf,x,y,z)])
1672                                   
1673            elif 'Axial' in SHData['PlotType']:
1674                pass
1675               
1676            else:                       #ordinary pole figure
1677                z = xpos**2+ypos**2
1678                if z <= 1.0:
1679                    z = np.sqrt(z)
1680                    if 'equal' in G2frame.Projection: 
1681                        r,p = 2.*npasind(z*sq2),npatan2d(ypos,xpos)
1682                    else:
1683                        r,p = 2.*npatand(z),npatan2d(ypos,xpos)
1684                    pf = G2lat.polfcal(ODFln,SamSym[textureData['Model']],np.array([r,]),np.array([p,]))
1685                    G2frame.G2plotNB.status.SetFields(['','phi =%9.3f, gam =%9.3f, MRD =%9.3f'%(r,p,pf)])
1686   
1687    try:
1688        plotNum = G2frame.G2plotNB.plotList.index('Texture')
1689        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1690        Page.figure.clf()
1691        Plot = Page.figure.gca()
1692        if not Page.IsShown():
1693            Page.Show()
1694    except ValueError:
1695        Plot = G2frame.G2plotNB.addMpl('Texture').gca()
1696        plotNum = G2frame.G2plotNB.plotList.index('Texture')
1697        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1698        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1699
1700    Page.Choice = None
1701    Page.SetFocus()
1702    G2frame.G2plotNB.status.SetFields(['',''])   
1703    PH = np.array(SHData['PFhkl'])
1704    phi,beta = G2lat.CrsAng(PH,cell,SGData)
1705    ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
1706    PX = np.array(SHData['PFxyz'])
1707    gam = atan2d(PX[0],PX[1])
1708    xy = math.sqrt(PX[0]**2+PX[1]**2)
1709    xyz = math.sqrt(PX[0]**2+PX[1]**2+PX[2]**2)
1710    psi = asind(xy/xyz)
1711    IODFln = G2lat.Glnh(Start,SHCoef,psi,gam,SamSym[textureData['Model']])
1712    if 'Axial' in SHData['PlotType']:
1713        X = np.linspace(0,90.0,26)
1714        Y = G2lat.polfcal(ODFln,SamSym[textureData['Model']],X,0.0)
1715        Plot.plot(X,Y,color='k',label=str(SHData['PFhkl']))
1716        Plot.legend(loc='best')
1717        Plot.set_title('Axial distribution for HKL='+str(SHData['PFhkl']))
1718        Plot.set_xlabel(r'$\psi$',fontsize=16)
1719        Plot.set_ylabel('MRD',fontsize=14)
1720       
1721    else:       
1722        npts = 201
1723        if 'Inverse' in SHData['PlotType']:
1724            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
1725            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
1726            if 'equal' in G2frame.Projection:
1727                R = np.where(R <= 1.,2.*npasind(R*sq2),0.0)
1728            else:
1729                R = np.where(R <= 1.,2.*npatand(R),0.0)
1730            Z = np.zeros_like(R)
1731            Z = G2lat.invpolfcal(IODFln,SGData,R,P)
1732            Z = np.reshape(Z,(npts,npts))
1733            CS = Plot.contour(Y,X,Z,aspect='equal')
1734            Plot.clabel(CS,fontsize=9,inline=1)
1735            try:
1736                Img = Plot.imshow(Z.T,aspect='equal',cmap=G2frame.ContourColor,extent=[-1,1,-1,1])
1737            except ValueError:
1738                pass
1739            Page.figure.colorbar(Img)
1740            Plot.set_title('Inverse pole figure for XYZ='+str(SHData['PFxyz']))
1741            Plot.set_xlabel(G2frame.Projection.capitalize()+' projection')
1742                       
1743        else:
1744            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
1745            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
1746            if 'equal' in G2frame.Projection:
1747                R = np.where(R <= 1.,2.*npasind(R*sq2),0.0)
1748            else:
1749                R = np.where(R <= 1.,2.*npatand(R),0.0)
1750            Z = np.zeros_like(R)
1751            Z = G2lat.polfcal(ODFln,SamSym[textureData['Model']],R,P)
1752            Z = np.reshape(Z,(npts,npts))
1753            try:
1754                CS = Plot.contour(Y,X,Z,aspect='equal')
1755                Plot.clabel(CS,fontsize=9,inline=1)
1756            except ValueError:
1757                pass
1758            Img = Plot.imshow(Z.T,aspect='equal',cmap=G2frame.ContourColor,extent=[-1,1,-1,1])
1759            Page.figure.colorbar(Img)
1760            Plot.set_title('Pole figure for HKL='+str(SHData['PFhkl']))
1761            Plot.set_xlabel(G2frame.Projection.capitalize()+' projection')
1762    Page.canvas.draw()
1763
1764################################################################################
1765##### PlotCovariance
1766################################################################################
1767           
1768def PlotCovariance(G2frame,Data):
1769    'needs a doc string'
1770    if not Data:
1771        print 'No covariance matrix available'
1772        return
1773    varyList = Data['varyList']
1774    values = Data['variables']
1775    Xmax = len(varyList)
1776    covMatrix = Data['covMatrix']
1777    sig = np.sqrt(np.diag(covMatrix))
1778    xvar = np.outer(sig,np.ones_like(sig))
1779    covArray = np.divide(np.divide(covMatrix,xvar),xvar.T)
1780    title = ' for\n'+Data['title']
1781    newAtomDict = Data['newAtomDict']
1782   
1783
1784    def OnPlotKeyPress(event):
1785        newPlot = False
1786        if event.key == 's':
1787            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
1788            choice.sort()
1789            dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
1790            if dlg.ShowModal() == wx.ID_OK:
1791                sel = dlg.GetSelection()
1792                G2frame.VcovColor = choice[sel]
1793            else:
1794                G2frame.VcovColor = 'RdYlGn'
1795            dlg.Destroy()
1796        PlotCovariance(G2frame,Data)
1797
1798    def OnMotion(event):
1799        #there is a problem here - reports wrong values
1800        if event.button:
1801            ytics = imgAx.get_yticks()
1802            ytics = np.where(ytics<len(varyList),ytics,-1)
1803            ylabs = [np.where(0<=i ,varyList[int(i)],' ') for i in ytics]
1804            imgAx.set_yticklabels(ylabs)           
1805        if event.xdata and event.ydata:                 #avoid out of frame errors
1806            xpos = int(event.xdata+.5)
1807            ypos = int(event.ydata+.5)
1808            if -1 < xpos < len(varyList) and -1 < ypos < len(varyList):
1809                if xpos == ypos:
1810                    value = values[xpos]
1811                    name = varyList[xpos]
1812                    if varyList[xpos] in newAtomDict:
1813                        name,value = newAtomDict[name]                       
1814                    msg = '%s value = %.4g, esd = %.4g'%(name,value,sig[xpos])
1815                else:
1816                    msg = '%s - %s: %5.3f'%(varyList[xpos],varyList[ypos],covArray[xpos][ypos])
1817                Page.canvas.SetToolTipString(msg)
1818                G2frame.G2plotNB.status.SetFields(['',msg])
1819               
1820    try:
1821        plotNum = G2frame.G2plotNB.plotList.index('Covariance')
1822        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1823        Page.figure.clf()
1824        Plot = Page.figure.gca()
1825        if not Page.IsShown():
1826            Page.Show()
1827    except ValueError:
1828        Plot = G2frame.G2plotNB.addMpl('Covariance').gca()
1829        plotNum = G2frame.G2plotNB.plotList.index('Covariance')
1830        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1831        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1832        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
1833    Page.Choice = ['s: to change colors']
1834    Page.keyPress = OnPlotKeyPress
1835    Page.SetFocus()
1836    G2frame.G2plotNB.status.SetFields(['',''])   
1837    acolor = mpl.cm.get_cmap(G2frame.VcovColor)
1838    Img = Plot.imshow(covArray,aspect='equal',cmap=acolor,interpolation='nearest',origin='lower',
1839        vmin=-1.,vmax=1.)
1840    imgAx = Img.get_axes()
1841    ytics = imgAx.get_yticks()
1842    ylabs = [varyList[int(i)] for i in ytics[:-1]]
1843    imgAx.set_yticklabels(ylabs)
1844    colorBar = Page.figure.colorbar(Img)
1845    Plot.set_title('V-Cov matrix'+title)
1846    Plot.set_xlabel('Variable number')
1847    Plot.set_ylabel('Variable name')
1848    Page.canvas.draw()
1849   
1850################################################################################
1851##### PlotTorsion
1852################################################################################
1853
1854def PlotTorsion(G2frame,phaseName,Torsion,TorName,Names=[],Angles=[],Coeff=[]):
1855    'needs a doc string'
1856   
1857    global names
1858    names = Names
1859    sum = np.sum(Torsion)
1860    torsion = np.log(2*Torsion+1.)/sum
1861    tMin = np.min(torsion)
1862    tMax = np.max(torsion)
1863    torsion = 3.*(torsion-tMin)/(tMax-tMin)
1864    X = np.linspace(0.,360.,num=45)
1865   
1866    def OnPick(event):
1867        ind = event.ind[0]
1868        msg = 'atoms:'+names[ind]
1869        Page.canvas.SetToolTipString(msg)
1870        try:
1871            page = G2frame.dataDisplay.GetSelection()
1872        except:
1873            return
1874        if G2frame.dataDisplay.GetPageText(page) == 'Torsion restraints':
1875            torGrid = G2frame.dataDisplay.GetPage(page).Torsions
1876            torGrid.ClearSelection()
1877            for row in range(torGrid.GetNumberRows()):
1878                if names[ind] in torGrid.GetCellValue(row,0):
1879                    torGrid.SelectRow(row)
1880            torGrid.ForceRefresh()
1881               
1882    def OnMotion(event):
1883        if event.xdata and event.ydata:                 #avoid out of frame errors
1884            xpos = event.xdata
1885            ypos = event.ydata
1886            msg = 'torsion,energy: %5.3f %5.3f'%(xpos,ypos)
1887            Page.canvas.SetToolTipString(msg)
1888
1889    try:
1890        plotNum = G2frame.G2plotNB.plotList.index('Torsion')
1891        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1892        Page.figure.clf()
1893        Plot = Page.figure.gca()
1894        if not Page.IsShown():
1895            Page.Show()
1896    except ValueError:
1897        Plot = G2frame.G2plotNB.addMpl('Torsion').gca()
1898        plotNum = G2frame.G2plotNB.plotList.index('Torsion')
1899        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1900        Page.canvas.mpl_connect('pick_event', OnPick)
1901        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1902   
1903    Page.SetFocus()
1904    G2frame.G2plotNB.status.SetFields(['','Use mouse LB to identify torsion atoms'])
1905    Plot.plot(X,torsion,'b+')
1906    if len(Coeff):
1907        X2 = np.linspace(0.,360.,45)
1908        Y2 = np.array([-G2mth.calcTorsionEnergy(x,Coeff)[1] for x in X2])
1909        Plot.plot(X2,Y2,'r')
1910    if len(Angles):
1911        Eval = np.array([-G2mth.calcTorsionEnergy(x,Coeff)[1] for x in Angles])
1912        Plot.plot(Angles,Eval,'ro',picker=5)
1913    Plot.set_xlim((0.,360.))
1914    Plot.set_title('Torsion angles for '+TorName+' in '+phaseName)
1915    Plot.set_xlabel('angle',fontsize=16)
1916    Plot.set_ylabel('Energy',fontsize=16)
1917    Page.canvas.draw()
1918   
1919################################################################################
1920##### PlotRama
1921################################################################################
1922
1923def PlotRama(G2frame,phaseName,Rama,RamaName,Names=[],PhiPsi=[],Coeff=[]):
1924    'needs a doc string'
1925
1926    global names
1927    names = Names
1928    rama = np.log(2*Rama+1.)
1929    ramaMax = np.max(rama)
1930    rama = np.reshape(rama,(45,45))
1931    global Phi,Psi
1932    Phi = []
1933    Psi = []
1934
1935    def OnPlotKeyPress(event):
1936        newPlot = False
1937        if event.key == 's':
1938            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
1939            choice.sort()
1940            dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
1941            if dlg.ShowModal() == wx.ID_OK:
1942                sel = dlg.GetSelection()
1943                G2frame.RamaColor = choice[sel]
1944            else:
1945                G2frame.RamaColor = 'RdYlGn'
1946            dlg.Destroy()
1947        PlotRama(G2frame,phaseName,Rama)
1948
1949    def OnPick(event):
1950        ind = event.ind[0]
1951        msg = 'atoms:'+names[ind]
1952        Page.canvas.SetToolTipString(msg)
1953        try:
1954            page = G2frame.dataDisplay.GetSelection()
1955        except:
1956            return
1957        if G2frame.dataDisplay.GetPageText(page) == 'Ramachandran restraints':
1958            ramaGrid = G2frame.dataDisplay.GetPage(page).Ramas
1959            ramaGrid.ClearSelection()
1960            for row in range(ramaGrid.GetNumberRows()):
1961                if names[ind] in ramaGrid.GetCellValue(row,0):
1962                    ramaGrid.SelectRow(row)
1963            ramaGrid.ForceRefresh()
1964
1965    def OnMotion(event):
1966        if event.xdata and event.ydata:                 #avoid out of frame errors
1967            xpos = event.xdata
1968            ypos = event.ydata
1969            msg = 'phi/psi: %5.3f %5.3f'%(xpos,ypos)
1970            Page.canvas.SetToolTipString(msg)
1971           
1972    try:
1973        plotNum = G2frame.G2plotNB.plotList.index('Ramachandran')
1974        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1975        Page.figure.clf()
1976        Plot = Page.figure.gca()
1977        if not Page.IsShown():
1978            Page.Show()
1979    except ValueError:
1980        Plot = G2frame.G2plotNB.addMpl('Ramachandran').gca()
1981        plotNum = G2frame.G2plotNB.plotList.index('Ramachandran')
1982        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1983        Page.canvas.mpl_connect('pick_event', OnPick)
1984        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1985        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
1986
1987    Page.Choice = ['s: to change colors']
1988    Page.keyPress = OnPlotKeyPress
1989    Page.SetFocus()
1990    G2frame.G2plotNB.status.SetFields(['','Use mouse LB to identify phi/psi atoms'])
1991    acolor = mpl.cm.get_cmap(G2frame.RamaColor)
1992    if RamaName == 'All' or '-1' in RamaName:
1993        if len(Coeff): 
1994            X,Y = np.meshgrid(np.linspace(-180.,180.,45),np.linspace(-180.,180.,45))
1995            Z = np.array([-G2mth.calcRamaEnergy(x,y,Coeff)[1] for x,y in zip(X.flatten(),Y.flatten())])
1996            Plot.contour(X,Y,np.reshape(Z,(45,45)))
1997        Img = Plot.imshow(rama,aspect='equal',cmap=acolor,interpolation='nearest',
1998            extent=[-180,180,-180,180],origin='lower')
1999        if len(PhiPsi):
2000            Phi,Psi = PhiPsi.T
2001            Phi = np.where(Phi>180.,Phi-360.,Phi)
2002            Psi = np.where(Psi>180.,Psi-360.,Psi)
2003            Plot.plot(Phi,Psi,'ro',picker=5)
2004        Plot.set_xlim((-180.,180.))
2005        Plot.set_ylim((-180.,180.))
2006    else:
2007        if len(Coeff): 
2008            X,Y = np.meshgrid(np.linspace(0.,360.,45),np.linspace(0.,360.,45))
2009            Z = np.array([-G2mth.calcRamaEnergy(x,y,Coeff)[1] for x,y in zip(X.flatten(),Y.flatten())])
2010            Plot.contour(X,Y,np.reshape(Z,(45,45)))
2011        Img = Plot.imshow(rama,aspect='equal',cmap=acolor,interpolation='nearest',
2012            extent=[0,360,0,360],origin='lower')
2013        if len(PhiPsi):
2014            Phi,Psi = PhiPsi.T
2015            Plot.plot(Phi,Psi,'ro',picker=5)
2016        Plot.set_xlim((0.,360.))
2017        Plot.set_ylim((0.,360.))
2018    Plot.set_title('Ramachandran for '+RamaName+' in '+phaseName)
2019    Plot.set_xlabel(r'$\phi$',fontsize=16)
2020    Plot.set_ylabel(r'$\psi$',fontsize=16)
2021    colorBar = Page.figure.colorbar(Img)
2022    Page.canvas.draw()
2023
2024
2025################################################################################
2026##### PlotSeq
2027################################################################################
2028           
2029def PlotSeq(G2frame,SeqData,SeqSig,SeqNames,sampleParm):
2030    'needs a doc string'
2031   
2032    def OnKeyPress(event):
2033        if event.key == 's' and sampleParm:
2034            if G2frame.xAxis:
2035                G2frame.xAxis = False
2036            else:
2037                G2frame.xAxis = True
2038            Draw(False)
2039    try:
2040        plotNum = G2frame.G2plotNB.plotList.index('Sequential refinement')
2041        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2042        Page.figure.clf()
2043        Plot = Page.figure.gca()
2044        if not Page.IsShown():
2045            Page.Show()
2046    except ValueError:
2047        Plot = G2frame.G2plotNB.addMpl('Sequential refinement').gca()
2048        plotNum = G2frame.G2plotNB.plotList.index('Sequential refinement')
2049        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2050        Page.canvas.mpl_connect('key_press_event', OnKeyPress)
2051        G2frame.xAxis = False
2052    Page.Choice = ['s to toggle x-axis = sample environment parameter']
2053    Page.keyPress = OnKeyPress
2054       
2055    def Draw(newPlot):
2056        Page.SetFocus()
2057        G2frame.G2plotNB.status.SetFields(['','press '])
2058        if len(SeqData):
2059            Plot.clear()
2060            if G2frame.xAxis:   
2061                xName = sampleParm.keys()[0]
2062                X = sampleParm[xName]
2063            else:
2064                X = np.arange(0,len(SeqData[0]),1)
2065                xName = 'Data sequence number'
2066            for Y,sig,name in zip(SeqData,SeqSig,SeqNames):
2067                Plot.errorbar(X,Y,yerr=sig,label=name)       
2068            Plot.legend(loc='best')
2069            Plot.set_ylabel('Parameter values')
2070            Plot.set_xlabel(xName)
2071            Page.canvas.draw()           
2072    Draw(True)
2073           
2074################################################################################
2075##### PlotExposedImage & PlotImage
2076################################################################################
2077           
2078def PlotExposedImage(G2frame,newPlot=False,event=None):
2079    '''General access module for 2D image plotting
2080    '''
2081    plotNo = G2frame.G2plotNB.nb.GetSelection()
2082    if G2frame.G2plotNB.nb.GetPageText(plotNo) == '2D Powder Image':
2083        PlotImage(G2frame,newPlot,event,newImage=True)
2084    elif G2frame.G2plotNB.nb.GetPageText(plotNo) == '2D Integration':
2085        PlotIntegration(G2frame,newPlot,event)
2086
2087def OnStartMask(G2frame):
2088    '''Initiate the start of a Frame or Polygon map
2089
2090    :param wx.Frame G2frame: The main GSAS-II tree "window"
2091    :param str eventkey: a single letter ('f' or 'p') that
2092      determines what type of mask is created.   
2093    '''
2094    Masks = G2frame.PatternTree.GetItemPyData(
2095        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2096    if G2frame.MaskKey == 'f':
2097        Masks['Frames'] = []
2098    elif G2frame.MaskKey == 'p':
2099        Masks['Polygons'].append([])
2100    elif G2frame.MaskKey == 's':
2101        Masks['Points'].append([])
2102    elif G2frame.MaskKey == 'a':
2103        Masks['Arcs'].append([])
2104    elif G2frame.MaskKey == 'r':
2105        Masks['Rings'].append([])
2106    G2imG.UpdateMasks(G2frame,Masks)
2107    PlotImage(G2frame,newImage=True)
2108
2109def PlotImage(G2frame,newPlot=False,event=None,newImage=True):
2110    '''Plot of 2D detector images as contoured plot. Also plot calibration ellipses,
2111    masks, etc.
2112    '''
2113    from matplotlib.patches import Ellipse,Arc,Circle,Polygon
2114    import numpy.ma as ma
2115    Dsp = lambda tth,wave: wave/(2.*npsind(tth/2.))
2116    global Data,Masks
2117    colors=['b','g','r','c','m','k']
2118    Data = G2frame.PatternTree.GetItemPyData(
2119        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
2120# patch
2121    if 'invert_x' not in Data:
2122        Data['invert_x'] = False
2123        Data['invert_y'] = True
2124# end patch
2125    Masks = G2frame.PatternTree.GetItemPyData(
2126        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2127    try:    #may be absent
2128        StrSta = G2frame.PatternTree.GetItemPyData(
2129            G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Stress/Strain'))
2130    except TypeError:   #is missing
2131        StrSta = {}
2132
2133    def OnImMotion(event):
2134        Page.canvas.SetToolTipString('')
2135        sizexy = Data['size']
2136        if event.xdata and event.ydata and len(G2frame.ImageZ):                 #avoid out of frame errors
2137            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2138            item = G2frame.itemPicked
2139            pixelSize = Data['pixelSize']
2140            scalex = 1000./pixelSize[0]
2141            scaley = 1000./pixelSize[1]
2142            if item and G2frame.PatternTree.GetItemText(G2frame.PickId) == 'Image Controls':
2143                if 'Text' in str(item):
2144                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
2145                else:
2146                    xcent,ycent = Data['center']
2147                    xpos = event.xdata-xcent
2148                    ypos = event.ydata-ycent
2149                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
2150                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
2151                        Page.canvas.SetToolTipString('%6d deg'%(azm))
2152                    elif 'line1' in  str(item) or 'line2' in str(item):
2153                        Page.canvas.SetToolTipString('%8.3fdeg'%(tth))                           
2154            else:
2155                xpos = event.xdata
2156                ypos = event.ydata
2157                xpix = xpos*scalex
2158                ypix = ypos*scaley
2159                Int = 0
2160                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
2161                    Int = G2frame.ImageZ[ypix][xpix]
2162                tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
2163                Q = 2.*math.pi/dsp
2164                if G2frame.MaskKey in ['p','f']:
2165                    G2frame.G2plotNB.status.SetFields(['','Polygon/frame mask pick - LB next point, RB close polygon'])
2166                else:
2167                    G2frame.G2plotNB.status.SetFields(\
2168                        ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)])
2169
2170    def OnImPlotKeyPress(event):
2171        try:
2172            PickName = G2frame.PatternTree.GetItemText(G2frame.PickId)
2173        except TypeError:
2174            return
2175        if PickName == 'Masks':
2176            if event.key in ['p','f','s','a','r']:
2177                G2frame.MaskKey = event.key
2178                OnStartMask(G2frame)
2179               
2180        elif PickName == 'Image Controls':
2181            if event.key in ['c',]:
2182                Xpos = event.xdata
2183                if not Xpos:            #got point out of frame
2184                    return
2185                Ypos = event.ydata
2186                dlg = wx.MessageDialog(G2frame,'Are you sure you want to change the center?',
2187                    'Center change',style=wx.OK|wx.CANCEL)
2188                try:
2189                    if dlg.ShowModal() == wx.ID_OK:
2190                        print 'move center to: ',Xpos,Ypos
2191                        Data['center'] = [Xpos,Ypos]
2192                        G2imG.UpdateImageControls(G2frame,Data,Masks)
2193                finally:
2194                    dlg.Destroy()
2195            elif event.key == 'l':
2196                if G2frame.logPlot:
2197                    G2frame.logPlot = False
2198                else:
2199                    G2frame.logPlot = True
2200            elif event.key in ['x',]:
2201                if Data['invert_x']:
2202                    Data['invert_x'] = False
2203                else:
2204                    Data['invert_x'] = True
2205            elif event.key in ['y',]:
2206                if Data['invert_y']:
2207                    Data['invert_y'] = False
2208                else:
2209                    Data['invert_y'] = True
2210        PlotImage(G2frame,newPlot=True)
2211           
2212    def OnKeyBox(event):
2213        if G2frame.G2plotNB.nb.GetSelection() == G2frame.G2plotNB.plotList.index('2D Powder Image'):
2214            event.key = cb.GetValue()[0]
2215            cb.SetValue(' key press')
2216            if event.key in ['l','s','a','r','p','x','y']:
2217                wx.CallAfter(OnImPlotKeyPress,event)
2218        Page.canvas.SetFocus() # redirect the Focus from the button back to the plot
2219                       
2220    def OnImPick(event):
2221        if G2frame.PatternTree.GetItemText(G2frame.PickId) not in ['Image Controls','Masks']:
2222            return
2223        if G2frame.itemPicked is not None: return
2224        G2frame.itemPicked = event.artist
2225        G2frame.mousePicked = event.mouseevent
2226       
2227    def OnImRelease(event):
2228        try:
2229            PickName = G2frame.PatternTree.GetItemText(G2frame.PickId)
2230        except TypeError:
2231            return
2232        if PickName not in ['Image Controls','Masks']:
2233            return
2234        pixelSize = Data['pixelSize']
2235        scalex = 1000./pixelSize[0]
2236        scaley = 1000./pixelSize[1]
2237        pixLimit = Data['pixLimit']
2238        if G2frame.itemPicked is None and PickName == 'Image Controls' and len(G2frame.ImageZ):
2239            Xpos = event.xdata
2240            if not (Xpos and G2frame.ifGetRing):                   #got point out of frame
2241                return
2242            Ypos = event.ydata
2243            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
2244                if event.button == 1:
2245                    Xpix = Xpos*scalex
2246                    Ypix = Ypos*scaley
2247                    xpos,ypos,I,J = G2img.ImageLocalMax(G2frame.ImageZ,pixLimit,Xpix,Ypix)
2248                    if I and J:
2249                        xpos += .5                              #shift to pixel center
2250                        ypos += .5
2251                        xpos /= scalex                          #convert to mm
2252                        ypos /= scaley
2253                        Data['ring'].append([xpos,ypos])
2254                elif event.button == 3:
2255                    G2frame.dataFrame.GetStatusBar().SetStatusText('Calibrating...')
2256                    if G2img.ImageCalibrate(G2frame,Data):
2257                        G2frame.dataFrame.GetStatusBar().SetStatusText('Calibration successful - Show ring picks to check')
2258                        print 'Calibration successful'
2259                    else:
2260                        G2frame.dataFrame.GetStatusBar().SetStatusText('Calibration failed - Show ring picks to diagnose')
2261                        print 'Calibration failed'
2262                    G2frame.ifGetRing = False
2263                    G2imG.UpdateImageControls(G2frame,Data,Masks)
2264                    return
2265                PlotImage(G2frame,newImage=False)
2266            return
2267        elif G2frame.MaskKey and PickName == 'Masks':
2268            Xpos,Ypos = [event.xdata,event.ydata]
2269            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
2270                return
2271            if G2frame.MaskKey == 's' and event.button == 1:
2272                Masks['Points'][-1] = [Xpos,Ypos,1.]
2273                G2frame.MaskKey = ''               
2274            elif G2frame.MaskKey == 'r' and event.button == 1:
2275                tth = G2img.GetTth(Xpos,Ypos,Data)
2276                Masks['Rings'][-1] = [tth,0.1]
2277                G2frame.MaskKey = ''               
2278            elif G2frame.MaskKey == 'a' and event.button == 1:
2279                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
2280                azm = int(azm)               
2281                Masks['Arcs'][-1] = [tth,[azm-5,azm+5],0.1]
2282                G2frame.MaskKey = ''               
2283            elif G2frame.MaskKey =='p':
2284                polygon = Masks['Polygons'][-1]
2285                if len(polygon) > 2 and event.button == 3:
2286                    x0,y0 = polygon[0]
2287                    polygon.append([x0,y0])
2288                    G2frame.MaskKey = ''
2289                    G2frame.G2plotNB.status.SetFields(['','Polygon closed - RB drag a vertex to change shape'])
2290                else:
2291                    G2frame.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(Xpos,Ypos)])
2292                    polygon.append([Xpos,Ypos])
2293            elif G2frame.MaskKey =='f':
2294                frame = Masks['Frames']
2295                if len(frame) > 2 and event.button == 3:
2296                    x0,y0 = frame[0]
2297                    frame.append([x0,y0])
2298                    G2frame.MaskKey = ''
2299                    G2frame.G2plotNB.status.SetFields(['','Frame closed - RB drag a vertex to change shape'])
2300                else:
2301                    G2frame.G2plotNB.status.SetFields(['','New frame point: %.1f,%.1f'%(Xpos,Ypos)])
2302                    frame.append([Xpos,Ypos])
2303            G2imG.UpdateMasks(G2frame,Masks)
2304            PlotImage(G2frame,newImage=False)
2305        else:
2306            Xpos,Ypos = [event.xdata,event.ydata]
2307            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
2308                return
2309            if G2frame.ifGetRing:                          #delete a calibration ring pick
2310                xypos = [Xpos,Ypos]
2311                rings = Data['ring']
2312                for ring in rings:
2313                    if np.allclose(ring,xypos,.01,0):
2314                        rings.remove(ring)
2315            else:
2316                tth,azm,dsp = G2img.GetTthAzmDsp(Xpos,Ypos,Data)
2317                itemPicked = str(G2frame.itemPicked)
2318                if 'Line2D' in itemPicked and PickName == 'Image Controls':
2319                    if 'line1' in itemPicked:
2320                        Data['IOtth'][0] = max(tth,0.001)
2321                    elif 'line2' in itemPicked:
2322                        Data['IOtth'][1] = tth
2323                    elif 'line3' in itemPicked:
2324                        Data['LRazimuth'][0] = int(azm)
2325                        if Data['fullIntegrate']:
2326                            Data['LRazimuth'][1] = Data['LRazimuth'][0]+360
2327                    elif 'line4' in itemPicked and not Data['fullIntegrate']:
2328                        Data['LRazimuth'][1] = int(azm)
2329                       
2330                    if Data['LRazimuth'][0] > Data['LRazimuth'][1]:
2331                        Data['LRazimuth'][0] -= 360
2332                       
2333                    azLim = np.array(Data['LRazimuth'])   
2334                    if np.any(azLim>360):
2335                        azLim -= 360
2336                        Data['LRazimuth'] = list(azLim)
2337                       
2338                    if  Data['IOtth'][0] > Data['IOtth'][1]:
2339                        Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
2340                       
2341                    G2frame.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
2342                    G2frame.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
2343                    G2frame.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
2344                    G2frame.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
2345                elif 'Circle' in itemPicked and PickName == 'Masks':
2346                    spots = Masks['Points']
2347                    newPos = itemPicked.split(')')[0].split('(')[2].split(',')
2348                    newPos = np.array([float(newPos[0]),float(newPos[1])])
2349                    for spot in spots:
2350                        if np.allclose(np.array([spot[:2]]),newPos):
2351                            spot[:2] = Xpos,Ypos
2352                    G2imG.UpdateMasks(G2frame,Masks)
2353                elif 'Line2D' in itemPicked and PickName == 'Masks':
2354                    Obj = G2frame.itemPicked.findobj()
2355                    rings = Masks['Rings']
2356                    arcs = Masks['Arcs']
2357                    polygons = Masks['Polygons']
2358                    frame = Masks['Frames']
2359                    for ring in G2frame.ringList:
2360                        if Obj == ring[0]:
2361                            rN = ring[1]
2362                            if ring[2] == 'o':
2363                                rings[rN][0] = G2img.GetTth(Xpos,Ypos,Data)-rings[rN][1]/2.
2364                            else:
2365                                rings[rN][0] = G2img.GetTth(Xpos,Ypos,Data)+rings[rN][1]/2.
2366                    for arc in G2frame.arcList:
2367                        if Obj == arc[0]:
2368                            aN = arc[1]
2369                            if arc[2] == 'o':
2370                                arcs[aN][0] = G2img.GetTth(Xpos,Ypos,Data)-arcs[aN][2]/2
2371                            elif arc[2] == 'i':
2372                                arcs[aN][0] = G2img.GetTth(Xpos,Ypos,Data)+arcs[aN][2]/2
2373                            elif arc[2] == 'l':
2374                                arcs[aN][1][0] = int(G2img.GetAzm(Xpos,Ypos,Data))
2375                            else:
2376                                arcs[aN][1][1] = int(G2img.GetAzm(Xpos,Ypos,Data))
2377                    for poly in G2frame.polyList:
2378                        if Obj == poly[0]:
2379                            ind = G2frame.itemPicked.contains(G2frame.mousePicked)[1]['ind'][0]
2380                            oldPos = np.array([G2frame.mousePicked.xdata,G2frame.mousePicked.ydata])
2381                            pN = poly[1]
2382                            for i,xy in enumerate(polygons[pN]):
2383                                if np.allclose(np.array([xy]),oldPos,atol=1.0):
2384                                    polygons[pN][i] = Xpos,Ypos
2385                    if frame:
2386                        oldPos = np.array([G2frame.mousePicked.xdata,G2frame.mousePicked.ydata])
2387                        for i,xy in enumerate(frame):
2388                            if np.allclose(np.array([xy]),oldPos,atol=1.0):
2389                                frame[i] = Xpos,Ypos
2390                    G2imG.UpdateMasks(G2frame,Masks)
2391#                else:                  #keep for future debugging
2392#                    print str(G2frame.itemPicked),event.xdata,event.ydata,event.button
2393            PlotImage(G2frame,newImage=True)
2394            G2frame.itemPicked = None
2395           
2396    try:
2397        plotNum = G2frame.G2plotNB.plotList.index('2D Powder Image')
2398        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2399        if not newPlot:
2400            Plot = Page.figure.gca()          #get previous powder plot & get limits
2401            xylim = Plot.get_xlim(),Plot.get_ylim()
2402        if newImage:
2403            Page.figure.clf()
2404            Plot = Page.figure.gca()          #get a fresh plot after clf()
2405    except ValueError:
2406        Plot = G2frame.G2plotNB.addMpl('2D Powder Image').gca()
2407        plotNum = G2frame.G2plotNB.plotList.index('2D Powder Image')
2408        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2409        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
2410        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
2411        Page.canvas.mpl_connect('pick_event', OnImPick)
2412        Page.canvas.mpl_connect('button_release_event', OnImRelease)
2413        xylim = []
2414    Page.Choice = None
2415    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
2416        Page.SetFocus()
2417    Title = G2frame.PatternTree.GetItemText(G2frame.Image)[4:]
2418    G2frame.G2plotNB.status.DestroyChildren()
2419    if G2frame.logPlot:
2420        Title = 'log('+Title+')'
2421    Plot.set_title(Title)
2422    try:
2423        if G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Image Controls',]:
2424            Page.Choice = (' key press','l: log(I) on','x: flip x','y: flip y',)
2425            if G2frame.logPlot:
2426                Page.Choice[1] = 'l: log(I) off'
2427            Page.keyPress = OnImPlotKeyPress
2428        elif G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Masks',]:
2429            Page.Choice = (' key press','s: spot mask','a: arc mask','r: ring mask',
2430                'p: polygon mask','f: frame mask',)
2431            Page.keyPress = OnImPlotKeyPress
2432    except TypeError:
2433        pass
2434    size,imagefile = G2frame.PatternTree.GetItemPyData(G2frame.Image)
2435    if imagefile != G2frame.oldImagefile:
2436        imagefile = G2IO.CheckImageFile(G2frame,imagefile)
2437        if not imagefile:
2438            G2frame.G2plotNB.Delete('2D Powder Image')
2439            return
2440        G2frame.PatternTree.SetItemPyData(G2frame.Image,[size,imagefile])
2441        G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,imageOnly=True)
2442        G2frame.oldImagefile = imagefile
2443
2444    imScale = 1
2445    if len(G2frame.ImageZ) > 1024:
2446        imScale = len(G2frame.ImageZ)/1024
2447    sizexy = Data['size']
2448    pixelSize = Data['pixelSize']
2449    scalex = 1000./pixelSize[0]
2450    scaley = 1000./pixelSize[1]
2451    Xmax = sizexy[0]*pixelSize[0]/1000.
2452    Ymax = sizexy[1]*pixelSize[1]/1000.
2453    xlim = (0,Xmax)
2454    ylim = (Ymax,0)
2455    Imin,Imax = Data['range'][1]
2456    acolor = mpl.cm.get_cmap(Data['color'])
2457    xcent,ycent = Data['center']
2458    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
2459    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
2460    #do threshold mask - "real" mask - others are just bondaries
2461    Zlim = Masks['Thresholds'][1]
2462    wx.BeginBusyCursor()
2463    try:
2464           
2465        if newImage:                   
2466            MA = ma.masked_greater(ma.masked_less(G2frame.ImageZ,Zlim[0]),Zlim[1])
2467            MaskA = ma.getmaskarray(MA)
2468            A = G2img.ImageCompress(MA,imScale)
2469            AM = G2img.ImageCompress(MaskA,imScale)
2470            if G2frame.logPlot:
2471                A = np.where(A>0,np.log(A),0)
2472                AM = np.where(AM>0,np.log(AM),0)
2473                Imin,Imax = [np.amin(A),np.amax(A)]
2474            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
2475                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Ymax,0])
2476            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
2477                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
2478   
2479        Plot.plot(xcent,ycent,'x')
2480        #G2frame.PatternTree.GetItemText(item)
2481        if Data['showLines']:
2482            LRAzim = Data['LRazimuth']                  #NB: integers
2483            Nazm = Data['outAzimuths']
2484            delAzm = float(LRAzim[1]-LRAzim[0])/Nazm
2485            AzmthOff = Data['azmthOff']
2486            IOtth = Data['IOtth']
2487            wave = Data['wavelength']
2488            dspI = wave/(2.0*sind(IOtth[0]/2.0))
2489            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
2490            dspO = wave/(2.0*sind(IOtth[1]/2.0))
2491            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
2492            Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
2493            if ellI:
2494                xyI = []
2495                for azm in Azm:
2496                    xyI.append(G2img.GetDetectorXY(dspI,azm,Data))      #what about hyperbola?
2497                xyI = np.array(xyI)
2498                arcxI,arcyI = xyI.T
2499                Plot.plot(arcxI,arcyI,picker=3)
2500            if ellO:
2501                xyO = []
2502                for azm in Azm:
2503                    xyO.append(G2img.GetDetectorXY(dspO,azm,Data))      #what about hyperbola?
2504                xyO = np.array(xyO)
2505                arcxO,arcyO = xyO.T
2506                Plot.plot(arcxO,arcyO,picker=3)
2507            if ellO and ellI:
2508                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
2509                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
2510            for i in range(Nazm):
2511                cake = LRAzim[0]+i*delAzm-AzmthOff
2512                if Data['centerAzm']:
2513                    cake += delAzm/2.
2514                ind = np.searchsorted(Azm,cake)
2515                Plot.plot([arcxI[ind],arcxO[ind]],[arcyI[ind],arcyO[ind]],color='k',dashes=(5,5))
2516                   
2517        if G2frame.PatternTree.GetItemText(G2frame.PickId) in 'Image Controls':
2518            for xring,yring in Data['ring']:
2519                Plot.plot(xring,yring,'r+',picker=3)
2520            if Data['setRings']:
2521                N = 0
2522                for ring in Data['rings']:
2523                    xring,yring = np.array(ring).T[:2]
2524                    Plot.plot(xring,yring,'+',color=colors[N%6])
2525                    N += 1           
2526            for ellipse in Data['ellipses']:      #what about hyperbola?
2527                cent,phi,[width,height],col = ellipse
2528                if width > 0:       #ellipses
2529                    Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
2530                    Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
2531        if G2frame.PatternTree.GetItemText(G2frame.PickId) in 'Stress/Strain':
2532            print 'plot stress/strain stuff'
2533            for ring in StrSta['d-zero']:
2534                xring,yring = ring['ImxyObs']
2535                Plot.plot(xring,yring,'r+')
2536#                for xring,yring in ring['ImxyCalc'].T:
2537#                    Plot.add_artist(Polygon(ring['ImxyCalc'].T,ec='b',fc='none'))
2538#                    Plot.plot(xring,yring)
2539        #masks - mask lines numbered after integration limit lines
2540        spots = Masks['Points']
2541        rings = Masks['Rings']
2542        arcs = Masks['Arcs']
2543        polygons = Masks['Polygons']
2544        if 'Frames' not in Masks:
2545            Masks['Frames'] = []
2546        frame = Masks['Frames']
2547        for spot in spots:
2548            if spot:
2549                x,y,d = spot
2550                Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
2551        G2frame.ringList = []
2552        for iring,ring in enumerate(rings):
2553            if ring:
2554                tth,thick = ring
2555                wave = Data['wavelength']
2556                xy1 = []
2557                xy2 = []
2558                Azm = np.linspace(0,362,181)
2559                for azm in Azm:
2560                    xy1.append(G2img.GetDetectorXY(Dsp(tth+thick/2.,wave),azm,Data))      #what about hyperbola
2561                    xy2.append(G2img.GetDetectorXY(Dsp(tth-thick/2.,wave),azm,Data))      #what about hyperbola
2562                x1,y1 = np.array(xy1).T
2563                x2,y2 = np.array(xy2).T
2564                G2frame.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
2565                G2frame.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
2566        G2frame.arcList = []
2567        for iarc,arc in enumerate(arcs):
2568            if arc:
2569                tth,azm,thick = arc           
2570                wave = Data['wavelength']
2571                xy1 = []
2572                xy2 = []
2573                aR = azm[0],azm[1],azm[1]-azm[0]
2574                if azm[1]-azm[0] > 180:
2575                    aR[2] /= 2
2576                Azm = np.linspace(aR[0],aR[1],aR[2])
2577                for azm in Azm:
2578                    xy1.append(G2img.GetDetectorXY(Dsp(tth+thick/2.,wave),azm,Data))      #what about hyperbola
2579                    xy2.append(G2img.GetDetectorXY(Dsp(tth-thick/2.,wave),azm,Data))      #what about hyperbola
2580                x1,y1 = np.array(xy1).T
2581                x2,y2 = np.array(xy2).T
2582                G2frame.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
2583                G2frame.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
2584                G2frame.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
2585                G2frame.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
2586        G2frame.polyList = []
2587        for ipoly,polygon in enumerate(polygons):
2588            if polygon:
2589                x,y = np.hsplit(np.array(polygon),2)
2590                G2frame.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
2591                Plot.plot(x,y,'r')           
2592        G2frame.frameList = []
2593        if frame:
2594            x,y = np.hsplit(np.array(frame),2)
2595            G2frame.frameList.append([Plot.plot(x,y,'g+',picker=10),0])
2596            Plot.plot(x,y,'g')           
2597        if newImage:
2598            colorBar = Page.figure.colorbar(Img)
2599        Plot.set_xlim(xlim)
2600        Plot.set_ylim(ylim)
2601        if Data['invert_x']:
2602            Plot.invert_xaxis()
2603        if Data['invert_y']:
2604            Plot.invert_yaxis()
2605        if not newPlot and xylim:
2606            Page.toolbar.push_current()
2607            Plot.set_xlim(xylim[0])
2608            Plot.set_ylim(xylim[1])
2609            xylim = []
2610            Page.toolbar.push_current()
2611            Page.toolbar.draw()
2612        else:
2613            Page.canvas.draw()
2614    finally:
2615        wx.EndBusyCursor()
2616       
2617################################################################################
2618##### PlotIntegration
2619################################################################################
2620           
2621def PlotIntegration(G2frame,newPlot=False,event=None):
2622    '''Plot of 2D image after image integration with 2-theta and azimuth as coordinates
2623    '''
2624           
2625    def OnMotion(event):
2626        Page.canvas.SetToolTipString('')
2627        Page.canvas.SetCursor(wx.CROSS_CURSOR)
2628        azm = event.ydata
2629        tth = event.xdata
2630        if azm and tth:
2631            G2frame.G2plotNB.status.SetFields(\
2632                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
2633                               
2634    try:
2635        plotNum = G2frame.G2plotNB.plotList.index('2D Integration')
2636        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2637        if not newPlot:
2638            Plot = Page.figure.gca()          #get previous plot & get limits
2639            xylim = Plot.get_xlim(),Plot.get_ylim()
2640        Page.figure.clf()
2641        Plot = Page.figure.gca()          #get a fresh plot after clf()
2642       
2643    except ValueError:
2644        Plot = G2frame.G2plotNB.addMpl('2D Integration').gca()
2645        plotNum = G2frame.G2plotNB.plotList.index('2D Integration')
2646        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2647        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2648        Page.views = False
2649        view = False
2650    Page.Choice = None
2651    if not event:
2652        Page.SetFocus()
2653       
2654    Data = G2frame.PatternTree.GetItemPyData(
2655        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
2656    image = G2frame.Integrate[0]
2657    xsc = G2frame.Integrate[1]
2658    ysc = G2frame.Integrate[2]
2659    Imin,Imax = Data['range'][1]
2660    acolor = mpl.cm.get_cmap(Data['color'])
2661    Plot.set_title(G2frame.PatternTree.GetItemText(G2frame.Image)[4:])
2662    Plot.set_ylabel('azimuth',fontsize=12)
2663    Plot.set_xlabel('2-theta',fontsize=12)
2664    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
2665        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
2666    colorBar = Page.figure.colorbar(Img)
2667#    if Data['ellipses']:           
2668#        for ellipse in Data['ellipses']:
2669#            x,y = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
2670#            tth,azm = G2img.GetTthAzm(x,y,Data)
2671##            azm = np.where(azm < 0.,azm+360,azm)
2672#            Plot.plot(tth,azm,'b,')
2673    if not newPlot:
2674        Page.toolbar.push_current()
2675        Plot.set_xlim(xylim[0])
2676        Plot.set_ylim(xylim[1])
2677        xylim = []
2678        Page.toolbar.push_current()
2679        Page.toolbar.draw()
2680    else:
2681        Page.canvas.draw()
2682               
2683################################################################################
2684##### PlotTRImage
2685################################################################################
2686           
2687def PlotTRImage(G2frame,tax,tay,taz,newPlot=False):
2688    '''a test plot routine - not normally used
2689    ''' 
2690           
2691    def OnMotion(event):
2692        Page.canvas.SetToolTipString('')
2693        Page.canvas.SetCursor(wx.CROSS_CURSOR)
2694        azm = event.xdata
2695        tth = event.ydata
2696        if azm and tth:
2697            G2frame.G2plotNB.status.SetFields(\
2698                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
2699                               
2700    try:
2701        plotNum = G2frame.G2plotNB.plotList.index('2D Transformed Powder Image')
2702        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2703        if not newPlot:
2704            Plot = Page.figure.gca()          #get previous plot & get limits
2705            xylim = Plot.get_xlim(),Plot.get_ylim()
2706        Page.figure.clf()
2707        Plot = Page.figure.gca()          #get a fresh plot after clf()
2708       
2709    except ValueError:
2710        Plot = G2frame.G2plotNB.addMpl('2D Transformed Powder Image').gca()
2711        plotNum = G2frame.G2plotNB.plotList.index('2D Transformed Powder Image')
2712        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2713        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2714        Page.views = False
2715        view = False
2716    Page.Choice = None
2717    Page.SetFocus()
2718       
2719    Data = G2frame.PatternTree.GetItemPyData(
2720        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
2721    Imin,Imax = Data['range'][1]
2722    step = (Imax-Imin)/5.
2723    V = np.arange(Imin,Imax,step)
2724    acolor = mpl.cm.get_cmap(Data['color'])
2725    Plot.set_title(G2frame.PatternTree.GetItemText(G2frame.Image)[4:])
2726    Plot.set_xlabel('azimuth',fontsize=12)
2727    Plot.set_ylabel('2-theta',fontsize=12)
2728    Plot.contour(tax,tay,taz,V,cmap=acolor)
2729    if Data['showLines']:
2730        IOtth = Data['IOtth']
2731        if Data['fullIntegrate']:
2732            LRAzim = [-180,180]
2733        else:
2734            LRAzim = Data['LRazimuth']                  #NB: integers
2735        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[0],IOtth[0]],picker=True)
2736        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[1],IOtth[1]],picker=True)
2737        if not Data['fullIntegrate']:
2738            Plot.plot([LRAzim[0],LRAzim[0]],[IOtth[0],IOtth[1]],picker=True)
2739            Plot.plot([LRAzim[1],LRAzim[1]],[IOtth[0],IOtth[1]],picker=True)
2740    if Data['setRings']:
2741        rings = np.concatenate((Data['rings']),axis=0)
2742        for xring,yring,dsp in rings:
2743            x,y = G2img.GetTthAzm(xring,yring,Data)
2744            Plot.plot(y,x,'r+')           
2745    if Data['ellipses']:           
2746        for ellipse in Data['ellipses']:
2747            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
2748            x,y = np.hsplit(ring,2)
2749            tth,azm = G2img.GetTthAzm(x,y,Data)
2750            Plot.plot(azm,tth,'b,')
2751    if not newPlot:
2752        Page.toolbar.push_current()
2753        Plot.set_xlim(xylim[0])
2754        Plot.set_ylim(xylim[1])
2755        xylim = []
2756        Page.toolbar.push_current()
2757        Page.toolbar.draw()
2758    else:
2759        Page.canvas.draw()
2760       
2761################################################################################
2762##### PlotStructure
2763################################################################################
2764           
2765def PlotStructure(G2frame,data):
2766    '''Crystal structure plotting package. Can show structures as balls, sticks, lines,
2767    thermal motion ellipsoids and polyhedra
2768    '''
2769
2770    def FindPeaksBonds(XYZ):
2771        rFact = data['Drawing']['radiusFactor']
2772        Bonds = [[] for x in XYZ]
2773        for i,xyz in enumerate(XYZ):
2774            Dx = XYZ-xyz
2775            dist = np.sqrt(np.sum(np.inner(Dx,Amat)**2,axis=1))
2776            IndB = ma.nonzero(ma.masked_greater(dist,rFact*2.2))
2777            for j in IndB[0]:
2778                Bonds[i].append(Dx[j]/2.)
2779                Bonds[j].append(-Dx[j]/2.)
2780        return Bonds
2781
2782    ForthirdPI = 4.0*math.pi/3.0
2783    generalData = data['General']
2784    cell = generalData['Cell'][1:7]
2785    Vol = generalData['Cell'][7:8][0]
2786    Amat,Bmat = G2lat.cell2AB(cell)         #Amat - crystal to cartesian, Bmat - inverse
2787    Gmat,gmat = G2lat.cell2Gmat(cell)
2788    A4mat = np.concatenate((np.concatenate((Amat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
2789    B4mat = np.concatenate((np.concatenate((Bmat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
2790    SGData = generalData['SGData']
2791    Mydir = generalData['Mydir']
2792    atomData = data['Atoms']
2793    mapPeaks = []
2794    drawingData = data['Drawing']   
2795    if 'Map Peaks' in data:
2796        mapPeaks = np.array(data['Map Peaks'])
2797        peakMax = 100.
2798        if len(mapPeaks):
2799            peakMax = np.max(mapPeaks.T[0])
2800    resRBData = data['RBModels'].get('Residue',[])
2801    vecRBData = data['RBModels'].get('Vector',[])
2802    rbAtmDict = {}
2803    for rbObj in resRBData+vecRBData:
2804        exclList = ['X' for i in range(len(rbObj['Ids']))]
2805        rbAtmDict.update(dict(zip(rbObj['Ids'],exclList)))
2806    testRBObj = data.get('testRBObj',{})
2807    rbObj = testRBObj.get('rbObj',{})
2808    MCSA = data.get('MCSA',{})
2809    mcsaModels = MCSA.get('Models',[])
2810    if mcsaModels:
2811        XYZs,Types = G2mth.UpdateMCSAxyz(Bmat,MCSA)
2812        mcsaXYZ = []
2813        mcsaTypes = []
2814        for xyz,atyp in zip(XYZs,Types):
2815            for item in G2spc.GenAtom(xyz,SGData):
2816                mcsaXYZ.append(item[0]) 
2817                mcsaTypes.append(atyp)
2818        mcsaBonds = FindPeaksBonds(mcsaXYZ)       
2819    drawAtoms = drawingData.get('Atoms',[])
2820    mapData = {}
2821    flipData = {}
2822    rhoXYZ = []
2823    showBonds = False
2824    if 'Map' in generalData:
2825        mapData = generalData['Map']
2826        showBonds = mapData.get('Show bonds',False)
2827    if 'Flip' in generalData:
2828        flipData = generalData['Flip']                       
2829        flipData['mapRoll'] = [0,0,0]
2830    Wt = np.array([255,255,255])
2831    Rd = np.array([255,0,0])
2832    Gr = np.array([0,255,0])
2833    wxGreen = wx.Color(0,255,0)
2834    Bl = np.array([0,0,255])
2835    Or = np.array([255,128,0])
2836    wxOrange = wx.Color(255,128,0)
2837    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]])
2838    uEdges = np.array([
2839        [uBox[0],uBox[1]],[uBox[0],uBox[3]],[uBox[0],uBox[4]],[uBox[1],uBox[2]], 
2840        [uBox[2],uBox[3]],[uBox[1],uBox[5]],[uBox[2],uBox[6]],[uBox[3],uBox[7]], 
2841        [uBox[4],uBox[5]],[uBox[5],uBox[6]],[uBox[6],uBox[7]],[uBox[7],uBox[4]]])
2842    mD = 0.1
2843    mV = np.array([[[-mD,0,0],[mD,0,0]],[[0,-mD,0],[0,mD,0]],[[0,0,-mD],[0,0,mD]]])
2844    mapPeakVecs = np.inner(mV,Bmat)
2845
2846    uColors = [Rd,Gr,Bl,Wt, Wt,Wt,Wt,Wt, Wt,Wt,Wt,Wt]
2847    altDown = False
2848    shiftDown = False
2849    ctrlDown = False
2850   
2851    def OnKeyBox(event):
2852        import Image
2853#        Draw()                          #make sure plot is fresh!!
2854        mode = cb.GetValue()
2855        if mode in ['jpeg','bmp','tiff',]:
2856            Fname = os.path.join(Mydir,generalData['Name']+'.'+mode)
2857            size = Page.canvas.GetSize()
2858            glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
2859            if mode in ['jpeg',]:
2860                Pix = glReadPixels(0,0,size[0],size[1],GL_RGBA, GL_UNSIGNED_BYTE)
2861                im = Image.new("RGBA", (size[0],size[1]))
2862            else:
2863                Pix = glReadPixels(0,0,size[0],size[1],GL_RGB, GL_UNSIGNED_BYTE)
2864                im = Image.new("RGB", (size[0],size[1]))
2865            im.fromstring(Pix)
2866            im.save(Fname,mode)
2867            cb.SetValue(' save as/key:')
2868            G2frame.G2plotNB.status.SetStatusText('Drawing saved to: '+Fname,1)
2869        else:
2870            event.key = cb.GetValue()[0]
2871            cb.SetValue(' save as/key:')
2872            wx.CallAfter(OnKey,event)
2873        Page.canvas.SetFocus() # redirect the Focus from the button back to the plot
2874
2875    def OnKey(event):           #on key UP!!
2876#        Draw()                          #make sure plot is fresh!!
2877        try:
2878            keyCode = event.GetKeyCode()
2879            if keyCode > 255:
2880                keyCode = 0
2881            key = chr(keyCode)
2882        except AttributeError:       #if from OnKeyBox above
2883            key = str(event.key).upper()
2884        indx = drawingData['selectedAtoms']
2885        cx,ct = drawingData['atomPtrs'][:2]
2886        if key in ['C']:
2887            drawingData['viewPoint'] = [[.5,.5,.5],[0,0]]
2888            drawingData['viewDir'] = [0,0,1]
2889            drawingData['oldxy'] = []
2890            V0 = np.array([0,0,1])
2891            V = np.inner(Amat,V0)
2892            V /= np.sqrt(np.sum(V**2))
2893            A = np.arccos(np.sum(V*V0))
2894            Q = G2mth.AV2Q(A,[0,1,0])
2895            drawingData['Quaternion'] = Q
2896            SetViewPointText(drawingData['viewPoint'][0])
2897            SetViewDirText(drawingData['viewDir'])
2898            Q = drawingData['Quaternion']
2899            G2frame.G2plotNB.status.SetStatusText('New quaternion: %.2f+, %.2fi+ ,%.2fj+, %.2fk'%(Q[0],Q[1],Q[2],Q[3]),1)
2900        elif key in ['N']:
2901            drawAtoms = drawingData['Atoms']
2902            if not len(drawAtoms):      #no atoms
2903                return
2904            pI = drawingData['viewPoint'][1]
2905            if not len(pI):
2906                pI = [0,0]
2907            if indx:
2908                pI[0] = indx[pI[1]]
2909                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2910                pI[1] += 1
2911                if pI[1] >= len(indx):
2912                    pI[1] = 0
2913            else:
2914                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2915                pI[0] += 1
2916                if pI[0] >= len(drawAtoms):
2917                    pI[0] = 0
2918            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2919            SetViewPointText(drawingData['viewPoint'][0])
2920            G2frame.G2plotNB.status.SetStatusText('View point at atom '+drawAtoms[pI[0]][ct-1]+str(pI),1)
2921               
2922        elif key in ['P']:
2923            drawAtoms = drawingData['Atoms']
2924            if not len(drawAtoms):      #no atoms
2925                return
2926            pI = drawingData['viewPoint'][1]
2927            if not len(pI):
2928                pI = [0,0]
2929            if indx:
2930                pI[0] = indx[pI[1]]
2931                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2932                pI[1] -= 1
2933                if pI[1] < 0:
2934                    pI[1] = len(indx)-1
2935            else:
2936                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2937                pI[0] -= 1
2938                if pI[0] < 0:
2939                    pI[0] = len(drawAtoms)-1
2940            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2941            SetViewPointText(drawingData['viewPoint'][0])           
2942            G2frame.G2plotNB.status.SetStatusText('View point at atom '+drawAtoms[pI[0]][ct-1]+str(pI),1)
2943        elif key in ['U','D','L','R'] and mapData['Flip'] == True:
2944            dirDict = {'U':[0,1],'D':[0,-1],'L':[-1,0],'R':[1,0]}
2945            SetMapRoll(dirDict[key])
2946            SetPeakRoll(dirDict[key])
2947            SetMapPeaksText(mapPeaks)
2948        Draw('key')
2949           
2950    def GetTruePosition(xy,Add=False):
2951        View = glGetIntegerv(GL_VIEWPORT)
2952        Proj = glGetDoublev(GL_PROJECTION_MATRIX)
2953        Model = glGetDoublev(GL_MODELVIEW_MATRIX)
2954        Zmax = 1.
2955        if Add:
2956            Indx = GetSelectedAtoms()
2957        if G2frame.dataDisplay.GetPageText(getSelection()) == 'Map peaks':
2958            for i,peak in enumerate(mapPeaks):
2959                x,y,z = peak[1:4]
2960                X,Y,Z = gluProject(x,y,z,Model,Proj,View)
2961                XY = [int(X),int(View[3]-Y)]
2962                if np.allclose(xy,XY,atol=10) and Z < Zmax:
2963                    Zmax = Z
2964                    try:
2965                        Indx.remove(i)
2966                        ClearSelectedAtoms()
2967                        for id in Indx:
2968                            SetSelectedAtoms(id,Add)
2969                    except:
2970                        SetSelectedAtoms(i,Add)
2971        else:
2972            cx = drawingData['atomPtrs'][0]
2973            for i,atom in enumerate(drawAtoms):
2974                x,y,z = atom[cx:cx+3]
2975                X,Y,Z = gluProject(x,y,z,Model,Proj,View)
2976                XY = [int(X),int(View[3]-Y)]
2977                if np.allclose(xy,XY,atol=10) and Z < Zmax:
2978                    Zmax = Z
2979                    try:
2980                        Indx.remove(i)
2981                        ClearSelectedAtoms()
2982                        for id in Indx:
2983                            SetSelectedAtoms(id,Add)
2984                    except:
2985                        SetSelectedAtoms(i,Add)
2986                                       
2987    def OnMouseDown(event):
2988        xy = event.GetPosition()
2989        if event.ShiftDown():
2990            if event.LeftIsDown():
2991                GetTruePosition(xy)
2992            elif event.RightIsDown():
2993                GetTruePosition(xy,True)
2994        else:
2995            drawingData['oldxy'] = list(xy)
2996       
2997    def OnMouseMove(event):
2998        if event.ShiftDown():           #don't want any inadvertant moves when picking
2999            return
3000        newxy = event.GetPosition()
3001                               
3002        if event.Dragging():
3003            if event.AltDown() and rbObj:
3004                if event.LeftIsDown():
3005                    SetRBRotation(newxy)
3006                    Q = rbObj['Orient'][0]
3007                    G2frame.G2plotNB.status.SetStatusText('New quaternion: %.2f+, %.2fi+ ,%.2fj+, %.2fk'%(Q[0],Q[1],Q[2],Q[3]),1)
3008                elif event.RightIsDown():
3009                    SetRBTranslation(newxy)
3010                    Tx,Ty,Tz = rbObj['Orig'][0]
3011                    G2frame.G2plotNB.status.SetStatusText('New view point: %.4f, %.4f, %.4f'%(Tx,Ty,Tz),1)
3012                elif event.MiddleIsDown():
3013                    SetRBRotationZ(newxy)
3014                    Q = rbObj['Orient'][0]
3015                    G2frame.G2plotNB.status.SetStatusText('New quaternion: %.2f+, %.2fi+ ,%.2fj+, %.2fk'%(Q[0],Q[1],Q[2],Q[3]),1)
3016                Draw('move')
3017            elif not event.ControlDown():
3018                if event.LeftIsDown():
3019                    SetRotation(newxy)
3020                    Q = drawingData['Quaternion']
3021                    G2frame.G2plotNB.status.SetStatusText('New quaternion: %.2f+, %.2fi+ ,%.2fj+, %.2fk'%(Q[0],Q[1],Q[2],Q[3]),1)
3022                elif event.RightIsDown():
3023                    SetTranslation(newxy)
3024                    Tx,Ty,Tz = drawingData['viewPoint'][0]
3025                    G2frame.G2plotNB.status.SetStatusText('New view point: %.4f, %.4f, %.4f'%(Tx,Ty,Tz),1)
3026                elif event.MiddleIsDown():
3027                    SetRotationZ(newxy)
3028                    Q = drawingData['Quaternion']
3029                    G2frame.G2plotNB.status.SetStatusText('New quaternion: %.2f+, %.2fi+ ,%.2fj+, %.2fk'%(Q[0],Q[1],Q[2],Q[3]),1)
3030                Draw('move')
3031           
3032       
3033    def OnMouseWheel(event):
3034        if event.ShiftDown():
3035            return
3036        drawingData['cameraPos'] += event.GetWheelRotation()/24.
3037        drawingData['cameraPos'] = max(10,min(500,drawingData['cameraPos']))
3038        G2frame.G2plotNB.status.SetStatusText('New camera distance: %.2f'%(drawingData['cameraPos']),1)
3039        page = getSelection()
3040        if page:
3041            if G2frame.dataDisplay.GetPageText(page) == 'Draw Options':
3042                G2frame.dataDisplay.cameraPosTxt.SetLabel('Camera Position: '+'%.2f'%(drawingData['cameraPos']))
3043                G2frame.dataDisplay.cameraSlider.SetValue(drawingData['cameraPos'])
3044            Draw('wheel')
3045       
3046    def getSelection():
3047        try:
3048            return G2frame.dataDisplay.GetSelection()
3049        except AttributeError:
3050            G2frame.G2plotNB.status.SetStatusText('Select this from Phase data window!')
3051            return 0
3052           
3053    def SetViewPointText(VP):
3054        page = getSelection()
3055        if page:
3056            if G2frame.dataDisplay.GetPageText(page) == 'Draw Options':
3057                G2frame.dataDisplay.viewPoint.SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))
3058               
3059    def SetRBOrigText():
3060        page = getSelection()
3061        if page:
3062            if G2frame.dataDisplay.GetPageText(page) == 'RB Models':
3063                for i,sizer in enumerate(testRBObj['Sizers']['Xsizers']):
3064                    sizer.SetValue('%8.5f'%(testRBObj['rbObj']['Orig'][0][i]))
3065                   
3066    def SetRBOrienText():
3067        page = getSelection()
3068        if page:
3069            if G2frame.dataDisplay.GetPageText(page) == 'RB Models':
3070                for i,sizer in enumerate(testRBObj['Sizers']['Osizers']):
3071                    sizer.SetValue('%8.5f'%(testRBObj['rbObj']['Orient'][0][i]))
3072               
3073    def SetViewDirText(VD):
3074        page = getSelection()
3075        if page:
3076            if G2frame.dataDisplay.GetPageText(page) == 'Draw Options':
3077                G2frame.dataDisplay.viewDir.SetValue('%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]))
3078               
3079    def SetMapPeaksText(mapPeaks):
3080        page = getSelection()
3081        if page:
3082            if G2frame.dataDisplay.GetPageText(page) == 'Map peaks':
3083                G2frame.MapPeaksTable.SetData(mapPeaks)
3084                panel = G2frame.dataDisplay.GetPage(page).GetChildren()
3085                names = [child.GetName() for child in panel]
3086                panel[names.index('grid window')].Refresh()
3087           
3088    def ClearSelectedAtoms():
3089        page = getSelection()
3090        if page:
3091            if G2frame.dataDisplay.GetPageText(page) == 'Draw Atoms':
3092                G2frame.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Draw Atoms
3093            elif G2frame.dataDisplay.GetPageText(page) == 'Map peaks':
3094                G2frame.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Atoms
3095            elif G2frame.dataDisplay.GetPageText(page) == 'Atoms':
3096                G2frame.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Atoms
3097               
3098                   
3099    def SetSelectedAtoms(ind,Add=False):
3100        page = getSelection()
3101        if page:
3102            if G2frame.dataDisplay.GetPageText(page) == 'Draw Atoms':
3103                G2frame.dataDisplay.GetPage(page).SelectRow(ind,Add)      #this is the Atoms grid in Draw Atoms
3104            elif G2frame.dataDisplay.GetPageText(page) == 'Map peaks':
3105                G2frame.dataDisplay.GetPage(page).SelectRow(ind,Add)                 
3106            elif G2frame.dataDisplay.GetPageText(page) == 'Atoms':
3107                Id = drawAtoms[ind][-3]
3108                for i,atom in enumerate(atomData):
3109                    if atom[-1] == Id:
3110                        G2frame.dataDisplay.GetPage(page).SelectRow(i)      #this is the Atoms grid in Atoms
3111                 
3112    def GetSelectedAtoms():
3113        page = getSelection()
3114        Ind = []
3115        if page:
3116            if G2frame.dataDisplay.GetPageText(page) == 'Draw Atoms':
3117                Ind = G2frame.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Draw Atoms
3118            elif G2frame.dataDisplay.GetPageText(page) == 'Map peaks':
3119                Ind = G2frame.dataDisplay.GetPage(page).GetSelectedRows()
3120            elif G2frame.dataDisplay.GetPageText(page) == 'Atoms':
3121                Ind = G2frame.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Atoms
3122        return Ind
3123                                       
3124    def SetBackground():
3125        R,G,B,A = Page.camera['backColor']
3126        glClearColor(R,G,B,A)
3127        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
3128       
3129    def SetLights():
3130        glEnable(GL_DEPTH_TEST)
3131        glShadeModel(GL_SMOOTH)
3132        glEnable(GL_LIGHTING)
3133        glEnable(GL_LIGHT0)
3134        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0)
3135        glLightfv(GL_LIGHT0,GL_AMBIENT,[1,1,1,.8])
3136        glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
3137       
3138    def GetRoll(newxy,rho):
3139        Q = drawingData['Quaternion']
3140        dxy = G2mth.prodQVQ(G2mth.invQ(Q),np.inner(Bmat,newxy+[0,]))
3141        dxy = np.array(dxy*rho.shape)       
3142        roll = np.where(dxy>0.5,1,np.where(dxy<-.5,-1,0))
3143        return roll
3144               
3145    def SetMapRoll(newxy):
3146        rho = mapData['rho']
3147        roll = GetRoll(newxy,rho)
3148        mapData['rho'] = np.roll(np.roll(np.roll(rho,roll[0],axis=0),roll[1],axis=1),roll[2],axis=2)
3149        drawingData['oldxy'] = list(newxy)
3150       
3151    def SetPeakRoll(newxy):
3152        rho = mapData['rho']
3153        roll = GetRoll(newxy,rho)
3154        steps = 1./np.array(rho.shape)
3155        dxy = roll*steps
3156        for peak in mapPeaks:
3157            peak[1:4] += dxy
3158            peak[1:4] %= 1.
3159            peak[4] = np.sqrt(np.sum(np.inner(Amat,peak[1:4])**2))
3160               
3161    def SetTranslation(newxy):
3162#first get translation vector in screen coords.       
3163        oldxy = drawingData['oldxy']
3164        if not len(oldxy): oldxy = list(newxy)
3165        dxy = newxy-oldxy
3166        drawingData['oldxy'] = list(newxy)
3167        V = np.array([-dxy[0],dxy[1],0.])
3168#then transform to rotated crystal coordinates & apply to view point       
3169        Q = drawingData['Quaternion']
3170        V = np.inner(Bmat,G2mth.prodQVQ(G2mth.invQ(Q),V))
3171        Tx,Ty,Tz = drawingData['viewPoint'][0]
3172        Tx += V[0]*0.01
3173        Ty += V[1]*0.01
3174        Tz += V[2]*0.01
3175        drawingData['viewPoint'][0] =  Tx,Ty,Tz
3176        SetViewPointText([Tx,Ty,Tz])
3177       
3178    def SetRBTranslation(newxy):
3179#first get translation vector in screen coords.       
3180        oldxy = drawingData['oldxy']
3181        if not len(oldxy): oldxy = list(newxy)
3182        dxy = newxy-oldxy
3183        drawingData['oldxy'] = list(newxy)
3184        V = np.array([-dxy[0],dxy[1],0.])
3185#then transform to rotated crystal coordinates & apply to RB origin       
3186        Q = drawingData['Quaternion']
3187        V = np.inner(Bmat,G2mth.prodQVQ(G2mth.invQ(Q),V))
3188        Tx,Ty,Tz = rbObj['Orig'][0]
3189        Tx -= V[0]*0.01
3190        Ty -= V[1]*0.01
3191        Tz -= V[2]*0.01
3192        rbObj['Orig'][0] =  Tx,Ty,Tz
3193        SetRBOrigText()
3194       
3195    def SetRotation(newxy):
3196#first get rotation vector in screen coords. & angle increment       
3197        oldxy = drawingData['oldxy']
3198        if not len(oldxy): oldxy = list(newxy)
3199        dxy = newxy-oldxy
3200        drawingData['oldxy'] = list(newxy)
3201        V = np.array([dxy[1],dxy[0],0.])
3202        A = 0.25*np.sqrt(dxy[0]**2+dxy[1]**2)
3203# next transform vector back to xtal coordinates via inverse quaternion
3204# & make new quaternion
3205        Q = drawingData['Quaternion']
3206        V = G2mth.prodQVQ(G2mth.invQ(Q),np.inner(Bmat,V))
3207        DQ = G2mth.AVdeg2Q(A,V)
3208        Q = G2mth.prodQQ(Q,DQ)
3209        drawingData['Quaternion'] = Q
3210# finally get new view vector - last row of rotation matrix
3211        VD = np.inner(Bmat,G2mth.Q2Mat(Q)[2])
3212        VD /= np.sqrt(np.sum(VD**2))
3213        drawingData['viewDir'] = VD
3214        SetViewDirText(VD)
3215       
3216    def SetRotationZ(newxy):                       
3217#first get rotation vector (= view vector) in screen coords. & angle increment       
3218        View = glGetIntegerv(GL_VIEWPORT)
3219        cent = [View[2]/2,View[3]/2]
3220        oldxy = drawingData['oldxy']
3221        if not len(oldxy): oldxy = list(newxy)
3222        dxy = newxy-oldxy
3223        drawingData['oldxy'] = list(newxy)
3224        V = drawingData['viewDir']
3225        A = [0,0]
3226        A[0] = dxy[1]*.25
3227        A[1] = dxy[0]*.25
3228        if newxy[0] > cent[0]:
3229            A[0] *= -1
3230        if newxy[1] < cent[1]:
3231            A[1] *= -1       
3232# next transform vector back to xtal coordinates & make new quaternion
3233        Q = drawingData['Quaternion']
3234        V = np.inner(Amat,V)
3235        Qx = G2mth.AVdeg2Q(A[0],V)
3236        Qy = G2mth.AVdeg2Q(A[1],V)
3237        Q = G2mth.prodQQ(Q,Qx)
3238        Q = G2mth.prodQQ(Q,Qy)
3239        drawingData['Quaternion'] = Q
3240
3241    def SetRBRotation(newxy):
3242#first get rotation vector in screen coords. & angle increment       
3243        oldxy = drawingData['oldxy']
3244        if not len(oldxy): oldxy = list(newxy)
3245        dxy = newxy-oldxy
3246        drawingData['oldxy'] = list(newxy)
3247        V = np.array([dxy[1],dxy[0],0.])
3248        A = 0.25*np.sqrt(dxy[0]**2+dxy[1]**2)
3249# next transform vector back to xtal coordinates via inverse quaternion
3250# & make new quaternion
3251        Q = rbObj['Orient'][0]              #rotate RB to Cart
3252        QC = drawingData['Quaternion']      #rotate Cart to drawing
3253        V = G2mth.prodQVQ(G2mth.invQ(QC),V)
3254        V = G2mth.prodQVQ(G2mth.invQ(Q),V)
3255        DQ = G2mth.AVdeg2Q(A,V)
3256        Q = G2mth.prodQQ(Q,DQ)
3257        rbObj['Orient'][0] = Q
3258        SetRBOrienText()
3259       
3260    def SetRBRotationZ(newxy):                       
3261#first get rotation vector (= view vector) in screen coords. & angle increment       
3262        View = glGetIntegerv(GL_VIEWPORT)
3263        cent = [View[2]/2,View[3]/2]
3264        oldxy = drawingData['oldxy']
3265        if not len(oldxy): oldxy = list(newxy)
3266        dxy = newxy-oldxy
3267        drawingData['oldxy'] = list(newxy)
3268        V = drawingData['viewDir']
3269        A = [0,0]
3270        A[0] = dxy[1]*.25
3271        A[1] = dxy[0]*.25
3272        if newxy[0] < cent[0]:
3273            A[0] *= -1
3274        if newxy[1] > cent[1]:
3275            A[1] *= -1       
3276# next transform vector back to RB coordinates & make new quaternion
3277        Q = rbObj['Orient'][0]              #rotate RB to cart
3278        V = np.inner(Amat,V)
3279        V = -G2mth.prodQVQ(G2mth.invQ(Q),V)
3280        Qx = G2mth.AVdeg2Q(A[0],V)
3281        Qy = G2mth.AVdeg2Q(A[1],V)
3282        Q = G2mth.prodQQ(Q,Qx)
3283        Q = G2mth.prodQQ(Q,Qy)
3284        rbObj['Orient'][0] = Q
3285        SetRBOrienText()
3286
3287    def RenderBox():
3288        glEnable(GL_COLOR_MATERIAL)
3289        glLineWidth(2)
3290        glEnable(GL_BLEND)
3291        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
3292        glEnable(GL_LINE_SMOOTH)
3293        glBegin(GL_LINES)
3294        for line,color in zip(uEdges,uColors):
3295            glColor3ubv(color)
3296            glVertex3fv(line[0])
3297            glVertex3fv(line[1])
3298        glEnd()
3299        glColor4ubv([0,0,0,0])
3300        glDisable(GL_LINE_SMOOTH)
3301        glDisable(GL_BLEND)
3302        glDisable(GL_COLOR_MATERIAL)
3303       
3304    def RenderUnitVectors(x,y,z):
3305        xyz = np.array([x,y,z])
3306        glEnable(GL_COLOR_MATERIAL)
3307        glLineWidth(1)
3308        glPushMatrix()
3309        glTranslate(x,y,z)
3310        glScalef(1/cell[0],1/cell[1],1/cell[2])
3311        glBegin(GL_LINES)
3312        for line,color in zip(uEdges,uColors)[:3]:
3313            glColor3ubv(color)
3314            glVertex3fv(-line[1]/2.)
3315            glVertex3fv(line[1]/2.)
3316        glEnd()
3317        glPopMatrix()
3318        glColor4ubv([0,0,0,0])
3319        glDisable(GL_COLOR_MATERIAL)
3320               
3321    def RenderSphere(x,y,z,radius,color):
3322        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
3323        glPushMatrix()
3324        glTranslate(x,y,z)
3325        glMultMatrixf(B4mat.T)
3326        q = gluNewQuadric()
3327        gluSphere(q,radius,20,10)
3328        glPopMatrix()
3329       
3330    def RenderDots(XYZ,RC):
3331        glEnable(GL_COLOR_MATERIAL)
3332        XYZ = np.array(XYZ)
3333        glPushMatrix()
3334        for xyz,rc in zip(XYZ,RC):
3335            x,y,z = xyz
3336            r,c = rc
3337            glColor3ubv(c)
3338            glPointSize(r*50)
3339            glBegin(GL_POINTS)
3340            glVertex3fv(xyz)
3341            glEnd()
3342        glPopMatrix()
3343        glColor4ubv([0,0,0,0])
3344        glDisable(GL_COLOR_MATERIAL)
3345       
3346    def RenderSmallSphere(x,y,z,radius,color):
3347        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
3348        glPushMatrix()
3349        glTranslate(x,y,z)
3350        glMultMatrixf(B4mat.T)
3351        q = gluNewQuadric()
3352        gluSphere(q,radius,4,2)
3353        glPopMatrix()
3354               
3355    def RenderEllipsoid(x,y,z,ellipseProb,E,R4,color):
3356        s1,s2,s3 = E
3357        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
3358        glPushMatrix()
3359        glTranslate(x,y,z)
3360        glMultMatrixf(B4mat.T)
3361        glMultMatrixf(R4.T)
3362        glEnable(GL_NORMALIZE)
3363        glScale(s1,s2,s3)
3364        q = gluNewQuadric()
3365        gluSphere(q,ellipseProb,20,10)
3366        glDisable(GL_NORMALIZE)
3367        glPopMatrix()
3368       
3369    def RenderBonds(x,y,z,Bonds,radius,color,slice=20):
3370        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
3371        glPushMatrix()
3372        glTranslate(x,y,z)
3373        glMultMatrixf(B4mat.T)
3374        for bond in Bonds:
3375            glPushMatrix()
3376            Dx = np.inner(Amat,bond)
3377            Z = np.sqrt(np.sum(Dx**2))
3378            if Z:
3379                azm = atan2d(-Dx[1],-Dx[0])
3380                phi = acosd(Dx[2]/Z)
3381                glRotate(-azm,0,0,1)
3382                glRotate(phi,1,0,0)
3383                q = gluNewQuadric()
3384                gluCylinder(q,radius,radius,Z,slice,2)
3385            glPopMatrix()           
3386        glPopMatrix()
3387               
3388    def RenderLines(x,y,z,Bonds,color):
3389        glShadeModel(GL_FLAT)
3390        xyz = np.array([x,y,z])
3391        glEnable(GL_COLOR_MATERIAL)
3392        glLineWidth(1)
3393        glColor3fv(color)
3394        glPushMatrix()
3395        glBegin(GL_LINES)
3396        for bond in Bonds:
3397            glVertex3fv(xyz)
3398            glVertex3fv(xyz+bond)
3399        glEnd()
3400        glColor4ubv([0,0,0,0])
3401        glPopMatrix()
3402        glDisable(GL_COLOR_MATERIAL)
3403        glShadeModel(GL_SMOOTH)
3404       
3405    def RenderPolyhedra(x,y,z,Faces,color):
3406        glShadeModel(GL_FLAT)
3407        glPushMatrix()
3408        glTranslate(x,y,z)
3409        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
3410        glShadeModel(GL_SMOOTH)
3411        glMultMatrixf(B4mat.T)
3412        for face,norm in Faces:
3413            glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
3414            glFrontFace(GL_CW)
3415            glNormal3fv(norm)
3416            glBegin(GL_TRIANGLES)
3417            for vert in face:
3418                glVertex3fv(vert)
3419            glEnd()
3420        glPopMatrix()
3421        glShadeModel(GL_SMOOTH)
3422
3423    def RenderMapPeak(x,y,z,color,den):
3424        glShadeModel(GL_FLAT)
3425        xyz = np.array([x,y,z])
3426        glEnable(GL_COLOR_MATERIAL)
3427        glLineWidth(3)
3428        glColor3fv(color*den/255)
3429        glPushMatrix()
3430        glBegin(GL_LINES)
3431        for vec in mapPeakVecs:
3432            glVertex3fv(vec[0]+xyz)
3433            glVertex3fv(vec[1]+xyz)
3434        glEnd()
3435        glColor4ubv([0,0,0,0])
3436        glPopMatrix()
3437        glDisable(GL_COLOR_MATERIAL)
3438        glShadeModel(GL_SMOOTH)
3439       
3440    def RenderBackbone(Backbone,BackboneColor,radius):
3441        glPushMatrix()
3442        glMultMatrixf(B4mat.T)
3443        glEnable(GL_COLOR_MATERIAL)
3444        glShadeModel(GL_SMOOTH)
3445        gleSetJoinStyle(TUBE_NORM_EDGE | TUBE_JN_ANGLE | TUBE_JN_CAP)
3446        glePolyCylinder(Backbone,BackboneColor,radius)
3447        glPopMatrix()       
3448        glDisable(GL_COLOR_MATERIAL)
3449       
3450    def RenderLabel(x,y,z,label,r,color,matRot):
3451        '''
3452        color wx.Color object
3453        '''       
3454        glPushMatrix()
3455        glTranslate(x,y,z)
3456        glMultMatrixf(B4mat.T)
3457        glDisable(GL_LIGHTING)
3458        glRasterPos3f(0,0,0)
3459        glMultMatrixf(matRot)
3460        glRotate(180,1,0,0)             #fix to flip about x-axis
3461        text = gltext.Text(text=label,font=Font,foreground=color)
3462        text.draw_text(scale=0.025)
3463        glEnable(GL_LIGHTING)
3464        glPopMatrix()
3465       
3466    def RenderMap(rho,rhoXYZ,indx,Rok):
3467        glShadeModel(GL_FLAT)
3468        cLevel = drawingData['contourLevel']
3469        XYZ = []
3470        RC = []
3471        for i,xyz in enumerate(rhoXYZ):
3472            if not Rok[i]:
3473                x,y,z = xyz
3474                I,J,K = indx[i]
3475                alpha = 1.0
3476                if cLevel < 1.:
3477                    alpha = (abs(rho[I,J,K])/mapData['rhoMax']-cLevel)/(1.-cLevel)
3478                if rho[I,J,K] < 0.:
3479                    XYZ.append(xyz)
3480                    RC.append([0.1*alpha,Rd])
3481                else:
3482                    XYZ.append(xyz)
3483                    RC.append([0.1*alpha,Gr])
3484        RenderDots(XYZ,RC)
3485        glShadeModel(GL_SMOOTH)
3486                           
3487    def Draw(caller=''):
3488#useful debug?       
3489#        if caller:
3490#            print caller
3491# end of useful debug
3492        mapData = generalData['Map']
3493        pageName = ''
3494        page = getSelection()
3495        if page:
3496            pageName = G2frame.dataDisplay.GetPageText(page)
3497        rhoXYZ = []
3498        if len(mapData['rho']):
3499            VP = np.array(drawingData['viewPoint'][0])-np.array([.5,.5,.5])
3500            contLevel = drawingData['contourLevel']*mapData['rhoMax']
3501            if 'delt-F' in mapData['MapType']:
3502                rho = ma.array(mapData['rho'],mask=(np.abs(mapData['rho'])<contLevel))
3503            else:
3504                rho = ma.array(mapData['rho'],mask=(mapData['rho']<contLevel))
3505            steps = 1./np.array(rho.shape)
3506            incre = np.where(VP>=0,VP%steps,VP%steps-steps)
3507            Vsteps = -np.array(VP/steps,dtype='i')
3508            rho = np.roll(np.roll(np.roll(rho,Vsteps[0],axis=0),Vsteps[1],axis=1),Vsteps[2],axis=2)
3509            indx = np.array(ma.nonzero(rho)).T
3510            rhoXYZ = indx*steps+VP-incre
3511            Nc = len(rhoXYZ)
3512            rcube = 2000.*Vol/(ForthirdPI*Nc)
3513            rmax = math.exp(math.log(rcube)/3.)**2
3514            radius = min(drawingData['mapSize']**2,rmax)
3515            view = np.array(drawingData['viewPoint'][0])
3516            Rok = np.sum(np.inner(Amat,rhoXYZ-view).T**2,axis=1)>radius
3517        Ind = GetSelectedAtoms()
3518        VS = np.array(Page.canvas.GetSize())
3519        aspect = float(VS[0])/float(VS[1])
3520        cPos = drawingData['cameraPos']
3521        Zclip = drawingData['Zclip']*cPos/200.
3522        Q = drawingData['Quaternion']
3523        Tx,Ty,Tz = drawingData['viewPoint'][0]
3524        cx,ct,cs,ci = drawingData['atomPtrs']
3525        bondR = drawingData['bondRadius']
3526        G,g = G2lat.cell2Gmat(cell)
3527        GS = G
3528        GS[0][1] = GS[1][0] = math.sqrt(GS[0][0]*GS[1][1])
3529        GS[0][2] = GS[2][0] = math.sqrt(GS[0][0]*GS[2][2])
3530        GS[1][2] = GS[2][1] = math.sqrt(GS[1][1]*GS[2][2])
3531        ellipseProb = G2lat.criticalEllipse(drawingData['ellipseProb']/100.)
3532       
3533        SetBackground()
3534        glInitNames()
3535        glPushName(0)
3536       
3537        glMatrixMode(GL_PROJECTION)
3538        glLoadIdentity()
3539        glViewport(0,0,VS[0],VS[1])
3540        gluPerspective(20.,aspect,cPos-Zclip,cPos+Zclip)
3541        gluLookAt(0,0,cPos,0,0,0,0,1,0)
3542        SetLights()           
3543           
3544        glMatrixMode(GL_MODELVIEW)
3545        glLoadIdentity()
3546        matRot = G2mth.Q2Mat(Q)
3547        matRot = np.concatenate((np.concatenate((matRot,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
3548        glMultMatrixf(matRot.T)
3549        glMultMatrixf(A4mat.T)
3550        glTranslate(-Tx,-Ty,-Tz)
3551        if drawingData['unitCellBox']:
3552            RenderBox()
3553        if drawingData['showABC']:
3554            x,y,z = drawingData['viewPoint'][0]
3555            RenderUnitVectors(x,y,z)
3556        Backbones = {}
3557        BackboneColor = []
3558        time0 = time.time()
3559#        glEnable(GL_BLEND)
3560#        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
3561        for iat,atom in enumerate(drawingData['Atoms']):
3562            x,y,z = atom[cx:cx+3]
3563            Bonds = atom[-2]
3564            Faces = atom[-1]
3565            try:
3566                atNum = generalData['AtomTypes'].index(atom[ct])
3567            except ValueError:
3568                atNum = -1
3569            CL = atom[cs+2]
3570            atColor = np.array(CL)/255.
3571            if drawingData['showRigidBodies'] and atom[ci] in rbAtmDict:
3572                bndColor = Or
3573            else:
3574                bndColor = atColor
3575            if iat in Ind and G2frame.dataDisplay.GetPageText(getSelection()) != 'Map peaks':
3576                atColor = np.array(Gr)/255.
3577#            color += [.25,]
3578            radius = 0.5
3579            if atom[cs] != '':
3580                try:
3581                    glLoadName(atom[-3])
3582                except: #problem with old files - missing code
3583                    pass                   
3584            if 'balls' in atom[cs]:
3585                vdwScale = drawingData['vdwScale']
3586                ballScale = drawingData['ballScale']
3587                if atNum < 0:
3588                    radius = 0.2
3589                elif 'H' == atom[ct]:
3590                    if drawingData['showHydrogen']:
3591                        if 'vdW' in atom[cs] and atNum >= 0:
3592                            radius = vdwScale*generalData['vdWRadii'][atNum]
3593                        else:
3594                            radius = ballScale*drawingData['sizeH']
3595                    else:
3596                        radius = 0.0
3597                else:
3598                    if 'vdW' in atom[cs]:
3599                        radius = vdwScale*generalData['vdWRadii'][atNum]
3600                    else:
3601                        radius = ballScale*generalData['BondRadii'][atNum]
3602                RenderSphere(x,y,z,radius,atColor)
3603                if 'sticks' in atom[cs]:
3604                    RenderBonds(x,y,z,Bonds,bondR,bndColor)
3605            elif 'ellipsoids' in atom[cs]:
3606                RenderBonds(x,y,z,Bonds,bondR,bndColor)
3607                if atom[cs+3] == 'A':                   
3608                    Uij = atom[cs+5:cs+11]
3609                    U = np.multiply(G2spc.Uij2U(Uij),GS)
3610                    U = np.inner(Amat,np.inner(U,Amat).T)
3611                    E,R = nl.eigh(U)
3612                    R4 = np.concatenate((np.concatenate((R,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
3613                    E = np.sqrt(E)
3614                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
3615                        pass
3616                    else:
3617                        RenderEllipsoid(x,y,z,ellipseProb,E,R4,atColor)                   
3618                else:
3619                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
3620                        pass
3621                    else:
3622                        radius = ellipseProb*math.sqrt(abs(atom[cs+4]))
3623                        RenderSphere(x,y,z,radius,atColor)
3624            elif 'lines' in atom[cs]:
3625                radius = 0.1
3626                RenderLines(x,y,z,Bonds,bndColor)
3627#                RenderBonds(x,y,z,Bonds,0.05,color,6)
3628            elif atom[cs] == 'sticks':
3629                radius = 0.1
3630                RenderBonds(x,y,z,Bonds,bondR,bndColor)
3631            elif atom[cs] == 'polyhedra':
3632                RenderPolyhedra(x,y,z,Faces,atColor)
3633            elif atom[cs] == 'backbone':
3634                if atom[ct-1].split()[0] in ['C','N']:
3635                    if atom[2] not in Backbones:
3636                        Backbones[atom[2]] = []
3637                    Backbones[atom[2]].append(list(np.inner(Amat,np.array([x,y,z]))))
3638                    BackboneColor.append(list(atColor))
3639                   
3640            if atom[cs+1] == 'type':
3641                RenderLabel(x,y,z,'  '+atom[ct],radius,wxGreen,matRot)
3642            elif atom[cs+1] == 'name':
3643                RenderLabel(x,y,z,'  '+atom[ct-1],radius,wxGreen,matRot)
3644            elif atom[cs+1] == 'number':
3645                RenderLabel(x,y,z,'  '+str(iat),radius,wxGreen,matRot)
3646            elif atom[cs+1] == 'residue' and atom[ct-1] == 'CA':
3647                RenderLabel(x,y,z,'  '+atom[ct-4],radius,wxGreen,matRot)
3648            elif atom[cs+1] == '1-letter' and atom[ct-1] == 'CA':
3649                RenderLabel(x,y,z,'  '+atom[ct-3],radius,wxGreen,matRot)
3650            elif atom[cs+1] == 'chain' and atom[ct-1] == 'CA':
3651                RenderLabel(x,y,z,'  '+atom[ct-2],radius,wxGreen,matRot)
3652#        glDisable(GL_BLEND)
3653        if len(rhoXYZ):
3654            RenderMap(rho,rhoXYZ,indx,Rok)
3655        if len(mapPeaks):
3656            XYZ = mapPeaks.T[1:4].T
3657            mapBonds = FindPeaksBonds(XYZ)
3658            for ind,[mag,x,y,z,d] in enumerate(mapPeaks):
3659                if ind in Ind and pageName == 'Map peaks':
3660                    RenderMapPeak(x,y,z,Gr,1.0)
3661                else:
3662                    RenderMapPeak(x,y,z,Wt,mag/peakMax)
3663                if showBonds:
3664                    RenderLines(x,y,z,mapBonds[ind],Wt)
3665        if len(testRBObj) and pageName == 'RB Models':
3666            XYZ = G2mth.UpdateRBXYZ(Bmat,testRBObj['rbObj'],testRBObj['rbData'],testRBObj['rbType'])[0]
3667            rbBonds = FindPeaksBonds(XYZ)
3668            for ind,[x,y,z] in enumerate(XYZ):
3669                aType = testRBObj['rbAtTypes'][ind]
3670                name = '  '+aType+str(ind)
3671                color = np.array(testRBObj['AtInfo'][aType][1])
3672                RenderSphere(x,y,z,0.2,color/255.)
3673                RenderBonds(x,y,z,rbBonds[ind],0.03,Gr)
3674                RenderLabel(x,y,z,name,0.2,wxOrange,matRot)
3675        if len(mcsaModels) > 1 and pageName == 'MC/SA':             #skip the default MD entry
3676            for ind,[x,y,z] in enumerate(mcsaXYZ):
3677                aType = mcsaTypes[ind]
3678                name = '  '+aType+str(ind)
3679                color = np.array(MCSA['AtInfo'][aType][1])
3680                RenderSphere(x,y,z,0.2,color/255.)
3681                RenderBonds(x,y,z,mcsaBonds[ind],0.03,Gr)
3682                RenderLabel(x,y,z,name,0.2,wxOrange,matRot)
3683        if Backbones:
3684            for chain in Backbones:
3685                Backbone = Backbones[chain]
3686                RenderBackbone(Backbone,BackboneColor,bondR)
3687#        print time.time()-time0
3688        Page.canvas.SwapBuffers()
3689       
3690    def OnSize(event):
3691        Draw('size')
3692       
3693    def OnFocus(event):         #not needed?? Bind commented out below
3694        Draw('focus')
3695       
3696    try:
3697        plotNum = G2frame.G2plotNB.plotList.index(generalData['Name'])
3698        Page = G2frame.G2plotNB.nb.GetPage(plotNum)       
3699    except ValueError:
3700        Plot = G2frame.G2plotNB.addOgl(generalData['Name'])
3701        plotNum = G2frame.G2plotNB.plotList.index(generalData['Name'])
3702        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3703        Page.views = False
3704        view = False
3705        altDown = False
3706    Font = Page.GetFont()
3707    Page.SetFocus()
3708    Page.Choice = None
3709    if mapData['Flip']:
3710        choice = [' save as/key:','jpeg','tiff','bmp','c: center on 1/2,1/2,1/2',
3711            'u: roll up','d: roll down','l: roll left','r: roll right']
3712    else:
3713        choice = [' save as/key:','jpeg','tiff','bmp','c: center on 1/2,1/2,1/2','n: next','p: previous']
3714    cb = wx.ComboBox(G2frame.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,choices=choice)
3715    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
3716    cb.SetValue(' save as/key:')
3717    Page.canvas.Bind(wx.EVT_MOUSEWHEEL, OnMouseWheel)
3718    Page.canvas.Bind(wx.EVT_LEFT_DOWN, OnMouseDown)
3719    Page.canvas.Bind(wx.EVT_RIGHT_DOWN, OnMouseDown)
3720    Page.canvas.Bind(wx.EVT_MIDDLE_DOWN, OnMouseDown)
3721    Page.canvas.Bind(wx.EVT_KEY_UP, OnKey)
3722    Page.canvas.Bind(wx.EVT_MOTION, OnMouseMove)
3723    Page.canvas.Bind(wx.EVT_SIZE, OnSize)
3724#    Page.canvas.Bind(wx.EVT_SET_FOCUS, OnFocus)
3725    Page.camera['position'] = drawingData['cameraPos']
3726    Page.camera['viewPoint'] = np.inner(Amat,drawingData['viewPoint'][0])
3727    Page.camera['backColor'] = np.array(list(drawingData['backColor'])+[0,])/255.
3728    try:
3729        Page.canvas.SetCurrent()
3730    except:
3731        pass
3732    Draw('main')
3733       
3734################################################################################
3735#### Plot Rigid Body
3736################################################################################
3737
3738def PlotRigidBody(G2frame,rbType,AtInfo,rbData,defaults):
3739    '''RB plotting package. Can show rigid body structures as balls & sticks
3740    '''
3741
3742    def FindBonds(XYZ):
3743        rbTypes = rbData['rbTypes']
3744        Radii = []
3745        for Atype in rbTypes:
3746            Radii.append(AtInfo[Atype][0])
3747            if Atype == 'H':
3748                Radii[-1] = 0.5
3749        Radii = np.array(Radii)
3750        Bonds = [[] for i in range(len(Radii))]
3751        for i,xyz in enumerate(XYZ):
3752            Dx = XYZ-xyz
3753            dist = np.sqrt(np.sum(Dx**2,axis=1))
3754            sumR = Radii[i]+Radii
3755            IndB = ma.nonzero(ma.masked_greater(dist-0.85*sumR,0.))
3756            for j in IndB[0]:
3757                Bonds[i].append(Dx[j]*Radii[i]/sumR[j])
3758                Bonds[j].append(-Dx[j]*Radii[j]/sumR[j])
3759        return Bonds
3760                       
3761    Wt = np.array([255,255,255])
3762    Rd = np.array([255,0,0])
3763    Gr = np.array([0,255,0])
3764    Bl = np.array([0,0,255])
3765    uBox = np.array([[0,0,0],[1,0,0],[0,1,0],[0,0,1]])
3766    uEdges = np.array([[uBox[0],uBox[1]],[uBox[0],uBox[2]],[uBox[0],uBox[3]]])
3767    uColors = [Rd,Gr,Bl]
3768    if rbType == 'Vector':
3769        atNames = [str(i)+':'+Ty for i,Ty in enumerate(rbData['rbTypes'])]
3770        XYZ = np.array([[0.,0.,0.] for Ty in rbData['rbTypes']])
3771        for imag,mag in enumerate(rbData['VectMag']):
3772            XYZ += mag*rbData['rbVect'][imag]
3773        Bonds = FindBonds(XYZ)
3774    elif rbType == 'Residue':
3775#        atNames = [str(i)+':'+Ty for i,Ty in enumerate(rbData['atNames'])]
3776        atNames = rbData['atNames']
3777        XYZ = np.copy(rbData['rbXYZ'])      #don't mess with original!
3778        Seq = rbData['rbSeq']
3779        for ia,ib,ang,mv in Seq:
3780            va = XYZ[ia]-XYZ[ib]
3781            Q = G2mth.AVdeg2Q(ang,va)
3782            for im in mv:
3783                vb = XYZ[im]-XYZ[ib]
3784                vb = G2mth.prodQVQ(Q,vb)
3785                XYZ[im] = XYZ[ib]+vb
3786        Bonds = FindBonds(XYZ)
3787    elif rbType == 'Z-matrix':
3788        pass
3789
3790#    def SetRBOrigin():
3791#        page = getSelection()
3792#        if page:
3793#            if G2frame.dataDisplay.GetPageText(page) == 'Rigid bodies':
3794#                G2frame.MapPeaksTable.SetData(mapPeaks)
3795#                panel = G2frame.dataDisplay.GetPage(page).GetChildren()
3796#                names = [child.GetName() for child in panel]
3797#                panel[names.index('grid window')].Refresh()
3798           
3799    def OnMouseDown(event):
3800        xy = event.GetPosition()
3801        defaults['oldxy'] = list(xy)
3802
3803    def OnMouseMove(event):
3804        newxy = event.GetPosition()
3805                               
3806        if event.Dragging():
3807            if event.LeftIsDown():
3808                SetRotation(newxy)
3809                Q = defaults['Quaternion']
3810                G2frame.G2plotNB.status.SetStatusText('New quaternion: %.2f+, %.2fi+ ,%.2fj+, %.2fk'%(Q[0],Q[1],Q[2],Q[3]),1)
3811#            elif event.RightIsDown():
3812#                SetRBOrigin(newxy)
3813            elif event.MiddleIsDown():
3814                SetRotationZ(newxy)
3815                Q = defaults['Quaternion']
3816                G2frame.G2plotNB.status.SetStatusText('New quaternion: %.2f+, %.2fi+ ,%.2fj+, %.2fk'%(Q[0],Q[1],Q[2],Q[3]),1)
3817            Draw('move')
3818       
3819    def OnMouseWheel(event):
3820        defaults['cameraPos'] += event.GetWheelRotation()/24
3821        defaults['cameraPos'] = max(10,min(500,defaults['cameraPos']))
3822        G2frame.G2plotNB.status.SetStatusText('New camera distance: %.2f'%(defaults['cameraPos']),1)
3823        Draw('wheel')
3824       
3825    def SetBackground():
3826        R,G,B,A = Page.camera['backColor']
3827        glClearColor(R,G,B,A)
3828        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
3829       
3830    def SetLights():
3831        glEnable(GL_DEPTH_TEST)
3832        glShadeModel(GL_FLAT)
3833        glEnable(GL_LIGHTING)
3834        glEnable(GL_LIGHT0)
3835        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0)
3836        glLightfv(GL_LIGHT0,GL_AMBIENT,[1,1,1,.8])
3837        glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
3838       
3839#    def SetRBOrigin(newxy):
3840##first get translation vector in screen coords.       
3841#        oldxy = defaults['oldxy']
3842#        if not len(oldxy): oldxy = list(newxy)
3843#        dxy = newxy-oldxy
3844#        defaults['oldxy'] = list(newxy)
3845#        V = np.array([dxy[0],-dxy[1],0.])/100.
3846#        Q = defaults['Quaternion']
3847#        V = G2mth.prodQVQ(G2mth.invQ(Q),V)
3848#        rbData['rbXYZ'] += V
3849#        PlotRigidBody(G2frame,rbType,AtInfo,rbData,defaults)
3850#               
3851    def SetRotation(newxy):
3852#first get rotation vector in screen coords. & angle increment       
3853        oldxy = defaults['oldxy']
3854        if not len(oldxy): oldxy = list(newxy)
3855        dxy = newxy-oldxy
3856        defaults['oldxy'] = list(newxy)
3857        V = np.array([dxy[1],dxy[0],0.])
3858        A = 0.25*np.sqrt(dxy[0]**2+dxy[1]**2)
3859# next transform vector back to xtal coordinates via inverse quaternion
3860# & make new quaternion
3861        Q = defaults['Quaternion']
3862        V = G2mth.prodQVQ(G2mth.invQ(Q),V)
3863        DQ = G2mth.AVdeg2Q(A,V)
3864        Q = G2mth.prodQQ(Q,DQ)
3865        defaults['Quaternion'] = Q
3866# finally get new view vector - last row of rotation matrix
3867        VD = G2mth.Q2Mat(Q)[2]
3868        VD /= np.sqrt(np.sum(VD**2))
3869        defaults['viewDir'] = VD
3870       
3871    def SetRotationZ(newxy):                       
3872#first get rotation vector (= view vector) in screen coords. & angle increment       
3873        View = glGetIntegerv(GL_VIEWPORT)
3874        cent = [View[2]/2,View[3]/2]
3875        oldxy = defaults['oldxy']
3876        if not len(oldxy): oldxy = list(newxy)
3877        dxy = newxy-oldxy
3878        defaults['oldxy'] = list(newxy)
3879        V = defaults['viewDir']
3880        A = [0,0]
3881        A[0] = dxy[1]*.25
3882        A[1] = dxy[0]*.25
3883        if newxy[0] > cent[0]:
3884            A[0] *= -1
3885        if newxy[1] < cent[1]:
3886            A[1] *= -1       
3887# next transform vector back to xtal coordinates & make new quaternion
3888        Q = defaults['Quaternion']
3889        Qx = G2mth.AVdeg2Q(A[0],V)
3890        Qy = G2mth.AVdeg2Q(A[1],V)
3891        Q = G2mth.prodQQ(Q,Qx)
3892        Q = G2mth.prodQQ(Q,Qy)
3893        defaults['Quaternion'] = Q
3894
3895    def RenderUnitVectors(x,y,z):
3896        xyz = np.array([x,y,z])
3897        glEnable(GL_COLOR_MATERIAL)
3898        glLineWidth(1)
3899        glPushMatrix()
3900        glTranslate(x,y,z)
3901        glBegin(GL_LINES)
3902        for line,color in zip(uEdges,uColors):
3903            glColor3ubv(color)
3904            glVertex3fv(-line[1])
3905            glVertex3fv(line[1])
3906        glEnd()
3907        glPopMatrix()
3908        glColor4ubv([0,0,0,0])
3909        glDisable(GL_COLOR_MATERIAL)
3910               
3911    def RenderSphere(x,y,z,radius,color):
3912        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
3913        glPushMatrix()
3914        glTranslate(x,y,z)
3915        q = gluNewQuadric()
3916        gluSphere(q,radius,20,10)
3917        glPopMatrix()
3918       
3919    def RenderBonds(x,y,z,Bonds,radius,color,slice=20):
3920        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
3921        glPushMatrix()
3922        glTranslate(x,y,z)
3923        for Dx in Bonds:
3924            glPushMatrix()
3925            Z = np.sqrt(np.sum(Dx**2))
3926            if Z:
3927                azm = atan2d(-Dx[1],-Dx[0])
3928                phi = acosd(Dx[2]/Z)
3929                glRotate(-azm,0,0,1)
3930                glRotate(phi,1,0,0)
3931                q = gluNewQuadric()
3932                gluCylinder(q,radius,radius,Z,slice,2)
3933            glPopMatrix()           
3934        glPopMatrix()
3935               
3936    def RenderLabel(x,y,z,label,matRot):       
3937        glPushMatrix()
3938        glTranslate(x,y,z)
3939        glDisable(GL_LIGHTING)
3940        glRasterPos3f(0,0,0)
3941        glMultMatrixf(matRot)
3942        glRotate(180,1,0,0)             #fix to flip about x-axis
3943        text = gltext.TextElement(text=label,font=Font,foreground=wx.WHITE)
3944        text.draw_text(scale=0.025)
3945        glEnable(GL_LIGHTING)
3946        glPopMatrix()
3947       
3948    def Draw(caller=''):
3949#useful debug?       
3950#        if caller:
3951#            print caller
3952# end of useful debug
3953        cPos = defaults['cameraPos']
3954        VS = np.array(Page.canvas.GetSize())
3955        aspect = float(VS[0])/float(VS[1])
3956        Zclip = 500.0
3957        Q = defaults['Quaternion']
3958        SetBackground()
3959        glInitNames()
3960        glPushName(0)
3961       
3962        glMatrixMode(GL_PROJECTION)
3963        glLoadIdentity()
3964        glViewport(0,0,VS[0],VS[1])
3965        gluPerspective(20.,aspect,1.,500.)
3966        gluLookAt(0,0,cPos,0,0,0,0,1,0)
3967        SetLights()           
3968           
3969        glMatrixMode(GL_MODELVIEW)
3970        glLoadIdentity()
3971        matRot = G2mth.Q2Mat(Q)
3972        matRot = np.concatenate((np.concatenate((matRot,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
3973        glMultMatrixf(matRot.T)
3974        RenderUnitVectors(0.,0.,0.)
3975        radius = 0.2
3976        for iat,atom in enumerate(XYZ):
3977            x,y,z = atom
3978            CL = AtInfo[rbData['rbTypes'][iat]][1]
3979            color = np.array(CL)/255.
3980            RenderSphere(x,y,z,radius,color)
3981            RenderBonds(x,y,z,Bonds[iat],0.05,color)
3982            RenderLabel(x,y,z,'  '+atNames[iat],matRot)
3983        Page.canvas.SwapBuffers()
3984
3985    def OnSize(event):
3986        Draw('size')
3987       
3988    try:
3989        plotNum = G2frame.G2plotNB.plotList.index('Rigid body')
3990        Page = G2frame.G2plotNB.nb.GetPage(plotNum)       
3991    except ValueError:
3992        Plot = G2frame.G2plotNB.addOgl('Rigid body')
3993        plotNum = G2frame.G2plotNB.plotList.index('Rigid body')
3994        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3995        Page.views = False
3996        view = False
3997        altDown = False
3998    Page.SetFocus()
3999    Font = Page.GetFont()
4000    Page.canvas.Bind(wx.EVT_MOUSEWHEEL, OnMouseWheel)
4001    Page.canvas.Bind(wx.EVT_LEFT_DOWN, OnMouseDown)
4002    Page.canvas.Bind(wx.EVT_RIGHT_DOWN, OnMouseDown)
4003    Page.canvas.Bind(wx.EVT_MIDDLE_DOWN, OnMouseDown)
4004    Page.canvas.Bind(wx.EVT_MOTION, OnMouseMove)
4005    Page.canvas.Bind(wx.EVT_SIZE, OnSize)
4006    Page.camera['position'] = defaults['cameraPos']
4007    Page.camera['backColor'] = np.array([0,0,0,0])
4008    Page.canvas.SetCurrent()
4009    Draw('main')
Note: See TracBrowser for help on using the repository browser.