If I create an Axes
object in matplotlib
and mutate it (i.e. by plotting some data) and then I call a function without passing my Axes
object to that function then that function can still mutate my Axes
. For example:
import matplotlib.pyplot as plt
import numpy as np
def innocent_looking_function():
#let's draw a red line on some unsuspecting Axes!
plt.plot(100*np.random.rand(20), color='r')
fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20), color='b') #draw blue line on ax
#ax now has a blue line, as expected
innocent_looking_function()
#ax now unexpectedly has a blue line and a red line!
My question is: can I prevent this global-variable behaviour in general? I know I can call plt.close()
before calling any innocent_looking_function()
but is there some way to make this the default?
“With this backend, the output of plotting commands is displayed inline within frontends like the Jupyter notebook, directly below the code cell that produced it. The resulting plots will then also be stored in the notebook document.”
plt. clf() clears the entire current figure with all its axes, but leaves the window opened, such that it may be reused for other plots. plt. close() closes a window, which will be the current window, if not specified otherwise.
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:
FigureManager
for that figure using the appropriate backendFigureCanvas
, gui window (as needed), and NavigationToolbar2
(zoom buttons, etc)_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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With