source: trunk/GSASIIplot.py @ 1005

Last change on this file since 1005 was 1005, checked in by vondreele, 10 years ago

removed try/except for set focus items
fixed 'N' & 'P' key behavior for structure plots

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