7

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

arne
  • 587
  • 1
  • 5
  • 12
  • Those look like [Moiré patterns](https://en.wikipedia.org/wiki/Moir%C3%A9_pattern) to me. With the pdf the pattern changes based on the zoom level. – tacaswell Apr 05 '13 at 02:49
  • 2
    @arne: The files linked are gone - any chance of replacing them? – Chris H Mar 19 '14 at 16:00

2 Answers2

14

After using the useful answer by @pelson for a while, I finally found a proper solution to this long-standing problem (currently in Matplotlib 2.0), 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')
Community
  • 1
  • 1
divenex
  • 10,369
  • 8
  • 44
  • 45
6

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.

pelson
  • 18,423
  • 3
  • 80
  • 88
  • 1
    Hi pelson. I went for your second solution, and it worked really well. Thanks a lot. – arne Apr 07 '13 at 23:49
  • 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. – theta May 27 '13 at 00:22
  • 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. – theta May 27 '13 at 00:24
  • @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... – theta May 27 '13 at 00:45
  • 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. – Chris H Mar 19 '14 at 16:07