source: trunk/GSASIIplot.py @ 261

Last change on this file since 261 was 261, checked in by vondreele, 11 years ago

new fortran fellipse - for fitting ellipses!
GSASIIplot.py - change calibration start to RB not on a point, more foolproof than the shift method
GSASIIimgGUI.py - change status text to reflect above & add another place to dmin
GSASIIimage.py - implement fellipse & tighten up the fitting process

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