【matplotlib】グラフの色々な位置にアノテーションをつける
Excelなどで作成したグラフは、PowerPointなどを使って色々説明を追記したりすることがありますが、Pythonのmatplotlibでもグラフに注釈を記載できます。
慣れると、ちょっとしたアノテーションであれば、Pythonのコードで作成できるため、手作業を減らせます。
アノテーションは、文字を記載するだけでなく色々な矢印も記載できますが、本記事ではアノテーションを記載する位置の指定方法について、主に説明します。
色々な位置にアノテーションを付けたグラフ
グラフへのアノテーションはmatplotlib.pyplot.annotate
またはmatplotlib.axes.Axes.annotate
を使います。
以下の例ではplt.annotateを使ってアノテーションを記載しています。
次のコードは
- y軸の上側に単位を記載
- x軸の右側に単位を記載
- 最大値となるデータに「最大値」と記載
- 最小値となるデータに「minimum 0」と記載
するコードです。
1# サンプルデータの作成
2x = [1, 2, 3, 4, 5, 6, 7]
3y = [0, 1, 2, 3, 5, 8, 13]
4
5plt.figure(figsize=(8, 4.5))
6plt.bar(x, y, color='gray')
7
8# y軸の上に「円」という注釈を加える
9plt.annotate('円', xy=(0, 1), xytext=(10, 0),
10 xycoords='axes fraction',
11 textcoords='offset points',
12 ha='right', va='bottom')
13# x軸の右に「月」という注釈を加える
14plt.annotate('月', xy=(1, 0), xytext=(-5, -10),
15 xycoords='axes fraction',
16 textcoords='offset points',
17 ha='center', va='center')
18# 最大値となるバーに注釈をつける
19y_max = max(y)
20x_max = x[y.index(y_max)]
21plt.annotate('最大値', xy=(x_max, y_max), xytext=(0, -10),
22 xycoords='data', textcoords='offset points',
23 ha='center', va='top', color='white')
24
25# 最小値となるバーに注釈をつける
26y_min = min(y)
27x_min = x[y.index(y_min)]
28plt.annotate('minimum 0', xy=(x_min, y_min), xytext=(10, 40),
29 xycoords='data', textcoords='offset points',
30 ha='center', va='top',
31 arrowprops=dict(arrowstyle='-|>', facecolor='blue', edgecolor='red')
32 )
33
34
35title = 'annotation_sample'
36plt.title(title)
37plt.tight_layout()
38plt.show()
annotate関数の引数の説明は以降でします。
annotate()の基本的な引数
表示位置に関する引数(xy, xytext, xycoords, textcoords, ha, va)については、後で詳しく解説します。
基本の引数
- text: 注釈に表示する文字です。
- xy: 注釈をつけるポイントの座標です。
- xytext: テキストの座標です。
- xycoords: xyの座標系を指定します。
- textcoords: xytextの座標系を指定します。
- arrowprops: 矢印のスタイルを辞書形式で指定します。今回の記事では解説しません。
引数の説明はこれから解説しますが、公式HPでも確認できます。
その他の引数
いわゆる**kwargs的な引数で指定可能なものの一部を紹介します。
- fontsize: 注釈のフォントサイズを指定します。
- color, facecolor, edgecolor: 注釈の色を指定します。
- ha(horizontal alignment): 水平位置について注釈のどの部分を基準点に合わせるかを指定します。本記事で解説します。
- va(vertical alignment): 垂直位置について、注釈のどの部分を基準点に合わせるかを指定します。本記事で解説します。
ha(水平位置)とva(垂直位置)について
これらはkwargsに含まれる引数なので、annotateに限らず、matplotlibの他の関数でも引数として使用する機会があります。
正しく意味を理解せずに、ExcelやPowerPointの右寄せ、左寄せみたいな感覚で使っていると、直感と逆に表示されるため、注意が必要です。
きちんと理解しておけば、色々な関数で使える引数なので便利です。
1# サンプルデータの作成
2x = [1, 2, 3, 4, 5, 6, 7]
3y = [1, 1, 1, 1, 1, 1, 1]
4
5
6plt.figure(figsize=(10, 4.5))
7plt.bar(x, y, color=sns.color_palette('pastel'))
8
9# haの位置をcenter, right, leftに設定した注釈
10# haにcenterを設定すると、注釈テキストの中心が、基準点(xyで指定した点)に来るように配置される。
11plt.annotate('ha-center', xy=(x[0], y[0]), xytext=(0, 0),
12 xycoords='data', textcoords='offset points',
13 ha='center',
14 va='center',
15 fontsize='large',
16 )
17
18# haにrightを設定すると、注釈テキストの右端が、基準点(xyで指定した点)に来るように配置される。
19# つまり、この例の場合、注釈は中心よりも左側に表示される
20plt.annotate('ha-right', xy=(x[1], y[1]), xytext=(0, 0),
21 xycoords='data', textcoords='offset points',
22 ha='right',
23 va='center',
24 fontsize='large',
25 )
26
27
28# haにleftを設定すると、注釈テキストの左端が、基準点(xyで指定した点)に来るように配置される。
29# つまり、この例の場合、注釈は中心よりも右側に表示される
30plt.annotate('ha-right', xy=(x[2], y[2]), xytext=(0, 0),
31 xycoords='data', textcoords='offset points',
32 ha='left',
33 va='center',
34 fontsize='large',
35 )
36
37# vaの位置をcenter, top, bottomに設定した注釈
38# vaにcenterを設定すると、注釈テキストの中心が、基準点(xyで指定した点)に来るように配置される。
39plt.annotate('va-center', xy=(x[3], y[3]), xytext=(0, 0),
40 xycoords='data', textcoords='offset points',
41 ha='center',
42 va='center',
43 fontsize='large',
44 )
45
46# vaにtopを設定すると、注釈テキストの上端が、基準点(xyで指定した点)に来るように配置される。
47# つまり、この例の場合、注釈は中心よりも下側に表示される
48plt.annotate('va-top', xy=(x[4], y[4]), xytext=(0, 0),
49 xycoords='data', textcoords='offset points',
50 ha='center',
51 va='top',
52 fontsize='large',
53 )
54
55# vaにbottomを設定すると、注釈テキストの下端が、基準点(xyで指定した点)に来るように配置される。
56# つまり、この例の場合、注釈は中心よりも上側に表示される
57plt.annotate('va-bottom', xy=(x[5], y[5]), xytext=(0, 0),
58 xycoords='data', textcoords='offset points',
59 ha='center',
60 va='bottom',
61 fontsize='large',
62 )
63
64# ha=left, va-topに指定することで注釈テキストの左上が基準点に来るようにする。
65# 更にxytextにoffset pointsを指定して10ポイント右下に移動させる。
66plt.annotate('left-top', xy=(x[6], y[6]), xytext=(10, -10),
67 xycoords='data', textcoords='offset points',
68 ha='left',
69 va='top',
70 fontsize='large',
71 )
72
73title = 'annotation_va_ha_sample'
74plt.title(title)
75plt.tight_layout()
76plt.show()
見ての通り、haにrightを指定すると注釈は左側に、leftを指定すると右側に寄ります。
垂直位置についても、vaにbottomと指定すると上側に、topと指定すると下側に寄ります。
コメント中でも解説していますが、
ha=rightは注釈テキストの右端が基準点に来るような指定となります。
上記の例では各バーの中心、上端が基準点となっています。
そのため、ha=rightとすると、注釈テキストの右端がバーの中心に来るように配置されます。
なので、注釈の表示が左寄りになります。
xyとxycordsについて
xyはannotate関数の必須引数で、基準点の設定に使われます。
その基準点をどのように決めるかをxycoordsで指定できます
xycoordsで指定可能な内容
xycoordsで良く使用される値は以下の通りです。
xycoordsの設定値 | 内容 |
---|---|
data | デフォルトの座標系。 データの座標系を使用します。 |
axes fraction | 軸のサイズを基準とした相対的な座標系を使用します。 軸の左下が(0, 0)、右上が(1, 1)となります。 |
figure fraction | 図のサイズを基準とした相対的な座標系を使用します。 図の左下が(0, 0)、右上が(1, 1)となります。 |
axes points | 軸の左下を原点として、ポイント単位で位置を指定します。 1ポイント≒1/72インチです。 ディスプレイ上では、1ポイントの大きさは固定となります。 |
axes pixels | 軸の左下を原点として、ピクセル単位で位置を指定します。 ディスプレイの解像度が異なると、グラフ上の注釈の表示位置が変わったりします。 |
xyとxycordsの使用例
xycoordsにdata、axes fraction, figure fraction, axes pints, axes pixelsを指定した場合の例が以下のコードです。
特に使用頻度が高いと思うのは、axes fractionとdataかと思います。
1# サンプルデータの作成
2x = [1, 2, 3, 4, 5, 6, 7]
3y = [1, 1, 2, 3, 5, 8, 13]
4
5plt.figure(figsize=(8, 4.5))
6plt.bar(x, y, color=sns.color_palette('muted'))
7
8# 基準点の座標系をデータの座標系を設定する
9# グラフのx=3, y=5の点を基準として注釈が表示される
10# グラフ内の特定の値に対して注釈をつけたい時などに使う
11plt.annotate('data: 3, 5', xy=(3, 5),
12 xycoords='data',
13 ha='center', va='center')
14
15# 基準点の座標系に軸のサイズを基準とした相対的な座標系を設定する
16# 軸の左下が0になり、右上が1になる
17# 以下の例の場合、x軸は0から20%の点が基準となる。y軸は1なので軸の上端が基準となる。
18# そのため、軸の上端の上に注釈が表示される。
19# グラフ内の決まった位置に注釈をつけたい時などに使う
20plt.annotate('axes fraction: 0.2, 1', xy=(0.2, 1),
21 xycoords='axes fraction',
22 ha='center', va='center')
23
24# 基準点の座標系に図のサイズを基準とした相対的な座標系を設定する
25# 図の左下が0になり、右上が1になる
26# 以下の例の場合、x軸方向は図の左端から20%の点が基準となる。y軸方向は図の上端が基準となる。
27# 図の一番上部分が中心となるように設定しているため、文字の上半分が切れている。
28# axes fractionでは指定しにくい場所に注釈をつけたい時には使うかも。
29# subplotsを使ったグラフの全体で座標指定して注釈をつけたい時には使うかも
30plt.annotate('figure fraction: 0.2, 1', xy=(0.2, 1),
31 xycoords='figure fraction',
32 ha='center', va='center')
33
34# 基準点の座標系に、軸の左下を原点としたポイント単位の座標系を設定する。
35# 1ポイント≒1/72インチで大きさが決まっている。
36# 以下の例の場合、軸の原点からx軸方向に100ポイント、y軸方向に50ポイント移動した点を基準点とする。
37plt.annotate('axes points: 100, 50', xy=(100, 50),
38 xycoords='axes points',
39 ha='center', va='center')
40
41# 基準点の座標系に、軸の左下を原点としたピクセル単位の座標系を設定する。
42# 以下の例の場合、軸の原点からx軸方向に100ピクセル、y軸方向に50ピクセル移動した点を基準点とする。
43# ピクセル単位なので、ディスプレイの解像度が異なると、グラフ上の表示位置も変わる。
44# xycoordsの指定には、ポイントもピクセルもあまり使わない気がする。
45plt.annotate('axes pixels: 100, 50', xy=(100, 50),
46 xycoords='axes pixels',
47 ha='center', va='center')
48
49title = 'annotation_xycoords_sample'
50plt.title(title, fontsize='x-large')
51plt.tight_layout()
52plt.show()
dataは特定のデータポイントに対して注釈をつけたい時に使うことが多いです。
axes fractionは個別グラフの特定位置に注釈を表示したい時に使うことが多いです。複数のグラフが一つの図に入っている場合なども各グラフに対して注釈を表示させられます。
一方、figure fractionは図での範囲指定をするため、図の中での特定の位置に注釈をつけたい場合に使います。複数グラフが含まれる図で特定の位置に注釈をつけたい場合などはよく使います。
なお、上記のサンプルコードでは、axes fraction=(0.2, 1)とy軸方向は図の上端となる位置を指定しているため、注釈の中心が図の上端になり、上半分が見切れています。
fraction系は、図の大きさが変わっても、大体同じような位置に注釈を表示することができます。
一方、axes points, axes pixelsは位置を絶対値で指定することになるため、図の大きさが変わるような場合には不向きです。図などの色々な大きさが決まっている場合などは使うことがあるかもしれません。
また、points, pixelsにはaxesだけでなくfigure points, figure pixelsも指定できます。こちらは軸ではなく図の左下を原点とした絶対位置になります。
ここではannotate()関数の必須引数であるxyと、その座標系を指定するxycoordsについて説明しました。
xyとxycoordsはアノテーション表示位置の基準点となるので、重要な引数ですが、そこから更に基準点を動かすことができます。
それがxytextとtextcoordsです。
xytextとtextcoordsについて
xytextとtextcoordsは必須の引数ではないため指定しなくても問題ありません。
単に文字を表示させたい場合だけなどであれば、xyとxycoordsだけでも十分なことが多いです。
xytextは基準点をxyで指定した点から更に動かすようなイメージです。
「動かすようなイメージ」としているのは、矢印を表示させる場合は意味が異なってくるからです。(本記事では矢印の表示は説明しないので、文字を表示する場合に絞って説明します。)
textcoordsで指定可能な値
textcoordsでは、xycoordsで指定できる値は基本的に使えます。
しかし、textcoordsの性質上、dataやaxes fractionなどは基本的に使われません。
textcoordsには基本的にoffset pointsという値が使われます。
offset points(またはoffset pixels)は指定したポイント(またはピクセル)分だけ、xyで指定した基準点から基準点を移動させます。
xytextとtextcoordsの使用例
1# サンプルデータの作成
2x = [1, 2, 3, 4, 5, 6, 7]
3y = [1, 1, 2, 3, 5, 8, 13]
4
5plt.figure(figsize=(8, 4.5))
6plt.bar(x, y, color=sns.color_palette('deep'))
7
8# 軸の中心点に注釈を表示
9plt.annotate('x', xy=(0.5, 0.5), xycoords='axes fraction', ha='center', va='center')
10
11# xy(基準点)をaxes fractionで(0.5, 0.5)と指定(軸の中心が基準となる。
12# 基準点からx軸方向へ100ポイント、y軸方向へ50ポイント移動した点が新たな基準点となる。
13plt.annotate('offset pixels: 100, 50', xy=(0.5, 0.5), xycoords='axes fraction',
14 xytext=(100, 50),
15 textcoords='offset points',
16 ha='center', va='center')
17
18title = 'annotation_textcoords_sample'
19plt.title(title, fontsize='x-large')
20plt.tight_layout()
21plt.show()
上記のコードでは、xyとxycoordsで基準点を軸の中心に指定し、そこからxytext=(100, 50)とtextcoords=’offset points’と指定することで、基準点を中心点から更にx軸方向へ100ポイント、y軸方向へ50ポイント移動させた点を新たな基準点に設定します。
なので、中心よりも少し右上に注釈が表示されます。
ここで、もしtextcoordsにoffset pointやoffset pixels以外の値、例えばaxes pointsなどを指定すると、xyとxycoordsで指定した基準点からの移動ではなく、軸の左下を原点としてx軸方向に100ポイント、y軸方向に50ポイント移動した点を基準として設定されてしまいます。
offset系以外を指定すると、xyで指定した点が基準にならないため、文字を表示したい場合であれば、offset系以外を使うことはないと思います。(矢印表示とかだと場合によってはoffset系以外も使うこともある)
まとめ
グラフに文字を表示させたいだけであれば、基本的にはxyとxycoordsで基準点を指定し、必要に応じてha、va、xytextとtextcoordsで調整していくことになります。
1# xy(基準点)をaxes fractionで(0.5, 0.5)と指定(軸の中心が基準となる。
2# 基準点からx軸方向へ100ポイント、y軸方向へ50ポイント移動した点が新たな基準点となる。
3plt.annotate('offset pixels: 100, 50', xy=(0.5, 0.5), xycoords='axes fraction',
4 xytext=(100, 50),
5 textcoords='offset points',
6 ha='center', va='center')
7