Filling Areas (fill_between)

Reviewed & published by Brayan K

fill_between is a Matplotlib function that shades the area between a curve and a baseline — or between two curves — making it easy to highlight gaps, ranges, and confidence bands at a glance.

Part of the free Matplotlib course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

In this lesson you'll fill under a curve, shade the region between two lines, use the where argument to fill conditionally, build a confidence band, and flip the fill with fill_betweenx.

What You'll Learn in This Lesson

1 Filling Under a Curve

The simplest use of ax.fill_between() shades the area between a curve and the line y = 0. Pass your x and y arrays and Matplotlib paints everything below the curve. Combine it with a regular ax.plot() on top and a low alpha so the outline stays crisp while the area is softly tinted.

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)

fig, ax = plt.subplots()
ax.plot(x, y, color="navy")
ax.fill_between(x, y, color="navy", alpha=0.25)

ax.set_title("Area Under a Sine Wave")
ax.set_xlabel("x")
ax.set_ylabel("sin(x)")

plt.show()
The chart this code draws: Shade the area between sin(x) and zero
What this code draws, rendered with Matplotlib.

What you'll see: a navy sine wave with the space between it and the x-axis softly tinted. Where the curve dips below zero in the second half, the shading appears below the axis — fill_between follows the curve in both directions.

2 Between Two Curves & Conditional Fills

Pass two y arrays and fill_between shades the gap between them — perfect for showing the spread between a high and a low series. Add the where= argument with a boolean condition to fill only part of the range. A classic example shades green where one curve beats another and red where it loses.

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 12, 200)
revenue = 50 + 10 * np.sin(x) + x
cost    = 55 + 8 * np.cos(x)

fig, ax = plt.subplots()
ax.plot(x, revenue, label="Revenue", color="black")
ax.plot(x, cost, label="Cost", color="gray")

# Green where we profit, red where we lose
ax.fill_between(x, revenue, cost, where=(revenue >= cost),
                color="green", alpha=0.4, label="Profit")
ax.fill_between(x, revenue, cost, where=(revenue < cost),
                color="red", alpha=0.4, label="Loss")

ax.set_title("Profit vs Loss Zones")
ax.set_xlabel("Week")
ax.legend()

plt.show()
The chart this code draws: Shade profit green and loss red
What this code draws, rendered with Matplotlib.

What you'll see: two wavy lines crossing back and forth. Where revenue rises above cost the gap fills green; where it dips below, the gap fills red. The alternating colored patches make profit and loss periods pop out instantly.

3 Confidence Bands & fill_betweenx

A confidence band is just a fill between y - err and y + err wrapped around a line — the same trick we used in the error bars lesson, now in its natural home. And when your independent variable runs up the vertical axis, reach for ax.fill_betweenx(), which shades between two x values across a range of y.

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.log1p(x) * 3
err = 0.3 + 0.15 * x

fig, ax = plt.subplots()
ax.plot(x, y, color="crimson", label="Trend")
ax.fill_between(x, y - err, y + err,
                color="crimson", alpha=0.2, label="Uncertainty")

# A vertical highlight band using fill_betweenx
ax.fill_betweenx(y, 4, 6, color="gray", alpha=0.15)

ax.set_title("Confidence Band + Highlighted Region")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()

plt.show()
The chart this code draws: Combine a confidence band with a vertical highlight
What this code draws, rendered with Matplotlib.

What you'll see: a crimson curve rising and leveling off, hugged by a soft red band that widens to the right. A faint gray vertical stripe between x = 4 and x = 6 (drawn with fill_betweenx) highlights that slice of the plot.

🎯 Your Turn: Fill in the Blanks

Replace each ___ to draw a line and shade a translucent band around it.

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 6, 60)
y = np.cos(x) + 2
err = 0.3

fig, ax = plt.subplots()
ax.plot(x, y, color="teal")

# Shade between y - err and y + err, semi-transparent
ax.___(x, y - err, y ___ err, color="teal", alpha=___)

ax.set_title("Cosine With a Band")

plt.show()

📋 Common Errors & Quick Reference

❌ The fill hides my line

Draw the fill first or lower its alpha. A solid fill at alpha=1 will paint right over the line.

❌ Gaps appear at the crossing points

When using where=, add interpolate=True so the shaded regions meet exactly where the curves cross.

❌ ValueError: arrays must be the same length

Your x, lower, and upper arrays must all match in length. Build the bounds from the same x.

CallWhat It Does
ax.fill_between(x, y)Fill down to y = 0
ax.fill_between(x, lo, hi)Fill between two curves
where=(a > b)Fill only where True
alpha=0.3Make the fill see-through
ax.fill_betweenx(y, l, r)Fill horizontally

🎯 Mini-Challenge: Temperature Range

Plot the average daily temperature with a shaded band between the daily low and high, and mark the freezing line.

import matplotlib.pyplot as plt
import numpy as np

days = np.arange(1, 31)
avg = 5 + 8 * np.sin(days / 5)
low = avg - 4
high = avg + 4

fig, ax = plt.subplots(figsize=(9, 4))
ax.plot(days, avg, color="darkblue", label="Average")
ax.fill_between(days, low, high, color="skyblue", alpha=0.5,
                label="Low-High range")

# Shade below freezing in light red
ax.fill_between(days, low, 0, where=(low < 0),
                color="red", alpha=0.2, interpolate=True,
                label="Below freezing")
ax.axhline(0, color="gray", linestyle="--", linewidth=1)

ax.set_title("Daily Temperature Range")
ax.set_xlabel("Day")
ax.set_ylabel("Temp (C)")
ax.legend()

plt.tight_layout()
plt.show()
The chart this code draws: Band between low and high, plus a freezing highlight
What this code draws, rendered with Matplotlib.
import matplotlib.pyplot as plt

x = [0, 1, 2, 3, 4]
low = [1, 2, 2, 3, 4]
high = [3, 4, 5, 6, 8]

fig, ax = plt.subplots()
band = ax.fill_between(x, low, high, alpha=0.3, color="tab:blue", label="range")
mid = ax.plot(x, [(a + b) / 2 for a, b in zip(low, high)], color="tab:blue", label="middle")
ax.legend()

print("Filled areas:", len(ax.collections))
print("Lines on top:", len(ax.lines))
print("Band label:", band.get_label())
print("Band transparency:", band.get_alpha())
print("Middle values:", [(a + b) / 2 for a, b in zip(low, high)])
print("Legend entries:", [t.get_text() for t in ax.get_legend().get_texts()])

# ✅ Expected output:
# Filled areas: 1
# Lines on top: 1
# Band label: range
# Band transparency: 0.3
# Middle values: [2.0, 3.0, 3.5, 4.5, 6.0]
# Legend entries: ['range', 'middle']
The chart this code draws: A filled band is a collection, not a line — count both, and read the legend that names them
What this code draws, rendered with Matplotlib.

❓ Frequently Asked Questions

Lesson complete — you can shade meaningful regions!

You filled under a curve, shaded between two lines, used where to fill conditionally, built a confidence band, and flipped the fill with fill_betweenx.

Practice quiz

By default, ax.fill_between(x, y) shades the area between the curve and what?

  • The top of the figure
  • The line y = 0
  • The mean of y
  • The first data point

Answer: The line y = 0. With a single y array, fill_between shades down to the horizontal line y = 0.

How do you shade the region between two curves?

  • ax.fill_between(x, y1, y2)
  • ax.fill(x, y1) twice
  • ax.plot(x, y1, y2)
  • ax.between(y1, y2)

Answer: ax.fill_between(x, y1, y2). Passing two y arrays, fill_between(x, y1, y2), shades the gap between them.

Which argument fills only where a condition is True?

  • mask=
  • only=
  • where=
  • cond=

Answer: where=. Pass a boolean array to where= and Matplotlib fills only the True x positions.

How do you make the fill semi-transparent?

  • transparent=True
  • alpha=0.3
  • opacity=0.3
  • fade=0.3

Answer: alpha=0.3. alpha takes a value between 0 and 1; lower numbers are more see-through.

What does fill_betweenx do differently from fill_between?

  • It fills between two x values across a range of y
  • It only fills triangles
  • It uses 3D
  • It ignores alpha

Answer: It fills between two x values across a range of y. fill_betweenx flips the roles, shading between two x values across a range of y.

Which argument removes gaps at the crossing points of two curves?

  • smooth=True
  • interpolate=True
  • snap=True
  • close=True

Answer: interpolate=True. interpolate=True makes the shaded regions meet exactly where the curves cross.

How do you fill between a curve and the line y = 5 (not 0)?

  • ax.fill_between(x, y, 5)
  • ax.fill_between(x, 5)
  • ax.fill_between(x, y, base=5)
  • ax.fill_between(x, y, offset=5)

Answer: ax.fill_between(x, y, 5). Pass 5 as the third positional argument to fill down to the line y = 5.

A confidence band around a line is drawn by filling between which bounds?

  • 0 and y
  • y and 2*y
  • y - err and y + err
  • min(y) and max(y)

Answer: y - err and y + err. A band is just ax.fill_between(x, y - err, y + err) wrapped around the line.

For where= to work correctly, the x, lower, and upper arrays must be...

  • Different lengths
  • The same length
  • Sorted descending
  • Integers only

Answer: The same length. All three arrays must match in length; build the bounds from the same x.

If a solid fill hides your line, a good fix is to...

  • Increase alpha to 1
  • Lower alpha or draw the fill first
  • Remove the line
  • Use fill_betweenx

Answer: Lower alpha or draw the fill first. Lower the fill's alpha (or draw it before the line) so the line stays visible.

Continue this course

Frequently asked questions

What does ax.fill_between() actually fill?

By default ax.fill_between(x, y) shades the area between the curve y and the horizontal line y = 0. If you pass two curves, ax.fill_between(x, y1, y2), it shades the region between them. This is perfect for highlighting a gap, a range, or a confidence band around a line.

How do I shade only part of a curve?

Pass a boolean array to the where= argument. Matplotlib fills only the x positions where the condition is True. For example, where=(y > 0) shades only the parts of the curve above zero, which is great for marking surplus versus deficit.

What is the difference between fill_between and fill_betweenx?

fill_between fills vertically — it shades between two y values across a range of x. fill_betweenx flips the roles: it shades between two x values across a range of y, which is useful when your independent variable runs up the vertical axis.

How do I make the fill semi-transparent so I can still see the line?

Set the alpha argument to a value between 0 and 1, such as alpha=0.3. Lower numbers are more see-through. This lets a solid line and other plot elements show clearly through the shaded region.