简体   繁体   中英

Matplotlib contour plots as postscript

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM