33

Problem : Need to transform a graphic image of matplotlib to a base64 image

Current Solution : Save the matplot image in a cache folder and read it with read() method and then convert to base64

New Problem : Annoyance : Need a workaround so I dont need to save the graphic as image in any folder. I want to just use the image in the memory. Doing unnecessary I/O is a bad practice.

def save_single_graphic_data(data, y_label="Loss", x_label="Epochs", save_as="data.png"):
    total_epochs = len(data)
    plt.figure()
    plt.clf()

    plt.plot(total_epochs, data)

    ax = plt.gca()
    ax.ticklabel_format(useOffset=False)

    plt.ylabel(y_label)
    plt.xlabel(x_label)

    if save_as is not None:
        plt.savefig(save_as)

    plt.savefig("cache/cached1.png")

    cached_img = open("cache/cached1.png")

    cached_img_b64 = base64.b64encode(cached_img.read())

    os.remove("cache/cached1.png")

    return cached_img_b64
KenobiBastila
  • 539
  • 4
  • 16
  • 52

3 Answers3

41
import cStringIO
my_stringIObytes = cStringIO.StringIO()
plt.savefig(my_stringIObytes, format='jpg')
my_stringIObytes.seek(0)
my_base64_jpgData = base64.b64encode(my_stringIObytes.read())

[edit] in python3 it should be

import io
my_stringIObytes = io.BytesIO()
plt.savefig(my_stringIObytes, format='jpg')
my_stringIObytes.seek(0)
my_base64_jpgData = base64.b64encode(my_stringIObytes.read()).decode()

I think at least ... based on the documentation http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.savefig

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • 8
    If you are using Python 3 or greater, you need to use `io.BytesIO` as mentioned by @nobar at https://stackoverflow.com/a/18284900/1802726. – Raniere Silva Sep 27 '17 at 15:23
  • 1
    Or for Python 2/3 compatibility with fastest implementation: `try: from cStringIO import StringIO; except ImportError: from six import StringIO` ([`six` ref](https://six.readthedocs.io/#six.StringIO)) – A T Sep 21 '19 at 07:01
  • Hi Joran, from your code, where is the figure variable? I only see my_stringIObytes, I don't see any variable related to original mtaplotlib plot object. Thanks for clarifying. – roudan Feb 21 '22 at 20:57
  • `my_base64_jpgData` has the base64 encoded data you could then do something like `` or use other methods to decode it back to the original image – Joran Beasley Feb 21 '22 at 22:44
  • `my_base64_jpgData ` might have to be wrapped in an `str()`, as the data is in binary string format by default. ( `b'sfsafs'`) – kn_pavan Feb 01 '23 at 17:16
  • 05.05.23 - Linked here via another question. This contributed to helping me solve my issue. +1 – MacItaly May 05 '23 at 20:28
24

For python 3

import base64
import io 
pic_IObytes = io.BytesIO()
plt.savefig(pic_IObytes,  format='png')
pic_IObytes.seek(0)
pic_hash = base64.b64encode(pic_IObytes.read())

The reason is both cStringIO and cStringIO.StringIO() are deprecated

BoyePanthera
  • 546
  • 5
  • 10
  • 1
    You might want to add a more detailed explanation – Yulia V Dec 19 '19 at 17:57
  • 2
    @YuliaV what I was saying is that in Python 3 the ```cStringIO``` module has been deprecated in place of ```io``` module. So that is why I used the io module in my answer. – BoyePanthera Apr 01 '21 at 16:28
20

I could not get answers above work, but this did:

    import io
    import base64
    s = io.BytesIO()
    plt.plot(list(range(100)))
    plt.savefig(s, format='png', bbox_inches="tight")
    plt.close()
    s = base64.b64encode(s.getvalue()).decode("utf-8").replace("\n", "")
    return '<img align="left" src="data:image/png;base64,%s">' % s
Rex D
  • 497
  • 3
  • 9