source: trunk/GSASIIplot.py @ 1237

Last change on this file since 1237 was 1237, checked in by vondreele, 9 years ago

Allow changes to limits when in SASD Models
"fix" matplotlib warning message when log plot is hit with a mouse button event
There is still an underlying problem.
Mods to SASD Model to have scaled errors on data for fitting purposes - uses wtFactor
Start on size distribution fitting

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