source: sasview/guitools/PlotPanel.py @ 83fe2cc

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 83fe2cc was 71c64d6, checked in by Gervaise Alina <gervyh@…>, 16 years ago

more changed on plotpanel

  • Property mode set to 100644
File size: 23.6 KB
Line 
1import wx.lib.newevent
2import matplotlib
3matplotlib.interactive(False)
4#Use the WxAgg back end. The Wx one takes too long to render
5matplotlib.use('WXAgg')
6from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
7from matplotlib.figure import Figure
8import os
9import fittings
10import transform
11from canvas import FigureCanvas
12from matplotlib.widgets import RectangleSelector
13from pylab import  gca, gcf
14from plottables import Theory1D
15#from plottables import Data1D
16#TODO: make the plottables interactive
17
18from plottables import Graph
19#(FuncFitEvent, EVT_FUNC_FIT) = wx.lib.newevent.NewEvent()
20import math,pylab
21def show_tree(obj,d=0):
22    """Handy function for displaying a tree of graph objects"""
23    print "%s%s" % ("-"*d,obj.__class__.__name__)
24    if 'get_children' in dir(obj):
25        for a in obj.get_children(): show_tree(a,d+1)
26def _rescale(lo,hi,step,pt=None,bal=None,scale='linear'):
27        """
28        Rescale (lo,hi) by step, returning the new (lo,hi)
29        The scaling is centered on pt, with positive values of step
30        driving lo/hi away from pt and negative values pulling them in.
31        If bal is given instead of point, it is already in [0,1] coordinates.
32   
33        This is a helper function for step-based zooming.
34        """
35        # Convert values into the correct scale for a linear transformation
36        # TODO: use proper scale transformers
37        loprev = lo
38        hiprev = hi
39        ptprev = pt
40        if scale=='log':
41            #assert lo >0
42            if lo > 0 :
43                lo = math.log10(lo)
44            if hi > 0 :
45                hi = math.log10(hi)
46            if pt is not None: pt = math.log10(pt)
47       
48        # Compute delta from axis range * %, or 1-% if persent is negative
49        if step > 0:
50            delta = float(hi-lo)*step/100
51        else:
52            delta = float(hi-lo)*step/(100-step)
53   
54        # Add scale factor proportionally to the lo and hi values, preserving the
55        # point under the mouse
56        if bal is None:
57            bal = float(pt-lo)/(hi-lo)
58        lo = lo - bal*delta
59        hi = hi + (1-bal)*delta
60   
61        # Convert transformed values back to the original scale
62        if scale=='log':
63            #if (lo <= -300) and (hi >= 300):
64            if (lo > 0) and (math.log(lo) <= -300):
65                lo=loprev
66                hi=hiprev
67                print "Not possible to scale"
68            if (lo == 0) or (lo <= -300):
69                lo=loprev
70                hi=hiprev
71                print "Not possible to scale"
72            else:
73                lo,hi = math.pow(10.,lo),math.pow(10.,hi)
74                #assert lo >0,"lo = %g"%lo
75                print "possible to scale"
76           
77        print "these are low and high",lo,hi
78
79        return (lo,hi)
80
81
82class PlotPanel(wx.Panel):
83    """
84    The PlotPanel has a Figure and a Canvas. OnSize events simply set a
85    flag, and the actually redrawing of the
86    figure is triggered by an Idle event.
87    """
88    def __init__(self, parent, id = -1, color = None,\
89        dpi = None, **kwargs):
90        wx.Panel.__init__(self, parent, id = id, **kwargs)
91        self.parent = parent
92        self.figure = Figure(None, dpi)
93        #self.figure = pylab.Figure(None, dpi)
94        #self.canvas = NoRepaintCanvas(self, -1, self.figure)
95        self.canvas = FigureCanvas(self, -1, self.figure)
96        self.SetColor(color)
97        #self.Bind(wx.EVT_IDLE, self._onIdle)
98        #self.Bind(wx.EVT_SIZE, self._onSize)
99        self._resizeflag = True
100        self._SetSize()
101        self.subplot = self.figure.add_subplot(111)
102        self.figure.subplots_adjust(left=.2, bottom=.2)
103        self.yscale = 'linear'
104        self.xscale = 'linear'
105        sizer = wx.BoxSizer(wx.VERTICAL)
106        sizer.Add(self.canvas,1,wx.EXPAND)
107        self.SetSizer(sizer)
108       
109        # Graph object to manage the plottables
110        self.graph = Graph()
111        #self.Bind(EVT_FUNC_FIT, self.onFitRange)
112        self.Bind(wx.EVT_CONTEXT_MENU, self.onContextMenu)
113        #self.Bind(EVT_PROPERTY, self._onEVT_FUNC_PROPERTY)
114        # Define some constants
115        self.colorlist = ['b','g','r','c','m','y']
116        self.symbollist = ['o','x','^','v','<','>','+','s','d','D','h','H','p']
117        #User scale
118        self.xLabel ="x"
119        self.yLabel ="log10(y)"
120        self.viewModel ="--"
121        # keep track if the previous transformation of x and y in Property dialog
122        self.prevXtrans =" "
123        self.prevYtrans =" "
124        self.canvas.mpl_connect('scroll_event',self.onWheel)
125        self.axes = [self.subplot]
126         # new data for the fit
127        self.fit_result = Theory1D(x=[], y=[], dy=None)
128        #self.fit_result = Data1D(x=[], y=[],dx=None, dy=None)
129        self.fit_result.name = "Fit"
130        # For fit Dialog initial display
131        self.xmin=0.0
132        self.xmax=0.0
133        self.xminView=0.0
134        self.xmaxView=0.0
135        self.Avalue=None
136        self.Bvalue=None
137        self.ErrAvalue=None
138        self.ErrBvalue=None
139        self.Chivalue=None
140    def resetFitView(self):
141        """
142             For fit Dialog initial display
143        """
144        self.xmin=0.0
145        self.xmax=0.0
146        self.xminView=0.0
147        self.xmaxView=0.0
148        self.Avalue=None
149        self.Bvalue=None
150        self.ErrAvalue=None
151        self.ErrBvalue=None
152        self.Chivalue=None
153    def onWheel(self, event):
154        """
155        Process mouse wheel as zoom events
156        """
157        ax = event.inaxes
158        step = event.step
159
160        if ax != None:
161            # Event occurred inside a plotting area
162            lo,hi = ax.get_xlim()
163            lo,hi = _rescale(lo,hi,step,pt=event.xdata)
164            ax.set_xlim((lo,hi))
165
166            lo,hi = ax.get_ylim()
167            lo,hi = _rescale(lo,hi,step,pt=event.ydata)
168            ax.set_ylim((lo,hi))
169        else:
170             # Check if zoom happens in the axes
171            xdata,ydata = None,None
172            x,y = event.x,event.y
173           
174            for ax in self.axes:
175                insidex,_ = ax.xaxis.contains(event)
176                if insidex:
177                    xdata,_ = ax.transAxes.inverse_xy_tup((x,y))
178                    print "xaxis",x,"->",xdata
179                insidey,_ = ax.yaxis.contains(event)
180                if insidey:
181                    _,ydata = ax.transAxes.inverse_xy_tup((x,y))
182                    print "yaxis",y,"->",ydata
183            if xdata is not None:
184                lo,hi = ax.get_xlim()
185                lo,hi = _rescale(lo,hi,step,bal=xdata,scale=ax.get_xscale())
186                ax.set_xlim((lo,hi))
187            if ydata is not None:
188                lo,hi = ax.get_ylim()
189                lo,hi = _rescale(lo,hi,step,bal=ydata,scale=ax.get_yscale())
190                ax.set_ylim((lo,hi))
191               
192        self.canvas.draw_idle()
193
194
195    def returnTrans(self):
196        """
197            Return values and labels used by Fit Dialog
198        """
199        return self.xLabel,self.yLabel, self.Avalue, self.Bvalue,\
200                self.ErrAvalue,self.ErrBvalue,self.Chivalue
201   
202    def setTrans(self,xtrans,ytrans): 
203        """
204            @param xtrans: set x transformation on Property dialog
205            @param ytrans: set y transformation on Property dialog
206        """
207        self.prevXtrans =xtrans
208        self.prevYtrans =ytrans
209   
210    def onFitting(self, event): 
211        """
212            when clicking on linear Fit on context menu , display Fitting Dialog
213        """
214        list =[]
215        list = self.graph.returnPlottable()
216        from fitDialog import LinearFit
217       
218        if len(list.keys())>0:
219            first_item = list.keys()[0]
220            dlg = LinearFit( None, first_item, self.onFitDisplay,self.returnTrans, -1, 'Fitting')
221           
222            if (self.xmin !=0.0 )and ( self.xmax !=0.0)\
223                and(self.xminView !=0.0 )and ( self.xmaxView !=0.0):
224                dlg.setFitRange(self.xminView,self.xmaxView,self.xmin,self.xmax)
225            dlg.ShowModal() 
226
227    def _onProperties(self, event):
228        """
229            when clicking on Properties on context menu ,The Property dialog is displayed
230            The user selects a transformation for x or y value and a new plot is displayed
231        """
232        list =[]
233        list = self.graph.returnPlottable()
234        if len(list.keys())>0:
235            first_item = list.keys()[0]
236            if first_item.x !=[]:
237                from PropertyDialog import Properties
238                dial = Properties(self, -1, 'Properties')
239                dial.setValues( self.prevXtrans, self.prevYtrans,self.viewModel )
240                if dial.ShowModal() == wx.ID_OK:
241                    self.xLabel, self.yLabel,self.viewModel = dial.getValues()
242                    if self.viewModel =="Guinier lny vs x^(2)":
243                        self.xLabel="x^(2)"
244                        self.yLabel="ln(y)"
245                        self.viewModel = "--"
246                        dial.setValues( self.xLabel, self.yLabel,self.viewModel )
247                    self._onEVT_FUNC_PROPERTY()
248                dial.Destroy()
249           
250 
251    def set_yscale(self, scale='linear'):
252        """
253            Set the scale on Y-axis
254            @param scale: the scale of y-axis
255        """
256        self.subplot.set_yscale(scale)
257        self.yscale = scale
258       
259    def get_yscale(self):
260        """
261             @return: Y-axis scale
262        """
263        return self.yscale
264   
265    def set_xscale(self, scale='linear'):
266        """
267            Set the scale on x-axis
268            @param scale: the scale of x-axis
269        """
270        self.subplot.set_xscale(scale)
271        self.xscale = scale
272       
273    def get_xscale(self):
274        """
275             @return: x-axis scale
276        """
277        return self.xscale
278
279    def SetColor(self, rgbtuple):
280        """Set figure and canvas colours to be the same"""
281        if not rgbtuple:
282            rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
283        col = [c/255.0 for c in rgbtuple]
284        self.figure.set_facecolor(col)
285        self.figure.set_edgecolor(col)
286        self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
287
288    def _onSize(self, event):
289        self._resizeflag = True
290
291    def _onIdle(self, evt):
292        if self._resizeflag:
293            self._resizeflag = False
294            self._SetSize()
295            self.draw()
296
297    def _SetSize(self, pixels = None):
298        """
299        This method can be called to force the Plot to be a desired size, which defaults to
300        the ClientSize of the panel
301        """
302        if not pixels:
303            pixels = self.GetClientSize()
304        self.canvas.SetSize(pixels)
305        self.figure.set_size_inches(pixels[0]/self.figure.get_dpi(),
306        pixels[1]/self.figure.get_dpi())
307
308    def draw(self):
309        """Where the actual drawing happens"""
310        self.figure.canvas.draw_idle()
311       
312
313 
314 
315       
316    def onSaveImage(self, evt):
317        #figure.savefig
318        #print "Save image not implemented"
319        path = None
320        dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.png", wx.SAVE)
321        if dlg.ShowModal() == wx.ID_OK:
322            path = dlg.GetPath()
323            mypath = os.path.basename(path)
324            print path
325        dlg.Destroy()
326        if not path == None:
327            self.subplot.figure.savefig(path,dpi=300, facecolor='w', edgecolor='w',
328                                        orentation='portrait', papertype=None, format='png')
329       
330    def onContextMenu(self, event):
331        """
332            Default context menu for a plot panel
333        """
334        # Slicer plot popup menu
335        slicerpop = wx.Menu()
336        slicerpop.Append(313,'&Save image', 'Save image as PNG')
337        wx.EVT_MENU(self, 313, self.onSaveImage)
338       
339        slicerpop.Append(316, '&Load 1D data file')
340        wx.EVT_MENU(self, 316, self._onLoad1DData)
341       
342        slicerpop.AppendSeparator()
343        slicerpop.Append(315, '&Properties')
344        wx.EVT_MENU(self, 315, self._onProperties)
345       
346        slicerpop.AppendSeparator()
347        slicerpop.Append(317, '&Linear Fit')
348        wx.EVT_MENU(self, 317, self.onFitting)
349       
350        slicerpop.AppendSeparator()
351        slicerpop.Append(318, '&Reset Graph')
352        wx.EVT_MENU(self, 318, self.onResetGraph)
353       
354        pos = event.GetPosition()
355        pos = self.ScreenToClient(pos)
356        self.PopupMenu(slicerpop, pos)
357   
358    ## The following is plottable functionality
359
360
361    def properties(self,prop):
362        """Set some properties of the graph.
363       
364        The set of properties is not yet determined.
365        """
366        # The particulars of how they are stored and manipulated (e.g., do
367        # we want an inventory internally) is not settled.  I've used a
368        # property dictionary for now.
369        #
370        # How these properties interact with a user defined style file is
371        # even less clear.
372
373        # Properties defined by plot
374        self.subplot.set_xlabel(r"$%s$" % prop["xlabel"])
375        self.subplot.set_ylabel(r"$%s$" % prop["ylabel"])
376        self.subplot.set_title(prop["title"])
377
378        # Properties defined by user
379        #self.axes.grid(True)
380
381    def clear(self):
382        """Reset the plot"""
383       
384        # TODO: Redraw is brutal.  Render to a backing store and swap in
385        # TODO: rather than redrawing on the fly.
386        self.subplot.clear()
387        self.subplot.hold(True)
388   
389    def render(self):
390        """Commit the plot after all objects are drawn"""
391        # TODO: this is when the backing store should be swapped in.
392        from matplotlib.font_manager import FontProperties
393        self.subplot.legend(prop=FontProperties(size=10))
394        #self.subplot.legend()
395        pass
396
397    def xaxis(self,label,units):
398        """xaxis label and units.
399       
400        Axis labels know about units.
401       
402        We need to do this so that we can detect when axes are not
403        commesurate.  Currently this is ignored other than for formatting
404        purposes.
405        """
406        if units != "": label = label + " (" + units + ")"
407        self.subplot.set_xlabel(label)
408        pass
409   
410    def yaxis(self,label,units):
411        """yaxis label and units."""
412        if units != "": label = label + " (" + units + ")"
413        self.subplot.set_ylabel(label)
414        pass
415
416    def _connect_to_xlim(self,callback):
417        """Bind the xlim change notification to the callback"""
418        def process_xlim(axes):
419            lo,hi = subplot.get_xlim()
420            callback(lo,hi)
421        self.subplot.callbacks.connect('xlim_changed',process_xlim)
422   
423    #def connect(self,trigger,callback):
424    #    print "PlotPanel.connect???"
425    #    if trigger == 'xlim': self._connect_to_xlim(callback)
426
427    def points(self,x,y,dx=None,dy=None,color=0,symbol=0,label=None):
428        """Draw markers with error bars"""
429        self.subplot.set_yscale('linear')
430        self.subplot.set_xscale('linear')
431        # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
432        if dx != None and type(dx) == type(()):
433            dx = nx.vstack((x-dx[0],dx[1]-x)).transpose()
434        if dy != None and type(dy) == type(()):
435            dy = nx.vstack((y-dy[0],dy[1]-y)).transpose()
436
437        if dx==None and dy==None:
438            h = self.subplot.plot(x,y,color=self._color(color),
439                                   marker=self._symbol(symbol),linestyle='',label=label)
440        else:
441            self.subplot.errorbar(x, y, yerr=dy, xerr=None,
442             ecolor=self._color(color), capsize=2,linestyle='', barsabove=False,
443             marker=self._symbol(symbol),
444             lolims=False, uplims=False,
445             xlolims=False, xuplims=False,label=label)
446           
447        self.subplot.set_yscale(self.yscale)
448        self.subplot.set_xscale(self.xscale)
449
450    def curve(self,x,y,dy=None,color=0,symbol=0,label=None):
451        """Draw a line on a graph, possibly with confidence intervals."""
452        c = self._color(color)
453        self.subplot.set_yscale('linear')
454        self.subplot.set_xscale('linear')
455       
456        hlist = self.subplot.plot(x,y,color=c,marker='',linestyle='-',label=label)
457       
458        self.subplot.set_yscale(self.yscale)
459        self.subplot.set_xscale(self.xscale)
460
461    def _color(self,c):
462        """Return a particular colour"""
463        return self.colorlist[c%len(self.colorlist)]
464
465    def _symbol(self,s):
466        """Return a particular symbol"""
467        return self.symbollist[s%len(self.symbollist)]
468   
469    def _onEVT_FUNC_PROPERTY(self):
470        """
471             Receive the x and y transformation from myDialog,Transforms x and y in View
472              and set the scale   
473        """ 
474        list =[]
475        list = self.graph.returnPlottable()
476        self.fit_result.x =[] 
477        self.fit_result.y =[] 
478        self.fit_result.dx=None
479        self.fit_result.dy=None
480       
481        for item in list:
482            item.setLabel(self.xLabel,self.yLabel)
483            if ( self.xLabel=="x" ):
484                item.transformX(transform.toX,transform.errToX)
485                self.set_xscale("linear")
486                name, units = item.get_xaxis()
487                self.graph.xaxis("%s" % name,  "%s^{-1}" % units)
488               
489            if ( self.xLabel=="x^(2)" ):
490                item.transformX(transform.toX2,transform.errToX2)
491                self.set_xscale('linear')
492                name, units = item.get_xaxis()
493                self.graph.xaxis("%s^{2}" % name,  "%s^{-2}" % units)
494               
495            if (self.xLabel=="log10(x)" ):
496                item.transformX(transform.toX,transform.errToX)
497                self.set_xscale("log")
498                name, units = item.get_xaxis() 
499                self.graph.xaxis("\log_{10}\ \  %s" % name,  "%s^{-1}" % units)
500               
501            if ( self.yLabel=="ln(y)" ):
502                item.transformY(transform.toLogX,transform.errToLogX)
503                self.set_yscale("linear")
504                name, units = item.get_yaxis()
505                self.graph.yaxis("log\ \ %s" % name,  "%s^{-1}" % units)
506               
507            if ( self.yLabel=="y" ):
508                item.transformY(transform.toX,transform.errToX)
509                self.set_yscale("linear")
510                name, units = item.get_yaxis()
511                self.graph.yaxis("%s" % name,  "%s^{-1}" % units)
512               
513            if ( self.yLabel=="log10(y)" ): 
514                item.transformY(transform.toX,transform.errToX)
515                self.set_yscale("log") 
516                name, units = item.get_yaxis()
517                self.graph.yaxis("\log_{10}\ \ %s" % name,  "%s^{-1}" % units)
518               
519            if ( self.yLabel=="y^(2)" ):
520                item.transformY( transform.toX2,transform.errToX2 )   
521                self.set_yscale("linear")
522                name, units = item.get_yaxis()
523                self.graph.yaxis("%s^{2}" % name,  "%s^{-2}" % units)
524               
525            if ( self.yLabel =="1/y"):
526                item.transformY(transform.toOneOverX,transform.errOneOverX )
527                self.set_yscale("linear")
528                name, units = item.get_yaxis()
529                self.graph.yaxis("%s" % name,  "\ \%s" % units)
530               
531            if ( self.yLabel =="1/sqrt(y)" ):
532                item.transformY(transform.toOneOverSqrtX,transform.errOneOverSqrtX )
533                self.set_yscale("linear")
534                name, units = item.get_yaxis()
535                self.graph.yaxis("\sqrt{%s}" %name,  "%s" % units)
536               
537            if ( self.yLabel =="ln(y*x)"):
538                item.transformY( transform.toLogXY,transform.errToLogXY)
539                self.set_yscale("linear")
540                yname, yunits = item.get_yaxis()
541                xname, xunits = item.get_xaxis()
542                self.graph.yaxis("log\ %s %s" % (yname,xname),  "%s^{-1}%s^{-1}" % (yunits,xunits))
543               
544            if ( self.yLabel =="ln(y*x^(2))"):
545                item.transformY( transform.toLogYX2,transform.errToLogYX2)
546                self.set_yscale("linear")
547                yname, yunits = item.get_yaxis()
548                xname, xunits = item.get_xaxis() 
549                self.graph.yaxis("Log %s%s^{2}" % (yname,xname),  "%s^{-1}%s^{-2}" % (yunits,xunits))
550           
551            if ( self.yLabel =="ln(y*x^(4))"):
552                item.transformY(transform.toLogYX4,transform.errToLogYX4)
553                self.set_yscale("linear")
554                yname, yunits = item.get_yaxis()
555                xname, xunits = item.get_xaxis()
556                self.graph.yaxis("Log %s%s^{4}" % (yname,xname),  "%s^{-1}%s^{-4}" % (yunits,xunits))
557           
558            if ( self.viewModel == "Guinier lny vs x^(2)"):
559               
560                item.transformX(transform.toX2,transform.errToX2)
561                self.set_xscale('linear')
562                name, units = item.get_xaxis()
563                self.graph.xaxis("%s^{2}" % name,  "%s^{-2}" % units)
564               
565                item.transformY(transform.toLogX,transform.errToLogX )
566                self.set_yscale("linear")
567                name, units = item.get_yaxis()
568                self.graph.yaxis("$Log %s$" % name,  "%s^{-1}" % units)
569               
570            item.transformView()
571           
572        #item.name = self.yLabel+" vs " +self.xLabel 
573        self.resetFitView()   
574        self.prevXtrans = self.xLabel
575        self.prevYtrans = self.yLabel 
576        self.graph.render(self)
577        self.subplot.figure.canvas.draw_idle()
578       
579    def onFitDisplay(self, tempx,tempy,xminView,xmaxView,xmin,xmax,func):
580        """
581            Add a new plottable into the graph .In this case this plottable will be used
582            to fit some data
583            @param tempx: The x data of fit line
584            @param tempy: The y data of fit line
585            @param xminView: the lower bound of fitting range
586            @param xminView: the upper bound of  fitting range
587            @param xmin: the lowest value of data to fit to the line
588            @param xmax: the highest value of data to fit to the line
589        """
590        # Saving value to redisplay in Fit Dialog when it is opened again
591        self.Avalue,self.Bvalue,self.ErrAvalue,self.ErrBvalue,self.Chivalue=func
592        self.xminView=xminView
593        self.xmaxView=xmaxView
594        self.xmin= xmin
595        self.xmax= xmax
596        #In case need to change the range of data plotted
597        list =[]
598        list = self.graph.returnPlottable()
599        for item in list:
600            #item.onFitRange(xminView,xmaxView)
601            item.onFitRange(None,None)
602       
603        # Create new data plottable with result
604        self.fit_result.x =[] 
605        self.fit_result.y =[]
606        self.fit_result.x =tempx 
607        self.fit_result.y =tempy     
608        self.fit_result.dx=None
609        self.fit_result.dy=None
610        #Load the view with the new values
611        self.fit_result.reset_view()
612        # Add the new plottable to the graph
613        self.graph.add(self.fit_result) 
614        self.graph.render(self)
615        self.subplot.figure.canvas.draw_idle()
616       
617   
618    def onResetGraph(self,event):
619        """
620            Reset the graph by plotting the full range of data
621        """
622        list =[]
623        list = self.graph.returnPlottable()
624        for item in list:
625            item.onReset()
626        self.graph.render(self)
627        self.subplot.figure.canvas.draw_idle()
628       
629class NoRepaintCanvas(FigureCanvasWxAgg):
630    """We subclass FigureCanvasWxAgg, overriding the _onPaint method, so that
631    the draw method is only called for the first two paint events. After that,
632    the canvas will only be redrawn when it is resized.
633    """
634    def __init__(self, *args, **kwargs):
635        FigureCanvasWxAgg.__init__(self, *args, **kwargs)
636        self._drawn = 0
637
638    def _onPaint(self, evt):
639        """
640        Called when wxPaintEvt is generated
641        """
642        if not self._isRealized:
643            self.realize()
644        if self._drawn < 2:
645            self.draw(repaint = False)
646            self._drawn += 1
647        self.gui_repaint(drawDC=wx.PaintDC(self))
648           
Note: See TracBrowser for help on using the repository browser.