TUのブログ

Pythonを使ってデータ処理するときの忘備録

簡単な矢印を描く

matplotlibを使ってグラフを描画するとき、ある点から別の点を結ぶ矢印を入れたくなる時があります。
使う頻度は高くないですが、低くもない。また忘れたときにコピペするために、メモしておきます。

参考にした公式マニュアルのページ:
matplotlib.axes.Axes.arrow — Matplotlib 3.0.3 documentation
matplotlib.axes.Axes.annotate — Matplotlib 3.0.3 documentation

サイン波のグラフを描いておきましょう。

import numpy as np
from matplotlib import pyplot as plt

fig, ax = plt.subplots(1,1,figsize=(6,4))
x = np.arange(0,2*np.pi,0.1)
ax.plot(x,np.sin(x))
ax.set_xlabel('x')
ax.set_ylabel('y')

f:id:tanukigraph:20171206222809p:plain

arrow

一番簡単なのはこれでしょうか。axesクラスのarrow。
僕の場合、凝った矢印はあまり使わないので、例えば下記を上のコードに加えてプロットしてみます。

ax.arrow(x=0,y=0,dx=np.pi,dy=0,width=0.01,head_width=0.05,head_length=0.2,length_includes_head=True,color='k')

出力は、こうなります。

f:id:tanukigraph:20171206225314p:plain

注意点が3点
① widthとhead_width、head_lengthのデフォルト値。

width(矢印の棒の部分の幅):0.001。単位はポイントではない。
head_width(矢の部分の幅):widthの3倍というデフォルト値が設定されています。
head_length(矢の部分の長さ):head_widthの1.5倍。

初めて使ったときはデフォルトの挙動に悩まされました。

② length_includes_headはデフォルトでFalseなので、先っちょを指定した終点に合わせたいときはTrueにしましょう。

③ axes.arrowで描いた矢印はaxisの大きさに合わせて太さ大きさが変わります。
※後日追記:サイズはデータの座標が使われます。

annotate

注釈用のannotateも(もちろん)矢印を書くのに使えます。
かなり多機能なのですが、ここでは、ただ矢印を描くだけに使います。

使い方は例えば、

ax.annotate(s='',xy=(0,0),xytext=(np.pi,0),xycoords='data',\
            arrowprops=dict(facecolor='black', width =2.0,headwidth=7.0,headlength=7.0,shrink=0.01))

引数のsは注釈用コメントですね。今は空にしてますが。

コメント位置(xytext)からxyに向かって矢印が引かれます。
xycoordsは座標の指定で、デフォルトでdataです。他にも、例えば'axes fraction'(axisの割合)とかを指定できます。

arrowpropsでは、矢印の見た目に関する指定をします。大きさに関しては、上で見たarrowと違って、ポイント数で指定できます。shrinkは矢印の長さをどのくらい縮めるかで、端から端まで引きたいときは0にします。

サイン波に重ねて出力した結果がこちらです。

f:id:tanukigraph:20171225220902p:plain

矢印の頭の形状を変えたいときは、arrowpropsでarrowstyleを指定します。
例えば、

ax.annotate(s='',xy=(0,0),xytext=(np.pi,0),xycoords='data',\
            arrowprops=dict(facecolor='black',arrowstyle='<-, head_width=0.5',lw=3,shrinkA=0,shrinkB=0))

で、出力結果がこちら、

f:id:tanukigraph:20171225223821p:plain

ここで注意すべき点が、arrowstyleを指定すると、widthとかheadwidthを指定することができなくなるということです。なぜか、arrowstyleに文字列で入力することになります。

あと、PathPatchを使って、線の太さ(linewidth; lw)とか種類(linestyle; ls)を指定することもできます。

shrinkAとBはそれぞれ、始点(xytext)と終点(xy)と矢印の隙間をポイント数で指定します。

・・・疲れたので、以上にします。