source: trunk/GSASIIplot.py @ 1882

Last change on this file since 1882 was 1882, checked in by vondreele, 7 years ago

fix bug in G2plot that only shows up in Anaconda pythons

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