source: trunk/GSASIIplot.py @ 1319

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

fix status line stuff in G2plot

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