source: trunk/GSASIIplot.py @ 1780

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

force collapse of all children when main tree item is collapsed
begin texture fitting from seq. refinements
fix bugs in plotting if all SH coeff = 0
set background on Fcsq when delt = 3sig & 10 sig

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