Matplotlib: Save Plot to Numpy Array

How to save a greyscale matplotlib plot to numpy array

Once you have a ploted data (self contained example bellow):

import numpy as np
import matplotlib.pyplot as plt
from skimage import data, color

img = data.camera()

x = np.random.rand(100) * img.shape[1]
y = np.random.rand(100) * img.shape[0]

fig = plt.figure(figsize=(10,10))
plt.imshow(img,cmap="gray")
plt.scatter(x, y, color='k')
plt.ylim([img.shape[0], 0])
plt.xlim([0, img.shape[1]])

The underlying data can be recovered as array by using fig.canvas (the matplotlib's canvas). First trigger its drawing:

fig.canvas.draw()

Get the data as array:

width, height = fig.get_size_inches() * fig.get_dpi()
mplimage = np.fromstring(fig.canvas.tostring_rgb(), dtype='uint8').reshape(height, width, 3)

If you want your array to be the same shape as the original image you will have to play with figsize and dpi properties of plt.figure().

Last, matplotlib returns an RGB image, if you want it grayscale:

gray_image = color.rgb2gray(mplimage)

Matplotlib: Convert plot to numpy array without borders

I figured out how to get rid of the borders. Just replace

fig, ax = plt.subplots(frameon=False)

with

fig = plt.figure()
ax = fig.add_axes([0.,0.,1.,1.])

and it works just fine.

Matplotlib figure to image as a numpy array

In order to get the figure contents as RGB pixel values, the matplotlib.backend_bases.Renderer needs to first draw the contents of the canvas. You can do this by manually calling canvas.draw():

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure

fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.gca()

ax.text(0.0,0.0,"Test", fontsize=45)
ax.axis('off')

canvas.draw() # draw the canvas, cache the renderer

image = np.frombuffer(canvas.tostring_rgb(), dtype='uint8')

See here for more info on the Matplotlib API.

how to get matplotlib plot data as numpy array

fig = plt.figure(figsize=(20, 20)) # this is imp for sizing
# plot
plt.imshow(image, cmap='gray', interpolation='none')
plt.imshow(masked_contour, cmap='cool', interpolation='none', alpha=0.7)
# get image as np.array
canvas = plt.gca().figure.canvas
canvas.draw()
data = np.frombuffer(canvas.tostring_rgb(), dtype=np.uint8)
image = data.reshape(canvas.get_width_height()[::-1] + (3,))
# (Optional) show image
plt.imshow(image)
plt.show()

Save data from plot to numpy array

For recent versions of matplotlib, you can use pickle to save the whole plot or just selected pieces, and even show the plot again from the pickled data:

import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import pickle

if 0: # to generate the file
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10.0 * (Z2 - Z1)

ax = plt.subplot(111)
CS = ax.contourf(X, Y, Z)

pickle.dump(ax, open("mpl_test.pkl", "w"))
pickle.dump(CS, open("contours.pkl", "w"))

else: # Then at a later time...

x0 = pickle.load(open("mpl_test.pkl", "r"))
x1 = pickle.load(open("contours.pkl", "r"))

v = x1.collections[0].get_paths()[0].vertices # get the vertices of the contour
x, y = v[:,0]+.2, v[:,1]+.1 # shift the contour
x0.plot(x, y, 'w', linewidth=3) # add it to the plot as a white line

The example above first pickles the contour plot with the if clause, and then, at a latter time, using the else part. It then takes one of the contours and shifts it and replots it as a white line.

That is, this figure and modified contour are drawn completely from the reloaded pickled figure.

Sample Image

Contours, are mpl Paths, and can be more complicated than this example implies, so this method won't always work so well (though a generalized version of it the took into account other path data would -- see the docs linked above).

Pickling mpl items is a bit new and not fully documented or reliable, but is a useful feature.

IPython Notebook:

On the other hand, maybe what you really want is something like an IPython Notebook! There, the whole history of your computations is available, viewable, and runnable. Rather than storing the data, it allows you to easily re-access, modify what you did before, etc. It's very powerful. Here are a few links and examples: A, B, C, D.

matplotlib figure to numpy array without white borders

I guess subplots_adjust is the key here. Seems to work with a toy example but it would be great it you could provide minimal working code to see if it works in your use case.

import numpy as np
import matplotlib as mpl
# mpl.use('Agg')
import matplotlib.pyplot as plt

img = np.ones((100, 200))
img[25:75, 50:150] = 0

fig = plt.figure()
ax = fig.gca()

ax.imshow(img)
ax.axis('tight')

plt.subplots_adjust(0,0,1,1,0,0)

plt.show()

data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
w, h = fig.canvas.get_width_height()
data = data.reshape((h, w, 3))

plt.close()

how to save this Matplotlib drawing as a Numpy array?

The problem is that your fig variable is not a figure but an AxesImage as the error is stating. Thus change the first line of your code with :

fig, ax = plt.subplots()
ax = plt.imshow(imdata)

The complete function is then :

def draw_boxes(imdata, v_boxes, v_labels, v_scores):
fig, ax = plt.subplots()
ax = plt.imshow(imdata)
# get the context for drawing boxes
ax = pyplot.gca()
# plot each box
for i in range(len(v_boxes)):
box = v_boxes[i]
# get coordinates
y1, x1, y2, x2 = box.ymin, box.xmin, box.ymax, box.xmax
# calculate width and height of the box
width, height = x2 - x1, y2 - y1
# create the shape
rect = Rectangle((x1, y1), width, height, fill=False, color='white')
# draw the box
ax.add_patch(rect)
# draw text and score in top left corner
label = "%s (%.3f)" % (v_labels[i], v_scores[i])
ax.text(x1, y1, label, color='white')
fig.canvas.draw()
X = np.array(fig.canvas.renderer.buffer_rgba(), dtype=float)
return X

Convert Matplotlib Figure to greyscale and b&w numpy array

Thanks to the answers from the following posts on conversion to RGB array and conversion to grayscale and/or b&w array, I have managed to solve the problem with the following code:

DPI = 300

# data sample
data = np.array([88, 70, 88.67903235, 50, 20, 88.66447851, 70, 88.65119164, 60])
time = np.array([1,2,3,4,5,6,7,8,9])

# plot the figure without axes and margins
f = plt.figure(figsize=(3,3), dpi = DPI)
ax = f.add_axes([0,0,1,1]) # remove margins
ax.set_ylim(time[0], time[len(time)-1]) # y limits
ax.set_xlim(0, 150) # x limits
ax.set_ylim(ax.get_ylim()[::-1]) # invert y-axis
ax.plot(data, time, "black") # plot the line in black
ax.axis('off') # turn off axes

import io
io_buf = io.BytesIO()
f.savefig(io_buf, format='raw', dpi=DPI)
io_buf.seek(0)
img_arr = np.reshape(np.frombuffer(io_buf.getvalue(), dtype=np.uint8),
newshape=(int(f.bbox.bounds[3]), int(f.bbox.bounds[2]), -1))

from PIL import Image
col = Image.fromarray(img_arr) # RGB image
gray = col.convert('L') # grayscale image
bw = gray.point(lambda x: 0 if x<128 else 255, '1') # b&wimage

# saving
path = "C:/Users/<id>/<folder>/"

bw.save(path+"result_bw.png")
gray.save(path+"result_gray.png")
col.save(path+"result_col.png")


Related Topics



Leave a reply



Submit