source: trunk/GSASIIplot.py @ 2132

Last change on this file since 2132 was 2132, checked in by vondreele, 6 years ago

more rationalization of FWHM calculations

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