Question

I haven't used Matplotlib much. Based on someone's advice, I'm trying to write some plotting codes using object-oriented paradigms as much as possible---and therefore trying to use pure Matplotlib (i.e. not relying on pyplot) to generate some simple figures.

A stripped-down version of my code looks like this:

import matplotlib as mpl

time = [0,1,2,3,4]
cell = [1,2,1,2,1]
sample = [3,2,3,4,4]

(figHt, figWd) = (5, 8) # in
lBorderWidth = bBorderWidth = rBorderWidth = tBorderWidth = 0.1
lbwh = (lBorderWidth, bBorderWidth,
        (1-lBorderWidth-rBorderWidth),
        (1-tBorderWidth-bBorderWidth)) # left, bottom, width, height

fig = mpl.figure.Figure(figsize=(figHt, figWd))

ax = fig.add_axes(lbwh)
lines1, = ax.plot(time,cell,'k--')
lines2, = ax.plot(time,sample,'k-')

fig.legend([lines1,lines2],['p','q'],'upper left')
fig.canvas.draw()

But when I run it, Python complains when it reaches fig.canvas.draw() that canvas type is None.

Based on a reading of the Matplotlib Artists tutorial, it seems like pyplot takes care of a few behind-the-scenes setup tasks, most notably establishing the connection between the Figure object and the desired renderer/backend. The tutorial says:

In the example below, we create a Figure instance using matplotlib.pyplot.figure(), which is a convenience method for instantiating Figure instances and connecting them with your user interface or drawing toolkit FigureCanvas. As we will discuss below, this is not necessary – you can work directly with PostScript, PDF Gtk+, or wxPython FigureCanvas instances, instantiate your Figures directly and connect them yourselves – but since we are focusing here on the Artist API we’ll let pyplot handle some of those details for us

Unfortunately, that particular page doesn't proceed beyond generating plots with pyplot.figure(), so I am still trying to discover what the required steps are. Again, I realize pyplot can simplify this task---just trying to grok how all the pieces fit together.

I saw this description of a base class used by backends, FigureCanvasBase, and I assume that I need to assign fig.canvas one of FigureCanvasBase's subclasses.

Also, I verified that Python is using a default backend. So I know the problem isn't caused by lack of a backend.

>>> matplotlib.backends.backend
'Qt4Agg'

Thanks in advance for any help. In summary, two questions:

  1. What am I missing that is causing this to fail? Is it because I didn't assign the figure object a renderer?
  2. I mentioned that I suspected I needed a subclass of FigureCanvasBase to move forward. Even if the problem can probably be solved more elegantly, is there a way to search the Python environment for subclasses that inherit from FigureCanvasBase? This might come in handy in other problems.
Was it helpful?

Solution

You need to create a FigureCanvasAgg in order to plot manually, try this:

import matplotlib as mpl
mpl.use('Agg') #setup the backend
import matplotlib.figure as mfigure
from matplotlib.backends.backend_agg import FigureCanvasAgg #canvas

time = [0,1,2,3,4]
cell = [1,2,1,2,1]
sample = [3,2,3,4,4]

(figHt, figWd) = (5, 8) # in
lBorderWidth = bBorderWidth = rBorderWidth = tBorderWidth = 0.1
lbwh = (lBorderWidth, bBorderWidth,
        (1-lBorderWidth-rBorderWidth),
        (1-tBorderWidth-bBorderWidth)) # left, bottom, width, height

fig = mfigure.Figure(figsize=(figHt, figWd))
canvas = FigureCanvasAgg(fig) #create the canvas

ax = fig.add_axes(lbwh)
lines1, = ax.plot(time,cell,'k--')
lines2, = ax.plot(time,sample,'k-')

fig.legend([lines1,lines2],['p','q'],'upper left')
fig.savefig('test.png') #save the figure

Note: You can find the subclasses of FigureCanvasBase in matplotlib.backends.<your backend>.FigureCanvas<your backend>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top