source: trunk/GSASIIplot.py @ 1451

Last change on this file since 1451 was 1451, checked in by toby, 7 years ago

Cleanup Instrument Parms bug due to reformat of peak list

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