Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does matplotlib fill_between draw edgelines only on a PDF?

In python's matplotlib.fill_between the following minimal working example below draws correctly to the screen, and to the .png. In the resulting .pdf however, the edge lines are still drawn. How can I fix this?

from numpy import *
import pylab as plt

# Sample data
X  = linspace(0,2*pi,1000)
Y0 = sin(X)
Y1 = sin(X+.2)
Y2 = sin(X+.4)

# fill_kwargs (what am I missing?)
fbk = {'lw':0.0, 'edgecolor':None}

ax = plt.subplot(111)
ax.fill_between(X, 0, Y0 , facecolor = 'b', **fbk)
ax.fill_between(X, Y0, Y1, facecolor = 'g', **fbk)
ax.fill_between(X, Y1, Y2, facecolor = 'r', **fbk)
plt.xlim(pi-.8,pi+.5)
plt.ylim(-.5,.5)

plt.savefig('fA.png')  # No edge lines
plt.savefig('fA.pdf')  # Edge lines!

PNG result

enter image description here

PDF result

enter image description here

While it seems trivial, it becomes extremely problematic when you stack 200 fill_between plots, all you see is an ugly mess of black!

like image 699
Hooked Avatar asked Jan 03 '13 16:01

Hooked


People also ask

How do I fill between in Matplotlib?

Matplotlib fill between three lines Firstly we fill the area, between y1 and y2 by using the fill_between() method and we set the color red by using the parameter color. Then we fill the area, between y2 and y3 by using the fill_between() method and we set its color to yellow by using a color parameter.

How do I fill multiple lines in Matplotlib?

We can fill an area between multiple lines in Matplotlib using the matplotlib. pyplot. fill_between() method. The fill_between() function fills the space between two lines at a time, but we can select one pair of lines to fill the area between multiple lines.

How do I plot a shaded area in Matplotlib?

MatPlotLib with Python Plot x and y data points, with color=red and linewidth=2. To shade an area parallel to X-axis, initialize two variables, y1 and y2. To add horizontal span across the axes, use axhspan() method with y1, y2, green as shade color,and alpha for transprency of the shade.


2 Answers

It's not perfect, but I've found a solution (and will accept a better one if it comes). Apparently postscript might be to blame:

... note that interpreting a linewidth of zero as a 1 pixel wide line is what PostScript does. So the only way to get a true zero width for PostScript output is to fill the polygon without stroking it.

The solution is to make the edgecolor the same as the facecolor. This works, but if the facecolor has a transparency it seems that the edgecolor does not get that same transparency value.

like image 53
Hooked Avatar answered Oct 13 '22 08:10

Hooked


It's not pretty at all, but if you set it to None, it will throw this error:

Traceback (most recent call last): File "/usr/local/lib/python2.7/site-packages/matplotlib/artist.py", line 59, >in draw_wrapper draw(artist, renderer, *args, **kwargs) File "/usr/local/lib/python2.7/site-packages/matplotlib/figure.py", line 1085, >in draw func(*args) File "/usr/local/lib/python2.7/site-packages/matplotlib/artist.py", line 59, > in draw_wrapper draw(artist, renderer, *args, **kwargs) File "/usr/local/lib/python2.7/site-packages/matplotlib/axes/_base.py", line > 2110, in draw a.draw(renderer) File "/usr/local/lib/python2.7/site-packages/matplotlib/artist.py", line 59, > in draw_wrapper draw(artist, renderer, *args, **kwargs) File "/usr/local/lib/python2.7/site-packages/matplotlib/lines.py", line 694, >in draw gc.set_linewidth(self._linewidth) TypeError: a float is required

and continue to render without the line. Stacked violin plots work now with Seaborn!

with 0.0 linewidth:

with 0.0 linewidth

with None:

Using None

like image 29
Rob Bird Avatar answered Oct 13 '22 10:10

Rob Bird