How to convert a matplotlib figure to a numpy array or a PIL image

Description

For manipulating a figure build with matplotlib, it is sometimes requested to convert it in a format understandable by other python libraries. This can be useful for using scipy image filters or manually adding annotations for example.

Prerequisites

Language
  • PYTHON >=2.5
Libraries
  • matplotlib >=0.99.0
  • numpy >=1.2.1
  • PIL (Python Imaging Library) >=0.1.6
Probably supported by earlier versions, but not tested. Building a matplotlib figure To begin with, we will need a figure to convert. The following code produces a simple cardinal sine plot.
import matplotlib.pyplot
import numpy
 
# Generate a figure with matplotlib</font>
figure = matplotlib.pyplot.figure(  )
plot   = figure.add_subplot ( 111 )
 
# draw a cardinal sine plot
x = numpy.arange ( 0, 100, 0.1 )
y = numpy.sin ( x ) / x
plot.plot ( x, y )
Now, if you run the command
matplotlib.pyplot.show()
You will obtain the widget :
1D Plot of a Cardinal Sine, with frame decorations
Sinc plot 1D

REM If you obtain an message like :
.../python2.5/lib/python2.5/site-packages/matplotlib/backends/__init__.py:41: UserWarning: 
Your currently selected backend, 'agg' does not support show().
Please select a GUI backend in your matplotlibrc file
It means that your matplotlib installation is not configured to use a interactive frame. Instead of using the show command, you can dump the figure to an image file and open it externally :
matplotlib.pyplot.savefig ( "./my_img.png" )
Conversion to a numpy array of RGBA values Now we have a figure, we can transform it in a numpy array of RGBA values with the function :
import numpy
 
def fig2data ( fig ):
    """
    @brief Convert a Matplotlib figure to a 4D numpy array with RGBA channels and return it
    @param fig a matplotlib figure
    @return a numpy 3D array of RGBA values
    """
    # draw the renderer
    fig.canvas.draw ( )
 
    # Get the RGBA buffer from the figure
    w,h = fig.canvas.get_width_height()
    buf = numpy.fromstring ( fig.canvas.tostring_argb(), dtype=numpy.uint8 )
    buf.shape = ( w, h,4 )
 
    # canvas.tostring_argb give pixmap in ARGB mode. Roll the ALPHA channel to have it in RGBA mode
    buf = numpy.roll ( buf, 3, axis = 2 )
    return buf
Conversion to a PIL image At this point, we just have to convert the numpy array to a PIL Image to end the conversion. This is managed by the function
import Image
 
def fig2img ( fig ):
    """
    @brief Convert a Matplotlib figure to a PIL Image in RGBA format and return it
    @param fig a matplotlib figure
    @return a Python Imaging Library ( PIL ) image
    """
    # put the figure pixmap into a numpy array
    buf = fig2data ( fig )
    w, h, d = buf.shape
    return Image.fromstring( "RGBA", ( w ,h ), buf.tostring( ) )
This will return a PIL Image that you can open for example with
im = fig2img ( figure )
im.show()