HOWTO · Matplotlib
Matplotlib でプロットの内側にテキストを追加する
このチュートリアルでは、Matplotlib のプロット内の指定した位置にラベルや注記を追加するために、`matplotlib.pyplot.text()` 関数を使う方法を説明します。
このページの内容
matplotlib.pyplot.text() を使うと、Matplotlib プロット内の任意の位置にラベルや注記を配置できます。この関数は x 座標と y 座標、その後に表示する文字列を受け取り、オプションの引数でテキストの見た目を制御します。たとえば、plt.text(2, 20, "Peak point") はデータ座標 (2, 20) にラベルを配置します。Axes オブジェクトでは、同等の呼び出し ax.text(2, 20, "Peak point") を使います。パラメータの完全な一覧は pyplot.text() API リファレンス を参照してください。
matplotlib.pyplot.text() でプロットにテキストを追加する
次の例では、線を描画し、そのデータ点の 1 つにラベルを配置します。pyplot インターフェースを使い、選んだ座標がプロットに含まれるよう表示範囲を設定します。
import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
y = [10, 15, 25, 30]
plt.plot(x, y, marker="o")
plt.xlim(0, 5)
plt.ylim(0, 35)
plt.text(3, 25, "Peak point", fontsize=12, color="crimson")
plt.title("A labeled line plot")
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
x と y にはプロットするデータが入っており、この呼び出しにより「Peak point」が座標 (3, 25) に配置されます。2 つの範囲設定の呼び出しにより、その座標が表示範囲に含まれます。複数のプロットを作成するスクリプトでは、ax.text(x, y, label) によってテキストが特定の Axes に関連付けられ、どのプロットに表示されるかが明確になります。pyplot の呼び出しは、現在の単一プロットに対して便利です。ラベル「Peak point」は、変更されていないコード内では英語のままです。
データ座標と軸範囲を使ってテキストの位置を決める
デフォルトでは、text() の x 引数と y 引数はデータ座標を使います。そのため、(3, 25) のラベルはグラフ上のその値に従い、隅からのピクセル距離で位置が決まるわけではありません。現在の x と y の範囲によって、データ座標平面のどの部分が表示されるかが決まります。plt.xlim() と plt.ylim() で適切な範囲を設定するか、Axes オブジェクトでは ax.set_xlim() と ax.set_ylim() を使います。
ラベルが読みやすく、重要なデータを覆わない位置を選びましょう。データ値に関係なく軸の一定の割合の位置に注記を固定したい場合は、transform=ax.transAxes を使って軸座標を指定します。(0, 0) が軸の左下、(1, 1) が右上です。これはデフォルトのデータ座標とは異なり、プロット内に固定されるキャプションに便利です。次の例では両方の方式を組み合わせます。データラベルは (3, 25) に留まり、下書きの注記は、データや範囲が変わっても軸の左上隅に留まります。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 15, 25, 30], marker="o")
ax.set_xlim(0, 5)
ax.set_ylim(0, 35)
ax.text(3, 25, "Peak point", fontsize=12, color="crimson")
ax.text(0.02, 0.95, "Draft - internal data", transform=ax.transAxes,
fontsize=10, ha="left", va="top")
ax.set_title("Data and axes coordinates")
plt.show()
多くのユーザーが驚く境界ケースがあります。テキストはその座標に固定されますが、デフォルトでは軸に合わせて切り取られません。プロット内部から始まるラベルは軸の端を越えて余白にはみ出すことがあり、範囲外に固定されたラベルは軸の領域の外に描画されます。代わりに clip_on=True を渡すと、テキストが軸の端でぴったり切り取られます。この例では、右端の x = 5 に近い x = 4.6 から、同一のラベルを 2 つ開始します。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 15, 25, 30], marker="o")
ax.set_xlim(0, 5)
ax.set_ylim(0, 35)
ax.text(4.6, 32, "Clipped at the edge", fontsize=12, clip_on=True)
ax.text(4.6, 27, "Drawn in full", fontsize=12)
ax.set_title("Text at the axes edge")
plt.show()
最初のラベルは右側の軸線で止まり、2 つ目は余白へと続いています。ラベルの可読性を保つ必要がある場合は、はみ出しを警告なく取り除くクリッピングに頼るのではなく、アンカーとラベル全体の幅が範囲内に収まるよう、範囲を広げるかアンカーを移動してください。ラベル「Clipped at the edge」と「Drawn in full」は、コード全体と同様に英語のままです。
テキストの見た目を調整する
text() にキーワード引数を渡すと、ラベルのスタイルを設定できます。fontsize は大きさを、color は色を変更し、fontweight="bold" はテキストを強調します。rotation を設定するとテキストが回転し、horizontalalignment(または ha)と verticalalignment(または va)で、x 座標と y 座標を基準にテキストを揃えます。たとえば、ha="center" と va="bottom" を指定すると、ラベルが点の上に中央揃えされ、その点より上に保たれます。
bbox 引数を指定するとテキストの背後に背景が追加され、混み合った線やマーカーからラベルを際立たせることができます。この引数は patch プロパティの辞書を受け取ります。この例では、配置、強調、回転、半透明の白いボックスを組み合わせます。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [2, 4, 3], marker="o")
ax.set_ylim(1.8, 4.7)
ax.text(2, 4, "Peak", fontsize=12, color="crimson", fontweight="bold",
ha="center", va="bottom", rotation=15,
bbox={"facecolor": "white", "alpha": 0.8})
ax.set_title("Styled text")
plt.show()
たとえば、bbox={"facecolor": "white", "alpha": 0.8} は部分的に透明な白い背景を作成します。読みやすさを向上させるオプションだけを使ってください。強い色、大きなフォント、回転を広範囲に適用すると、データと競合するおそれがあります。変更されていないコード例に表示されるラベルは英語のままです。
注釈と複数行のテキストを追加する
注記が特定の特徴を指し示す必要がある場合は、plt.annotate() を使います。引数 xy は説明するデータ点を、xytext はテキストの位置を指定します。注釈テキストの位置もデフォルトではデータ座標を使うため、対象と注記の両方が含まれるよう範囲を設定してください。Axes では ax.annotate() を使うと、対象と注記が意図したプロットに属するようになります。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 15, 25, 30], marker="o")
ax.set_xlim(0, 5)
ax.set_ylim(0, 35)
ax.annotate("Peak", xy=(3, 25), xytext=(1.2, 31),
arrowprops={"arrowstyle": "->"})
ax.set_title("Annotation with an arrow")
plt.show()
ここでは、arrowprops={"arrowstyle": "->"} により、(1.2, 31) の注記から (3, 25) の頂点へ矢印が描かれます。arrowprops がない場合、annotate() は text() とほぼ同様にプレーンなテキストを配置します。
複数行の注記を作成するには、text() に渡す文字列に改行文字を含めます。たとえば "First line\nSecond line" のようにします。Matplotlib は、選択した位置に各部分をそれぞれの行に描画します。複数行ラベルはコンパクトな説明に便利です。表示されるプロット領域内に収まり、近くのデータを覆わないよう、位置と配置を調整してください。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [10, 15, 25, 30], marker="o")
ax.set_xlim(0, 5)
ax.set_ylim(0, 35)
ax.text(0.4, 33, "First line\nSecond line", fontsize=12, va="top")
ax.set_title("Multi-line text")
plt.show()
va="top" を指定すると、y 座標 (33) が 2 行ブロックの上端を固定するため、両方の行がプロット内に収まります。ラベル「Peak」「First line」「Second line」は、変更されていない例では英語のままです。これらの手法により、各注記を、それが結び付く座標や特徴に関連付けながら、ラベル、文脈、ポインターを追加できます。