I have a 2D array from which I want to produce a contour plot using matplotlib. Everything works fine saving as PNG (or other raster formats), however for including the figure in a paper I need to save to postscript format.
The problem is, the file I get is quite big (some MB) when I save to postscript. It looks like Matplotlib saves everything in vector format. While this makes sense for the axes and the labels, that would be degraded if rasterized, I would like to have the contour plot itself in raster format (which I know can be embedded inside a postscript). Does anybody know how to do it? I'm using the Agg backend.
You can set:
plt.gcf().set_rasterized(True)
before plt.savefig
Here is a minimal working example. I used the code from sega_sai for some time now without any problems.
from matplotlib.collections import Collection
from matplotlib.artist import allow_rasterization
import matplotlib.pyplot as plt
class ListCollection(Collection):
def __init__(self, collections, **kwargs):
Collection.__init__(self, **kwargs)
self.set_collections(collections)
def set_collections(self, collections):
self._collections = collections
def get_collections(self):
return self._collections
@allow_rasterization
def draw(self, renderer):
for _c in self._collections:
_c.draw(renderer)
def insert_rasterized_contour_plot(c):
collections = c.collections
for _c in collections:
_c.remove()
cc = ListCollection(collections, rasterized=True)
ax = plt.gca()
ax.add_artist(cc)
return cc
if __name__ == '__main__':
import numpy as np
x, y = np.meshgrid(*(np.linspace(-1,1,500),)*2)
z = np.sin(20*x**2)*np.cos(30*y)
c = plt.contourf(x,y,z,30)
plt.savefig('fig_normal.pdf')
insert_rasterized_contour_plot(c)
plt.savefig('fig_rasterized.pdf')
On my PC this results in:
fig_normal.pdf: filesize is 5810 KByte & needs ~5 sec to render in Adobe Reader
fig_rasterized.pdf: filesize is 60 KByte & renders directly in Adobe Reader
Unfortunately, I did not manage to run solution from this or this answer. However, i found an easy 1 line workaround.
So, it is possible to set rasterization level for axes
ax.set_rasterization_zorder(Z)
in such way all the objects with zorder smaller than Z will be rasterized.
For me it looked somehow like that:
plt.contourf(<all plotting properties>, zorder=-2)
ax.set_rasterization_zorder(-1)
In such way contours are in raster format, but all other objects (lines, text) are vectors on top of it. For my figure the size went from ~4 Mb to ~400 kb.
OK, in the end I found the answer to my own question. It required a difficult digging in the matplotlib mailing list, so I am linking here the relevant thread in the hope it will be helpful also for someone else, and possibly easier to find (by the way, no-one replied to the poor guy who sent the message).
I willl summarize here the idea in words. One has to use the set_rasterized
method, as sega_sai suggested . However, rather than applying the method to the whole figure, as I explained in my comment, the method has to be applied to the lines that comprise the contour plot. The trick is to first create a "container" for them all and to rasterize that, instead of rasterizing each individual line (which was something I already tried and gives bad results). This works fine. In the discussion I linked you can find the code for doing it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.