2020年7月26日日曜日

PythonのMatplotlibで矢印つきの注釈を表示する

Pythonのmatplotlibでラベル付き散布図を作成するでは散布図の各要素にラベル(注釈)を表示させたが、Matplotlibでは矢印つきの注釈をグラフ上に表示できる。今回は折れ線グラフ上に矢印つきの注釈を表示させてみる。



環境


Debian Buster(Dockerコンテナ)とJupyter Lab。さらに日本語フォント(Takao)もインストール済み。



グラフで表示するデータ


まずはグラフ表示するデータを用意する。DTW(動的時間伸縮法)で時系列データ間の距離を求めるで作成したcsvを使う。元データは、厚生労働省のホームページ地域ごとの感染状況等の公表についてからダウンロードできる「3.帰国者・接触者相談センターへの相談件数の推移(都道府県別・各日)・帰国者・接触者外来の受診者数の推移・うちPCR検査実施件数の推移(都道府県別・各日) 」のPDFで、これをcsvに変換したもの。全国と各都道府県の日ごとの数値が含まれる。以下はExcelで開いた状態。


注釈のデータ


今回は主なニュースを注釈としてグラフ上に表示させる。グラフで表示するデータが日ごとの数値なので、日にちをキーとするPythonの辞書型でデータを用意する。
from datetime import datetime as dt
# グラフ上に表示するイベント
events = {
      dt(2020, 5, 2): '国内死者500人超え',
      dt(2020, 5, 4): '緊急事態宣言を5月31日まで延長',
      dt(2020, 5, 14): '39県で緊急事態宣言解除を決定',
      dt(2020, 5, 21): '京都、大阪、兵庫の緊急事態宣言解除を決定',
      dt(2020, 5, 25): '北海道および首都圏の1都3県緊急事態宣言解除を決定',    
}



グラフ用データの読み込み


PDFから抽出したデータを保存したcsv(000643758.csv)を読み込んで、このcsvに含まれる全国の「帰国者・接触者相談センター(全相談件数)」を使う。期間は5月のひと月分。日ごとのデータなので、日をインデックスとするPandasのDataFrameにする。

%matplotlib inline
 
from datetime import datetime as dt
import pandas as pd
import matplotlib.pyplot as plt

# 日本語フォントの指定
plt.rcParams['font.family'] = 'TakaoGothic'
 
DT_FROM = '2020-05-01'
DT_TO = '2020-05-30'

def load_csv(csvpath):
    df = pd.read_csv(csvpath, index_col=0, header=[0,1], parse_dates=True, encoding='shift-jis')
  
    # 全国の「帰国者・接触者相談センター(全相談件数)」だけを選択
    df_con = df.loc[:, [('全国', '帰国者・接触者相談センター(全相談件数)')]]
     
    # カラムのレベルを全国のみにする
    df_con.columns = df_con.columns.droplevel(level=1)
 
    return df_con[DT_FROM:DT_TO]
 
df = load_csv('000643758.csv')
df.plot()
plt.show()
プロットすると以下のようになる。




グラフ上に矢印付きの注釈を表示


はじめに折れ線グラフを表示し、さらにその上に辞書型の注釈データを使って矢印つき注釈を表示する。

%matplotlib inline
 
from datetime import datetime as dt
import pandas as pd
import matplotlib.pyplot as plt

# 日本語フォントの指定
plt.rcParams['font.family'] = 'TakaoGothic'
 
DT_FROM = '2020-05-01'
DT_TO = '2020-05-30'

# グラフ上に表示するイベント
events = {
      dt(2020, 5, 2): '国内死者500人超え',
      dt(2020, 5, 4): '緊急事態宣言を5月31日まで延長',
      dt(2020, 5, 14): '39県で緊急事態宣言解除を決定',
      dt(2020, 5, 21): '京都、大阪、兵庫の緊急事態宣言解除を決定',
      dt(2020, 5, 25): '北海道および首都圏の1都3県緊急事態宣言解除を決定',    
}

def load_csv(csvpath):
    df = pd.read_csv(csvpath, index_col=0, header=[0,1], parse_dates=True, encoding='shift-jis')
  
    # 全国の「帰国者・接触者相談センター(全相談件数)」だけを選択
    df_con = df.loc[:, [('全国', '帰国者・接触者相談センター(全相談件数)')]]
     
    # カラムのレベルを全国のみにする
    df_con.columns = df_con.columns.droplevel(level=1)
 
    return df_con[DT_FROM:DT_TO]
 
df = load_csv('000643758.csv')
df.plot()

# y軸の最大値
mx = df.max()

# イベントを注釈としてグラフに追加
for d, annot in events.items():
    # イベント日に縦の点線を描く
    plt.axvline(x=d, color='black', linestyle='--', alpha=0.5)

    # プロットのy軸上の位置
    if d in df.index:
        y = df.loc[d]
    else:
        continue

    # プロット値の上部に注釈と矢印を表示
    plt.annotate(annot, xy=(d, y+mx*0.1), 
                 xytext=(d, y+mx*0.2), 
                 arrowprops=dict(color='red', headwidth=4, width=2, headlength=4),
                 horizontalalignment='left', verticalalignment='top')

plt.legend()
plt.show()

以下のようにグラフ上に矢印つきの注釈が表示された。


0 件のコメント:

コメントを投稿