Using io.BytesIO() with Python

bgp4_table & bgp6_table currently tweet two images a week. One showing a graph for prefix counts over the week on a Monday. Then a pie graph showing subnet distribution on a Wednesday.

When I first started with these images years ago I did it in a rather silly way. I had a function create the required graphs and save it to locally as a png. I’d then craft the tweet, attach the image, and send it on it’s way. I never bothered to clean up and so I have loads of images scattered on my drive.

This is pointless, as once the image is tweeted out I don’t need it any more. I can recreate these images at any time I need them. I’m also writing and reading to local storage.

Instead of this, you can read and write to a file-like object. This acts like a file, but it’s just sitting in memory. You can save data to this file, pass it around, and it never gets written anywhere.

In this example I’ll create a graph in matplotlib and just save to a virtual file.

#!/usr/bin/env python3

import io
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)

fig, ax = plt.subplots()
ax.plot(t, s)

ax.set(xlabel='time (s)', ylabel='voltage (mV)',
       title='About as simple as it gets, folks')
ax.grid()

b = io.BytesIO()
plt.savefig(b, format='png')
plt.close()

b is now an in-memory object that can be used wherever a file is used. Attach it to your tweet and you’re set.

If you do need to now dump this image to storage you can still do that.

with open("image.png", "wb") as f:
    f.write(b.read())