source: trunk/GSASIIplot.py @ 326

Last change on this file since 326 was 326, checked in by vondreele, 12 years ago

remove cf2py
add inverse polefigure

  • Property svn:keywords set to Date Author Revision URL Id
File size: 103.7 KB
Line 
1#GSASII plotting routines
2########### SVN repository information ###################
3# $Date: 2011-06-30 16:38:20 +0000 (Thu, 30 Jun 2011) $
4# $Author: vondreele $
5# $Revision: 326 $
6# $URL: trunk/GSASIIplot.py $
7# $Id: GSASIIplot.py 326 2011-06-30 16:38:20Z vondreele $
8########### SVN repository information ###################
9import math
10import time
11import copy
12import os.path
13import numpy as np
14import numpy.linalg as nl
15import wx
16import wx.aui
17import wx.glcanvas
18import matplotlib as mpl
19import mpl_toolkits.mplot3d.axes3d as mp3d
20import GSASIIpath
21import GSASIIgrid as G2gd
22import GSASIIimage as G2img
23import GSASIIpwd as G2pwd
24import GSASIIIO as G2IO
25import GSASIIpwdGUI as G2pdG
26import GSASIIimgGUI as G2imG
27import GSASIIphsGUI as G2phG
28import GSASIIlattice as G2lat
29import GSASIIspc as G2spc
30import pytexture as ptx
31from  OpenGL.GL import *
32from OpenGL.GLU import *
33from OpenGL.GLUT import *
34from OpenGL.GLE import *
35from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
36from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
37
38# useful degree trig functions
39sind = lambda x: math.sin(x*math.pi/180.)
40cosd = lambda x: math.cos(x*math.pi/180.)
41tand = lambda x: math.tan(x*math.pi/180.)
42asind = lambda x: 180.*math.asin(x)/math.pi
43acosd = lambda x: 180.*math.acos(x)/math.pi
44atan2d = lambda x,y: 180.*math.atan2(y,x)/math.pi
45atand = lambda x: 180.*math.atan(x)/math.pi
46# numpy versions
47npsind = lambda x: np.sin(x*np.pi/180.)
48npcosd = lambda x: np.cos(x*np.pi/180.)
49npacosd = lambda x: 180.*np.arccos(x)/np.pi
50npasind = lambda x: 180.*np.arcsin(x)/np.pi
51npatan2d = lambda x,y: 180.*np.arctan2(x,y)/np.pi
52   
53class G2PlotMpl(wx.Panel):   
54    def __init__(self,parent,id=-1,dpi=None,**kwargs):
55        wx.Panel.__init__(self,parent,id=id,**kwargs)
56        mpl.rcParams['legend.fontsize'] = 8
57        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(5,7))
58        self.canvas = Canvas(self,-1,self.figure)
59        self.toolbar = Toolbar(self.canvas)
60
61        self.toolbar.Realize()
62       
63        sizer=wx.BoxSizer(wx.VERTICAL)
64        sizer.Add(self.canvas,1,wx.EXPAND)
65        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
66        self.SetSizer(sizer)
67       
68class G2PlotOgl(wx.Panel):
69    def __init__(self,parent,id=-1,dpi=None,**kwargs):
70        self.figure = wx.Panel.__init__(self,parent,id=id,**kwargs)
71        self.canvas = wx.glcanvas.GLCanvas(self,-1,**kwargs)
72        self.camera = {}
73        sizer=wx.BoxSizer(wx.VERTICAL)
74        sizer.Add(self.canvas,1,wx.EXPAND)
75        self.SetSizer(sizer)
76       
77class G2Plot3D(wx.Panel):
78    def __init__(self,parent,id=-1,dpi=None,**kwargs):
79        wx.Panel.__init__(self,parent,id=id,**kwargs)
80        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(6,6))
81        self.canvas = Canvas(self,-1,self.figure)
82        self.toolbar = Toolbar(self.canvas)
83
84        self.toolbar.Realize()
85       
86        sizer=wx.BoxSizer(wx.VERTICAL)
87        sizer.Add(self.canvas,1,wx.EXPAND)
88        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
89        self.SetSizer(sizer)
90                             
91class G2PlotNoteBook(wx.Panel):
92    def __init__(self,parent,id=-1):
93        wx.Panel.__init__(self,parent,id=id)
94        #so one can't delete a plot page!!
95        self.nb = wx.aui.AuiNotebook(self, \
96            style=wx.aui.AUI_NB_DEFAULT_STYLE ^ wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
97        sizer = wx.BoxSizer()
98        sizer.Add(self.nb,1,wx.EXPAND)
99        self.SetSizer(sizer)
100        self.status = parent.CreateStatusBar()
101        self.status.SetFieldsCount(2)
102        self.status.SetStatusWidths([150,-1])
103        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
104       
105        self.plotList = []
106           
107    def addMpl(self,name=""):
108        page = G2PlotMpl(self.nb)
109        self.nb.AddPage(page,name)
110       
111        self.plotList.append(name)
112       
113        return page.figure
114       
115    def add3D(self,name=""):
116        page = G2Plot3D(self.nb)
117        self.nb.AddPage(page,name)
118       
119        self.plotList.append(name)
120       
121        return page.figure
122       
123    def addOgl(self,name=""):
124        page = G2PlotOgl(self.nb)
125        self.nb.AddPage(page,name)
126       
127        self.plotList.append(name)
128       
129        return page.figure
130       
131    def Delete(self,name):
132        try:
133            item = self.plotList.index(name)
134            del self.plotList[item]
135            self.nb.DeletePage(item)
136        except ValueError:          #no plot of this name - do nothing
137            return     
138               
139    def clear(self):
140        while self.nb.GetPageCount():
141            self.nb.DeletePage(0)
142        self.plotList = []
143        self.status.DestroyChildren()
144       
145    def Rename(self,oldName,newName):
146        try:
147            item = self.plotList.index(oldName)
148            self.plotList[item] = newName
149            self.nb.SetPageText(item,newName)
150        except ValueError:          #no plot of this name - do nothing
151            return     
152       
153    def OnPageChanged(self,event):       
154        if self.plotList:
155            self.status.SetStatusText('Better to select this from GSAS-II data tree',1)
156        self.status.DestroyChildren()                           #get rid of special stuff on status bar
157       
158def PlotSngl(self,newPlot=False):
159    '''Single crystal structure factor plotting package - displays zone of reflections as rings proportional
160        to F, F**2, etc. as requested
161    '''
162    from matplotlib.patches import Circle
163    global HKL,HKLF
164
165    def OnSCMotion(event):
166        xpos = event.xdata
167        if xpos:
168            xpos = round(xpos)                                        #avoid out of frame mouse position
169            ypos = round(event.ydata)
170            zpos = Data['Layer']
171            if '100' in Data['Zone']:
172                HKLtxt = '(%3d,%3d,%3d)'%(zpos,xpos,ypos)
173            elif '010' in Data['Zone']:
174                HKLtxt = '(%3d,%3d,%3d)'%(xpos,zpos,ypos)
175            elif '001' in Data['Zone']:
176                HKLtxt = '(%3d,%3d,%3d)'%(xpos,ypos,zpos)
177            Page.canvas.SetToolTipString(HKLtxt)
178            self.G2plotNB.status.SetFields(['HKL = '+HKLtxt,''])
179               
180    def OnSCPick(event):
181        zpos = Data['Layer']
182        pos = event.artist.center
183        if '100' in Data['Zone']:
184            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(zpos,pos[0],pos[1]))
185            hkl = np.array([zpos,pos[0],pos[1]])
186        elif '010' in Data['Zone']:
187            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],zpos,pos[1]))
188            hkl = np.array([pos[0],zpos,pos[1]])
189        elif '001' in Data['Zone']:
190            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],pos[1],zpos))
191            hkl = np.array([pos[0],pos[1],zpos])
192        h,k,l = hkl
193        hklf = HKLF[np.where(np.all(HKL-hkl == [0,0,0],axis=1))]
194        if len(hklf):
195            Fosq,sig,Fcsq = hklf[0]
196            HKLtxt = '(%3d,%3d,%3d %.2f %.3f %.2f %.2f)'%(h,k,l,Fosq,sig,Fcsq,(Fosq-Fcsq)/(scale*sig))
197            self.G2plotNB.status.SetFields(['','HKL, Fosq, sig, Fcsq, delFsq/sig = '+HKLtxt])
198                                 
199    def OnSCKeyPress(event):
200        print event.key
201
202    try:
203        plotNum = self.G2plotNB.plotList.index('Structure Factors')
204        Page = self.G2plotNB.nb.GetPage(plotNum)
205        if not newPlot:
206            Plot = Page.figure.gca()          #get previous powder plot & get limits
207            xylim = Plot.get_xlim(),Plot.get_ylim()
208        Page.figure.clf()
209        Plot = Page.figure.gca()          #get a fresh plot after clf()
210    except ValueError:
211        Plot = self.G2plotNB.addMpl('Structure Factors').gca()
212        plotNum = self.G2plotNB.plotList.index('Structure Factors')
213        Page = self.G2plotNB.nb.GetPage(plotNum)
214#        Page.canvas.mpl_connect('key_press_event', OnSCKeyPress)
215        Page.canvas.mpl_connect('pick_event', OnSCPick)
216        Page.canvas.mpl_connect('motion_notify_event', OnSCMotion)
217    Page.SetFocus()
218   
219    Plot.set_aspect(aspect='equal')
220    HKLref = self.PatternTree.GetItemPyData(self.Sngl)
221    Data = self.PatternTree.GetItemPyData( \
222        G2gd.GetPatternTreeItemId(self,self.Sngl, 'HKL Plot Controls'))
223    Type = Data['Type']           
224    scale = Data['Scale']
225    HKLmax = Data['HKLmax']
226    HKLmin = Data['HKLmin']
227    FosqMax = Data['FoMax']
228    FoMax = math.sqrt(FosqMax)
229    ifFc = Data['ifFc']
230    xlabel = ['k, h=','h, k=','h, l=']
231    ylabel = ['l','l','k']
232    zones = ['100','010','001']
233    pzone = [[1,2],[0,2],[0,1]]
234    izone = zones.index(Data['Zone'])
235    Plot.set_title(self.PatternTree.GetItemText(self.Sngl)[5:])
236    HKL = []
237    HKLF = []
238    for H,Fosq,sig,Fcsq,x,x,x in HKLref:
239        HKL.append(H)
240        HKLF.append([Fosq,sig,Fcsq])
241        if H[izone] == Data['Layer']:
242            B = 0
243            if Type == 'Fosq':
244                A = scale*Fosq/FosqMax
245                B = scale*Fcsq/FosqMax
246                C = abs(A-B)
247            elif Type == 'Fo':
248                A = scale*math.sqrt(max(0,Fosq))/FoMax
249                B = scale*math.sqrt(max(0,Fcsq))/FoMax
250                C = abs(A-B)
251            elif Type == '|DFsq|/sig':
252                A = abs(Fosq-Fcsq)/(scale*sig)
253            elif Type == '|DFsq|>sig':
254                A = abs(Fosq-Fcsq)/(scale*sig)
255                if A < 1.0: A = 0                   
256            elif Type == '|DFsq|>3sig':
257                A = abs(Fosq-Fcsq)/(scale*sig)
258                if A < 3.0: A = 0                   
259            xy = (H[pzone[izone][0]],H[pzone[izone][1]])
260            if A > 0.0:
261                Plot.add_artist(Circle(xy,radius=A,ec='g',fc='w',picker=3))
262            if B:
263                Plot.add_artist(Circle(xy,radius=B,ec='b',fc='w'))
264                radius = C
265                if radius > 0:
266                    if A > B:
267                        Plot.add_artist(Circle(xy,radius=radius,ec='g',fc='g'))
268                    else:                   
269                        Plot.add_artist(Circle(xy,radius=radius,ec='r',fc='r'))
270    HKL = np.array(HKL,dtype=np.int)
271    HKLF = np.array(HKLF)
272    Plot.set_xlabel(xlabel[izone]+str(Data['Layer']),fontsize=12)
273    Plot.set_ylabel(ylabel[izone],fontsize=12)
274    Plot.set_xlim((HKLmin[pzone[izone][0]],HKLmax[pzone[izone][0]]))
275    Plot.set_ylim((HKLmin[pzone[izone][1]],HKLmax[pzone[izone][1]]))
276    if not newPlot:
277        Page.toolbar.push_current()
278        Plot.set_xlim(xylim[0])
279        Plot.set_ylim(xylim[1])
280        xylim = []
281        Page.toolbar.push_current()
282        Page.toolbar.draw()
283    else:
284        Page.canvas.draw()
285       
286def PlotPatterns(self,newPlot=False):
287    '''Powder pattern plotting package - displays single or multiple powder patterns as intensity vs
288    2-theta or q (future TOF). Can display multiple patterns as "waterfall plots" or contour plots. Log I
289    plotting available.
290    '''
291    global HKL
292   
293    def OnPick(event):
294        if self.itemPicked is not None: return
295        PatternId = self.PatternId
296        try:
297            Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.PatternId, 'Instrument Parameters'))[1::2]
298        except TypeError:
299            return
300        Parms = dict(zip(Names,Values))
301        try:
302            wave = Parms['Lam']
303        except KeyError:
304            wave = Parms['Lam1']
305        PickId = self.PickId
306        pick = event.artist
307        mouse = event.mouseevent       
308        xpos = pick.get_xdata()
309        ypos = pick.get_ydata()
310        ind = event.ind
311        xy = list(zip(np.take(xpos,ind),np.take(ypos,ind))[0])
312        if self.PatternTree.GetItemText(PickId) == 'Peak List':
313            if ind.all() != [0]:                                    #picked a data point
314                if 'C' in Parms['Type']:                            #CW data - TOF later in an elif
315                    ins = [Parms[x] for x in ['U','V','W','X','Y']]
316                    if self.qPlot:                              #qplot - convert back to 2-theta
317                        xy[0] = 2.0*asind(xy[0]*wave/(4*math.pi))
318                    sig = ins[0]*tand(xy[0]/2.0)**2+ins[1]*tand(xy[0]/2.0)+ins[2]
319                    gam = ins[3]/cosd(xy[0]/2.0)+ins[4]*tand(xy[0]/2.0)           
320                    data = self.PatternTree.GetItemPyData(self.PickId)
321                    XY = [xy[0],0, xy[1],1, sig,0, gam,0]       #default refine intensity 1st
322                data.append(XY)
323                G2pdG.UpdatePeakGrid(self,data)
324                PlotPatterns(self)
325            else:                                                   #picked a peak list line
326                self.itemPicked = pick
327        elif self.PatternTree.GetItemText(PickId) == 'Limits':
328            if ind.all() != [0]:                                    #picked a data point
329                LimitId = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
330                data = self.PatternTree.GetItemPyData(LimitId)
331                if 'C' in Parms['Type']:                            #CW data - TOF later in an elif
332                    if self.qPlot:                              #qplot - convert back to 2-theta
333                        xy[0] = 2.0*asind(xy[0]*wave/(4*math.pi))
334                if mouse.button==1:
335                    data[1][0] = min(xy[0],data[1][1])
336                if mouse.button==3:
337                    data[1][1] = max(xy[0],data[1][0])
338                self.PatternTree.SetItemPyData(LimitId,data)
339                G2pdG.UpdateLimitsGrid(self,data)
340                PlotPatterns(self)
341            else:                                                   #picked a limit line
342                self.itemPicked = pick
343       
344    def OnPlotKeyPress(event):
345        newPlot = False
346        if event.key == 'w':
347            if self.Weight:
348                self.Weight = False
349            else:
350                self.Weight = True
351            print 'plot weighting:',self.Weight
352        elif event.key == 'n':
353            if self.Contour:
354                pass
355            else:
356                if self.logPlot:
357                    self.logPlot = False
358                else:
359                    self.Offset[0] = 0
360                    self.logPlot = True
361        elif event.key == 'u':
362            if self.Contour:
363                self.Cmax = min(1.0,self.Cmax*1.2)
364            elif self.logPlot:
365                pass
366            elif self.Offset[0] < 100.:
367                self.Offset[0] += 1.
368        elif event.key == 'd':
369            if self.Contour:
370                self.Cmax = max(0.0,self.Cmax*0.8)
371            elif self.logPlot:
372                pass
373            elif self.Offset[0] > 0.:
374                self.Offset[0] -= 1.
375        elif event.key == 'l':
376            self.Offset[1] -= 1.
377        elif event.key == 'r':
378            self.Offset[1] += 1.
379        elif event.key == 'o':
380            self.Offset = [0,0]
381        elif event.key == 'c':
382            newPlot = True
383            if self.Contour:
384                self.Contour = False
385            else:
386                self.Contour = True
387                self.SinglePlot = False
388                self.Offset = [0.,0.]
389        elif event.key == 'q':
390            newPlot = True
391            if self.qPlot:
392                self.qPlot = False
393            else:
394                self.qPlot = True
395        elif event.key == 's':
396            if self.Contour:
397                choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
398                choice.sort()
399                dlg = wx.SingleChoiceDialog(self,'Select','Color scheme',choice)
400                if dlg.ShowModal() == wx.ID_OK:
401                    sel = dlg.GetSelection()
402                    self.ContourColor = choice[sel]
403                else:
404                    self.ContourColor = 'Paired'
405                dlg.Destroy()
406            else:               
407                if self.SinglePlot:
408                    self.SinglePlot = False
409                else:
410                    self.SinglePlot = True
411        elif event.key == '+':
412            if self.PickId:
413                self.PickId = False
414        elif event.key == 'i':                  #for smoothing contour plot
415            choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
416               'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
417               'mitchell','sinc','lanczos']
418            dlg = wx.SingleChoiceDialog(self,'Select','Interpolation',choice)
419            if dlg.ShowModal() == wx.ID_OK:
420                sel = dlg.GetSelection()
421                self.Interpolate = choice[sel]
422            else:
423                self.Interpolate = 'nearest'
424            dlg.Destroy()
425           
426        PlotPatterns(self,newPlot=newPlot)
427       
428    def OnKeyBox(event):
429        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index('Powder Patterns'):
430            event.key = cb.GetValue()[0]
431            cb.SetValue(' key press')
432            OnPlotKeyPress(event)
433                       
434    def OnMotion(event):
435        xpos = event.xdata
436        if xpos:                                        #avoid out of frame mouse position
437            ypos = event.ydata
438            Page.canvas.SetCursor(wx.CROSS_CURSOR)
439            try:
440                Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.PatternId, 'Instrument Parameters'))[1::2]
441                Parms = dict(zip(Names,Values))
442                try:
443                    wave = Parms['Lam']
444                except KeyError:
445                    wave = Parms['Lam1']
446                if self.qPlot:
447                    xpos = 2.0*asind(xpos*wave/(4*math.pi))
448                dsp = 0.0
449                if abs(xpos) > 0.:                  #avoid possible singularity at beam center
450                    dsp = wave/(2.*sind(abs(xpos)/2.0))
451                if self.Contour:
452                    self.G2plotNB.status.SetStatusText('2-theta =%9.3f d =%9.5f pattern ID =%5d'%(xpos,dsp,int(ypos)),1)
453                else:
454                    self.G2plotNB.status.SetStatusText('2-theta =%9.3f d =%9.5f Intensity =%9.1f'%(xpos,dsp,ypos),1)
455                if self.itemPicked:
456                    Page.canvas.SetToolTipString('%9.3f'%(xpos))
457                if self.PickId and self.PatternTree.GetItemText(self.PickId) in ['Index Peak List','Unit Cells List']:
458                    found = []
459                    if len(HKL):
460                        view = Page.toolbar._views.forward()[0][:2]
461                        wid = view[1]-view[0]
462                        found = HKL[np.where(np.fabs(HKL.T[5]-xpos) < 0.002*wid)]
463                    if len(found):
464                        h,k,l = found[0][:3] 
465                        Page.canvas.SetToolTipString('%d,%d,%d'%(int(h),int(k),int(l)))
466                    else:
467                        Page.canvas.SetToolTipString('')
468
469            except TypeError:
470                self.G2plotNB.status.SetStatusText('Select PWDR powder pattern first',1)
471                                                   
472    def OnRelease(event):
473        if self.itemPicked is None: return
474        Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.PatternId, 'Instrument Parameters'))[1::2]
475        Parms = dict(zip(Names,Values))
476        try:
477            wave = Parms['Lam']
478        except KeyError:
479            wave = Parms['Lam1']
480        xpos = event.xdata
481        if xpos:                                        #avoid out of frame mouse position
482            lines = []
483            for line in self.Lines: lines.append(line.get_xdata()[0])
484            lineNo = lines.index(self.itemPicked.get_xdata()[0])
485            if  lineNo in [0,1]:
486                LimitId = G2gd.GetPatternTreeItemId(self,self.PatternId, 'Limits')
487                data = self.PatternTree.GetItemPyData(LimitId)
488#                print 'limits',xpos
489                if self.qPlot:
490                    data[1][lineNo] = 2.0*asind(wave*xpos/(4*math.pi))
491                else:
492                    data[1][lineNo] = xpos
493                self.PatternTree.SetItemPyData(LimitId,data)
494                if self.PatternTree.GetItemText(self.PickId) == 'Limits':
495                    G2pdG.UpdateLimitsGrid(self,data)
496            else:
497                PeakId = G2gd.GetPatternTreeItemId(self,self.PatternId, 'Peak List')
498                data = self.PatternTree.GetItemPyData(PeakId)
499#                print 'peaks',xpos
500                if event.button == 3:
501                    del data[lineNo-2]
502                else:
503                    if self.qPlot:
504                        data[lineNo-2][0] = 2.0*asind(wave*xpos/(4*math.pi))
505                    else:
506                        data[lineNo-2][0] = xpos
507                self.PatternTree.SetItemPyData(PeakId,data)
508                G2pdG.UpdatePeakGrid(self,data)
509        PlotPatterns(self)
510        self.itemPicked = None   
511
512    xylim = []
513    try:
514        plotNum = self.G2plotNB.plotList.index('Powder Patterns')
515        Page = self.G2plotNB.nb.GetPage(plotNum)
516        if not newPlot:
517            Plot = Page.figure.gca()          #get previous powder plot & get limits
518            xylim = Plot.get_xlim(),Plot.get_ylim()
519        Page.figure.clf()
520        Plot = Page.figure.gca()          #get a fresh plot after clf()
521    except ValueError:
522        newPlot = True
523        self.Cmax = 1.0
524        Plot = self.G2plotNB.addMpl('Powder Patterns').gca()
525        plotNum = self.G2plotNB.plotList.index('Powder Patterns')
526        Page = self.G2plotNB.nb.GetPage(plotNum)
527        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
528        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
529        Page.canvas.mpl_connect('pick_event', OnPick)
530        Page.canvas.mpl_connect('button_release_event', OnRelease)
531    Page.SetFocus()
532    self.G2plotNB.status.DestroyChildren()
533    if self.Contour:
534        Choice = (' key press','d: lower contour max','u: raise contour max',
535            'i: interpolation method','s: color scheme','c: contour off')
536    else:
537        if self.logPlot:
538            Choice = (' key press','n: log(I) off','l: offset left','r: offset right',
539                'c: contour on','q: toggle q plot','s: toggle single plot','+: no selection')
540        else:
541            Choice = (' key press','l: offset left','r: offset right','d: offset down',
542                'u: offset up','o: reset offset','n: log(I) on','c: contour on',
543                'q: toggle q plot','s: toggle single plot','+: no selection')
544    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
545        choices=Choice)
546    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
547    cb.SetValue(' key press')
548   
549    PickId = self.PickId
550    PatternId = self.PatternId
551    colors=['b','g','r','c','m','k']
552    Lines = []
553    if self.SinglePlot:
554        Pattern = self.PatternTree.GetItemPyData(PatternId)
555        Pattern.append(self.PatternTree.GetItemText(PatternId))
556        PlotList = [Pattern,]
557        ParmList = [self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,
558            self.PatternId, 'Instrument Parameters'))[1],]
559    else:       
560        PlotList = []
561        ParmList = []
562        item, cookie = self.PatternTree.GetFirstChild(self.root)
563        while item:
564            if 'PWDR' in self.PatternTree.GetItemText(item):
565                Pattern = self.PatternTree.GetItemPyData(item)
566                if len(Pattern) < 3:                    # put name on end if needed
567                    Pattern.append(self.PatternTree.GetItemText(item))
568                PlotList.append(Pattern)
569                ParmList.append(self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,
570                    item,'Instrument Parameters'))[1])
571            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
572    Ymax = 1.0
573    lenX = 0
574    HKL = np.array(self.HKL)
575    for Pattern in PlotList:
576        xye = Pattern[1]
577        Ymax = max(Ymax,max(xye[1]))
578    offset = self.Offset[0]*Ymax/100.0
579    Title = 'Powder Patterns: '+os.path.split(self.GSASprojectfile)[1]
580    if self.logPlot:
581        Title = 'log('+Title+')'
582    Plot.set_title(Title)
583    if self.qPlot:
584        Plot.set_xlabel(r'$q, \AA^{-1}$',fontsize=14)
585    else:       
586        Plot.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
587    Plot.set_ylabel('Intensity',fontsize=12)
588    if self.Contour:
589        ContourZ = []
590        ContourY = []
591        Nseq = 0
592    for N,Pattern in enumerate(PlotList):
593        Parms = ParmList[N]
594        ifpicked = False
595        LimitId = 0
596        xye = np.array(Pattern[1])
597        if PickId:
598            ifpicked = Pattern[2] == self.PatternTree.GetItemText(PatternId)
599            LimitId = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
600        if self.qPlot:
601            Id = G2gd.GetPatternTreeItemId(self,self.root, Pattern[2])
602            X = 4*np.pi*npsind(xye[0]/2.0)/Parms[1]
603        else:
604            X = xye[0]
605        if not lenX:
606            lenX = len(X)           
607        Y = xye[1]+offset*N
608        if LimitId:
609            limits = np.array(self.PatternTree.GetItemPyData(LimitId))
610            if self.qPlot:
611                limits = 4*np.pi*npsind(limits/2.0)/Parms[1]
612            Lines.append(Plot.axvline(limits[1][0],color='g',dashes=(5,5),picker=3.))   
613            Lines.append(Plot.axvline(limits[1][1],color='r',dashes=(5,5),picker=3.))                   
614        if self.Contour:
615           
616            if lenX == len(X):
617                ContourY.append(N)
618                ContourZ.append(Y)
619                ContourX = X
620                Nseq += 1
621                Plot.set_ylabel('Data sequence',fontsize=12)
622        else:
623            X += self.Offset[1]*.005*N
624            if ifpicked:
625                Z = xye[3]+offset*N
626                W = xye[4]+offset*N
627                D = xye[5]+offset*N-Ymax*.02
628                if self.Weight:
629                    W2 = np.sqrt(xye[2])
630                    D *= W2-Ymax*.02
631                if self.logPlot:
632                    Plot.semilogy(X,Y,colors[N%6]+'+',picker=3.,clip_on=False,nonposy='mask')
633                    Plot.semilogy(X,Z,colors[(N+1)%6],picker=False,nonposy='mask')
634                    Plot.semilogy(X,W,colors[(N+2)%6],picker=False,nonposy='mask')
635                else:
636                    Plot.plot(X,Y,colors[N%6]+'+',picker=3.,clip_on=False)
637                    Plot.plot(X,Z,colors[(N+1)%6],picker=False)
638                    Plot.plot(X,W,colors[(N+2)%6],picker=False)
639                    Plot.plot(X,D,colors[(N+3)%6],picker=False)
640                    Plot.axhline(0.,color=wx.BLACK)
641                Page.canvas.SetToolTipString('')
642                if self.PatternTree.GetItemText(PickId) == 'Peak List':
643                    tip = 'On data point: Pick peak - L or R MB. On line: L-move, R-delete'
644                    Page.canvas.SetToolTipString(tip)
645                    data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Peak List'))
646                    for item in data:
647                        if self.qPlot:
648                            Lines.append(Plot.axvline(4*math.pi*sind(item[0]/2.)/Parms[1],color=colors[N%6],picker=2.))
649                        else:
650                            Lines.append(Plot.axvline(item[0],color=colors[N%6],picker=2.))
651                if self.PatternTree.GetItemText(PickId) == 'Limits':
652                    tip = 'On data point: Lower limit - L MB; Upper limit - R MB. On limit: MB down to move'
653                    Page.canvas.SetToolTipString(tip)
654                    data = self.LimitsTable.GetData()
655            else:
656                if self.logPlot:
657                    Plot.semilogy(X,Y,colors[N%6],picker=False,nonposy='clip')
658                else:
659                    Plot.plot(X,Y,colors[N%6],picker=False)
660    if PickId and self.PatternTree.GetItemText(PickId) in ['Index Peak List','Unit Cells List']:
661        Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Instrument Parameters'))[1::2]
662        Parms = dict(zip(Names,Values))
663        try:
664            wave = Parms['Lam']
665        except KeyError:
666            wave = Parms['Lam1']
667        peaks = np.array((self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Index Peak List'))))
668        for peak in peaks:
669            if self.qPlot:
670                Plot.axvline(4*np.pi*sind(peak[0]/2.0)/wave,color='b')
671            else:
672                Plot.axvline(peak[0],color='b')
673        for hkl in self.HKL:
674            if self.qPlot:
675                Plot.axvline(4*np.pi*sind(hkl[5]/2.0)/wave,color='r',dashes=(5,5))
676            else:
677                Plot.axvline(hkl[5],color='r',dashes=(5,5))
678    if self.Contour:
679        acolor = mpl.cm.get_cmap(self.ContourColor)
680        Img = Plot.imshow(ContourZ,cmap=acolor,vmin=0,vmax=Ymax*self.Cmax,interpolation=self.Interpolate, 
681            extent=[ContourX[0],ContourX[-1],ContourY[0],ContourY[-1]],aspect='auto',origin='lower')
682        Page.figure.colorbar(Img)
683    else:
684        self.Lines = Lines
685    if not newPlot:
686        Page.toolbar.push_current()
687        Plot.set_xlim(xylim[0])
688        Plot.set_ylim(xylim[1])
689        xylim = []
690        Page.toolbar.push_current()
691        Page.toolbar.draw()
692    else:
693        Page.canvas.draw()
694    self.Pwdr = True
695   
696def PlotISFG(self,newPlot=False,type=''):
697    ''' PLotting package for PDF analysis; displays I(q), S(q), F(q) and G(r) as single
698    or multiple plots with waterfall and contour plots as options
699    '''
700    if not type:
701        type = self.G2plotNB.plotList[self.G2plotNB.nb.GetSelection()]
702    if type not in ['I(Q)','S(Q)','F(Q)','G(R)']:
703        return
704    superMinusOne = unichr(0xaf)+unichr(0xb9)
705   
706    def OnPlotKeyPress(event):
707        newPlot = False
708        if event.key == 'u':
709            if self.Contour:
710                self.Cmax = min(1.0,self.Cmax*1.2)
711            elif self.Offset[0] < 100.:
712                self.Offset[0] += 1.
713        elif event.key == 'd':
714            if self.Contour:
715                self.Cmax = max(0.0,self.Cmax*0.8)
716            elif self.Offset[0] > 0.:
717                self.Offset[0] -= 1.
718        elif event.key == 'l':
719            self.Offset[1] -= 1.
720        elif event.key == 'r':
721            self.Offset[1] += 1.
722        elif event.key == 'o':
723            self.Offset = [0,0]
724        elif event.key == 'c':
725            newPlot = True
726            if self.Contour:
727                self.Contour = False
728            else:
729                self.Contour = True
730                self.SinglePlot = False
731                self.Offset = [0.,0.]
732        elif event.key == 's':
733            if self.Contour:
734                choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
735                choice.sort()
736                dlg = wx.SingleChoiceDialog(self,'Select','Color scheme',choice)
737                if dlg.ShowModal() == wx.ID_OK:
738                    sel = dlg.GetSelection()
739                    self.ContourColor = choice[sel]
740                else:
741                    self.ContourColor = 'Paired'
742                dlg.Destroy()
743            else:               
744                if self.SinglePlot:
745                    self.SinglePlot = False
746                else:
747                    self.SinglePlot = True
748        elif event.key == 'i':                  #for smoothing contour plot
749            choice = ['nearest','bilinear','bicubic','spline16','spline36','hanning',
750               'hamming','hermite','kaiser','quadric','catrom','gaussian','bessel',
751               'mitchell','sinc','lanczos']
752            dlg = wx.SingleChoiceDialog(self,'Select','Interpolation',choice)
753            if dlg.ShowModal() == wx.ID_OK:
754                sel = dlg.GetSelection()
755                self.Interpolate = choice[sel]
756            else:
757                self.Interpolate = 'nearest'
758            dlg.Destroy()
759        elif event.key == 't' and not self.Contour:
760            if self.Legend:
761                self.Legend = False
762            else:
763                self.Legend = True
764           
765           
766        PlotISFG(self,newPlot=newPlot,type=type)
767       
768    def OnKeyBox(event):
769        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index(type):
770            event.key = cb.GetValue()[0]
771            cb.SetValue(' key press')
772            OnPlotKeyPress(event)
773                       
774    def OnMotion(event):
775        xpos = event.xdata
776        if xpos:                                        #avoid out of frame mouse position
777            ypos = event.ydata
778            Page.canvas.SetCursor(wx.CROSS_CURSOR)
779            try:
780                if self.Contour:
781                    self.G2plotNB.status.SetStatusText('R =%.3fA pattern ID =%5d'%(xpos,int(ypos)),1)
782                else:
783                    self.G2plotNB.status.SetStatusText('R =%.3fA %s =%.2f'%(xpos,type,ypos),1)                   
784            except TypeError:
785                self.G2plotNB.status.SetStatusText('Select '+type+' pattern first',1)
786   
787    xylim = []
788    try:
789        plotNum = self.G2plotNB.plotList.index(type)
790        Page = self.G2plotNB.nb.GetPage(plotNum)
791        if not newPlot:
792            Plot = Page.figure.gca()          #get previous plot & get limits
793            xylim = Plot.get_xlim(),Plot.get_ylim()
794        Page.figure.clf()
795        Plot = Page.figure.gca()
796    except ValueError:
797        newPlot = True
798        self.Cmax = 1.0
799        Plot = self.G2plotNB.addMpl(type).gca()
800        plotNum = self.G2plotNB.plotList.index(type)
801        Page = self.G2plotNB.nb.GetPage(plotNum)
802        Page.canvas.mpl_connect('key_press_event', OnPlotKeyPress)
803        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
804   
805    Page.SetFocus()
806    self.G2plotNB.status.DestroyChildren()
807    if self.Contour:
808        Choice = (' key press','d: lower contour max','u: raise contour max',
809            'i: interpolation method','s: color scheme','c: contour off')
810    else:
811        Choice = (' key press','l: offset left','r: offset right','d: offset down','u: offset up',
812            'o: reset offset','t: toggle legend','c: contour on','s: toggle single plot')
813    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
814        choices=Choice)
815    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
816    cb.SetValue(' key press')
817    PatternId = self.PatternId
818    PickId = self.PickId
819    Plot.set_title(type)
820    if type == 'G(R)':
821        Plot.set_xlabel(r'$R,\AA$',fontsize=14)
822    else:
823        Plot.set_xlabel(r'$Q,\AA$'+superMinusOne,fontsize=14)
824    Plot.set_ylabel(r''+type,fontsize=14)
825    colors=['b','g','r','c','m','k']
826    name = self.PatternTree.GetItemText(PatternId)[4:]
827    Pattern = []   
828    if self.SinglePlot:
829        name = self.PatternTree.GetItemText(PatternId)
830        name = type+name[4:]
831        Id = G2gd.GetPatternTreeItemId(self,PatternId,name)
832        Pattern = self.PatternTree.GetItemPyData(Id)
833        if Pattern:
834            Pattern.append(name)
835        PlotList = [Pattern,]
836    else:
837        PlotList = []
838        item, cookie = self.PatternTree.GetFirstChild(self.root)
839        while item:
840            if 'PDF' in self.PatternTree.GetItemText(item):
841                name = type+self.PatternTree.GetItemText(item)[4:]
842                Id = G2gd.GetPatternTreeItemId(self,item,name)
843                Pattern = self.PatternTree.GetItemPyData(Id)
844                if Pattern:
845                    Pattern.append(name)
846                    PlotList.append(Pattern)
847            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
848    PDFdata = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'PDF Controls'))
849    numbDen = G2pwd.GetNumDensity(PDFdata['ElList'],PDFdata['Form Vol'])
850    Xb = [0.,10.]
851    Yb = [0.,-40.*np.pi*numbDen]
852    Ymax = 1.0
853    lenX = 0
854    for Pattern in PlotList:
855        xye = Pattern[1]
856        Ymax = max(Ymax,max(xye[1]))
857    offset = self.Offset[0]*Ymax/100.0
858    if self.Contour:
859        ContourZ = []
860        ContourY = []
861        Nseq = 0
862    for N,Pattern in enumerate(PlotList):
863        xye = Pattern[1]
864        if PickId:
865            ifpicked = Pattern[2] == self.PatternTree.GetItemText(PatternId)
866        X = xye[0]
867        if not lenX:
868            lenX = len(X)           
869        Y = xye[1]+offset*N
870        if self.Contour:
871            if lenX == len(X):
872                ContourY.append(N)
873                ContourZ.append(Y)
874                ContourX = X
875                Nseq += 1
876                Plot.set_ylabel('Data sequence',fontsize=12)
877        else:
878            X = xye[0]+self.Offset[1]*.005*N
879            if ifpicked:
880                Plot.plot(X,Y,colors[N%6]+'+',picker=3.,clip_on=False)
881                Page.canvas.SetToolTipString('')
882            else:
883                if self.Legend:
884                    Plot.plot(X,Y,colors[N%6],picker=False,label='Azm:'+Pattern[2].split('=')[1])
885                else:
886                    Plot.plot(X,Y,colors[N%6],picker=False)
887            if type == 'G(R)':
888                Plot.plot(Xb,Yb,color='k',dashes=(5,5))
889            elif type == 'F(Q)':
890                Plot.axhline(0.,color=wx.BLACK)
891            elif type == 'S(Q)':
892                Plot.axhline(1.,color=wx.BLACK)
893    if self.Contour:
894        acolor = mpl.cm.get_cmap(self.ContourColor)
895        Img = Plot.imshow(ContourZ,cmap=acolor,vmin=0,vmax=Ymax*self.Cmax,interpolation=self.Interpolate, 
896            extent=[ContourX[0],ContourX[-1],ContourY[0],ContourY[-1]],aspect='auto',origin='lower')
897        Page.figure.colorbar(Img)
898    elif self.Legend:
899        Plot.legend(loc='best')
900    if not newPlot:
901        Page.toolbar.push_current()
902        Plot.set_xlim(xylim[0])
903        Plot.set_ylim(xylim[1])
904        xylim = []
905        Page.toolbar.push_current()
906        Page.toolbar.draw()
907    else:
908        Page.canvas.draw()
909       
910def PlotXY(self,XY,newPlot=False,type=''):
911    '''simple plot of xy data, used for diagnostic purposes
912    '''
913    def OnMotion(event):
914        xpos = event.xdata
915        if xpos:                                        #avoid out of frame mouse position
916            ypos = event.ydata
917            Page.canvas.SetCursor(wx.CROSS_CURSOR)
918            try:
919                self.G2plotNB.status.SetStatusText('X =%9.3f %s =%9.3f'%(xpos,type,ypos),1)                   
920            except TypeError:
921                self.G2plotNB.status.SetStatusText('Select '+type+' pattern first',1)
922
923    try:
924        plotNum = self.G2plotNB.plotList.index(type)
925        Page = self.G2plotNB.nb.GetPage(plotNum)
926        if not newPlot:
927            Plot = Page.figure.gca()
928            xylim = Plot.get_xlim(),Plot.get_ylim()
929        Page.figure.clf()
930        Plot = Page.figure.gca()
931    except ValueError:
932        newPlot = True
933        Plot = self.G2plotNB.addMpl(type).gca()
934        plotNum = self.G2plotNB.plotList.index(type)
935        Page = self.G2plotNB.nb.GetPage(plotNum)
936        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
937   
938    Page.SetFocus()
939    self.G2plotNB.status.DestroyChildren()
940    Plot.set_title(type)
941    Plot.set_xlabel(r'X',fontsize=14)
942    Plot.set_ylabel(r''+type,fontsize=14)
943    colors=['b','g','r','c','m','k']
944    Ymax = 1.0
945    lenX = 0
946    X,Y = XY[:2]
947    Ymax = max(Ymax,max(Y))
948    Plot.plot(X,Y,'k',picker=False)
949    if not newPlot:
950        Page.toolbar.push_current()
951        Plot.set_xlim(xylim[0])
952        Plot.set_ylim(xylim[1])
953        xylim = []
954        Page.toolbar.push_current()
955        Page.toolbar.draw()
956    else:
957        Page.canvas.draw()
958
959def PlotPowderLines(self):
960    ''' plotting of powder lines (i.e. no powder pattern) as sticks
961    '''
962    global HKL
963
964    def OnMotion(event):
965        xpos = event.xdata
966        if xpos:                                        #avoid out of frame mouse position
967            Page.canvas.SetCursor(wx.CROSS_CURSOR)
968            self.G2plotNB.status.SetFields(['','2-theta =%9.3f '%(xpos,)])
969            if self.PickId and self.PatternTree.GetItemText(self.PickId) in ['Index Peak List','Unit Cells List']:
970                found = []
971                if len(HKL):
972                    view = Page.toolbar._views.forward()[0][:2]
973                    wid = view[1]-view[0]
974                    found = HKL[np.where(np.fabs(HKL.T[5]-xpos) < 0.002*wid)]
975                if len(found):
976                    h,k,l = found[0][:3] 
977                    Page.canvas.SetToolTipString('%d,%d,%d'%(int(h),int(k),int(l)))
978                else:
979                    Page.canvas.SetToolTipString('')
980
981    try:
982        plotNum = self.G2plotNB.plotList.index('Powder Lines')
983        Page = self.G2plotNB.nb.GetPage(plotNum)
984        Page.figure.clf()
985        Plot = Page.figure.gca()
986    except ValueError:
987        Plot = self.G2plotNB.addMpl('Powder Lines').gca()
988        plotNum = self.G2plotNB.plotList.index('Powder Lines')
989        Page = self.G2plotNB.nb.GetPage(plotNum)
990        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
991       
992    Page.SetFocus()
993    Plot.set_title('Powder Pattern Lines')
994    Plot.set_xlabel(r'$\mathsf{2\theta}$',fontsize=14)
995    PickId = self.PickId
996    PatternId = self.PatternId
997    peaks = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PatternId, 'Index Peak List'))
998    for peak in peaks:
999        Plot.axvline(peak[0],color='b')
1000    HKL = np.array(self.HKL)
1001    for hkl in self.HKL:
1002        Plot.axvline(hkl[5],color='r',dashes=(5,5))
1003    xmin = peaks[0][0]
1004    xmax = peaks[-1][0]
1005    delt = xmax-xmin
1006    xlim = [max(0,xmin-delt/20.),min(180.,xmax+delt/20.)]
1007    Plot.set_xlim(xlim)
1008    Page.canvas.draw()
1009    Page.toolbar.push_current()
1010
1011def PlotPeakWidths(self):
1012    ''' Plotting of instrument broadening terms as function of 2-theta (future TOF)
1013    Seen when "Instrument Parameters" chosen from powder pattern data tree
1014    '''
1015    PatternId = self.PatternId
1016    limitID = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
1017    if limitID:
1018        limits = self.PatternTree.GetItemPyData(limitID)
1019    else:
1020        return
1021    instParms = self.PatternTree.GetItemPyData( \
1022        G2gd.GetPatternTreeItemId(self,PatternId, 'Instrument Parameters'))
1023    if instParms[0][0] == 'PXC':
1024        lam = instParms[1][1]
1025        if len(instParms[1]) == 13:
1026            GU,GV,GW,LX,LY = instParms[0][6:11]
1027        else:
1028            GU,GV,GW,LX,LY = instParms[0][4:9]
1029    peakID = G2gd.GetPatternTreeItemId(self,PatternId, 'Peak List')
1030    if peakID:
1031        peaks = self.PatternTree.GetItemPyData(peakID)
1032    else:
1033        peaks = []
1034   
1035    try:
1036        plotNum = self.G2plotNB.plotList.index('Peak Widths')
1037        Page = self.G2plotNB.nb.GetPage(plotNum)
1038        Page.figure.clf()
1039        Plot = Page.figure.gca()
1040    except ValueError:
1041        Plot = self.G2plotNB.addMpl('Peak Widths').gca()
1042        plotNum = self.G2plotNB.plotList.index('Peak Widths')
1043        Page = self.G2plotNB.nb.GetPage(plotNum)
1044    Page.SetFocus()
1045   
1046    Page.canvas.SetToolTipString('')
1047    colors=['b','g','r','c','m','k']
1048    Xmin,Xmax = limits[1]
1049    Xmin = min(0.5,max(Xmin,1))
1050    Xmin /= 2
1051    Xmax /= 2
1052    nPts = 100
1053    delt = (Xmax-Xmin)/nPts
1054    thetas = []
1055    for i in range(nPts):
1056        thetas.append(Xmin+i*delt)
1057    X = []
1058    Y = []
1059    Z = []
1060    W = []
1061    V = []
1062    sig = lambda Th,U,V,W: 1.17741*math.sqrt(U*tand(Th)**2+V*tand(Th)+W)*math.pi/18000.
1063    gam = lambda Th,X,Y: (X/cosd(Th)+Y*tand(Th))*math.pi/18000.
1064    gamFW = lambda s,g: math.exp(math.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.)
1065    gamFW2 = lambda s,g: math.sqrt(s**2+(0.4654996*g)**2)+.5345004*#Ubaldo Bafile - private communication
1066    for theta in thetas:
1067        X.append(4.0*math.pi*sind(theta)/lam)              #q
1068        s = sig(theta,GU,GV,GW)
1069        g = gam(theta,LX,LY)
1070        G = gamFW(g,s)
1071        H = gamFW2(g,s)
1072        Y.append(s/tand(theta))
1073        Z.append(g/tand(theta))
1074        W.append(G/tand(theta))
1075        V.append(H/tand(theta))
1076    Plot.set_title('Instrument and sample peak widths')
1077    Plot.set_ylabel(r'$\Delta q/q, \Delta d/d$',fontsize=14)
1078    Plot.set_xlabel(r'$q, \AA^{-1}$',fontsize=14)
1079    Plot.plot(X,Y,color='r',label='Gaussian')
1080    Plot.plot(X,Z,color='g',label='Lorentzian')
1081    Plot.plot(X,W,color='b',label='G+L')
1082    Plot.plot(X,V,color='k',label='G+L2')
1083    X = []
1084    Y = []
1085    Z = []
1086    W = []
1087    V = []
1088    for peak in peaks:
1089        X.append(4.0*math.pi*sind(peak[0]/2.0)/lam)
1090        s = 1.17741*math.sqrt(peak[4])*math.pi/18000.
1091        g = peak[6]*math.pi/18000.
1092        G = gamFW(g,s)
1093        H = gamFW2(g,s)
1094        Y.append(s/tand(peak[0]/2.))
1095        Z.append(g/tand(peak[0]/2.))
1096        W.append(G/tand(peak[0]/2.))
1097        V.append(H/tand(peak[0]/2.))
1098    Plot.plot(X,Y,'+',color='r',label='G peak')
1099    Plot.plot(X,Z,'+',color='g',label='L peak')
1100    Plot.plot(X,W,'+',color='b',label='G+L peak')
1101    Plot.plot(X,V,'+',color='k',label='G+L2 peak')
1102    Plot.legend(loc='best')
1103    Page.canvas.draw()
1104   
1105def PlotStrain(self,data):
1106    '''Plot 3D microstrain figure. In this instance data is for a phase
1107    '''
1108    PatternId = self.PatternId
1109    generalData = data['General']
1110    SGData = generalData['SGData']
1111    MuStrKeys = G2spc.MustrainNames(SGData)
1112    cell = generalData['Cell'][1:]
1113    A,B = G2lat.cell2AB(cell[:6])
1114    Vol = cell[6]
1115    useList = data['Histograms']
1116    for item in useList:
1117        if useList[item]['Show']:
1118            break
1119    else:
1120        self.G2plotNB.Delete('Microstrain')
1121        return            #nothing to show!!
1122   
1123    numPlots = len(useList)
1124   
1125    try:
1126        plotNum = self.G2plotNB.plotList.index('Microstrain')
1127        Page = self.G2plotNB.nb.GetPage(plotNum)
1128        Page.figure.clf()
1129        Plot = mp3d.Axes3D(Page.figure)
1130        if not Page.IsShown():
1131            Page.Show()
1132    except ValueError:
1133        Plot = mp3d.Axes3D(self.G2plotNB.add3D('Microstrain'))
1134        plotNum = self.G2plotNB.plotList.index('Microstrain')
1135        Page = self.G2plotNB.nb.GetPage(plotNum)
1136    Page.SetFocus()
1137    self.G2plotNB.status.SetStatusText('Adjust frame size to get desired aspect ratio',1)
1138   
1139    for item in useList:
1140        if useList[item]['Show']:
1141            muStrain = useList[item]['Mustrain']
1142            PHI = np.linspace(0.,360.,30,True)
1143            PSI = np.linspace(0.,180.,30,True)
1144            X = np.outer(npsind(PHI),npsind(PSI))
1145            Y = np.outer(npcosd(PHI),npsind(PSI))
1146            Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
1147            if muStrain[0] == 'isotropic':
1148                muiso = muStrain[1][0]*math.pi/0.018      #centidegrees to radians!
1149                X *= muiso
1150                Y *= muiso
1151                Z *= muiso               
1152               
1153            elif muStrain[0] == 'uniaxial':
1154                def uniaxMustrain(xyz,muiso,muaniso,axes):
1155                    cp = abs(np.dot(xyz,axes))
1156                    S = muiso+muaniso*cp
1157                    return S*xyz*math.pi/0.018      #centidegrees to radians!
1158                muiso,muaniso = muStrain[1][:2]
1159                axes = np.inner(A,np.array(muStrain[3]))
1160                axes /= nl.norm(axes)
1161                Shkl = np.array(muStrain[1])
1162                Shape = X.shape[0]
1163                XYZ = np.dstack((X,Y,Z))
1164                XYZ = np.nan_to_num(np.apply_along_axis(uniaxMustrain,2,XYZ,muiso,muaniso,axes))
1165                X,Y,Z = np.dsplit(XYZ,3)
1166                X = X[:,:,0]
1167                Y = Y[:,:,0]
1168                Z = Z[:,:,0]
1169               
1170            elif muStrain[0] == 'generalized':
1171                def genMustrain(xyz,SGData,A,Shkl):
1172                    uvw = np.inner(A.T,xyz)
1173                    Strm = np.array(G2spc.MustrainCoeff(uvw,SGData))
1174                    sum = np.sqrt(np.sum(np.multiply(Shkl,Strm)))*math.pi/0.018      #centidegrees to radians!
1175                    return sum*xyz
1176                Shkl = np.array(muStrain[4])
1177                if np.any(Shkl):
1178                    Shape = X.shape[0]
1179                    XYZ = np.dstack((X,Y,Z))
1180                    XYZ = np.nan_to_num(np.apply_along_axis(genMustrain,2,XYZ,SGData,A,Shkl))
1181                    X,Y,Z = np.dsplit(XYZ,3)
1182                    X = X[:,:,0]
1183                    Y = Y[:,:,0]
1184                    Z = Z[:,:,0]
1185                   
1186            if np.any(X) and np.any(Y) and np.any(Z):
1187                Plot.plot_surface(X,Y,Z,rstride=1,cstride=1,color='g')
1188               
1189            Plot.set_xlabel('X')
1190            Plot.set_ylabel('Y')
1191            Plot.set_zlabel('Z')
1192    Page.canvas.draw()
1193   
1194def PlotTexture(self,data,newPlot=False):
1195    '''Pole figure, inverse pole figure(?), 3D pole distribution and 3D inverse pole distribution(?)
1196    plotting; Need way to select 
1197    pole figure or pole distribution to be displayed - do in key enter menu
1198    dict generalData contains all phase info needed which is in data
1199    '''
1200
1201    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
1202    SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
1203    PatternId = self.PatternId
1204    generalData = data['General']
1205    SGData = generalData['SGData']
1206    textureData = generalData['SH Texture']
1207    if not textureData['Order']:
1208        self.G2plotNB.Delete('Texture')
1209        return                  #no plot!!
1210    SHData = generalData['SH Texture']
1211    SHCoef = SHData['SH Coeff'][1]
1212    cell = generalData['Cell'][1:7]
1213    Start = True
1214   
1215    def OnMotion(event):
1216        Page.canvas.SetToolTipString('')
1217        if event.xdata and event.ydata:                 #avoid out of frame errors
1218            if 'Pole figure' in SHData['PlotType']:
1219                xpos = event.xdata
1220                ypos = event.ydata
1221                Int = 0
1222                if xpos**2+ypos**2 < 1.0:
1223                    r,p = 2.*npasind(np.sqrt(xpos**2+ypos**2)*0.707106782),npatan2d(ypos,xpos)
1224                    pf = G2lat.polfcal(ODFln,SamSym[textureData['Model']],np.array([r,]),np.array([p,]))
1225                    self.G2plotNB.status.SetFields(['','phi =%9.3f, gam =%9.3f, MRD =%9.3f'%(r,p,pf)])
1226   
1227    try:
1228        plotNum = self.G2plotNB.plotList.index('Texture')
1229        Page = self.G2plotNB.nb.GetPage(plotNum)
1230        Page.figure.clf()
1231        Plot = Page.figure.gca()
1232        if not Page.IsShown():
1233            Page.Show()
1234    except ValueError:
1235        Plot = self.G2plotNB.addMpl('Texture').gca()
1236        plotNum = self.G2plotNB.plotList.index('Texture')
1237        Page = self.G2plotNB.nb.GetPage(plotNum)
1238        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1239        Page.SetFocus()
1240   
1241    if 'Axial' in SHData['PlotType']:
1242        PH = np.array(SHData['PFhkl'])
1243        phi,beta = G2lat.CrsAng(PH,cell,SGData)
1244        ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
1245        X = np.linspace(0,90.0,26)
1246        Y = G2lat.polfcal(ODFln,SamSym[textureData['Model']],X,0.0)
1247        Plot.plot(X,Y,color='k',label=str(SHData['PFhkl']))
1248        Plot.legend(loc='best')
1249        Plot.set_title('Axial distribution for HKL='+str(SHData['PFhkl']))
1250        Plot.set_xlabel(r'$\psi$',fontsize=16)
1251        Plot.set_ylabel('MRD',fontsize=14)
1252       
1253    else:       
1254        if 'Inverse' in SHData['PlotType']:
1255            PX = np.array(SHData['PFxyz'])
1256            gam = atan2d(PX[0],PX[1])
1257            xy = math.sqrt(PX[0]**2+PX[1]**2)
1258            xyz = math.sqrt(PX[0]**2+PX[1]**2+PX[2]**2)
1259            psi = asind(xy/xyz)
1260            npts = 201
1261            ODFln = G2lat.Glnh(Start,SHCoef,psi,gam,SamSym[textureData['Model']])
1262            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
1263            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
1264            R = np.where(R <= 1.,2.*npasind(R*0.70710678),0.0)
1265            Z = np.zeros_like(R)
1266            time0 = time.time()
1267            Z = G2lat.invpolfcal(ODFln,SGData,R,P)
1268            print 'inverse time:',time.time()-time0
1269            Z = np.reshape(Z,(npts,npts))
1270            CS = Plot.contour(Y,X,Z,aspect='equal')
1271            Plot.clabel(CS,fontsize=9,inline=1)
1272            Img = Plot.imshow(Z.T,aspect='equal',cmap='binary',extent=[-1,1,-1,1])
1273            if newPlot:
1274                Page.figure.colorbar(Img)
1275                newPlot = False
1276            Plot.set_title('Inverse pole figure for XYZ='+str(SHData['PFxyz']))
1277            print 'inverse pole figure',Img
1278                       
1279        else:
1280            PH = np.array(SHData['PFhkl'])
1281            phi,beta = G2lat.CrsAng(PH,cell,SGData)
1282            npts = 201
1283            ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
1284            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
1285            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
1286            R = np.where(R <= 1.,2.*npasind(R*0.70710678),0.0)
1287            Z = np.zeros_like(R)
1288            time0 = time.time()
1289            Z = G2lat.polfcal(ODFln,SamSym[textureData['Model']],R,P)
1290            print 'polfig time:',time.time()-time0
1291            Z = np.reshape(Z,(npts,npts))
1292            CS = Plot.contour(Y,X,Z,aspect='equal')
1293            Plot.clabel(CS,fontsize=9,inline=1)
1294            Img = Plot.imshow(Z.T,aspect='equal',cmap='binary',extent=[-1,1,-1,1])
1295            if newPlot:
1296                Page.figure.colorbar(Img)
1297                newPlot = False
1298            Plot.set_title('Pole figure for HKL='+str(SHData['PFhkl']))
1299            print 'pole figure',Img
1300    Page.canvas.draw()
1301           
1302def PlotExposedImage(self,newPlot=False,event=None):
1303    '''General access module for 2D image plotting
1304    '''
1305    plotNo = self.G2plotNB.nb.GetSelection()
1306    if self.G2plotNB.nb.GetPageText(plotNo) == '2D Powder Image':
1307        PlotImage(self,newPlot,event,newImage=True)
1308    elif self.G2plotNB.nb.GetPageText(plotNo) == '2D Integration':
1309        PlotIntegration(self,newPlot,event)
1310
1311def PlotImage(self,newPlot=False,event=None,newImage=True):
1312    '''Plot of 2D detector images as contoured plot. Also plot calibration ellipses,
1313    masks, etc.
1314    '''
1315    from matplotlib.patches import Ellipse,Arc,Circle,Polygon
1316    import numpy.ma as ma
1317    Dsp = lambda tth,wave: wave/(2.*sind(tth/2.))
1318    global Data,Masks
1319    colors=['b','g','r','c','m','k']
1320    Data = self.PatternTree.GetItemPyData(
1321        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1322    Masks = self.PatternTree.GetItemPyData(
1323        G2gd.GetPatternTreeItemId(self,self.Image, 'Masks'))
1324
1325    def OnImMotion(event):
1326        Page.canvas.SetToolTipString('')
1327        sizexy = Data['size']
1328        if event.xdata and event.ydata:                 #avoid out of frame errors
1329            Page.canvas.SetCursor(wx.CROSS_CURSOR)
1330            item = self.itemPicked
1331            pixelSize = Data['pixelSize']
1332            scalex = 1000./pixelSize[0]
1333            scaley = 1000./pixelSize[1]
1334            if item and self.PatternTree.GetItemText(self.PickId) == 'Image Controls':
1335                if 'Text' in str(item):
1336                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
1337                else:
1338                    xcent,ycent = Data['center']
1339                    xpos = event.xdata-xcent
1340                    ypos = event.ydata-ycent
1341                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
1342                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
1343                        Page.canvas.SetToolTipString('%6d deg'%(azm))
1344                    elif 'line1' in  str(item) or 'line2' in str(item):
1345                        Page.canvas.SetToolTipString('%8.3fdeg'%(tth))                           
1346            else:
1347                xpos = event.xdata
1348                ypos = event.ydata
1349                xpix = xpos*scalex
1350                ypix = ypos*scaley
1351                Int = 0
1352                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
1353                    Int = self.ImageZ[ypix][xpix]
1354                tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1355                Q = 2.*math.pi/dsp
1356                if self.setPoly:
1357                    self.G2plotNB.status.SetFields(['','Polygon mask pick - LB next point, RB close polygon'])
1358                else:
1359                    self.G2plotNB.status.SetFields(\
1360                        ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)])
1361
1362    def OnImPlotKeyPress(event):
1363        try:
1364            PickName = self.PatternTree.GetItemText(self.PickId)
1365        except TypeError:
1366            return
1367        if PickName == 'Masks':
1368            Xpos = event.xdata
1369            if not Xpos:            #got point out of frame
1370                return
1371            Ypos = event.ydata
1372            if event.key == 's':
1373                Masks['Points'].append([Xpos,Ypos,1.])
1374            elif event.key == 'r':
1375                tth = G2img.GetTth(Xpos,Ypos,Data)
1376                Masks['Rings'].append([tth,0.1])
1377            elif event.key == 'a':
1378                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
1379                azm = int(azm)               
1380                Masks['Arcs'].append([tth,[azm-5,azm+5],0.1])
1381            elif event.key == 'p':
1382                self.setPoly = True
1383                Masks['Polygons'].append([])
1384                self.G2plotNB.status.SetFields(['','Polygon mask active - LB pick next point, RB close polygon'])
1385            G2imG.UpdateMasks(self,Masks)
1386        elif PickName == 'Image Controls':
1387            if event.key == 'c':
1388                Xpos = event.xdata
1389                if not Xpos:            #got point out of frame
1390                    return
1391                Ypos = event.ydata
1392                dlg = wx.MessageDialog(self,'Are you sure you want to change the center?',
1393                    'Center change',style=wx.OK|wx.CANCEL)
1394                try:
1395                    if dlg.ShowModal() == wx.ID_OK:
1396                        print 'move center to: ',Xpos,Ypos
1397                        Data['center'] = [Xpos,Ypos]
1398                        G2imG.UpdateImageControls(self,Data,Masks)
1399                finally:
1400                    dlg.Destroy()
1401            elif event.key == 'l':
1402                if self.logPlot:
1403                    self.logPlot = False
1404                else:
1405                    self.logPlot = True
1406        PlotImage(self,newImage=True)
1407           
1408    def OnKeyBox(event):
1409        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index('2D Powder Image'):
1410            event.key = cb.GetValue()[0]
1411            cb.SetValue(' key press')
1412            if event.key in 'l':
1413                OnImPlotKeyPress(event)
1414                       
1415    def OnImPick(event):
1416        if self.PatternTree.GetItemText(self.PickId) not in ['Image Controls','Masks']:
1417            return
1418        if self.setPoly:
1419            polygon = Masks['Polygons'][-1]
1420            xpos,ypos = event.mouseevent.xdata,event.mouseevent.ydata
1421            if xpos and ypos:                       #point inside image
1422                if len(polygon) > 2 and event.mouseevent.button == 3:
1423                    x0,y0 = polygon[0]
1424                    polygon.append([x0,y0])
1425                    self.setPoly = False
1426                    self.G2plotNB.status.SetFields(['','Polygon closed - RB drag a vertex to change shape'])
1427                else:
1428                    self.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(xpos,ypos)])
1429                    polygon.append([xpos,ypos])
1430                G2imG.UpdateMasks(self,Masks)
1431        else:
1432            if self.itemPicked is not None: return
1433            self.itemPicked = event.artist
1434            self.mousePicked = event.mouseevent
1435       
1436    def OnImRelease(event):
1437        try:
1438            PickName = self.PatternTree.GetItemText(self.PickId)
1439        except TypeError:
1440            return
1441        if PickName not in ['Image Controls','Masks']:
1442            return
1443        pixelSize = Data['pixelSize']
1444        scalex = 1000./pixelSize[0]
1445        scaley = 1000./pixelSize[1]
1446        pixLimit = Data['pixLimit']
1447        if self.itemPicked is None and PickName == 'Image Controls':
1448#            sizexy = Data['size']
1449            Xpos = event.xdata
1450            if not (Xpos and self.ifGetRing):                   #got point out of frame
1451                return
1452            Ypos = event.ydata
1453            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
1454                if event.button == 1:
1455                    Xpix = Xpos*scalex
1456                    Ypix = Ypos*scaley
1457                    xpos,ypos,I,J = G2img.ImageLocalMax(self.ImageZ,pixLimit,Xpix,Ypix)
1458                    if I and J:
1459                        xpos += .5                              #shift to pixel center
1460                        ypos += .5
1461                        xpos /= scalex                          #convert to mm
1462                        ypos /= scaley
1463                        Data['ring'].append([xpos,ypos])
1464                elif event.button == 3:
1465                    self.dataFrame.GetStatusBar().SetStatusText('Calibrating...')
1466                    if G2img.ImageCalibrate(self,Data):
1467                        self.dataFrame.GetStatusBar().SetStatusText('Calibration successful - Show ring picks to check')
1468                        print 'Calibration successful'
1469                    else:
1470                        self.dataFrame.GetStatusBar().SetStatusText('Calibration failed - Show ring picks to diagnose')
1471                        print 'Calibration failed'
1472                    self.ifGetRing = False
1473                    G2imG.UpdateImageControls(self,Data,Masks)
1474                    return
1475                PlotImage(self,newImage=False)
1476            return
1477        else:
1478            xpos = event.xdata
1479            if xpos:                                        #avoid out of frame mouse position
1480                ypos = event.ydata
1481                if self.ifGetRing:                          #delete a calibration ring pick
1482                    xypos = [xpos,ypos]
1483                    rings = Data['ring']
1484                    for ring in rings:
1485                        if np.allclose(ring,xypos,.01,0):
1486                            rings.remove(ring)                                                                       
1487                else:
1488                    tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1489                    itemPicked = str(self.itemPicked)
1490                    if 'Line2D' in itemPicked and PickName == 'Image Controls':
1491                        if 'line1' in itemPicked:
1492                            Data['IOtth'][0] = max(tth,0.001)
1493                        elif 'line2' in itemPicked:
1494                            Data['IOtth'][1] = tth
1495                        elif 'line3' in itemPicked:
1496                            Data['LRazimuth'][0] = int(azm)
1497                            if Data['fullIntegrate']:
1498                                Data['LRazimuth'][1] = Data['LRazimuth'][0]+360
1499                        elif 'line4' in itemPicked and not Data['fullIntegrate']:
1500                            Data['LRazimuth'][1] = int(azm)
1501                           
1502                        if Data['LRazimuth'][0] > Data['LRazimuth'][1]:
1503                            Data['LRazimuth'][0] -= 360
1504                           
1505                        azLim = np.array(Data['LRazimuth'])   
1506                        if np.any(azLim>360):
1507                            azLim -= 360
1508                            Data['LRazimuth'] = list(azLim)
1509                           
1510                        if  Data['IOtth'][0] > Data['IOtth'][1]:
1511                            Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
1512                           
1513                        self.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
1514                        self.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
1515                        self.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
1516                        self.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
1517                    elif 'Circle' in itemPicked and PickName == 'Masks':
1518                        spots = Masks['Points']
1519                        newPos = itemPicked.split(')')[0].split('(')[2].split(',')
1520                        newPos = np.array([float(newPos[0]),float(newPos[1])])
1521                        for spot in spots:
1522                            if np.allclose(np.array([spot[:2]]),newPos):
1523                                spot[:2] = xpos,ypos
1524                        G2imG.UpdateMasks(self,Masks)
1525                    elif 'Line2D' in itemPicked and PickName == 'Masks':
1526                        Obj = self.itemPicked.findobj()
1527                        rings = Masks['Rings']
1528                        arcs = Masks['Arcs']
1529                        polygons = Masks['Polygons']
1530                        for ring in self.ringList:
1531                            if Obj == ring[0]:
1532                                rN = ring[1]
1533                                if ring[2] == 'o':
1534                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)-rings[rN][1]/2.
1535                                else:
1536                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)+rings[rN][1]/2.
1537                        for arc in self.arcList:
1538                            if Obj == arc[0]:
1539                                aN = arc[1]
1540                                if arc[2] == 'o':
1541                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)-arcs[aN][2]/2
1542                                elif arc[2] == 'i':
1543                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)+arcs[aN][2]/2
1544                                elif arc[2] == 'l':
1545                                    arcs[aN][1][0] = int(G2img.GetAzm(xpos,ypos,Data))
1546                                else:
1547                                    arcs[aN][1][1] = int(G2img.GetAzm(xpos,ypos,Data))
1548                        for poly in self.polyList:
1549                            if Obj == poly[0]:
1550                                ind = self.itemPicked.contains(self.mousePicked)[1]['ind'][0]
1551                                oldPos = np.array([self.mousePicked.xdata,self.mousePicked.ydata])
1552                                pN = poly[1]
1553                                for i,xy in enumerate(polygons[pN]):
1554                                    if np.allclose(np.array([xy]),oldPos,atol=1.0):
1555                                        polygons[pN][i] = xpos,ypos
1556                        G2imG.UpdateMasks(self,Masks)
1557#                    else:                  #keep for future debugging
1558#                        print str(self.itemPicked),event.xdata,event.ydata,event.button
1559                PlotImage(self,newImage=True)
1560            self.itemPicked = None
1561           
1562    try:
1563        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1564        Page = self.G2plotNB.nb.GetPage(plotNum)
1565        if not newPlot:
1566            Plot = Page.figure.gca()          #get previous powder plot & get limits
1567            xylim = Plot.get_xlim(),Plot.get_ylim()
1568        if newImage:
1569            Page.figure.clf()
1570            Plot = Page.figure.gca()          #get a fresh plot after clf()
1571       
1572    except ValueError:
1573        Plot = self.G2plotNB.addMpl('2D Powder Image').gca()
1574        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1575        Page = self.G2plotNB.nb.GetPage(plotNum)
1576        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
1577        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
1578        Page.canvas.mpl_connect('pick_event', OnImPick)
1579        Page.canvas.mpl_connect('button_release_event', OnImRelease)
1580        xylim = []
1581    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
1582        Page.SetFocus()
1583    Title = self.PatternTree.GetItemText(self.Image)[4:]
1584    self.G2plotNB.status.DestroyChildren()
1585    if self.logPlot:
1586        Title = 'log('+Title+')'
1587    Plot.set_title(Title)
1588    try:
1589        if self.PatternTree.GetItemText(self.PickId) in ['Image Controls',]:
1590            if self.logPlot:
1591                Choice = (' key press','l: log(I) off')
1592            else:
1593                Choice = (' key press','l: log(I) on')
1594            cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
1595                choices=Choice)
1596            cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
1597            cb.SetValue(' key press')
1598    except TypeError:
1599        pass
1600    size,imagefile = self.PatternTree.GetItemPyData(self.Image)
1601    if imagefile != self.oldImagefile:
1602        imagefile = G2IO.CheckImageFile(self,imagefile)
1603        if not imagefile:
1604            self.G2plotNB.Delete('2D Powder Image')
1605            return
1606        self.PatternTree.SetItemPyData(self.Image,[size,imagefile])
1607        self.ImageZ = G2IO.GetImageData(self,imagefile,imageOnly=True)
1608#        print self.ImageZ.shape,self.ImageZ.size,Data['size'] #might be useful debugging line
1609        self.oldImagefile = imagefile
1610
1611    imScale = 1
1612    if len(self.ImageZ) > 1024:
1613        imScale = len(self.ImageZ)/1024
1614    sizexy = Data['size']
1615    pixelSize = Data['pixelSize']
1616    scalex = 1000./pixelSize[0]
1617    scaley = 1000./pixelSize[1]
1618    Xmax = sizexy[0]*pixelSize[0]/1000.
1619    Ymax = sizexy[1]*pixelSize[1]/1000.
1620    xlim = (0,Xmax)
1621    ylim = (Ymax,0)
1622    Imin,Imax = Data['range'][1]
1623    acolor = mpl.cm.get_cmap(Data['color'])
1624    xcent,ycent = Data['center']
1625    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
1626    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
1627    #do threshold mask - "real" mask - others are just bondaries
1628    Zlim = Masks['Thresholds'][1]
1629    wx.BeginBusyCursor()
1630    try:
1631           
1632        if newImage:                   
1633            MA = ma.masked_greater(ma.masked_less(self.ImageZ,Zlim[0]),Zlim[1])
1634            MaskA = ma.getmaskarray(MA)
1635            A = G2img.ImageCompress(MA,imScale)
1636            AM = G2img.ImageCompress(MaskA,imScale)
1637            if self.logPlot:
1638                A = np.log(A)
1639                AM = np.log(AM)
1640                Imin,Imax = [np.amin(A),np.amax(A)]
1641            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
1642                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Xmax,0])
1643            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
1644                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
1645            if self.setPoly:
1646                Img.set_picker(True)
1647   
1648        Plot.plot(xcent,ycent,'x')
1649        if Data['showLines']:
1650            LRAzim = Data['LRazimuth']                  #NB: integers
1651            Nazm = Data['outAzimuths']
1652            delAzm = float(LRAzim[1]-LRAzim[0])/Nazm
1653            AzmthOff = Data['azmthOff']
1654            IOtth = Data['IOtth']
1655            wave = Data['wavelength']
1656            dspI = wave/(2.0*sind(IOtth[0]/2.0))
1657            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
1658            dspO = wave/(2.0*sind(IOtth[1]/2.0))
1659            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
1660            Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
1661            if ellI:
1662                xyI = []
1663                for azm in Azm:
1664                    xyI.append(G2img.GetDetectorXY(dspI,azm-90.,Data))
1665                xyI = np.array(xyI)
1666                arcxI,arcyI = xyI.T
1667                Plot.plot(arcxI,arcyI,picker=3)
1668            if ellO:
1669                xyO = []
1670                for azm in Azm:
1671                    xyO.append(G2img.GetDetectorXY(dspO,azm-90.,Data))
1672                xyO = np.array(xyO)
1673                arcxO,arcyO = xyO.T
1674                Plot.plot(arcxO,arcyO,picker=3)
1675            if ellO and ellI:
1676                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
1677                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
1678            for i in range(Nazm):
1679                cake = LRAzim[0]+i*delAzm
1680                ind = np.searchsorted(Azm,cake)
1681                Plot.plot([arcxI[ind],arcxO[ind]],[arcyI[ind],arcyO[ind]],color='k',dashes=(5,5))
1682                   
1683        for xring,yring in Data['ring']:
1684            Plot.plot(xring,yring,'r+',picker=3)
1685        if Data['setRings']:
1686#            rings = np.concatenate((Data['rings']),axis=0)
1687            N = 0
1688            for ring in Data['rings']:
1689                xring,yring = np.array(ring).T[:2]
1690                Plot.plot(xring,yring,'+',color=colors[N%6])
1691                N += 1           
1692        for ellipse in Data['ellipses']:
1693            cent,phi,[width,height],col = ellipse
1694            Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
1695            Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
1696        #masks - mask lines numbered after integration limit lines
1697        spots = Masks['Points']
1698        rings = Masks['Rings']
1699        arcs = Masks['Arcs']
1700        polygons = Masks['Polygons']
1701        for x,y,d in spots:
1702            Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
1703        self.ringList = []
1704        for iring,(tth,thick) in enumerate(rings):
1705            wave = Data['wavelength']
1706            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data))),2)
1707            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth-thick/2.,wave),Data))),2)
1708            self.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
1709            self.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
1710        self.arcList = []
1711        for iarc,(tth,azm,thick) in enumerate(arcs):           
1712            wave = Data['wavelength']
1713            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data),azm)),2)
1714            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(max(0.01,tth-thick/2.),wave),Data),azm)),2)
1715            self.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
1716            self.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
1717            self.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
1718            self.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
1719        self.polyList = []
1720        for ipoly,polygon in enumerate(polygons):
1721            x,y = np.hsplit(np.array(polygon),2)
1722            self.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
1723            Plot.plot(x,y,'r')           
1724        if newImage:
1725            colorBar = Page.figure.colorbar(Img)
1726        Plot.set_xlim(xlim)
1727        Plot.set_ylim(ylim)
1728        if not newPlot and xylim:
1729            Page.toolbar.push_current()
1730            Plot.set_xlim(xylim[0])
1731            Plot.set_ylim(xylim[1])
1732            xylim = []
1733            Page.toolbar.push_current()
1734            Page.toolbar.draw()
1735        else:
1736            Page.canvas.draw()
1737    finally:
1738        wx.EndBusyCursor()
1739       
1740def PlotIntegration(self,newPlot=False,event=None):
1741    '''Plot of 2D image after image integration with 2-theta and azimuth as coordinates
1742    '''
1743           
1744    def OnMotion(event):
1745        Page.canvas.SetToolTipString('')
1746        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1747        azm = event.ydata
1748        tth = event.xdata
1749        if azm and tth:
1750            self.G2plotNB.status.SetFields(\
1751                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1752                               
1753    try:
1754        plotNum = self.G2plotNB.plotList.index('2D Integration')
1755        Page = self.G2plotNB.nb.GetPage(plotNum)
1756        if not newPlot:
1757            Plot = Page.figure.gca()          #get previous plot & get limits
1758            xylim = Plot.get_xlim(),Plot.get_ylim()
1759        Page.figure.clf()
1760        Plot = Page.figure.gca()          #get a fresh plot after clf()
1761       
1762    except ValueError:
1763        Plot = self.G2plotNB.addMpl('2D Integration').gca()
1764        plotNum = self.G2plotNB.plotList.index('2D Integration')
1765        Page = self.G2plotNB.nb.GetPage(plotNum)
1766        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1767        Page.views = False
1768        view = False
1769    if not event:
1770        Page.SetFocus()
1771       
1772    Data = self.PatternTree.GetItemPyData(
1773        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1774    image = self.Integrate[0]
1775    xsc = self.Integrate[1]
1776    ysc = self.Integrate[2]
1777    Imin,Imax = Data['range'][1]
1778    acolor = mpl.cm.get_cmap(Data['color'])
1779    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1780    Plot.set_ylabel('azimuth',fontsize=12)
1781    Plot.set_xlabel('2-theta',fontsize=12)
1782    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
1783        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
1784    colorBar = Page.figure.colorbar(Img)
1785    if Data['setRings'] and Data['rings']:
1786        rings = np.concatenate((Data['rings']),axis=0)
1787        for xring,yring,dsp in rings:
1788            x,y = G2img.GetTthAzm(xring,yring,Data)
1789            Plot.plot(x,y,'r+')
1790    if Data['ellipses']:           
1791        for ellipse in Data['ellipses']:
1792            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1793            x,y = np.hsplit(ring,2)
1794            tth,azm = G2img.GetTthAzm(x,y,Data)
1795            azm = np.where(azm < 0.,azm+360,azm)
1796            Plot.plot(tth,azm,'b,')
1797    if not newPlot:
1798        Page.toolbar.push_current()
1799        Plot.set_xlim(xylim[0])
1800        Plot.set_ylim(xylim[1])
1801        xylim = []
1802        Page.toolbar.push_current()
1803        Page.toolbar.draw()
1804    else:
1805        Page.canvas.draw()
1806               
1807def PlotTRImage(self,tax,tay,taz,newPlot=False):
1808    '''a test plot routine - not normally used
1809    ''' 
1810           
1811    def OnMotion(event):
1812        Page.canvas.SetToolTipString('')
1813        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1814        azm = event.xdata
1815        tth = event.ydata
1816        if azm and tth:
1817            self.G2plotNB.status.SetFields(\
1818                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1819                               
1820    try:
1821        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1822        Page = self.G2plotNB.nb.GetPage(plotNum)
1823        if not newPlot:
1824            Plot = Page.figure.gca()          #get previous plot & get limits
1825            xylim = Plot.get_xlim(),Plot.get_ylim()
1826        Page.figure.clf()
1827        Plot = Page.figure.gca()          #get a fresh plot after clf()
1828       
1829    except ValueError:
1830        Plot = self.G2plotNB.addMpl('2D Transformed Powder Image').gca()
1831        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1832        Page = self.G2plotNB.nb.GetPage(plotNum)
1833        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1834        Page.views = False
1835        view = False
1836    Page.SetFocus()
1837       
1838    Data = self.PatternTree.GetItemPyData(
1839        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1840    Imin,Imax = Data['range'][1]
1841    step = (Imax-Imin)/5.
1842    V = np.arange(Imin,Imax,step)
1843    acolor = mpl.cm.get_cmap(Data['color'])
1844    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1845    Plot.set_xlabel('azimuth',fontsize=12)
1846    Plot.set_ylabel('2-theta',fontsize=12)
1847    Plot.contour(tax,tay,taz,V,cmap=acolor)
1848    if Data['showLines']:
1849        IOtth = Data['IOtth']
1850        if Data['fullIntegrate']:
1851            LRAzim = [-180,180]
1852        else:
1853            LRAzim = Data['LRazimuth']                  #NB: integers
1854        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[0],IOtth[0]],picker=True)
1855        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[1],IOtth[1]],picker=True)
1856        if not Data['fullIntegrate']:
1857            Plot.plot([LRAzim[0],LRAzim[0]],[IOtth[0],IOtth[1]],picker=True)
1858            Plot.plot([LRAzim[1],LRAzim[1]],[IOtth[0],IOtth[1]],picker=True)
1859    if Data['setRings']:
1860        rings = np.concatenate((Data['rings']),axis=0)
1861        for xring,yring,dsp in rings:
1862            x,y = G2img.GetTthAzm(xring,yring,Data)
1863            Plot.plot(y,x,'r+')           
1864    if Data['ellipses']:           
1865        for ellipse in Data['ellipses']:
1866            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1867            x,y = np.hsplit(ring,2)
1868            tth,azm = G2img.GetTthAzm(x,y,Data)
1869            Plot.plot(azm,tth,'b,')
1870    if not newPlot:
1871        Page.toolbar.push_current()
1872        Plot.set_xlim(xylim[0])
1873        Plot.set_ylim(xylim[1])
1874        xylim = []
1875        Page.toolbar.push_current()
1876        Page.toolbar.draw()
1877    else:
1878        Page.canvas.draw()
1879       
1880def PlotStructure(self,data):
1881    '''Crystal structure plotting package. Can show structures as balls, sticks, lines,
1882    thermal motion ellipsoids and polyhedra
1883    '''
1884    generalData = data['General']
1885    cell = generalData['Cell'][1:7]
1886    Amat,Bmat = G2lat.cell2AB(cell)         #Amat - crystal to cartesian, Bmat - inverse
1887    A4mat = np.concatenate((np.concatenate((Amat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1888    B4mat = np.concatenate((np.concatenate((Bmat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1889    Mydir = generalData['Mydir']
1890    atomData = data['Atoms']
1891    drawingData = data['Drawing']
1892    drawAtoms = drawingData['Atoms']
1893    cx,ct,cs = drawingData['atomPtrs']
1894    Wt = [255,255,255]
1895    Rd = [255,0,0]
1896    Gr = [0,255,0]
1897    Bl = [0,0,255]
1898    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]])
1899    uEdges = np.array([
1900        [uBox[0],uBox[1]],[uBox[0],uBox[3]],[uBox[0],uBox[4]],[uBox[1],uBox[2]], 
1901        [uBox[2],uBox[3]],[uBox[1],uBox[5]],[uBox[2],uBox[6]],[uBox[3],uBox[7]], 
1902        [uBox[4],uBox[5]],[uBox[5],uBox[6]],[uBox[6],uBox[7]],[uBox[7],uBox[4]]])
1903    uColors = [Rd,Gr,Bl,Wt, Wt,Wt,Wt,Wt, Wt,Wt,Wt,Wt]
1904    altDown = False
1905    shiftDown = False
1906    ctrlDown = False
1907   
1908    def OnKeyBox(event):
1909        import Image
1910        Draw()                          #make sure plot is fresh!!
1911        mode = cb.GetValue()
1912        Fname = Mydir+'\\'+generalData['Name']+'.'+mode
1913        size = Page.canvas.GetSize()
1914        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
1915        if mode in ['jpeg',]:
1916            Pix = glReadPixels(0,0,size[0],size[1],GL_RGBA, GL_UNSIGNED_BYTE)
1917            im = Image.new("RGBA", (size[0],size[1]))
1918        else:
1919            Pix = glReadPixels(0,0,size[0],size[1],GL_RGB, GL_UNSIGNED_BYTE)
1920            im = Image.new("RGB", (size[0],size[1]))
1921        im.fromstring(Pix)
1922        im.save(Fname,mode)
1923        cb.SetValue(' Save as:')
1924        self.G2plotNB.status.SetStatusText('Drawing saved to: '+Fname,1)
1925   
1926    def GetTruePosition(xy):
1927        View = glGetIntegerv(GL_VIEWPORT)
1928        Proj = glGetDoublev(GL_PROJECTION_MATRIX)
1929        Model = glGetDoublev(GL_MODELVIEW_MATRIX)
1930        Zmax = 1.
1931        for i,atom in enumerate(drawAtoms):
1932            x,y,z = atom[cx:cx+3]
1933            X,Y,Z = gluProject(x,y,z,Model,Proj,View)
1934            XY = [int(X),int(View[3]-Y)]
1935            if np.allclose(xy,XY,atol=10) and Z < Zmax:
1936                Zmax = Z
1937                SetSelectedAtoms(i)
1938                   
1939    def OnMouseDown(event):
1940        xy = event.GetPosition()
1941        if event.ShiftDown():
1942            GetTruePosition(xy)
1943        else:
1944            drawingData['Rotation'][3] = xy
1945        Draw()
1946       
1947    def OnMouseMove(event):
1948        newxy = event.GetPosition()
1949        page = getSelection()
1950        if event.ControlDown() and drawingData['showABC']:
1951            if event.LeftIsDown():
1952                SetTestRot(newxy)
1953            elif event.RightIsDown():
1954                SetTestPos(newxy)
1955            elif event.MiddleIsDown():
1956                SetTestRotZ(newxy)
1957            x,y,z = drawingData['testPos'][0]
1958            self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
1959               
1960               
1961        if event.Dragging() and not event.ControlDown():
1962            if event.LeftIsDown():
1963                SetRotation(newxy)
1964                angX,angY,angZ = drawingData['Rotation'][:3]
1965                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f ,%.2f'%(angX,angY,angZ),1)
1966            elif event.RightIsDown():
1967                SetTranslation(newxy)
1968                Tx,Ty,Tz = drawingData['viewPoint'][0]
1969                self.G2plotNB.status.SetStatusText('New view point: %.4f, %.4f, %.4f'%(Tx,Ty,Tz),1)
1970            elif event.MiddleIsDown():
1971                SetRotationZ(newxy)
1972                angX,angY,angZ = drawingData['Rotation'][:3]
1973                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f, %.2f'%(angX,angY,angZ),1)
1974        Draw()
1975       
1976    def OnMouseWheel(event):
1977        drawingData['cameraPos'] += event.GetWheelRotation()/24
1978        drawingData['cameraPos'] = max(10,min(500,drawingData['cameraPos']))
1979        self.G2plotNB.status.SetStatusText('New camera distance: %.2f'%(drawingData['cameraPos']),1)
1980        page = getSelection()
1981        if page:
1982            if self.dataDisplay.GetPageText(page) == 'Draw Options':
1983                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
1984                names = [child.GetName() for child in panel]
1985                panel[names.index('cameraPos')].SetLabel('Camera Position: '+'%.2f'%(drawingData['cameraPos']))
1986                panel[names.index('cameraSlider')].SetValue(drawingData['cameraPos'])
1987        Draw()
1988       
1989    def getSelection():
1990        try:
1991            return self.dataDisplay.GetSelection()
1992        except AttributeError:
1993            print self.dataDisplay.GetLabel()
1994            self.G2plotNB.status.SetStatusText('Select this from Phase data window!')
1995            return 0
1996           
1997    def SetViewPointText(VP):
1998        page = getSelection()
1999        if page:
2000            if self.dataDisplay.GetPageText(page) == 'Draw Options':
2001                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
2002                names = [child.GetName() for child in panel]
2003                panel[names.index('viewPoint')].SetValue('%.3f, %.3f, %.3f'%(VP[0],VP[1],VP[2]))
2004           
2005    def ClearSelectedAtoms():
2006        page = getSelection()
2007        if page:
2008            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2009                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Draw Atoms
2010            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2011                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Atoms
2012                   
2013    def SetSelectedAtoms(ind):
2014        page = getSelection()
2015        if page:
2016            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2017                self.dataDisplay.GetPage(page).SelectRow(ind)      #this is the Atoms grid in Draw Atoms
2018            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2019                Id = drawAtoms[ind][-2]
2020                for i,atom in enumerate(atomData):
2021                    if atom[-1] == Id:
2022                        self.dataDisplay.GetPage(page).SelectRow(i)      #this is the Atoms grid in Atoms
2023                 
2024    def GetSelectedAtoms():
2025        page = getSelection()
2026        Ind = []
2027        if page:
2028            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2029                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Draw Atoms
2030            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2031                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Atoms
2032        return Ind
2033                                       
2034    def OnKey(event):           #on key UP!!
2035        keyCode = event.GetKeyCode()
2036        if keyCode > 255:
2037            keyCode = 0
2038        key,xyz = chr(keyCode),event.GetPosition()
2039        indx = drawingData['selectedAtoms']
2040        if key in ['c','C']:
2041            drawingData['viewPoint'] = [[.5,.5,.5],[0,0]]
2042            drawingData['testPos'] = [[-.1,-.1,-.1],[0.0,0.0,0.0],[0,0]]
2043            drawingData['Rotation'] = [0.0,0.0,0.0,[]]
2044            SetViewPointText(drawingData['viewPoint'][0])
2045        elif key in ['n','N']:
2046            drawAtoms = drawingData['Atoms']
2047            pI = drawingData['viewPoint'][1]
2048            if indx:
2049                pI[0] = indx[pI[1]]
2050                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2051                pI[1] += 1
2052                if pI[1] >= len(indx):
2053                    pI[1] = 0
2054            else:
2055                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2056                pI[0] += 1
2057                if pI[0] >= len(drawAtoms):
2058                    pI[0] = 0
2059            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2060            SetViewPointText(drawingData['viewPoint'][0])
2061               
2062        elif key in ['p','P']:
2063            drawAtoms = drawingData['Atoms']
2064            pI = drawingData['viewPoint'][1]
2065            if indx:
2066                pI[0] = indx[pI[1]]
2067                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2068                pI[1] -= 1
2069                if pI[1] < 0:
2070                    pI[1] = len(indx)-1
2071            else:
2072                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2073                pI[0] -= 1
2074                if pI[0] < 0:
2075                    pI[0] = len(drawAtoms)-1
2076            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2077            SetViewPointText(drawingData['viewPoint'][0])           
2078        Draw()
2079           
2080    def SetBackground():
2081        R,G,B,A = Page.camera['backColor']
2082        glClearColor(R,G,B,A)
2083        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
2084       
2085    def SetLights():
2086        glEnable(GL_DEPTH_TEST)
2087        glShadeModel(GL_SMOOTH)
2088        glEnable(GL_LIGHTING)
2089        glEnable(GL_LIGHT0)
2090        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0)
2091        glLightfv(GL_LIGHT0,GL_AMBIENT,[1,1,1,.8])
2092        glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
2093       
2094    def SetTranslation(newxy):
2095        Tx,Ty,Tz = drawingData['viewPoint'][0]
2096        anglex,angley,anglez,oldxy = drawingData['Rotation']
2097        Rx = G2lat.rotdMat(anglex,0)
2098        Ry = G2lat.rotdMat(angley,1)
2099        Rz = G2lat.rotdMat(anglez,2)
2100        dxy = list(newxy-oldxy)+[0,]
2101        dxy = np.inner(Bmat,np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy))))
2102        Tx -= dxy[0]*0.01
2103        Ty += dxy[1]*0.01
2104        Tz -= dxy[2]*0.01
2105        drawingData['Rotation'][3] = newxy
2106        drawingData['viewPoint'][0] =  Tx,Ty,Tz
2107        SetViewPointText([Tx,Ty,Tz])
2108       
2109    def SetTestPos(newxy):
2110        Tx,Ty,Tz = drawingData['testPos'][0]
2111        anglex,angley,anglez,oldxy = drawingData['Rotation']
2112        Rx = G2lat.rotdMat(anglex,0)
2113        Ry = G2lat.rotdMat(angley,1)
2114        Rz = G2lat.rotdMat(anglez,2)
2115        dxy = list(newxy-oldxy)+[0,]
2116        dxy = np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy)))
2117        Tx += dxy[0]*0.001
2118        Ty -= dxy[1]*0.001
2119        Tz += dxy[2]*0.001
2120        drawingData['Rotation'][3] = newxy
2121        drawingData['testPos'][0] =  Tx,Ty,Tz
2122       
2123    def SetTestRot(newxy):
2124        Txyz = np.array(drawingData['testPos'][0])
2125        oldxy = drawingData['testPos'][2]
2126        Ax,Ay,Az = drawingData['testPos'][1]
2127        Vxyz = np.array(drawingData['viewPoint'][0])
2128        Dxyz = np.inner(Amat,Txyz-Vxyz)
2129        dxy = list(newxy-oldxy)+[0,]
2130        Ax += dxy[1]*0.01
2131        Ay += dxy[0]*0.01
2132        Rx = G2lat.rotdMat(Ax,0)
2133        Ry = G2lat.rotdMat(Ay,1)
2134        Dxyz = np.inner(Ry,np.inner(Rx,Dxyz))       
2135        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
2136        drawingData['testPos'][1] = [Ax,Ay,Az]
2137        drawingData['testPos'][2] = newxy
2138        drawingData['testPos'][0] = Dxyz
2139       
2140    def SetTestRotZ(newxy):
2141        Txyz = np.array(drawingData['testPos'][0])
2142        oldxy = drawingData['testPos'][2]
2143        Ax,Ay,Az = drawingData['testPos'][1]
2144        Vxyz = np.array(drawingData['viewPoint'][0])
2145        Dxyz = np.inner(Amat,Txyz-Vxyz)       
2146        dxy = list(newxy-oldxy)+[0,]
2147        Az += (dxy[0]+dxy[1])*.01
2148        Rz = G2lat.rotdMat(Az,2)
2149        Dxyz = np.inner(Rz,Dxyz)       
2150        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
2151        drawingData['testPos'][1] = [Ax,Ay,Az]
2152        drawingData['testPos'][2] = newxy
2153        drawingData['testPos'][0] = Dxyz
2154                             
2155    def SetRotation(newxy):       
2156        anglex,angley,anglez,oldxy = drawingData['Rotation']
2157        dxy = newxy-oldxy
2158        anglex += dxy[1]*.25
2159        angley += dxy[0]*.25
2160        oldxy = newxy
2161        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2162       
2163    def SetRotationZ(newxy):                       
2164        anglex,angley,anglez,oldxy = drawingData['Rotation']
2165        dxy = newxy-oldxy
2166        anglez += (dxy[0]+dxy[1])*.25
2167        oldxy = newxy
2168        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2169       
2170    def RenderBox():
2171        glEnable(GL_COLOR_MATERIAL)
2172        glLineWidth(2)
2173        glEnable(GL_BLEND)
2174        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
2175        glEnable(GL_LINE_SMOOTH)
2176        glBegin(GL_LINES)
2177        for line,color in zip(uEdges,uColors):
2178            glColor3ubv(color)
2179            glVertex3fv(line[0])
2180            glVertex3fv(line[1])
2181        glEnd()
2182        glColor4ubv([0,0,0,0])
2183        glDisable(GL_LINE_SMOOTH)
2184        glDisable(GL_BLEND)
2185        glDisable(GL_COLOR_MATERIAL)
2186       
2187    def RenderUnitVectors(x,y,z):
2188        xyz = np.array([x,y,z])
2189        glEnable(GL_COLOR_MATERIAL)
2190        glLineWidth(1)
2191        glPushMatrix()
2192        glTranslate(x,y,z)
2193        glScalef(1/cell[0],1/cell[1],1/cell[2])
2194        glBegin(GL_LINES)
2195        for line,color in zip(uEdges,uColors)[:3]:
2196            glColor3ubv(color)
2197            glVertex3fv(line[0])
2198            glVertex3fv(line[1])
2199        glEnd()
2200        glPopMatrix()
2201        glColor4ubv([0,0,0,0])
2202        glDisable(GL_COLOR_MATERIAL)
2203               
2204    def RenderSphere(x,y,z,radius,color):
2205        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2206        glPushMatrix()
2207        glTranslate(x,y,z)
2208        glMultMatrixf(B4mat.T)
2209        q = gluNewQuadric()
2210        gluSphere(q,radius,20,10)
2211        glPopMatrix()
2212       
2213    def RenderEllipsoid(x,y,z,ellipseProb,E,R4,color):
2214        s1,s2,s3 = E
2215        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2216        glPushMatrix()
2217        glTranslate(x,y,z)
2218        glMultMatrixf(B4mat.T)
2219        glMultMatrixf(R4.T)
2220        glEnable(GL_NORMALIZE)
2221        glScale(s1,s2,s3)
2222        q = gluNewQuadric()
2223        gluSphere(q,ellipseProb,20,10)
2224        glDisable(GL_NORMALIZE)
2225        glPopMatrix()
2226       
2227    def RenderBonds(x,y,z,Bonds,radius,color,slice=20):
2228        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2229        glPushMatrix()
2230        glTranslate(x,y,z)
2231        glMultMatrixf(B4mat.T)
2232        for bond in Bonds:
2233            glPushMatrix()
2234            Dx = np.inner(Amat,bond)
2235            Z = np.sqrt(np.sum(Dx**2))
2236            azm = atan2d(-Dx[1],-Dx[0])
2237            phi = acosd(Dx[2]/Z)
2238            glRotate(-azm,0,0,1)
2239            glRotate(phi,1,0,0)
2240            q = gluNewQuadric()
2241            gluCylinder(q,radius,radius,Z,slice,2)
2242            glPopMatrix()           
2243        glPopMatrix()
2244               
2245    def RenderLines(x,y,z,Bonds,color):
2246        xyz = np.array([x,y,z])
2247        glEnable(GL_COLOR_MATERIAL)
2248        glLineWidth(1)
2249        glColor3fv(color)
2250        glPushMatrix()
2251        glBegin(GL_LINES)
2252        for bond in Bonds:
2253            glVertex3fv(xyz)
2254            glVertex3fv(xyz+bond)
2255        glEnd()
2256        glColor4ubv([0,0,0,0])
2257        glPopMatrix()
2258        glDisable(GL_COLOR_MATERIAL)
2259       
2260    def RenderPolyhedra(x,y,z,Faces,color):
2261        glPushMatrix()
2262        glTranslate(x,y,z)
2263        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2264        glShadeModel(GL_SMOOTH)
2265        glMultMatrixf(B4mat.T)
2266        for face,norm in Faces:
2267            glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
2268            glFrontFace(GL_CW)
2269            glNormal3fv(norm)
2270            glBegin(GL_TRIANGLES)
2271            for vert in face:
2272                glVertex3fv(vert)
2273            glEnd()
2274        glPopMatrix()
2275       
2276    def RenderBackbone(Backbone,BackboneColor,radius):
2277        glPushMatrix()
2278        glMultMatrixf(B4mat.T)
2279        glEnable(GL_COLOR_MATERIAL)
2280        glShadeModel(GL_SMOOTH)
2281        gleSetJoinStyle(TUBE_NORM_EDGE | TUBE_JN_ANGLE | TUBE_JN_CAP)
2282        glePolyCylinder(Backbone,BackboneColor,radius)
2283        glPopMatrix()       
2284        glDisable(GL_COLOR_MATERIAL)
2285       
2286    def RenderLabel(x,y,z,label,r):       
2287        glPushMatrix()
2288        glTranslate(x,y,z)
2289        glMultMatrixf(B4mat.T)
2290        glDisable(GL_LIGHTING)
2291        glColor3f(0,1.,0)
2292        glRasterPos3f(r,r,r)
2293        for c in list(label):
2294            glutBitmapCharacter(GLUT_BITMAP_8_BY_13,ord(c))
2295        glEnable(GL_LIGHTING)
2296        glPopMatrix()
2297                           
2298    def Draw():
2299        import numpy.linalg as nl
2300        Ind = GetSelectedAtoms()
2301        VS = np.array(Page.canvas.GetSize())
2302        aspect = float(VS[0])/float(VS[1])
2303        cPos = drawingData['cameraPos']
2304        Zclip = drawingData['Zclip']*cPos/200.
2305        anglex,angley,anglez = drawingData['Rotation'][:3]
2306        Tx,Ty,Tz = drawingData['viewPoint'][0]
2307        cx,ct,cs = drawingData['atomPtrs']
2308        bondR = drawingData['bondRadius']
2309        G,g = G2lat.cell2Gmat(cell)
2310        GS = G
2311        GS[0][1] = GS[1][0] = math.sqrt(GS[0][0]*GS[1][1])
2312        GS[0][2] = GS[2][0] = math.sqrt(GS[0][0]*GS[2][2])
2313        GS[1][2] = GS[2][1] = math.sqrt(GS[1][1]*GS[2][2])
2314        ellipseProb = G2lat.criticalEllipse(drawingData['ellipseProb']/100.)
2315       
2316        SetBackground()
2317        glInitNames()
2318        glPushName(0)
2319       
2320        glMatrixMode(GL_PROJECTION)
2321        glLoadIdentity()
2322        glViewport(0,0,VS[0],VS[1])
2323        gluPerspective(20.,aspect,cPos-Zclip,cPos+Zclip)
2324        gluLookAt(0,0,cPos,0,0,0,0,1,0)
2325        SetLights()           
2326           
2327        glMatrixMode(GL_MODELVIEW)
2328        glLoadIdentity()
2329        glRotate(anglez,0,0,1)
2330        glRotate(anglex,cosd(anglez),-sind(anglez),0)
2331        glRotate(angley,sind(anglez),cosd(anglez),0)
2332        glMultMatrixf(A4mat.T)
2333        glTranslate(-Tx,-Ty,-Tz)
2334        if drawingData['unitCellBox']:
2335            RenderBox()
2336        if drawingData['showABC']:
2337            x,y,z = drawingData['testPos'][0]
2338#            if altDown:
2339#                self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
2340#            else:
2341#                self.G2plotNB.status.SetStatusText('test point %.4f,%.4f,%.4f'%(x,y,z),1)           
2342            RenderUnitVectors(x,y,z)
2343        Backbone = []
2344        BackboneColor = []
2345        time0 = time.time()
2346        for iat,atom in enumerate(drawingData['Atoms']):
2347            x,y,z = atom[cx:cx+3]
2348            Bonds = atom[-2]
2349            Faces = atom[-1]
2350            try:
2351                atNum = generalData['AtomTypes'].index(atom[ct])
2352            except ValueError:
2353                atNum = -1
2354            CL = atom[cs+2]
2355            color = np.array(CL)/255.
2356            if iat in Ind:
2357                color = np.array(Gr)/255.
2358            radius = 0.5
2359            if atom[cs] != '':
2360                glLoadName(atom[-3])                   
2361            if 'balls' in atom[cs]:
2362                vdwScale = drawingData['vdwScale']
2363                ballScale = drawingData['ballScale']
2364                if atNum < 0:
2365                    radius = 0.2
2366                elif 'H' == atom[ct]:
2367                    if drawingData['showHydrogen']:
2368                        if 'vdW' in atom[cs] and atNum >= 0:
2369                            radius = vdwScale*generalData['vdWRadii'][atNum]
2370                        else:
2371                            radius = ballScale*drawingData['sizeH']
2372                    else:
2373                        radius = 0.0
2374                else:
2375                    if 'vdW' in atom[cs]:
2376                        radius = vdwScale*generalData['vdWRadii'][atNum]
2377                    else:
2378                        radius = ballScale*generalData['BondRadii'][atNum]
2379                RenderSphere(x,y,z,radius,color)
2380                if 'sticks' in atom[cs]:
2381                    RenderBonds(x,y,z,Bonds,bondR,color)
2382            elif 'ellipsoids' in atom[cs]:
2383                RenderBonds(x,y,z,Bonds,bondR,color)
2384                if atom[cs+3] == 'A':                   
2385                    Uij = atom[cs+5:cs+11]
2386                    U = np.multiply(G2spc.Uij2U(Uij),GS)
2387                    U = np.inner(Amat,np.inner(U,Amat).T)
2388                    E,R = nl.eigh(U)
2389                    R4 = np.concatenate((np.concatenate((R,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
2390                    E = np.sqrt(E)
2391                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2392                        pass
2393                    else:
2394                        RenderEllipsoid(x,y,z,ellipseProb,E,R4,color)                   
2395                else:
2396                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2397                        pass
2398                    else:
2399                        radius = ellipseProb*math.sqrt(abs(atom[cs+4]))
2400                        RenderSphere(x,y,z,radius,color)
2401            elif 'lines' in atom[cs]:
2402                radius = 0.1
2403                RenderLines(x,y,z,Bonds,color)
2404#                RenderBonds(x,y,z,Bonds,0.05,color,6)
2405            elif atom[cs] == 'sticks':
2406                radius = 0.1
2407                RenderBonds(x,y,z,Bonds,bondR,color)
2408            elif atom[cs] == 'polyhedra':
2409                RenderPolyhedra(x,y,z,Faces,color)
2410            elif atom[cs] == 'backbone':
2411                if atom[ct-1].split()[0] in ['C','N']:
2412                    Backbone.append(list(np.inner(Amat,np.array([x,y,z]))))
2413                    BackboneColor.append(list(color))
2414                   
2415            if atom[cs+1] == 'type':
2416                RenderLabel(x,y,z,atom[ct],radius)
2417            elif atom[cs+1] == 'name':
2418                RenderLabel(x,y,z,atom[ct-1],radius)
2419            elif atom[cs+1] == 'number':
2420                RenderLabel(x,y,z,str(iat+1),radius)
2421            elif atom[cs+1] == 'residue' and atom[ct-1] == 'CA':
2422                RenderLabel(x,y,z,atom[ct-4],radius)
2423            elif atom[cs+1] == '1-letter' and atom[ct-1] == 'CA':
2424                RenderLabel(x,y,z,atom[ct-3],radius)
2425            elif atom[cs+1] == 'chain' and atom[ct-1] == 'CA':
2426                RenderLabel(x,y,z,atom[ct-2],radius)
2427        if Backbone:
2428            RenderBackbone(Backbone,BackboneColor,bondR)
2429#        print time.time()-time0
2430        Page.canvas.SwapBuffers()
2431       
2432    def OnSize(event):
2433        Draw()
2434       
2435    def OnFocus(event):
2436        Draw()
2437       
2438    try:
2439        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2440        Page = self.G2plotNB.nb.GetPage(plotNum)       
2441    except ValueError:
2442        Plot = self.G2plotNB.addOgl(generalData['Name'])
2443        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2444        Page = self.G2plotNB.nb.GetPage(plotNum)
2445        Page.views = False
2446        view = False
2447        altDown = False
2448    Page.SetFocus()
2449    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
2450        choices=(' save as:','jpeg','tiff','bmp'))
2451    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
2452    cb.SetValue(' save as:')
2453    Page.canvas.Bind(wx.EVT_MOUSEWHEEL, OnMouseWheel)
2454    Page.canvas.Bind(wx.EVT_LEFT_DOWN, OnMouseDown)
2455    Page.canvas.Bind(wx.EVT_RIGHT_DOWN, OnMouseDown)
2456    Page.canvas.Bind(wx.EVT_MIDDLE_DOWN, OnMouseDown)
2457    Page.canvas.Bind(wx.EVT_KEY_UP, OnKey)
2458    Page.canvas.Bind(wx.EVT_MOTION, OnMouseMove)
2459    Page.canvas.Bind(wx.EVT_SIZE, OnSize)
2460    Page.canvas.Bind(wx.EVT_SET_FOCUS, OnFocus)
2461    Page.camera['position'] = drawingData['cameraPos']
2462    Page.camera['viewPoint'] = np.inner(Amat,drawingData['viewPoint'][0])
2463    Page.camera['backColor'] = np.array(list(drawingData['backColor'])+[0,])/255.
2464    Page.canvas.SetCurrent()
2465    Draw()
2466       
Note: See TracBrowser for help on using the repository browser.