source: trunk/GSASIIplot.py @ 327

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

fix to path name for atomdata.dat
fix to texture display - can't have colorbars!
put in bit to show #threads used

  • Property svn:keywords set to Date Author Revision URL Id
File size: 103.5 KB
Line 
1#GSASII plotting routines
2########### SVN repository information ###################
3# $Date: 2011-07-01 17:10:28 +0000 (Fri, 01 Jul 2011) $
4# $Author: vondreele $
5# $Revision: 327 $
6# $URL: trunk/GSASIIplot.py $
7# $Id: GSASIIplot.py 327 2011-07-01 17:10:28Z 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,Start=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   
1214    def OnMotion(event):
1215        Page.canvas.SetToolTipString('')
1216        if event.xdata and event.ydata:                 #avoid out of frame errors
1217            if 'Pole figure' in SHData['PlotType']:
1218                xpos = event.xdata
1219                ypos = event.ydata
1220                Int = 0
1221                if xpos**2+ypos**2 < 1.0:
1222                    r,p = 2.*npasind(np.sqrt(xpos**2+ypos**2)*0.707106782),npatan2d(ypos,xpos)
1223                    pf = G2lat.polfcal(ODFln,SamSym[textureData['Model']],np.array([r,]),np.array([p,]))
1224                    self.G2plotNB.status.SetFields(['','phi =%9.3f, gam =%9.3f, MRD =%9.3f'%(r,p,pf)])
1225   
1226    try:
1227        plotNum = self.G2plotNB.plotList.index('Texture')
1228        Page = self.G2plotNB.nb.GetPage(plotNum)
1229        Page.figure.clf()
1230        Plot = Page.figure.gca()
1231        if not Page.IsShown():
1232            Page.Show()
1233    except ValueError:
1234        Plot = self.G2plotNB.addMpl('Texture').gca()
1235        plotNum = self.G2plotNB.plotList.index('Texture')
1236        Page = self.G2plotNB.nb.GetPage(plotNum)
1237        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1238        Page.SetFocus()
1239   
1240    if 'Axial' in SHData['PlotType']:
1241        PH = np.array(SHData['PFhkl'])
1242        phi,beta = G2lat.CrsAng(PH,cell,SGData)
1243        ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
1244        X = np.linspace(0,90.0,26)
1245        Y = G2lat.polfcal(ODFln,SamSym[textureData['Model']],X,0.0)
1246        Plot.plot(X,Y,color='k',label=str(SHData['PFhkl']))
1247        Plot.legend(loc='best')
1248        Plot.set_title('Axial distribution for HKL='+str(SHData['PFhkl']))
1249        Plot.set_xlabel(r'$\psi$',fontsize=16)
1250        Plot.set_ylabel('MRD',fontsize=14)
1251       
1252    else:       
1253        if 'Inverse' in SHData['PlotType']:
1254            PX = np.array(SHData['PFxyz'])
1255            gam = atan2d(PX[0],PX[1])
1256            xy = math.sqrt(PX[0]**2+PX[1]**2)
1257            xyz = math.sqrt(PX[0]**2+PX[1]**2+PX[2]**2)
1258            psi = asind(xy/xyz)
1259            npts = 201
1260            ODFln = G2lat.Glnh(Start,SHCoef,psi,gam,SamSym[textureData['Model']])
1261            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
1262            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
1263            R = np.where(R <= 1.,2.*npasind(R*0.70710678),0.0)
1264            Z = np.zeros_like(R)
1265            Z = G2lat.invpolfcal(ODFln,SGData,R,P)
1266            Z = np.reshape(Z,(npts,npts))
1267            CS = Plot.contour(Y,X,Z,aspect='equal')
1268            Plot.clabel(CS,fontsize=9,inline=1)
1269            Img = Plot.imshow(Z.T,aspect='equal',cmap='binary',extent=[-1,1,-1,1])
1270            if newPlot:
1271#                Page.figure.colorbar(Img)    #colorbar fails - crashes gsasii
1272                newPlot = False
1273            Plot.set_title('Inverse pole figure for XYZ='+str(SHData['PFxyz']))
1274                       
1275        else:
1276            PH = np.array(SHData['PFhkl'])
1277            phi,beta = G2lat.CrsAng(PH,cell,SGData)
1278            npts = 201
1279            ODFln = G2lat.Flnh(Start,SHCoef,phi,beta,SGData)
1280            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
1281            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
1282            R = np.where(R <= 1.,2.*npasind(R*0.70710678),0.0)
1283            Z = np.zeros_like(R)
1284            Z = G2lat.polfcal(ODFln,SamSym[textureData['Model']],R,P)
1285            Z = np.reshape(Z,(npts,npts))
1286            CS = Plot.contour(Y,X,Z,aspect='equal')
1287            Plot.clabel(CS,fontsize=9,inline=1)
1288            Img = Plot.imshow(Z.T,aspect='equal',cmap='binary',extent=[-1,1,-1,1])
1289            if newPlot:
1290#                Page.figure.colorbar(Img)    #colorbar fails - crashes gsasii
1291                newPlot = False
1292            Plot.set_title('Pole figure for HKL='+str(SHData['PFhkl']))
1293    Page.canvas.draw()
1294
1295           
1296def PlotExposedImage(self,newPlot=False,event=None):
1297    '''General access module for 2D image plotting
1298    '''
1299    plotNo = self.G2plotNB.nb.GetSelection()
1300    if self.G2plotNB.nb.GetPageText(plotNo) == '2D Powder Image':
1301        PlotImage(self,newPlot,event,newImage=True)
1302    elif self.G2plotNB.nb.GetPageText(plotNo) == '2D Integration':
1303        PlotIntegration(self,newPlot,event)
1304
1305def PlotImage(self,newPlot=False,event=None,newImage=True):
1306    '''Plot of 2D detector images as contoured plot. Also plot calibration ellipses,
1307    masks, etc.
1308    '''
1309    from matplotlib.patches import Ellipse,Arc,Circle,Polygon
1310    import numpy.ma as ma
1311    Dsp = lambda tth,wave: wave/(2.*sind(tth/2.))
1312    global Data,Masks
1313    colors=['b','g','r','c','m','k']
1314    Data = self.PatternTree.GetItemPyData(
1315        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1316    Masks = self.PatternTree.GetItemPyData(
1317        G2gd.GetPatternTreeItemId(self,self.Image, 'Masks'))
1318
1319    def OnImMotion(event):
1320        Page.canvas.SetToolTipString('')
1321        sizexy = Data['size']
1322        if event.xdata and event.ydata:                 #avoid out of frame errors
1323            Page.canvas.SetCursor(wx.CROSS_CURSOR)
1324            item = self.itemPicked
1325            pixelSize = Data['pixelSize']
1326            scalex = 1000./pixelSize[0]
1327            scaley = 1000./pixelSize[1]
1328            if item and self.PatternTree.GetItemText(self.PickId) == 'Image Controls':
1329                if 'Text' in str(item):
1330                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
1331                else:
1332                    xcent,ycent = Data['center']
1333                    xpos = event.xdata-xcent
1334                    ypos = event.ydata-ycent
1335                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
1336                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
1337                        Page.canvas.SetToolTipString('%6d deg'%(azm))
1338                    elif 'line1' in  str(item) or 'line2' in str(item):
1339                        Page.canvas.SetToolTipString('%8.3fdeg'%(tth))                           
1340            else:
1341                xpos = event.xdata
1342                ypos = event.ydata
1343                xpix = xpos*scalex
1344                ypix = ypos*scaley
1345                Int = 0
1346                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
1347                    Int = self.ImageZ[ypix][xpix]
1348                tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1349                Q = 2.*math.pi/dsp
1350                if self.setPoly:
1351                    self.G2plotNB.status.SetFields(['','Polygon mask pick - LB next point, RB close polygon'])
1352                else:
1353                    self.G2plotNB.status.SetFields(\
1354                        ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)])
1355
1356    def OnImPlotKeyPress(event):
1357        try:
1358            PickName = self.PatternTree.GetItemText(self.PickId)
1359        except TypeError:
1360            return
1361        if PickName == 'Masks':
1362            Xpos = event.xdata
1363            if not Xpos:            #got point out of frame
1364                return
1365            Ypos = event.ydata
1366            if event.key == 's':
1367                Masks['Points'].append([Xpos,Ypos,1.])
1368            elif event.key == 'r':
1369                tth = G2img.GetTth(Xpos,Ypos,Data)
1370                Masks['Rings'].append([tth,0.1])
1371            elif event.key == 'a':
1372                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
1373                azm = int(azm)               
1374                Masks['Arcs'].append([tth,[azm-5,azm+5],0.1])
1375            elif event.key == 'p':
1376                self.setPoly = True
1377                Masks['Polygons'].append([])
1378                self.G2plotNB.status.SetFields(['','Polygon mask active - LB pick next point, RB close polygon'])
1379            G2imG.UpdateMasks(self,Masks)
1380        elif PickName == 'Image Controls':
1381            if event.key == 'c':
1382                Xpos = event.xdata
1383                if not Xpos:            #got point out of frame
1384                    return
1385                Ypos = event.ydata
1386                dlg = wx.MessageDialog(self,'Are you sure you want to change the center?',
1387                    'Center change',style=wx.OK|wx.CANCEL)
1388                try:
1389                    if dlg.ShowModal() == wx.ID_OK:
1390                        print 'move center to: ',Xpos,Ypos
1391                        Data['center'] = [Xpos,Ypos]
1392                        G2imG.UpdateImageControls(self,Data,Masks)
1393                finally:
1394                    dlg.Destroy()
1395            elif event.key == 'l':
1396                if self.logPlot:
1397                    self.logPlot = False
1398                else:
1399                    self.logPlot = True
1400        PlotImage(self,newImage=True)
1401           
1402    def OnKeyBox(event):
1403        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index('2D Powder Image'):
1404            event.key = cb.GetValue()[0]
1405            cb.SetValue(' key press')
1406            if event.key in 'l':
1407                OnImPlotKeyPress(event)
1408                       
1409    def OnImPick(event):
1410        if self.PatternTree.GetItemText(self.PickId) not in ['Image Controls','Masks']:
1411            return
1412        if self.setPoly:
1413            polygon = Masks['Polygons'][-1]
1414            xpos,ypos = event.mouseevent.xdata,event.mouseevent.ydata
1415            if xpos and ypos:                       #point inside image
1416                if len(polygon) > 2 and event.mouseevent.button == 3:
1417                    x0,y0 = polygon[0]
1418                    polygon.append([x0,y0])
1419                    self.setPoly = False
1420                    self.G2plotNB.status.SetFields(['','Polygon closed - RB drag a vertex to change shape'])
1421                else:
1422                    self.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(xpos,ypos)])
1423                    polygon.append([xpos,ypos])
1424                G2imG.UpdateMasks(self,Masks)
1425        else:
1426            if self.itemPicked is not None: return
1427            self.itemPicked = event.artist
1428            self.mousePicked = event.mouseevent
1429       
1430    def OnImRelease(event):
1431        try:
1432            PickName = self.PatternTree.GetItemText(self.PickId)
1433        except TypeError:
1434            return
1435        if PickName not in ['Image Controls','Masks']:
1436            return
1437        pixelSize = Data['pixelSize']
1438        scalex = 1000./pixelSize[0]
1439        scaley = 1000./pixelSize[1]
1440        pixLimit = Data['pixLimit']
1441        if self.itemPicked is None and PickName == 'Image Controls':
1442#            sizexy = Data['size']
1443            Xpos = event.xdata
1444            if not (Xpos and self.ifGetRing):                   #got point out of frame
1445                return
1446            Ypos = event.ydata
1447            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
1448                if event.button == 1:
1449                    Xpix = Xpos*scalex
1450                    Ypix = Ypos*scaley
1451                    xpos,ypos,I,J = G2img.ImageLocalMax(self.ImageZ,pixLimit,Xpix,Ypix)
1452                    if I and J:
1453                        xpos += .5                              #shift to pixel center
1454                        ypos += .5
1455                        xpos /= scalex                          #convert to mm
1456                        ypos /= scaley
1457                        Data['ring'].append([xpos,ypos])
1458                elif event.button == 3:
1459                    self.dataFrame.GetStatusBar().SetStatusText('Calibrating...')
1460                    if G2img.ImageCalibrate(self,Data):
1461                        self.dataFrame.GetStatusBar().SetStatusText('Calibration successful - Show ring picks to check')
1462                        print 'Calibration successful'
1463                    else:
1464                        self.dataFrame.GetStatusBar().SetStatusText('Calibration failed - Show ring picks to diagnose')
1465                        print 'Calibration failed'
1466                    self.ifGetRing = False
1467                    G2imG.UpdateImageControls(self,Data,Masks)
1468                    return
1469                PlotImage(self,newImage=False)
1470            return
1471        else:
1472            xpos = event.xdata
1473            if xpos:                                        #avoid out of frame mouse position
1474                ypos = event.ydata
1475                if self.ifGetRing:                          #delete a calibration ring pick
1476                    xypos = [xpos,ypos]
1477                    rings = Data['ring']
1478                    for ring in rings:
1479                        if np.allclose(ring,xypos,.01,0):
1480                            rings.remove(ring)                                                                       
1481                else:
1482                    tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1483                    itemPicked = str(self.itemPicked)
1484                    if 'Line2D' in itemPicked and PickName == 'Image Controls':
1485                        if 'line1' in itemPicked:
1486                            Data['IOtth'][0] = max(tth,0.001)
1487                        elif 'line2' in itemPicked:
1488                            Data['IOtth'][1] = tth
1489                        elif 'line3' in itemPicked:
1490                            Data['LRazimuth'][0] = int(azm)
1491                            if Data['fullIntegrate']:
1492                                Data['LRazimuth'][1] = Data['LRazimuth'][0]+360
1493                        elif 'line4' in itemPicked and not Data['fullIntegrate']:
1494                            Data['LRazimuth'][1] = int(azm)
1495                           
1496                        if Data['LRazimuth'][0] > Data['LRazimuth'][1]:
1497                            Data['LRazimuth'][0] -= 360
1498                           
1499                        azLim = np.array(Data['LRazimuth'])   
1500                        if np.any(azLim>360):
1501                            azLim -= 360
1502                            Data['LRazimuth'] = list(azLim)
1503                           
1504                        if  Data['IOtth'][0] > Data['IOtth'][1]:
1505                            Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
1506                           
1507                        self.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
1508                        self.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
1509                        self.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
1510                        self.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
1511                    elif 'Circle' in itemPicked and PickName == 'Masks':
1512                        spots = Masks['Points']
1513                        newPos = itemPicked.split(')')[0].split('(')[2].split(',')
1514                        newPos = np.array([float(newPos[0]),float(newPos[1])])
1515                        for spot in spots:
1516                            if np.allclose(np.array([spot[:2]]),newPos):
1517                                spot[:2] = xpos,ypos
1518                        G2imG.UpdateMasks(self,Masks)
1519                    elif 'Line2D' in itemPicked and PickName == 'Masks':
1520                        Obj = self.itemPicked.findobj()
1521                        rings = Masks['Rings']
1522                        arcs = Masks['Arcs']
1523                        polygons = Masks['Polygons']
1524                        for ring in self.ringList:
1525                            if Obj == ring[0]:
1526                                rN = ring[1]
1527                                if ring[2] == 'o':
1528                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)-rings[rN][1]/2.
1529                                else:
1530                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)+rings[rN][1]/2.
1531                        for arc in self.arcList:
1532                            if Obj == arc[0]:
1533                                aN = arc[1]
1534                                if arc[2] == 'o':
1535                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)-arcs[aN][2]/2
1536                                elif arc[2] == 'i':
1537                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)+arcs[aN][2]/2
1538                                elif arc[2] == 'l':
1539                                    arcs[aN][1][0] = int(G2img.GetAzm(xpos,ypos,Data))
1540                                else:
1541                                    arcs[aN][1][1] = int(G2img.GetAzm(xpos,ypos,Data))
1542                        for poly in self.polyList:
1543                            if Obj == poly[0]:
1544                                ind = self.itemPicked.contains(self.mousePicked)[1]['ind'][0]
1545                                oldPos = np.array([self.mousePicked.xdata,self.mousePicked.ydata])
1546                                pN = poly[1]
1547                                for i,xy in enumerate(polygons[pN]):
1548                                    if np.allclose(np.array([xy]),oldPos,atol=1.0):
1549                                        polygons[pN][i] = xpos,ypos
1550                        G2imG.UpdateMasks(self,Masks)
1551#                    else:                  #keep for future debugging
1552#                        print str(self.itemPicked),event.xdata,event.ydata,event.button
1553                PlotImage(self,newImage=True)
1554            self.itemPicked = None
1555           
1556    try:
1557        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1558        Page = self.G2plotNB.nb.GetPage(plotNum)
1559        if not newPlot:
1560            Plot = Page.figure.gca()          #get previous powder plot & get limits
1561            xylim = Plot.get_xlim(),Plot.get_ylim()
1562        if newImage:
1563            Page.figure.clf()
1564            Plot = Page.figure.gca()          #get a fresh plot after clf()
1565       
1566    except ValueError:
1567        Plot = self.G2plotNB.addMpl('2D Powder Image').gca()
1568        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1569        Page = self.G2plotNB.nb.GetPage(plotNum)
1570        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
1571        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
1572        Page.canvas.mpl_connect('pick_event', OnImPick)
1573        Page.canvas.mpl_connect('button_release_event', OnImRelease)
1574        xylim = []
1575    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
1576        Page.SetFocus()
1577    Title = self.PatternTree.GetItemText(self.Image)[4:]
1578    self.G2plotNB.status.DestroyChildren()
1579    if self.logPlot:
1580        Title = 'log('+Title+')'
1581    Plot.set_title(Title)
1582    try:
1583        if self.PatternTree.GetItemText(self.PickId) in ['Image Controls',]:
1584            if self.logPlot:
1585                Choice = (' key press','l: log(I) off')
1586            else:
1587                Choice = (' key press','l: log(I) on')
1588            cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
1589                choices=Choice)
1590            cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
1591            cb.SetValue(' key press')
1592    except TypeError:
1593        pass
1594    size,imagefile = self.PatternTree.GetItemPyData(self.Image)
1595    if imagefile != self.oldImagefile:
1596        imagefile = G2IO.CheckImageFile(self,imagefile)
1597        if not imagefile:
1598            self.G2plotNB.Delete('2D Powder Image')
1599            return
1600        self.PatternTree.SetItemPyData(self.Image,[size,imagefile])
1601        self.ImageZ = G2IO.GetImageData(self,imagefile,imageOnly=True)
1602#        print self.ImageZ.shape,self.ImageZ.size,Data['size'] #might be useful debugging line
1603        self.oldImagefile = imagefile
1604
1605    imScale = 1
1606    if len(self.ImageZ) > 1024:
1607        imScale = len(self.ImageZ)/1024
1608    sizexy = Data['size']
1609    pixelSize = Data['pixelSize']
1610    scalex = 1000./pixelSize[0]
1611    scaley = 1000./pixelSize[1]
1612    Xmax = sizexy[0]*pixelSize[0]/1000.
1613    Ymax = sizexy[1]*pixelSize[1]/1000.
1614    xlim = (0,Xmax)
1615    ylim = (Ymax,0)
1616    Imin,Imax = Data['range'][1]
1617    acolor = mpl.cm.get_cmap(Data['color'])
1618    xcent,ycent = Data['center']
1619    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
1620    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
1621    #do threshold mask - "real" mask - others are just bondaries
1622    Zlim = Masks['Thresholds'][1]
1623    wx.BeginBusyCursor()
1624    try:
1625           
1626        if newImage:                   
1627            MA = ma.masked_greater(ma.masked_less(self.ImageZ,Zlim[0]),Zlim[1])
1628            MaskA = ma.getmaskarray(MA)
1629            A = G2img.ImageCompress(MA,imScale)
1630            AM = G2img.ImageCompress(MaskA,imScale)
1631            if self.logPlot:
1632                A = np.log(A)
1633                AM = np.log(AM)
1634                Imin,Imax = [np.amin(A),np.amax(A)]
1635            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
1636                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Xmax,0])
1637            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
1638                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
1639            if self.setPoly:
1640                Img.set_picker(True)
1641   
1642        Plot.plot(xcent,ycent,'x')
1643        if Data['showLines']:
1644            LRAzim = Data['LRazimuth']                  #NB: integers
1645            Nazm = Data['outAzimuths']
1646            delAzm = float(LRAzim[1]-LRAzim[0])/Nazm
1647            AzmthOff = Data['azmthOff']
1648            IOtth = Data['IOtth']
1649            wave = Data['wavelength']
1650            dspI = wave/(2.0*sind(IOtth[0]/2.0))
1651            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
1652            dspO = wave/(2.0*sind(IOtth[1]/2.0))
1653            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
1654            Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
1655            if ellI:
1656                xyI = []
1657                for azm in Azm:
1658                    xyI.append(G2img.GetDetectorXY(dspI,azm-90.,Data))
1659                xyI = np.array(xyI)
1660                arcxI,arcyI = xyI.T
1661                Plot.plot(arcxI,arcyI,picker=3)
1662            if ellO:
1663                xyO = []
1664                for azm in Azm:
1665                    xyO.append(G2img.GetDetectorXY(dspO,azm-90.,Data))
1666                xyO = np.array(xyO)
1667                arcxO,arcyO = xyO.T
1668                Plot.plot(arcxO,arcyO,picker=3)
1669            if ellO and ellI:
1670                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
1671                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
1672            for i in range(Nazm):
1673                cake = LRAzim[0]+i*delAzm
1674                ind = np.searchsorted(Azm,cake)
1675                Plot.plot([arcxI[ind],arcxO[ind]],[arcyI[ind],arcyO[ind]],color='k',dashes=(5,5))
1676                   
1677        for xring,yring in Data['ring']:
1678            Plot.plot(xring,yring,'r+',picker=3)
1679        if Data['setRings']:
1680#            rings = np.concatenate((Data['rings']),axis=0)
1681            N = 0
1682            for ring in Data['rings']:
1683                xring,yring = np.array(ring).T[:2]
1684                Plot.plot(xring,yring,'+',color=colors[N%6])
1685                N += 1           
1686        for ellipse in Data['ellipses']:
1687            cent,phi,[width,height],col = ellipse
1688            Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
1689            Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
1690        #masks - mask lines numbered after integration limit lines
1691        spots = Masks['Points']
1692        rings = Masks['Rings']
1693        arcs = Masks['Arcs']
1694        polygons = Masks['Polygons']
1695        for x,y,d in spots:
1696            Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
1697        self.ringList = []
1698        for iring,(tth,thick) in enumerate(rings):
1699            wave = Data['wavelength']
1700            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data))),2)
1701            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth-thick/2.,wave),Data))),2)
1702            self.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
1703            self.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
1704        self.arcList = []
1705        for iarc,(tth,azm,thick) in enumerate(arcs):           
1706            wave = Data['wavelength']
1707            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data),azm)),2)
1708            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(max(0.01,tth-thick/2.),wave),Data),azm)),2)
1709            self.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
1710            self.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
1711            self.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
1712            self.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
1713        self.polyList = []
1714        for ipoly,polygon in enumerate(polygons):
1715            x,y = np.hsplit(np.array(polygon),2)
1716            self.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
1717            Plot.plot(x,y,'r')           
1718        if newImage:
1719            colorBar = Page.figure.colorbar(Img)
1720        Plot.set_xlim(xlim)
1721        Plot.set_ylim(ylim)
1722        if not newPlot and xylim:
1723            Page.toolbar.push_current()
1724            Plot.set_xlim(xylim[0])
1725            Plot.set_ylim(xylim[1])
1726            xylim = []
1727            Page.toolbar.push_current()
1728            Page.toolbar.draw()
1729        else:
1730            Page.canvas.draw()
1731    finally:
1732        wx.EndBusyCursor()
1733       
1734def PlotIntegration(self,newPlot=False,event=None):
1735    '''Plot of 2D image after image integration with 2-theta and azimuth as coordinates
1736    '''
1737           
1738    def OnMotion(event):
1739        Page.canvas.SetToolTipString('')
1740        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1741        azm = event.ydata
1742        tth = event.xdata
1743        if azm and tth:
1744            self.G2plotNB.status.SetFields(\
1745                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1746                               
1747    try:
1748        plotNum = self.G2plotNB.plotList.index('2D Integration')
1749        Page = self.G2plotNB.nb.GetPage(plotNum)
1750        if not newPlot:
1751            Plot = Page.figure.gca()          #get previous plot & get limits
1752            xylim = Plot.get_xlim(),Plot.get_ylim()
1753        Page.figure.clf()
1754        Plot = Page.figure.gca()          #get a fresh plot after clf()
1755       
1756    except ValueError:
1757        Plot = self.G2plotNB.addMpl('2D Integration').gca()
1758        plotNum = self.G2plotNB.plotList.index('2D Integration')
1759        Page = self.G2plotNB.nb.GetPage(plotNum)
1760        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1761        Page.views = False
1762        view = False
1763    if not event:
1764        Page.SetFocus()
1765       
1766    Data = self.PatternTree.GetItemPyData(
1767        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1768    image = self.Integrate[0]
1769    xsc = self.Integrate[1]
1770    ysc = self.Integrate[2]
1771    Imin,Imax = Data['range'][1]
1772    acolor = mpl.cm.get_cmap(Data['color'])
1773    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1774    Plot.set_ylabel('azimuth',fontsize=12)
1775    Plot.set_xlabel('2-theta',fontsize=12)
1776    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
1777        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
1778    colorBar = Page.figure.colorbar(Img)
1779    if Data['setRings'] and Data['rings']:
1780        rings = np.concatenate((Data['rings']),axis=0)
1781        for xring,yring,dsp in rings:
1782            x,y = G2img.GetTthAzm(xring,yring,Data)
1783            Plot.plot(x,y,'r+')
1784    if Data['ellipses']:           
1785        for ellipse in Data['ellipses']:
1786            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1787            x,y = np.hsplit(ring,2)
1788            tth,azm = G2img.GetTthAzm(x,y,Data)
1789            azm = np.where(azm < 0.,azm+360,azm)
1790            Plot.plot(tth,azm,'b,')
1791    if not newPlot:
1792        Page.toolbar.push_current()
1793        Plot.set_xlim(xylim[0])
1794        Plot.set_ylim(xylim[1])
1795        xylim = []
1796        Page.toolbar.push_current()
1797        Page.toolbar.draw()
1798    else:
1799        Page.canvas.draw()
1800               
1801def PlotTRImage(self,tax,tay,taz,newPlot=False):
1802    '''a test plot routine - not normally used
1803    ''' 
1804           
1805    def OnMotion(event):
1806        Page.canvas.SetToolTipString('')
1807        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1808        azm = event.xdata
1809        tth = event.ydata
1810        if azm and tth:
1811            self.G2plotNB.status.SetFields(\
1812                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1813                               
1814    try:
1815        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1816        Page = self.G2plotNB.nb.GetPage(plotNum)
1817        if not newPlot:
1818            Plot = Page.figure.gca()          #get previous plot & get limits
1819            xylim = Plot.get_xlim(),Plot.get_ylim()
1820        Page.figure.clf()
1821        Plot = Page.figure.gca()          #get a fresh plot after clf()
1822       
1823    except ValueError:
1824        Plot = self.G2plotNB.addMpl('2D Transformed Powder Image').gca()
1825        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1826        Page = self.G2plotNB.nb.GetPage(plotNum)
1827        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1828        Page.views = False
1829        view = False
1830    Page.SetFocus()
1831       
1832    Data = self.PatternTree.GetItemPyData(
1833        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1834    Imin,Imax = Data['range'][1]
1835    step = (Imax-Imin)/5.
1836    V = np.arange(Imin,Imax,step)
1837    acolor = mpl.cm.get_cmap(Data['color'])
1838    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1839    Plot.set_xlabel('azimuth',fontsize=12)
1840    Plot.set_ylabel('2-theta',fontsize=12)
1841    Plot.contour(tax,tay,taz,V,cmap=acolor)
1842    if Data['showLines']:
1843        IOtth = Data['IOtth']
1844        if Data['fullIntegrate']:
1845            LRAzim = [-180,180]
1846        else:
1847            LRAzim = Data['LRazimuth']                  #NB: integers
1848        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[0],IOtth[0]],picker=True)
1849        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[1],IOtth[1]],picker=True)
1850        if not Data['fullIntegrate']:
1851            Plot.plot([LRAzim[0],LRAzim[0]],[IOtth[0],IOtth[1]],picker=True)
1852            Plot.plot([LRAzim[1],LRAzim[1]],[IOtth[0],IOtth[1]],picker=True)
1853    if Data['setRings']:
1854        rings = np.concatenate((Data['rings']),axis=0)
1855        for xring,yring,dsp in rings:
1856            x,y = G2img.GetTthAzm(xring,yring,Data)
1857            Plot.plot(y,x,'r+')           
1858    if Data['ellipses']:           
1859        for ellipse in Data['ellipses']:
1860            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1861            x,y = np.hsplit(ring,2)
1862            tth,azm = G2img.GetTthAzm(x,y,Data)
1863            Plot.plot(azm,tth,'b,')
1864    if not newPlot:
1865        Page.toolbar.push_current()
1866        Plot.set_xlim(xylim[0])
1867        Plot.set_ylim(xylim[1])
1868        xylim = []
1869        Page.toolbar.push_current()
1870        Page.toolbar.draw()
1871    else:
1872        Page.canvas.draw()
1873       
1874def PlotStructure(self,data):
1875    '''Crystal structure plotting package. Can show structures as balls, sticks, lines,
1876    thermal motion ellipsoids and polyhedra
1877    '''
1878    generalData = data['General']
1879    cell = generalData['Cell'][1:7]
1880    Amat,Bmat = G2lat.cell2AB(cell)         #Amat - crystal to cartesian, Bmat - inverse
1881    A4mat = np.concatenate((np.concatenate((Amat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1882    B4mat = np.concatenate((np.concatenate((Bmat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1883    Mydir = generalData['Mydir']
1884    atomData = data['Atoms']
1885    drawingData = data['Drawing']
1886    drawAtoms = drawingData['Atoms']
1887    cx,ct,cs = drawingData['atomPtrs']
1888    Wt = [255,255,255]
1889    Rd = [255,0,0]
1890    Gr = [0,255,0]
1891    Bl = [0,0,255]
1892    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]])
1893    uEdges = np.array([
1894        [uBox[0],uBox[1]],[uBox[0],uBox[3]],[uBox[0],uBox[4]],[uBox[1],uBox[2]], 
1895        [uBox[2],uBox[3]],[uBox[1],uBox[5]],[uBox[2],uBox[6]],[uBox[3],uBox[7]], 
1896        [uBox[4],uBox[5]],[uBox[5],uBox[6]],[uBox[6],uBox[7]],[uBox[7],uBox[4]]])
1897    uColors = [Rd,Gr,Bl,Wt, Wt,Wt,Wt,Wt, Wt,Wt,Wt,Wt]
1898    altDown = False
1899    shiftDown = False
1900    ctrlDown = False
1901   
1902    def OnKeyBox(event):
1903        import Image
1904        Draw()                          #make sure plot is fresh!!
1905        mode = cb.GetValue()
1906        Fname = Mydir+'\\'+generalData['Name']+'.'+mode
1907        size = Page.canvas.GetSize()
1908        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
1909        if mode in ['jpeg',]:
1910            Pix = glReadPixels(0,0,size[0],size[1],GL_RGBA, GL_UNSIGNED_BYTE)
1911            im = Image.new("RGBA", (size[0],size[1]))
1912        else:
1913            Pix = glReadPixels(0,0,size[0],size[1],GL_RGB, GL_UNSIGNED_BYTE)
1914            im = Image.new("RGB", (size[0],size[1]))
1915        im.fromstring(Pix)
1916        im.save(Fname,mode)
1917        cb.SetValue(' Save as:')
1918        self.G2plotNB.status.SetStatusText('Drawing saved to: '+Fname,1)
1919   
1920    def GetTruePosition(xy):
1921        View = glGetIntegerv(GL_VIEWPORT)
1922        Proj = glGetDoublev(GL_PROJECTION_MATRIX)
1923        Model = glGetDoublev(GL_MODELVIEW_MATRIX)
1924        Zmax = 1.
1925        for i,atom in enumerate(drawAtoms):
1926            x,y,z = atom[cx:cx+3]
1927            X,Y,Z = gluProject(x,y,z,Model,Proj,View)
1928            XY = [int(X),int(View[3]-Y)]
1929            if np.allclose(xy,XY,atol=10) and Z < Zmax:
1930                Zmax = Z
1931                SetSelectedAtoms(i)
1932                   
1933    def OnMouseDown(event):
1934        xy = event.GetPosition()
1935        if event.ShiftDown():
1936            GetTruePosition(xy)
1937        else:
1938            drawingData['Rotation'][3] = xy
1939        Draw()
1940       
1941    def OnMouseMove(event):
1942        newxy = event.GetPosition()
1943        page = getSelection()
1944        if event.ControlDown() and drawingData['showABC']:
1945            if event.LeftIsDown():
1946                SetTestRot(newxy)
1947            elif event.RightIsDown():
1948                SetTestPos(newxy)
1949            elif event.MiddleIsDown():
1950                SetTestRotZ(newxy)
1951            x,y,z = drawingData['testPos'][0]
1952            self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
1953               
1954               
1955        if event.Dragging() and not event.ControlDown():
1956            if event.LeftIsDown():
1957                SetRotation(newxy)
1958                angX,angY,angZ = drawingData['Rotation'][:3]
1959                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f ,%.2f'%(angX,angY,angZ),1)
1960            elif event.RightIsDown():
1961                SetTranslation(newxy)
1962                Tx,Ty,Tz = drawingData['viewPoint'][0]
1963                self.G2plotNB.status.SetStatusText('New view point: %.4f, %.4f, %.4f'%(Tx,Ty,Tz),1)
1964            elif event.MiddleIsDown():
1965                SetRotationZ(newxy)
1966                angX,angY,angZ = drawingData['Rotation'][:3]
1967                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f, %.2f'%(angX,angY,angZ),1)
1968        Draw()
1969       
1970    def OnMouseWheel(event):
1971        drawingData['cameraPos'] += event.GetWheelRotation()/24
1972        drawingData['cameraPos'] = max(10,min(500,drawingData['cameraPos']))
1973        self.G2plotNB.status.SetStatusText('New camera distance: %.2f'%(drawingData['cameraPos']),1)
1974        page = getSelection()
1975        if page:
1976            if self.dataDisplay.GetPageText(page) == 'Draw Options':
1977                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
1978                names = [child.GetName() for child in panel]
1979                panel[names.index('cameraPos')].SetLabel('Camera Position: '+'%.2f'%(drawingData['cameraPos']))
1980                panel[names.index('cameraSlider')].SetValue(drawingData['cameraPos'])
1981        Draw()
1982       
1983    def getSelection():
1984        try:
1985            return self.dataDisplay.GetSelection()
1986        except AttributeError:
1987            print self.dataDisplay.GetLabel()
1988            self.G2plotNB.status.SetStatusText('Select this from Phase data window!')
1989            return 0
1990           
1991    def SetViewPointText(VP):
1992        page = getSelection()
1993        if page:
1994            if self.dataDisplay.GetPageText(page) == 'Draw Options':
1995                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
1996                names = [child.GetName() for child in panel]
1997                panel[names.index('viewPoint')].SetValue('%.3f, %.3f, %.3f'%(VP[0],VP[1],VP[2]))
1998           
1999    def ClearSelectedAtoms():
2000        page = getSelection()
2001        if page:
2002            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2003                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Draw Atoms
2004            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2005                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Atoms
2006                   
2007    def SetSelectedAtoms(ind):
2008        page = getSelection()
2009        if page:
2010            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2011                self.dataDisplay.GetPage(page).SelectRow(ind)      #this is the Atoms grid in Draw Atoms
2012            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2013                Id = drawAtoms[ind][-2]
2014                for i,atom in enumerate(atomData):
2015                    if atom[-1] == Id:
2016                        self.dataDisplay.GetPage(page).SelectRow(i)      #this is the Atoms grid in Atoms
2017                 
2018    def GetSelectedAtoms():
2019        page = getSelection()
2020        Ind = []
2021        if page:
2022            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2023                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Draw Atoms
2024            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2025                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Atoms
2026        return Ind
2027                                       
2028    def OnKey(event):           #on key UP!!
2029        keyCode = event.GetKeyCode()
2030        if keyCode > 255:
2031            keyCode = 0
2032        key,xyz = chr(keyCode),event.GetPosition()
2033        indx = drawingData['selectedAtoms']
2034        if key in ['c','C']:
2035            drawingData['viewPoint'] = [[.5,.5,.5],[0,0]]
2036            drawingData['testPos'] = [[-.1,-.1,-.1],[0.0,0.0,0.0],[0,0]]
2037            drawingData['Rotation'] = [0.0,0.0,0.0,[]]
2038            SetViewPointText(drawingData['viewPoint'][0])
2039        elif key in ['n','N']:
2040            drawAtoms = drawingData['Atoms']
2041            pI = drawingData['viewPoint'][1]
2042            if indx:
2043                pI[0] = indx[pI[1]]
2044                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2045                pI[1] += 1
2046                if pI[1] >= len(indx):
2047                    pI[1] = 0
2048            else:
2049                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2050                pI[0] += 1
2051                if pI[0] >= len(drawAtoms):
2052                    pI[0] = 0
2053            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2054            SetViewPointText(drawingData['viewPoint'][0])
2055               
2056        elif key in ['p','P']:
2057            drawAtoms = drawingData['Atoms']
2058            pI = drawingData['viewPoint'][1]
2059            if indx:
2060                pI[0] = indx[pI[1]]
2061                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2062                pI[1] -= 1
2063                if pI[1] < 0:
2064                    pI[1] = len(indx)-1
2065            else:
2066                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2067                pI[0] -= 1
2068                if pI[0] < 0:
2069                    pI[0] = len(drawAtoms)-1
2070            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2071            SetViewPointText(drawingData['viewPoint'][0])           
2072        Draw()
2073           
2074    def SetBackground():
2075        R,G,B,A = Page.camera['backColor']
2076        glClearColor(R,G,B,A)
2077        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
2078       
2079    def SetLights():
2080        glEnable(GL_DEPTH_TEST)
2081        glShadeModel(GL_SMOOTH)
2082        glEnable(GL_LIGHTING)
2083        glEnable(GL_LIGHT0)
2084        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0)
2085        glLightfv(GL_LIGHT0,GL_AMBIENT,[1,1,1,.8])
2086        glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
2087       
2088    def SetTranslation(newxy):
2089        Tx,Ty,Tz = drawingData['viewPoint'][0]
2090        anglex,angley,anglez,oldxy = drawingData['Rotation']
2091        Rx = G2lat.rotdMat(anglex,0)
2092        Ry = G2lat.rotdMat(angley,1)
2093        Rz = G2lat.rotdMat(anglez,2)
2094        dxy = list(newxy-oldxy)+[0,]
2095        dxy = np.inner(Bmat,np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy))))
2096        Tx -= dxy[0]*0.01
2097        Ty += dxy[1]*0.01
2098        Tz -= dxy[2]*0.01
2099        drawingData['Rotation'][3] = newxy
2100        drawingData['viewPoint'][0] =  Tx,Ty,Tz
2101        SetViewPointText([Tx,Ty,Tz])
2102       
2103    def SetTestPos(newxy):
2104        Tx,Ty,Tz = drawingData['testPos'][0]
2105        anglex,angley,anglez,oldxy = drawingData['Rotation']
2106        Rx = G2lat.rotdMat(anglex,0)
2107        Ry = G2lat.rotdMat(angley,1)
2108        Rz = G2lat.rotdMat(anglez,2)
2109        dxy = list(newxy-oldxy)+[0,]
2110        dxy = np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy)))
2111        Tx += dxy[0]*0.001
2112        Ty -= dxy[1]*0.001
2113        Tz += dxy[2]*0.001
2114        drawingData['Rotation'][3] = newxy
2115        drawingData['testPos'][0] =  Tx,Ty,Tz
2116       
2117    def SetTestRot(newxy):
2118        Txyz = np.array(drawingData['testPos'][0])
2119        oldxy = drawingData['testPos'][2]
2120        Ax,Ay,Az = drawingData['testPos'][1]
2121        Vxyz = np.array(drawingData['viewPoint'][0])
2122        Dxyz = np.inner(Amat,Txyz-Vxyz)
2123        dxy = list(newxy-oldxy)+[0,]
2124        Ax += dxy[1]*0.01
2125        Ay += dxy[0]*0.01
2126        Rx = G2lat.rotdMat(Ax,0)
2127        Ry = G2lat.rotdMat(Ay,1)
2128        Dxyz = np.inner(Ry,np.inner(Rx,Dxyz))       
2129        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
2130        drawingData['testPos'][1] = [Ax,Ay,Az]
2131        drawingData['testPos'][2] = newxy
2132        drawingData['testPos'][0] = Dxyz
2133       
2134    def SetTestRotZ(newxy):
2135        Txyz = np.array(drawingData['testPos'][0])
2136        oldxy = drawingData['testPos'][2]
2137        Ax,Ay,Az = drawingData['testPos'][1]
2138        Vxyz = np.array(drawingData['viewPoint'][0])
2139        Dxyz = np.inner(Amat,Txyz-Vxyz)       
2140        dxy = list(newxy-oldxy)+[0,]
2141        Az += (dxy[0]+dxy[1])*.01
2142        Rz = G2lat.rotdMat(Az,2)
2143        Dxyz = np.inner(Rz,Dxyz)       
2144        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
2145        drawingData['testPos'][1] = [Ax,Ay,Az]
2146        drawingData['testPos'][2] = newxy
2147        drawingData['testPos'][0] = Dxyz
2148                             
2149    def SetRotation(newxy):       
2150        anglex,angley,anglez,oldxy = drawingData['Rotation']
2151        dxy = newxy-oldxy
2152        anglex += dxy[1]*.25
2153        angley += dxy[0]*.25
2154        oldxy = newxy
2155        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2156       
2157    def SetRotationZ(newxy):                       
2158        anglex,angley,anglez,oldxy = drawingData['Rotation']
2159        dxy = newxy-oldxy
2160        anglez += (dxy[0]+dxy[1])*.25
2161        oldxy = newxy
2162        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2163       
2164    def RenderBox():
2165        glEnable(GL_COLOR_MATERIAL)
2166        glLineWidth(2)
2167        glEnable(GL_BLEND)
2168        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
2169        glEnable(GL_LINE_SMOOTH)
2170        glBegin(GL_LINES)
2171        for line,color in zip(uEdges,uColors):
2172            glColor3ubv(color)
2173            glVertex3fv(line[0])
2174            glVertex3fv(line[1])
2175        glEnd()
2176        glColor4ubv([0,0,0,0])
2177        glDisable(GL_LINE_SMOOTH)
2178        glDisable(GL_BLEND)
2179        glDisable(GL_COLOR_MATERIAL)
2180       
2181    def RenderUnitVectors(x,y,z):
2182        xyz = np.array([x,y,z])
2183        glEnable(GL_COLOR_MATERIAL)
2184        glLineWidth(1)
2185        glPushMatrix()
2186        glTranslate(x,y,z)
2187        glScalef(1/cell[0],1/cell[1],1/cell[2])
2188        glBegin(GL_LINES)
2189        for line,color in zip(uEdges,uColors)[:3]:
2190            glColor3ubv(color)
2191            glVertex3fv(line[0])
2192            glVertex3fv(line[1])
2193        glEnd()
2194        glPopMatrix()
2195        glColor4ubv([0,0,0,0])
2196        glDisable(GL_COLOR_MATERIAL)
2197               
2198    def RenderSphere(x,y,z,radius,color):
2199        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2200        glPushMatrix()
2201        glTranslate(x,y,z)
2202        glMultMatrixf(B4mat.T)
2203        q = gluNewQuadric()
2204        gluSphere(q,radius,20,10)
2205        glPopMatrix()
2206       
2207    def RenderEllipsoid(x,y,z,ellipseProb,E,R4,color):
2208        s1,s2,s3 = E
2209        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2210        glPushMatrix()
2211        glTranslate(x,y,z)
2212        glMultMatrixf(B4mat.T)
2213        glMultMatrixf(R4.T)
2214        glEnable(GL_NORMALIZE)
2215        glScale(s1,s2,s3)
2216        q = gluNewQuadric()
2217        gluSphere(q,ellipseProb,20,10)
2218        glDisable(GL_NORMALIZE)
2219        glPopMatrix()
2220       
2221    def RenderBonds(x,y,z,Bonds,radius,color,slice=20):
2222        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2223        glPushMatrix()
2224        glTranslate(x,y,z)
2225        glMultMatrixf(B4mat.T)
2226        for bond in Bonds:
2227            glPushMatrix()
2228            Dx = np.inner(Amat,bond)
2229            Z = np.sqrt(np.sum(Dx**2))
2230            azm = atan2d(-Dx[1],-Dx[0])
2231            phi = acosd(Dx[2]/Z)
2232            glRotate(-azm,0,0,1)
2233            glRotate(phi,1,0,0)
2234            q = gluNewQuadric()
2235            gluCylinder(q,radius,radius,Z,slice,2)
2236            glPopMatrix()           
2237        glPopMatrix()
2238               
2239    def RenderLines(x,y,z,Bonds,color):
2240        xyz = np.array([x,y,z])
2241        glEnable(GL_COLOR_MATERIAL)
2242        glLineWidth(1)
2243        glColor3fv(color)
2244        glPushMatrix()
2245        glBegin(GL_LINES)
2246        for bond in Bonds:
2247            glVertex3fv(xyz)
2248            glVertex3fv(xyz+bond)
2249        glEnd()
2250        glColor4ubv([0,0,0,0])
2251        glPopMatrix()
2252        glDisable(GL_COLOR_MATERIAL)
2253       
2254    def RenderPolyhedra(x,y,z,Faces,color):
2255        glPushMatrix()
2256        glTranslate(x,y,z)
2257        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2258        glShadeModel(GL_SMOOTH)
2259        glMultMatrixf(B4mat.T)
2260        for face,norm in Faces:
2261            glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
2262            glFrontFace(GL_CW)
2263            glNormal3fv(norm)
2264            glBegin(GL_TRIANGLES)
2265            for vert in face:
2266                glVertex3fv(vert)
2267            glEnd()
2268        glPopMatrix()
2269       
2270    def RenderBackbone(Backbone,BackboneColor,radius):
2271        glPushMatrix()
2272        glMultMatrixf(B4mat.T)
2273        glEnable(GL_COLOR_MATERIAL)
2274        glShadeModel(GL_SMOOTH)
2275        gleSetJoinStyle(TUBE_NORM_EDGE | TUBE_JN_ANGLE | TUBE_JN_CAP)
2276        glePolyCylinder(Backbone,BackboneColor,radius)
2277        glPopMatrix()       
2278        glDisable(GL_COLOR_MATERIAL)
2279       
2280    def RenderLabel(x,y,z,label,r):       
2281        glPushMatrix()
2282        glTranslate(x,y,z)
2283        glMultMatrixf(B4mat.T)
2284        glDisable(GL_LIGHTING)
2285        glColor3f(0,1.,0)
2286        glRasterPos3f(r,r,r)
2287        for c in list(label):
2288            glutBitmapCharacter(GLUT_BITMAP_8_BY_13,ord(c))
2289        glEnable(GL_LIGHTING)
2290        glPopMatrix()
2291                           
2292    def Draw():
2293        import numpy.linalg as nl
2294        Ind = GetSelectedAtoms()
2295        VS = np.array(Page.canvas.GetSize())
2296        aspect = float(VS[0])/float(VS[1])
2297        cPos = drawingData['cameraPos']
2298        Zclip = drawingData['Zclip']*cPos/200.
2299        anglex,angley,anglez = drawingData['Rotation'][:3]
2300        Tx,Ty,Tz = drawingData['viewPoint'][0]
2301        cx,ct,cs = drawingData['atomPtrs']
2302        bondR = drawingData['bondRadius']
2303        G,g = G2lat.cell2Gmat(cell)
2304        GS = G
2305        GS[0][1] = GS[1][0] = math.sqrt(GS[0][0]*GS[1][1])
2306        GS[0][2] = GS[2][0] = math.sqrt(GS[0][0]*GS[2][2])
2307        GS[1][2] = GS[2][1] = math.sqrt(GS[1][1]*GS[2][2])
2308        ellipseProb = G2lat.criticalEllipse(drawingData['ellipseProb']/100.)
2309       
2310        SetBackground()
2311        glInitNames()
2312        glPushName(0)
2313       
2314        glMatrixMode(GL_PROJECTION)
2315        glLoadIdentity()
2316        glViewport(0,0,VS[0],VS[1])
2317        gluPerspective(20.,aspect,cPos-Zclip,cPos+Zclip)
2318        gluLookAt(0,0,cPos,0,0,0,0,1,0)
2319        SetLights()           
2320           
2321        glMatrixMode(GL_MODELVIEW)
2322        glLoadIdentity()
2323        glRotate(anglez,0,0,1)
2324        glRotate(anglex,cosd(anglez),-sind(anglez),0)
2325        glRotate(angley,sind(anglez),cosd(anglez),0)
2326        glMultMatrixf(A4mat.T)
2327        glTranslate(-Tx,-Ty,-Tz)
2328        if drawingData['unitCellBox']:
2329            RenderBox()
2330        if drawingData['showABC']:
2331            x,y,z = drawingData['testPos'][0]
2332#            if altDown:
2333#                self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
2334#            else:
2335#                self.G2plotNB.status.SetStatusText('test point %.4f,%.4f,%.4f'%(x,y,z),1)           
2336            RenderUnitVectors(x,y,z)
2337        Backbone = []
2338        BackboneColor = []
2339        time0 = time.time()
2340        for iat,atom in enumerate(drawingData['Atoms']):
2341            x,y,z = atom[cx:cx+3]
2342            Bonds = atom[-2]
2343            Faces = atom[-1]
2344            try:
2345                atNum = generalData['AtomTypes'].index(atom[ct])
2346            except ValueError:
2347                atNum = -1
2348            CL = atom[cs+2]
2349            color = np.array(CL)/255.
2350            if iat in Ind:
2351                color = np.array(Gr)/255.
2352            radius = 0.5
2353            if atom[cs] != '':
2354                glLoadName(atom[-3])                   
2355            if 'balls' in atom[cs]:
2356                vdwScale = drawingData['vdwScale']
2357                ballScale = drawingData['ballScale']
2358                if atNum < 0:
2359                    radius = 0.2
2360                elif 'H' == atom[ct]:
2361                    if drawingData['showHydrogen']:
2362                        if 'vdW' in atom[cs] and atNum >= 0:
2363                            radius = vdwScale*generalData['vdWRadii'][atNum]
2364                        else:
2365                            radius = ballScale*drawingData['sizeH']
2366                    else:
2367                        radius = 0.0
2368                else:
2369                    if 'vdW' in atom[cs]:
2370                        radius = vdwScale*generalData['vdWRadii'][atNum]
2371                    else:
2372                        radius = ballScale*generalData['BondRadii'][atNum]
2373                RenderSphere(x,y,z,radius,color)
2374                if 'sticks' in atom[cs]:
2375                    RenderBonds(x,y,z,Bonds,bondR,color)
2376            elif 'ellipsoids' in atom[cs]:
2377                RenderBonds(x,y,z,Bonds,bondR,color)
2378                if atom[cs+3] == 'A':                   
2379                    Uij = atom[cs+5:cs+11]
2380                    U = np.multiply(G2spc.Uij2U(Uij),GS)
2381                    U = np.inner(Amat,np.inner(U,Amat).T)
2382                    E,R = nl.eigh(U)
2383                    R4 = np.concatenate((np.concatenate((R,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
2384                    E = np.sqrt(E)
2385                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2386                        pass
2387                    else:
2388                        RenderEllipsoid(x,y,z,ellipseProb,E,R4,color)                   
2389                else:
2390                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2391                        pass
2392                    else:
2393                        radius = ellipseProb*math.sqrt(abs(atom[cs+4]))
2394                        RenderSphere(x,y,z,radius,color)
2395            elif 'lines' in atom[cs]:
2396                radius = 0.1
2397                RenderLines(x,y,z,Bonds,color)
2398#                RenderBonds(x,y,z,Bonds,0.05,color,6)
2399            elif atom[cs] == 'sticks':
2400                radius = 0.1
2401                RenderBonds(x,y,z,Bonds,bondR,color)
2402            elif atom[cs] == 'polyhedra':
2403                RenderPolyhedra(x,y,z,Faces,color)
2404            elif atom[cs] == 'backbone':
2405                if atom[ct-1].split()[0] in ['C','N']:
2406                    Backbone.append(list(np.inner(Amat,np.array([x,y,z]))))
2407                    BackboneColor.append(list(color))
2408                   
2409            if atom[cs+1] == 'type':
2410                RenderLabel(x,y,z,atom[ct],radius)
2411            elif atom[cs+1] == 'name':
2412                RenderLabel(x,y,z,atom[ct-1],radius)
2413            elif atom[cs+1] == 'number':
2414                RenderLabel(x,y,z,str(iat+1),radius)
2415            elif atom[cs+1] == 'residue' and atom[ct-1] == 'CA':
2416                RenderLabel(x,y,z,atom[ct-4],radius)
2417            elif atom[cs+1] == '1-letter' and atom[ct-1] == 'CA':
2418                RenderLabel(x,y,z,atom[ct-3],radius)
2419            elif atom[cs+1] == 'chain' and atom[ct-1] == 'CA':
2420                RenderLabel(x,y,z,atom[ct-2],radius)
2421        if Backbone:
2422            RenderBackbone(Backbone,BackboneColor,bondR)
2423#        print time.time()-time0
2424        Page.canvas.SwapBuffers()
2425       
2426    def OnSize(event):
2427        Draw()
2428       
2429    def OnFocus(event):
2430        Draw()
2431       
2432    try:
2433        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2434        Page = self.G2plotNB.nb.GetPage(plotNum)       
2435    except ValueError:
2436        Plot = self.G2plotNB.addOgl(generalData['Name'])
2437        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2438        Page = self.G2plotNB.nb.GetPage(plotNum)
2439        Page.views = False
2440        view = False
2441        altDown = False
2442    Page.SetFocus()
2443    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
2444        choices=(' save as:','jpeg','tiff','bmp'))
2445    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
2446    cb.SetValue(' save as:')
2447    Page.canvas.Bind(wx.EVT_MOUSEWHEEL, OnMouseWheel)
2448    Page.canvas.Bind(wx.EVT_LEFT_DOWN, OnMouseDown)
2449    Page.canvas.Bind(wx.EVT_RIGHT_DOWN, OnMouseDown)
2450    Page.canvas.Bind(wx.EVT_MIDDLE_DOWN, OnMouseDown)
2451    Page.canvas.Bind(wx.EVT_KEY_UP, OnKey)
2452    Page.canvas.Bind(wx.EVT_MOTION, OnMouseMove)
2453    Page.canvas.Bind(wx.EVT_SIZE, OnSize)
2454    Page.canvas.Bind(wx.EVT_SET_FOCUS, OnFocus)
2455    Page.camera['position'] = drawingData['cameraPos']
2456    Page.camera['viewPoint'] = np.inner(Amat,drawingData['viewPoint'][0])
2457    Page.camera['backColor'] = np.array(list(drawingData['backColor'])+[0,])/255.
2458    Page.canvas.SetCurrent()
2459    Draw()
2460       
Note: See TracBrowser for help on using the repository browser.