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

2

13

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

Leilaleilah answered 4/4, 2013 at 21:34 Comment(2)
Those look like Moiré patterns to me. With the pdf the pattern changes based on the zoom level.Towage
@arne: The files linked are gone - any chance of replacing them?Imena
V
22

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')
Vestavestal answered 2/10, 2015 at 16:32 Comment(0)
C
7

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.

Contrary answered 5/4, 2013 at 10:1 Comment(6)
Hi pelson. I went for your second solution, and it worked really well. Thanks a lot.Leilaleilah
I can also confirm this behaviour, if I save contourf() with levels, in either PS,EPS,PDF but not in SVG output. Also running this kind of PS/EPS/PDF through GhostScript and outputting for example PNG at 300dpi, shows no issue, but viewing PDF in Acrobat, SumatraPDF (uses mupdf engine, disigned by same people behind GhostScript), CorelDraw, Ipe,... all show this artifact as visible.Septicidal
More into, it's not that contours have outlines, but there is tiny gap between contours and white background of the plot window is what shows as contour outline.Septicidal
@pelson's trick with contour lines is good, it seems it fills the gaps just fine. Another one would be to plot the array with imshow() before calling contourf() - this way plot background will mach contour boundary and gaps will be invisible. Or of course just use SVG and print it to PDF or PS...Septicidal
Id had the same issue in SVG and your second solution fixed it - but I had to manually specify the zorder as I had some hatched overlays generated with fill_between, and the contour was on top of those.Imena
Thanks pelson, your second solution works well, even in polar contour plots. Better yet, one can set zorder=1.5 so that the contours are placed in the right order.Gon

© 2022 - 2024 — McMap. All rights reserved.