Matplotlib graphic image to base64 - python

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

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

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

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

Related

Model card fails to show plots

I am trying to add a .png image to my model card. But it keeps giving a blank picture. I followed the instruction given by Google.
Here is what my code looks like,
from io import BytesIO
import base64
from google.colab import files
def plot_to_str():
img = BytesIO()
plt.savefig(img, format='png')
return base64.encodebytes(img.getvalue()).decode('utf-8')
my_plot = files.upload()
my_plot = plot_to_str()
And for the model card:
mct = mctlib.ModelCardToolkit()
model_card = mct.scaffold_assets()
# skipped the beginning of the model_card
model_card.model_parameters.data.append(mctlib.Dataset())
model_card.model_parameters.data[0].graphics.collection = [
mctlib.Graphic(image=my_plot)
]
mct.update_model_card(model_card)
html = mct.export_format()
display.display(display.HTML(html))
As a result I get this, a blan plot:

Matplotlib - export figure to png in memory buffer

Is it possible to export a matplotlib figure as a png to a bytes type?
Here is the code I currently have:
def import_chart(df, x_label, y_label, title):
fig, ax = plt.subplots()
ax.plot(data[x_label], data[y_label])
ax.set(xlabel=x_label, ylabel=y_label,
title=title)
image_name = 'test.png'
fig.savefig(image_name)
f = open(image_name, 'rb+')
img = f.read()
f.close()
os.remove(image_name)
return img
The image that is returned is of type class 'bytes'. I would like to avoid saving to the hard drive and reading it again. Something like this:
def import_chart(self, x_label, y_label, title):
fig, ax = plt.subplots()
data = self.file_data.get_column([x_label,y_label])
ax.plot(data[x_label], data[y_label])
ax.set(xlabel=x_label, ylabel=y_label,
title=title)
buffer = buffer.to_buffer(fig.savefig(), format='png')
img = buffer.read()
return img
I've been using this to render matplotlib images from a web server:
import base64
from io import BytesIO
...
buffer = BytesIO()
plt.savefig(buffer, format='png')
buffer.seek(0)
image_png = buffer.getvalue()
buffer.close()
graphic = base64.b64encode(image_png)
graphic = graphic.decode('utf-8')
return graphic

How to convert Image PIL into Base64 without saving

I generate an image with Python, and I need to convert this Pil Image into a Base64, without saving this one into any folder...
I have some data, and I get RGB img with the line below:
img = Image.fromarray(data,'RGB')
What is the simple way to convert this PIL into base64 ?(I can't open a file image because I must not save the img) ?
Thank you for your help
With Node JS, I can get the correct base64 with these lines :
pythonShell= require("python-shell");
app.post('/index/gen/',urlencodedParser, function (req,res){
pythonShell.run('minigen.py', function (err, results) {
if (err) throw err;
var img = base64img.base64Sync('./images/miniature.jpg');
res.send(img); });
})
But I have to save the file if I use NodeJS...
this is the code to generate the matrix from the image, you don't need to know what is in data ;)
image = Image.open("./carte/"+fichier)
image = image.resize((400,400),Image.ANTIALIAS)
w,h = image.size
tab = numpy.array(image)
data = numpy.zeros((h, w, 3), dtype=numpy.uint8)
I found the solution. Hope this helps !
img = Image.fromarray(data, 'RGB') #Crée une image à partir de la matrice
buffer = BytesIO()
img.save(buffer,format="JPEG") #Enregistre l'image dans le buffer
myimage = buffer.getvalue()
print "data:image/jpeg;base64,"+base64.b64encode(myimage)
#florian answer helped me a lot but base64.b64encode(img_byte) returned bytes so I needed to decode it to string before concatenation (using python 3.6):
def img_to_base64_str(self, img):
buffered = BytesIO()
img.save(buffered, format="PNG")
buffered.seek(0)
img_byte = buffered.getvalue()
img_str = "data:image/png;base64," + base64.b64encode(img_byte).decode()
You can use base64 library like this:
import base64
base64.b64encode(img.tobytes())
See tobytes() method of Image object.
Or you can use something like this:
import glob
import random
import base64
from PIL import Image
from io import BytesIO
import io
def get_thumbnail(path):
path = "\\\\?\\"+path # This "\\\\?\\" is used to prevent problems with long Windows paths
i = Image.open(path)
return i
def image_base64(im):
if isinstance(im, str):
im = get_thumbnail(im)
with BytesIO() as buffer:
im.save(buffer, 'jpeg')
return base64.b64encode(buffer.getvalue()).decode()
def image_formatter(im):
return f'<img src="data:image/jpeg;base64,{image_base64(im)}">'
Just pass path of image in get_thumbnail function and image_formatter to display it in HTML.

Displaying matplotlib plot in CGI with cStringIO

Trying to return a simple plot (saved in StringIO) to web browser. After hours of reading, finally getting close, maybe.
import cgi
import cStringIO
import matplotlib.pyplot as plt
import numpy as np
def doit():
x = np.linspace(-2,2,100)
y = np.sin(x)
format = "png"
ggg = cStringIO.StringIO()
plt.plot(x, y)
plt.savefig(ggg, format=format)
data_uri = ggg.read().encode('base64').replace('\n', '')
img_tag = '<img src="data:image/png;base64,{0}" alt="thisistheplot"/>'.format(data_uri)
print("Content-type: text/html\n")
print("<title>Try Ageen</title>")
print("<h1>Hi</h1>")
print(img_tag)
doit()
It's returning a broken image icon. I've looked already read this: Dynamically serving a matplotlib image to the web using python, among others...
Actually, just figured it out. Will leave posted, as I haven't seen this approach being taken and hope it can help:
#!/usr/bin/env python
import cgi
import cStringIO
import matplotlib.pyplot as plt
import numpy as np
def doit():
x = np.linspace(-2,2,100)
y = np.sin(x)
format = "png"
sio = cStringIO.StringIO()
plt.plot(x, y)
plt.savefig(sio, format=format)
data_uri = sio.getvalue().encode('base64').replace('\n', '')
img_tag = '<img src="data:image/png;base64,{0}" alt="sucka" />'.format(data_uri)
print("Content-type: text/html\n")
print("<title>Try Ageen</title>")
print("<h1>Hi</h1>")
print(img_tag)
doit()
The goal is to have a client input a trigonometric function and have it returned on a subsequent page. Still any comments to help this code perform/look better are welcomed.

How to store an image in a variable

I would like to store the image generated by matplotlib in a variable raw_data to use it as inline image.
import os
import sys
os.environ['MPLCONFIGDIR'] = '/tmp/'
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
print "Content-type: image/png\n"
plt.plot(range(10, 20))
raw_data = plt.show()
if raw_data:
uri = 'data:image/png;base64,' + urllib.quote(base64.b64encode(raw_data))
print '<img src = "%s"/>' % uri
else:
print "No data"
#plt.savefig(sys.stdout, format='png')
None of the functions suit my use case:
plt.savefig(sys.stdout, format='png') - Writes it to stdout. This does help.. as I have to embed the image in a html file.
plt.show() / plt.draw() does nothing when executed from command line
Have you tried cStringIO or an equivalent?
import os
import sys
import matplotlib
import matplotlib.pyplot as plt
import StringIO
import urllib, base64
plt.plot(range(10, 20))
fig = plt.gcf()
imgdata = StringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0) # rewind the data
print "Content-type: image/png\n"
uri = 'data:image/png;base64,' + urllib.quote(base64.b64encode(imgdata.buf))
print '<img src = "%s"/>' % uri
Complete python 3 version, putting together Paul's answer and metaperture's comment.
import matplotlib.pyplot as plt
import io
import urllib, base64
plt.plot(range(10))
fig = plt.gcf()
buf = io.BytesIO()
fig.savefig(buf, format='png')
buf.seek(0)
string = base64.b64encode(buf.read())
uri = 'data:image/png;base64,' + urllib.parse.quote(string)
html = '<img src = "%s"/>' % uri

Categories