Sure! What you need to do is bypass the pyplot
state machine entirely when you make your figure.
It's more verbose, as you can't just call fig = plt.figure()
.
First off, let me explain how plt.gca()
or plt.gcf()
works. When using the pyplot
interface, matplotlib stores all created-but-not-displayed figure managers. Figure managers are basically the gui wrapper for a figure.
plt._pylab_helpers.Gcf
is the singleton object that stores the figure managers and keeps track of which one is currently active. plt.gcf()
returns the active figure from _pylab_helpers.Gcf
. Each Figure
object keeps track of it's own axes, so plt.gca()
is just plt.gcf().gca()
.
Normally, when you call plt.figure()
, it:
- Creates the figure object that's returned
- Creates a
FigureManager
for that figure using the appropriate backend
- The figure manager creates a
FigureCanvas
, gui window (as needed), and NavigationToolbar2
(zoom buttons, etc)
- The figure manager instance is then added to
_pylab_helpers.Gcf
's list of figures.
It's this last step that we want to bypass.
Here's a quick example using a non-interactive backend. Note that because we're not worried about interacting with the plot, we can skip the entire figure manager and just create a Figure
and FigureCanvas
instance. (Technically we could skip the FigureCanvas
, but it will be needed as soon as we want to save the plot to an image, etc.)
import matplotlib.backends.backend_agg as backend
from matplotlib.figure import Figure
# The pylab figure manager will be bypassed in this instance. `plt.gca()`
# can't access the axes created here.
fig = Figure()
canvas = backend.FigureCanvas(fig)
ax = fig.add_subplot(111)
Just to prove that gca
can't see this axes:
import matplotlib.pyplot as plt
import matplotlib.backends.backend_agg as backend
from matplotlib.figure import Figure
# Independent figure/axes
fig = Figure()
canvas = backend.FigureCanvas(fig)
ax = fig.add_subplot(111)
ax.plot(range(10))
# gca() is completely unaware of this axes and will create a new one instead:
ax2 = plt.gca()
print 'Same axes?:', id(ax) == id(ax2)
# And `plt.show()` would show the blank axes of `ax2`
With an interactive backed, it's a touch more complicated. You can't call plt.show()
, so you need to start the gui's mainloop yourself. You can do it all "from scratch" (see any of the "embedding matplotlib" examples), but the FigureManager
abstracts the backed-specific parts away:
As an example using the TkAgg backend:
import matplotlib.backends.backend_tkagg as backend
from matplotlib.figure import Figure
fig = Figure()
ax = fig.add_subplot(111)
manager = backend.new_figure_manager_given_figure(1, fig)
manager.show()
backend.show.mainloop()
To use one of the other backends, just change the backend import. For example, for Qt4:
import matplotlib.backends.backend_qt4agg as backend
from matplotlib.figure import Figure
fig = Figure()
ax = fig.add_subplot(111)
manager = backend.new_figure_manager_given_figure(1, fig)
manager.show()
backend.show.mainloop()
This actually even works with the nbagg
backend used in IPython notebooks. Just change the backend import to import matplotlib.backends.backend_nbagg as backend