Closed lines in matplotlib contour plots
<p>When looking closely at contour plots made with matplotlib, I noticed that smaller contours have inaccurate endpoints which do not close perfectly in PDF figures.  Consider the minimal example:</p>

<pre><code>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))
plt.savefig("test.pdf")
</code></pre>

<p>The central part of the resulting test.pdf file, shown below, clearly shows the problem.  Is there a way to solve this or is it a bug/intrinsic inaccuracy of matploplib?</p>

<p><a href="http://i.stack.imgur.com/NJWKC.png" rel="nofollow"><img src="http://i.stack.imgur.com/NJWKC.png" alt="enter image description here"></a></p>

<p>Disclaimer: this is more an <strong>explanation + hack</strong> than a real answer.</p>

<p>I believe that there is a fundamental problem the way matplotlib makes contour plots.  Essentially, all contours are collections of lines (<code>LineCollection</code>), while they should be collection of possibly closed lines (<code>PolyCollection</code>).  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 <code>LineCollection</code>'s into <code>PolyCollection</code>'s.  This is what is done in the following code</p>

<pre><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]) &lt; eps) and (abs(s[0,1] - s[-1,1]) &lt; 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")
</code></pre>

<p>A zoom of the result obtained shows that everything is OK now:</p>

<p><a href="http://i.stack.imgur.com/rEP4i.png" rel="nofollow"><img src="http://i.stack.imgur.com/rEP4i.png" alt="enter image description here"></a></p>

<p>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).</p>

python pdf matplotlib contour