Subclassing PyPlot, need some help

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