source: trunk/GSASIIplot.py @ 396

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

make image calibration 0-360 (not -180-180) to match usual integration range
shift bins to center from corner - fixes "wiggle" in integration

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