source: trunk/GSASIIplot.py @ 426

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

allow repositioning of reflection markers (up or down)

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