source: sasview/guitools/PlotPanel.py @ b43a009

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 b43a009 was b43a009, checked in by Gervaise Alina <gervyh@…>, 16 years ago

some modificatiosn made

  • Property mode set to 100644
File size: 23.0 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        # For fit Dialog initial display
142        self.xmin=0.0
143        self.xmax=0.0
144        self.xminView=0.0
145        self.xmaxView=0.0
146        self.Avalue=None
147        self.Bvalue=None
148        self.ErrAvalue=None
149        self.ErrBvalue=None
150        self.Chivalue=None
151    def onWheel(self, event):
152        """
153        Process mouse wheel as zoom events
154        """
155        ax = event.inaxes
156        step = event.step
157
158        if ax != None:
159            # Event occurred inside a plotting area
160            lo,hi = ax.get_xlim()
161            lo,hi = _rescale(lo,hi,step,pt=event.xdata)
162            ax.set_xlim((lo,hi))
163
164            lo,hi = ax.get_ylim()
165            lo,hi = _rescale(lo,hi,step,pt=event.ydata)
166            ax.set_ylim((lo,hi))
167        else:
168             # Check if zoom happens in the axes
169            xdata,ydata = None,None
170            x,y = event.x,event.y
171           
172            for ax in self.axes:
173                insidex,_ = ax.xaxis.contains(event)
174                if insidex:
175                    xdata,_ = ax.transAxes.inverse_xy_tup((x,y))
176                    print "xaxis",x,"->",xdata
177                insidey,_ = ax.yaxis.contains(event)
178                if insidey:
179                    _,ydata = ax.transAxes.inverse_xy_tup((x,y))
180                    print "yaxis",y,"->",ydata
181            if xdata is not None:
182                lo,hi = ax.get_xlim()
183                lo,hi = _rescale(lo,hi,step,bal=xdata,scale=ax.get_xscale())
184                ax.set_xlim((lo,hi))
185            if ydata is not None:
186                lo,hi = ax.get_ylim()
187                lo,hi = _rescale(lo,hi,step,bal=ydata,scale=ax.get_yscale())
188                ax.set_ylim((lo,hi))
189               
190        self.canvas.draw_idle()
191
192
193    def returnTrans(self):
194        return self.xLabel,self.yLabel, self.Avalue, self.Bvalue,\
195        self.ErrAvalue,self.ErrBvalue,self.Chivalue
196   
197    def setTrans(self,xtrans,ytrans): 
198        """
199            @param xtrans: set x transformation on Property dialog
200            @param ytrans: set y transformation on Property dialog
201        """
202        self.prevXtrans =xtrans
203        self.prevYtrans =ytrans
204   
205    def onFitting(self, event): 
206        """
207            when clicking on linear Fit on context menu , display Fitting Dialog
208        """
209        list =[]
210        list = self.graph.returnPlottable()
211        from fitDialog import LinearFit
212       
213        if len(list.keys())>0:
214            first_item = list.keys()[0]
215            dlg = LinearFit( None, first_item, self.onFitDisplay,self.returnTrans, -1, 'Fitting')
216           
217            if (self.xmin !=0.0 )and ( self.xmax !=0.0)\
218                and(self.xminView !=0.0 )and ( self.xmaxView !=0.0):
219                dlg.setFitRange(self.xminView,self.xmaxView,self.xmin,self.xmax)
220            dlg.ShowModal() 
221
222    def _onProperties(self, event):
223        """
224            when clicking on Properties on context menu ,The Property dialog is displayed
225            The user selects a transformation for x or y value and a new plot is displayed
226        """
227        list =[]
228        list = self.graph.returnPlottable()
229        if len(list.keys())>0:
230            first_item = list.keys()[0]
231            if first_item.x !=[]:
232                from PropertyDialog import Properties
233                dial = Properties(self, -1, 'Properties')
234                dial.setValues( self.prevXtrans, self.prevYtrans,self.viewModel )
235                if dial.ShowModal() == wx.ID_OK:
236                    self.xLabel, self.yLabel,self.viewModel = dial.getValues()
237                    if self.viewModel =="Guinier lny vs x^(2)":
238                        self.xLabel="x^(2)"
239                        self.yLabel="ln(y)"
240                        self.viewModel = "--"
241                        dial.setValues( self.xLabel, self.yLabel,self.viewModel )
242                    self._onEVT_FUNC_PROPERTY()
243                dial.Destroy()
244           
245 
246    def set_yscale(self, scale='linear'):
247        """
248            Set the scale on Y-axis
249            @param scale: the scale of y-axis
250        """
251        self.subplot.set_yscale(scale)
252        self.yscale = scale
253       
254    def get_yscale(self):
255        """
256             @return: Y-axis scale
257        """
258        return self.yscale
259   
260    def set_xscale(self, scale='linear'):
261        """
262            Set the scale on x-axis
263            @param scale: the scale of x-axis
264        """
265        self.subplot.set_xscale(scale)
266        self.xscale = scale
267       
268    def get_xscale(self):
269        """
270             @return: x-axis scale
271        """
272        return self.xscale
273
274    def SetColor(self, rgbtuple):
275        """Set figure and canvas colours to be the same"""
276        if not rgbtuple:
277            rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
278        col = [c/255.0 for c in rgbtuple]
279        self.figure.set_facecolor(col)
280        self.figure.set_edgecolor(col)
281        self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
282
283    def _onSize(self, event):
284        self._resizeflag = True
285
286    def _onIdle(self, evt):
287        if self._resizeflag:
288            self._resizeflag = False
289            self._SetSize()
290            self.draw()
291
292    def _SetSize(self, pixels = None):
293        """
294        This method can be called to force the Plot to be a desired size, which defaults to
295        the ClientSize of the panel
296        """
297        if not pixels:
298            pixels = self.GetClientSize()
299        self.canvas.SetSize(pixels)
300        self.figure.set_size_inches(pixels[0]/self.figure.get_dpi(),
301        pixels[1]/self.figure.get_dpi())
302
303    def draw(self):
304        """Where the actual drawing happens"""
305        self.figure.canvas.draw_idle()
306       
307
308 
309 
310       
311    def onSaveImage(self, evt):
312        #figure.savefig
313        #print "Save image not implemented"
314        path = None
315        dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.png", wx.SAVE)
316        if dlg.ShowModal() == wx.ID_OK:
317            path = dlg.GetPath()
318            mypath = os.path.basename(path)
319            print path
320        dlg.Destroy()
321        if not path == None:
322            self.subplot.figure.savefig(path,dpi=300, facecolor='w', edgecolor='w',
323                                        orentation='portrait', papertype=None, format='png')
324       
325    def onContextMenu(self, event):
326        """
327            Default context menu for a plot panel
328        """
329        # Slicer plot popup menu
330        slicerpop = wx.Menu()
331        slicerpop.Append(313,'&Save image', 'Save image as PNG')
332        wx.EVT_MENU(self, 313, self.onSaveImage)
333       
334        slicerpop.Append(316, '&Load 1D data file')
335        wx.EVT_MENU(self, 316, self._onLoad1DData)
336       
337        slicerpop.AppendSeparator()
338        slicerpop.Append(315, '&Properties')
339        wx.EVT_MENU(self, 315, self._onProperties)
340       
341        slicerpop.AppendSeparator()
342        slicerpop.Append(317, '&Linear Fit')
343        wx.EVT_MENU(self, 317, self.onFitting)
344       
345        slicerpop.AppendSeparator()
346        slicerpop.Append(318, '&Reset Graph')
347        wx.EVT_MENU(self, 318, self.onResetGraph)
348       
349        pos = event.GetPosition()
350        pos = self.ScreenToClient(pos)
351        self.PopupMenu(slicerpop, pos)
352   
353    ## The following is plottable functionality
354
355
356    def properties(self,prop):
357        """Set some properties of the graph.
358       
359        The set of properties is not yet determined.
360        """
361        # The particulars of how they are stored and manipulated (e.g., do
362        # we want an inventory internally) is not settled.  I've used a
363        # property dictionary for now.
364        #
365        # How these properties interact with a user defined style file is
366        # even less clear.
367
368        # Properties defined by plot
369        self.subplot.set_xlabel(r"$%s$" % prop["xlabel"])
370        self.subplot.set_ylabel(r"$%s$" % prop["ylabel"])
371        self.subplot.set_title(prop["title"])
372
373        # Properties defined by user
374        #self.axes.grid(True)
375
376    def clear(self):
377        """Reset the plot"""
378       
379        # TODO: Redraw is brutal.  Render to a backing store and swap in
380        # TODO: rather than redrawing on the fly.
381        self.subplot.clear()
382        self.subplot.hold(True)
383   
384    def render(self):
385        """Commit the plot after all objects are drawn"""
386        # TODO: this is when the backing store should be swapped in.
387        from matplotlib.font_manager import FontProperties
388        self.subplot.legend(prop=FontProperties(size=10))
389        #self.subplot.legend()
390        pass
391
392    def xaxis(self,label,units):
393        """xaxis label and units.
394       
395        Axis labels know about units.
396       
397        We need to do this so that we can detect when axes are not
398        commesurate.  Currently this is ignored other than for formatting
399        purposes.
400        """
401        if units != "": label = label + " (" + units + ")"
402        self.subplot.set_xlabel(label)
403        pass
404   
405    def yaxis(self,label,units):
406        """yaxis label and units."""
407        if units != "": label = label + " (" + units + ")"
408        self.subplot.set_ylabel(label)
409        pass
410
411    def _connect_to_xlim(self,callback):
412        """Bind the xlim change notification to the callback"""
413        def process_xlim(axes):
414            lo,hi = subplot.get_xlim()
415            callback(lo,hi)
416        self.subplot.callbacks.connect('xlim_changed',process_xlim)
417   
418    #def connect(self,trigger,callback):
419    #    print "PlotPanel.connect???"
420    #    if trigger == 'xlim': self._connect_to_xlim(callback)
421
422    def points(self,x,y,dx=None,dy=None,color=0,symbol=0,label=None):
423        """Draw markers with error bars"""
424        self.subplot.set_yscale('linear')
425        self.subplot.set_xscale('linear')
426        # Convert tuple (lo,hi) to array [(x-lo),(hi-x)]
427        if dx != None and type(dx) == type(()):
428            dx = nx.vstack((x-dx[0],dx[1]-x)).transpose()
429        if dy != None and type(dy) == type(()):
430            dy = nx.vstack((y-dy[0],dy[1]-y)).transpose()
431
432        if dx==None and dy==None:
433            h = self.subplot.plot(x,y,color=self._color(color),
434                                   marker=self._symbol(symbol),linestyle='',label=label)
435        else:
436            self.subplot.errorbar(x, y, yerr=dy, xerr=None,
437             ecolor=self._color(color), capsize=2,linestyle='', barsabove=False,
438             marker=self._symbol(symbol),
439             lolims=False, uplims=False,
440             xlolims=False, xuplims=False,label=label)
441           
442        self.subplot.set_yscale(self.yscale)
443        self.subplot.set_xscale(self.xscale)
444
445    def curve(self,x,y,dy=None,color=0,symbol=0,label=None):
446        """Draw a line on a graph, possibly with confidence intervals."""
447        c = self._color(color)
448        self.subplot.set_yscale('linear')
449        self.subplot.set_xscale('linear')
450       
451        hlist = self.subplot.plot(x,y,color=c,marker='',linestyle='-',label=label)
452       
453        self.subplot.set_yscale(self.yscale)
454        self.subplot.set_xscale(self.xscale)
455
456    def _color(self,c):
457        """Return a particular colour"""
458        return self.colorlist[c%len(self.colorlist)]
459
460    def _symbol(self,s):
461        """Return a particular symbol"""
462        return self.symbollist[s%len(self.symbollist)]
463   
464    def _onEVT_FUNC_PROPERTY(self):
465        """
466             Receive the x and y transformation from myDialog,Transforms x and y in View
467              and set the scale   
468        """ 
469        list =[]
470        list = self.graph.returnPlottable()
471        self.fit_result.x =[] 
472        self.fit_result.y =[] 
473        self.fit_result.dx=None
474        self.fit_result.dy=None
475       
476        for item in list:
477            item.setLabel(self.xLabel,self.yLabel)
478            if ( self.xLabel=="x" ):
479                item.transformX(transform.toX,transform.errToX)
480                self.set_xscale("linear")
481                name, units = item.get_xaxis()
482                self.graph.xaxis("%s" % name,  "%s^{-1}" % units)
483               
484            if ( self.xLabel=="x^(2)" ):
485                item.transformX(transform.toX2,transform.errToX2)
486                self.set_xscale('linear')
487                name, units = item.get_xaxis()
488                self.graph.xaxis("%s^{2}" % name,  "%s^{-2}" % units)
489               
490            if (self.xLabel=="log10(x)" ):
491                item.transformX(transform.toX,transform.errToX)
492                self.set_xscale("log")
493                name, units = item.get_xaxis() 
494                self.graph.xaxis("\log_{10}\ \  %s" % name,  "%s^{-1}" % units)
495               
496            if ( self.yLabel=="ln(y)" ):
497                item.transformY(transform.toLogX,transform.errToLogX)
498                self.set_yscale("linear")
499                name, units = item.get_yaxis()
500                self.graph.yaxis("log\ \ %s" % name,  "%s^{-1}" % units)
501               
502            if ( self.yLabel=="y" ):
503                item.transformY(transform.toX,transform.errToX)
504                self.set_yscale("linear")
505                name, units = item.get_yaxis()
506                self.graph.yaxis("%s" % name,  "%s^{-1}" % units)
507               
508            if ( self.yLabel=="log10(y)" ): 
509                item.transformY(transform.toX,transform.errToX)
510                self.set_yscale("log") 
511                name, units = item.get_yaxis()
512                self.graph.yaxis("\log_{10}\ \ %s" % name,  "%s^{-1}" % units)
513               
514            if ( self.yLabel=="y^(2)" ):
515                item.transformY( transform.toX2,transform.errToX2 )   
516                self.set_yscale("linear")
517                name, units = item.get_yaxis()
518                self.graph.yaxis("%s^{2}" % name,  "%s^{-2}" % units)
519               
520            if ( self.yLabel =="1/y"):
521                item.transformY(transform.toOneOverX,transform.errOneOverX )
522                self.set_yscale("linear")
523                name, units = item.get_yaxis()
524                self.graph.yaxis("%s" % name,  "\ \%s" % units)
525               
526            if ( self.yLabel =="1/sqrt(y)" ):
527                item.transformY(transform.toOneOverSqrtX,transform.errOneOverSqrtX )
528                self.set_yscale("linear")
529                name, units = item.get_yaxis()
530                self.graph.yaxis("\sqrt{%s}" %name,  "%s" % units)
531               
532            if ( self.yLabel =="ln(y*x)"):
533                item.transformY( transform.toLogXY,transform.errToLogXY)
534                self.set_yscale("linear")
535                yname, yunits = item.get_yaxis()
536                xname, xunits = item.get_xaxis()
537                self.graph.yaxis("log\ %s %s" % (yname,xname),  "%s^{-1}%s^{-1}" % (yunits,xunits))
538               
539            if ( self.yLabel =="ln(y*x^(2))"):
540                item.transformY( transform.toLogYX2,transform.errToLogYX2)
541                self.set_yscale("linear")
542                yname, yunits = item.get_yaxis()
543                xname, xunits = item.get_xaxis() 
544                self.graph.yaxis("Log %s%s^{2}" % (yname,xname),  "%s^{-1}%s^{-2}" % (yunits,xunits))
545           
546            if ( self.yLabel =="ln(y*x^(4))"):
547                item.transformY(transform.toLogYX4,transform.errToLogYX4)
548                self.set_yscale("linear")
549                yname, yunits = item.get_yaxis()
550                xname, xunits = item.get_xaxis()
551                self.graph.yaxis("Log %s%s^{4}" % (yname,xname),  "%s^{-1}%s^{-4}" % (yunits,xunits))
552           
553            if ( self.viewModel == "Guinier lny vs x^(2)"):
554               
555                item.transformX(transform.toX2,transform.errToX2)
556                self.set_xscale('linear')
557                name, units = item.get_xaxis()
558                self.graph.xaxis("%s^{2}" % name,  "%s^{-2}" % units)
559               
560                item.transformY(transform.toLogX,transform.errToLogX )
561                self.set_yscale("linear")
562                name, units = item.get_yaxis()
563                self.graph.yaxis("$Log %s$" % name,  "%s^{-1}" % units)
564               
565            item.transformView()
566           
567        #item.name = self.yLabel+" vs " +self.xLabel 
568        self.xmin=0.0
569        self.xmax=0.0
570        self.xminView=0.0
571        self.xmaxView=0.0   
572        self.prevXtrans = self.xLabel
573        self.prevYtrans = self.yLabel 
574        self.graph.render(self)
575        self.subplot.figure.canvas.draw_idle()
576       
577    def onFitDisplay(self, tempx,tempy,xminView,xmaxView,xmin,xmax,func):
578        """
579            Add a new plottable into the graph .In this case this plottable will be used
580            to fit some data
581            @param plottable: the plottable to plot
582        """
583        self.Avalue,self.Bvalue,self.ErrAvalue,self.ErrBvalue,self.Chivalue=func
584       
585        list =[]
586        list = self.graph.returnPlottable()
587        for item in list:
588            #item.onFitRange(xminView,xmaxView)
589            item.onFitRange(None,None)
590        self.xminView=xminView
591        self.xmaxView=xmaxView
592        self.xmin= xmin
593        self.xmax= xmax
594        # Create new data plottable with result
595        self.fit_result.x =[] 
596        self.fit_result.y =[]
597        self.fit_result.x =tempx 
598        self.fit_result.y =tempy     
599        self.fit_result.dx=None
600        self.fit_result.dy=None
601        #Load the view with the new values
602        self.fit_result.reset_view() 
603        self.graph.add(self.fit_result) 
604       
605        self.graph.render(self)
606        self.subplot.figure.canvas.draw_idle()
607        #self.graph.delete(plottable)
608   
609    def onResetGraph(self,event):
610        list =[]
611        list = self.graph.returnPlottable()
612        for item in list:
613            item.onReset()
614        self.graph.render(self)
615        self.subplot.figure.canvas.draw_idle()
616       
617class NoRepaintCanvas(FigureCanvasWxAgg):
618    """We subclass FigureCanvasWxAgg, overriding the _onPaint method, so that
619    the draw method is only called for the first two paint events. After that,
620    the canvas will only be redrawn when it is resized.
621    """
622    def __init__(self, *args, **kwargs):
623        FigureCanvasWxAgg.__init__(self, *args, **kwargs)
624        self._drawn = 0
625
626    def _onPaint(self, evt):
627        """
628        Called when wxPaintEvt is generated
629        """
630        if not self._isRealized:
631            self.realize()
632        if self._drawn < 2:
633            self.draw(repaint = False)
634            self._drawn += 1
635        self.gui_repaint(drawDC=wx.PaintDC(self))
636           
Note: See TracBrowser for help on using the repository browser.