HOWTO · Matplotlib

Matplotlibで任意の線を描く方法

Matplotlibでplot()、hlines()、vlines()、LineCollectionを使って有限の線分を描く方法を説明します。

このページの内容

Matplotlib で 1 本の有限な線分を描くには、2 つの端点の座標を Axes.plot() に渡します。線分が水平または垂直なら hlines() や vlines() を使い、多数の独立した線分には LineCollection を使います。これらの API はデータ座標を使用しますが、axhline()、axvline()、axline() は軸全体に広がる線や無限の直線という別の用途に対応します。

例では Matplotlib と Python を使います。まだインストールされていなければ python -m pip install matplotlib で Matplotlib をインストールしてください。各実行可能な例は、非対話的な環境でも確認できるように PNG を保存します。対話的なウィンドウで表示したい場合は、savefig() を plt.show() に置き換えてください。

plot() で有限の線分を描く

(x1, y1) から (x2, y2) までの線分には、2 つの x 値からなるシーケンスと 2 つの y 値からなるシーケンスを plot() に渡します。Matplotlib は同じ位置の値同士を結ぶため、最初の x/y の組が一方の端点になり、2 番目の組がもう一方の端点になります。

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([3, 5], [1, 6], color="tab:green", marker="o")
ax.set(xlabel="x", ylabel="y", title="Finite segment with plot()")
fig.savefig("plot-segment.png", dpi=120)
print("saved: plot-segment.png")
saved: plot-segment.png

2 つのプロットされた端点を結ぶ有限な緑色の線分

マーカーによって 2 つの端点が見やすくなります。値の組を追加するのはポリラインを作成するときだけにしてください。plot() は独立した線分を作るのではなく、連続する点同士を結びます。

有限の水平線分または垂直線分を描く

水平線分には hlines(y, xmin, xmax) を、垂直線分には vlines(x, ymin, ymax) を使います。一定に保たれる座標が最初の引数で、残りの 2 つの引数がデータ座標上の有限な端点になります。

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.hlines(3, 2, 5, color="tab:red")
ax.vlines(6, 1, 5, color="tab:green")
ax.set(xlim=(0, 7), ylim=(0, 6), xlabel="x", ylabel="y")
fig.savefig("horizontal-vertical-segments.png", dpi=120)
print("saved: horizontal-vertical-segments.png")
saved: horizontal-vertical-segments.png

有限な赤い水平線分と有限な緑の垂直線分

ここでは、赤い線分が (2, 3) から (5, 3) まで、緑の線分が (6, 1) から (6, 5) まで伸びています。明示的な範囲によって意図したデータ領域が明確になり、切り取られた線を短い線分と誤解することを防げます。

軸全体に広がる基準線で代用しない

axhline() と axvline() は便利な基準線ですが、データ座標上の 2 つの端点を使うのではなく、軸を一方向に横切ります。同様に、axline() は点を通る無限の直線、または傾きを指定した無限の直線を表します。グラフにその動作が必要な場合だけ、これらの API を使ってください。

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
segment = ax.hlines(3, 2, 5, color="tab:red")
reference = ax.axhline(3, color="0.35", linestyle="--")
assert segment.get_segments()[0].tolist() == [[2.0, 3.0], [5.0, 3.0]]
assert reference.get_transform() is ax.get_yaxis_transform()
print("hlines endpoints: [2.0, 3.0] to [5.0, 3.0]")
print("axhline uses axes-relative x coordinates")
hlines endpoints: [2.0, 3.0] to [5.0, 3.0]
axhline uses axes-relative x coordinates

このアサーションは違いを示しています。hlines() は有限なデータ座標の端点を保持しますが、axhline() は水平方向の範囲に軸相対座標を使います。ズーム、範囲の変更、グラフの書き出しを行うときに、この区別が重要になります。

LineCollection で独立した線分を複数描く

互いに接続されていない線分を多数描く場合は、2 点で構成された線分のシーケンスから LineCollection を作成し、Axes に追加します。add_collection() の後に autoscale() を呼び出すと、コレクションが軸のスケールに含まれます。グラフの表示範囲を固定する場合は、代わりに明示的な範囲を設定してください。

import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

segments = [[(1, 10), (6, 9)], [(1, 7), (3, 6)]]
collection = LineCollection(segments, colors=["tab:red", "tab:green"])

fig, ax = plt.subplots()
ax.add_collection(collection)
ax.autoscale()
ax.set(xlabel="x", ylabel="y", title="Two independent segments")
fig.savefig("line-collection.png", dpi=120)
print("segments: 2")
print("saved: line-collection.png")
segments: 2
saved: line-collection.png

Matplotlib の LineCollection に追加した 2 つの独立した線分

LineCollection は多数の線分を 1 つのコレクションにまとめられるため便利です。ある線分の終点と次の線分の始点を結ばないことが、より長い点のシーケンスを plot() に渡す場合との重要な違いです。

形状に合った API を選ぶ

1 本の線分や接続されたパスには plot()、有限で軸に平行な線分には hlines() と vlines()、独立した線分のまとまりには LineCollection を選びます。axhline() や axvline() は軸全体に広がるガイドにだけ使い、axline() が無限の直線であることを覚えておいてください。

パラメーターの詳細とスタイルのオプションについては、公式の plot() ドキュメント、hlines() ドキュメント、vlines() ドキュメント、LineCollection ドキュメントを参照してください。上の例は、記録済みのローカル Polyglot コンテナで Matplotlib 3.11.2 を使って実行しました。