Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib: how to show a figure that has been closed

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?

like image 265
Peque Avatar asked Jul 30 '15 17:07

Peque


1 Answers

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:

enter image description here

like image 200
Jean-Sébastien Avatar answered Nov 12 '22 07:11

Jean-Sébastien