source: trunk/GSASIIplot.py @ 388

Last change on this file since 388 was 388, checked in by vondreele, 10 years ago

add SGPolax to SGData dictionary - marks arbitrary axes in polar space groups
remove plotting of #2 from instrument parameter plots

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