source: trunk/GSASIIplot.py @ 2065

Last change on this file since 2065 was 2065, checked in by toby, 8 years ago

Allow reading of multiple images from single file

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