source: trunk/GSASIIplot.py @ 2136

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

fix indexing problem in 32 bit versions - Skip in ProgressDialog? doesn't work
skip user excluded reflections in HKLF exporters
modify MergeDialog? & more work on LaueUnique?
add 'O' option to 3DHKLF plots to center on origin

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