Issue
I have a function which returns a Figure
created with pyplot
. This function closes the figure before returning it. If I didn't close it, showing it would be very easy with just plt.show()
, but let us assume I cannot do that.
I can easily save the returned Figure
to a file, but I cannot find the way to display it (i.e.: have a popped window showing the figure).
from matplotlib import pyplot as plt
def new_figure():
fig = plt.figure()
plt.plot([0, 1], [2, 3])
plt.close(fig)
return fig
fig = new_figure()
fig.savefig('output.svg')
fig.show()
How could I show the figure?
Solution
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:
Answered By - Jean-Sébastien
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.