Matplotlib: how to show a figure that has been closed
When plt.close
is called on a figure
instance, what is actually destroyed is the graphical interface (the FigureManager) that is used to show the figure on-screen (see comment by JoeKington at Matplotlib: re-open a closed figure?). So the figure instance still exists and has not been destroyed. To show the figure on-screen again, we would have to reconstruct, in some way, an interface to replace the one that has been destroyed when calling plt.close(fig)
.
This can be done by simply creating a new figure with plt.figure()
, "stealing" its manager, and use it to display the figure that we want to show on-screen. Alternatively, it is possible to reconstruct manually an interface to display the figure with a GUI Toolkit. I provide an example with PySide using the Qt4Agg backend. Moreover, there is a nice example that shows how this can be done with Tkinter (TkAgg) here : http://matplotlib.org/examples/user_interfaces/embedding_in_tk.html (I've tested this approach also and it works).
Dummy figure approach:
This solution is based on how to close a show() window but keep the figure alive? and Obtaining the figure manager via the OO interface in Matplotlib. The GUI toolkit that is used to construct the graphical interface for showing the figure on-screen depends on the backend that is used by matplotlib. If the backend used is TkAgg, TkInter will give some warning in Python 2.7 that can be ignored (see this post on python bug tracker).
import matplotlib.pyplot as plt
def new_figure():
fig = plt.figure()
plt.plot([0, 1], [2, 3])
plt.close(fig)
return fig
def show_figure(fig):
# create a dummy figure and use its
# manager to display "fig"
dummy = plt.figure()
new_manager = dummy.canvas.manager
new_manager.canvas.figure = fig
fig.set_canvas(new_manager.canvas)
if __name__ == '__main__':
fig = new_figure()
show_figure(fig)
plt.show()
Pyside approach:
This consists in reconstructing a GUI with a new canvas and toolbar to display the fig
instance on-screen.
Important Note: The code below must be executed in a new dedicated Python console (press F6) if run from Spyder, since Spyder is also a Qt application that starts it's own QApplication (see PySide Qt script doesn't launch from Spyder but works from shell).
import matplotlib
matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT
import matplotlib.pyplot as plt
from PySide import QtGui
import sys
def new_figure():
fig = plt.figure()
plt.plot([0, 1], [2, 3])
plt.close(fig)
return fig
class myFigCanvas(QtGui.QWidget):
def __init__(self, fig, parent=None):
super(myFigCanvas, self).__init__(parent)
#---- create new canvas and toolbar --
canvas = FigureCanvasQTAgg(fig)
toolbar = NavigationToolbar2QT(canvas, self)
#---- setup layout of GUI ----
grid = QtGui.QGridLayout()
grid.addWidget(canvas, 0, 0)
grid.addWidget(toolbar, 1, 0)
self.setLayout(grid)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
fig = new_figure()
new_canvas = myFigCanvas(fig)
new_canvas.show()
sys.exit(app.exec_())
which results in: Detect which figure was closed with Matplotlib
The evt
that is passed to your handler has a member canvas
, which in turn has a member figure
, which of course is the figure the event refers to.
So if you want to remove that figure from your list, you would do
figs.remove(evt.canvas.figure)
If you want to get the figure number, you access evt.canvas.figure.number
and you could get the name fromevt.canvas.figure._label
However, the leading _
probably means you shouldn't rely on that. view and then close the figure automatically in matplotlib?
Documentation on pyplot.show()
reads:
So the solution is this:
matplotlib.pyplot.show(*args, **kw)
Display a figure. When running in ipython with its pylab mode, display
all figures and return to the ipython prompt.In non-interactive mode, display all figures and block until the figures have been closed; in interactive mode it has no effect
unless figures were created prior to a change from non-interactive to
interactive mode (not recommended). In that case it displays the
figures but does not block.A single experimental keyword argument,
block
, may be set toTrue
orFalse
to override the blocking behavior described above.
plt.show(block=False)
plt.pause(3)
plt.close()
How to detect that an axis belong to a window that has been closed in matplotlib
Why not just connect a callback to the "close_event"
? You could either add a ax.has_been_closed
flag to the axes object or your class itself. (There are probably even cleaner solutions than a "has_been_closed" flag, depending on exactly what you're doing... The callback function can be anything.)
import matplotlib.pyplot as plt
def on_close(event):
event.canvas.figure.axes[0].has_been_closed = True
print 'Closed Figure'
fig = plt.figure()
ax = fig.add_subplot(111)
ax.has_been_closed = False
ax.plot(range(10))
fig.canvas.mpl_connect('close_event', on_close)
plt.show()
print ax.has_been_closed
Edit: (Expanding on my comment below) If the OSX backend end doesn't properly implement a close event, you could also do something like this:import matplotlib.pyplot as plt
def has_been_closed(ax):
fig = ax.figure.canvas.manager
active_fig_managers = plt._pylab_helpers.Gcf.figs.values()
return fig not in active_fig_managers
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(10))
print has_been_closed(ax)
plt.show()
print has_been_closed(ax)
How do I tell matplotlib that I am done with a plot?
You can use figure
to create a new plot, for example, or use close
after the first plot.
Matplotlib: re-open a closed figure?
Yes, closing the figure deletes it completely.
Matplotlib pyplot show() doesn't work once closed
It might be from a bug in previous versions of matplotlib. I was having a similar problem when I issued sequential show()
commands -- only the first would show (and stay); but, when I updated matplotlib to 1.0.1 the problem went away.
Related Topics
Loading JSONl File as JSON Objects
Installing Pygraphviz on Windows 10 64-Bit, Python 3.6
Regex for Existence of Some Words Whose Order Doesn't Matter
Selenium Using Python: Enter/Provide Http Proxy Password for Firefox
Round Up to Second Decimal Place in Python
Animated Subplots Using Matplotlib
In What Order Does Python Display Dictionary Keys
What Is the Relationship Between Google's App Engine Sdk and Cloud Sdk
How to Troubleshoot Python "Could Not Find Platform Independent Libraries <Prefix>"
Pivot Tables or Group by for Pandas
Python, Default Keyword Arguments After Variable Length Positional Arguments
Using Only the Db Part of Django
Pip: How to Install a Git Pull Request
How to Fix Selenium Webdriverexception: the Browser Appears to Have Exited Before We Could Connect
"Overflowerror: Python Int Too Large to Convert to C Long" on Windows But Not MAC