source: trunk/GSASIIplot.py @ 1339

Last change on this file since 1339 was 1339, checked in by vondreele, 11 years ago

make single pattern plot the default
begin slit smearing implementation - doesn't work just yet
some tweaking of pattern plotting

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