Rasterized contourf (mixed-mode rendering)?


I am trying to figure out how to produce a mixed-mode rendering PDF of a
contourf plot.

I tried something like this:

>>> from pylab import meshgrid, sin, cos, linspace, contourf, savefig, clf
>>> x, y = meshgrid(*(linspace(-1,1,500),)*2)
>>> z = sin(20*x**2)*cos(30*y)
>>> c = contourf(x,y,z,30,rasterized=True)
>>> savefig('tst0.pdf')

but this does not work. (The QuadContourSet c does not support set_rasterized()
so the rasterized argument is just ignored. Is the ignoring of the argument a
bug or a feature?)

I tried calling set_rasterized() on all of the of PathCollection objects in
c.collections but this did not help:

>>> for pc in c.collections:
>>> pc.set_rasterized(True)
>>> savefig('tst1.pdf')

While this helps, there are still 30 rasterized patches which renders slowly as
a PDF.

I found one possible solution: make a custom Collection subclass as shown below,
then remove all of the PathCollection instances from the figure, inserting
instead this new collection as a single rasterized entity:

>>> insert(c) # See code below for definition of insert()
>>> savefig('tst2.pdf')

The file-sizes are:

$ ls -lah *.pdf
... 4.2M Aug 13 02:38 tst0.pdf
... 1.8M Aug 13 02:38 tst1.pdf
... 629K Aug 13 02:40 tst2.pdf

but tst2.pdf looks as good as tst1.pdf, and is much faster to load. (There are
some faint white lines between the patches similar to those discussed before:


but the rasterizer here is in the PDF backend, so maybe something can be done?
Should I look into this as a potential bug? I am using the version of
matplotlib included with the latest EPD on a 32 bit Mac.)

Question: Is there some way of doing this with current matplotlib API, or is
some sort of extension like this required? If the latter, is there anything I
should be careful about? (The ListCollection should probably be inserted in
contourf rather than retroactively like this.)



from matplotlib.collections import Collection
from matplotlib.artist import allow_rasterization
from matplotlib import pyplot as plt

class ListCollection(Collection):
     def __init__(self, collections, **kwargs):
         Collection.__init__(self, **kwargs)
     def set_collections(self, collections):
         self._collections = collections
     def get_collections(self):
         return self._collections
     def draw(self, renderer):
         for _c in self._collections:

def insert(c):
     collections = c.collections
     for _c in collections:
     cc = ListCollection(collections, rasterized=True)
     ax = plt.gca()
     return cc