source: trunk/GSASIIplot.py @ 342

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

major modifications to get 1st "working" version of Refine
Add GSASIImapvars.py
fix cell refinement in indexing window
single cycle for peak refinement

  • Property svn:keywords set to Date Author Revision URL Id
File size: 106.4 KB
Line 
1#GSASII plotting routines
2########### SVN repository information ###################
3# $Date: 2011-08-05 19:35:43 +0000 (Fri, 05 Aug 2011) $
4# $Author: vondreele $
5# $Revision: 342 $
6# $URL: trunk/GSASIIplot.py $
7# $Id: GSASIIplot.py 342 2011-08-05 19:35:43Z vondreele $
8########### SVN repository information ###################
9import math
10import time
11import copy
12import os.path
13import numpy as np
14import numpy.linalg as nl
15import wx
16import wx.aui
17import wx.glcanvas
18import matplotlib as mpl
19import mpl_toolkits.mplot3d.axes3d as mp3d
20import GSASIIpath
21import GSASIIgrid as G2gd
22import GSASIIimage as G2img
23import GSASIIpwd as G2pwd
24import GSASIIIO as G2IO
25import GSASIIpwdGUI as G2pdG
26import GSASIIimgGUI as G2imG
27import GSASIIphsGUI as G2phG
28import GSASIIlattice as G2lat
29import GSASIIspc as G2spc
30import pytexture as ptx
31from  OpenGL.GL import *
32from OpenGL.GLU import *
33from OpenGL.GLUT import *
34from OpenGL.GLE import *
35from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
36from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
37
38# useful degree trig functions
39sind = lambda x: math.sin(x*math.pi/180.)
40cosd = lambda x: math.cos(x*math.pi/180.)
41tand = lambda x: math.tan(x*math.pi/180.)
42asind = lambda x: 180.*math.asin(x)/math.pi
43acosd = lambda x: 180.*math.acos(x)/math.pi
44atan2d = lambda x,y: 180.*math.atan2(y,x)/math.pi
45atand = lambda x: 180.*math.atan(x)/math.pi
46# numpy versions
47npsind = lambda x: np.sin(x*np.pi/180.)
48npcosd = lambda x: np.cos(x*np.pi/180.)
49npacosd = lambda x: 180.*np.arccos(x)/np.pi
50npasind = lambda x: 180.*np.arcsin(x)/np.pi
51npatand = lambda x: 180.*np.arctan(x)/np.pi
52npatan2d = lambda x,y: 180.*np.arctan2(x,y)/np.pi
53   
54class G2PlotMpl(wx.Panel):   
55    def __init__(self,parent,id=-1,dpi=None,**kwargs):
56        wx.Panel.__init__(self,parent,id=id,**kwargs)
57        mpl.rcParams['legend.fontsize'] = 8
58        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(5,7))
59        self.canvas = Canvas(self,-1,self.figure)
60        self.toolbar = Toolbar(self.canvas)
61
62        self.toolbar.Realize()
63       
64        sizer=wx.BoxSizer(wx.VERTICAL)
65        sizer.Add(self.canvas,1,wx.EXPAND)
66        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
67        self.SetSizer(sizer)
68       
69class G2PlotOgl(wx.Panel):
70    def __init__(self,parent,id=-1,dpi=None,**kwargs):
71        self.figure = wx.Panel.__init__(self,parent,id=id,**kwargs)
72        self.canvas = wx.glcanvas.GLCanvas(self,-1,**kwargs)
73        self.camera = {}
74        sizer=wx.BoxSizer(wx.VERTICAL)
75        sizer.Add(self.canvas,1,wx.EXPAND)
76        self.SetSizer(sizer)
77       
78class G2Plot3D(wx.Panel):
79    def __init__(self,parent,id=-1,dpi=None,**kwargs):
80        wx.Panel.__init__(self,parent,id=id,**kwargs)
81        self.figure = mpl.figure.Figure(dpi=dpi,figsize=(6,6))
82        self.canvas = Canvas(self,-1,self.figure)
83        self.toolbar = Toolbar(self.canvas)
84
85        self.toolbar.Realize()
86       
87        sizer=wx.BoxSizer(wx.VERTICAL)
88        sizer.Add(self.canvas,1,wx.EXPAND)
89        sizer.Add(self.toolbar,0,wx.LEFT|wx.EXPAND)
90        self.SetSizer(sizer)
91                             
92class G2PlotNoteBook(wx.Panel):
93    def __init__(self,parent,id=-1):
94        wx.Panel.__init__(self,parent,id=id)
95        #so one can't delete a plot page!!
96        self.nb = wx.aui.AuiNotebook(self, \
97            style=wx.aui.AUI_NB_DEFAULT_STYLE ^ wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
98        sizer = wx.BoxSizer()
99        sizer.Add(self.nb,1,wx.EXPAND)
100        self.SetSizer(sizer)
101        self.status = parent.CreateStatusBar()
102        self.status.SetFieldsCount(2)
103        self.status.SetStatusWidths([150,-1])
104        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
105       
106        self.plotList = []
107           
108    def addMpl(self,name=""):
109        page = G2PlotMpl(self.nb)
110        self.nb.AddPage(page,name)
111       
112        self.plotList.append(name)
113       
114        return page.figure
115       
116    def add3D(self,name=""):
117        page = G2Plot3D(self.nb)
118        self.nb.AddPage(page,name)
119       
120        self.plotList.append(name)
121       
122        return page.figure
123       
124    def addOgl(self,name=""):
125        page = G2PlotOgl(self.nb)
126        self.nb.AddPage(page,name)
127       
128        self.plotList.append(name)
129       
130        return page.figure
131       
132    def Delete(self,name):
133        try:
134            item = self.plotList.index(name)
135            del self.plotList[item]
136            self.nb.DeletePage(item)
137        except ValueError:          #no plot of this name - do nothing
138            return     
139               
140    def clear(self):
141        while self.nb.GetPageCount():
142            self.nb.DeletePage(0)
143        self.plotList = []
144        self.status.DestroyChildren()
145       
146    def Rename(self,oldName,newName):
147        try:
148            item = self.plotList.index(oldName)
149            self.plotList[item] = newName
150            self.nb.SetPageText(item,newName)
151        except ValueError:          #no plot of this name - do nothing
152            return     
153       
154    def OnPageChanged(self,event):       
155        if self.plotList:
156            self.status.SetStatusText('Better to select this from GSAS-II data tree',1)
157        self.status.DestroyChildren()                           #get rid of special stuff on status bar
158       
159def PlotSngl(self,newPlot=False):
160    '''Single crystal structure factor plotting package - displays zone of reflections as rings proportional
161        to F, F**2, etc. as requested
162    '''
163    from matplotlib.patches import Circle
164    global HKL,HKLF
165
166    def OnSCMotion(event):
167        xpos = event.xdata
168        if xpos:
169            xpos = round(xpos)                                        #avoid out of frame mouse position
170            ypos = round(event.ydata)
171            zpos = Data['Layer']
172            if '100' in Data['Zone']:
173                HKLtxt = '(%3d,%3d,%3d)'%(zpos,xpos,ypos)
174            elif '010' in Data['Zone']:
175                HKLtxt = '(%3d,%3d,%3d)'%(xpos,zpos,ypos)
176            elif '001' in Data['Zone']:
177                HKLtxt = '(%3d,%3d,%3d)'%(xpos,ypos,zpos)
178            Page.canvas.SetToolTipString(HKLtxt)
179            self.G2plotNB.status.SetFields(['HKL = '+HKLtxt,''])
180               
181    def OnSCPick(event):
182        zpos = Data['Layer']
183        pos = event.artist.center
184        if '100' in Data['Zone']:
185            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(zpos,pos[0],pos[1]))
186            hkl = np.array([zpos,pos[0],pos[1]])
187        elif '010' in Data['Zone']:
188            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],zpos,pos[1]))
189            hkl = np.array([pos[0],zpos,pos[1]])
190        elif '001' in Data['Zone']:
191            Page.canvas.SetToolTipString('(picked:(%3d,%3d,%3d))'%(pos[0],pos[1],zpos))
192            hkl = np.array([pos[0],pos[1],zpos])
193        h,k,l = hkl
194        hklf = HKLF[np.where(np.all(HKL-hkl == [0,0,0],axis=1))]
195        if len(hklf):
196            Fosq,sig,Fcsq = hklf[0]
197            HKLtxt = '(%3d,%3d,%3d %.2f %.3f %.2f %.2f)'%(h,k,l,Fosq,sig,Fcsq,(Fosq-Fcsq)/(scale*sig))
198            self.G2plotNB.status.SetFields(['','HKL, Fosq, sig, Fcsq, delFsq/sig = '+HKLtxt])
199                                 
200    def OnSCKeyPress(event):
201        print event.key
202
203    try:
204        plotNum = self.G2plotNB.plotList.index('Structure Factors')
205        Page = self.G2plotNB.nb.GetPage(plotNum)
206        if not newPlot:
207            Plot = Page.figure.gca()          #get previous powder plot & get limits
208            xylim = Plot.get_xlim(),Plot.get_ylim()
209        Page.figure.clf()
210        Plot = Page.figure.gca()          #get a fresh plot after clf()
211    except ValueError:
212        Plot = self.G2plotNB.addMpl('Structure Factors').gca()
213        plotNum = self.G2plotNB.plotList.index('Structure Factors')
214        Page = self.G2plotNB.nb.GetPage(plotNum)
215#        Page.canvas.mpl_connect('key_press_event', OnSCKeyPress)
216        Page.canvas.mpl_connect('pick_event', OnSCPick)
217        Page.canvas.mpl_connect('motion_notify_event', OnSCMotion)
218    Page.SetFocus()
219   
220    Plot.set_aspect(aspect='equal')
221    HKLref = self.PatternTree.GetItemPyData(self.Sngl)
222    Data = self.PatternTree.GetItemPyData( \
223        G2gd.GetPatternTreeItemId(self,self.Sngl, 'HKL Plot Controls'))
224    Type = Data['Type']           
225    scale = Data['Scale']
226    HKLmax = Data['HKLmax']
227    HKLmin = Data['HKLmin']
228    FosqMax = Data['FoMax']
229    FoMax = math.sqrt(FosqMax)
230    ifFc = Data['ifFc']
231    xlabel = ['k, h=','h, k=','h, l=']
232    ylabel = ['l','l','k']
233    zones = ['100','010','001']
234    pzone = [[1,2],[0,2],[0,1]]
235    izone = zones.index(Data['Zone'])
236    Plot.set_title(self.PatternTree.GetItemText(self.Sngl)[5:])
237    HKL = []
238    HKLF = []
239    for H,Fosq,sig,Fcsq,x,x,x in HKLref:
240        HKL.append(H)
241        HKLF.append([Fosq,sig,Fcsq])
242        if H[izone] == Data['Layer']:
243            B = 0
244            if Type == 'Fosq':
245                A = scale*Fosq/FosqMax
246                B = scale*Fcsq/FosqMax
247                C = abs(A-B)
248            elif Type == 'Fo':
249                A = scale*math.sqrt(max(0,Fosq))/FoMax
250                B = scale*math.sqrt(max(0,Fcsq))/FoMax
251                C = abs(A-B)
252            elif Type == '|DFsq|/sig':
253                A = abs(Fosq-Fcsq)/(scale*sig)
254            elif Type == '|DFsq|>sig':
255                A = abs(Fosq-Fcsq)/(scale*sig)
256                if A < 1.0: A = 0                   
257            elif Type == '|DFsq|>3sig':
258                A = abs(Fosq-Fcsq)/(scale*sig)
259                if A < 3.0: A = 0                   
260            xy = (H[pzone[izone][0]],H[pzone[izone][1]])
261            if A > 0.0:
262                Plot.add_artist(Circle(xy,radius=A,ec='g',fc='w',picker=3))
263            if B:
264                Plot.add_artist(Circle(xy,radius=B,ec='b',fc='w'))
265                radius = C
266                if radius > 0:
267                    if A > B:
268                        Plot.add_artist(Circle(xy,radius=radius,ec='g',fc='g'))
269                    else:                   
270                        Plot.add_artist(Circle(xy,radius=radius,ec='r',fc='r'))
271    HKL = np.array(HKL,dtype=np.int)
272    HKLF = np.array(HKLF)
273    Plot.set_xlabel(xlabel[izone]+str(Data['Layer']),fontsize=12)
274    Plot.set_ylabel(ylabel[izone],fontsize=12)
275    Plot.set_xlim((HKLmin[pzone[izone][0]],HKLmax[pzone[izone][0]]))
276    Plot.set_ylim((HKLmin[pzone[izone][1]],HKLmax[pzone[izone][1]]))
277    if not newPlot:
278        Page.toolbar.push_current()
279        Plot.set_xlim(xylim[0])
280        Plot.set_ylim(xylim[1])
281        xylim = []
282        Page.toolbar.push_current()
283        Page.toolbar.draw()
284    else:
285        Page.canvas.draw()
286       
287def PlotPatterns(self,newPlot=False):
288    '''Powder pattern plotting package - displays single or multiple powder patterns as intensity vs
289    2-theta or q (future TOF). Can display multiple patterns as "waterfall plots" or contour plots. Log I
290    plotting available.
291    '''
292    global HKL
293   
294    def OnPick(event):
295        if self.itemPicked is not None: return
296        PatternId = self.PatternId
297        try:
298            Values,Names = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.PatternId, 'Instrument Parameters'))[1::2]
299        except TypeError:
300            return
301        Parms = dict(zip(Names,Values))
302        try:
303            wave = Parms['Lam']
304        except KeyError:
305            wave = Parms['Lam1']
306        PickId = self.PickId
307        pick = event.artist
308        mouse = event.mouseevent       
309        xpos = pick.get_xdata()
310        ypos = pick.get_ydata()
311        ind = event.ind
312        xy = list(zip(np.take(xpos,ind),np.take(ypos,ind))[0])
313        if self.PatternTree.GetItemText(PickId) == 'Peak List':
314            if ind.all() != [0]:                                    #picked a data point
315                if 'C' in Parms['Type']:                            #CW data - TOF later in an elif
316                    ins = [Parms[x] for x in ['U','V','W','X','Y']]
317                    if self.qPlot:                              #qplot - convert back to 2-theta
318                        xy[0] = 2.0*asind(xy[0]*wave/(4*math.pi))
319                    sig = ins[0]*tand(xy[0]/2.0)**2+ins[1]*tand(xy[0]/2.0)+ins[2]
320                    gam = ins[3]/cosd(xy[0]/2.0)+ins[4]*tand(xy[0]/2.0)           
321                    data = self.PatternTree.GetItemPyData(self.PickId)
322                    XY = [xy[0],0, xy[1],1, sig,0, gam,0]       #default refine intensity 1st
323                data.append(XY)
324                G2pdG.UpdatePeakGrid(self,data)
325                PlotPatterns(self)
326            else:                                                   #picked a peak list line
327                self.itemPicked = pick
328        elif self.PatternTree.GetItemText(PickId) == 'Limits':
329            if ind.all() != [0]:                                    #picked a data point
330                LimitId = G2gd.GetPatternTreeItemId(self,PatternId, 'Limits')
331                data = self.PatternTree.GetItemPyData(LimitId)
332                if 'C' in Parms['Type']:                            #CW data - TOF later in an elif
333                    if self.qPlot:                              #qplot - convert back to 2-theta
334                        xy[0] = 2.0*asind(xy[0]*wave/(4*math.pi))
335                if mouse.button==1:
336                    data[1][0] = min(xy[0],data[1][1])
337                if mouse.button==3:
338                    data[1][1] = max(xy[0],data[1][0])
339                self.PatternTree.SetItemPyData(LimitId,data)
340                G2pdG.UpdateLimitsGrid(self,data)
341                PlotPatterns(self)
342            else:                                                   #picked a limit line
343                self.itemPicked = pick
344       
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            Img = Plot.imshow(Z.T,aspect='equal',cmap=self.ContourColor,extent=[-1,1,-1,1])
1331            if newPlot:
1332#                Page.figure.colorbar(Img)    #colorbar fails - crashes gsasii
1333                newPlot = False
1334            Plot.set_title('Inverse pole figure for XYZ='+str(SHData['PFxyz']))
1335            Plot.set_xlabel(self.Projection.capitalize()+' projection')
1336                       
1337        else:
1338            X,Y = np.meshgrid(np.linspace(1.,-1.,npts),np.linspace(-1.,1.,npts))
1339            R,P = np.sqrt(X**2+Y**2).flatten(),npatan2d(X,Y).flatten()
1340            if 'equal' in self.Projection:
1341                R = np.where(R <= 1.,2.*npasind(R*sq2),0.0)
1342            else:
1343                R = np.where(R <= 1.,2.*npatand(R),0.0)
1344            Z = np.zeros_like(R)
1345            Z = G2lat.polfcal(ODFln,SamSym[textureData['Model']],R,P)
1346            Z = np.reshape(Z,(npts,npts))
1347            CS = Plot.contour(Y,X,Z,aspect='equal')
1348            Plot.clabel(CS,fontsize=9,inline=1)
1349            Img = Plot.imshow(Z.T,aspect='equal',cmap=self.ContourColor,extent=[-1,1,-1,1])
1350            if newPlot:
1351#                Page.figure.colorbar(Img)    #colorbar fails - crashes gsasii
1352                newPlot = False
1353            Plot.set_title('Pole figure for HKL='+str(SHData['PFhkl']))
1354            Plot.set_xlabel(self.Projection.capitalize()+' projection')
1355    Page.canvas.draw()
1356
1357           
1358def PlotExposedImage(self,newPlot=False,event=None):
1359    '''General access module for 2D image plotting
1360    '''
1361    plotNo = self.G2plotNB.nb.GetSelection()
1362    if self.G2plotNB.nb.GetPageText(plotNo) == '2D Powder Image':
1363        PlotImage(self,newPlot,event,newImage=True)
1364    elif self.G2plotNB.nb.GetPageText(plotNo) == '2D Integration':
1365        PlotIntegration(self,newPlot,event)
1366
1367def PlotImage(self,newPlot=False,event=None,newImage=True):
1368    '''Plot of 2D detector images as contoured plot. Also plot calibration ellipses,
1369    masks, etc.
1370    '''
1371    from matplotlib.patches import Ellipse,Arc,Circle,Polygon
1372    import numpy.ma as ma
1373    Dsp = lambda tth,wave: wave/(2.*sind(tth/2.))
1374    global Data,Masks
1375    colors=['b','g','r','c','m','k']
1376    Data = self.PatternTree.GetItemPyData(
1377        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1378    Masks = self.PatternTree.GetItemPyData(
1379        G2gd.GetPatternTreeItemId(self,self.Image, 'Masks'))
1380
1381    def OnImMotion(event):
1382        Page.canvas.SetToolTipString('')
1383        sizexy = Data['size']
1384        if event.xdata and event.ydata:                 #avoid out of frame errors
1385            Page.canvas.SetCursor(wx.CROSS_CURSOR)
1386            item = self.itemPicked
1387            pixelSize = Data['pixelSize']
1388            scalex = 1000./pixelSize[0]
1389            scaley = 1000./pixelSize[1]
1390            if item and self.PatternTree.GetItemText(self.PickId) == 'Image Controls':
1391                if 'Text' in str(item):
1392                    Page.canvas.SetToolTipString('%8.3f %8.3fmm'%(event.xdata,event.ydata))
1393                else:
1394                    xcent,ycent = Data['center']
1395                    xpos = event.xdata-xcent
1396                    ypos = event.ydata-ycent
1397                    tth,azm = G2img.GetTthAzm(event.xdata,event.ydata,Data)
1398                    if 'line3' in  str(item) or 'line4' in str(item) and not Data['fullIntegrate']:
1399                        Page.canvas.SetToolTipString('%6d deg'%(azm))
1400                    elif 'line1' in  str(item) or 'line2' in str(item):
1401                        Page.canvas.SetToolTipString('%8.3fdeg'%(tth))                           
1402            else:
1403                xpos = event.xdata
1404                ypos = event.ydata
1405                xpix = xpos*scalex
1406                ypix = ypos*scaley
1407                Int = 0
1408                if (0 <= xpix <= sizexy[0]) and (0 <= ypix <= sizexy[1]):
1409                    Int = self.ImageZ[ypix][xpix]
1410                tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1411                Q = 2.*math.pi/dsp
1412                if self.setPoly:
1413                    self.G2plotNB.status.SetFields(['','Polygon mask pick - LB next point, RB close polygon'])
1414                else:
1415                    self.G2plotNB.status.SetFields(\
1416                        ['','Detector 2-th =%9.3fdeg, dsp =%9.3fA, Q = %6.5fA-1, azm = %7.2fdeg, I = %6d'%(tth,dsp,Q,azm,Int)])
1417
1418    def OnImPlotKeyPress(event):
1419        try:
1420            PickName = self.PatternTree.GetItemText(self.PickId)
1421        except TypeError:
1422            return
1423        if PickName == 'Masks':
1424            Xpos = event.xdata
1425            if not Xpos:            #got point out of frame
1426                return
1427            Ypos = event.ydata
1428            if event.key == 's':
1429                Masks['Points'].append([Xpos,Ypos,1.])
1430            elif event.key == 'r':
1431                tth = G2img.GetTth(Xpos,Ypos,Data)
1432                Masks['Rings'].append([tth,0.1])
1433            elif event.key == 'a':
1434                tth,azm = G2img.GetTthAzm(Xpos,Ypos,Data)
1435                azm = int(azm)               
1436                Masks['Arcs'].append([tth,[azm-5,azm+5],0.1])
1437            elif event.key == 'p':
1438                self.setPoly = True
1439                Masks['Polygons'].append([])
1440                self.G2plotNB.status.SetFields(['','Polygon mask active - LB pick next point, RB close polygon'])
1441            G2imG.UpdateMasks(self,Masks)
1442        elif PickName == 'Image Controls':
1443            if event.key == 'c':
1444                Xpos = event.xdata
1445                if not Xpos:            #got point out of frame
1446                    return
1447                Ypos = event.ydata
1448                dlg = wx.MessageDialog(self,'Are you sure you want to change the center?',
1449                    'Center change',style=wx.OK|wx.CANCEL)
1450                try:
1451                    if dlg.ShowModal() == wx.ID_OK:
1452                        print 'move center to: ',Xpos,Ypos
1453                        Data['center'] = [Xpos,Ypos]
1454                        G2imG.UpdateImageControls(self,Data,Masks)
1455                finally:
1456                    dlg.Destroy()
1457            elif event.key == 'l':
1458                if self.logPlot:
1459                    self.logPlot = False
1460                else:
1461                    self.logPlot = True
1462        PlotImage(self,newImage=True)
1463           
1464    def OnKeyBox(event):
1465        if self.G2plotNB.nb.GetSelection() == self.G2plotNB.plotList.index('2D Powder Image'):
1466            event.key = cb.GetValue()[0]
1467            cb.SetValue(' key press')
1468            if event.key in 'l':
1469                OnImPlotKeyPress(event)
1470                       
1471    def OnImPick(event):
1472        if self.PatternTree.GetItemText(self.PickId) not in ['Image Controls','Masks']:
1473            return
1474        if self.setPoly:
1475            polygon = Masks['Polygons'][-1]
1476            xpos,ypos = event.mouseevent.xdata,event.mouseevent.ydata
1477            if xpos and ypos:                       #point inside image
1478                if len(polygon) > 2 and event.mouseevent.button == 3:
1479                    x0,y0 = polygon[0]
1480                    polygon.append([x0,y0])
1481                    self.setPoly = False
1482                    self.G2plotNB.status.SetFields(['','Polygon closed - RB drag a vertex to change shape'])
1483                else:
1484                    self.G2plotNB.status.SetFields(['','New polygon point: %.1f,%.1f'%(xpos,ypos)])
1485                    polygon.append([xpos,ypos])
1486                G2imG.UpdateMasks(self,Masks)
1487        else:
1488            if self.itemPicked is not None: return
1489            self.itemPicked = event.artist
1490            self.mousePicked = event.mouseevent
1491       
1492    def OnImRelease(event):
1493        try:
1494            PickName = self.PatternTree.GetItemText(self.PickId)
1495        except TypeError:
1496            return
1497        if PickName not in ['Image Controls','Masks']:
1498            return
1499        pixelSize = Data['pixelSize']
1500        scalex = 1000./pixelSize[0]
1501        scaley = 1000./pixelSize[1]
1502        pixLimit = Data['pixLimit']
1503        if self.itemPicked is None and PickName == 'Image Controls':
1504#            sizexy = Data['size']
1505            Xpos = event.xdata
1506            if not (Xpos and self.ifGetRing):                   #got point out of frame
1507                return
1508            Ypos = event.ydata
1509            if Ypos and not Page.toolbar._active:         #make sure zoom/pan not selected
1510                if event.button == 1:
1511                    Xpix = Xpos*scalex
1512                    Ypix = Ypos*scaley
1513                    xpos,ypos,I,J = G2img.ImageLocalMax(self.ImageZ,pixLimit,Xpix,Ypix)
1514                    if I and J:
1515                        xpos += .5                              #shift to pixel center
1516                        ypos += .5
1517                        xpos /= scalex                          #convert to mm
1518                        ypos /= scaley
1519                        Data['ring'].append([xpos,ypos])
1520                elif event.button == 3:
1521                    self.dataFrame.GetStatusBar().SetStatusText('Calibrating...')
1522                    if G2img.ImageCalibrate(self,Data):
1523                        self.dataFrame.GetStatusBar().SetStatusText('Calibration successful - Show ring picks to check')
1524                        print 'Calibration successful'
1525                    else:
1526                        self.dataFrame.GetStatusBar().SetStatusText('Calibration failed - Show ring picks to diagnose')
1527                        print 'Calibration failed'
1528                    self.ifGetRing = False
1529                    G2imG.UpdateImageControls(self,Data,Masks)
1530                    return
1531                PlotImage(self,newImage=False)
1532            return
1533        else:
1534            xpos = event.xdata
1535            if xpos:                                        #avoid out of frame mouse position
1536                ypos = event.ydata
1537                if self.ifGetRing:                          #delete a calibration ring pick
1538                    xypos = [xpos,ypos]
1539                    rings = Data['ring']
1540                    for ring in rings:
1541                        if np.allclose(ring,xypos,.01,0):
1542                            rings.remove(ring)                                                                       
1543                else:
1544                    tth,azm,dsp = G2img.GetTthAzmDsp(xpos,ypos,Data)
1545                    itemPicked = str(self.itemPicked)
1546                    if 'Line2D' in itemPicked and PickName == 'Image Controls':
1547                        if 'line1' in itemPicked:
1548                            Data['IOtth'][0] = max(tth,0.001)
1549                        elif 'line2' in itemPicked:
1550                            Data['IOtth'][1] = tth
1551                        elif 'line3' in itemPicked:
1552                            Data['LRazimuth'][0] = int(azm)
1553                            if Data['fullIntegrate']:
1554                                Data['LRazimuth'][1] = Data['LRazimuth'][0]+360
1555                        elif 'line4' in itemPicked and not Data['fullIntegrate']:
1556                            Data['LRazimuth'][1] = int(azm)
1557                           
1558                        if Data['LRazimuth'][0] > Data['LRazimuth'][1]:
1559                            Data['LRazimuth'][0] -= 360
1560                           
1561                        azLim = np.array(Data['LRazimuth'])   
1562                        if np.any(azLim>360):
1563                            azLim -= 360
1564                            Data['LRazimuth'] = list(azLim)
1565                           
1566                        if  Data['IOtth'][0] > Data['IOtth'][1]:
1567                            Data['IOtth'][0],Data['IOtth'][1] = Data['IOtth'][1],Data['IOtth'][0]
1568                           
1569                        self.InnerTth.SetValue("%8.2f" % (Data['IOtth'][0]))
1570                        self.OuterTth.SetValue("%8.2f" % (Data['IOtth'][1]))
1571                        self.Lazim.SetValue("%6d" % (Data['LRazimuth'][0]))
1572                        self.Razim.SetValue("%6d" % (Data['LRazimuth'][1]))
1573                    elif 'Circle' in itemPicked and PickName == 'Masks':
1574                        spots = Masks['Points']
1575                        newPos = itemPicked.split(')')[0].split('(')[2].split(',')
1576                        newPos = np.array([float(newPos[0]),float(newPos[1])])
1577                        for spot in spots:
1578                            if np.allclose(np.array([spot[:2]]),newPos):
1579                                spot[:2] = xpos,ypos
1580                        G2imG.UpdateMasks(self,Masks)
1581                    elif 'Line2D' in itemPicked and PickName == 'Masks':
1582                        Obj = self.itemPicked.findobj()
1583                        rings = Masks['Rings']
1584                        arcs = Masks['Arcs']
1585                        polygons = Masks['Polygons']
1586                        for ring in self.ringList:
1587                            if Obj == ring[0]:
1588                                rN = ring[1]
1589                                if ring[2] == 'o':
1590                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)-rings[rN][1]/2.
1591                                else:
1592                                    rings[rN][0] = G2img.GetTth(xpos,ypos,Data)+rings[rN][1]/2.
1593                        for arc in self.arcList:
1594                            if Obj == arc[0]:
1595                                aN = arc[1]
1596                                if arc[2] == 'o':
1597                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)-arcs[aN][2]/2
1598                                elif arc[2] == 'i':
1599                                    arcs[aN][0] = G2img.GetTth(xpos,ypos,Data)+arcs[aN][2]/2
1600                                elif arc[2] == 'l':
1601                                    arcs[aN][1][0] = int(G2img.GetAzm(xpos,ypos,Data))
1602                                else:
1603                                    arcs[aN][1][1] = int(G2img.GetAzm(xpos,ypos,Data))
1604                        for poly in self.polyList:
1605                            if Obj == poly[0]:
1606                                ind = self.itemPicked.contains(self.mousePicked)[1]['ind'][0]
1607                                oldPos = np.array([self.mousePicked.xdata,self.mousePicked.ydata])
1608                                pN = poly[1]
1609                                for i,xy in enumerate(polygons[pN]):
1610                                    if np.allclose(np.array([xy]),oldPos,atol=1.0):
1611                                        polygons[pN][i] = xpos,ypos
1612                        G2imG.UpdateMasks(self,Masks)
1613#                    else:                  #keep for future debugging
1614#                        print str(self.itemPicked),event.xdata,event.ydata,event.button
1615                PlotImage(self,newImage=True)
1616            self.itemPicked = None
1617           
1618    try:
1619        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1620        Page = self.G2plotNB.nb.GetPage(plotNum)
1621        if not newPlot:
1622            Plot = Page.figure.gca()          #get previous powder plot & get limits
1623            xylim = Plot.get_xlim(),Plot.get_ylim()
1624        if newImage:
1625            Page.figure.clf()
1626            Plot = Page.figure.gca()          #get a fresh plot after clf()
1627       
1628    except ValueError:
1629        Plot = self.G2plotNB.addMpl('2D Powder Image').gca()
1630        plotNum = self.G2plotNB.plotList.index('2D Powder Image')
1631        Page = self.G2plotNB.nb.GetPage(plotNum)
1632        Page.canvas.mpl_connect('key_press_event', OnImPlotKeyPress)
1633        Page.canvas.mpl_connect('motion_notify_event', OnImMotion)
1634        Page.canvas.mpl_connect('pick_event', OnImPick)
1635        Page.canvas.mpl_connect('button_release_event', OnImRelease)
1636        xylim = []
1637    if not event:                       #event from GUI TextCtrl - don't want focus to change to plot!!!
1638        Page.SetFocus()
1639    Title = self.PatternTree.GetItemText(self.Image)[4:]
1640    self.G2plotNB.status.DestroyChildren()
1641    if self.logPlot:
1642        Title = 'log('+Title+')'
1643    Plot.set_title(Title)
1644    try:
1645        if self.PatternTree.GetItemText(self.PickId) in ['Image Controls',]:
1646            if self.logPlot:
1647                Choice = (' key press','l: log(I) off')
1648            else:
1649                Choice = (' key press','l: log(I) on')
1650            cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
1651                choices=Choice)
1652            cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
1653            cb.SetValue(' key press')
1654    except TypeError:
1655        pass
1656    size,imagefile = self.PatternTree.GetItemPyData(self.Image)
1657    if imagefile != self.oldImagefile:
1658        imagefile = G2IO.CheckImageFile(self,imagefile)
1659        if not imagefile:
1660            self.G2plotNB.Delete('2D Powder Image')
1661            return
1662        self.PatternTree.SetItemPyData(self.Image,[size,imagefile])
1663        self.ImageZ = G2IO.GetImageData(self,imagefile,imageOnly=True)
1664#        print self.ImageZ.shape,self.ImageZ.size,Data['size'] #might be useful debugging line
1665        self.oldImagefile = imagefile
1666
1667    imScale = 1
1668    if len(self.ImageZ) > 1024:
1669        imScale = len(self.ImageZ)/1024
1670    sizexy = Data['size']
1671    pixelSize = Data['pixelSize']
1672    scalex = 1000./pixelSize[0]
1673    scaley = 1000./pixelSize[1]
1674    Xmax = sizexy[0]*pixelSize[0]/1000.
1675    Ymax = sizexy[1]*pixelSize[1]/1000.
1676    xlim = (0,Xmax)
1677    ylim = (Ymax,0)
1678    Imin,Imax = Data['range'][1]
1679    acolor = mpl.cm.get_cmap(Data['color'])
1680    xcent,ycent = Data['center']
1681    Plot.set_xlabel('Image x-axis, mm',fontsize=12)
1682    Plot.set_ylabel('Image y-axis, mm',fontsize=12)
1683    #do threshold mask - "real" mask - others are just bondaries
1684    Zlim = Masks['Thresholds'][1]
1685    wx.BeginBusyCursor()
1686    try:
1687           
1688        if newImage:                   
1689            MA = ma.masked_greater(ma.masked_less(self.ImageZ,Zlim[0]),Zlim[1])
1690            MaskA = ma.getmaskarray(MA)
1691            A = G2img.ImageCompress(MA,imScale)
1692            AM = G2img.ImageCompress(MaskA,imScale)
1693            if self.logPlot:
1694                A = np.log(A)
1695                AM = np.log(AM)
1696                Imin,Imax = [np.amin(A),np.amax(A)]
1697            ImgM = Plot.imshow(AM,aspect='equal',cmap='Reds',
1698                interpolation='nearest',vmin=0,vmax=2,extent=[0,Xmax,Xmax,0])
1699            Img = Plot.imshow(A,aspect='equal',cmap=acolor,
1700                interpolation='nearest',vmin=Imin,vmax=Imax,extent=[0,Xmax,Ymax,0])
1701            if self.setPoly:
1702                Img.set_picker(True)
1703   
1704        Plot.plot(xcent,ycent,'x')
1705        if Data['showLines']:
1706            LRAzim = Data['LRazimuth']                  #NB: integers
1707            Nazm = Data['outAzimuths']
1708            delAzm = float(LRAzim[1]-LRAzim[0])/Nazm
1709            AzmthOff = Data['azmthOff']
1710            IOtth = Data['IOtth']
1711            wave = Data['wavelength']
1712            dspI = wave/(2.0*sind(IOtth[0]/2.0))
1713            ellI = G2img.GetEllipse(dspI,Data)           #=False if dsp didn't yield an ellipse (ugh! a parabola or a hyperbola)
1714            dspO = wave/(2.0*sind(IOtth[1]/2.0))
1715            ellO = G2img.GetEllipse(dspO,Data)           #Ditto & more likely for outer ellipse
1716            Azm = np.array(range(LRAzim[0],LRAzim[1]+1))-AzmthOff
1717            if ellI:
1718                xyI = []
1719                for azm in Azm:
1720                    xyI.append(G2img.GetDetectorXY(dspI,azm-90.,Data))
1721                xyI = np.array(xyI)
1722                arcxI,arcyI = xyI.T
1723                Plot.plot(arcxI,arcyI,picker=3)
1724            if ellO:
1725                xyO = []
1726                for azm in Azm:
1727                    xyO.append(G2img.GetDetectorXY(dspO,azm-90.,Data))
1728                xyO = np.array(xyO)
1729                arcxO,arcyO = xyO.T
1730                Plot.plot(arcxO,arcyO,picker=3)
1731            if ellO and ellI:
1732                Plot.plot([arcxI[0],arcxO[0]],[arcyI[0],arcyO[0]],picker=3)
1733                Plot.plot([arcxI[-1],arcxO[-1]],[arcyI[-1],arcyO[-1]],picker=3)
1734            for i in range(Nazm):
1735                cake = LRAzim[0]+i*delAzm
1736                ind = np.searchsorted(Azm,cake)
1737                Plot.plot([arcxI[ind],arcxO[ind]],[arcyI[ind],arcyO[ind]],color='k',dashes=(5,5))
1738                   
1739        for xring,yring in Data['ring']:
1740            Plot.plot(xring,yring,'r+',picker=3)
1741        if Data['setRings']:
1742#            rings = np.concatenate((Data['rings']),axis=0)
1743            N = 0
1744            for ring in Data['rings']:
1745                xring,yring = np.array(ring).T[:2]
1746                Plot.plot(xring,yring,'+',color=colors[N%6])
1747                N += 1           
1748        for ellipse in Data['ellipses']:
1749            cent,phi,[width,height],col = ellipse
1750            Plot.add_artist(Ellipse([cent[0],cent[1]],2*width,2*height,phi,ec=col,fc='none'))
1751            Plot.text(cent[0],cent[1],'+',color=col,ha='center',va='center')
1752        #masks - mask lines numbered after integration limit lines
1753        spots = Masks['Points']
1754        rings = Masks['Rings']
1755        arcs = Masks['Arcs']
1756        polygons = Masks['Polygons']
1757        for x,y,d in spots:
1758            Plot.add_artist(Circle((x,y),radius=d/2,fc='none',ec='r',picker=3))
1759        self.ringList = []
1760        for iring,(tth,thick) in enumerate(rings):
1761            wave = Data['wavelength']
1762            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data))),2)
1763            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth-thick/2.,wave),Data))),2)
1764            self.ringList.append([Plot.plot(x1,y1,'r',picker=3),iring,'o'])           
1765            self.ringList.append([Plot.plot(x2,y2,'r',picker=3),iring,'i'])
1766        self.arcList = []
1767        for iarc,(tth,azm,thick) in enumerate(arcs):           
1768            wave = Data['wavelength']
1769            x1,y1 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(tth+thick/2.,wave),Data),azm)),2)
1770            x2,y2 = np.hsplit(np.array(G2img.makeIdealRing(G2img.GetEllipse(Dsp(max(0.01,tth-thick/2.),wave),Data),azm)),2)
1771            self.arcList.append([Plot.plot(x1,y1,'r',picker=3),iarc,'o'])           
1772            self.arcList.append([Plot.plot(x2,y2,'r',picker=3),iarc,'i'])
1773            self.arcList.append([Plot.plot([x1[0],x2[0]],[y1[0],y2[0]],'r',picker=3),iarc,'l'])
1774            self.arcList.append([Plot.plot([x1[-1],x2[-1]],[y1[-1],y2[-1]],'r',picker=3),iarc,'u'])
1775        self.polyList = []
1776        for ipoly,polygon in enumerate(polygons):
1777            x,y = np.hsplit(np.array(polygon),2)
1778            self.polyList.append([Plot.plot(x,y,'r+',picker=10),ipoly])
1779            Plot.plot(x,y,'r')           
1780        if newImage:
1781            colorBar = Page.figure.colorbar(Img)
1782        Plot.set_xlim(xlim)
1783        Plot.set_ylim(ylim)
1784        if not newPlot and xylim:
1785            Page.toolbar.push_current()
1786            Plot.set_xlim(xylim[0])
1787            Plot.set_ylim(xylim[1])
1788            xylim = []
1789            Page.toolbar.push_current()
1790            Page.toolbar.draw()
1791        else:
1792            Page.canvas.draw()
1793    finally:
1794        wx.EndBusyCursor()
1795       
1796def PlotIntegration(self,newPlot=False,event=None):
1797    '''Plot of 2D image after image integration with 2-theta and azimuth as coordinates
1798    '''
1799           
1800    def OnMotion(event):
1801        Page.canvas.SetToolTipString('')
1802        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1803        azm = event.ydata
1804        tth = event.xdata
1805        if azm and tth:
1806            self.G2plotNB.status.SetFields(\
1807                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1808                               
1809    try:
1810        plotNum = self.G2plotNB.plotList.index('2D Integration')
1811        Page = self.G2plotNB.nb.GetPage(plotNum)
1812        if not newPlot:
1813            Plot = Page.figure.gca()          #get previous plot & get limits
1814            xylim = Plot.get_xlim(),Plot.get_ylim()
1815        Page.figure.clf()
1816        Plot = Page.figure.gca()          #get a fresh plot after clf()
1817       
1818    except ValueError:
1819        Plot = self.G2plotNB.addMpl('2D Integration').gca()
1820        plotNum = self.G2plotNB.plotList.index('2D Integration')
1821        Page = self.G2plotNB.nb.GetPage(plotNum)
1822        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1823        Page.views = False
1824        view = False
1825    if not event:
1826        Page.SetFocus()
1827       
1828    Data = self.PatternTree.GetItemPyData(
1829        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1830    image = self.Integrate[0]
1831    xsc = self.Integrate[1]
1832    ysc = self.Integrate[2]
1833    Imin,Imax = Data['range'][1]
1834    acolor = mpl.cm.get_cmap(Data['color'])
1835    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1836    Plot.set_ylabel('azimuth',fontsize=12)
1837    Plot.set_xlabel('2-theta',fontsize=12)
1838    Img = Plot.imshow(image,cmap=acolor,vmin=Imin,vmax=Imax,interpolation='nearest', \
1839        extent=[ysc[0],ysc[-1],xsc[-1],xsc[0]],aspect='auto')
1840    colorBar = Page.figure.colorbar(Img)
1841    if Data['setRings'] and Data['rings']:
1842        rings = np.concatenate((Data['rings']),axis=0)
1843        for xring,yring,dsp in rings:
1844            x,y = G2img.GetTthAzm(xring,yring,Data)
1845            Plot.plot(x,y,'r+')
1846    if Data['ellipses']:           
1847        for ellipse in Data['ellipses']:
1848            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1849            x,y = np.hsplit(ring,2)
1850            tth,azm = G2img.GetTthAzm(x,y,Data)
1851            azm = np.where(azm < 0.,azm+360,azm)
1852            Plot.plot(tth,azm,'b,')
1853    if not newPlot:
1854        Page.toolbar.push_current()
1855        Plot.set_xlim(xylim[0])
1856        Plot.set_ylim(xylim[1])
1857        xylim = []
1858        Page.toolbar.push_current()
1859        Page.toolbar.draw()
1860    else:
1861        Page.canvas.draw()
1862               
1863def PlotTRImage(self,tax,tay,taz,newPlot=False):
1864    '''a test plot routine - not normally used
1865    ''' 
1866           
1867    def OnMotion(event):
1868        Page.canvas.SetToolTipString('')
1869        Page.canvas.SetCursor(wx.CROSS_CURSOR)
1870        azm = event.xdata
1871        tth = event.ydata
1872        if azm and tth:
1873            self.G2plotNB.status.SetFields(\
1874                ['','Detector 2-th =%9.3fdeg, azm = %7.2fdeg'%(tth,azm)])
1875                               
1876    try:
1877        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1878        Page = self.G2plotNB.nb.GetPage(plotNum)
1879        if not newPlot:
1880            Plot = Page.figure.gca()          #get previous plot & get limits
1881            xylim = Plot.get_xlim(),Plot.get_ylim()
1882        Page.figure.clf()
1883        Plot = Page.figure.gca()          #get a fresh plot after clf()
1884       
1885    except ValueError:
1886        Plot = self.G2plotNB.addMpl('2D Transformed Powder Image').gca()
1887        plotNum = self.G2plotNB.plotList.index('2D Transformed Powder Image')
1888        Page = self.G2plotNB.nb.GetPage(plotNum)
1889        Page.canvas.mpl_connect('motion_notify_event', OnMotion)
1890        Page.views = False
1891        view = False
1892    Page.SetFocus()
1893       
1894    Data = self.PatternTree.GetItemPyData(
1895        G2gd.GetPatternTreeItemId(self,self.Image, 'Image Controls'))
1896    Imin,Imax = Data['range'][1]
1897    step = (Imax-Imin)/5.
1898    V = np.arange(Imin,Imax,step)
1899    acolor = mpl.cm.get_cmap(Data['color'])
1900    Plot.set_title(self.PatternTree.GetItemText(self.Image)[4:])
1901    Plot.set_xlabel('azimuth',fontsize=12)
1902    Plot.set_ylabel('2-theta',fontsize=12)
1903    Plot.contour(tax,tay,taz,V,cmap=acolor)
1904    if Data['showLines']:
1905        IOtth = Data['IOtth']
1906        if Data['fullIntegrate']:
1907            LRAzim = [-180,180]
1908        else:
1909            LRAzim = Data['LRazimuth']                  #NB: integers
1910        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[0],IOtth[0]],picker=True)
1911        Plot.plot([LRAzim[0],LRAzim[1]],[IOtth[1],IOtth[1]],picker=True)
1912        if not Data['fullIntegrate']:
1913            Plot.plot([LRAzim[0],LRAzim[0]],[IOtth[0],IOtth[1]],picker=True)
1914            Plot.plot([LRAzim[1],LRAzim[1]],[IOtth[0],IOtth[1]],picker=True)
1915    if Data['setRings']:
1916        rings = np.concatenate((Data['rings']),axis=0)
1917        for xring,yring,dsp in rings:
1918            x,y = G2img.GetTthAzm(xring,yring,Data)
1919            Plot.plot(y,x,'r+')           
1920    if Data['ellipses']:           
1921        for ellipse in Data['ellipses']:
1922            ring = np.array(G2img.makeIdealRing(ellipse[:3])) #skip color
1923            x,y = np.hsplit(ring,2)
1924            tth,azm = G2img.GetTthAzm(x,y,Data)
1925            Plot.plot(azm,tth,'b,')
1926    if not newPlot:
1927        Page.toolbar.push_current()
1928        Plot.set_xlim(xylim[0])
1929        Plot.set_ylim(xylim[1])
1930        xylim = []
1931        Page.toolbar.push_current()
1932        Page.toolbar.draw()
1933    else:
1934        Page.canvas.draw()
1935       
1936def PlotStructure(self,data):
1937    '''Crystal structure plotting package. Can show structures as balls, sticks, lines,
1938    thermal motion ellipsoids and polyhedra
1939    '''
1940    generalData = data['General']
1941    cell = generalData['Cell'][1:7]
1942    Amat,Bmat = G2lat.cell2AB(cell)         #Amat - crystal to cartesian, Bmat - inverse
1943    A4mat = np.concatenate((np.concatenate((Amat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1944    B4mat = np.concatenate((np.concatenate((Bmat,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
1945    Mydir = generalData['Mydir']
1946    atomData = data['Atoms']
1947    drawingData = data['Drawing']
1948    drawAtoms = drawingData['Atoms']
1949    cx,ct,cs = drawingData['atomPtrs']
1950    Wt = [255,255,255]
1951    Rd = [255,0,0]
1952    Gr = [0,255,0]
1953    Bl = [0,0,255]
1954    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]])
1955    uEdges = np.array([
1956        [uBox[0],uBox[1]],[uBox[0],uBox[3]],[uBox[0],uBox[4]],[uBox[1],uBox[2]], 
1957        [uBox[2],uBox[3]],[uBox[1],uBox[5]],[uBox[2],uBox[6]],[uBox[3],uBox[7]], 
1958        [uBox[4],uBox[5]],[uBox[5],uBox[6]],[uBox[6],uBox[7]],[uBox[7],uBox[4]]])
1959    uColors = [Rd,Gr,Bl,Wt, Wt,Wt,Wt,Wt, Wt,Wt,Wt,Wt]
1960    altDown = False
1961    shiftDown = False
1962    ctrlDown = False
1963   
1964    def OnKeyBox(event):
1965        import Image
1966        Draw()                          #make sure plot is fresh!!
1967        mode = cb.GetValue()
1968        Fname = Mydir+'\\'+generalData['Name']+'.'+mode
1969        size = Page.canvas.GetSize()
1970        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
1971        if mode in ['jpeg',]:
1972            Pix = glReadPixels(0,0,size[0],size[1],GL_RGBA, GL_UNSIGNED_BYTE)
1973            im = Image.new("RGBA", (size[0],size[1]))
1974        else:
1975            Pix = glReadPixels(0,0,size[0],size[1],GL_RGB, GL_UNSIGNED_BYTE)
1976            im = Image.new("RGB", (size[0],size[1]))
1977        im.fromstring(Pix)
1978        im.save(Fname,mode)
1979        cb.SetValue(' Save as:')
1980        self.G2plotNB.status.SetStatusText('Drawing saved to: '+Fname,1)
1981   
1982    def GetTruePosition(xy):
1983        View = glGetIntegerv(GL_VIEWPORT)
1984        Proj = glGetDoublev(GL_PROJECTION_MATRIX)
1985        Model = glGetDoublev(GL_MODELVIEW_MATRIX)
1986        Zmax = 1.
1987        for i,atom in enumerate(drawAtoms):
1988            x,y,z = atom[cx:cx+3]
1989            X,Y,Z = gluProject(x,y,z,Model,Proj,View)
1990            XY = [int(X),int(View[3]-Y)]
1991            if np.allclose(xy,XY,atol=10) and Z < Zmax:
1992                Zmax = Z
1993                SetSelectedAtoms(i)
1994                   
1995    def OnMouseDown(event):
1996        xy = event.GetPosition()
1997        if event.ShiftDown():
1998            GetTruePosition(xy)
1999        else:
2000            drawingData['Rotation'][3] = xy
2001        Draw()
2002       
2003    def OnMouseMove(event):
2004        newxy = event.GetPosition()
2005        page = getSelection()
2006        if event.ControlDown() and drawingData['showABC']:
2007            if event.LeftIsDown():
2008                SetTestRot(newxy)
2009            elif event.RightIsDown():
2010                SetTestPos(newxy)
2011            elif event.MiddleIsDown():
2012                SetTestRotZ(newxy)
2013            x,y,z = drawingData['testPos'][0]
2014            self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
2015               
2016               
2017        if event.Dragging() and not event.ControlDown():
2018            if event.LeftIsDown():
2019                SetRotation(newxy)
2020                angX,angY,angZ = drawingData['Rotation'][:3]
2021                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f ,%.2f'%(angX,angY,angZ),1)
2022            elif event.RightIsDown():
2023                SetTranslation(newxy)
2024                Tx,Ty,Tz = drawingData['viewPoint'][0]
2025                self.G2plotNB.status.SetStatusText('New view point: %.4f, %.4f, %.4f'%(Tx,Ty,Tz),1)
2026            elif event.MiddleIsDown():
2027                SetRotationZ(newxy)
2028                angX,angY,angZ = drawingData['Rotation'][:3]
2029                self.G2plotNB.status.SetStatusText('New rotation: %.2f, %.2f, %.2f'%(angX,angY,angZ),1)
2030        Draw()
2031       
2032    def OnMouseWheel(event):
2033        drawingData['cameraPos'] += event.GetWheelRotation()/24
2034        drawingData['cameraPos'] = max(10,min(500,drawingData['cameraPos']))
2035        self.G2plotNB.status.SetStatusText('New camera distance: %.2f'%(drawingData['cameraPos']),1)
2036        page = getSelection()
2037        if page:
2038            if self.dataDisplay.GetPageText(page) == 'Draw Options':
2039                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
2040                names = [child.GetName() for child in panel]
2041                panel[names.index('cameraPos')].SetLabel('Camera Position: '+'%.2f'%(drawingData['cameraPos']))
2042                panel[names.index('cameraSlider')].SetValue(drawingData['cameraPos'])
2043        Draw()
2044       
2045    def getSelection():
2046        try:
2047            return self.dataDisplay.GetSelection()
2048        except AttributeError:
2049            print self.dataDisplay.GetLabel()
2050            self.G2plotNB.status.SetStatusText('Select this from Phase data window!')
2051            return 0
2052           
2053    def SetViewPointText(VP):
2054        page = getSelection()
2055        if page:
2056            if self.dataDisplay.GetPageText(page) == 'Draw Options':
2057                panel = self.dataDisplay.GetPage(page).GetChildren()[0].GetChildren()
2058                names = [child.GetName() for child in panel]
2059                panel[names.index('viewPoint')].SetValue('%.3f, %.3f, %.3f'%(VP[0],VP[1],VP[2]))
2060           
2061    def ClearSelectedAtoms():
2062        page = getSelection()
2063        if page:
2064            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2065                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Draw Atoms
2066            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2067                self.dataDisplay.GetPage(page).ClearSelection()      #this is the Atoms grid in Atoms
2068                   
2069    def SetSelectedAtoms(ind):
2070        page = getSelection()
2071        if page:
2072            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2073                self.dataDisplay.GetPage(page).SelectRow(ind)      #this is the Atoms grid in Draw Atoms
2074            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2075                Id = drawAtoms[ind][-2]
2076                for i,atom in enumerate(atomData):
2077                    if atom[-1] == Id:
2078                        self.dataDisplay.GetPage(page).SelectRow(i)      #this is the Atoms grid in Atoms
2079                 
2080    def GetSelectedAtoms():
2081        page = getSelection()
2082        Ind = []
2083        if page:
2084            if self.dataDisplay.GetPageText(page) == 'Draw Atoms':
2085                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Draw Atoms
2086            elif self.dataDisplay.GetPageText(page) == 'Atoms':
2087                Ind = self.dataDisplay.GetPage(page).GetSelectedRows()      #this is the Atoms grid in Atoms
2088        return Ind
2089                                       
2090    def OnKey(event):           #on key UP!!
2091        keyCode = event.GetKeyCode()
2092        if keyCode > 255:
2093            keyCode = 0
2094        key,xyz = chr(keyCode),event.GetPosition()
2095        indx = drawingData['selectedAtoms']
2096        if key in ['c','C']:
2097            drawingData['viewPoint'] = [[.5,.5,.5],[0,0]]
2098            drawingData['testPos'] = [[-.1,-.1,-.1],[0.0,0.0,0.0],[0,0]]
2099            drawingData['Rotation'] = [0.0,0.0,0.0,[]]
2100            SetViewPointText(drawingData['viewPoint'][0])
2101        elif key in ['n','N']:
2102            drawAtoms = drawingData['Atoms']
2103            pI = drawingData['viewPoint'][1]
2104            if indx:
2105                pI[0] = indx[pI[1]]
2106                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2107                pI[1] += 1
2108                if pI[1] >= len(indx):
2109                    pI[1] = 0
2110            else:
2111                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2112                pI[0] += 1
2113                if pI[0] >= len(drawAtoms):
2114                    pI[0] = 0
2115            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2116            SetViewPointText(drawingData['viewPoint'][0])
2117               
2118        elif key in ['p','P']:
2119            drawAtoms = drawingData['Atoms']
2120            pI = drawingData['viewPoint'][1]
2121            if indx:
2122                pI[0] = indx[pI[1]]
2123                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]
2124                pI[1] -= 1
2125                if pI[1] < 0:
2126                    pI[1] = len(indx)-1
2127            else:
2128                Tx,Ty,Tz = drawAtoms[pI[0]][cx:cx+3]               
2129                pI[0] -= 1
2130                if pI[0] < 0:
2131                    pI[0] = len(drawAtoms)-1
2132            drawingData['viewPoint'] = [[Tx,Ty,Tz],pI]
2133            SetViewPointText(drawingData['viewPoint'][0])           
2134        Draw()
2135           
2136    def SetBackground():
2137        R,G,B,A = Page.camera['backColor']
2138        glClearColor(R,G,B,A)
2139        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
2140       
2141    def SetLights():
2142        glEnable(GL_DEPTH_TEST)
2143        glShadeModel(GL_SMOOTH)
2144        glEnable(GL_LIGHTING)
2145        glEnable(GL_LIGHT0)
2146        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0)
2147        glLightfv(GL_LIGHT0,GL_AMBIENT,[1,1,1,.8])
2148        glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1])
2149       
2150    def SetTranslation(newxy):
2151        Tx,Ty,Tz = drawingData['viewPoint'][0]
2152        anglex,angley,anglez,oldxy = drawingData['Rotation']
2153        Rx = G2lat.rotdMat(anglex,0)
2154        Ry = G2lat.rotdMat(angley,1)
2155        Rz = G2lat.rotdMat(anglez,2)
2156        dxy = list(newxy-oldxy)+[0,]
2157        dxy = np.inner(Bmat,np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy))))
2158        Tx -= dxy[0]*0.01
2159        Ty += dxy[1]*0.01
2160        Tz -= dxy[2]*0.01
2161        drawingData['Rotation'][3] = newxy
2162        drawingData['viewPoint'][0] =  Tx,Ty,Tz
2163        SetViewPointText([Tx,Ty,Tz])
2164       
2165    def SetTestPos(newxy):
2166        Tx,Ty,Tz = drawingData['testPos'][0]
2167        anglex,angley,anglez,oldxy = drawingData['Rotation']
2168        Rx = G2lat.rotdMat(anglex,0)
2169        Ry = G2lat.rotdMat(angley,1)
2170        Rz = G2lat.rotdMat(anglez,2)
2171        dxy = list(newxy-oldxy)+[0,]
2172        dxy = np.inner(Rz,np.inner(Ry,np.inner(Rx,dxy)))
2173        Tx += dxy[0]*0.001
2174        Ty -= dxy[1]*0.001
2175        Tz += dxy[2]*0.001
2176        drawingData['Rotation'][3] = newxy
2177        drawingData['testPos'][0] =  Tx,Ty,Tz
2178       
2179    def SetTestRot(newxy):
2180        Txyz = np.array(drawingData['testPos'][0])
2181        oldxy = drawingData['testPos'][2]
2182        Ax,Ay,Az = drawingData['testPos'][1]
2183        Vxyz = np.array(drawingData['viewPoint'][0])
2184        Dxyz = np.inner(Amat,Txyz-Vxyz)
2185        dxy = list(newxy-oldxy)+[0,]
2186        Ax += dxy[1]*0.01
2187        Ay += dxy[0]*0.01
2188        Rx = G2lat.rotdMat(Ax,0)
2189        Ry = G2lat.rotdMat(Ay,1)
2190        Dxyz = np.inner(Ry,np.inner(Rx,Dxyz))       
2191        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
2192        drawingData['testPos'][1] = [Ax,Ay,Az]
2193        drawingData['testPos'][2] = newxy
2194        drawingData['testPos'][0] = Dxyz
2195       
2196    def SetTestRotZ(newxy):
2197        Txyz = np.array(drawingData['testPos'][0])
2198        oldxy = drawingData['testPos'][2]
2199        Ax,Ay,Az = drawingData['testPos'][1]
2200        Vxyz = np.array(drawingData['viewPoint'][0])
2201        Dxyz = np.inner(Amat,Txyz-Vxyz)       
2202        dxy = list(newxy-oldxy)+[0,]
2203        Az += (dxy[0]+dxy[1])*.01
2204        Rz = G2lat.rotdMat(Az,2)
2205        Dxyz = np.inner(Rz,Dxyz)       
2206        Dxyz = np.inner(Bmat,Dxyz)+Vxyz
2207        drawingData['testPos'][1] = [Ax,Ay,Az]
2208        drawingData['testPos'][2] = newxy
2209        drawingData['testPos'][0] = Dxyz
2210                             
2211    def SetRotation(newxy):       
2212        anglex,angley,anglez,oldxy = drawingData['Rotation']
2213        dxy = newxy-oldxy
2214        anglex += dxy[1]*.25
2215        angley += dxy[0]*.25
2216        oldxy = newxy
2217        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2218       
2219    def SetRotationZ(newxy):                       
2220        anglex,angley,anglez,oldxy = drawingData['Rotation']
2221        dxy = newxy-oldxy
2222        anglez += (dxy[0]+dxy[1])*.25
2223        oldxy = newxy
2224        drawingData['Rotation'] = [anglex,angley,anglez,oldxy]
2225       
2226    def RenderBox():
2227        glEnable(GL_COLOR_MATERIAL)
2228        glLineWidth(2)
2229        glEnable(GL_BLEND)
2230        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
2231        glEnable(GL_LINE_SMOOTH)
2232        glBegin(GL_LINES)
2233        for line,color in zip(uEdges,uColors):
2234            glColor3ubv(color)
2235            glVertex3fv(line[0])
2236            glVertex3fv(line[1])
2237        glEnd()
2238        glColor4ubv([0,0,0,0])
2239        glDisable(GL_LINE_SMOOTH)
2240        glDisable(GL_BLEND)
2241        glDisable(GL_COLOR_MATERIAL)
2242       
2243    def RenderUnitVectors(x,y,z):
2244        xyz = np.array([x,y,z])
2245        glEnable(GL_COLOR_MATERIAL)
2246        glLineWidth(1)
2247        glPushMatrix()
2248        glTranslate(x,y,z)
2249        glScalef(1/cell[0],1/cell[1],1/cell[2])
2250        glBegin(GL_LINES)
2251        for line,color in zip(uEdges,uColors)[:3]:
2252            glColor3ubv(color)
2253            glVertex3fv(line[0])
2254            glVertex3fv(line[1])
2255        glEnd()
2256        glPopMatrix()
2257        glColor4ubv([0,0,0,0])
2258        glDisable(GL_COLOR_MATERIAL)
2259               
2260    def RenderSphere(x,y,z,radius,color):
2261        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2262        glPushMatrix()
2263        glTranslate(x,y,z)
2264        glMultMatrixf(B4mat.T)
2265        q = gluNewQuadric()
2266        gluSphere(q,radius,20,10)
2267        glPopMatrix()
2268       
2269    def RenderEllipsoid(x,y,z,ellipseProb,E,R4,color):
2270        s1,s2,s3 = E
2271        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2272        glPushMatrix()
2273        glTranslate(x,y,z)
2274        glMultMatrixf(B4mat.T)
2275        glMultMatrixf(R4.T)
2276        glEnable(GL_NORMALIZE)
2277        glScale(s1,s2,s3)
2278        q = gluNewQuadric()
2279        gluSphere(q,ellipseProb,20,10)
2280        glDisable(GL_NORMALIZE)
2281        glPopMatrix()
2282       
2283    def RenderBonds(x,y,z,Bonds,radius,color,slice=20):
2284        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2285        glPushMatrix()
2286        glTranslate(x,y,z)
2287        glMultMatrixf(B4mat.T)
2288        for bond in Bonds:
2289            glPushMatrix()
2290            Dx = np.inner(Amat,bond)
2291            Z = np.sqrt(np.sum(Dx**2))
2292            azm = atan2d(-Dx[1],-Dx[0])
2293            phi = acosd(Dx[2]/Z)
2294            glRotate(-azm,0,0,1)
2295            glRotate(phi,1,0,0)
2296            q = gluNewQuadric()
2297            gluCylinder(q,radius,radius,Z,slice,2)
2298            glPopMatrix()           
2299        glPopMatrix()
2300               
2301    def RenderLines(x,y,z,Bonds,color):
2302        xyz = np.array([x,y,z])
2303        glEnable(GL_COLOR_MATERIAL)
2304        glLineWidth(1)
2305        glColor3fv(color)
2306        glPushMatrix()
2307        glBegin(GL_LINES)
2308        for bond in Bonds:
2309            glVertex3fv(xyz)
2310            glVertex3fv(xyz+bond)
2311        glEnd()
2312        glColor4ubv([0,0,0,0])
2313        glPopMatrix()
2314        glDisable(GL_COLOR_MATERIAL)
2315       
2316    def RenderPolyhedra(x,y,z,Faces,color):
2317        glPushMatrix()
2318        glTranslate(x,y,z)
2319        glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color)
2320        glShadeModel(GL_SMOOTH)
2321        glMultMatrixf(B4mat.T)
2322        for face,norm in Faces:
2323            glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
2324            glFrontFace(GL_CW)
2325            glNormal3fv(norm)
2326            glBegin(GL_TRIANGLES)
2327            for vert in face:
2328                glVertex3fv(vert)
2329            glEnd()
2330        glPopMatrix()
2331       
2332    def RenderBackbone(Backbone,BackboneColor,radius):
2333        glPushMatrix()
2334        glMultMatrixf(B4mat.T)
2335        glEnable(GL_COLOR_MATERIAL)
2336        glShadeModel(GL_SMOOTH)
2337        gleSetJoinStyle(TUBE_NORM_EDGE | TUBE_JN_ANGLE | TUBE_JN_CAP)
2338        glePolyCylinder(Backbone,BackboneColor,radius)
2339        glPopMatrix()       
2340        glDisable(GL_COLOR_MATERIAL)
2341       
2342    def RenderLabel(x,y,z,label,r):       
2343        glPushMatrix()
2344        glTranslate(x,y,z)
2345        glMultMatrixf(B4mat.T)
2346        glDisable(GL_LIGHTING)
2347        glColor3f(0,1.,0)
2348        glRasterPos3f(r,r,r)
2349        for c in list(label):
2350            glutBitmapCharacter(GLUT_BITMAP_8_BY_13,ord(c))
2351        glEnable(GL_LIGHTING)
2352        glPopMatrix()
2353                           
2354    def Draw():
2355        import numpy.linalg as nl
2356        Ind = GetSelectedAtoms()
2357        VS = np.array(Page.canvas.GetSize())
2358        aspect = float(VS[0])/float(VS[1])
2359        cPos = drawingData['cameraPos']
2360        Zclip = drawingData['Zclip']*cPos/200.
2361        anglex,angley,anglez = drawingData['Rotation'][:3]
2362        Tx,Ty,Tz = drawingData['viewPoint'][0]
2363        cx,ct,cs = drawingData['atomPtrs']
2364        bondR = drawingData['bondRadius']
2365        G,g = G2lat.cell2Gmat(cell)
2366        GS = G
2367        GS[0][1] = GS[1][0] = math.sqrt(GS[0][0]*GS[1][1])
2368        GS[0][2] = GS[2][0] = math.sqrt(GS[0][0]*GS[2][2])
2369        GS[1][2] = GS[2][1] = math.sqrt(GS[1][1]*GS[2][2])
2370        ellipseProb = G2lat.criticalEllipse(drawingData['ellipseProb']/100.)
2371       
2372        SetBackground()
2373        glInitNames()
2374        glPushName(0)
2375       
2376        glMatrixMode(GL_PROJECTION)
2377        glLoadIdentity()
2378        glViewport(0,0,VS[0],VS[1])
2379        gluPerspective(20.,aspect,cPos-Zclip,cPos+Zclip)
2380        gluLookAt(0,0,cPos,0,0,0,0,1,0)
2381        SetLights()           
2382           
2383        glMatrixMode(GL_MODELVIEW)
2384        glLoadIdentity()
2385        glRotate(anglez,0,0,1)
2386        glRotate(anglex,cosd(anglez),-sind(anglez),0)
2387        glRotate(angley,sind(anglez),cosd(anglez),0)
2388        glMultMatrixf(A4mat.T)
2389        glTranslate(-Tx,-Ty,-Tz)
2390        if drawingData['unitCellBox']:
2391            RenderBox()
2392        if drawingData['showABC']:
2393            x,y,z = drawingData['testPos'][0]
2394#            if altDown:
2395#                self.G2plotNB.status.SetStatusText('moving test point %.4f,%.4f,%.4f'%(x,y,z),1)
2396#            else:
2397#                self.G2plotNB.status.SetStatusText('test point %.4f,%.4f,%.4f'%(x,y,z),1)           
2398            RenderUnitVectors(x,y,z)
2399        Backbone = []
2400        BackboneColor = []
2401        time0 = time.time()
2402        for iat,atom in enumerate(drawingData['Atoms']):
2403            x,y,z = atom[cx:cx+3]
2404            Bonds = atom[-2]
2405            Faces = atom[-1]
2406            try:
2407                atNum = generalData['AtomTypes'].index(atom[ct])
2408            except ValueError:
2409                atNum = -1
2410            CL = atom[cs+2]
2411            color = np.array(CL)/255.
2412            if iat in Ind:
2413                color = np.array(Gr)/255.
2414            radius = 0.5
2415            if atom[cs] != '':
2416                glLoadName(atom[-3])                   
2417            if 'balls' in atom[cs]:
2418                vdwScale = drawingData['vdwScale']
2419                ballScale = drawingData['ballScale']
2420                if atNum < 0:
2421                    radius = 0.2
2422                elif 'H' == atom[ct]:
2423                    if drawingData['showHydrogen']:
2424                        if 'vdW' in atom[cs] and atNum >= 0:
2425                            radius = vdwScale*generalData['vdWRadii'][atNum]
2426                        else:
2427                            radius = ballScale*drawingData['sizeH']
2428                    else:
2429                        radius = 0.0
2430                else:
2431                    if 'vdW' in atom[cs]:
2432                        radius = vdwScale*generalData['vdWRadii'][atNum]
2433                    else:
2434                        radius = ballScale*generalData['BondRadii'][atNum]
2435                RenderSphere(x,y,z,radius,color)
2436                if 'sticks' in atom[cs]:
2437                    RenderBonds(x,y,z,Bonds,bondR,color)
2438            elif 'ellipsoids' in atom[cs]:
2439                RenderBonds(x,y,z,Bonds,bondR,color)
2440                if atom[cs+3] == 'A':                   
2441                    Uij = atom[cs+5:cs+11]
2442                    U = np.multiply(G2spc.Uij2U(Uij),GS)
2443                    U = np.inner(Amat,np.inner(U,Amat).T)
2444                    E,R = nl.eigh(U)
2445                    R4 = np.concatenate((np.concatenate((R,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
2446                    E = np.sqrt(E)
2447                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2448                        pass
2449                    else:
2450                        RenderEllipsoid(x,y,z,ellipseProb,E,R4,color)                   
2451                else:
2452                    if atom[ct] == 'H' and not drawingData['showHydrogen']:
2453                        pass
2454                    else:
2455                        radius = ellipseProb*math.sqrt(abs(atom[cs+4]))
2456                        RenderSphere(x,y,z,radius,color)
2457            elif 'lines' in atom[cs]:
2458                radius = 0.1
2459                RenderLines(x,y,z,Bonds,color)
2460#                RenderBonds(x,y,z,Bonds,0.05,color,6)
2461            elif atom[cs] == 'sticks':
2462                radius = 0.1
2463                RenderBonds(x,y,z,Bonds,bondR,color)
2464            elif atom[cs] == 'polyhedra':
2465                RenderPolyhedra(x,y,z,Faces,color)
2466            elif atom[cs] == 'backbone':
2467                if atom[ct-1].split()[0] in ['C','N']:
2468                    Backbone.append(list(np.inner(Amat,np.array([x,y,z]))))
2469                    BackboneColor.append(list(color))
2470                   
2471            if atom[cs+1] == 'type':
2472                RenderLabel(x,y,z,atom[ct],radius)
2473            elif atom[cs+1] == 'name':
2474                RenderLabel(x,y,z,atom[ct-1],radius)
2475            elif atom[cs+1] == 'number':
2476                RenderLabel(x,y,z,str(iat+1),radius)
2477            elif atom[cs+1] == 'residue' and atom[ct-1] == 'CA':
2478                RenderLabel(x,y,z,atom[ct-4],radius)
2479            elif atom[cs+1] == '1-letter' and atom[ct-1] == 'CA':
2480                RenderLabel(x,y,z,atom[ct-3],radius)
2481            elif atom[cs+1] == 'chain' and atom[ct-1] == 'CA':
2482                RenderLabel(x,y,z,atom[ct-2],radius)
2483        if Backbone:
2484            RenderBackbone(Backbone,BackboneColor,bondR)
2485#        print time.time()-time0
2486        Page.canvas.SwapBuffers()
2487       
2488    def OnSize(event):
2489        Draw()
2490       
2491    def OnFocus(event):
2492        Draw()
2493       
2494    try:
2495        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2496        Page = self.G2plotNB.nb.GetPage(plotNum)       
2497    except ValueError:
2498        Plot = self.G2plotNB.addOgl(generalData['Name'])
2499        plotNum = self.G2plotNB.plotList.index(generalData['Name'])
2500        Page = self.G2plotNB.nb.GetPage(plotNum)
2501        Page.views = False
2502        view = False
2503        altDown = False
2504    Page.SetFocus()
2505    cb = wx.ComboBox(self.G2plotNB.status,style=wx.CB_DROPDOWN|wx.CB_READONLY,
2506        choices=(' save as:','jpeg','tiff','bmp'))
2507    cb.Bind(wx.EVT_COMBOBOX, OnKeyBox)
2508    cb.SetValue(' save as:')
2509    Page.canvas.Bind(wx.EVT_MOUSEWHEEL, OnMouseWheel)
2510    Page.canvas.Bind(wx.EVT_LEFT_DOWN, OnMouseDown)
2511    Page.canvas.Bind(wx.EVT_RIGHT_DOWN, OnMouseDown)
2512    Page.canvas.Bind(wx.EVT_MIDDLE_DOWN, OnMouseDown)
2513    Page.canvas.Bind(wx.EVT_KEY_UP, OnKey)
2514    Page.canvas.Bind(wx.EVT_MOTION, OnMouseMove)
2515    Page.canvas.Bind(wx.EVT_SIZE, OnSize)
2516    Page.canvas.Bind(wx.EVT_SET_FOCUS, OnFocus)
2517    Page.camera['position'] = drawingData['cameraPos']
2518    Page.camera['viewPoint'] = np.inner(Amat,drawingData['viewPoint'][0])
2519    Page.camera['backColor'] = np.array(list(drawingData['backColor'])+[0,])/255.
2520    Page.canvas.SetCurrent()
2521    Draw()
2522       
Note: See TracBrowser for help on using the repository browser.