source: trunk/GSASIIplot.py @ 1907

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

comment out the G2plotNB.clear in OnRefine? so that the new plot will have the same limits as the old one before refinement

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