Skip to content

Commit 0877fa6

Browse files
committed
Improve example for fill_between
1 parent efafb6c commit 0877fa6

File tree

1 file changed

+116
-48
lines changed

1 file changed

+116
-48
lines changed

examples/lines_bars_and_markers/fill_between_demo.py

Lines changed: 116 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,76 +3,144 @@
33
Filling the area between lines
44
==============================
55
6-
This example shows how to use ``fill_between`` to color between lines based on
7-
user-defined logic.
6+
This example shows how to use `~.axes.Axes.fill_between` to color the area
7+
between two lines.
88
"""
99

1010
import matplotlib.pyplot as plt
1111
import numpy as np
1212

13+
###############################################################################
14+
#
15+
# Basic usage
16+
# -----------
17+
# The parameters *y1* and *y2* can be a scalar, indicating a horizontal
18+
# boundary a the given y-values. If only *y1* is given, *y2* defaults to 0.
19+
1320
x = np.arange(0.0, 2, 0.01)
1421
y1 = np.sin(2 * np.pi * x)
15-
y2 = 1.2 * np.sin(4 * np.pi * x)
22+
y2 = 0.8 * np.sin(4 * np.pi * x)
1623

17-
###############################################################################
24+
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex=True, figsize=(6, 6))
1825

19-
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, sharex=True)
20-
21-
ax1.fill_between(x, 0, y1)
22-
ax1.set_ylabel('between y1 and 0')
26+
ax1.fill_between(x, y1)
27+
ax1.set_title('fill between y1 and 0')
2328

2429
ax2.fill_between(x, y1, 1)
25-
ax2.set_ylabel('between y1 and 1')
30+
ax2.set_title('fill between y1 and 1')
2631

2732
ax3.fill_between(x, y1, y2)
28-
ax3.set_ylabel('between y1 and y2')
33+
ax3.set_title('fill between y1 and y2')
2934
ax3.set_xlabel('x')
35+
fig.tight_layout()
3036

3137
###############################################################################
32-
# Now fill between y1 and y2 where a logical condition is met. Note
33-
# this is different than calling
34-
# ``fill_between(x[where], y1[where], y2[where] ...)``
35-
# because of edge effects over multiple contiguous regions.
36-
37-
fig, (ax, ax1) = plt.subplots(2, 1, sharex=True)
38-
ax.plot(x, y1, x, y2, color='black')
39-
ax.fill_between(x, y1, y2, where=y2 >= y1, facecolor='green', interpolate=True)
40-
ax.fill_between(x, y1, y2, where=y2 <= y1, facecolor='red', interpolate=True)
41-
ax.set_title('fill between where')
42-
43-
# Test support for masked arrays.
44-
y2 = np.ma.masked_greater(y2, 1.0)
45-
ax1.plot(x, y1, x, y2, color='black')
46-
ax1.fill_between(x, y1, y2, where=y2 >= y1,
47-
facecolor='green', interpolate=True)
48-
ax1.fill_between(x, y1, y2, where=y2 <= y1,
49-
facecolor='red', interpolate=True)
50-
ax1.set_title('Now regions with y2>1 are masked')
38+
#
39+
# Example: Confidence bands
40+
# -------------------------
41+
# A common application for `~.axes.Axes.fill_between` is the indication of
42+
# confidence bands.
43+
#
44+
# `~.axes.Axes.fill_between` uses the colors of the color cycle as the fill
45+
# color. These may be a bit strong when applied to fill areas. It is
46+
# therefore often a good practice to lighten the color by making the area
47+
# semi-transparent using *alpha*.
48+
49+
# sphinx_gallery_thumbnail_number = 2
50+
51+
N = 21
52+
x = np.linspace(0, 10, 11)
53+
y = [3.9, 4.4, 10.8, 10.3, 11.2, 13.1, 14.1, 9.9, 13.9, 15.1, 12.5]
54+
55+
# fit a linear curve an estimate its y-values and their error.
56+
a, b = np.polyfit(x, y, deg=1)
57+
y_est = a * x + b
58+
y_err = x.std() * np.sqrt(1/len(x) +
59+
(x - x.mean())**2 / np.sum((x - x.mean())**2))
60+
61+
fig, ax = plt.subplots()
62+
ax.plot(x, y_est, '-')
63+
ax.fill_between(x, y_est - y_err, y_est + y_err, alpha=0.2)
64+
ax.plot(x, y, 'o', color='tab:brown')
5165

5266
###############################################################################
53-
# This example illustrates a problem; because of the data
54-
# gridding, there are undesired unfilled triangles at the crossover
55-
# points. A brute-force solution would be to interpolate all
56-
# arrays to a very fine grid before plotting.
67+
#
68+
# Selectively filling horizontal regions
69+
# --------------------------------------
70+
# The parameter *where* allows to specify the x-ranges to fill. It's a boolean
71+
# array with the same size as *x*.
72+
#
73+
# Only x-ranges of contiguous *True* sequences are filled. As a result the
74+
# range between neighboring *True* and *False* values is never filled. This
75+
# often undesired when the data points should represent a contiguous quantity.
76+
# It is therefore recommended to set ``interpolate=True`` unless the
77+
# x-distance of the data points is fine enough so that the above effect is not
78+
# noticeable. Interpolation approximates the actual x position at which the
79+
# *where* condition will change and extends the filling up to there.
80+
81+
x = np.array([0, 1, 2, 3])
82+
y1 = np.array([0.8, 0.8, 0.2, 0.2])
83+
y2 = np.array([0, 0, 1, 1])
84+
85+
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
86+
87+
ax1.set_title('interpolation=False')
88+
ax1.plot(x, y1, 'o--')
89+
ax1.plot(x, y2, 'o--')
90+
ax1.fill_between(x, y1, y2, where=(y1 > y2), color='C0', alpha=0.3)
91+
ax1.fill_between(x, y1, y2, where=(y1 < y2), color='C1', alpha=0.3)
92+
93+
ax2.set_title('interpolation=True')
94+
ax2.plot(x, y1, 'o--')
95+
ax2.plot(x, y2, 'o--')
96+
ax2.fill_between(x, y1, y2, where=(y1 > y2), color='C0', alpha=0.3,
97+
interpolate=True)
98+
ax2.fill_between(x, y1, y2, where=(y1 <= y2), color='C1', alpha=0.3,
99+
interpolate=True)
100+
fig.tight_layout()
57101

102+
###############################################################################
103+
#
104+
# .. note::
105+
#
106+
# Similar gaps will occur if *y1* or *y2* are masked arrays. Since missing
107+
# values cannot be approximated, *interpolate* has no effect in this case.
108+
# The gaps around masked values can only be reduced by adding more data
109+
# points close to the masked values.
58110

59111
###############################################################################
60-
# Use transforms to create axes spans where a certain condition is satisfied:
112+
#
113+
# Selectively marking horizontal regions across the whole Axes
114+
# ------------------------------------------------------------
115+
# The same selection mechanism can be applied to fill the full vertical height
116+
# of the axes. To be independent of y-limits, we add a transform that
117+
# interprets the x-values in data coorindates and the y-values in axes
118+
# coordinates.
119+
#
120+
# The following example marks the regions in which the y-data are above a
121+
# given threshold.
61122

62123
fig, ax = plt.subplots()
63-
y = np.sin(4 * np.pi * x)
124+
x = np.arange(0, 4 * np.pi, 0.01)
125+
y = np.sin(x)
64126
ax.plot(x, y, color='black')
65127

66-
# use data coordinates for the x-axis and the axes coordinates for the y-axis
67-
import matplotlib.transforms as mtransforms
68-
trans = mtransforms.blended_transform_factory(ax.transData, ax.transAxes)
69-
theta = 0.9
70-
ax.axhline(theta, color='green', lw=2, alpha=0.5)
71-
ax.axhline(-theta, color='red', lw=2, alpha=0.5)
72-
ax.fill_between(x, 0, 1, where=y > theta,
73-
facecolor='green', alpha=0.5, transform=trans)
74-
ax.fill_between(x, 0, 1, where=y < -theta,
75-
facecolor='red', alpha=0.5, transform=trans)
76-
77-
78-
plt.show()
128+
threshold = 0.75
129+
ax.axhline(threshold, color='green', lw=2, alpha=0.7)
130+
ax.fill_between(x, 0, 1, where=y > threshold,
131+
color='green', alpha=0.5, transform=ax.get_xaxis_transform())
132+
133+
#############################################################################
134+
#
135+
# ------------
136+
#
137+
# References
138+
# """"""""""
139+
#
140+
# The use of the following functions, methods and classes is shown
141+
# in this example:
142+
143+
import matplotlib
144+
matplotlib.axes.Axes.fill_between
145+
matplotlib.pyplot.fill_between
146+
matplotlib.axes.Axes.get_xaxis_transform

0 commit comments

Comments
 (0)