source: trunk/GSASIIplot.py @ 1343

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

allow moving the difference curve

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