Disclaimer: this is more an explanation + hack than a real answer.
I believe that there is a fundamental problem the way matplotlib makes contour plots. Essentially, all contours are collections of lines (LineCollection
), while they should be collection of possibly closed lines (PolyCollection
). There might be good reasons why things are done this way, but in the simple example I made this choice clearly produces artifacts. A not-very-nice solution is to convert a posteriori all LineCollection
's into PolyCollection
's. This is what is done in the following code
from matplotlib.collections import PolyCollection
eps = 1e-5
plt.gca().set_aspect('equal')
x,y = np.meshgrid(np.linspace(-1,1,100), np.linspace(-1,1,100))
r = x*x + y*y
plt.contour(np.log(r/1.2))
ca = plt.gca()
N = len(ca.collections)
for n in range(N):
c = ca.collections.pop(0)
for s in c.get_segments():
closed = (abs(s[0,0] - s[-1,0]) < eps) and (abs(s[0,1] - s[-1,1]) < eps)
p = PolyCollection([s], edgecolors=c.get_edgecolors(),
linewidths=c.get_linewidths(), linestyles=c.get_linestyles(),
facecolors=c.get_facecolors(), closed=closed)
ca.add_collection(p)
plt.savefig("test.pdf")
A zoom of the result obtained shows that everything is OK now:

Some care is taken to check if a contour is closed: in the present code, this is done with an approximate equality check for the first and last point: I am wandering if there is a better way to do this (perhaps matplotlib returns some data to check closed contours?). In any case, again, this is hack: I would be happy to hear if anyone has a better solution (or has a way to fix this within matplotlib).