Vector and raster in one with Matplotlib

Vector images are great, except when they shouldn’t be vector. Figures with intricate detail can actually benefit from being rasterized. This can reduce file size and help the figure load more quickly. Python’s Matplotlib has an option to rasterize certain elements, but it doesn’t always work as simply as expected.

This post describes a function that (i) lets you rasterize any chosen elements when you export the figure and (ii) overcomes problems with the current implementation of rasterizing objects with Matplotlib.

How to rasterize in Matplotlib

For most plot types, it is as simple as including

rasterized=True

in the call to, say, pcolormesh or scatter. For example,

from numpy.random import randn
N = 10000
plt.scatter(x=randn(N), y=randn(N), s=20*randn(N),
            rasterized=True)

The resolution of the rasterization is set by the dpi argument when saving:

plt.savefig('output.pdf', dpi=300)

Simplifying matters

Setting rasterized=True does not always work as easily as you might expect. For example, filled contour plots (plt.contourf) appear to ignore the setting and Basemap maps (m.fillcontinents) don’t give the option. Furthermore, it would be simpler if we could specify which objects to rasterize when we export the figure as opposed to early in the code. For these reasons, I have developed a function entitled rasterize_and_save that works much like plt.savefig, but takes as an argument a list of objects to rasterize.

Consider an example containing various plot types. We want to rasterize all but the line plot.

from numpy.random import randn
X, Y, Z = randn(9, 9), randn(9, 9), randn(9, 9)

fig, axs = plt.subplots(ncols=2, nrows=2)
(ax1, ax2), (ax3, ax4) = axs

cax1 = ax1.contourf(Z)
cax2 = ax2.scatter(X, Y, s=Z)
cax3 = ax3.pcolormesh(Z)
cax4 = ax4.plot(Z[:, 0])

rasterize_list = [cax1, cax2, cax3]
rasterize_and_save('out.svg', rasterize_list, dpi=300)

All but the last two lines will be familiar to Matplotlib users. The penultimate line specifies which objects will be rasterized. The final line exports the figure as an svg image at a resolution of 300 dpi. Here’s the (annotated) result:

rasterize_example.svg

Keeping some of the panels as vector elements is as simple as changing the objects contained in rasterize_list. Also, note how the contour plot is rasterized. This works because the rasterize_and_save function does the hard work of changing the rasterized setting on each filled contour individually.

Author: Ken Hughes

Post-doctoral research scientist in physical oceanography

3 thoughts on “Vector and raster in one with Matplotlib”

  1. Thanks for posting this. However, how do you use this with other savefig keyword arguments? I’d like to include “bbox_inches = ‘tight'”; however, no approach I use allows this to be recognized. Thanks again!

    1. The raster_and_save function includes an argument entitled savefig_kw that allows you to pass extra keyword options to savefig as a dict. In your case, you want something like raster_and_save(…, savefig_kw=dict(bbox_inches=’tight’))

Comments are closed.

%d bloggers like this: