source: trunk/GSASIIplot.py @ 1966

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

new 3D HKL plot commands for selecting view axes & set a zone plot - trouble with rotations tho.
SS structure factor by integration, not Bessel fxns.

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