source: trunk/GSASIIplot.py @ 1300

Last change on this file since 1300 was 1300, checked in by vondreele, 9 years ago

Add additional column to SASD profile - contains fixed background
remove contour plotting from SASD data
Add background file to SASD models GUI
this change breaks old SASD gpx files, they will need to be recreated!

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