how to save a pylab figure into in-memory file which can be read into PIL image?

46,211

Solution 1

Remember to call buf.seek(0) so Image.open(buf) starts reading from the beginning of the buf:

import io
from PIL import Image
import matplotlib.pyplot as plt

plt.figure()
plt.plot([1, 2])
plt.title("test")
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
im = Image.open(buf)
im.show()
buf.close()

Solution 2

I like having it encapsulated in a function:

def fig2img(fig):
    """Convert a Matplotlib figure to a PIL Image and return it"""
    import io
    buf = io.BytesIO()
    fig.savefig(buf)
    buf.seek(0)
    img = Image.open(buf)
    return img

Then I can call it easily this way:

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

x = np.arange(-3,3)
plt.plot(x)
fig = plt.gcf()

img = fig2img(fig)
img.show()
Share:
46,211

Related videos on Youtube

nye17
Author by

nye17

coding is boring.

Updated on July 05, 2022

Comments

  • nye17
    nye17 almost 2 years

    The following is my first shot which never works:

    import cStringIO
    import pylab
    from PIL import Image
    pylab.figure()
    pylab.plot([1,2])
    pylab.title("test")
    buffer = cStringIO.StringIO()
    pylab.savefig(buffer, format='png')
    im = Image.open(buffer.read())
    buffer.close()
    

    the error says,

    Traceback (most recent call last):
      File "try.py", line 10, in <module>
        im = Image.open(buffer.read())
      File "/awesomepath/python2.7/site-packages/PIL/Image.py", line 1952, in open
        fp = __builtin__.open(fp, "rb")
    

    any ideas? I don't want the solution to involve extra packages.

  • nye17
    nye17 over 12 years
    Awesome! it works like a charm! even when I substitute io.BytesIO with my original StringIO. Can you remind you what the why you choose to use the former here? Thanks!
  • unutbu
    unutbu over 12 years
    For Python2.6 or better, use io.BytesIO instead of cStringIO.StringIO for forward-compatibility. In Python3, the cStringIO, StringIO modules are gone. Their functionality is all in the io module.
  • Little Bobby Tables
    Little Bobby Tables over 5 years
    How do you set a sensible file name for your .png? It seems to just call mine fig.png - thanks.
  • unutbu
    unutbu over 5 years
    @josh: plt.savefig(buf, format='png') writes to an in-memory BytesIO object. No file is created. The more usual way to use savefig is to call plt.savefig('/path/to/anyfilenameyouwant.png'), which allows you to specify the filename.
  • Little Bobby Tables
    Little Bobby Tables over 5 years
    I am sending this in a response from a Falsk app so the file gets downloaded by Chrome, etc. Maybe there is a better way to do this, where I get to choose my file name (of the downloaded .png). Thanks though.
  • jmd_dk
    jmd_dk over 5 years
    If you want the image as an array, you can get by without PIL/pillow and use im = plt.imread(buf). You can also save the im array using plt.imsave('/path/to/saved/file.png', im).