source: trunk/GSASIIplot.py @ 2106

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

more for Andrey: 3. no update on contour plot (change so y-axis is expanded); give up on 2. Load Controls” menu entry messes up plot redraw.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 240.0 KB
Line 
1# -*- coding: utf-8 -*-
2'''
3*GSASIIplot: plotting routines*
4===============================
5
6'''
7########### SVN repository information ###################
8# $Date: 2015-12-24 19:09:50 +0000 (Thu, 24 Dec 2015) $
9# $Author: toby $
10# $Revision: 2106 $
11# $URL: trunk/GSASIIplot.py $
12# $Id: GSASIIplot.py 2106 2015-12-24 19:09:50Z 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: 2106 $")
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') 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    from matplotlib.patches import Ellipse,Arc,Circle,Polygon
3604    import numpy.ma as ma
3605    Dsp = lambda tth,wave: wave/(2.*npsind(tth/2.))
3606    global Data,Masks,StrSta
3607    colors=['b','g','r','c','m','k']
3608    Data = G2frame.PatternTree.GetItemPyData(
3609        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
3610# patch
3611    if 'invert_x' not in Data:
3612        Data['invert_x'] = False
3613        Data['invert_y'] = True
3614# end patch
3615    Masks = G2frame.PatternTree.GetItemPyData(
3616        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
3617    try:    #may be absent
3618        StrSta = G2frame.PatternTree.GetItemPyData(
3619            G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Stress/Strain'))
3620    except TypeError:   #is missing
3621        StrSta = {}
3622
3623    def OnImMotion(event):
3624        Page.canvas.SetToolTipString('')
3625        sizexy = Data['size']
3626        FlatBkg = Data.get('Flat Bkg',0.)
3627        if event.xdata and event.ydata and len(G2frame.ImageZ):                 #avoid out of frame errors
3628            Page.canvas.SetToolTipString('%8.2f %8.2fmm'%(event.xdata,event.ydata))
3629            Page.canvas.SetCursor(wx.CROSS_CURSOR)
3630            item = G2frame.itemPicked
3631            pixelSize = Data['pixelSize']
3632            scalex = 1000./pixelSize[0]
3633            scaley = 1000./pixelSize[1]
3634            if item and G2frame.PatternTree.GetItemText(G2frame.PickId) == 'Image Controls':
3635                if 'Text' in str(item):
3636                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
3637                else:
3638                    xcent,ycent = Data['center']
3639                    xpos = event.xdata-xcent
3640                    ypos = event.ydata-ycent
3641                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
3642                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
3643                        Page.canvas.SetToolTipString('%6d deg'%(azm))
3644                    elif 'line1' in  str(item) or 'line2' in str(item):
3645                        Page.canvas.SetToolTipString('%8.3f deg'%(tth))                           
3646            else:
3647                xpos = event.xdata
3648                ypos = event.ydata
3649                xpix = xpos*scalex
3650                ypix = ypos*scaley
3651                Int = 0
3652                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
3653                    Int = G2frame.ImageZ[ypix][xpix]-int(FlatBkg)
3654                tth,azm,D,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
3655                Q = 2.*math.pi/dsp
3656                fields = ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)]
3657                if G2frame.MaskKey in ['p','f']:
3658                    fields[1] = 'Polygon/frame mask pick - LB next point, RB close polygon'
3659                elif G2frame.StrainKey:
3660                    fields[0] = 'd-zero pick active'
3661                G2frame.G2plotNB.status.SetFields(fields)
3662
3663    def OnImPlotKeyPress(event):
3664        try:
3665            PickName = G2frame.PatternTree.GetItemText(G2frame.PickId)
3666        except TypeError:
3667            return
3668        if PickName == 'Masks':
3669            if event.key in ['l','p','f','s','a','r']:
3670                G2frame.MaskKey = event.key
3671                OnStartMask(G2frame)
3672                PlotImage(G2frame,newPlot=False)
3673               
3674        elif PickName == 'Stress/Strain':
3675            if event.key in ['a',]:
3676                G2frame.StrainKey = event.key
3677                StrSta = OnStartNewDzero(G2frame)
3678                PlotImage(G2frame,newPlot=False)
3679               
3680        elif PickName == 'Image Controls':
3681            if event.key in ['c',]:
3682                Xpos = event.xdata
3683                if not Xpos:            #got point out of frame
3684                    return
3685                Ypos = event.ydata
3686                dlg = wx.MessageDialog(G2frame,'Are you sure you want to change the center?',
3687                    'Center change',style=wx.OK|wx.CANCEL)
3688                try:
3689                    if dlg.ShowModal() == wx.ID_OK:
3690                        print 'move center to: ',Xpos,Ypos
3691                        Data['center'] = [Xpos,Ypos]
3692                        G2imG.UpdateImageControls(G2frame,Data,Masks)
3693                        PlotImage(G2frame,newPlot=False)
3694                finally:
3695                    dlg.Destroy()
3696                return
3697            elif event.key == 'l':
3698                G2frame.logPlot = not G2frame.logPlot
3699            elif event.key in ['x',]:
3700                Data['invert_x'] = not Data['invert_x']
3701            elif event.key in ['y',]:
3702                Data['invert_y'] = not Data['invert_y']
3703            PlotImage(G2frame,newPlot=True)
3704           
3705    def OnKeyBox(event):
3706        if G2frame.G2plotNB.nb.GetSelection() == G2frame.G2plotNB.plotList.index('2D Powder Image'):
3707            event.key = cb.GetValue()[0]
3708            cb.SetValue(' key press')
3709            if event.key in ['l','s','a','r','p','x','y']:
3710                wx.CallAfter(OnImPlotKeyPress,event)
3711        Page.canvas.SetFocus() # redirect the Focus from the button back to the plot
3712                       
3713    def OnImPick(event):
3714        if G2frame.PatternTree.GetItemText(G2frame.PickId) not in ['Image Controls','Masks']:
3715            return
3716        if G2frame.itemPicked is not None: return
3717        G2frame.itemPicked = event.artist
3718        G2frame.mousePicked = event.mouseevent
3719       
3720    def OnImRelease(event):
3721        try:
3722            PickName = G2frame.PatternTree.GetItemText(G2frame.PickId)
3723        except TypeError:
3724            return
3725        if PickName not in ['Image Controls','Masks','Stress/Strain']:
3726            return
3727        pixelSize = Data['pixelSize']
3728        FlatBkg = Data.get('Flat Bkg',0.)
3729        scalex = 1000./pixelSize[0]
3730        scaley = 1000./pixelSize[1]
3731#        pixLimit = Data['pixLimit']    #can be too tight
3732        pixLimit = 20       #this makes the search box 40x40 pixels
3733        if G2frame.itemPicked is None and PickName == 'Image Controls' and len(G2frame.ImageZ):
3734            Xpos = event.xdata
3735            if not (Xpos and G2frame.ifGetRing):                   #got point out of frame
3736                return
3737            Ypos = event.ydata
3738            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
3739                if event.button == 1:
3740                    Xpix = Xpos*scalex
3741                    Ypix = Ypos*scaley
3742                    xpos,ypos,I,J = G2img.ImageLocalMax(G2frame.ImageZ-FlatBkg,pixLimit,Xpix,Ypix)
3743                    if I and J:
3744                        xpos += .5                              #shift to pixel center
3745                        ypos += .5
3746                        xpos /= scalex                          #convert to mm
3747                        ypos /= scaley
3748                        Data['ring'].append([xpos,ypos])
3749                elif event.button == 3:
3750                    G2frame.dataFrame.GetStatusBar().SetStatusText('Calibrating...',0)
3751                    if G2img.ImageCalibrate(G2frame,Data):
3752                        G2frame.dataFrame.GetStatusBar().SetStatusText('Calibration successful - Show ring picks to check',0)
3753                        print 'Calibration successful'
3754                    else:
3755                        G2frame.dataFrame.GetStatusBar().SetStatusText('Calibration failed - Show ring picks to diagnose',0)
3756                        print 'Calibration failed'
3757                    G2frame.ifGetRing = False
3758                    G2imG.UpdateImageControls(G2frame,Data,Masks)
3759                    return
3760                PlotImage(G2frame,newImage=False)
3761            return
3762        elif G2frame.MaskKey and PickName == 'Masks':
3763            Xpos,Ypos = [event.xdata,event.ydata]
3764            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
3765                return
3766            if G2frame.MaskKey == 's' and event.button == 1:
3767                Masks['Points'][-1] = [Xpos,Ypos,1.]
3768                G2frame.MaskKey = ''               
3769            elif G2frame.MaskKey == 'r' and event.button == 1:
3770                tth = G2img.GetTth(Xpos,Ypos,Data)
3771                Masks['Rings'][-1] = [tth,0.1]
3772                G2frame.MaskKey = ''               
3773            elif G2frame.MaskKey == 'a' and event.button == 1:
3774                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
3775                azm = int(azm)               
3776                Masks['Arcs'][-1] = [tth,[azm-5,azm+5],0.1]
3777                G2frame.MaskKey = ''               
3778            elif G2frame.MaskKey =='p':
3779                polygon = Masks['Polygons'][-1]
3780                if len(polygon) > 2 and event.button == 3:
3781                    x0,y0 = polygon[0]
3782                    polygon.append([x0,y0])
3783                    G2frame.MaskKey = ''
3784                    G2frame.G2plotNB.status.SetFields(['','Polygon closed'])
3785                else:
3786                    G2frame.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(Xpos,Ypos)])
3787                    polygon.append([Xpos,Ypos])
3788            elif G2frame.MaskKey =='f':
3789                frame = Masks['Frames']
3790                if len(frame) > 2 and event.button == 3:
3791                    x0,y0 = frame[0]
3792                    frame.append([x0,y0])
3793                    G2frame.MaskKey = ''
3794                    G2frame.G2plotNB.status.SetFields(['','Frame closed'])
3795                else:
3796                    G2frame.G2plotNB.status.SetFields(['','New frame point: %.1f,%.1f'%(Xpos,Ypos)])
3797                    frame.append([Xpos,Ypos])
3798            G2imG.UpdateMasks(G2frame,Masks)
3799            PlotImage(G2frame,newImage=False)
3800        elif PickName == 'Stress/Strain' and G2frame.StrainKey:
3801            Xpos,Ypos = [event.xdata,event.ydata]
3802            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
3803                return
3804            dsp = G2img.GetDsp(Xpos,Ypos,Data)
3805            StrSta['d-zero'].append({'Dset':dsp,'Dcalc':0.0,'pixLimit':10,'cutoff':0.5,
3806                'ImxyObs':[[],[]],'ImtaObs':[[],[]],'ImtaCalc':[[],[]],'Emat':[1.0,1.0,1.0]})
3807            R,r = G2img.MakeStrStaRing(StrSta['d-zero'][-1],G2frame.ImageZ-FlatBkg,Data)
3808            if not len(R):
3809                del StrSta['d-zero'][-1]
3810                G2frame.ErrorDialog('Strain peak selection','WARNING - No points found for this ring selection')
3811            StrSta['d-zero'] = G2mth.sortArray(StrSta['d-zero'],'Dset',reverse=True)
3812            G2frame.StrainKey = ''
3813            G2imG.UpdateStressStrain(G2frame,StrSta)
3814            PlotStrain(G2frame,StrSta)
3815            PlotImage(G2frame,newPlot=False)           
3816        else:
3817            Xpos,Ypos = [event.xdata,event.ydata]
3818            if not Xpos or not Ypos or Page.toolbar._active:  #got point out of frame or zoom/pan selected
3819                return
3820            if G2frame.ifGetRing:                          #delete a calibration ring pick
3821                xypos = [Xpos,Ypos]
3822                rings = Data['ring']
3823                for ring in rings:
3824                    if np.allclose(ring,xypos,.01,0):
3825                        rings.remove(ring)
3826            else:
3827                tth,azm,dsp = G2img.GetTthAzmDsp(Xpos,Ypos,Data)[:3]
3828                itemPicked = str(G2frame.itemPicked)
3829                if 'Line2D' in itemPicked and PickName == 'Image Controls':
3830                    if 'line1' in itemPicked:
3831                        Data['IOtth'][0] = max(tth,0.001)
3832                    elif 'line2' in itemPicked:
3833                        Data['IOtth'][1] = tth
3834                    elif 'line3' in itemPicked:
3835                        Data['LRazimuth'][0] = int(azm)
3836                    elif 'line4' in itemPicked and not Data['fullIntegrate']:
3837                        Data['LRazimuth'][1] = int(azm)
3838                   
3839                    Data['LRazimuth'][0] %= 360
3840                    Data['LRazimuth'][1] %= 360
3841                    if Data['LRazimuth'][0] > Data['LRazimuth'][1]:
3842                        Data['LRazimuth'][1] += 360                       
3843                    if Data['fullIntegrate']:
3844                        Data['LRazimuth'][1] = Data['LRazimuth'][0]+360
3845                       
3846                    if  Data['IOtth'][0] > Data['IOtth'][1]:
3847                        Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
3848                       
3849                    G2frame.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
3850                    G2frame.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
3851                    G2frame.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
3852                    G2frame.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
3853                elif 'Circle' in itemPicked and PickName == 'Masks':
3854                    spots = Masks['Points']
3855                    newPos = itemPicked.split(')')[0].split('(')[2].split(',')
3856                    newPos = np.array([float(newPos[0]),float(newPos[1])])
3857                    for spot in spots:
3858                        if spot and np.allclose(np.array([spot[:2]]),newPos):
3859                            spot[:2] = Xpos,Ypos
3860                    G2imG.UpdateMasks(G2frame,Masks)
3861                elif 'Line2D' in itemPicked and PickName == 'Masks':
3862                    Obj = G2frame.itemPicked.findobj()
3863                    rings = Masks['Rings']
3864                    arcs = Masks['Arcs']
3865                    polygons = Masks['Polygons']
3866                    frame = Masks['Frames']
3867                    for ring in G2frame.ringList:
3868                        if Obj == ring[0]:
3869                            rN = ring[1]
3870                            if ring[2] == 'o':
3871                                rings[rN][0] = G2img.GetTth(Xpos,Ypos,Data)-rings[rN][1]/2.
3872                            else:
3873                                rings[rN][0] = G2img.GetTth(Xpos,Ypos,Data)+rings[rN][1]/2.
3874                    for arc in G2frame.arcList:
3875                        if Obj == arc[0]:
3876                            aN = arc[1]
3877                            if arc[2] == 'o':
3878                                arcs[aN][0] = G2img.GetTth(Xpos,Ypos,Data)-arcs[aN][2]/2
3879                            elif arc[2] == 'i':
3880                                arcs[aN][0] = G2img.GetTth(Xpos,Ypos,Data)+arcs[aN][2]/2
3881                            elif arc[2] == 'l':
3882                                arcs[aN][1][0] = int(G2img.GetAzm(Xpos,Ypos,Data))
3883                            else:
3884                                arcs[aN][1][1] = int(G2img.GetAzm(Xpos,Ypos,Data))
3885                    for poly in G2frame.polyList:   #merging points problem here?
3886                        if Obj == poly[0]:
3887                            ind = G2frame.itemPicked.contains(G2frame.mousePicked)[1]['ind'][0]
3888                            oldPos = np.array([G2frame.mousePicked.xdata,G2frame.mousePicked.ydata])
3889                            pN = poly[1]
3890                            for i,xy in enumerate(polygons[pN]):
3891                                if np.allclose(np.array([xy]),oldPos,atol=1.0):
3892                                    if event.button == 1:
3893                                        polygons[pN][i] = Xpos,Ypos
3894                                    elif event.button == 3:
3895                                        polygons[pN].insert(i,[Xpos,Ypos])
3896                                        break
3897                    if frame:
3898                        oldPos = np.array([G2frame.mousePicked.xdata,G2frame.mousePicked.ydata])
3899                        for i,xy in enumerate(frame):
3900                            if np.allclose(np.array([xy]),oldPos,atol=1.0):
3901                                if event.button == 1:
3902                                    frame[i] = Xpos,Ypos
3903                                elif event.button == 3:
3904                                    frame.insert(i,[Xpos,Ypos])
3905                                    break
3906                    G2imG.UpdateMasks(G2frame,Masks)
3907#                else:                  #keep for future debugging
3908#                    print str(G2frame.itemPicked),event.xdata,event.ydata,event.button
3909            PlotImage(G2frame,newImage=True)
3910            G2frame.itemPicked = None
3911           
3912    # PlotImage execution starts here       
3913    xylim = []
3914    try:
3915        plotNum = G2frame.G2plotNB.plotList.index('2D Powder Image')
3916        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3917        if not newPlot:
3918            Plot = Page.figure.gca()          #get previous powder plot & get limits
3919            xylim = Plot.get_xlim(),Plot.get_ylim()
3920        if newImage:
3921            Page.figure.clf()
3922            Plot = Page.figure.gca()          #get a fresh plot after clf()
3923    except ValueError:
3924        Plot = G2frame.G2plotNB.addMpl('2D Powder Image').gca()
3925        plotNum = G2frame.G2plotNB.plotList.index('2D Powder Image')
3926        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
3927        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
3928        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
3929        Page.canvas.mpl_connect('pick_event', OnImPick)
3930        Page.canvas.mpl_connect('button_release_event', OnImRelease)
3931        xylim = []
3932    Page.Choice = None
3933    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
3934        Page.SetFocus()
3935    Title = G2frame.PatternTree.GetItemText(G2frame.Image)[4:]
3936    G2frame.G2plotNB.status.DestroyChildren()
3937    if G2frame.logPlot:
3938        Title = 'log('+Title+')'
3939    Plot.set_title(Title)
3940    try:
3941        if G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Image Controls',]:
3942            Page.Choice = (' key press','l: log(I) on','x: flip x','y: flip y',)
3943            if G2frame.logPlot:
3944                Page.Choice[1] = 'l: log(I) off'
3945            Page.keyPress = OnImPlotKeyPress
3946        elif G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Masks',]:
3947            Page.Choice = (' key press','l: log(I) on','s: spot mask','a: arc mask','r: ring mask',
3948                'p: polygon mask','f: frame mask',)
3949            if G2frame.logPlot:
3950                Page.Choice[1] = 'l: log(I) off'
3951            Page.keyPress = OnImPlotKeyPress
3952        elif G2frame.PatternTree.GetItemText(G2frame.PickId) in ['Stress/Strain',]:
3953            Page.Choice = (' key press','a: add new ring',)
3954            Page.keyPress = OnImPlotKeyPress
3955    except TypeError:
3956        pass
3957    size,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(G2frame.Image)
3958    dark = Data.get('dark image',[0,''])
3959    if imagefile != G2frame.oldImagefile or G2frame.oldImageTag != imagetag or dark[0]: # always reread to apply dark correction
3960        imagefile = G2IO.CheckImageFile(G2frame,imagefile)
3961        if not imagefile:
3962            G2frame.G2plotNB.Delete('2D Powder Image')
3963            return
3964        if imagetag:
3965            G2frame.PatternTree.SetItemPyData(G2frame.Image,
3966                                              [size,(imagefile,imagetag)])
3967        else:
3968            G2frame.PatternTree.SetItemPyData(G2frame.Image,[size,imagefile])         
3969        G2frame.ImageZ = G2IO.GetImageData(G2frame,imagefile,imageOnly=True,ImageTag=imagetag)
3970        if dark[0]:
3971            dsize,darkfile,darktag = G2frame.PatternTree.GetImageLoc(
3972                G2gd.GetPatternTreeItemId(G2frame,G2frame.root,dark[0]))
3973            darkImg = G2IO.GetImageData(G2frame,darkfile,imageOnly=True,ImageTag=darktag)
3974            G2frame.ImageZ += dark[1]*darkImg
3975        G2frame.oldImagefile = imagefile # save name of the last image file read
3976        G2frame.oldImageTag = imagetag   # save tag of the last image file read
3977    #else:
3978    #    if GSASIIpath.GetConfigValue('debug'): print('Skipping image reread')
3979
3980    imScale = 1
3981    if len(G2frame.ImageZ) > 1024:
3982        imScale = len(G2frame.ImageZ)/1024
3983    sizexy = Data['size']
3984    pixelSize = Data['pixelSize']
3985    scalex = 1000./pixelSize[0]
3986    scaley = 1000./pixelSize[1]
3987    Xmax = sizexy[0]*pixelSize[0]/1000.
3988    Ymax = sizexy[1]*pixelSize[1]/1000.
3989    xlim = (0,Xmax)
3990    ylim = (Ymax,0)
3991    Imin,Imax = Data['range'][1]
3992    acolor = mpl.cm.get_cmap(Data['color'])
3993    xcent,ycent = Data['center']
3994    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
3995    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
3996    #do threshold mask - "real" mask - others are just bondaries
3997    Zlim = Masks['Thresholds'][1]
3998    FlatBkg = Data.get('Flat Bkg',0.0)
3999    wx.BeginBusyCursor()
4000    try:
4001           
4002        if newImage:                   
4003            Imin,Imax = Data['range'][1]
4004            MA = ma.masked_greater(ma.masked_less(G2frame.ImageZ,Zlim[0]+FlatBkg),Zlim[1]+FlatBkg)
4005            MaskA = ma.getmaskarray(MA)
4006            A = G2img.ImageCompress(MA,imScale)-FlatBkg
4007            AM = G2img.ImageCompress(MaskA,imScale)
4008            if G2frame.logPlot:
4009                A = np.where(A>Imin,np.where(A<Imax,A,0),0)
4010                A = np.where(A>0,np.log(A),0)
4011                AM = np.where(AM>0,np.log(AM),0)
4012                Imin,Imax = [np.amin(A),np.amax(A)]
4013            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
4014                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Ymax,0])
4015            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
4016                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
4017   
4018        Plot.plot(xcent,ycent,'x')
4019        #G2frame.PatternTree.GetItemText(item)
4020        if Data['showLines']:
4021            LRAzim = Data['LRazimuth']                  #NB: integers
4022            Nazm = Data['outAzimuths']
4023            delAzm = float(LRAzim[1]-LRAzim[0])/Nazm
4024            AzmthOff = Data['azmthOff']
4025            IOtth = Data['IOtth']
4026            wave = Data['wavelength']
4027            dspI = wave/(2.0*sind(IOtth[0]/2.0))
4028            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
4029            dspO = wave/(2.0*sind(IOtth[1]/2.0))
4030            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
4031            Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
4032            if ellI:
4033                xyI = []
4034                for azm in Azm:
4035                    xy = G2img.GetDetectorXY(dspI,azm,Data)
4036                    if np.any(xy):
4037                        xyI.append(xy)
4038                if len(xyI):
4039                    xyI = np.array(xyI)
4040                    arcxI,arcyI = xyI.T
4041                    Plot.plot(arcxI,arcyI,picker=3)
4042            if ellO:
4043                xyO = []
4044                for azm in Azm:
4045                    xy = G2img.GetDetectorXY(dspO,azm,Data)
4046                    if np.any(xy):
4047                        xyO.append(xy)
4048                if len(xyO):
4049                    xyO = np.array(xyO)
4050                    arcxO,arcyO = xyO.T               
4051                    Plot.plot(arcxO,arcyO,picker=3)
4052            if ellO and ellI:
4053                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
4054                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
4055            for i in range(Nazm):
4056                cake = LRAzim[0]+i*delAzm-AzmthOff
4057                if Data['centerAzm']:
4058                    cake += delAzm/2.
4059                ind = np.searchsorted(Azm,cake)
4060                Plot.plot([arcxI[ind],arcxO[ind]],[arcyI[ind],arcyO[ind]],color='k',dashes=(5,5))
4061                   
4062        if G2frame.PatternTree.GetItemText(G2frame.PickId) in 'Image Controls':
4063            for xring,yring in Data['ring']:
4064                Plot.plot(xring,yring,'r+',picker=3)
4065            if Data['setRings']:
4066                N = 0
4067                for ring in Data['rings']:
4068                    xring,yring = np.array(ring).T[:2]
4069                    Plot.plot(xring,yring,'.',color=colors[N%6])
4070                    N += 1           
4071            for ellipse in Data['ellipses']:      #what about hyperbola?
4072                cent,phi,[width,height],col = ellipse
4073                if width > 0:       #ellipses
4074                    Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
4075                    Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
4076        if G2frame.PatternTree.GetItemText(G2frame.PickId) in 'Stress/Strain':
4077            for N,ring in enumerate(StrSta['d-zero']):
4078                xring,yring = ring['ImxyObs']
4079                Plot.plot(xring,yring,colors[N%6]+'.')
4080        #masks - mask lines numbered after integration limit lines
4081        spots = Masks['Points']
4082        rings = Masks['Rings']
4083        arcs = Masks['Arcs']
4084        polygons = Masks['Polygons']
4085        if 'Frames' not in Masks:
4086            Masks['Frames'] = []
4087        frame = Masks['Frames']
4088        for spot in spots:
4089            if spot:
4090                x,y,d = spot
4091                Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
4092        G2frame.ringList = []
4093        for iring,ring in enumerate(rings):
4094            if ring:
4095                tth,thick = ring
4096                wave = Data['wavelength']
4097                xy1 = []
4098                xy2 = []
4099                Azm = np.linspace(0,362,181)
4100                for azm in Azm:
4101                    xy1.append(G2img.GetDetectorXY(Dsp(tth+thick/2.,wave),azm,Data))      #what about hyperbola
4102                    xy2.append(G2img.GetDetectorXY(Dsp(tth-thick/2.,wave),azm,Data))      #what about hyperbola
4103                x1,y1 = np.array(xy1).T
4104                x2,y2 = np.array(xy2).T
4105                G2frame.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
4106                G2frame.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
4107        G2frame.arcList = []
4108        for iarc,arc in enumerate(arcs):
4109            if arc:
4110                tth,azm,thick = arc           
4111                wave = Data['wavelength']
4112                xy1 = []
4113                xy2 = []
4114                aR = azm[0],azm[1],azm[1]-azm[0]
4115                if azm[1]-azm[0] > 180:
4116                    aR[2] /= 2
4117                Azm = np.linspace(aR[0],aR[1],aR[2])
4118                for azm in Azm:
4119                    xy1.append(G2img.GetDetectorXY(Dsp(tth+thick/2.,wave),azm,Data))      #what about hyperbola
4120                    xy2.append(G2img.GetDetectorXY(Dsp(tth-thick/2.,wave),azm,Data))      #what about hyperbola
4121                x1,y1 = np.array(xy1).T
4122                x2,y2 = np.array(xy2).T
4123                G2frame.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
4124                G2frame.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
4125                G2frame.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
4126                G2frame.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
4127        G2frame.polyList = []
4128        for ipoly,polygon in enumerate(polygons):
4129            if polygon:
4130                x,y = np.hsplit(np.array(polygon),2)
4131                G2frame.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
4132                Plot.plot(x,y,'r')           
4133        G2frame.frameList = []
4134        if frame:
4135            x,y = np.hsplit(np.array(frame),2)
4136            G2frame.frameList.append([Plot.plot(x,y,'g+',picker=10),0])
4137            Plot.plot(x,y,'g')           
4138        if newImage:
4139            colorBar = Page.figure.colorbar(Img)
4140        Plot.set_xlim(xlim)
4141        Plot.set_ylim(ylim)
4142        if Data['invert_x']:
4143            Plot.invert_xaxis()
4144        if Data['invert_y']:
4145            Plot.invert_yaxis()
4146        if not newPlot and xylim:
4147            Page.toolbar.push_current()
4148            Plot.set_xlim(xylim[0])
4149            Plot.set_ylim(xylim[1])
4150            xylim = []
4151            Page.toolbar.push_current()
4152            Page.toolbar.draw()
4153            # patch for wx 2.9 on Mac, to force a redraw
4154            i,j= wx.__version__.split('.')[0:2]
4155            if int(i)+int(j)/10. > 2.8 and 'wxOSX' in wx.PlatformInfo:
4156                Page.canvas.draw()
4157        else:
4158            Page.canvas.draw()
4159    finally:
4160        wx.EndBusyCursor()
4161       
4162################################################################################
4163##### PlotIntegration
4164################################################################################
4165           
4166def PlotIntegration(G2frame,newPlot=False,event=None):
4167    '''Plot of 2D image after image integration with 2-theta and azimuth as coordinates
4168    '''
4169           
4170    def OnMotion(event):
4171        Page.canvas.SetToolTipString('')
4172        Page.canvas.SetCursor(wx.CROSS_CURSOR)
4173        azm = event.ydata
4174        tth = event.xdata
4175        if azm and tth:
4176            G2frame.G2plotNB.status.SetFields(\
4177                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
4178                               
4179    try:
4180        plotNum = G2frame.G2plotNB.plotList.index('2D Integration')
4181        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
4182        if not newPlot:
4183            Plot = Page.figure.gca()          #get previous plot & get limits
4184            xylim = Plot.get_xlim(),Plot.get_ylim()
4185        Page.figure.clf()
4186        Plot = Page.figure.gca()          #get a fresh plot after clf()
4187       
4188    except ValueError:
4189        Plot = G2frame.G2plotNB.addMpl('2D Integration').gca()
4190        plotNum = G2frame.G2plotNB.plotList.index('2D Integration')
4191        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
4192        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
4193        Page.views = False
4194        view = False
4195    Page.Choice = None
4196    if not event:
4197        Page.SetFocus()
4198       
4199    Data = G2frame.PatternTree.GetItemPyData(
4200        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4201    image = G2frame.Integrate[0]
4202    xsc = G2frame.Integrate[1]
4203    ysc = G2frame.Integrate[2]
4204    Imin,Imax = Data['range'][1]
4205    acolor = mpl.cm.get_cmap(Data['color'])
4206    Plot.set_title(G2frame.PatternTree.GetItemText(G2frame.Image)[4:])
4207    Plot.set_ylabel('azimuth',fontsize=12)
4208    Plot.set_xlabel('2-theta',fontsize=12)
4209    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
4210        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
4211    colorBar = Page.figure.colorbar(Img)
4212#    if Data['ellipses']:           
4213#        for ellipse in Data['ellipses']:
4214#            x,y = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
4215#            tth,azm = G2img.GetTthAzm(x,y,Data)
4216##            azm = np.where(azm < 0.,azm+360,azm)
4217#            Plot.plot(tth,azm,'b,')
4218    if not newPlot:
4219        Page.toolbar.push_current()
4220        Plot.set_xlim(xylim[0])
4221        Plot.set_ylim(xylim[1])
4222        xylim = []
4223        Page.toolbar.push_current()
4224        Page.toolbar.draw()
4225    else:
4226        Page.canvas.draw()
4227               
4228################################################################################
4229##### PlotTRImage
4230################################################################################
4231           
4232def PlotTRImage(G2frame,tax,tay,taz,newPlot=False):
4233    '''a test plot routine - not normally used
4234    ''' 
4235           
4236    def OnMotion(event):
4237        Page.canvas.SetToolTipString('')
4238        Page.canvas.SetCursor(wx.CROSS_CURSOR)
4239        azm = event.xdata
4240        tth = event.ydata
4241        if azm and tth:
4242            G2frame.G2plotNB.status.SetFields(\
4243                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
4244                               
4245    try:
4246        plotNum = G2frame.G2plotNB.plotList.index('2D Transformed Powder Image')
4247        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
4248        if not newPlot:
4249            Plot = Page.figure.gca()          #get previous plot & get limits
4250            xylim = Plot.get_xlim(),Plot.get_ylim()
4251        Page.figure.clf()
4252        Plot = Page.figure.gca()          #get a fresh plot after clf()
4253       
4254    except ValueError:
4255        Plot = G2frame.G2plotNB.addMpl('2D Transformed Powder Image').gca()
4256        plotNum = G2frame.G2plotNB.plotList.index('2D Transformed Powder Image')
4257        Page = G2frame.G2plotNB.nb.GetPage(plotNum)
4258        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
4259        Page.views = False
4260        view = False
4261    Page.Choice = None
4262    Page.SetFocus()
4263       
4264    Data = G2frame.PatternTree.GetItemPyData(
4265        G2gd.GetPatternTreeItemId(G2frame,G2frame.Image, 'Image Controls'))
4266    Imin,Imax = Data['range'][1]
4267    step = (Imax-Imin)/5.
4268    V = np.arange(Imin,Imax,step)
4269    acolor = mpl.cm.get_cmap(Data['color'])
4270    Plot.set_title(G2frame.PatternTree.GetItemText(G2frame.Image)[4:])
4271    Plot.set_xlabel('azimuth',fontsize=12)
4272    Plot.set_ylabel('2-theta',fontsize=12)
4273    Plot.contour(tax,tay,taz,V,cmap=acolor)
4274    if Data['showLines']:
4275        IOtth = Data['IOtth']
4276        if Data['fullIntegrate']:
4277            LRAzim = [-180,180]
4278        else:
4279            LRAzim = Data['LRazimuth']                  #NB: integers
4280        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[0],IOtth[0]],picker=True)
4281        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[1],IOtth[1]],picker=True)
4282        if not Data['fullIntegrate']:
4283            Plot.plot([LRAzim[0],LRAzim[0]],[IOtth[0],IOtth[1]],picker=True)
4284            Plot.plot([LRAzim[1],LRAzim[1]],[IOtth[0],IOtth[1]],picker=True)
4285    if Data['setRings']:
4286        rings = np.concatenate((Data['rings']),axis=0)
4287        for xring,yring,dsp in rings:
4288            x,y = G2img.GetTthAzm(xring,yring,Data)
4289            Plot.plot(y,x,'r+')           
4290    if Data['ellipses']:           
4291        for ellipse in Data['ellipses']:
4292            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
4293            x,y = np.hsplit(ring,2)
4294            tth,azm = G2img.GetTthAzm(x,y,Data)
4295            Plot.plot(azm,tth,'b,')
4296    if not newPlot:
4297        Page.toolbar.push_current()
4298        Plot.set_xlim(xylim[0])
4299        Plot.set_ylim(xylim[1])
4300        xylim =