Skip to content
トピック
Matplotlib
Matplotlib fill_between:条件塗りつぶし・信頼区間バンド・isin() 対処

Matplotlib fill_between:条件塗りつぶし・信頼区間バンド・isin() 対処

公開日

更新日

plt.fill_between / ax.fill_between で曲線間を塗りつぶし、where= で条件ハイライト、信頼区間バンドを作り、isin() で index を絞るときの ValueError を直す方法。

fill_between は 2 本の y 曲線(または曲線とベースライン)のあいだを塗りつぶします。信頼区間バンド、「上側 / 下側」のハイライト、折れ線上の区間コールアウトの定番です。

クイック構文

import matplotlib.pyplot as plt
import numpy as np
 
x = np.linspace(0, 10, 200)
y1 = np.sin(x)
y2 = np.cos(x)
 
fig, ax = plt.subplots()
ax.plot(x, y1, label="sin")
ax.plot(x, y2, label="cos")
ax.fill_between(x, y1, y2, color="0.7", alpha=0.4)
ax.legend()
plt.show()
目的パターン
2 系列のあいだを塗るax.fill_between(x, y1, y2, alpha=0.3)
1 本の下を塗るax.fill_between(x, 0, y, alpha=0.3)
条件が真のところだけwhere=(y1 > y2)x と同じ長さ)
インデックス / カテゴリで絞るwhere=df.index.isin([...]) — Python の in ではない
条件の境をなめらかにinterpolate=True

fill_between がやっていること

Matplotlib は (x, y1) から (x, y2) までの多角形を描いて塗りつぶします。xy1y2 は同じ長さ(または y1 / y2 をスカラー)にします。

この一点で、「この区間を目立たせたい」系の仕事の大半が、自作パッチなしで足ります。

2 曲線のあいだを基本的に塗る

sine と cosine のあいだをすべて塗る例です。

import matplotlib.pyplot as plt
import numpy as np
 
x = np.linspace(0, 10, 300)
y1 = np.sin(x)
y2 = np.cos(x)
 
fig, ax = plt.subplots(figsize=(7.2, 4.2))
ax.plot(x, y1, label="sin(x)", color="#2563eb", lw=2)
ax.plot(x, y2, label="cos(x)", color="#dc2626", lw=2)
ax.fill_between(x, y1, y2, color="#94a3b8", alpha=0.45)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend(loc="upper right")
plt.show()

Basic fill_between between sine and cosine

よく使うつまみ:

  • alpha — 半透明にして線を読めるままにする
  • color / facecolor — 塗り色
  • linewidth=0 — 多角形の縁が線スタイルと喧嘩するなら消す
  • label= — 塗りが意味のあるカテゴリなら 凡例 に載せる

where= による条件付き塗りつぶし

x と同じ長さの真偽配列を渡し、帯の一部だけ塗ります。色を 2 つに分けたいなら呼び出しを 2 回にします。

fig, ax = plt.subplots(figsize=(7.2, 4.2))
ax.plot(x, y1, label="sin(x)", color="#2563eb", lw=2)
ax.plot(x, y2, label="cos(x)", color="#dc2626", lw=2)
 
ax.fill_between(
    x, y1, y2,
    where=(y1 > y2),
    interpolate=True,
    color="#22c55e",
    alpha=0.35,
    label="sin > cos",
)
ax.fill_between(
    x, y1, y2,
    where=(y1 <= y2),
    interpolate=True,
    color="#f97316",
    alpha=0.30,
    label="sin ≤ cos",
)
 
ax.legend(loc="upper right", ncol=2)
plt.show()

Conditional fill_between using where

なぜ interpolate=True が効くか

補間なしだと、サンプル点のあいだで条件が切り替わるところで塗りがブロック状の縦辺になりがちです。interpolate=True は交点を推定し、ハイライトが曲線に沿いやすくなります。密な連続系列では優先して使い、疎なカテゴリ x 軸では重要度は下がります。

信頼区間 / 誤差バンドのパターン

実務でいちばん多いのは「平均 ± 不確かさ」です。

t = np.linspace(0, 12, 200)
mean = np.sin(t / 1.5) + 0.15 * t
std = 0.35 + 0.08 * np.abs(np.cos(t))
 
fig, ax = plt.subplots(figsize=(7.2, 4.2))
ax.plot(t, mean, color="#0f766e", lw=2.2, label="estimate")
ax.fill_between(t, mean - std, mean + std, color="#14b8a6", alpha=0.28, label="±1σ band")
ax.set_xlabel("time")
ax.set_ylabel("value")
ax.legend(loc="upper left")
plt.show()

Confidence-style band with fill_between

分位点(p10 / p90)、予測レンジ、min/max エンベロープも同じ考え方です。塗りが強すぎるときは、中心線を あとから 描くか、z-order を上げます。

トラブルシュート: 一部のカテゴリ / 月だけ塗る

検索からこのページに来る人は、次のような失敗を一度していることが多いです。

# Broken ideas
where = plotMonths.index in ["January", "February", "March"]   # ValueError / nonsense
where = [m in ["January", "February", "March"] for m in plotMonths.index]  # may work, but isin is cleaner

何が起きているか

  • array in list は要素ごとの比較ではありません。NumPy / pandas オブジェクトは ValueError を出したり、曖昧な単一の真偽値を返したりします。
  • 必要なのは x に揃った真偽ベクトル であり、配列全体に対する 1 つの True/False ではありません。

修正: isin()(または np.isin

カテゴリ月ラベル付きの、そのまま動く例です。

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
 
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug"]
df = pd.DataFrame(
    {
        "A": [12, 14, 13, 15, 18, 17, 16, 19],
        "B": [10, 11, 12, 14, 13, 15, 14, 16],
    },
    index=months,
)
 
fig, ax = plt.subplots(figsize=(7.2, 4.2))
ax.plot(df.index, df["A"], marker="o", label="series A")
ax.plot(df.index, df["B"], marker="o", label="series B")
 
ax.fill_between(
    np.arange(len(df)),
    df["A"],
    df["B"],
    where=df.index.isin(["Jan", "Feb", "Mar"]),
    color="#38bdf8",
    alpha=0.35,
    label="Q1 highlight",
)
 
ax.set_xticks(range(len(df)), df.index)
ax.legend(loc="upper left")
plt.show()

Selected months highlighted with isin

補足:

  • DatetimeIndex なら (df.index.month <= 3) のような真偽マスクや、正規化したラベルへの .isin が扱いやすいです。
  • 軸上のカテゴリラベルがあるとき、fill_between には文字列カテゴリより 整数位置(上例)の方が安定しやすいです。
  • where の長さは渡した x 配列と揃えます。

よくある罠

症状直し方
長さ不一致ValueError: ... not the same sizex / y1 / y2 / where を揃える
Index/配列に Python の inValueError または塗りが空index.isin([...]) / np.isin
alpha を忘れる塗りが線を隠すalpha=0.2–0.4
外側凡例が PNG で切れる凡例が欠ける凡例を外側に置く + bbox_inches="tight"
条件境界がギザつくブロック状の領域interpolate=True

複数系列では、塗りとあわせて 複数折れ線 の線スタイルをはっきりさせます。注釈やバンドで窮屈なら、凡例位置をいじる前に 図のサイズ を先に直します。

fill_between と fill_betweenx

  • fill_between(x, y1, y2) — x 方向に沿って 2 つの y のあいだを縦方向に塗る(いちばん多い)
  • fill_betweenx(y, x1, x2) — y 方向に沿って 2 つの x のあいだを横方向に塗る(鉛直プロファイル、密度帯、tornado 型レンジなど)

where= の考え方はどちらも同じです。

FAQ

まとめ

ax.fill_between(x, y1, y2) は小さな API ですが見た目の効果が大きいです。系列比較、不確かさの表示、区間のスポットライトに使えます。条件付きなら where=、ラベル絞り込みは Python の in ではなく isin / 真偽マスク、データが主役のままになるよう alpha は低めに保ちます。

関連ガイド