Subclassing PyPlot, need some help

Christian K. ckkart at hoc.net
Wed Aug 1 20:26:50 PDT 2007


Andriy wrote:
> Hi,
> 
> I'm working on a subclass of PyPlot (specifically, I'm subclassing
> PlotCanvas from wx.lib.plot).  My purpose is to have a plot class that
> can draw multiple subplots into the class canvas.  My approach so far
> is this: the derived class constructor takes the number of rows and
> columns, and maintains a list of PlotCanvas instances based on that.
> The class has a Plot method, which takes a PlotGraphics instance and a
> plot index, and draws the graphics to the appropriate plot in the list
> based on the index. The subplots are all equally sized; their size is
> calculated based on the canvas size and number of rows & columns.
> When it will work, it should look something like a pylab plot with
> subplots, though I will index the subplots in the way that a GridSizer
> does (zero-based, left-right, top-to-bottom).
> 
> I think that I have built the OnSize event handler properly because I
> can see the SubPlotSize calculating correctly when I resize the parent
> panel. I'm not sure if I have built the OnPaint handler correctly
> because I don't draw to the main canvas yet. Which leads me to my
> questions:
> 
> Where do I put the code to draw the subplots together to the canvas?
> Should it be in the Plot method?
> What is the proper DC to use for drawing the subplots to the canvas? I
> am guessing I could use something like:
>     dc = wx.BufferedDC(wx.ClientDC(self.canvas), self._Buffer)
> and then pass this dc to PlotCanvas.Draw()  ?  But it's not quite
> right.. I need multiple dc's from all the plots.
> 
> If I do this right, I should be able to save the canvas image to file,
> as well as be able to print it by just delegating these actions to the
> superclass, right?
> 
> Here is a (working) skeleton of the subclass:
> 
> class FlexPlot(PlotCanvas):
>     def __init__(self, parent, rows=1, cols=1, title=''):
>         self.parent = parent
>         self.rows = rows
>         self.cols = cols
>         self.title = title
>         self.numplots = self.rows * self.cols
>         self.plots = []
>         for i in xrange(self.numplots):
>             self.plots.append(PlotCanvas(parent))
>             self.resetDefaults(self.plots[i])
>         #now initialize the superclass
>         PlotCanvas.__init__(self, parent)
>         parent.Bind(wx.EVT_SIZE, self.OnSize)
> 
>     def OnSize(self, event):
>         PlotCanvas.OnSize(self, event)
>         for subplot in self.plots:
>             PlotCanvas.OnSize(subplot, event)
>         buffer = getattr(self, '_Buffer', None)
>         if buffer: print 'Buffer size: %s' % (buffer.GetSize(),)
>         canvasSize = self.canvas.GetClientSize()
>         self.SubPlotSize = (canvasSize[0]/self.rows, canvasSize[1]/self.cols)
>         if event is not None:
>             event.Skip()
> 
>     def OnPaint(self, event):
>         #invoke the individual OnPaint events
>         for subplot in self.plots:
>             PlotCanvas.OnPaint(subplot, event)
>         event.Skip()
> 
>     def Plot(self, graphics, index=0, xlim=None, ylim=None,
> grid=False, legend=False):
>         """
>         Plotting command - wrapper around the
>         superclass Draw method to handle multiple subplots.
>             graphics: PlotGraphics instance
>             index: subplot index (zero-based)
>             xlim: tuple of (xmin, xmax) for the X axis
>             ylim: tuple of (ymin, ymax) for the Y axis
>             grid: turns grid on/off
>             legend: turns legend on/off
>         """
>         subPlot = self.plots[index]
>         dc = wx.BufferedDC(wx.ClientDC(self.canvas), self._Buffer)
>         self.resetDefaults(subPlot)
>         subPlot.Draw(graphics, xAxis=xlim, yAxis=ylim, dc=dc)
>         subPlot.SetEnableGrid(grid)
>         subPlot.SetEnableLegend(legend)
>         subPlot.SetShowScrollbars(False)

To me it looks like you are mixing different approaches. Either subclass 
PlotCanvas and modify only the drawing code, i.e. that part that 
actually paints the graph, frame, labels, etc. or create a custum class 
that contains an arbitrary number of PlotCanvas objects. Note that 
PlotCanvas is a wx.Panel, so you might want to put them in a sizer. 
Obviously only with the first method you will have a single DC which can 
be exported easily.

Currently you're subclassing PlotCanvas and then you put additional 
PlotCanvas objects in there. I doubt that this will work.

Christian





More information about the wxpython-users mailing list