結論:下側と上側の「幅」を2行に並べる
測定値の下限と上限が分かっている場合は、yerr = np.vstack((y - lower, upper - y))としてからerrorbarへ渡す。1行目が下向き、2行目が上向きの幅であり、配列の形は(2, N)となる。下限・上限そのものを渡すわけではない。この区別を押さえれば、上下で長さの違うエラーバーも通常の作図とほぼ同じ手順で描ける。
例えば推定値が10、区間が8〜13なら、下側の幅は2、上側の幅は3である。下側を負の値にする必要はない。描画側が下向きと上向きを区別するので、入力する幅はいずれも0以上とする。元の表が「値・下限・上限」なのか、「値・下側の幅・上側の幅」なのかを先に確かめたい。列名にerrorとだけ書かれている場合も、意味を確認してから変換する。
そのまま動かせる例
以下は3試料の推定値と区間を描く独立した例である。NumPyとMatplotlibを利用する。コードをexample.pyとして保存して実行すると、現在の作業フォルダーにasymmetric.pngを作る。同名ファイルがあれば上書きされるので、空の作業フォルダーで試してほしい。図中は環境ごとの日本語フォント設定に依存しない英語表記とした。
作図前に配列の形、有限値、下限と推定値と上限の順序を確認している。実データでは、表を並べ替えた際に下限だけ別順になったり、測定失敗の文字列が混ざったりする。間違った区間でも見た目だけは整った図を作れてしまうため、描画の直前で入力条件を確かめる方が原因を追いやすい。
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1, 2, 3])
y = np.array([10.0, 15.0, 12.0])
lower = np.array([8.0, 14.0, 9.0])
upper = np.array([13.0, 19.0, 14.0])
if not (y.shape == lower.shape == upper.shape == x.shape):
raise ValueError("shape mismatch")
if not np.isfinite([y, lower, upper]).all():
raise ValueError("non-finite input")
if not ((lower <= y).all() and (y <= upper).all()):
raise ValueError("expected lower <= y <= upper")
yerr = np.vstack((y - lower, upper - y))
assert yerr.shape == (2, 3)
np.testing.assert_allclose(y - yerr[0], lower)
np.testing.assert_allclose(y + yerr[1], upper)
print("lower widths:", yerr[0].tolist())
print("upper widths:", yerr[1].tolist())
fig, ax = plt.subplots(figsize=(6.2, 3.8), layout="constrained")
try:
bars = ax.errorbar(x, y, yerr=yerr, fmt="o", capsize=5,
color="#215f91", label="Estimate and interval")
ax.set(xlabel="Sample", ylabel="Signal (a.u.)", xticks=x,
title="Asymmetric intervals: endpoints are not widths")
ax.grid(axis="y", alpha=0.25)
ax.legend()
segments = bars[2][0].get_segments()
np.testing.assert_allclose([s[:, 1] for s in segments],
np.column_stack((lower, upper)))
fig.savefig("asymmetric.png", dpi=160)
finally:
plt.close(fig)
print("saved: asymmetric.png")
実行結果
lower widths: [2.0, 1.0, 3.0]
upper widths: [3.0, 4.0, 2.0]
saved: asymmetric.png

出力と配列の向きを読む
下側の幅は2・1・3、上側の幅は3・4・2となる。図では試料2が上側に長く、試料3が下側に長い。コード中では幅から元の境界値を復元し、さらに描画された線分の両端が下限・上限と一致することも確認している。エラーなく保存できたことだけでなく、意図した区間が図に表れたことまで確認するためである。
np.column_stackで2列に並べると形は(N, 2)になり、要求される向きと逆になる。点が2個の場合はどちらも2×2なので、形の確認だけでは取り違えを見つけられない。まず下側の幅だけを出力し、試料順に並んでいるかを確認するとよい。対称な誤差なら長さNの1次元配列、全点で同じ幅なら単一の数値でも指定できる。
横方向や片側の限界値との違い
横方向の不確かさも同じ考え方でxerrに渡せる。横軸の値から左端を引き、右端から横軸の値を引いて2行に並べる。ただし、上下限の片方しか測定できなかった上限値・下限値を、適当な幅を持つ両側区間として描かないこと。errorbarにはuplimsやlolimsによる限界値の表示もあるが、これは区間の両端が既知の場合とは意味が異なる。図を整える前に、通常の推定値、片側の限界、欠測をデータ上で区別しておくと表示方針がぶれにくい。
誤差棒を描く前に決めておくこと
この例は入力済みの区間を描画しているだけで、信頼区間を計算してはいない。標準偏差・標準誤差・信頼区間・観測範囲は別の量である。図の説明には「何の区間か」「何%か」「独立な測定の数はいくつか」を必要に応じて記し、単にエラーバーとだけ書かないようにする。非対称だから特定の統計手法による区間だと判断することもできない。
推定値が区間の外にあると負の幅が生じる。そこでabsを取って通してしまうと、与えられた境界とは違う区間を描くことになる。データの対応、推定値の定義、区間の計算方法へ戻って確認しよう。欠測値も0に置き換えず、欠測として表示から外す方針を別途決める。0幅は許されるが、欠測を意味するわけではない。
fmt="o"は点だけを描き、試料間を線で結ばない指定である。順序のない独立試料ならこの方が解釈しやすい。一方、時系列などで点を結ぶ意味があるなら線種も指定する。対数軸へ変更すると、推定値が正でも区間下端が0以下になることがある。軸を変える際は下端まで含めて表示可能かを調べ、見えない区間を黙って切り捨てないようにしたい。
確認環境と参考資料
例はLinux・CPython 3.12.14・NumPy 2.3.5・Matplotlib 3.10.8(Agg)で実行した。掲載した出力はこの環境での結果である。公式資料のstable版や最新版は更新されるため、手元のバージョンと対応する仕様も確認してほしい。
