source: trunk/GSASIIplot.py @ 360

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

just backup before trip

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