source: trunk/GSASIIplot.py @ 1297

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

setup sequential small angle refinements & display
includes copy & copy flags over Models
stop pattern plots in multiple integrations; now only when done

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