source: trunk/GSASIIplot.py @ 2120

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

Add plotting of 2D modulation vector result (a0g) for monoclinic.
Trap excessive approximations in TOF2dsp
Add a general purpose contour plot
restrict maxH = 1 for modulation search; higher maxH not effective

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 242.6 KB
Line 
1# -*- coding: utf-8 -*-
2'''
3*GSASIIplot: plotting routines*
4===============================
5
6'''
7########### SVN repository information ###################
8# $Date: 2016-01-11 20:12:00 +0000 (Mon, 11 Jan 2016) $
9# $Author: vondreele $
10# $Revision: 2120 $
11# $URL: trunk/GSASIIplot.py $
12# $Id: GSASIIplot.py 2120 2016-01-11 20:12:00Z vondreele $
13########### SVN repository information ###################
14import math
15import time
16import copy
17import sys
18import os.path
19import numpy as np
20import numpy.ma as ma
21import numpy.linalg as nl
22import wx
23import wx.aui
24import wx.glcanvas
25import matplotlib as mpl
26import mpl_toolkits.mplot3d.axes3d as mp3d
27import GSASIIpath
28GSASIIpath.SetVersionNumber("$Revision: 2120 $")
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)[1][:-1]
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        # this restores previous plot limits (but I'm not sure why there are two .push_current calls)
1930        Page.toolbar.push_current()
1931        if G2frame.Contour: # for contour plots expand y-axis to include all histograms
1932            G2frame.xylim = (G2frame.xylim[0], (0.,len(PlotList)-1.))
1933        Plot.set_xlim(G2frame.xylim[0])
1934        Plot.set_ylim(G2frame.xylim[1])
1935#        xylim = []
1936        Page.toolbar.push_current()
1937        Page.toolbar.draw()
1938    else:
1939        G2frame.xylim = Plot.get_xlim(),Plot.get_ylim()
1940        Page.canvas.draw()
1941    olderr = np.seterr(invalid='ignore') #ugh - this removes a matplotlib error for mouse clicks in log plots
1942    # and sqrt(-ve) in np.where usage               
1943#    G2frame.Pwdr = True
1944   
1945################################################################################
1946##### PlotDeltSig
1947################################################################################
1948           
1949def PlotDeltSig(G2frame,kind):
1950    'needs a doc string'
1951    try:
1952        plotNum = G2frame.G2plotNB.plotList.index('Error analysis')
1953        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1954        Page.figure.clf()
1955        Plot = Page.figure.gca()          #get a fresh plot after clf()
1956    except ValueError:
1957        newPlot = True
1958        G2frame.Cmax = 1.0
1959        Plot = G2frame.G2plotNB.addMpl('Error analysis').gca()
1960        plotNum = G2frame.G2plotNB.plotList.index('Error analysis')
1961        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
1962    Page.Choice = None
1963    PatternId = G2frame.PatternId
1964    Pattern = G2frame.PatternTree.GetItemPyData(PatternId)
1965    Pattern.append(G2frame.PatternTree.GetItemText(PatternId))
1966    wtFactor = Pattern[0]['wtFactor']
1967    if kind == 'PWDR':
1968        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
1969        xye = np.array(Pattern[1])
1970        xmin = np.searchsorted(xye[0],limits[0])
1971        xmax = np.searchsorted(xye[0],limits[1])
1972        DS = xye[5][xmin:xmax]*np.sqrt(wtFactor*xye[2][xmin:xmax])
1973    elif kind == 'HKLF':
1974        refl = Pattern[1]['RefList']
1975        im = 0
1976        if Pattern[1]['Super']:
1977            im = 1
1978        DS = []
1979        for ref in refl:
1980            if ref[6+im] > 0.:
1981                DS.append((ref[5+im]-ref[7+im])/ref[6+im])
1982    Page.SetFocus()
1983    G2frame.G2plotNB.status.DestroyChildren()
1984    DS.sort()
1985    EDS = np.zeros_like(DS)
1986    DX = np.linspace(0.,1.,num=len(DS),endpoint=True)
1987    oldErr = np.seterr(invalid='ignore')    #avoid problem at DX==0
1988    T = np.sqrt(np.log(1.0/DX**2))
1989    top = 2.515517+0.802853*T+0.010328*T**2
1990    bot = 1.0+1.432788*T+0.189269*T**2+0.001308*T**3
1991    EDS = np.where(DX>0,-(T-top/bot),(T-top/bot))
1992    low1 = np.searchsorted(EDS,-1.)
1993    hi1 = np.searchsorted(EDS,1.)
1994    slp,intcp = np.polyfit(EDS[low1:hi1],DS[low1:hi1],deg=1)
1995    frac = 100.*(hi1-low1)/len(DS)
1996    G2frame.G2plotNB.status.SetStatusText(  \
1997        'Over range -1. to 1. :'+' slope = %.3f, intercept = %.3f for %.2f%% of the fitted data'%(slp,intcp,frac),1)
1998    Plot.set_title('Normal probability for '+Pattern[-1])
1999    Plot.set_xlabel(r'expected $\mathsf{\Delta/\sigma}$',fontsize=14)
2000    Plot.set_ylabel(r'observed $\mathsf{\Delta/\sigma}$',fontsize=14)
2001    Plot.plot(EDS,DS,'r+',label='result')
2002    Plot.plot([-2,2],[-2,2],'k',dashes=(5,5),label='ideal')
2003    Plot.legend(loc='upper left')
2004    np.seterr(invalid='warn')
2005    Page.canvas.draw()
2006       
2007################################################################################
2008##### PlotISFG
2009################################################################################
2010           
2011def PlotISFG(G2frame,newPlot=False,type=''):
2012    ''' Plotting package for PDF analysis; displays I(q), S(q), F(q) and G(r) as single
2013    or multiple plots with waterfall and contour plots as options
2014    '''
2015    if not type:
2016        type = G2frame.G2plotNB.plotList[G2frame.G2plotNB.nb.GetSelection()]
2017    if type not in ['I(Q)','S(Q)','F(Q)','G(R)']:
2018        return
2019    superMinusOne = unichr(0xaf)+unichr(0xb9)
2020   
2021    def OnPlotKeyPress(event):
2022        newPlot = False
2023        if event.key == 'u':
2024            if G2frame.Contour:
2025                G2frame.Cmax = min(1.0,G2frame.Cmax*1.2)
2026            elif Pattern[0]['Offset'][0] < 100.:
2027                Pattern[0]['Offset'][0] += 1.
2028        elif event.key == 'd':
2029            if G2frame.Contour:
2030                G2frame.Cmax = max(0.0,G2frame.Cmax*0.8)
2031            elif Pattern[0]['Offset'][0] > 0.:
2032                Pattern[0]['Offset'][0] -= 1.
2033        elif event.key == 'l':
2034            Pattern[0]['Offset'][1] -= 1.
2035        elif event.key == 'r':
2036            Pattern[0]['Offset'][1] += 1.
2037        elif event.key == 'o':
2038            Pattern[0]['Offset'] = [0,0]
2039        elif event.key == 'c':
2040            newPlot = True
2041            G2frame.Contour = not G2frame.Contour
2042            if not G2frame.Contour:
2043                G2frame.SinglePlot = False
2044                Pattern[0]['Offset'] = [0.,0.]
2045        elif event.key == 's':
2046            if G2frame.Contour:
2047                choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
2048                choice.sort()
2049                dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
2050                if dlg.ShowModal() == wx.ID_OK:
2051                    sel = dlg.GetSelection()
2052                    G2frame.ContourColor = choice[sel]
2053                else:
2054                    G2frame.ContourColor = 'Paired'
2055                dlg.Destroy()
2056            else:
2057                G2frame.SinglePlot = not G2frame.SinglePlot               
2058        elif event.key == 'i':                  #for smoothing contour plot
2059            choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
2060               'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
2061               'mitchell','sinc','lanczos']
2062            dlg = wx.SingleChoiceDialog(G2frame,'Select','Interpolation',choice)
2063            if dlg.ShowModal() == wx.ID_OK:
2064                sel = dlg.GetSelection()
2065                G2frame.Interpolate = choice[sel]
2066            else:
2067                G2frame.Interpolate = 'nearest'
2068            dlg.Destroy()
2069        elif event.key == 't' and not G2frame.Contour:
2070            G2frame.Legend = not G2frame.Legend
2071        PlotISFG(G2frame,newPlot=newPlot,type=type)
2072       
2073    def OnKeyBox(event):
2074        if G2frame.G2plotNB.nb.GetSelection() == G2frame.G2plotNB.plotList.index(type):
2075            event.key = cb.GetValue()[0]
2076            cb.SetValue(' key press')
2077            wx.CallAfter(OnPlotKeyPress,event)
2078        Page.canvas.SetFocus() # redirect the Focus from the button back to the plot
2079                       
2080    def OnMotion(event):
2081        xpos = event.xdata
2082        if xpos:                                        #avoid out of frame mouse position
2083            ypos = event.ydata
2084            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2085            try:
2086                if G2frame.Contour:
2087                    G2frame.G2plotNB.status.SetStatusText('R =%.3fA pattern ID =%5d'%(xpos,int(ypos)),1)
2088                else:
2089                    G2frame.G2plotNB.status.SetStatusText('R =%.3fA %s =%.2f'%(xpos,type,ypos),1)                   
2090            except TypeError:
2091                G2frame.G2plotNB.status.SetStatusText('Select '+type+' pattern first',1)
2092   
2093    xylim = []
2094    try:
2095        plotNum = G2frame.G2plotNB.plotList.index(type)
2096        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2097        if not newPlot:
2098            Plot = Page.figure.gca()          #get previous plot & get limits
2099            xylim = Plot.get_xlim(),Plot.get_ylim()
2100        Page.figure.clf()
2101        Plot = Page.figure.gca()
2102    except ValueError:
2103        newPlot = True
2104        G2frame.Cmax = 1.0
2105        Plot = G2frame.G2plotNB.addMpl(type).gca()
2106        plotNum = G2frame.G2plotNB.plotList.index(type)
2107        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2108        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
2109        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2110   
2111    Page.SetFocus()
2112    G2frame.G2plotNB.status.DestroyChildren()
2113    if G2frame.Contour:
2114        Page.Choice = (' key press','d: lower contour max','u: raise contour max',
2115            'i: interpolation method','s: color scheme','c: contour off')
2116    else:
2117        Page.Choice = (' key press','l: offset left','r: offset right','d: offset down','u: offset up',
2118            'o: reset offset','t: toggle legend','c: contour on','s: toggle single plot')
2119    Page.keyPress = OnPlotKeyPress
2120    PatternId = G2frame.PatternId
2121    PickId = G2frame.PickId
2122    Plot.set_title(type)
2123    if type == 'G(R)':
2124        Plot.set_xlabel(r'$R,\AA$',fontsize=14)
2125    else:
2126        Plot.set_xlabel(r'$Q,\AA$'+superMinusOne,fontsize=14)
2127    Plot.set_ylabel(r''+type,fontsize=14)
2128    colors=['b','g','r','c','m','k']
2129    name = G2frame.PatternTree.GetItemText(PatternId)[4:]
2130    Pattern = []   
2131    if G2frame.SinglePlot:
2132        name = G2frame.PatternTree.GetItemText(PatternId)
2133        name = type+name[4:]
2134        Id = G2gd.GetPatternTreeItemId(G2frame,PatternId,name)
2135        Pattern = G2frame.PatternTree.GetItemPyData(Id)
2136        if Pattern:
2137            Pattern.append(name)
2138        PlotList = [Pattern,]
2139    else:
2140        PlotList = []
2141        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2142        while item:
2143            if 'PDF' in G2frame.PatternTree.GetItemText(item):
2144                name = type+G2frame.PatternTree.GetItemText(item)[4:]
2145                Id = G2gd.GetPatternTreeItemId(G2frame,item,name)
2146                Pattern = G2frame.PatternTree.GetItemPyData(Id)
2147                if Pattern:
2148                    Pattern.append(name)
2149                    PlotList.append(Pattern)
2150            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2151    PDFdata = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'PDF Controls'))
2152    numbDen = G2pwd.GetNumDensity(PDFdata['ElList'],PDFdata['Form Vol'])
2153    Xb = [0.,10.]
2154    Yb = [0.,-40.*np.pi*numbDen]
2155    Ymax = 0.01
2156    lenX = 0
2157    for Pattern in PlotList:
2158        try:
2159            xye = Pattern[1]
2160        except IndexError:
2161            return
2162        Ymax = max(Ymax,max(xye[1]))
2163    offset = Pattern[0]['Offset'][0]*Ymax/100.0
2164    if G2frame.Contour:
2165        ContourZ = []
2166        ContourY = []
2167        Nseq = 0
2168    for N,Pattern in enumerate(PlotList):
2169        xye = Pattern[1]
2170        if PickId:
2171            ifpicked = Pattern[2] == G2frame.PatternTree.GetItemText(PatternId)
2172        X = xye[0]
2173        if not lenX:
2174            lenX = len(X)           
2175        Y = xye[1]+offset*N
2176        if G2frame.Contour:
2177            if lenX == len(X):
2178                ContourY.append(N)
2179                ContourZ.append(Y)
2180                ContourX = X
2181                Nseq += 1
2182                Plot.set_ylabel('Data sequence',fontsize=12)
2183        else:
2184            X = xye[0]+Pattern[0]['Offset'][1]*.005*N
2185            if ifpicked:
2186                Plot.plot(X,Y,colors[N%6]+'+',picker=3.,clip_on=False)
2187                Page.canvas.SetToolTipString('')
2188            else:
2189                if G2frame.Legend:
2190                    Plot.plot(X,Y,colors[N%6],picker=False,label='Azm:'+Pattern[2].split('=')[1])
2191                else:
2192                    Plot.plot(X,Y,colors[N%6],picker=False)
2193            if type == 'G(R)':
2194                Plot.plot(Xb,Yb,color='k',dashes=(5,5))
2195            elif type == 'F(Q)':
2196                Plot.axhline(0.,color=wx.BLACK)
2197            elif type == 'S(Q)':
2198                Plot.axhline(1.,color=wx.BLACK)
2199    if G2frame.Contour:
2200        acolor = mpl.cm.get_cmap(G2frame.ContourColor)
2201        Img = Plot.imshow(ContourZ,cmap=acolor,vmin=0,vmax=Ymax*G2frame.Cmax,interpolation=G2frame.Interpolate, 
2202            extent=[ContourX[0],ContourX[-1],ContourY[0],ContourY[-1]],aspect='auto',origin='lower')
2203        Page.figure.colorbar(Img)
2204    elif G2frame.Legend:
2205        Plot.legend(loc='best')
2206    if not newPlot:
2207        Page.toolbar.push_current()
2208        Plot.set_xlim(xylim[0])
2209        Plot.set_ylim(xylim[1])
2210        xylim = []
2211        Page.toolbar.push_current()
2212        Page.toolbar.draw()
2213    else:
2214        Page.canvas.draw()
2215       
2216################################################################################
2217##### PlotCalib
2218################################################################################
2219           
2220def PlotCalib(G2frame,Inst,XY,Sigs,newPlot=False):
2221    '''plot of CW or TOF peak calibration
2222    '''
2223    def OnMotion(event):
2224        xpos = event.xdata
2225        if xpos:                                        #avoid out of frame mouse position
2226            ypos = event.ydata
2227            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2228            try:
2229                G2frame.G2plotNB.status.SetStatusText('X =%9.3f %s =%9.3g'%(xpos,Title,ypos),1)                   
2230            except TypeError:
2231                G2frame.G2plotNB.status.SetStatusText('Select '+Title+' pattern first',1)
2232            found = []
2233            wid = 1
2234            view = Page.toolbar._views.forward()
2235            if view:
2236                view = view[0][:2]
2237                wid = view[1]-view[0]
2238            found = XY[np.where(np.fabs(XY.T[0]-xpos) < 0.005*wid)]
2239            if len(found):
2240                pos = found[0][1]
2241                if 'C' in Inst['Type'][0]: 
2242                    Page.canvas.SetToolTipString('position=%.4f'%(pos))
2243                else:
2244                    Page.canvas.SetToolTipString('position=%.2f'%(pos))
2245            else:
2246                Page.canvas.SetToolTipString('')
2247
2248    Title = 'Position calibration'
2249    try:
2250        plotNum = G2frame.G2plotNB.plotList.index(Title)
2251        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2252        if not newPlot:
2253            Plot = Page.figure.gca()
2254            xylim = Plot.get_xlim(),Plot.get_ylim()
2255        Page.figure.clf()
2256        Plot = Page.figure.gca()
2257    except ValueError:
2258        newPlot = True
2259        Plot = G2frame.G2plotNB.addMpl(Title).gca()
2260        plotNum = G2frame.G2plotNB.plotList.index(Title)
2261        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2262        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2263   
2264    Page.Choice = None
2265    Page.SetFocus()
2266    G2frame.G2plotNB.status.DestroyChildren()
2267    Plot.set_title(Title)
2268    Plot.set_xlabel(r'd-spacing',fontsize=14)
2269    if 'C' in Inst['Type'][0]:
2270        Plot.set_ylabel(r'$\mathsf{\Delta(2\theta)}$',fontsize=14)
2271    else:
2272        Plot.set_ylabel(r'$\mathsf{\Delta}T/T$',fontsize=14)
2273    for ixy,xyw in enumerate(XY):
2274        if len(xyw) > 2:
2275            X,Y,W = xyw
2276        else:
2277            X,Y = xyw
2278            W = 0.
2279        Yc = G2lat.Dsp2pos(Inst,X)
2280        if 'C' in Inst['Type'][0]:
2281            Y = Y-Yc
2282            E = Sigs[ixy]
2283            bin = W/2.
2284        else:
2285            Y = (Y-Yc)/Yc
2286            E = Sigs[ixy]/Yc
2287            bin = W/(2.*Yc)
2288        if E:
2289            Plot.errorbar(X,Y,ecolor='k',yerr=E)
2290        if ixy:
2291            Plot.plot(X,Y,'kx',picker=3)
2292        else:
2293            Plot.plot(X,Y,'kx',label='peak')
2294        if W:
2295            if ixy:
2296                Plot.plot(X,bin,'b+')
2297            else:
2298                Plot.plot(X,bin,'b+',label='bin width')
2299            Plot.plot(X,-bin,'b+')
2300        Plot.axhline(0.,color='r',linestyle='--')
2301    Plot.legend(loc='best')
2302    if not newPlot:
2303        Page.toolbar.push_current()
2304        Plot.set_xlim(xylim[0])
2305        Plot.set_ylim(xylim[1])
2306#        xylim = []
2307        Page.toolbar.push_current()
2308        Page.toolbar.draw()
2309    else:
2310        Page.canvas.draw()
2311
2312################################################################################
2313##### PlotXY
2314################################################################################
2315           
2316def PlotXY(G2frame,XY,XY2=None,labelX=None,labelY=None,newPlot=False,Title=''):
2317    '''simple plot of xy data, used for diagnostic purposes
2318    '''
2319    def OnMotion(event):
2320        xpos = event.xdata
2321        if xpos:                                        #avoid out of frame mouse position
2322            ypos = event.ydata
2323            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2324            try:
2325                G2frame.G2plotNB.status.SetStatusText('X =%9.3f %s =%9.3f'%(xpos,Title,ypos),1)                   
2326            except TypeError:
2327                G2frame.G2plotNB.status.SetStatusText('Select '+Title+' pattern first',1)
2328
2329    try:
2330        plotNum = G2frame.G2plotNB.plotList.index(Title)
2331        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2332        if not newPlot:
2333            Plot = Page.figure.gca()
2334            xylim = Plot.get_xlim(),Plot.get_ylim()
2335        Page.figure.clf()
2336        Plot = Page.figure.gca()
2337    except ValueError:
2338        newPlot = True
2339        Plot = G2frame.G2plotNB.addMpl(Title).gca()
2340        plotNum = G2frame.G2plotNB.plotList.index(Title)
2341        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2342        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2343   
2344    Page.Choice = None
2345    Page.SetFocus()
2346    G2frame.G2plotNB.status.DestroyChildren()
2347    Plot.set_title(Title)
2348    if labelX:
2349        Plot.set_xlabel(r''+labelX,fontsize=14)
2350    else:
2351        Plot.set_xlabel(r'X',fontsize=14)
2352    if labelY:
2353        Plot.set_ylabel(r''+labelY,fontsize=14)
2354    else:
2355        Plot.set_ylabel(r'Y',fontsize=14)
2356    colors=['b','g','r','c','m','k']
2357    for ixy,xy in enumerate(XY):
2358        X,Y = xy
2359        Plot.plot(X,Y,colors[ixy%6]+'+',picker=False)
2360    if len(XY2):
2361        for ixy,xy in enumerate(XY2):
2362            X,Y = xy
2363            Plot.plot(X,Y,colors[ixy%6],picker=False)
2364    if not newPlot:
2365        Page.toolbar.push_current()
2366        Plot.set_xlim(xylim[0])
2367        Plot.set_ylim(xylim[1])
2368        xylim = []
2369        Page.toolbar.push_current()
2370        Page.toolbar.draw()
2371    else:
2372        Page.canvas.draw()
2373       
2374def PlotXYZ(G2frame,XY,Z,labelX=None,labelY=None,newPlot=False,Title=''):
2375    '''simple contour plot of xyz data, used for diagnostic purposes
2376    '''
2377    def OnMotion(event):
2378        xpos = event.xdata
2379        if xpos:                                        #avoid out of frame mouse position
2380            ypos = event.ydata
2381            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2382            ix = int(Nxy[0]*(xpos-Xmin)+0.5)
2383            iy = int(Nxy[1]*(ypos-Ymin)+0.5)
2384            try:
2385                G2frame.G2plotNB.status.SetStatusText('%s =%9.3f %s =%9.3f val =%9.3f'% \
2386                    (labelX,xpos,labelY,ypos,Z[ix,iy]),1)                   
2387            except TypeError:
2388                G2frame.G2plotNB.status.SetStatusText('Select '+Title+' pattern first',1)
2389
2390    try:
2391        plotNum = G2frame.G2plotNB.plotList.index(Title)
2392        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2393        if not newPlot:
2394            Plot = Page.figure.gca()
2395            xylim = Plot.get_xlim(),Plot.get_ylim()
2396        Page.figure.clf()
2397        Plot = Page.figure.gca()
2398    except ValueError:
2399        newPlot = True
2400        Plot = G2frame.G2plotNB.addMpl(Title).gca()
2401        plotNum = G2frame.G2plotNB.plotList.index(Title)
2402        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2403        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2404   
2405    Page.Choice = None
2406    Page.SetFocus()
2407    G2frame.G2plotNB.status.DestroyChildren()
2408    Nxy = Z.shape
2409    Xmin = np.min(XY[0])
2410    Xmax = np.max(XY[0])
2411    Ymin = np.min(XY.T[0])
2412    Ymax = np.max(XY.T[0])
2413    Plot.set_title(Title)
2414    if labelX:
2415        Plot.set_xlabel(r''+labelX,fontsize=14)
2416    else:
2417        Plot.set_xlabel(r'X',fontsize=14)
2418    if labelY:
2419        Plot.set_ylabel(r''+labelY,fontsize=14)
2420    else:
2421        Plot.set_ylabel(r'Y',fontsize=14)
2422    Img = Plot.imshow(Z.T,cmap='Paired',interpolation='nearest',origin='lower', \
2423        aspect='auto',extent=[Xmin,Xmax,Ymin,Ymax])
2424    Page.figure.colorbar(Img)
2425    if not newPlot:
2426        Page.toolbar.push_current()
2427        Plot.set_xlim(xylim[0])
2428        Plot.set_ylim(xylim[1])
2429        xylim = []
2430        Page.toolbar.push_current()
2431        Page.toolbar.draw()
2432    else:
2433        Page.canvas.draw()
2434
2435################################################################################
2436##### PlotStrain
2437################################################################################
2438           
2439def PlotStrain(G2frame,data,newPlot=False):
2440    '''plot of strain data, used for diagnostic purposes
2441    '''
2442    def OnMotion(event):
2443        xpos = event.xdata
2444        if xpos:                                        #avoid out of frame mouse position
2445            ypos = event.ydata
2446            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2447            try:
2448                G2frame.G2plotNB.status.SetStatusText('d-spacing =%9.5f Azimuth =%9.3f'%(ypos,xpos),1)                   
2449            except TypeError:
2450                G2frame.G2plotNB.status.SetStatusText('Select Strain pattern first',1)
2451
2452    try:
2453        plotNum = G2frame.G2plotNB.plotList.index('Strain')
2454        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2455        if not newPlot:
2456            Plot = Page.figure.gca()
2457            xylim = Plot.get_xlim(),Plot.get_ylim()
2458        Page.figure.clf()
2459        Plot = Page.figure.gca()
2460    except ValueError:
2461        newPlot = True
2462        Plot = G2frame.G2plotNB.addMpl('Strain').gca()
2463        plotNum = G2frame.G2plotNB.plotList.index('Strain')
2464        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2465        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2466   
2467    Page.Choice = None
2468    Page.SetFocus()
2469    G2frame.G2plotNB.status.DestroyChildren()
2470    Plot.set_title('Strain')
2471    Plot.set_ylabel(r'd-spacing',fontsize=14)
2472    Plot.set_xlabel(r'Azimuth',fontsize=14)
2473    colors=['b','g','r','c','m','k']
2474    for N,item in enumerate(data['d-zero']):
2475        Y,X = np.array(item['ImtaObs'])         #plot azimuth as X & d-spacing as Y
2476        Plot.plot(X,Y,colors[N%6]+'+',picker=False)
2477        Y,X = np.array(item['ImtaCalc'])
2478        Plot.plot(X,Y,colors[N%6],picker=False)
2479    if not newPlot:
2480        Page.toolbar.push_current()
2481        Plot.set_xlim(xylim[0])
2482        Plot.set_ylim(xylim[1])
2483        xylim = []
2484        Page.toolbar.push_current()
2485        Page.toolbar.draw()
2486    else:
2487        Page.canvas.draw()
2488       
2489################################################################################
2490##### PlotSASDSizeDist
2491################################################################################
2492           
2493def PlotSASDSizeDist(G2frame):
2494   
2495    def OnPageChanged(event):
2496        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
2497        if 'Powder' in PlotText:
2498            PlotPatterns(G2frame,plotType='SASD',newPlot=True)
2499        elif 'Size' in PlotText:
2500            PlotSASDSizeDist(G2frame)
2501   
2502    def OnMotion(event):
2503        xpos = event.xdata
2504        if xpos:                                        #avoid out of frame mouse position
2505            ypos = event.ydata
2506            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2507            try:
2508                G2frame.G2plotNB.status.SetStatusText('diameter =%9.3f f(D) =%9.3g'%(xpos,ypos),1)                   
2509            except TypeError:
2510                G2frame.G2plotNB.status.SetStatusText('Select Strain pattern first',1)
2511
2512    try:
2513        plotNum = G2frame.G2plotNB.plotList.index('Size Distribution')
2514        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2515        Page.figure.clf()
2516        Plot = Page.figure.gca()          #get a fresh plot after clf()
2517    except ValueError:
2518        newPlot = True
2519        Plot = G2frame.G2plotNB.addMpl('Size Distribution').gca()
2520        G2frame.G2plotNB.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED,OnPageChanged)
2521        plotNum = G2frame.G2plotNB.plotList.index('Size Distribution')
2522        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2523        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2524    Page.Choice = None
2525    Page.SetFocus()
2526    PatternId = G2frame.PatternId
2527    data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'))
2528    Bins,Dbins,BinMag = data['Size']['Distribution']
2529    Plot.set_title('Size Distribution')
2530    Plot.set_xlabel(r'$D, \AA$',fontsize=14)
2531    Plot.set_ylabel(r'$Volume distribution f(D)$',fontsize=14)
2532    if data['Size']['logBins']:
2533        Plot.set_xscale("log",nonposy='mask')
2534        Plot.set_xlim([np.min(2.*Bins)/2.,np.max(2.*Bins)*2.])
2535    Plot.bar(2.*Bins-Dbins,BinMag,2.*Dbins,facecolor='white')       #plot diameters
2536    if 'Size Calc' in data:
2537        Rbins,Dist = data['Size Calc']
2538        for i in range(len(Rbins)):
2539            if len(Rbins[i]):
2540                Plot.plot(2.*Rbins[i],Dist[i])       #plot diameters
2541    Page.canvas.draw()
2542
2543################################################################################
2544##### PlotPowderLines
2545################################################################################
2546           
2547def PlotPowderLines(G2frame):
2548    ''' plotting of powder lines (i.e. no powder pattern) as sticks
2549    '''
2550
2551    def OnMotion(event):
2552        xpos = event.xdata
2553        if xpos:                                        #avoid out of frame mouse position
2554            Page.canvas.SetCursor(wx.CROSS_CURSOR)
2555            G2frame.G2plotNB.status.SetFields(['','2-theta =%9.3f '%(xpos,)])
2556            if G2frame.PickId and G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Index Peak List','Unit Cells List']:
2557                found = []
2558                if len(G2frame.HKL):
2559                    view = Page.toolbar._views.forward()[0][:2]
2560                    wid = view[1]-view[0]
2561                    found = G2frame.HKL[np.where(np.fabs(G2frame.HKL.T[-1]-xpos) < 0.002*wid)]
2562                if len(found):
2563                    h,k,l = found[0][:3] 
2564                    Page.canvas.SetToolTipString('%d,%d,%d'%(int(h),int(k),int(l)))
2565                else:
2566                    Page.canvas.SetToolTipString('')
2567
2568    try:
2569        plotNum = G2frame.G2plotNB.plotList.index('Powder Lines')
2570        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2571        Page.figure.clf()
2572        Plot = Page.figure.gca()
2573    except ValueError:
2574        Plot = G2frame.G2plotNB.addMpl('Powder Lines').gca()
2575        plotNum = G2frame.G2plotNB.plotList.index('Powder Lines')
2576        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2577        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
2578       
2579    Page.Choice = None
2580    Page.SetFocus()
2581    Plot.set_title('Powder Pattern Lines')
2582    Plot.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
2583    PickId = G2frame.PickId
2584    PatternId = G2frame.PatternId
2585    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))[0]
2586    for peak in peaks:
2587        Plot.axvline(peak[0],color='b')
2588    for hkl in G2frame.HKL:
2589        Plot.axvline(hkl[-2],color='r',dashes=(5,5))
2590    xmin = peaks[0][0]
2591    xmax = peaks[-1][0]
2592    delt = xmax-xmin
2593    xlim = [max(0,xmin-delt/20.),min(180.,xmax+delt/20.)]
2594    Plot.set_xlim(xlim)
2595    Page.canvas.draw()
2596    Page.toolbar.push_current()
2597
2598################################################################################
2599##### PlotPeakWidths
2600################################################################################
2601           
2602def PlotPeakWidths(G2frame):
2603    ''' Plotting of instrument broadening terms as function of 2-theta
2604    Seen when "Instrument Parameters" chosen from powder pattern data tree
2605    '''
2606#    sig = lambda Th,U,V,W: 1.17741*math.sqrt(U*tand(Th)**2+V*tand(Th)+W)*math.pi/18000.
2607#    gam = lambda Th,X,Y: (X/cosd(Th)+Y*tand(Th))*math.pi/18000.
2608#    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.)
2609#    gamFW2 = lambda s,g: math.sqrt(s**2+(0.4654996*g)**2)+.5345004*g  #Ubaldo Bafile - private communication
2610    PatternId = G2frame.PatternId
2611    limitID = G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits')
2612    if limitID:
2613        limits = G2frame.PatternTree.GetItemPyData(limitID)[:2]
2614    else:
2615        return
2616    Parms,Parms2 = G2frame.PatternTree.GetItemPyData( \
2617        G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
2618    if 'PKS' in Parms['Type'][0]:
2619        return
2620    elif 'T' in Parms['Type'][0]:
2621        difC = Parms['difC'][0]
2622    else:
2623        lam = G2mth.getWave(Parms)
2624    try:  # PATCH: deal with older peak lists, before changed to dict to implement TOF
2625        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))['peaks']
2626    except TypeError:
2627        print "Your peak list needs reformatting...",
2628        item = G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List')
2629        G2frame.PatternTree.SelectItem(item) 
2630        item = G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters')
2631        G2frame.PatternTree.SelectItem(item)
2632        print "done"
2633        return
2634    try:
2635        plotNum = G2frame.G2plotNB.plotList.index('Peak Widths')
2636        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2637        Page.figure.clf()
2638        Plot = Page.figure.gca()
2639    except ValueError:
2640        Plot = G2frame.G2plotNB.addMpl('Peak Widths').gca()
2641        plotNum = G2frame.G2plotNB.plotList.index('Peak Widths')
2642        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2643    Page.Choice = None
2644    Page.SetFocus()
2645   
2646    Page.canvas.SetToolTipString('')
2647    colors=['b','g','r','c','m','k']
2648    X = []
2649    Y = []
2650    Z = []
2651    W = []
2652    if 'C' in Parms['Type'][0]:
2653        Plot.set_title('Instrument and sample peak widths')
2654        Plot.set_xlabel(r'$Q, \AA^{-1}$',fontsize=14)
2655        Plot.set_ylabel(r'$\Delta Q/Q, \Delta d/d$',fontsize=14)
2656        try:
2657            Xmin,Xmax = limits[1]
2658            X = np.linspace(Xmin,Xmax,num=101,endpoint=True)
2659            Q = 4.*np.pi*npsind(X/2.)/lam
2660            Z = np.ones_like(X)
2661            data = G2mth.setPeakparms(Parms,Parms2,X,Z)
2662            s = 1.17741*np.sqrt(data[4])*np.pi/18000.
2663            g = data[6]*np.pi/18000.
2664            G = G2pwd.getgamFW(g,s)
2665            Y = s/nptand(X/2.)
2666            Z = g/nptand(X/2.)
2667            W = G/nptand(X/2.)
2668            Plot.plot(Q,Y,color='r',label='Gaussian')
2669            Plot.plot(Q,Z,color='g',label='Lorentzian')
2670            Plot.plot(Q,W,color='b',label='G+L')
2671           
2672            fit = G2mth.setPeakparms(Parms,Parms2,X,Z,useFit=True)
2673            sf = 1.17741*np.sqrt(fit[4])*np.pi/18000.
2674            gf = fit[6]*np.pi/18000.
2675            Gf = G2pwd.getgamFW(gf,sf)
2676            Yf = sf/nptand(X/2.)
2677            Zf = gf/nptand(X/2.)
2678            Wf = Gf/nptand(X/2.)
2679            Plot.plot(Q,Yf,color='r',dashes=(5,5),label='Gaussian fit')
2680            Plot.plot(Q,Zf,color='g',dashes=(5,5),label='Lorentzian fit')
2681            Plot.plot(Q,Wf,color='b',dashes=(5,5),label='G+L fit')
2682           
2683            X = []
2684            Y = []
2685            Z = []
2686            W = []
2687            V = []
2688            for peak in peaks:
2689                X.append(4.0*math.pi*sind(peak[0]/2.0)/lam)
2690                try:
2691                    s = 1.17741*math.sqrt(peak[4])*math.pi/18000.
2692                except ValueError:
2693                    s = 0.01
2694                g = peak[6]*math.pi/18000.
2695                G = G2pwd.getgamFW(g,s)
2696                Y.append(s/tand(peak[0]/2.))
2697                Z.append(g/tand(peak[0]/2.))
2698                W.append(G/tand(peak[0]/2.))
2699            if len(peaks):
2700                Plot.plot(X,Y,'+',color='r',label='G peak')
2701                Plot.plot(X,Z,'+',color='g',label='L peak')
2702                Plot.plot(X,W,'+',color='b',label='G+L peak')
2703            Plot.legend(loc='best')
2704            Page.canvas.draw()
2705        except ValueError:
2706            print '**** ERROR - default U,V,W profile coefficients yield sqrt of negative value at 2theta =', \
2707                '%.3f'%(2*theta)
2708            G2frame.G2plotNB.Delete('Peak Widths')
2709    else:   #'T'OF
2710        Plot.set_title('Instrument and sample peak coefficients')
2711        Plot.set_xlabel(r'$Q, \AA^{-1}$',fontsize=14)
2712        Plot.set_ylabel(r'$\alpha, \beta, \Delta Q/Q, \Delta d/d$',fontsize=14)
2713        Xmin,Xmax = limits[1]
2714        T = np.linspace(Xmin,Xmax,num=101,endpoint=True)
2715        Z = np.ones_like(T)
2716        data = G2mth.setPeakparms(Parms,Parms2,T,Z)
2717        ds = T/difC
2718        Q = 2.*np.pi/ds
2719        A = data[4]
2720        B = data[6]
2721        S = 1.17741*np.sqrt(data[8])/T
2722        G = data[10]/T
2723        Plot.plot(Q,A,color='r',label='Alpha')
2724        Plot.plot(Q,B,color='g',label='Beta')
2725        Plot.plot(Q,S,color='b',label='Gaussian')
2726        Plot.plot(Q,G,color='m',label='Lorentzian')
2727
2728        fit = G2mth.setPeakparms(Parms,Parms2,T,Z)
2729        ds = T/difC
2730        Q = 2.*np.pi/ds
2731        Af = fit[4]
2732        Bf = fit[6]
2733        Sf = 1.17741*np.sqrt(fit[8])/T
2734        Gf = fit[10]/T
2735        Plot.plot(Q,Af,color='r',dashes=(5,5),label='Alpha fit')
2736        Plot.plot(Q,Bf,color='g',dashes=(5,5),label='Beta fit')
2737        Plot.plot(Q,Sf,color='b',dashes=(5,5),label='Gaussian fit')
2738        Plot.plot(Q,Gf,color='m',dashes=(5,5),label='Lorentzian fit')
2739       
2740        T = []
2741        A = []
2742        B = []
2743        S = []
2744        G = []
2745        W = []
2746        Q = []
2747        V = []
2748        for peak in peaks:
2749            T.append(peak[0])
2750            A.append(peak[4])
2751            B.append(peak[6])
2752            Q.append(2.*np.pi*difC/peak[0])
2753            S.append(1.17741*np.sqrt(peak[8])/peak[0])
2754            G.append(peak[10]/peak[0])
2755           
2756       
2757        Plot.plot(Q,A,'+',color='r',label='Alpha peak')
2758        Plot.plot(Q,B,'+',color='g',label='Beta peak')
2759        Plot.plot(Q,S,'+',color='b',label='Gaussian peak')
2760        Plot.plot(Q,G,'+',color='m',label='Lorentzian peak')
2761        Plot.legend(loc='best')
2762        Page.canvas.draw()
2763
2764   
2765################################################################################
2766##### PlotSizeStrainPO
2767################################################################################
2768           
2769def PlotSizeStrainPO(G2frame,data,hist='',Start=False):
2770    '''Plot 3D mustrain/size/preferred orientation figure. In this instance data is for a phase
2771    '''
2772   
2773    PatternId = G2frame.PatternId
2774    generalData = data['General']
2775    SGData = generalData['SGData']
2776    SGLaue = SGData['SGLaue']
2777    if Start:                   #initialize the spherical harmonics qlmn arrays
2778        ptx.pyqlmninit()
2779        Start = False
2780#    MuStrKeys = G2spc.MustrainNames(SGData)
2781    cell = generalData['Cell'][1:]
2782    A,B = G2lat.cell2AB(cell[:6])
2783    Vol = cell[6]
2784    useList = data['Histograms']
2785    phase = generalData['Name']
2786    plotType = generalData['Data plot type']
2787    plotDict = {'Mustrain':'Mustrain','Size':'Size','Preferred orientation':'Pref.Ori.'}
2788    for ptype in plotDict:
2789        G2frame.G2plotNB.Delete(ptype)
2790    if plotType in ['None'] or not useList:
2791        return       
2792    if hist == '':
2793        hist = useList.keys()[0]
2794    numPlots = len(useList)
2795
2796    try:
2797        plotNum = G2frame.G2plotNB.plotList.index(plotType)
2798        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2799        Page.figure.clf()
2800        Plot = Page.figure.gca()
2801        if not Page.IsShown():
2802            Page.Show()
2803    except ValueError:
2804        if plotType in ['Mustrain','Size']:
2805            Plot = mp3d.Axes3D(G2frame.G2plotNB.add3D(plotType))
2806        else:
2807            Plot = G2frame.G2plotNB.addMpl(plotType).gca()               
2808        plotNum = G2frame.G2plotNB.plotList.index(plotType)
2809        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2810    Page.Choice = None
2811    G2frame.G2plotNB.status.SetStatusText('',1)
2812   
2813    PHI = np.linspace(0.,360.,30,True)
2814    PSI = np.linspace(0.,180.,30,True)
2815    X = np.outer(npsind(PHI),npsind(PSI))
2816    Y = np.outer(npcosd(PHI),npsind(PSI))
2817    Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
2818    try:        #temp patch instead of 'mustrain' for old files with 'microstrain'
2819        coeff = useList[hist][plotDict[plotType]]
2820    except KeyError:
2821        return
2822    if plotType in ['Mustrain','Size']:
2823        if coeff[0] == 'isotropic':
2824            X *= coeff[1][0]
2825            Y *= coeff[1][0]
2826            Z *= coeff[1][0]                               
2827        elif coeff[0] == 'uniaxial':
2828           
2829            def uniaxCalc(xyz,iso,aniso,axes):
2830                Z = np.array(axes)
2831                cp = abs(np.dot(xyz,Z))
2832                sp = np.sqrt(1.-cp**2)
2833                R = iso*aniso/np.sqrt((iso*cp)**2+(aniso*sp)**2)
2834                return R*xyz
2835               
2836            iso,aniso = coeff[1][:2]
2837            axes = np.inner(A,np.array(coeff[3]))
2838            axes /= nl.norm(axes)
2839            Shkl = np.array(coeff[1])
2840            XYZ = np.dstack((X,Y,Z))
2841            XYZ = np.nan_to_num(np.apply_along_axis(uniaxCalc,2,XYZ,iso,aniso,axes))
2842            X,Y,Z = np.dsplit(XYZ,3)
2843            X = X[:,:,0]
2844            Y = Y[:,:,0]
2845            Z = Z[:,:,0]
2846       
2847        elif coeff[0] == 'ellipsoidal':
2848           
2849            def ellipseCalc(xyz,E,R):
2850                XYZ = xyz*E.T
2851                return np.inner(XYZ.T,R)
2852               
2853            S6 = coeff[4]
2854            Sij = G2lat.U6toUij(S6)
2855            E,R = nl.eigh(Sij)
2856            XYZ = np.dstack((X,Y,Z))
2857            XYZ = np.nan_to_num(np.apply_along_axis(ellipseCalc,2,XYZ,E,R))
2858            X,Y,Z = np.dsplit(XYZ,3)
2859            X = X[:,:,0]
2860            Y = Y[:,:,0]
2861            Z = Z[:,:,0]
2862           
2863        elif coeff[0] == 'generalized':
2864           
2865            def genMustrain(xyz,SGData,A,Shkl):
2866                uvw = np.inner(A.T,xyz)
2867                Strm = np.array(G2spc.MustrainCoeff(uvw,SGData))
2868                Sum = np.sum(np.multiply(Shkl,Strm))
2869                Sum = np.where(Sum > 0.01,Sum,0.01)
2870                Sum = np.sqrt(Sum)
2871                return Sum*xyz
2872               
2873            Shkl = np.array(coeff[4])
2874            if np.any(Shkl):
2875                XYZ = np.dstack((X,Y,Z))
2876                XYZ = np.nan_to_num(np.apply_along_axis(genMustrain,2,XYZ,SGData,A,Shkl))
2877                X,Y,Z = np.dsplit(XYZ,3)
2878                X = X[:,:,0]
2879                Y = Y[:,:,0]
2880                Z = Z[:,:,0]
2881                   
2882        if np.any(X) and np.any(Y) and np.any(Z):
2883            errFlags = np.seterr(all='ignore')
2884            Plot.plot_surface(X,Y,Z,rstride=1,cstride=1,color='g',linewidth=1)
2885            np.seterr(all='ignore')
2886            xyzlim = np.array([Plot.get_xlim3d(),Plot.get_ylim3d(),Plot.get_zlim3d()]).T
2887            XYZlim = [min(xyzlim[0]),max(xyzlim[1])]
2888            Plot.set_xlim3d(XYZlim)
2889            Plot.set_ylim3d(XYZlim)
2890            Plot.set_zlim3d(XYZlim)
2891            Plot.set_aspect('equal')
2892        if plotType == 'Size':
2893            Plot.set_title('Crystallite size for '+phase+'\n'+coeff[0]+' model')
2894            Plot.set_xlabel(r'X, $\mu$m')
2895            Plot.set_ylabel(r'Y, $\mu$m')
2896            Plot.set_zlabel(r'Z, $\mu$m')
2897        else:   
2898            Plot.set_title(r'$\mu$strain for '+phase+'\n'+coeff[0]+' model')
2899            Plot.set_xlabel(r'X, $\mu$strain')
2900            Plot.set_ylabel(r'Y, $\mu$strain')
2901            Plot.set_zlabel(r'Z, $\mu$strain')
2902    else:
2903        h,k,l = generalData['POhkl']
2904        if coeff[0] == 'MD':
2905            print 'March-Dollase preferred orientation plot'
2906       
2907        else:
2908            PH = np.array(generalData['POhkl'])
2909            phi,beta = G2lat.CrsAng(PH,cell[:6],SGData)
2910            SHCoef = {}
2911            for item in coeff[5]:
2912                L,N = eval(item.strip('C'))
2913                SHCoef['C%d,0,%d'%(L,N)] = coeff[5][item]                       
2914            ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
2915            X = np.linspace(0,90.0,26)
2916            Y = G2lat.polfcal(ODFln,'0',X,0.0)
2917            Plot.plot(X,Y,color='k',label=str(PH))
2918            Plot.legend(loc='best')
2919            Plot.set_title('Axial distribution for HKL='+str(PH)+' in '+phase+'\n'+hist)
2920            Plot.set_xlabel(r'$\psi$',fontsize=16)
2921            Plot.set_ylabel('MRD',fontsize=14)
2922    Page.canvas.draw()
2923   
2924################################################################################
2925##### PlotTexture
2926################################################################################
2927
2928def PlotTexture(G2frame,data,Start=False):
2929    '''Pole figure, inverse pole figure plotting.
2930    dict generalData contains all phase info needed which is in data
2931    '''
2932
2933    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
2934    SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
2935    PatternId = G2frame.PatternId
2936    generalData = data['General']
2937    SGData = generalData['SGData']
2938    pName = generalData['Name']
2939    textureData = generalData['SH Texture']
2940    G2frame.G2plotNB.Delete('Texture')
2941    if not textureData['Order']:
2942        return                  #no plot!!
2943    SHData = generalData['SH Texture']
2944    SHCoef = SHData['SH Coeff'][1]
2945    cell = generalData['Cell'][1:7]
2946    Amat,Bmat = G2lat.cell2AB(cell)
2947    sq2 = 1.0/math.sqrt(2.0)
2948   
2949    def rp2xyz(r,p):
2950        z = npcosd(r)
2951        xy = np.sqrt(1.-z**2)
2952        return xy*npsind(p),xy*npcosd(p),z
2953           
2954    def OnMotion(event):
2955        SHData = data['General']['SH Texture']
2956        if event.xdata and event.ydata:                 #avoid out of frame errors
2957            xpos = event.xdata
2958            ypos = event.ydata
2959            if 'Inverse' in SHData['PlotType']:
2960                r = xpos**2+ypos**2
2961                if r <= 1.0:
2962                    if 'equal' in G2frame.Projection: 
2963                        r,p = 2.*npasind(np.sqrt(r)*sq2),npatan2d(ypos,xpos)
2964                    else:
2965                        r,p = 2.*npatand(np.sqrt(r)),npatan2d(ypos,xpos)
2966                    ipf = G2lat.invpolfcal(IODFln,SGData,np.array([r,]),np.array([p,]))
2967                    xyz = np.inner(Bmat,np.array([rp2xyz(r,p)]))
2968                    y,x,z = list(xyz/np.max(np.abs(xyz)))
2969                   
2970                    G2frame.G2plotNB.status.SetFields(['',
2971                        'psi =%9.3f, beta =%9.3f, MRD =%9.3f hkl=%5.2f,%5.2f,%5.2f'%(r,p,ipf,x,y,z)])
2972                                   
2973            elif 'Axial' in SHData['PlotType']:
2974                pass
2975               
2976            else:                       #ordinary pole figure
2977                z = xpos**2+ypos**2
2978                if z <= 1.0:
2979                    z = np.sqrt(z)
2980                    if 'equal' in G2frame.Projection: 
2981                        r,p = 2.*npasind(z*sq2),npatan2d(ypos,xpos)
2982                    else:
2983                        r,p = 2.*npatand(z),npatan2d(ypos,xpos)
2984                    pf = G2lat.polfcal(ODFln,SamSym[textureData['Model']],np.array([r,]),np.array([p,]))
2985                    G2frame.G2plotNB.status.SetFields(['','phi =%9.3f, gam =%9.3f, MRD =%9.3f'%(r,p,pf)])
2986   
2987    try:
2988        plotNum = G2frame.G2plotNB.plotList.index('Texture')
2989        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
2990        Page.figure.clf()
2991        Plot = Page.figure.gca()
2992        if not Page.IsShown():
2993            Page.Show()
2994    except ValueError:
2995        if '3D' in SHData['PlotType']:
2996            Plot = mp3d.Axes3D(G2frame.G2plotNB.add3D('Texture'))
2997        else:
2998            Plot = G2frame.G2plotNB.addMpl('Texture').gca()               
2999        plotNum = G2frame.G2plotNB.plotList.index('Texture')
3000        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3001        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
3002
3003    Page.Choice = None
3004    Page.SetFocus()
3005    G2frame.G2plotNB.status.SetFields(['',''])   
3006    PH = np.array(SHData['PFhkl'])
3007    phi,beta = G2lat.CrsAng(PH,cell,SGData)
3008    ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
3009    if not np.any(ODFln):
3010        return
3011    PX = np.array(SHData['PFxyz'])
3012    gam = atan2d(PX[0],PX[1])
3013    xy = math.sqrt(PX[0]**2+PX[1]**2)
3014    xyz = math.sqrt(PX[0]**2+PX[1]**2+PX[2]**2)
3015    psi = asind(xy/xyz)
3016    IODFln = G2lat.Glnh(Start,SHCoef,psi,gam,SamSym[textureData['Model']])
3017    if 'Axial' in SHData['PlotType']:
3018        X = np.linspace(0,90.0,26)
3019        Y = G2lat.polfcal(ODFln,SamSym[textureData['Model']],X,0.0)
3020        Plot.plot(X,Y,color='k',label=str(SHData['PFhkl']))
3021        Plot.legend(loc='best')
3022        h,k,l = SHData['PFhkl']
3023        Plot.set_title('%d %d %d Axial distribution for %s'%(h,k,l,pName))
3024        Plot.set_xlabel(r'$\psi$',fontsize=16)
3025        Plot.set_ylabel('MRD',fontsize=14)
3026       
3027    else:       
3028        npts = 201
3029        if 'Inverse' in SHData['PlotType']:
3030            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
3031            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
3032            if 'equal' in G2frame.Projection:
3033                R = np.where(R <= 1.,2.*npasind(R*sq2),0.0)
3034            else:
3035                R = np.where(R <= 1.,2.*npatand(R),0.0)
3036            Z = np.zeros_like(R)
3037            Z = G2lat.invpolfcal(IODFln,SGData,R,P)
3038            Z = np.reshape(Z,(npts,npts))
3039            try:
3040                CS = Plot.contour(Y,X,Z,aspect='equal')
3041                Plot.clabel(CS,fontsize=9,inline=1)
3042            except ValueError:
3043                pass
3044            Img = Plot.imshow(Z.T,aspect='equal',cmap=G2frame.ContourColor,extent=[-1,1,-1,1])
3045            Page.figure.colorbar(Img)
3046            x,y,z = SHData['PFxyz']
3047            Plot.axis('off')
3048            Plot.set_title('%d %d %d Inverse pole figure for %s'%(int(x),int(y),int(z),pName))
3049            Plot.set_xlabel(G2frame.Projection.capitalize()+' projection')
3050           
3051        elif '3D' in SHData['PlotType']:
3052            PSI,GAM = np.mgrid[0:31,0:31]
3053            PSI = PSI.flatten()*6.
3054            GAM = GAM.flatten()*12.
3055            P = G2lat.polfcal(ODFln,SamSym[textureData['Model']],PSI,GAM).reshape((31,31))           
3056            GAM = np.linspace(0.,360.,31,True)
3057            PSI = np.linspace(0.,180.,31,True)
3058            X = np.outer(npsind(GAM),npsind(PSI))*P.T
3059            Y = np.outer(npcosd(GAM),npsind(PSI))*P.T
3060            Z = np.outer(np.ones(np.size(GAM)),npcosd(PSI))*P.T
3061            h,k,l = SHData['PFhkl']
3062           
3063            if np.any(X) and np.any(Y) and np.any(Z):
3064                errFlags = np.seterr(all='ignore')
3065                Plot.plot_surface(X,Y,Z,rstride=1,cstride=1,color='g',linewidth=1)
3066                np.seterr(all='ignore')
3067                xyzlim = np.array([Plot.get_xlim3d(),Plot.get_ylim3d(),Plot.get_zlim3d()]).T
3068                XYZlim = [min(xyzlim[0]),max(xyzlim[1])]
3069                Plot.set_xlim3d(XYZlim)
3070                Plot.set_ylim3d(XYZlim)
3071                Plot.set_zlim3d(XYZlim)
3072                Plot.set_aspect('equal')                       
3073                Plot.set_title('%d %d %d Pole distribution for %s'%(h,k,l,pName))
3074                Plot.set_xlabel(r'X, MRD')
3075                Plot.set_ylabel(r'Y, MRD')
3076                Plot.set_zlabel(r'Z, MRD')
3077        else:
3078            PFproj = textureData.get('PFproj','XY')
3079            PRrev = textureData.get('PFrev',False)
3080            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
3081            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
3082            if 'equal' in G2frame.Projection:
3083                R = np.where(R <= 1.,2.*npasind(R*sq2),0.0)
3084            else:
3085                R = np.where(R <= 1.,2.*npatand(R),0.0)
3086            Z = np.zeros_like(R)
3087            Z = G2lat.polfcal(ODFln,SamSym[textureData['Model']],R,P)
3088            Z = np.reshape(Z,(npts,npts))
3089            try:
3090                CS = Plot.contour(Y,X,Z,aspect='equal')
3091                Plot.clabel(CS,fontsize=9,inline=1)
3092            except ValueError:
3093                pass
3094            Img = Plot.imshow(Z.T,aspect='equal',cmap=G2frame.ContourColor,extent=[-1,1,-1,1])
3095            Page.figure.colorbar(Img)
3096            h,k,l = SHData['PFhkl']
3097            Plot.axis('off')
3098            Plot.set_title('%d %d %d Pole figure for %s'%(h,k,l,pName))
3099            Plot.set_xlabel(G2frame.Projection.capitalize()+' projection')
3100    Page.canvas.draw()
3101
3102################################################################################
3103##### Plot Modulation
3104################################################################################
3105
3106def ModulationPlot(G2frame,data,atom,ax,off=0):
3107    global Off,Atom,Ax,Slab,Off
3108    Off = off
3109    Atom = atom
3110    Ax = ax
3111   
3112    def OnMotion(event):
3113        xpos = event.xdata
3114        if xpos:                                        #avoid out of frame mouse position
3115            ypos = event.ydata
3116            ix = int(round(xpos*10))
3117            iy = int(round((Slab.shape[0]-1)*(ypos+0.5-Off*0.005)))
3118            Page.canvas.SetCursor(wx.CROSS_CURSOR)
3119            try:
3120                G2frame.G2plotNB.status.SetStatusText('t =%9.3f %s =%9.3f %s=%9.3f'%(xpos,GkDelta+Ax,ypos,Gkrho,Slab[iy,ix]/8.),1)                   
3121#                GSASIIpath.IPyBreak()                 
3122            except (TypeError,IndexError):
3123                G2frame.G2plotNB.status.SetStatusText('Select '+Title+' pattern first',1)
3124   
3125    def OnPlotKeyPress(event):
3126        global Off,Atom,Ax
3127        newPlot = False
3128        if event.key == '0':
3129            Off = 0
3130        elif event.key in ['+','=']:
3131            Off += 1
3132        elif event.key == '-':
3133            Off -= 1
3134        elif event.key in ['l','r',] and mapData['Flip']:
3135            roll = 1
3136            if  event.key == 'l':
3137                roll = -1
3138            rho = Map['rho']
3139            Map['rho'] = np.roll(rho,roll,axis=3)
3140        wx.CallAfter(ModulationPlot,G2frame,data,Atom,Ax,Off)
3141
3142    try:
3143        plotNum = G2frame.G2plotNB.plotList.index('Modulation')
3144        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3145        Page.figure.clf()
3146        Plot = Page.figure.gca()
3147        if not Page.IsShown():
3148            Page.Show()
3149    except ValueError:
3150        Plot = G2frame.G2plotNB.addMpl('Modulation').gca()
3151        plotNum = G2frame.G2plotNB.plotList.index('Modulation')
3152        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3153        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
3154        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
3155   
3156    Page.SetFocus()
3157    General = data['General']
3158    cx,ct,cs,cia = General['AtomPtrs']
3159    mapData = General['Map']
3160    if mapData['Flip']:
3161        Page.Choice = ['+: shift up','-: shift down','0: reset shift','l: move left','r: move right']
3162    else:
3163        Page.Choice = ['+: shift up','-: shift down','0: reset shift']
3164    Page.keyPress = OnPlotKeyPress
3165    Map = General['4DmapData']
3166    MapType = mapData['MapType']
3167    rhoSize = np.array(Map['rho'].shape)
3168    atxyz = np.array(atom[cx:cx+3])
3169    waveType = atom[-1]['SS1']['waveType']
3170    Spos = atom[-1]['SS1']['Spos']
3171    tau = np.linspace(0.,2.,101)
3172    wave = np.zeros((3,101))
3173    if len(Spos):
3174        scof = []
3175        ccof = []
3176        for i,spos in enumerate(Spos):
3177            if waveType in ['ZigZag','Block'] and not i:
3178                Tminmax = spos[0][:2]
3179                XYZmax = np.array(spos[0][2:])
3180                if waveType == 'Block':
3181                    wave = G2mth.posBlock(tau,Tminmax,XYZmax).T
3182                elif waveType == 'ZigZag':
3183                    wave = G2mth.posZigZag(tau,Tminmax,XYZmax).T
3184            else:
3185                scof.append(spos[0][:3])
3186                ccof.append(spos[0][3:])
3187        wave += G2mth.posFourier(tau,np.array(scof),np.array(ccof))
3188    if mapData['Flip']:
3189        Title = 'Charge flip'
3190    else:
3191        Title = MapType
3192    Title += ' map for atom '+atom[0]+    \
3193        ' at %.4f %.4f %.4f'%(atxyz[0],atxyz[1],atxyz[2])
3194    ix = -np.array(np.rint(rhoSize[:3]*atxyz)+1,dtype='i')
3195    ix += (rhoSize[:3]/2)
3196    ix = ix%rhoSize[:3]
3197    rho = np.roll(np.roll(np.roll(Map['rho'],ix[0],axis=0),ix[1],axis=1),ix[2],axis=2)
3198    ix = rhoSize[:3]/2
3199    ib = 4
3200    hdx = [2,2,2]       #this needs to be something for an offset correction on atom positions
3201    if Ax == 'x':
3202        Doff = (hdx[0]+Off)*.005
3203        slab = np.sum(np.sum(rho[:,ix[1]-ib:ix[1]+ib,ix[2]-ib:ix[2]+ib,:],axis=2),axis=1)
3204        Plot.plot(tau,wave[0])
3205    elif Ax == 'y':
3206        Doff = (hdx[1]+Off)*.005
3207        slab = np.sum(np.sum(rho[ix[0]-ib:ix[0]+ib,:,ix[2]-ib:ix[2]+ib,:],axis=2),axis=0)
3208        Plot.plot(tau,wave[1])
3209    elif Ax == 'z':
3210        Doff = (hdx[2]+Off)*.005
3211        slab = np.sum(np.sum(rho[ix[0]-ib:ix[0]+ib,ix[1]-ib:ix[1]+ib,:,:],axis=1),axis=0)
3212        Plot.plot(tau,wave[2])
3213    Plot.set_title(Title)
3214    Plot.set_xlabel('t')
3215    Plot.set_ylabel(r'$\mathsf{\Delta}$%s'%(Ax))
3216    Slab = np.hstack((slab,slab,slab))   
3217    acolor = mpl.cm.get_cmap('RdYlGn')
3218    if 'delt' in MapType:
3219        Plot.contour(Slab[:,:21],20,extent=(0.,2.,-.5+Doff,.5+Doff),cmap=acolor)
3220    else:
3221        Plot.contour(Slab[:,:21],20,extent=(0.,2.,-.5+Doff,.5+Doff))
3222    Plot.set_ylim([-0.25,0.25])
3223    Page.canvas.draw()
3224   
3225################################################################################
3226##### PlotCovariance
3227################################################################################
3228           
3229def PlotCovariance(G2frame,Data):
3230    'needs a doc string'
3231    if not Data:
3232        print 'No covariance matrix available'
3233        return
3234    varyList = Data['varyList']
3235    values = Data['variables']
3236    Xmax = len(varyList)
3237    covMatrix = Data['covMatrix']
3238    sig = np.sqrt(np.diag(covMatrix))
3239    xvar = np.outer(sig,np.ones_like(sig))
3240    covArray = np.divide(np.divide(covMatrix,xvar),xvar.T)
3241    title = ' for\n'+Data['title']
3242    newAtomDict = Data.get('newAtomDict',{})
3243    G2frame.G2plotNB.Delete('Covariance')
3244   
3245
3246    def OnPlotKeyPress(event):
3247        newPlot = False
3248        if event.key == 's':
3249            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
3250            choice.sort()
3251            dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
3252            if dlg.ShowModal() == wx.ID_OK:
3253                sel = dlg.GetSelection()
3254                G2frame.VcovColor = choice[sel]
3255            else:
3256                G2frame.VcovColor = 'RdYlGn'
3257            dlg.Destroy()
3258        PlotCovariance(G2frame,Data)
3259
3260    def OnMotion(event):
3261        if event.button:
3262            ytics = imgAx.get_yticks()
3263            ytics = np.where(ytics<len(varyList),ytics,-1)
3264            ylabs = [np.where(0<=i ,varyList[int(i)],' ') for i in ytics]
3265            imgAx.set_yticklabels(ylabs)           
3266        if event.xdata and event.ydata:                 #avoid out of frame errors
3267            xpos = int(event.xdata+.5)
3268            ypos = int(event.ydata+.5)
3269            if -1 < xpos < len(varyList) and -1 < ypos < len(varyList):
3270                if xpos == ypos:
3271                    value = values[xpos]
3272                    name = varyList[xpos]
3273                    if varyList[xpos] in newAtomDict:
3274                        name,value = newAtomDict[name]                       
3275                    msg = '%s value = %.4g, esd = %.4g'%(name,value,sig[xpos])
3276                else:
3277                    msg = '%s - %s: %5.3f'%(varyList[xpos],varyList[ypos],covArray[xpos][ypos])
3278                Page.canvas.SetToolTipString(msg)
3279                G2frame.G2plotNB.status.SetFields(['',msg])
3280               
3281    try:
3282        plotNum = G2frame.G2plotNB.plotList.index('Covariance')
3283        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3284        Page.figure.clf()
3285        Plot = Page.figure.gca()
3286        if not Page.IsShown():
3287            Page.Show()
3288    except ValueError:
3289        Plot = G2frame.G2plotNB.addMpl('Covariance').gca()
3290        plotNum = G2frame.G2plotNB.plotList.index('Covariance')
3291        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3292        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
3293        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
3294    Page.Choice = ['s: to change colors']
3295    Page.keyPress = OnPlotKeyPress
3296    Page.SetFocus()
3297    G2frame.G2plotNB.status.SetFields(['',''])   
3298    acolor = mpl.cm.get_cmap(G2frame.VcovColor)
3299    Img = Plot.imshow(covArray,aspect='equal',cmap=acolor,interpolation='nearest',origin='lower',
3300        vmin=-1.,vmax=1.)
3301    imgAx = Img.get_axes()
3302    ytics = imgAx.get_yticks()
3303    ylabs = [varyList[int(i)] for i in ytics[:-1]]
3304    imgAx.set_yticklabels(ylabs)
3305    colorBar = Page.figure.colorbar(Img)
3306    Plot.set_title('V-Cov matrix'+title)
3307    Plot.set_xlabel('Variable number')
3308    Plot.set_ylabel('Variable name')
3309    Page.canvas.draw()
3310   
3311################################################################################
3312##### PlotTorsion
3313################################################################################
3314
3315def PlotTorsion(G2frame,phaseName,Torsion,TorName,Names=[],Angles=[],Coeff=[]):
3316    'needs a doc string'
3317   
3318    global names
3319    names = Names
3320    sum = np.sum(Torsion)
3321    torsion = np.log(2*Torsion+1.)/sum
3322    tMin = np.min(torsion)
3323    tMax = np.max(torsion)
3324    torsion = 3.*(torsion-tMin)/(tMax-tMin)
3325    X = np.linspace(0.,360.,num=45)
3326   
3327    def OnPick(event):
3328        ind = event.ind[0]
3329        msg = 'atoms:'+names[ind]
3330        Page.canvas.SetToolTipString(msg)
3331        try:
3332            page = G2frame.dataDisplay.GetSelection()
3333        except:
3334            return
3335        if G2frame.dataDisplay.GetPageText(page) == 'Torsion restraints':
3336            torGrid = G2frame.dataDisplay.GetPage(page).Torsions
3337            torGrid.ClearSelection()
3338            for row in range(torGrid.GetNumberRows()):
3339                if names[ind] in torGrid.GetCellValue(row,0):
3340                    torGrid.SelectRow(row)
3341            torGrid.ForceRefresh()
3342               
3343    def OnMotion(event):
3344        if event.xdata and event.ydata:                 #avoid out of frame errors
3345            xpos = event.xdata
3346            ypos = event.ydata
3347            msg = 'torsion,energy: %5.3f %5.3f'%(xpos,ypos)
3348            Page.canvas.SetToolTipString(msg)
3349
3350    try:
3351        plotNum = G2frame.G2plotNB.plotList.index('Torsion')
3352        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3353        Page.figure.clf()
3354        Plot = Page.figure.gca()
3355        if not Page.IsShown():
3356            Page.Show()
3357    except ValueError:
3358        Plot = G2frame.G2plotNB.addMpl('Torsion').gca()
3359        plotNum = G2frame.G2plotNB.plotList.index('Torsion')
3360        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3361        Page.canvas.mpl_connect('pick_event', OnPick)
3362        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
3363   
3364    Page.SetFocus()
3365    G2frame.G2plotNB.status.SetFields(['','Use mouse LB to identify torsion atoms'])
3366    Plot.plot(X,torsion,'b+')
3367    if len(Coeff):
3368        X2 = np.linspace(0.,360.,45)
3369        Y2 = np.array([-G2mth.calcTorsionEnergy(x,Coeff)[1] for x in X2])
3370        Plot.plot(X2,Y2,'r')
3371    if len(Angles):
3372        Eval = np.array([-G2mth.calcTorsionEnergy(x,Coeff)[1] for x in Angles])
3373        Plot.plot(Angles,Eval,'ro',picker=5)
3374    Plot.set_xlim((0.,360.))
3375    Plot.set_title('Torsion angles for '+TorName+' in '+phaseName)
3376    Plot.set_xlabel('angle',fontsize=16)
3377    Plot.set_ylabel('Energy',fontsize=16)
3378    Page.canvas.draw()
3379   
3380################################################################################
3381##### PlotRama
3382################################################################################
3383
3384def PlotRama(G2frame,phaseName,Rama,RamaName,Names=[],PhiPsi=[],Coeff=[]):
3385    'needs a doc string'
3386
3387    global names
3388    names = Names
3389    rama = np.log(2*Rama+1.)
3390    ramaMax = np.max(rama)
3391    rama = np.reshape(rama,(45,45))
3392    global Phi,Psi
3393    Phi = []
3394    Psi = []
3395
3396    def OnPlotKeyPress(event):
3397        newPlot = False
3398        if event.key == 's':
3399            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
3400            choice.sort()
3401            dlg = wx.SingleChoiceDialog(G2frame,'Select','Color scheme',choice)
3402            if dlg.ShowModal() == wx.ID_OK:
3403                sel = dlg.GetSelection()
3404                G2frame.RamaColor = choice[sel]
3405            else:
3406                G2frame.RamaColor = 'RdYlGn'
3407            dlg.Destroy()
3408        PlotRama(G2frame,phaseName,Rama)
3409
3410    def OnPick(event):
3411        ind = event.ind[0]
3412        msg = 'atoms:'+names[ind]
3413        Page.canvas.SetToolTipString(msg)
3414        try:
3415            page = G2frame.dataDisplay.GetSelection()
3416        except:
3417            return
3418        if G2frame.dataDisplay.GetPageText(page) == 'Ramachandran restraints':
3419            ramaGrid = G2frame.dataDisplay.GetPage(page).Ramas
3420            ramaGrid.ClearSelection()
3421            for row in range(ramaGrid.GetNumberRows()):
3422                if names[ind] in ramaGrid.GetCellValue(row,0):
3423                    ramaGrid.SelectRow(row)
3424            ramaGrid.ForceRefresh()
3425
3426    def OnMotion(event):
3427        if event.xdata and event.ydata:                 #avoid out of frame errors
3428            xpos = event.xdata
3429            ypos = event.ydata
3430            msg = 'phi/psi: %5.3f %5.3f'%(xpos,ypos)
3431            Page.canvas.SetToolTipString(msg)
3432           
3433    try:
3434        plotNum = G2frame.G2plotNB.plotList.index('Ramachandran')
3435        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3436        Page.figure.clf()
3437        Plot = Page.figure.gca()
3438        if not Page.IsShown():
3439            Page.Show()
3440    except ValueError:
3441        Plot = G2frame.G2plotNB.addMpl('Ramachandran').gca()
3442        plotNum = G2frame.G2plotNB.plotList.index('Ramachandran')
3443        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3444        Page.canvas.mpl_connect('pick_event', OnPick)
3445        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
3446        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
3447
3448    Page.Choice = ['s: to change colors']
3449    Page.keyPress = OnPlotKeyPress
3450    Page.SetFocus()
3451    G2frame.G2plotNB.status.SetFields(['','Use mouse LB to identify phi/psi atoms'])
3452    acolor = mpl.cm.get_cmap(G2frame.RamaColor)
3453    if RamaName == 'All' or '-1' in RamaName:
3454        if len(Coeff): 
3455            X,Y = np.meshgrid(np.linspace(-180.,180.,45),np.linspace(-180.,180.,45))
3456            Z = np.array([-G2mth.calcRamaEnergy(x,y,Coeff)[1] for x,y in zip(X.flatten(),Y.flatten())])
3457            Plot.contour(X,Y,np.reshape(Z,(45,45)))
3458        Img = Plot.imshow(rama,aspect='equal',cmap=acolor,interpolation='nearest',
3459            extent=[-180,180,-180,180],origin='lower')
3460        if len(PhiPsi):
3461            Phi,Psi = PhiPsi.T
3462            Phi = np.where(Phi>180.,Phi-360.,Phi)
3463            Psi = np.where(Psi>180.,Psi-360.,Psi)
3464            Plot.plot(Phi,Psi,'ro',picker=5)
3465        Plot.set_xlim((-180.,180.))
3466        Plot.set_ylim((-180.,180.))
3467    else:
3468        if len(Coeff): 
3469            X,Y = np.meshgrid(np.linspace(0.,360.,45),np.linspace(0.,360.,45))
3470            Z = np.array([-G2mth.calcRamaEnergy(x,y,Coeff)[1] for x,y in zip(X.flatten(),Y.flatten())])
3471            Plot.contour(X,Y,np.reshape(Z,(45,45)))
3472        Img = Plot.imshow(rama,aspect='equal',cmap=acolor,interpolation='nearest',
3473            extent=[0,360,0,360],origin='lower')
3474        if len(PhiPsi):
3475            Phi,Psi = PhiPsi.T
3476            Plot.plot(Phi,Psi,'ro',picker=5)
3477        Plot.set_xlim((0.,360.))
3478        Plot.set_ylim((0.,360.))
3479    Plot.set_title('Ramachandran for '+RamaName+' in '+phaseName)
3480    Plot.set_xlabel(r'$\phi$',fontsize=16)
3481    Plot.set_ylabel(r'$\psi$',fontsize=16)
3482    colorBar = Page.figure.colorbar(Img)
3483    Page.canvas.draw()
3484
3485
3486################################################################################
3487##### PlotSeq
3488################################################################################
3489def PlotSelectedSequence(G2frame,ColumnList,TableGet,SelectX,fitnum=None,fitvals=None):
3490    '''Plot a result from a sequential refinement
3491
3492    :param wx.Frame G2frame: The main GSAS-II tree "window"
3493    :param list ColumnList: list of int values corresponding to columns
3494      selected as y values
3495    :param function TableGet: a function that takes a column number
3496      as argument and returns the column label, the values and there ESDs (or None)
3497    :param function SelectX: a function that returns a selected column
3498      number (or None) as the X-axis selection
3499    '''
3500    global Title,xLabel,yLabel
3501    xLabel = yLabel = Title = ''
3502    def OnMotion(event):
3503        if event.xdata and event.ydata:                 #avoid out of frame errors
3504            xpos = event.xdata
3505            ypos = event.ydata
3506            msg = '%5.3f %.6g'%(xpos,ypos)
3507            Page.canvas.SetToolTipString(msg)
3508
3509    def OnKeyPress(event):
3510        global Title,xLabel,yLabel
3511        if event.key == 's':
3512            G2frame.seqXaxis = G2frame.seqXselect()
3513            Draw()
3514        elif event.key == 't':
3515            dlg = G2G.MultiStringDialog(G2frame,'Set titles & labels',[' Title ',' x-Label ',' y-Label '],
3516                [Title,xLabel,yLabel])
3517            if dlg.Show():
3518                Title,xLabel,yLabel = dlg.GetValues()
3519            dlg.Destroy()
3520            Draw()
3521        elif event.key == 'l':
3522            G2frame.seqLines = not G2frame.seqLines
3523            wx.CallAfter(Draw)
3524           
3525    def Draw():
3526        global Title,xLabel,yLabel
3527        Page.SetFocus()
3528        G2frame.G2plotNB.status.SetStatusText(  \
3529            'press L to toggle lines, S to select X axis, T to change titles (reselect column to show?)',1)
3530        Plot.clear()
3531        if G2frame.seqXaxis is not None:   
3532            xName,X,Xsig = Page.seqTableGet(G2frame.seqXaxis)
3533        else:
3534            X = np.arange(0,G2frame.SeqTable.GetNumberRows(),1)
3535            xName = 'Data sequence number'
3536        for col in Page.seqYaxisList:
3537            name,Y,sig = Page.seqTableGet(col)
3538            # deal with missing (None) values
3539            Xnew = []
3540            Ynew = []
3541            Ysnew = []
3542            for i in range(len(X)):
3543                if X[i] is None or Y[i] is None: continue
3544                Xnew.append(X[i])
3545                Ynew.append(Y[i])
3546                if sig: Ysnew.append(sig[i])
3547            if Ysnew:
3548                if G2frame.seqReverse and not G2frame.seqXaxis:
3549                    Ynew = Ynew[::-1]
3550                    Ysnew = Ysnew[::-1]
3551                if G2frame.seqLines:
3552                    Plot.errorbar(Xnew,Ynew,yerr=Ysnew,label=name)
3553                else:
3554                    Plot.errorbar(Xnew,Ynew,yerr=Ysnew,label=name,linestyle='None',marker='x')
3555            else:
3556                if G2frame.seqReverse and not G2frame.seqXaxis:
3557                    Ynew = Ynew[::-1]
3558                Plot.plot(Xnew,Ynew)
3559                Plot.plot(Xnew,Ynew,'o',label=name)
3560        if Page.fitvals: # TODO: deal with fitting of None values
3561            if G2frame.seqReverse and not G2frame.seqXaxis:
3562                Page.fitvals = Page.fitvals[::-1]
3563            Plot.plot(X,Page.fitvals,label='Fit')
3564           
3565        Plot.legend(loc='best')
3566        if Title:
3567            Plot.set_title(Title)
3568        else:
3569            Plot.set_title('')
3570        if xLabel:
3571            Plot.set_xlabel(xLabel)
3572        else:
3573            Plot.set_xlabel(xName)
3574        if yLabel:
3575            Plot.set_ylabel(yLabel)
3576        else:
3577            Plot.set_ylabel('Parameter values')
3578        Page.canvas.draw()
3579           
3580    G2frame.seqXselect = SelectX
3581    try:
3582        G2frame.seqXaxis
3583    except:
3584        G2frame.seqXaxis = None
3585
3586    if fitnum is None:
3587        label = 'Sequential refinement'
3588    else:
3589        label = 'Parametric fit #'+str(fitnum+1)
3590    try:
3591        plotNum = G2frame.G2plotNB.plotList.index(label)
3592        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3593        Page.figure.clf()
3594        Plot = Page.figure.gca()
3595        if not Page.IsShown():
3596            Page.Show()
3597    except ValueError:
3598        Plot = G2frame.G2plotNB.addMpl(label).gca()
3599        plotNum = G2frame.G2plotNB.plotList.index(label)
3600        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3601        Page.canvas.mpl_connect('key_press_event', OnKeyPress)
3602        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
3603    Page.Choice = ['l - toggle lines','s - select x-axis','t - change titles',]
3604    Page.keyPress = OnKeyPress
3605    Page.seqYaxisList = ColumnList
3606    Page.seqTableGet = TableGet
3607    Page.fitvals = fitvals
3608       
3609    Draw()
3610    G2frame.G2plotNB.nb.SetSelection(plotNum) # raises plot tab
3611               
3612################################################################################
3613##### PlotExposedImage & PlotImage
3614################################################################################
3615           
3616def PlotExposedImage(G2frame,newPlot=False,event=None):
3617    '''General access module for 2D image plotting
3618    '''
3619    plotNo = G2frame.G2plotNB.nb.GetSelection()
3620    if plotNo < 0: return # no plots
3621    if G2frame.G2plotNB.nb.GetPageText(plotNo) == '2D Powder Image':
3622        PlotImage(G2frame,newPlot,event,newImage=True)
3623    elif G2frame.G2plotNB.nb.GetPageText(plotNo) == '2D Integration':
3624        PlotIntegration(G2frame,newPlot,event)
3625
3626def OnStartMask(G2frame):
3627    '''Initiate the start of a Frame or Polygon map
3628
3629    :param wx.Frame G2frame: The main GSAS-II tree "window"
3630    :param str eventkey: a single letter ('f' or 'p', etc.) that
3631      determines what type of mask is created.   
3632    '''
3633    Masks = G2frame.PatternTree.GetItemPyData(
3634        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
3635    if G2frame.MaskKey == 'f':
3636        Masks['Frames'] = []
3637    elif G2frame.MaskKey == 'p':
3638        Masks['Polygons'].append([])
3639    elif G2frame.MaskKey == 's':
3640        Masks['Points'].append([])
3641    elif G2frame.MaskKey == 'a':
3642        Masks['Arcs'].append([])
3643    elif G2frame.MaskKey == 'r':
3644        Masks['Rings'].append([])
3645    G2imG.UpdateMasks(G2frame,Masks)
3646    PlotImage(G2frame,newImage=True)
3647   
3648def OnStartNewDzero(G2frame):
3649    '''Initiate the start of adding a new d-zero to a strain data set
3650
3651    :param wx.Frame G2frame: The main GSAS-II tree "window"
3652    :param str eventkey: a single letter ('a') that
3653      triggers the addition of a d-zero.   
3654    '''
3655    G2frame.dataFrame.GetStatusBar().SetStatusText('Add strain ring active - LB pick d-zero value',0)
3656    G2frame.PickId = G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Stress/Strain')
3657    data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
3658    return data
3659
3660def PlotImage(G2frame,newPlot=False,event=None,newImage=True):
3661    '''Plot of 2D detector images as contoured plot. Also plot calibration ellipses,
3662    masks, etc.
3663
3664    :param wx.Frame G2frame: main GSAS-II frame
3665    :param bool newPlot: if newPlot is True, the plot is reset (zoomed out, etc.)
3666    :param event: matplotlib mouse event (or None)
3667    :param bool newImage: If True, the Figure is cleared and redrawn
3668    '''
3669    from matplotlib.patches import Ellipse,Arc,Circle,Polygon
3670    import numpy.ma as ma
3671    Dsp = lambda tth,wave: wave/(2.*npsind(tth/2.))
3672    #global Data,Masks,StrSta  # BHT: I don't see why these need to be globals. Where are they accessed?
3673    colors=['b','g','r','c','m','k']
3674    Data = G2frame.PatternTree.GetItemPyData(
3675        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
3676# patch
3677    if 'invert_x' not in Data:
3678        Data['invert_x'] = False
3679        Data['invert_y'] = True
3680# end patch
3681    Masks = G2frame.PatternTree.GetItemPyData(
3682        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
3683    try:    #may be absent
3684        StrSta = G2frame.PatternTree.GetItemPyData(
3685            G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Stress/Strain'))
3686    except TypeError:   #is missing
3687        StrSta = {}
3688
3689    def OnImMotion(event):
3690        Page.canvas.SetToolTipString('')
3691        sizexy = Data['size']
3692        FlatBkg = Data.get('Flat Bkg',0.)
3693        if event.xdata and event.ydata and len(G2frame.ImageZ):                 #avoid out of frame errors
3694            Page.canvas.SetToolTipString('%8.2f %8.2fmm'%(event.xdata,event.ydata))
3695            Page.canvas.SetCursor(wx.CROSS_CURSOR)
3696            item = G2frame.itemPicked
3697            pixelSize = Data['pixelSize']
3698            scalex = 1000./pixelSize[0]
3699            scaley = 1000./pixelSize[1]
3700            if item and G2frame.PatternTree.GetItemText(G2frame.PickId) == 'Image Controls':
3701                if 'Text' in str(item):
3702                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
3703                else:
3704                    xcent,ycent = Data['center']
3705                    xpos = event.xdata-xcent
3706                    ypos = event.ydata-ycent
3707                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
3708                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
3709                        Page.canvas.SetToolTipString('%6d deg'%(azm))
3710                    elif 'line1' in  str(item) or 'line2' in str(item):
3711                        Page.canvas.SetToolTipString('%8.3f deg'%(tth))                           
3712            else:
3713                xpos = event.xdata
3714                ypos = event.ydata
3715                xpix = xpos*scalex
3716                ypix = ypos*scaley
3717                Int = 0
3718                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
3719                    Int = G2frame.ImageZ[ypix][xpix]-int(FlatBkg)
3720                tth,azm,D,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
3721                Q = 2.*math.pi/dsp
3722                fields = ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)]
3723                if G2frame.MaskKey in ['p','f']:
3724                    fields[1] = 'Polygon/frame mask pick - LB next point, RB close polygon'
3725                elif G2frame.StrainKey:
3726                    fields[0] = 'd-zero pick active'
3727                G2frame.G2plotNB.status.SetFields(fields)
3728
3729    def OnImPlotKeyPress(event):
3730        try:
3731            PickName = G2frame.PatternTree.GetItemText(G2frame.PickId)
3732        except TypeError:
3733            return
3734        if PickName == 'Masks':
3735            if event.key in ['l','p','f','s','a','r']:
3736                G2frame.MaskKey = event.key
3737                OnStartMask(G2frame)
3738                wx.CallAfter(PlotImage,G2frame,newImage=False)
3739               
3740        elif PickName == 'Stress/Strain':
3741            if event.key in ['a',]:
3742                G2frame.StrainKey = event.key
3743                StrSta = OnStartNewDzero(G2frame)
3744                wx.CallAfter(PlotImage,G2frame,newImage=False)
3745               
3746        elif PickName == 'Image Controls':
3747            if event.key in ['c',]:
3748                Xpos = event.xdata
3749                if not Xpos:            #got point out of frame
3750                    return
3751                Ypos = event.ydata
3752                dlg = wx.MessageDialog(G2frame,'Are you sure you want to change the center?',
3753                    'Center change',style=wx.OK|wx.CANCEL)
3754                try:
3755                    if dlg.ShowModal() == wx.ID_OK:
3756                        print 'move center to: ',Xpos,Ypos
3757                        Data['center'] = [Xpos,Ypos]
3758                        G2imG.UpdateImageControls(G2frame,Data,Masks)
3759                        wx.CallAfter(PlotImage,G2frame,newPlot=False)
3760                finally:
3761                    dlg.Destroy()
3762                return
3763            elif event.key == 'l':
3764                G2frame.logPlot = not G2frame.logPlot
3765            elif event.key in ['x',]:
3766                Data['invert_x'] = not Data['invert_x']
3767            elif event.key in ['y',]:
3768                Data['invert_y'] = not Data['invert_y']
3769            wx.CallAfter(PlotImage,G2frame,newPlot=True)
3770           
3771    def OnKeyBox(event):
3772        if G2frame.G2plotNB.nb.GetSelection() == G2frame.G2plotNB.plotList.index('2D Powder Image'):
3773            event.key = cb.GetValue()[0]
3774            cb.SetValue(' key press')
3775            if event.key in ['l','s','a','r','p','x','y']:
3776                wx.CallAfter(OnImPlotKeyPress,event)
3777        Page.canvas.SetFocus() # redirect the Focus from the button back to the plot
3778                       
3779    def OnImPick(event):
3780        if G2frame.PatternTree.GetItemText(G2frame.PickId) not in ['Image Controls','Masks']:
3781            return
3782        if G2frame.itemPicked is not None: return
3783        G2frame.itemPicked = event.artist
3784        G2frame.mousePicked = event.mouseevent
3785       
3786    def OnImRelease(event):
3787        try:
3788            PickName = G2frame.PatternTree.GetItemText(G2frame.PickId)
3789        except TypeError:
3790            return
3791        if PickName not in ['Image Controls','Masks','Stress/Strain']:
3792            return
3793        pixelSize = Data['pixelSize']
3794        FlatBkg = Data.get('Flat Bkg',0.)
3795        scalex = 1000./pixelSize[0]
3796        scaley = 1000./pixelSize[1]
3797#        pixLimit = Data['pixLimit']    #can be too tight
3798        pixLimit = 20       #this makes the search box 40x40 pixels
3799        if G2frame.itemPicked is None and PickName == 'Image Controls' and len(G2frame.ImageZ):
3800            Xpos = event.xdata
3801            if not (Xpos and G2frame.ifGetRing):                   #got point out of frame
3802                return
3803            Ypos = event.ydata
3804            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
3805                if event.button == 1:
3806                    Xpix = Xpos*scalex
3807                    Ypix = Ypos*scaley
3808                    xpos,ypos,I,J = G2img.ImageLocalMax(G2frame.ImageZ-FlatBkg,pixLimit,Xpix,Ypix)
3809                    if I and J:
3810                        xpos += .5                              #shift to pixel center
3811                        ypos += .5
3812                        xpos /= scalex                          #convert to mm
3813                        ypos /= scaley
3814                        Data['ring'].append([xpos,ypos])
3815                elif event.button == 3:
3816                    G2frame.dataFrame.GetStatusBar().SetStatusText('Calibrating...',0)
3817                    if G2img.ImageCalibrate(G2frame,Data):
3818                        G2frame.dataFrame.GetStatusBar().SetStatusText('Calibration successful - Show ring picks to check',0)
3819                        print 'Calibration successful'
3820                    else:
3821                        G2frame.dataFrame.GetStatusBar().SetStatusText('Calibration failed - Show ring picks to diagnose',0)
3822                        print 'Calibration failed'
3823                    G2frame.ifGetRing = False
3824                    G2imG.UpdateImageControls(G2frame,Data,Masks)
3825                    return
3826                wx.CallAfter(PlotImage,G2frame,newImage=False)
3827            return
3828        elif G2frame.MaskKey and PickName == 'Masks':
3829            Xpos,Ypos = [event.xdata,event.ydata]
3830            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
3831                return
3832            if G2frame.MaskKey == 's' and event.button == 1:
3833                Masks['Points'][-1] = [Xpos,Ypos,1.]
3834                G2frame.MaskKey = ''               
3835            elif G2frame.MaskKey == 'r' and event.button == 1:
3836                tth = G2img.GetTth(Xpos,Ypos,Data)
3837                Masks['Rings'][-1] = [tth,0.1]
3838                G2frame.MaskKey = ''               
3839            elif G2frame.MaskKey == 'a' and event.button == 1:
3840                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
3841                azm = int(azm)               
3842                Masks['Arcs'][-1] = [tth,[azm-5,azm+5],0.1]
3843                G2frame.MaskKey = ''               
3844            elif G2frame.MaskKey =='p':
3845                polygon = Masks['Polygons'][-1]
3846                if len(polygon) > 2 and event.button == 3:
3847                    x0,y0 = polygon[0]
3848                    polygon.append([x0,y0])
3849                    G2frame.MaskKey = ''
3850                    G2frame.G2plotNB.status.SetFields(['','Polygon closed'])
3851                else:
3852                    G2frame.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(Xpos,Ypos)])
3853                    polygon.append([Xpos,Ypos])
3854            elif G2frame.MaskKey =='f':
3855                frame = Masks['Frames']
3856                if len(frame) > 2 and event.button == 3:
3857                    x0,y0 = frame[0]
3858                    frame.append([x0,y0])
3859                    G2frame.MaskKey = ''
3860                    G2frame.G2plotNB.status.SetFields(['','Frame closed'])
3861                else:
3862                    G2frame.G2plotNB.status.SetFields(['','New frame point: %.1f,%.1f'%(Xpos,Ypos)])
3863                    frame.append([Xpos,Ypos])
3864            G2imG.UpdateMasks(G2frame,Masks)
3865            wx.CallAfter(PlotImage,G2frame,newImage=False)
3866        elif PickName == 'Stress/Strain' and G2frame.StrainKey:
3867            Xpos,Ypos = [event.xdata,event.ydata]
3868            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
3869                return
3870            dsp = G2img.GetDsp(Xpos,Ypos,Data)
3871            StrSta['d-zero'].append({'Dset':dsp,'Dcalc':0.0,'pixLimit':10,'cutoff':0.5,
3872                'ImxyObs':[[],[]],'ImtaObs':[[],[]],'ImtaCalc':[[],[]],'Emat':[1.0,1.0,1.0]})
3873            R,r = G2img.MakeStrStaRing(StrSta['d-zero'][-1],G2frame.ImageZ-FlatBkg,Data)
3874            if not len(R):
3875                del StrSta['d-zero'][-1]
3876                G2frame.ErrorDialog('Strain peak selection','WARNING - No points found for this ring selection')
3877            StrSta['d-zero'] = G2mth.sortArray(StrSta['d-zero'],'Dset',reverse=True)
3878            G2frame.StrainKey = ''
3879            G2imG.UpdateStressStrain(G2frame,StrSta)
3880            PlotStrain(G2frame,StrSta)
3881            wx.CallAfter(PlotImage,G2frame,newPlot=False)           
3882        else:
3883            Xpos,Ypos = [event.xdata,event.ydata]
3884            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
3885                return
3886            if G2frame.ifGetRing:                          #delete a calibration ring pick
3887                xypos = [Xpos,Ypos]
3888                rings = Data['ring']
3889                for ring in rings:
3890                    if np.allclose(ring,xypos,.01,0):
3891                        rings.remove(ring)
3892            else:
3893                tth,azm,dsp = G2img.GetTthAzmDsp(Xpos,Ypos,Data)[:3]
3894                itemPicked = str(G2frame.itemPicked)
3895                if 'Line2D' in itemPicked and PickName == 'Image Controls':
3896                    if 'line1' in itemPicked:
3897                        Data['IOtth'][0] = max(tth,0.001)
3898                    elif 'line2' in itemPicked:
3899                        Data['IOtth'][1] = tth
3900                    elif 'line3' in itemPicked:
3901                        Data['LRazimuth'][0] = int(azm)
3902                    elif 'line4' in itemPicked and not Data['fullIntegrate']:
3903                        Data['LRazimuth'][1] = int(azm)
3904                   
3905                    Data['LRazimuth'][0] %= 360
3906                    Data['LRazimuth'][1] %= 360
3907                    if Data['LRazimuth'][0] > Data['LRazimuth'][1]:
3908                        Data['LRazimuth'][1] += 360                       
3909                    if Data['fullIntegrate']:
3910                        Data['LRazimuth'][1] = Data['LRazimuth'][0]+360
3911                       
3912                    if  Data['IOtth'][0] > Data['IOtth'][1]:
3913                        Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
3914                       
3915                    G2frame.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
3916                    G2frame.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
3917                    G2frame.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
3918                    G2frame.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
3919                elif 'Circle' in itemPicked and PickName == 'Masks':
3920                    spots = Masks['Points']
3921                    newPos = itemPicked.split(')')[0].split('(')[2].split(',')
3922                    newPos = np.array([float(newPos[0]),float(newPos[1])])
3923                    for spot in spots:
3924                        if spot and np.allclose(np.array([spot[:2]]),newPos):
3925                            spot[:2] = Xpos,Ypos
3926                    G2imG.UpdateMasks(G2frame,Masks)
3927                elif 'Line2D' in itemPicked and PickName == 'Masks':
3928                    Obj = G2frame.itemPicked.findobj()
3929                    rings = Masks['Rings']
3930                    arcs = Masks['Arcs']
3931                    polygons = Masks['Polygons']
3932                    frame = Masks['Frames']
3933                    for ring in G2frame.ringList:
3934                        if Obj == ring[0]:
3935                            rN = ring[1]
3936                            if ring[2] == 'o':
3937                                rings[rN][0] = G2img.GetTth(Xpos,Ypos,Data)-rings[rN][1]/2.
3938                            else:
3939                                rings[rN][0] = G2img.GetTth(Xpos,Ypos,Data)+rings[rN][1]/2.
3940                    for arc in G2frame.arcList:
3941                        if Obj == arc[0]:
3942                            aN = arc[1]
3943                            if arc[2] == 'o':
3944                                arcs[aN][0] = G2img.GetTth(Xpos,Ypos,Data)-arcs[aN][2]/2
3945                            elif arc[2] == 'i':
3946                                arcs[aN][0] = G2img.GetTth(Xpos,Ypos,Data)+arcs[aN][2]/2
3947                            elif arc[2] == 'l':
3948                                arcs[aN][1][0] = int(G2img.GetAzm(Xpos,Ypos,Data))
3949                            else:
3950                                arcs[aN][1][1] = int(G2img.GetAzm(Xpos,Ypos,Data))
3951                    for poly in G2frame.polyList:   #merging points problem here?
3952                        if Obj == poly[0]:
3953                            ind = G2frame.itemPicked.contains(G2frame.mousePicked)[1]['ind'][0]
3954                            oldPos = np.array([G2frame.mousePicked.xdata,G2frame.mousePicked.ydata])
3955                            pN = poly[1]
3956                            for i,xy in enumerate(polygons[pN]):
3957                                if np.allclose(np.array([xy]),oldPos,atol=1.0):
3958                                    if event.button == 1:
3959                                        polygons[pN][i] = Xpos,Ypos
3960                                    elif event.button == 3:
3961                                        polygons[pN].insert(i,[Xpos,Ypos])
3962                                        break
3963                    if frame:
3964                        oldPos = np.array([G2frame.mousePicked.xdata,G2frame.mousePicked.ydata])
3965                        for i,xy in enumerate(frame):
3966                            if np.allclose(np.array([xy]),oldPos,atol=1.0):
3967                                if event.button == 1:
3968                                    frame[i] = Xpos,Ypos
3969                                elif event.button == 3:
3970                                    frame.insert(i,[Xpos,Ypos])
3971                                    break
3972                    G2imG.UpdateMasks(G2frame,Masks)
3973#                else:                  #keep for future debugging
3974#                    print str(G2frame.itemPicked),event.xdata,event.ydata,event.button
3975            wx.CallAfter(PlotImage,G2frame,newImage=True)
3976            G2frame.itemPicked = None
3977           
3978    # PlotImage execution starts here
3979    xylim = []
3980    try:
3981        plotNum = G2frame.G2plotNB.plotList.index('2D Powder Image')
3982        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3983        if not newPlot:
3984            Plot = Page.figure.gca()          #get previous powder plot & get limits
3985            xylim = Plot.get_xlim(),Plot.get_ylim()
3986        if newImage:
3987            Page.figure.clf()
3988            Plot = Page.figure.gca()          #get a fresh plot after clf()
3989    except ValueError:
3990        Plot = G2frame.G2plotNB.addMpl('2D Powder Image').gca()
3991        plotNum = G2frame.G2plotNB.plotList.index('2D Powder Image')
3992        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3993        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
3994        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
3995        Page.canvas.mpl_connect('pick_event', OnImPick)
3996        Page.canvas.mpl_connect('button_release_event', OnImRelease)
3997        xylim = []
3998    Page.Choice = None
3999    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
4000        Page.SetFocus()
4001    Title = G2frame.PatternTree.GetItemText(G2frame.Image)[4:]
4002    G2frame.G2plotNB.status.DestroyChildren()
4003    if G2frame.logPlot:
4004        Title = 'log('+Title+')'
4005    Plot.set_title(Title)
4006    try:
4007        if G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Image Controls',]:
4008            Page.Choice = (' key press','l: log(I) on','x: flip x','y: flip y',)
4009            if G2frame.logPlot:
4010                Page.Choice[1] = 'l: log(I) off'
4011            Page.keyPress = OnImPlotKeyPress
4012        elif G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Masks',]:
4013            Page.Choice = (' key press','l: log(I) on','s: spot mask','a: arc mask','r: ring mask',
4014                'p: polygon mask','f: frame mask',)
4015            if G2frame.logPlot:
4016                Page.Choice[1] = 'l: log(I) off'
4017            Page.keyPress = OnImPlotKeyPress
4018        elif G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Stress/Strain',]:
4019            Page.Choice = (' key press','a: add new ring',)
4020            Page.keyPress = OnImPlotKeyPress
4021    except TypeError:
4022        pass
4023    size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(G2frame.Image)
4024    dark = Data.get('dark image',[0,''])
4025    if imagefile != G2frame.oldImagefile or G2frame.oldImageTag != imagetag or dark[0]: # always reread to apply dark correction
4026        imagefile = G2IO.CheckImageFile(G2frame,imagefile)
4027        if not imagefile:
4028            G2frame.G2plotNB.Delete('2D Powder Image')
4029            return
4030        if imagetag:
4031            G2frame.PatternTree.SetItemPyData(G2frame.Image,
4032                                              [size,(imagefile,imagetag)])
4033        else:
4034            G2frame.PatternTree.SetItemPyData(G2frame.Image,[size,imagefile])         
4035        G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,imageOnly=True,ImageTag=imagetag)
4036        if dark[0]:
4037            dsize,darkfile,darktag = G2frame.PatternTree.GetImageLoc(
4038                G2gd.GetPatternTreeItemId(G2frame,G2frame.root,dark[0]))
4039            darkImg = G2IO.GetImageData(G2frame,darkfile,imageOnly=True,ImageTag=darktag)
4040            G2frame.ImageZ += dark[1]*darkImg
4041        G2frame.oldImagefile = imagefile # save name of the last image file read
4042        G2frame.oldImageTag = imagetag   # save tag of the last image file read
4043    #else:
4044    #    if GSASIIpath.GetConfigValue('debug'): print('Skipping image reread')
4045
4046    imScale = 1
4047    if len(G2frame.ImageZ) > 1024:
4048        imScale = len(G2frame.ImageZ)/1024
4049    sizexy = Data['size']
4050    pixelSize = Data['pixelSize']
4051    scalex = 1000./pixelSize[0]
4052    scaley = 1000./pixelSize[1]
4053    Xmax = sizexy[0]*pixelSize[0]/1000.
4054    Ymax = sizexy[1]*pixelSize[1]/1000.
4055    xlim = (0,Xmax)
4056    ylim = (Ymax,0)
4057    Imin,Imax = Data['range'][1]
4058    acolor = mpl.cm.get_cmap(Data['color'])
4059    xcent,ycent = Data['center']
4060    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
4061    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
4062    #do threshold mask - "real" mask - others are just bondaries
4063    Zlim = Masks['Thresholds'][1]
4064    FlatBkg = Data.get('Flat Bkg',0.0)
4065    wx.BeginBusyCursor()
4066    try:
4067        if newImage:                   
4068            Imin,Imax = Data['range'][1]
4069            MA = ma.masked_greater(ma.masked_less(G2frame.ImageZ,Zlim[0]+FlatBkg),Zlim[1]+FlatBkg)
4070            MaskA = ma.getmaskarray(MA)
4071            A = G2img.ImageCompress(MA,imScale)-FlatBkg
4072            AM = G2img.ImageCompress(MaskA,imScale)
4073            if G2frame.logPlot:
4074                A = np.where(A>Imin,np.where(A<Imax,A,0),0)
4075                A = np.where(A>0,np.log(A),0)
4076                AM = np.where(AM>0,np.log(AM),0)
4077                Imin,Imax = [np.amin(A),np.amax(A)]
4078            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
4079                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Ymax,0])
4080            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
4081                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
4082   
4083        Plot.plot(xcent,ycent,'x')
4084        #G2frame.PatternTree.GetItemText(item)
4085        if Data['showLines']:
4086            LRAzim = Data['LRazimuth']                  #NB: integers
4087            Nazm = Data['outAzimuths']
4088            delAzm = float(LRAzim[1]-LRAzim[0])/Nazm
4089            AzmthOff = Data['azmthOff']
4090            IOtth = Data['IOtth']
4091            wave = Data['wavelength']
4092            dspI = wave/(2.0*sind(IOtth[0]/2.0))
4093            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
4094            dspO = wave/(2.0*sind(IOtth[1]/2.0))
4095            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
4096            Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
4097            if ellI:
4098                xyI = []
4099                for azm in Azm:
4100                    xy = G2img.GetDetectorXY(dspI,azm,Data)
4101                    if np.any(xy):
4102                        xyI.append(xy)
4103                if len(xyI):
4104                    xyI = np.array(xyI)
4105                    arcxI,arcyI = xyI.T
4106                    Plot.plot(arcxI,arcyI,picker=3)
4107            if ellO:
4108                xyO = []
4109                for azm in Azm:
4110                    xy = G2img.GetDetectorXY(dspO,azm,Data)
4111                    if np.any(xy):
4112                        xyO.append(xy)
4113                if len(xyO):
4114                    xyO = np.array(xyO)
4115                    arcxO,arcyO = xyO.T               
4116                    Plot.plot(arcxO,arcyO,picker=3)
4117            if ellO and ellI:
4118                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
4119                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
4120            for i in range(Nazm):
4121                cake = LRAzim[0]+i*delAzm-AzmthOff
4122                if Data['centerAzm']:
4123                    cake += delAzm/2.
4124                ind = np.searchsorted(Azm,cake)
4125                Plot.plot([arcxI[ind],arcxO[ind]],[arcyI[ind],arcyO[ind]],color='k',dashes=(5,5))
4126                   
4127        if G2frame.PatternTree.GetItemText(G2frame.PickId) in 'Image Controls':
4128            for xring,yring in Data['ring']:
4129                Plot.plot(xring,yring,'r+',picker=3)
4130            if Data['setRings']:
4131                N = 0
4132                for ring in Data['rings']:
4133                    xring,yring = np.array(ring).T[:2]
4134                    Plot.plot(xring,yring,'.',color=colors[N%6])
4135                    N += 1
4136            for ellipse in Data['ellipses']:      #what about hyperbola?
4137                cent,phi,[width,height],col = ellipse
4138                if width > 0:       #ellipses
4139                    Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
4140                    Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
4141        if G2frame.PatternTree.GetItemText(G2frame.PickId) in 'Stress/Strain':
4142            for N,ring in enumerate(StrSta['d-zero']):
4143                xring,yring = ring['ImxyObs']
4144                Plot.plot(xring,yring,colors[N%6]+'.')
4145        #masks - mask lines numbered after integration limit lines
4146        spots = Masks['Points']
4147        rings = Masks['Rings']
4148        arcs = Masks['Arcs']
4149        polygons = Masks['Polygons']
4150        if 'Frames' not in Masks:
4151            Masks['Frames'] = []
4152        frame = Masks['Frames']
4153        for spot in spots:
4154            if spot:
4155                x,y,d = spot
4156                Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
4157        G2frame.ringList = []
4158        for iring,ring in enumerate(rings):
4159            if ring:
4160                tth,thick = ring
4161                wave = Data['wavelength']
4162                xy1 = []
4163                xy2 = []
4164                Azm = np.linspace(0,362,181)
4165                for azm in Azm:
4166                    xy1.append(G2img.GetDetectorXY(Dsp(tth+thick/2.,wave),azm,Data))      #what about hyperbola
4167                    xy2.append(G2img.GetDetectorXY(Dsp(tth-thick/2.,wave),azm,Data))      #what about hyperbola
4168                x1,y1 = np.array(xy1).T
4169                x2,y2 = np.array(xy2).T
4170                G2frame.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
4171                G2frame.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
4172        G2frame.arcList = []
4173        for iarc,arc in enumerate(arcs):
4174            if arc:
4175                tth,azm,thick = arc           
4176                wave = Data['wavelength']
4177                xy1 = []
4178                xy2 = []
4179                aR = azm[0],azm[1],azm[1]-azm[0]
4180                if azm[1]-azm[0] > 180:
4181                    aR[2] /= 2
4182                Azm = np.linspace(aR[0],aR[1],aR[2])
4183                for azm in Azm:
4184                    xy1.append(G2img.GetDetectorXY(Dsp(tth+thick/2.,wave),azm,Data))      #what about hyperbola
4185                    xy2.append(G2img.GetDetectorXY(Dsp(tth-thick/2.,wave),azm,Data))      #what about hyperbola
4186                x1,y1 = np.array(xy1).T
4187                x2,y2 = np.array(xy2).T
4188                G2frame.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
4189                G2frame.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
4190                G2frame.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
4191                G2frame.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
4192        G2frame.polyList = []
4193        for ipoly,polygon in enumerate(polygons):
4194            if polygon:
4195                x,y = np.hsplit(np.array(polygon),2)
4196                G2frame.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
4197                Plot.plot(x,y,'r')           
4198        G2frame.frameList = []
4199        if frame:
4200            x,y = np.hsplit(np.array(frame),2)
4201            G2frame.frameList.append([Plot.plot(x,y,'g+',picker=10),0])
4202            Plot.plot(x,y,'g')           
4203        if newImage:
4204            colorBar = Page.figure.colorbar(Img)
4205        Plot.set_xlim(xlim)
4206        Plot.set_ylim(ylim)
4207        if Data['invert_x']:
4208            Plot.invert_xaxis()
4209        if Data['invert_y']:
4210            Plot.invert_yaxis()
4211        if not newPlot and xylim:
4212            Page.toolbar.push_current()
4213            Plot.set_xlim(xylim[0])
4214            Plot.set_ylim(xylim[1])
4215            xylim = []
4216            Page.toolbar.push_current()
4217            Page.toolbar.draw()
4218            # patch for wx 2.9 on Mac, to force a redraw
4219            i,j= wx.__version__.split('.')[0:2]
4220            if int(i)+int(j)/10. > 2.8 and 'wxOSX' in wx.PlatformInfo:
4221                Page.canvas.draw()
4222        else:
4223            Page.canvas.draw()
4224    finally:
4225        wx.EndBusyCursor()
4226       
4227################################################################################
4228##### PlotIntegration
4229################################################################################
4230           
4231def PlotIntegration(G2frame,newPlot=False,event=None):
4232    '''Plot of 2D image after image integration with 2-theta and azimuth as coordinates
4233    '''
4234           
4235    def OnMotion(event):
4236        Page.canvas.SetToolTipString('')
4237        Page.canvas.SetCursor(wx.CROSS_CURSOR)
4238        azm = event.ydata
4239        tth = event.xdata
4240        if azm and tth:
4241            G2frame.G2plotNB.status.SetFields(\
4242                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
4243                               
4244    try:
4245        plotNum = G2frame.G2plotNB.plotList.index('2D Integration')
4246        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
4247        if not newPlot:
4248            Plot = Page.figure.gca()          #get previous plot & get limits
4249            xylim = Plot.get_xlim(),Plot.get_ylim()
4250        Page.figure.clf()
4251        Plot = Page.figure.gca()          #get a fresh plot after clf()
4252       
4253    except ValueError:
4254        Plot = G2frame.G2plotNB.addMpl('2D Integration').gca()
4255        plotNum = G2frame.G2plotNB.plotList.index('2D Integration')
4256        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
4257        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
4258        Page.views = False
4259        view = False
4260    Page.Choice = None
4261    if not event:
4262        Page.SetFocus()
4263       
4264    Data = G2frame.PatternTree.GetItemPyData(
4265        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4266    image = G2frame.Integrate[0]
4267    xsc = G2frame.Integrate[1]
4268    ysc = G2frame.Integrate[2]
4269    Imin,Imax = Data['range'][1]
4270    acolor = mpl.cm.get_cmap(Data['color'])
4271    Plot.set_title(G2frame.PatternTree.GetItemText(G2frame.Image)[4:])
4272    Plot.set_ylabel('azimuth',fontsize=12)
4273    Plot.set_xlabel('2-theta',fontsize=12)
4274    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
4275        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
4276    colorBar = Page.figure.colorbar(Img)
4277#    if Data['ellipses']:           
4278#        for ellipse in Data['ellipses']:
4279#            x,y = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
4280#            tth,azm = G2img.GetTthAzm(x,y,Data)
4281##            azm = np.where(azm < 0.,azm+360,azm)
4282#            Plot.plot(tth,azm,'b,')
4283    if not newPlot:
4284        Page.toolbar.push_current()
4285        Plot.set_xlim(xylim[0])
4286        Plot.set_ylim(xylim[1])
4287        xylim = []
4288        Page.toolbar.push_current()
4289        Page.toolbar.draw()
4290    else:
4291        Page.canvas.draw()
4292               
4293################################################################################
4294##### PlotTRImage
4295################################################################################
4296           
4297def PlotTRImage(G2frame,tax,tay,taz,newPlot=False):
4298    '''a test plot routine - not normally used
4299    ''' 
4300           
4301    def OnMotion(event):
4302        Page.canvas.SetToolTipString('')
4303        Page.canvas.SetCursor(wx.CROSS_CURSOR)
4304        azm = event.xdata
4305        tth = event.ydata
4306        if azm and tth: