200

In matplotlib, how do I plot error as a shaded region rather than error bars?

For example:

enter image description here

rather than

enter image description here

Georgy
  • 12,464
  • 7
  • 65
  • 73
Austin Richardson
  • 8,078
  • 13
  • 43
  • 49
  • Does this answer your question? [Plotting shaded uncertainty region in line plot in matplotlib when data has NaNs](https://stackoverflow.com/questions/43064524/plotting-shaded-uncertainty-region-in-line-plot-in-matplotlib-when-data-has-nans) – Reinderien Apr 18 '20 at 22:04

2 Answers2

208

Ignoring the smooth interpolation between points in your example graph (that would require doing some manual interpolation, or just have a higher resolution of your data), you can use pyplot.fill_between():

from matplotlib import pyplot as plt
import numpy as np

x = np.linspace(0, 30, 30)
y = np.sin(x/6*np.pi)
error = np.random.normal(0.1, 0.02, size=y.shape)
y += np.random.normal(0, 0.1, size=y.shape)

plt.plot(x, y, 'k-')
plt.fill_between(x, y-error, y+error)
plt.show()

enter image description here

See also the matplotlib examples.

Gabriel
  • 40,504
  • 73
  • 230
  • 404
  • 1
    Perfect. Yeah I didn't mean to include an example with smoothed lines. – Austin Richardson Oct 18 '12 at 15:49
  • Any idea how to make this show shaded boxes instead of a shaded band? My first instinct was to abuse `lw` but it appears to not use the same units as the axes. – Benjamin Bannier Aug 27 '13 at 20:30
  • @BenjaminBannier I'm not fully sure what you mean. It sounds as if you'd like a box drawn at each point, its height the same as that of the error bar, while the width should be such that they connect (touch) the neighbouring boxes. Is that correct? –  Aug 28 '13 at 09:13
  • Is there a way to combine the blue fill_between and the black plot as one entry in the legend? – EL_DON Aug 26 '16 at 05:36
  • 2
    @EL_DON You mean you'd like a legend with a black line + blue band, and the text would be something like "data + 1 sigma error region"? –  Aug 26 '16 at 06:27
  • @Evert Yes, exactly. – EL_DON Aug 26 '16 at 16:46
  • What if errorbars are horizontal? I don't seem to know a way of doing it. Any idea? – Rebel Apr 27 '17 at 05:45
  • 1
    @Allan if the only error bars you have are horizontal, you probably should flip the axes of your actual problem (and thus the figure as well). Normally, the independent variable is the one without (or with very small) error bars. You may be able to cheat, by swapping your data variables, and in matplotlib, swap the axes as well. –  Apr 27 '17 at 07:40
  • @Evert. Thanks for the suggestion, – Rebel Apr 28 '17 at 02:00
  • You can create a customized function that “interpolates” (x, y) points via numpy functions (linspace or tile or extending slices) inbetween your actual (x, y) data; apply the function iteratively, switching from moving iterating across x and y per iteration, and concatenate all the x and y data in the correct order. This way, plt.fill_between(...) will feel in such a way that the shaded region will appear as n boxes instead of a shaded band. The shorter the spacing between points along an axis, the boxier the filled region will appear. –  Mar 28 '18 at 11:49
  • I think this answer would have more value if - instead of making an `error` and adding it to `y` - add some random noise to `y` and calculate quartiles. This is what (IMO) most people coming to this question are actually interested in. – Reinderien Apr 18 '20 at 22:02
157

This is basically the same answer provided by Evert, but extended to show-off some cool options of fill_between

enter image description here

from matplotlib import pyplot as pl
import numpy as np

pl.clf()
pl.hold(1)

x = np.linspace(0, 30, 100)
y = np.sin(x) * 0.5
pl.plot(x, y, '-k')


x = np.linspace(0, 30, 30)
y = np.sin(x/6*np.pi)
error = np.random.normal(0.1, 0.02, size=y.shape) +.1
y += np.random.normal(0, 0.1, size=y.shape)

pl.plot(x, y, 'k', color='#CC4F1B')
pl.fill_between(x, y-error, y+error,
    alpha=0.5, edgecolor='#CC4F1B', facecolor='#FF9848')

y = np.cos(x/6*np.pi)    
error = np.random.rand(len(y)) * 0.5
y += np.random.normal(0, 0.1, size=y.shape)
pl.plot(x, y, 'k', color='#1B2ACC')
pl.fill_between(x, y-error, y+error,
    alpha=0.2, edgecolor='#1B2ACC', facecolor='#089FFF',
    linewidth=4, linestyle='dashdot', antialiased=True)



y = np.cos(x/6*np.pi)  + np.sin(x/3*np.pi)  
error = np.random.rand(len(y)) * 0.5
y += np.random.normal(0, 0.1, size=y.shape)
pl.plot(x, y, 'k', color='#3F7F4C')
pl.fill_between(x, y-error, y+error,
    alpha=1, edgecolor='#3F7F4C', facecolor='#7EFF99',
    linewidth=0)



pl.show()
Community
  • 1
  • 1
Boris Gorelik
  • 29,945
  • 39
  • 128
  • 170
  • 1
    Slightly better solution: https://stackoverflow.com/questions/43064524/plotting-shaded-uncertainty-region-in-line-plot-in-matplotlib-when-data-has-nans – Shital Shah Apr 17 '20 at 09:11