source: trunk/GSASIIplot.py @ 1344

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

print "chisq" after image calibration/recalibration
fixes to profile plots

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