source: trunk/GSASIIplot.py @ 257

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

change plotting during calibration - now at end - faster
make image plotting optional - saves a little here & there

  • Property svn:keywords set to Date Author Revision URL Id
File size: 85.0 KB
Line 
1#GSASII plotting routines
2########### SVN repository information ###################
3# $Date: 2011-03-09 19:09:55 +0000 (Wed, 09 Mar 2011) $
4# $Author: vondreele $
5# $Revision: 257 $
6# $URL: trunk/GSASIIplot.py $
7# $Id: GSASIIplot.py 257 2011-03-09 19:09:55Z 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    Data = self.PatternTree.GetItemPyData(
905        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
906    Masks = self.PatternTree.GetItemPyData(
907        G2gd.GetPatternTreeItemId(self,self.Image, 'Masks'))
908
909    def OnImMotion(event):
910        Page.canvas.SetToolTipString('')
911        sizexy = Data['size']
912        if event.xdata and event.ydata:                 #avoid out of frame errors
913            Page.canvas.SetCursor(wx.CROSS_CURSOR)
914            item = self.itemPicked
915            pixelSize = Data['pixelSize']
916            scalex = 1000./pixelSize[0]
917            scaley = 1000./pixelSize[1]
918            if item and self.PatternTree.GetItemText(self.PickId) == 'Image Controls':
919                if 'Text' in str(item):
920                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
921                else:
922                    xcent,ycent = Data['center']
923                    xpos = event.xdata-xcent
924                    ypos = event.ydata-ycent
925                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
926                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
927                        Page.canvas.SetToolTipString('%6d deg'%(azm))
928                    elif 'line1' in  str(item) or 'line2' in str(item):
929                        Page.canvas.SetToolTipString('%8.3fdeg'%(tth))                           
930            else:
931                xpos = event.xdata
932                ypos = event.ydata
933                xpix = xpos*scalex
934                ypix = ypos*scaley
935                Int = 0
936                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
937                    Int = self.ImageZ[ypix][xpix]
938                tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
939                Q = 2.*math.pi/dsp
940                if self.setPoly:
941                    self.G2plotNB.status.SetFields(['','Polygon mask pick - LB next point, RB close polygon'])
942                else:
943                    self.G2plotNB.status.SetFields(\
944                        ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)])
945
946    def OnImPlotKeyPress(event):
947        try:
948            PickName = self.PatternTree.GetItemText(self.PickId)
949        except TypeError:
950            return
951        if PickName == 'Masks':
952            Xpos = event.xdata
953            if not Xpos:            #got point out of frame
954                return
955            Ypos = event.ydata
956            if event.key == 's':
957                Masks['Points'].append([Xpos,Ypos,1.])
958            elif event.key == 'r':
959                tth = G2img.GetTth(Xpos,Ypos,Data)
960                Masks['Rings'].append([tth,0.1])
961            elif event.key == 'a':
962                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
963                azm = int(azm)               
964                Masks['Arcs'].append([tth,[azm-5,azm+5],0.1])
965            elif event.key == 'p':
966                self.setPoly = True
967                Masks['Polygons'].append([])
968                self.G2plotNB.status.SetFields(['','Polygon mask active - LB pick next point, RB close polygon'])
969            G2imG.UpdateMasks(self,Masks)
970        elif PickName == 'Image Controls':
971            if event.key == 'c':
972                Xpos = event.xdata
973                if not Xpos:            #got point out of frame
974                    return
975                Ypos = event.ydata
976                dlg = wx.MessageDialog(self,'Are you sure you want to change the center?',
977                    'Center change',style=wx.OK|wx.CANCEL)
978                try:
979                    if dlg.ShowModal() == wx.ID_OK:
980                        print 'move center to: ',Xpos,Ypos
981                        Data['center'] = [Xpos,Ypos]
982                        G2imG.UpdateImageControls(self,Data,Masks)
983                finally:
984                    dlg.Destroy()
985            elif event.key == 'l':
986                if self.logPlot:
987                    self.logPlot = False
988                else:
989                    self.logPlot = True
990        PlotImage(self,newImage=True)
991           
992    def OnKeyBox(event):
993        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index('2D Powder Image'):
994            event.key = cb.GetValue()[0]
995            cb.SetValue(' key press')
996            if event.key in 'l':
997                OnImPlotKeyPress(event)
998                       
999    def OnImPick(event):
1000        if self.PatternTree.GetItemText(self.PickId) not in ['Image Controls','Masks']:
1001            return
1002        if self.setPoly:
1003            polygon = Masks['Polygons'][-1]
1004            xpos,ypos = event.mouseevent.xdata,event.mouseevent.ydata
1005            if xpos and ypos:                       #point inside image
1006                if len(polygon) > 2 and event.mouseevent.button == 3:
1007                    x0,y0 = polygon[0]
1008                    polygon.append([x0,y0])
1009                    self.setPoly = False
1010                    self.G2plotNB.status.SetFields(['','Polygon closed - RB drag a vertex to change shape'])
1011                else:
1012                    self.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(xpos,ypos)])
1013                    polygon.append([xpos,ypos])
1014                G2imG.UpdateMasks(self,Masks)
1015        else:
1016            if self.itemPicked is not None: return
1017            self.itemPicked = event.artist
1018            self.mousePicked = event.mouseevent
1019       
1020    def OnImRelease(event):
1021        try:
1022            PickName = self.PatternTree.GetItemText(self.PickId)
1023        except TypeError:
1024            return
1025        if PickName not in ['Image Controls','Masks']:
1026            return
1027        pixelSize = Data['pixelSize']
1028        scalex = 1000./pixelSize[0]
1029        scaley = 1000./pixelSize[1]
1030        pixLimit = Data['pixLimit']
1031        if self.itemPicked is None and PickName == 'Image Controls':
1032#            sizexy = Data['size']
1033            Xpos = event.xdata
1034            if not (Xpos and self.ifGetRing):                   #got point out of frame
1035                return
1036            Ypos = event.ydata
1037            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
1038                if event.button == 1:
1039                    if event.key == 'shift':                #terminate picking?
1040                        print 'LB shift'
1041                        self.dataFrame.GetStatusBar().SetStatusText('Calibrating...')
1042                        if G2img.ImageCalibrate(self,Data):
1043                            self.dataFrame.GetStatusBar().SetStatusText('Calibration successful')
1044                            print 'Calibration successful'
1045                        else:
1046                            self.dataFrame.GetStatusBar().SetStatusText('Calibration failed')
1047                            print 'Calibration failed'
1048                        self.ifGetRing = False
1049                        G2imG.UpdateImageControls(self,Data,Masks)
1050                        return
1051                    Xpix = Xpos*scalex
1052                    Ypix = Ypos*scaley
1053                    xpos,ypos,I,J = G2img.ImageLocalMax(self.ImageZ,pixLimit,Xpix,Ypix)
1054                    if I and J:
1055                        xpos += .5                              #shift to pixel center
1056                        ypos += .5
1057                        xpos /= scalex                          #convert to mm
1058                        ypos /= scaley
1059                        Data['ring'].append([xpos,ypos])
1060                PlotImage(self,newImage=False)
1061            return
1062        else:
1063            xpos = event.xdata
1064            if xpos:                                        #avoid out of frame mouse position
1065                ypos = event.ydata
1066                if self.ifGetRing:                          #delete a calibration ring pick
1067                    xypos = [xpos,ypos]
1068                    rings = Data['ring']
1069                    for ring in rings:
1070                        if np.allclose(ring,xypos,.01,0):
1071                            rings.remove(ring)                                                                       
1072                else:
1073                    tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1074                    itemPicked = str(self.itemPicked)
1075                    if 'Line2D' in itemPicked and PickName == 'Image Controls':
1076                        if 'line1' in itemPicked:
1077                            Data['IOtth'][0] = max(tth,0.001)
1078                        elif 'line2' in itemPicked:
1079                            Data['IOtth'][1] = tth
1080                        elif 'line3' in itemPicked and not Data['fullIntegrate']:
1081                            Data['LRazimuth'][0] = int(azm)
1082                        elif 'line4' in itemPicked and not Data['fullIntegrate']:
1083                            Data['LRazimuth'][1] = int(azm)
1084                           
1085                        if Data['LRazimuth'][1] < Data['LRazimuth'][0]:
1086                            Data['LRazimuth'][1] += 360
1087                        if  Data['IOtth'][0] > Data['IOtth'][1]:
1088                            Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
1089                           
1090                        self.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
1091                        self.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
1092                        self.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
1093                        self.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
1094                    elif 'Circle' in itemPicked and PickName == 'Masks':
1095                        spots = Masks['Points']
1096                        newPos = itemPicked.split(')')[0].split('(')[2].split(',')
1097                        newPos = np.array([float(newPos[0]),float(newPos[1])])
1098                        for spot in spots:
1099                            if np.allclose(np.array([spot[:2]]),newPos):
1100                                spot[:2] = xpos,ypos
1101                        G2imG.UpdateMasks(self,Masks)
1102                    elif 'Line2D' in itemPicked and PickName == 'Masks':
1103                        Obj = self.itemPicked.findobj()
1104                        rings = Masks['Rings']
1105                        arcs = Masks['Arcs']
1106                        polygons = Masks['Polygons']
1107                        for ring in self.ringList:
1108                            if Obj == ring[0]:
1109                                rN = ring[1]
1110                                if ring[2] == 'o':
1111                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)-rings[rN][1]/2.
1112                                else:
1113                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)+rings[rN][1]/2.
1114                        for arc in self.arcList:
1115                            if Obj == arc[0]:
1116                                aN = arc[1]
1117                                if arc[2] == 'o':
1118                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)-arcs[aN][2]/2
1119                                elif arc[2] == 'i':
1120                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)+arcs[aN][2]/2
1121                                elif arc[2] == 'l':
1122                                    arcs[aN][1][0] = int(G2img.GetAzm(xpos,ypos,Data))
1123                                else:
1124                                    arcs[aN][1][1] = int(G2img.GetAzm(xpos,ypos,Data))
1125                        for poly in self.polyList:
1126                            if Obj == poly[0]:
1127                                ind = self.itemPicked.contains(self.mousePicked)[1]['ind'][0]
1128                                oldPos = np.array([self.mousePicked.xdata,self.mousePicked.ydata])
1129                                pN = poly[1]
1130                                for i,xy in enumerate(polygons[pN]):
1131                                    if np.allclose(np.array([xy]),oldPos,atol=1.0):
1132                                        polygons[pN][i] = xpos,ypos
1133                        G2imG.UpdateMasks(self,Masks)
1134#                    else:                  #keep for future debugging
1135#                        print str(self.itemPicked),event.xdata,event.ydata,event.button
1136                PlotImage(self,newImage=True)
1137            self.itemPicked = None
1138           
1139    try:
1140        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1141        Page = self.G2plotNB.nb.GetPage(plotNum)
1142        if not newPlot:
1143            Plot = Page.figure.gca()          #get previous powder plot & get limits
1144            xylim = Plot.get_xlim(),Plot.get_ylim()
1145        if newImage:
1146            Page.figure.clf()
1147            Plot = Page.figure.gca()          #get a fresh plot after clf()
1148       
1149    except ValueError,error:
1150        Plot = self.G2plotNB.addMpl('2D Powder Image').gca()
1151        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1152        Page = self.G2plotNB.nb.GetPage(plotNum)
1153        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
1154        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
1155        Page.canvas.mpl_connect('pick_event', OnImPick)
1156        Page.canvas.mpl_connect('button_release_event', OnImRelease)
1157        xylim = []
1158    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
1159        Page.SetFocus()
1160    Title = self.PatternTree.GetItemText(self.Image)[4:]
1161    self.G2plotNB.status.DestroyChildren()
1162    if self.logPlot:
1163        Title = 'log('+Title+')'
1164    Plot.set_title(Title)
1165    try:
1166        if self.PatternTree.GetItemText(self.PickId) in ['Image Controls',]:
1167            if self.logPlot:
1168                Choice = (' key press','l: log(I) off')
1169            else:
1170                Choice = (' key press','l: log(I) on')
1171            cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
1172                choices=Choice)
1173            cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
1174            cb.SetValue(' key press')
1175    except TypeError:
1176        pass
1177    size,imagefile = self.PatternTree.GetItemPyData(self.Image)
1178    if imagefile != self.oldImagefile:
1179        imagefile = G2IO.CheckImageFile(self,imagefile)
1180        if not imagefile:
1181            self.G2plotNB.Delete('2D Powder Image')
1182            return
1183        self.PatternTree.SetItemPyData(self.Image,[size,imagefile])
1184        self.ImageZ = G2IO.GetImageData(self,imagefile,imageOnly=True)
1185#        print self.ImageZ.shape,self.ImageZ.size,Data['size'] #might be useful debugging line
1186        self.oldImagefile = imagefile
1187
1188    imScale = 1
1189    if len(self.ImageZ) > 1024:
1190        imScale = len(self.ImageZ)/1024
1191    sizexy = Data['size']
1192    pixelSize = Data['pixelSize']
1193    scalex = 1000./pixelSize[0]
1194    scaley = 1000./pixelSize[1]
1195    Xmax = sizexy[0]*pixelSize[0]/1000.
1196    Ymax = sizexy[1]*pixelSize[1]/1000.
1197    xlim = (0,Xmax)
1198    ylim = (Ymax,0)
1199    Imin,Imax = Data['range'][1]
1200    acolor = mpl.cm.get_cmap(Data['color'])
1201    xcent,ycent = Data['center']
1202    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
1203    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
1204    #do threshold mask - "real" mask - others are just bondaries
1205    Zlim = Masks['Thresholds'][1]
1206    wx.BeginBusyCursor()
1207    try:
1208           
1209        if newImage:                   
1210            MA = ma.masked_greater(ma.masked_less(self.ImageZ,Zlim[0]),Zlim[1])
1211            MaskA = ma.getmaskarray(MA)
1212            A = G2img.ImageCompress(MA,imScale)
1213            AM = G2img.ImageCompress(MaskA,imScale)
1214            if self.logPlot:
1215                A = np.log(A)
1216                AM = np.log(AM)
1217                Imin,Imax = [np.amin(A),np.amax(A)]
1218            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
1219                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Xmax,0])
1220            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
1221                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
1222            if self.setPoly:
1223                Img.set_picker(True)
1224   
1225        Plot.plot(xcent,ycent,'x')
1226        if Data['showLines']:
1227            LRAzim = Data['LRazimuth']                  #NB: integers
1228            AzmthOff = Data['azmthOff']
1229            IOtth = Data['IOtth']
1230            wave = Data['wavelength']
1231            dspI = wave/(2.0*sind(IOtth[0]/2.0))
1232            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
1233            dspO = wave/(2.0*sind(IOtth[1]/2.0))
1234            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
1235            if Data['fullIntegrate']:
1236                Azm = np.array(range(0,361))
1237            else:
1238                Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
1239            if ellI:
1240                xyI = []
1241                for azm in Azm:
1242                    xyI.append(G2img.GetDetectorXY(dspI,azm,Data))
1243                xyI = np.array(xyI)
1244                arcxI,arcyI = xyI.T
1245                Plot.plot(arcxI,arcyI,picker=3)
1246            if ellO:
1247                xyO = []
1248                for azm in Azm:
1249                    xyO.append(G2img.GetDetectorXY(dspO,azm,Data))
1250                xyO = np.array(xyO)
1251                arcxO,arcyO = xyO.T
1252                Plot.plot(arcxO,arcyO,picker=3)
1253            if ellO and ellI and not Data['fullIntegrate']:
1254                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
1255                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
1256        for xring,yring in Data['ring']:
1257            Plot.plot(xring,yring,'r+',picker=3)
1258        if Data['setRings']:
1259            rings = np.concatenate((Data['rings']),axis=0)
1260            for xring,yring,dsp in rings:
1261                Plot.plot(xring,yring,'r+')           
1262        for ellipse in Data['ellipses']:
1263            cent,phi,[width,height],col = ellipse
1264            Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
1265            Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
1266        #masks - mask lines numbered after integration limit lines
1267        spots = Masks['Points']
1268        rings = Masks['Rings']
1269        arcs = Masks['Arcs']
1270        polygons = Masks['Polygons']
1271        for x,y,d in spots:
1272            Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
1273        self.ringList = []
1274        for iring,(tth,thick) in enumerate(rings):
1275            wave = Data['wavelength']
1276            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data))),2)
1277            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth-thick/2.,wave),Data))),2)
1278            self.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
1279            self.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
1280        self.arcList = []
1281        for iarc,(tth,azm,thick) in enumerate(arcs):           
1282            wave = Data['wavelength']
1283            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data),azm)),2)
1284            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(max(0.01,tth-thick/2.),wave),Data),azm)),2)
1285            self.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
1286            self.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
1287            self.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
1288            self.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
1289        self.polyList = []
1290        for ipoly,polygon in enumerate(polygons):
1291            x,y = np.hsplit(np.array(polygon),2)
1292            self.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
1293            Plot.plot(x,y,'r')           
1294        if newImage:
1295            colorBar = Page.figure.colorbar(Img)
1296        Plot.set_xlim(xlim)
1297        Plot.set_ylim(ylim)
1298        if not newPlot and xylim:
1299            Page.toolbar.push_current()
1300            Plot.set_xlim(xylim[0])
1301            Plot.set_ylim(xylim[1])
1302            xylim = []
1303            Page.toolbar.push_current()
1304            Page.toolbar.draw()
1305        else:
1306            Page.canvas.draw()
1307    finally:
1308        wx.EndBusyCursor()
1309       
1310def PlotIntegration(self,newPlot=False,event=None):
1311           
1312    def OnMotion(event):
1313        Page.canvas.SetToolTipString('')
1314        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1315        azm = event.ydata
1316        tth = event.xdata
1317        if azm and tth:
1318            self.G2plotNB.status.SetFields(\
1319                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1320                               
1321    try:
1322        plotNum = self.G2plotNB.plotList.index('2D Integration')
1323        Page = self.G2plotNB.nb.GetPage(plotNum)
1324        if not newPlot:
1325            Plot = Page.figure.gca()          #get previous plot & get limits
1326            xylim = Plot.get_xlim(),Plot.get_ylim()
1327        Page.figure.clf()
1328        Plot = Page.figure.gca()          #get a fresh plot after clf()
1329       
1330    except ValueError,error:
1331        Plot = self.G2plotNB.addMpl('2D Integration').gca()
1332        plotNum = self.G2plotNB.plotList.index('2D Integration')
1333        Page = self.G2plotNB.nb.GetPage(plotNum)
1334        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1335        Page.views = False
1336        view = False
1337    if not event:
1338        Page.SetFocus()
1339       
1340    Data = self.PatternTree.GetItemPyData(
1341        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1342    image = self.Integrate[0]
1343    xsc = self.Integrate[1]
1344    ysc = self.Integrate[2]
1345    Imin,Imax = Data['range'][1]
1346    acolor = mpl.cm.get_cmap(Data['color'])
1347    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1348    Plot.set_ylabel('azimuth',fontsize=12)
1349    Plot.set_xlabel('2-theta',fontsize=12)
1350    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
1351        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
1352    colorBar = Page.figure.colorbar(Img)
1353    if Data['setRings']:
1354        rings = np.concatenate((Data['rings']),axis=0)
1355        for xring,yring,dsp in rings:
1356            x,y = G2img.GetTthAzm(xring,yring,Data)
1357            Plot.plot(x,y,'r+')
1358    if Data['ellipses']:           
1359        for ellipse in Data['ellipses']:
1360            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1361            x,y = np.hsplit(ring,2)
1362            tth,azm = G2img.GetTthAzm(x,y,Data)
1363            Plot.plot(tth,azm,'b,')
1364    if not newPlot:
1365        Page.toolbar.push_current()
1366        Plot.set_xlim(xylim[0])
1367        Plot.set_ylim(xylim[1])
1368        xylim = []
1369        Page.toolbar.push_current()
1370        Page.toolbar.draw()
1371    else:
1372        Page.canvas.draw()
1373               
1374def PlotTRImage(self,tax,tay,taz,newPlot=False):
1375    #a test plot routine - not normally used
1376           
1377    def OnMotion(event):
1378        Page.canvas.SetToolTipString('')
1379        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1380        azm = event.xdata
1381        tth = event.ydata
1382        if azm and tth:
1383            self.G2plotNB.status.SetFields(\
1384                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1385                               
1386    try:
1387        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1388        Page = self.G2plotNB.nb.GetPage(plotNum)
1389        if not newPlot:
1390            Plot = Page.figure.gca()          #get previous plot & get limits
1391            xylim = Plot.get_xlim(),Plot.get_ylim()
1392        Page.figure.clf()
1393        Plot = Page.figure.gca()          #get a fresh plot after clf()
1394       
1395    except ValueError,error:
1396        Plot = self.G2plotNB.addMpl('2D Transformed Powder Image').gca()
1397        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1398        Page = self.G2plotNB.nb.GetPage(plotNum)
1399        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1400        Page.views = False
1401        view = False
1402    Page.SetFocus()
1403       
1404    Data = self.PatternTree.GetItemPyData(
1405        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1406    Imin,Imax = Data['range'][1]
1407    step = (Imax-Imin)/5.
1408    V = np.arange(Imin,Imax,step)
1409    acolor = mpl.cm.get_cmap(Data['color'])
1410    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1411    Plot.set_xlabel('azimuth',fontsize=12)
1412    Plot.set_ylabel('2-theta',fontsize=12)
1413    Plot.contour(tax,tay,taz,V,cmap=acolor)
1414    if Data['showLines']:
1415        IOtth = Data['IOtth']
1416        if Data['fullIntegrate']:
1417            LRAzim = [-180,180]
1418        else:
1419            LRAzim = Data['LRazimuth']                  #NB: integers
1420        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[0],IOtth[0]],picker=True)
1421        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[1],IOtth[1]],picker=True)
1422        if not Data['fullIntegrate']:
1423            Plot.plot([LRAzim[0],LRAzim[0]],[IOtth[0],IOtth[1]],picker=True)
1424            Plot.plot([LRAzim[1],LRAzim[1]],[IOtth[0],IOtth[1]],picker=True)
1425    if Data['setRings']:
1426        rings = np.concatenate((Data['rings']),axis=0)
1427        for xring,yring,dsp in rings:
1428            x,y = G2img.GetTthAzm(xring,yring,Data)
1429            Plot.plot(y,x,'r+')           
1430    if Data['ellipses']:           
1431        for ellipse in Data['ellipses']:
1432            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1433            x,y = np.hsplit(ring,2)
1434            tth,azm = G2img.GetTthAzm(x,y,Data)
1435            Plot.plot(azm,tth,'b,')
1436    if not newPlot:
1437        Page.toolbar.push_current()
1438        Plot.set_xlim(xylim[0])
1439        Plot.set_ylim(xylim[1])
1440        xylim = []
1441        Page.toolbar.push_current()
1442        Page.toolbar.draw()
1443    else:
1444        Page.canvas.draw()
1445       
1446def PlotStructure(self,data):
1447    generalData = data['General']
1448    cell = generalData['Cell'][1:7]
1449    Amat,Bmat = G2lat.cell2AB(cell)         #Amat - crystal to cartesian, Bmat - inverse
1450    A4mat = np.concatenate((np.concatenate((Amat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1451    B4mat = np.concatenate((np.concatenate((Bmat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1452    Mydir = generalData['Mydir']
1453    atomData = data['Atoms']
1454    drawingData = data['Drawing']
1455    drawAtoms = drawingData['Atoms']
1456    cx,ct,cs = drawingData['atomPtrs']
1457    Wt = [255,255,255]
1458    Rd = [255,0,0]
1459    Gr = [0,255,0]
1460    Bl = [0,0,255]
1461    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]])
1462    uEdges = np.array([
1463        [uBox[0],uBox[1]],[uBox[0],uBox[3]],[uBox[0],uBox[4]],[uBox[1],uBox[2]], 
1464        [uBox[2],uBox[3]],[uBox[1],uBox[5]],[uBox[2],uBox[6]],[uBox[3],uBox[7]], 
1465        [uBox[4],uBox[5]],[uBox[5],uBox[6]],[uBox[6],uBox[7]],[uBox[7],uBox[4]]])
1466    uColors = [Rd,Gr,Bl,Wt, Wt,Wt,Wt,Wt, Wt,Wt,Wt,Wt]
1467    altDown = False
1468    shiftDown = False
1469    ctrlDown = False
1470   
1471    def OnKeyBox(event):
1472        import Image
1473        Draw()                          #make sure plot is fresh!!
1474        mode = cb.GetValue()
1475        Fname = Mydir+'\\'+generalData['Name']+'.'+mode
1476        size = Page.canvas.GetSize()
1477        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
1478        if mode in ['jpeg',]:
1479            Pix = glReadPixels(0,0,size[0],size[1],GL_RGBA, GL_UNSIGNED_BYTE)
1480            im = Image.new("RGBA", (size[0],size[1]))
1481        else:
1482            Pix = glReadPixels(0,0,size[0],size[1],GL_RGB, GL_UNSIGNED_BYTE)
1483            im = Image.new("RGB", (size[0],size[1]))
1484        im.fromstring(Pix)
1485        im.save(Fname,mode)
1486        cb.SetValue(' Save as:')
1487        self.G2plotNB.status.SetStatusText('Drawing saved to: '+Fname,1)
1488   
1489    def GetTruePosition(xy):
1490        View = glGetIntegerv(GL_VIEWPORT)
1491        Proj = glGetDoublev(GL_PROJECTION_MATRIX)
1492        Model = glGetDoublev(GL_MODELVIEW_MATRIX)
1493        Zmax = 1.
1494        for i,atom in enumerate(drawAtoms):
1495            x,y,z = atom[cx:cx+3]
1496            X,Y,Z = gluProject(x,y,z,Model,Proj,View)
1497            XY = [int(X),int(View[3]-Y)]
1498            if np.allclose(xy,XY,atol=10) and Z < Zmax:
1499                Zmax = Z
1500                SetSelectedAtoms(i)
1501                   
1502    def OnMouseDown(event):
1503        xy = event.GetPosition()
1504        if event.ShiftDown():
1505            GetTruePosition(xy)
1506        else:
1507            drawingData['Rotation'][3] = xy
1508        Draw()
1509       
1510    def OnMouseMove(event):
1511        newxy = event.GetPosition()
1512        if event.ControlDown() and drawingData['showABC']:
1513            if event.LeftIsDown():
1514                ctrlDown = True
1515                SetTestRot(newxy)
1516            elif event.RightIsDown():
1517                SetTestPos(newxy)
1518            elif event.MiddleIsDown():
1519                SetTestRotZ(newxy)
1520               
1521               
1522        if event.Dragging() and not event.ControlDown():
1523            if event.LeftIsDown():
1524                SetRotation(newxy)
1525            elif event.RightIsDown():
1526                SetTranslation(newxy)
1527            elif event.MiddleIsDown():
1528                SetRotationZ(newxy)
1529        Draw()
1530       
1531    def OnMouseWheel(event):
1532        drawingData['cameraPos'] += event.GetWheelRotation()/24
1533        drawingData['cameraPos'] = max(10,min(500,drawingData['cameraPos']))
1534        page = self.dataDisplay.GetSelection()
1535        if page:
1536            if self.dataDisplay.GetPageText(page) == 'Draw Options':
1537                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
1538                names = [child.GetName() for child in panel]
1539                panel[names.index('cameraPos')].SetLabel('Camera Position: '+'%.2f'%(drawingData['cameraPos']))
1540                panel[names.index('cameraSlider')].SetValue(drawingData['cameraPos'])
1541        Draw()
1542           
1543    def SetViewPointText(VP):
1544        page = self.dataDisplay.GetSelection()
1545        if page:
1546            if self.dataDisplay.GetPageText(page) == 'Draw Options':
1547                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
1548                names = [child.GetName() for child in panel]
1549                panel[names.index('viewPoint')].SetValue('%.3f, %.3f, %.3f'%(VP[0],VP[1],VP[2]))
1550           
1551    def ClearSelectedAtoms():
1552        page = self.dataDisplay.GetSelection()
1553        if page:
1554            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
1555                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Draw Atoms
1556            elif self.dataDisplay.GetPageText(page) == 'Atoms':
1557                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Atoms
1558                   
1559    def SetSelectedAtoms(ind):
1560        page = self.dataDisplay.GetSelection()
1561        if page:
1562            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
1563                self.dataDisplay.GetPage(page).SelectRow(ind)      #this is the Atoms grid in Draw Atoms
1564            elif self.dataDisplay.GetPageText(page) == 'Atoms':
1565                Id = drawAtoms[ind][-2]
1566                for i,atom in enumerate(atomData):
1567                    if atom[-1] == Id:
1568                        self.dataDisplay.GetPage(page).SelectRow(i)      #this is the Atoms grid in Atoms
1569                 
1570    def GetSelectedAtoms():
1571        page = self.dataDisplay.GetSelection()
1572        Ind = []
1573        if page:
1574            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
1575                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Draw Atoms
1576            elif self.dataDisplay.GetPageText(page) == 'Atoms':
1577                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Atoms
1578        return Ind
1579                                       
1580    def OnKey(event):           #on key UP!!
1581        keyCode = event.GetKeyCode()
1582        if keyCode > 255:
1583            keyCode = 0
1584        key,xyz = chr(keyCode),event.GetPosition()
1585        indx = drawingData['selectedAtoms']
1586        if key in ['c','C']:
1587            drawingData['viewPoint'] = [[.5,.5,.5],[0,0]]
1588            drawingData['testPos'] = [[-.1,-.1,-.1],[0.0,0.0,0.0],[0,0]]
1589            drawingData['Rotation'] = [0.0,0.0,0.0,[]]
1590            SetViewPointText(drawingData['viewPoint'][0])
1591        elif key in ['n','N']:
1592            drawAtoms = drawingData['Atoms']
1593            pI = drawingData['viewPoint'][1]
1594            if indx:
1595                pI[0] = indx[pI[1]]
1596                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
1597                pI[1] += 1
1598                if pI[1] >= len(indx):
1599                    pI[1] = 0
1600            else:
1601                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
1602                pI[0] += 1
1603                if pI[0] >= len(drawAtoms):
1604                    pI[0] = 0
1605            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
1606            SetViewPointText(drawingData['viewPoint'][0])
1607               
1608        elif key in ['p','P']:
1609            drawAtoms = drawingData['Atoms']
1610            pI = drawingData['viewPoint'][1]
1611            if indx:
1612                pI[0] = indx[pI[1]]
1613                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
1614                pI[1] -= 1
1615                if pI[1] < 0:
1616                    pI[1] = len(indx)-1
1617            else:
1618                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
1619                pI[0] -= 1
1620                if pI[0] < 0:
1621                    pI[0] = len(drawAtoms)-1
1622            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
1623            SetViewPointText(drawingData['viewPoint'][0])           
1624        Draw()
1625           
1626    def SetBackground():
1627        R,G,B,A = Page.camera['backColor']
1628        glClearColor(R,G,B,A)
1629        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
1630       
1631    def SetLights():
1632        glEnable(GL_DEPTH_TEST)
1633        glShadeModel(GL_SMOOTH)
1634        glEnable(GL_LIGHTING)
1635        glEnable(GL_LIGHT0)
1636        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0)
1637        glLightfv(GL_LIGHT0,GL_AMBIENT,[1,1,1,.8])
1638        glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
1639       
1640    def SetTranslation(newxy):
1641        Tx,Ty,Tz = drawingData['viewPoint'][0]
1642        anglex,angley,anglez,oldxy = drawingData['Rotation']
1643        Rx = G2lat.rotdMat(anglex,0)
1644        Ry = G2lat.rotdMat(angley,1)
1645        Rz = G2lat.rotdMat(anglez,2)
1646        dxy = list(newxy-oldxy)+[0,]
1647        dxy = np.inner(Bmat,np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy))))
1648        Tx -= dxy[0]*0.01
1649        Ty += dxy[1]*0.01
1650        Tz -= dxy[2]*0.01
1651        drawingData['Rotation'][3] = newxy
1652        drawingData['viewPoint'][0] =  Tx,Ty,Tz
1653        SetViewPointText([Tx,Ty,Tz])
1654       
1655    def SetTestPos(newxy):
1656        Tx,Ty,Tz = drawingData['testPos'][0]
1657        anglex,angley,anglez,oldxy = drawingData['Rotation']
1658        Rx = G2lat.rotdMat(anglex,0)
1659        Ry = G2lat.rotdMat(angley,1)
1660        Rz = G2lat.rotdMat(anglez,2)
1661        dxy = list(newxy-oldxy)+[0,]
1662        dxy = np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy)))
1663        Tx += dxy[0]*0.001
1664        Ty -= dxy[1]*0.001
1665        Tz += dxy[2]*0.001
1666        drawingData['Rotation'][3] = newxy
1667        drawingData['testPos'][0] =  Tx,Ty,Tz
1668       
1669    def SetTestRot(newxy):
1670        Txyz = np.array(drawingData['testPos'][0])
1671        oldxy = drawingData['testPos'][2]
1672        Ax,Ay,Az = drawingData['testPos'][1]
1673        Vxyz = np.array(drawingData['viewPoint'][0])
1674        Dxyz = np.inner(Amat,Txyz-Vxyz)
1675        dxy = list(newxy-oldxy)+[0,]
1676        Ax += dxy[1]*0.01
1677        Ay += dxy[0]*0.01
1678        Rx = G2lat.rotdMat(Ax,0)
1679        Ry = G2lat.rotdMat(Ay,1)
1680        Dxyz = np.inner(Ry,np.inner(Rx,Dxyz))       
1681        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
1682        drawingData['testPos'][1] = [Ax,Ay,Az]
1683        drawingData['testPos'][2] = newxy
1684        drawingData['testPos'][0] = Dxyz
1685       
1686    def SetTestRotZ(newxy):
1687        Txyz = np.array(drawingData['testPos'][0])
1688        oldxy = drawingData['testPos'][2]
1689        Ax,Ay,Az = drawingData['testPos'][1]
1690        Vxyz = np.array(drawingData['viewPoint'][0])
1691        Dxyz = np.inner(Amat,Txyz-Vxyz)       
1692        dxy = list(newxy-oldxy)+[0,]
1693        Az += (dxy[0]+dxy[1])*.01
1694        Rz = G2lat.rotdMat(Az,2)
1695        Dxyz = np.inner(Rz,Dxyz)       
1696        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
1697        drawingData['testPos'][1] = [Ax,Ay,Az]
1698        drawingData['testPos'][2] = newxy
1699        drawingData['testPos'][0] = Dxyz
1700                             
1701    def SetRotation(newxy):       
1702        anglex,angley,anglez,oldxy = drawingData['Rotation']
1703        dxy = newxy-oldxy
1704        anglex += dxy[1]*.25
1705        angley += dxy[0]*.25
1706        oldxy = newxy
1707        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
1708       
1709    def SetRotationZ(newxy):                       
1710        anglex,angley,anglez,oldxy = drawingData['Rotation']
1711        dxy = newxy-oldxy
1712        anglez += (dxy[0]+dxy[1])*.25
1713        oldxy = newxy
1714        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
1715       
1716    def RenderBox():
1717        glEnable(GL_COLOR_MATERIAL)
1718        glLineWidth(2)
1719        glEnable(GL_BLEND)
1720        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
1721        glEnable(GL_LINE_SMOOTH)
1722        glBegin(GL_LINES)
1723        for line,color in zip(uEdges,uColors):
1724            glColor3ubv(color)
1725            glVertex3fv(line[0])
1726            glVertex3fv(line[1])
1727        glEnd()
1728        glColor4ubv([0,0,0,0])
1729        glDisable(GL_LINE_SMOOTH)
1730        glDisable(GL_BLEND)
1731        glDisable(GL_COLOR_MATERIAL)
1732       
1733    def RenderUnitVectors(x,y,z):
1734        xyz = np.array([x,y,z])
1735        glEnable(GL_COLOR_MATERIAL)
1736        glLineWidth(1)
1737        glPushMatrix()
1738        glTranslate(x,y,z)
1739        glScalef(1/cell[0],1/cell[1],1/cell[2])
1740        glBegin(GL_LINES)
1741        for line,color in zip(uEdges,uColors)[:3]:
1742            glColor3ubv(color)
1743            glVertex3fv(line[0])
1744            glVertex3fv(line[1])
1745        glEnd()
1746        glPopMatrix()
1747        glColor4ubv([0,0,0,0])
1748        glDisable(GL_COLOR_MATERIAL)
1749               
1750    def RenderSphere(x,y,z,radius,color):
1751        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
1752        glPushMatrix()
1753        glTranslate(x,y,z)
1754        glMultMatrixf(B4mat.T)
1755        q = gluNewQuadric()
1756        gluSphere(q,radius,20,10)
1757        glPopMatrix()
1758       
1759    def RenderEllipsoid(x,y,z,ellipseProb,E,R4,color):
1760        s1,s2,s3 = E
1761        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
1762        glPushMatrix()
1763        glTranslate(x,y,z)
1764        glMultMatrixf(B4mat.T)
1765        glMultMatrixf(R4.T)
1766        glEnable(GL_NORMALIZE)
1767        glScale(s1,s2,s3)
1768        q = gluNewQuadric()
1769        gluSphere(q,ellipseProb,20,10)
1770        glDisable(GL_NORMALIZE)
1771        glPopMatrix()
1772       
1773    def RenderBonds(x,y,z,Bonds,radius,color,slice=20):
1774        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
1775        glPushMatrix()
1776        glTranslate(x,y,z)
1777        glMultMatrixf(B4mat.T)
1778        for bond in Bonds:
1779            glPushMatrix()
1780            Dx = np.inner(Amat,bond)
1781            Z = np.sqrt(np.sum(Dx**2))
1782            azm = atan2d(-Dx[1],-Dx[0])
1783            phi = acosd(Dx[2]/Z)
1784            glRotate(-azm,0,0,1)
1785            glRotate(phi,1,0,0)
1786            q = gluNewQuadric()
1787            gluCylinder(q,radius,radius,Z,slice,2)
1788            glPopMatrix()           
1789        glPopMatrix()
1790               
1791    def RenderLines(x,y,z,Bonds,color):
1792        xyz = np.array([x,y,z])
1793        glEnable(GL_COLOR_MATERIAL)
1794        glLineWidth(1)
1795        glColor3fv(color)
1796        glPushMatrix()
1797        glBegin(GL_LINES)
1798        for bond in Bonds:
1799            glVertex3fv(xyz)
1800            glVertex3fv(xyz+bond)
1801        glEnd()
1802        glColor4ubv([0,0,0,0])
1803        glPopMatrix()
1804        glDisable(GL_COLOR_MATERIAL)
1805       
1806    def RenderPolyhedra(x,y,z,Faces,color):
1807        glPushMatrix()
1808        glTranslate(x,y,z)
1809        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
1810        glShadeModel(GL_SMOOTH)
1811        glMultMatrixf(B4mat.T)
1812        for face,norm in Faces:
1813            glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
1814            glFrontFace(GL_CW)
1815            glNormal3fv(norm)
1816            glBegin(GL_TRIANGLES)
1817            for vert in face:
1818                glVertex3fv(vert)
1819            glEnd()
1820        glPopMatrix()
1821       
1822    def RenderBackbone(Backbone,BackboneColor,radius):
1823        glPushMatrix()
1824        glMultMatrixf(B4mat.T)
1825        glEnable(GL_COLOR_MATERIAL)
1826        glShadeModel(GL_SMOOTH)
1827        gleSetJoinStyle(TUBE_NORM_EDGE | TUBE_JN_ANGLE | TUBE_JN_CAP)
1828        glePolyCylinder(Backbone,BackboneColor,radius)
1829        glPopMatrix()       
1830        glDisable(GL_COLOR_MATERIAL)
1831       
1832    def RenderLabel(x,y,z,label,r):       
1833        glPushMatrix()
1834        glTranslate(x,y,z)
1835        glMultMatrixf(B4mat.T)
1836        glDisable(GL_LIGHTING)
1837        glColor3f(0,1.,0)
1838        glRasterPos3f(r,r,r)
1839        for c in list(label):
1840            glutBitmapCharacter(GLUT_BITMAP_8_BY_13,ord(c))
1841        glEnable(GL_LIGHTING)
1842        glPopMatrix()
1843                           
1844    def Draw():
1845        import numpy.linalg as nl
1846        Ind = GetSelectedAtoms()
1847        VS = np.array(Page.canvas.GetSize())
1848        aspect = float(VS[0])/float(VS[1])
1849        cPos = drawingData['cameraPos']
1850        Zclip = drawingData['Zclip']*cPos/200.
1851        anglex,angley,anglez = drawingData['Rotation'][:3]
1852        Tx,Ty,Tz = drawingData['viewPoint'][0]
1853        cx,ct,cs = drawingData['atomPtrs']
1854        bondR = drawingData['bondRadius']
1855        G,g = G2lat.cell2Gmat(cell)
1856        GS = G
1857        GS[0][1] = GS[1][0] = math.sqrt(GS[0][0]*GS[1][1])
1858        GS[0][2] = GS[2][0] = math.sqrt(GS[0][0]*GS[2][2])
1859        GS[1][2] = GS[2][1] = math.sqrt(GS[1][1]*GS[2][2])
1860        ellipseProb = G2lat.criticalEllipse(drawingData['ellipseProb']/100.)
1861       
1862        SetBackground()
1863        glInitNames()
1864        glPushName(0)
1865       
1866        glMatrixMode(GL_PROJECTION)
1867        glLoadIdentity()
1868        glViewport(0,0,VS[0],VS[1])
1869        gluPerspective(20.,aspect,cPos-Zclip,cPos+Zclip)
1870        gluLookAt(0,0,cPos,0,0,0,0,1,0)
1871        SetLights()           
1872           
1873        glMatrixMode(GL_MODELVIEW)
1874        glLoadIdentity()
1875        glRotate(anglez,0,0,1)
1876        glRotate(anglex,cosd(anglez),-sind(anglez),0)
1877        glRotate(angley,sind(anglez),cosd(anglez),0)
1878        glMultMatrixf(A4mat.T)
1879        glTranslate(-Tx,-Ty,-Tz)
1880        if drawingData['unitCellBox']:
1881            RenderBox()
1882        if drawingData['showABC']:
1883#            try:            #temporary fix - not needed further?
1884#                x,y,z = drawingData['testPos'][0]
1885#            except TypeError:
1886#                x,y,z = drawingData['testPos']
1887            x,y,z = drawingData['testPos'][0]
1888            if altDown:
1889                self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
1890            else:
1891                self.G2plotNB.status.SetStatusText('test point %.4f,%.4f,%.4f'%(x,y,z),1)           
1892            RenderUnitVectors(x,y,z)
1893        Backbone = []
1894        BackboneColor = []
1895        time0 = time.time()
1896        for iat,atom in enumerate(drawingData['Atoms']):
1897            x,y,z = atom[cx:cx+3]
1898            Bonds = atom[-2]
1899            Faces = atom[-1]
1900            try:
1901                atNum = generalData['AtomTypes'].index(atom[ct])
1902            except ValueError:
1903                atNum = -1
1904            CL = atom[cs+2]
1905            color = np.array(CL)/255.
1906            if iat in Ind:
1907                color = np.array(Gr)/255.
1908            radius = 0.5
1909            if atom[cs] != '':
1910                glLoadName(atom[-3])                   
1911            if 'balls' in atom[cs]:
1912                vdwScale = drawingData['vdwScale']
1913                ballScale = drawingData['ballScale']
1914                if atNum < 0:
1915                    radius = 0.2
1916                elif 'H' == atom[ct]:
1917                    if drawingData['showHydrogen']:
1918                        if 'vdW' in atom[cs] and atNum >= 0:
1919                            radius = vdwScale*generalData['vdWRadii'][atNum]
1920                        else:
1921                            radius = ballScale*drawingData['sizeH']
1922                    else:
1923                        radius = 0.0
1924                else:
1925                    if 'vdW' in atom[cs]:
1926                        radius = vdwScale*generalData['vdWRadii'][atNum]
1927                    else:
1928                        radius = ballScale*generalData['BondRadii'][atNum]
1929                RenderSphere(x,y,z,radius,color)
1930                if 'sticks' in atom[cs]:
1931                    RenderBonds(x,y,z,Bonds,bondR,color)
1932            elif 'ellipsoids' in atom[cs]:
1933                RenderBonds(x,y,z,Bonds,bondR,color)
1934                if atom[cs+3] == 'A':                   
1935                    Uij = atom[cs+5:cs+11]
1936                    U = np.multiply(G2spc.Uij2U(Uij),GS)
1937                    U = np.inner(Amat,np.inner(U,Amat).T)
1938                    E,R = nl.eigh(U)
1939                    R4 = np.concatenate((np.concatenate((R,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1940                    E = np.sqrt(E)
1941                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
1942                        pass
1943                    else:
1944                        RenderEllipsoid(x,y,z,ellipseProb,E,R4,color)                   
1945                else:
1946                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
1947                        pass
1948                    else:
1949                        radius = ellipseProb*math.sqrt(abs(atom[cs+4]))
1950                        RenderSphere(x,y,z,radius,color)
1951            elif 'lines' in atom[cs]:
1952                radius = 0.1
1953                RenderLines(x,y,z,Bonds,color)
1954#                RenderBonds(x,y,z,Bonds,0.05,color,6)
1955            elif atom[cs] == 'sticks':
1956                radius = 0.1
1957                RenderBonds(x,y,z,Bonds,bondR,color)
1958            elif atom[cs] == 'polyhedra':
1959                RenderPolyhedra(x,y,z,Faces,color)
1960            elif atom[cs] == 'backbone':
1961                if atom[ct-1].split()[0] in ['C','N']:
1962                    Backbone.append(list(np.inner(Amat,np.array([x,y,z]))))
1963                    BackboneColor.append(list(color))
1964                   
1965            if atom[cs+1] == 'type':
1966                RenderLabel(x,y,z,atom[ct],radius)
1967            elif atom[cs+1] == 'name':
1968                RenderLabel(x,y,z,atom[ct-1],radius)
1969            elif atom[cs+1] == 'number':
1970                RenderLabel(x,y,z,str(iat+1),radius)
1971            elif atom[cs+1] == 'residue' and atom[ct-1] == 'CA':
1972                RenderLabel(x,y,z,atom[ct-4],radius)
1973            elif atom[cs+1] == '1-letter' and atom[ct-1] == 'CA':
1974                RenderLabel(x,y,z,atom[ct-3],radius)
1975            elif atom[cs+1] == 'chain' and atom[ct-1] == 'CA':
1976                RenderLabel(x,y,z,atom[ct-2],radius)
1977        if Backbone:
1978            RenderBackbone(Backbone,BackboneColor,bondR)
1979#        print time.time()-time0
1980        Page.canvas.SwapBuffers()
1981       
1982    def OnSize(event):
1983        Draw()
1984       
1985    def OnFocus(event):
1986        Draw()
1987       
1988    try:
1989        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
1990        Page = self.G2plotNB.nb.GetPage(plotNum)       
1991    except (ValueError,error):
1992        Plot = self.G2plotNB.addOgl(generalData['Name'])
1993        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
1994        Page = self.G2plotNB.nb.GetPage(plotNum)
1995        Page.views = False
1996        view = False
1997        altDown = False
1998    Page.SetFocus()
1999    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
2000        choices=(' save as:','jpeg','tiff','bmp'))
2001    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
2002    cb.SetValue(' save as:')
2003    Page.canvas.Bind(wx.EVT_MOUSEWHEEL, OnMouseWheel)
2004    Page.canvas.Bind(wx.EVT_LEFT_DOWN, OnMouseDown)
2005    Page.canvas.Bind(wx.EVT_RIGHT_DOWN, OnMouseDown)
2006    Page.canvas.Bind(wx.EVT_MIDDLE_DOWN, OnMouseDown)
2007    Page.canvas.Bind(wx.EVT_KEY_UP, OnKey)
2008    Page.canvas.Bind(wx.EVT_MOTION, OnMouseMove)
2009    Page.canvas.Bind(wx.EVT_SIZE, OnSize)
2010    Page.canvas.Bind(wx.EVT_SET_FOCUS, OnFocus)
2011    Page.camera['position'] = drawingData['cameraPos']
2012    Page.camera['viewPoint'] = np.inner(Amat,drawingData['viewPoint'][0])
2013    Page.camera['backColor'] = np.array(list(drawingData['backColor'])+[0,])/255.
2014    Page.canvas.SetCurrent()
2015    Draw()
2016       
Note: See TracBrowser for help on using the repository browser.