source: trunk/GSASIIplot.py @ 1652

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

add .gsa to default GSAS powder file extensions
floors (0.0001) for alp & bet before calculating profile
remove a stray print from G2plot

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