Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aliasing when saving matplotlib filled contour plot to .pdf or .eps

I'm generating a filed contour plot with the matplotlib.pyplot.contourf() function. The arguments in the call to the function are:

contourf(xvec,xvec,w,levels,cmap=matplotlib.cm.jet)

where

xvec = numpy.linspace(-3.,3.,50)
levels = numpy.linspace(-0.01,0.25,100)

and w is my data.

The resulting plot looks pretty good on screen, but when I save to pdf using a call to matplotlib.pyplot.savefig(), the resulting pdf has a lot of aliasing (I think that is what it is) going on. The call to savefig is simply savefig('filename.pdf'). I have tried using the dpi argument, but without luck. A call to matplotlib.get_backend() spits out 'TkAgg'.

I will attach a figure saved as pdf, compared to a figure saved as png (similar to what it looks like on screen) to demonstrate the problem:

png wihtout aliasing: https://dl.dropbox.com/u/6042643/wigner_g0.17.png

pdf with aliasing: https://dl.dropbox.com/u/6042643/wigner_g0.17.pdf

Please let me know if there are any other details I could give to help you give an answer. I should mention that saving as .eps gives similar bad results as saving to pdf. But the pdf shows the problem even clearer. My goal is to end up with a production quality .eps that I can attach to a latex document to be published as a scientific paper. I would be happy with some kind of work around where I save in one format, then convert it, if I can find a way that gives satisfying results.

Best,

Arne

like image 440
arne Avatar asked Apr 04 '13 21:04

arne


2 Answers

After using the useful answer by @pelson for a while, I finally found a proper solution to this long-standing problem (currently in Matplotlib 3), which does not require multiple calls to contour or rasterizing the figure.

I refer to my original answer here for a more extensive explanation and examples.

In summary, the solution consists of the following lines:

cnt = plt.contourf(x, y, z)

for c in cnt.collections:
    c.set_edgecolor("face")

plt.savefig('test.pdf')
like image 120
divenex Avatar answered Sep 24 '22 17:09

divenex


I had no idea that contouring in pdf was so bad. You're right, I think the contours are being anti-aliased by the PDF renderers outside of matplotlib. It is for this reason I think you need to be particularly careful which application you use to view the resulting PDF - the best behaviour I have seen is with GIMP, but I'm sure there are plenty of other viewers which perform well.

To fix this problem (when viewing the PDF with GIMP), I was able to "rasterize" the contours produced with matplotlib to avoid the ugly white line problem:

import matplotlib.pyplot as plt
import numpy as np


xs, ys = np.mgrid[0:30, 0:40]
data = (xs - 15) ** 2 + (ys - 20) ** 2 + (np.sin(ys) + 10) ** 2

cs = plt.contourf(xs, ys, data, 60, cmap='jet')

# Rasterize the contour collections
for c in cs.collections:
    c.set_rasterized(True)

plt.savefig('test.pdf')

This produced a contour plot which did not exhibit the problems you've shown.

Another alternative, perhaps better, approach, would be to fool the anti-aliasing by putting coloured lines below the contourf.

import matplotlib.pyplot as plt
import numpy as np


xs, ys = np.mgrid[0:30, 0:40]
data = (xs - 15) ** 2 + (ys - 20) ** 2 + (np.sin(ys) + 10) ** 2

# contour the plot first to remove any AA artifacts
plt.contour(xs, ys, data, 60, cmap='jet', lw=0.1)
cs = plt.contourf(xs, ys, data, 60, cmap='jet')

plt.savefig('test.pdf')

I should note that I don't see these problems if I save the figure as a ".ps" rather than a ".pdf" - perhaps that is a third alternative.

Hope this helps you get the paper looking exactly how you want it.

like image 21
pelson Avatar answered Sep 21 '22 17:09

pelson