source: trunk/GSASIIplot.py @ 2107

Last change on this file since 2107 was 2107, checked in by toby, 7 years ago

Bug fix: 6. After changing mask input plot is redrawn reseting limits and sometimes with two scale bars.; zoom is fixed, reason for two scale bars is unclear, but I am taking a guess that recursive calls to PlotImage? could be the problem, wx.CallAfter? added to these.

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