matplotlib 時系列グラフの軸設定
はじめに
時系列グラフの事例を紹介する。 このグラフ作成のポイントは、時間軸の設定方法である。
この記事はQiitaに投稿した以下の記事を再アレンジしたものである。
出力画像
プログラム
データ入力
このプログラムでは2つのファイルを読み込んでいる。
ファイル:xls_calvert.xlsx
1つ目のデータファイルは、エクセルファイルに、日(dd)、月(mm)、年(yy)、流量(Q)という順序にデータが格納されている。 これは、自分で打ち込んだため、打ち込みやすいように、日・月・年のカラムを分離したためである。 一つのカラムに dd/mm/yy と入力するよりは、打ち込み効率は高い。
これをpandasで読み込むわけであるが、作図時の扱いを楽にするため、各カラムの文字列を連結して年月日を示すインデックスとしてデータフレームに格納する。
プロットデータを線で連結したくない場所には、データとしてnan
を入れておけば、そこは線を結ばないよう自動調整してくれる。
# discharge data input fnameR='xls_calvert.xlsx' df = pd.read_excel(fnameR,sheet_name='data') ss=[] for sd,sm,sy in zip(df['dd'],df['mm'],df['yy']): s1='{0:0>2d}'.format(sd) s2='{0:0>2d}'.format(sm) s3='{0:0>4d}'.format(sy) ss=ss+[s1+'/'+s2+'/'+s3] df.index=pd.to_datetime(ss, format='%d/%m/%Y')
ファイル:xls_v-notch.xlsx
2つ目のデータファイルは、エクセル上のカラムで、A〜Nまでに格納されているが、今回使うのは、AとNだけであるので、データ読み込み時に、usecols=[0,13]
を指定し、col=0
をインデックスとしている。
# reservoir water level input fnameR='xls_v-notch.xlsx' dfr = pd.read_excel(fnameR,usecols=[0,13],index_col=0) dfr.index = pd.to_datetime(dfr.index, format='%d/%m/%Y')
横軸設定
横軸の範囲を2015年3月1日から2019年3月31日に指定する。
sxmin='2015-03-01' sxmax='2019-03-31' xmin = datetime.datetime.strptime(sxmin, '%Y-%m-%d') xmax = datetime.datetime.strptime(sxmax, '%Y-%m-%d') plt.xlim([xmin,xmax])
データプロット
2軸グラフとしているため、plt.twinx()
の前後で、左縦軸プロット、右縦軸プロットを実施する。
プロットデータは、横軸をデータフレームのインデックス、縦軸をデータフレームのカラムとして行う。
# 左縦軸プロット df = pd.read_excel(fnameR,sheet_name='data') ..... plt.twinx() ..... # 右縦軸プロット plt.plot(dfr.index,dfr['RWL'],'-',lw=2,color='#0000ff',label='RWL')
横軸(時間軸)目盛りの書式制御
プロット命令が終わったあとに、以下を挿入して横軸(時間軸)目盛りの出力を制御する。 この事例では、以下の設定を行っている。
- 日付目盛り書式を「日ー月ー年」とし、月は英語短縮形とする。
- 6ヶ月ピッチにグリッド線を入れる。( grid の指定は major のみ)
- 1ヶ月ピッチで小さい目盛り線を入れる。
- 日付を適当に自動で回転させる。
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%d-%b-%Y')) plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=6)) plt.gca().xaxis.set_minor_locator(mdates.MonthLocator(interval=1)) plt.gcf().autofmt_xdate()
プログラム全文
# Time series drawing import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime import matplotlib.dates as mdates def inpdata(): # discharge data input fnameR='xls_calvert.xlsx' df = pd.read_excel(fnameR,sheet_name='data') ss=[] for sd,sm,sy in zip(df['dd'],df['mm'],df['yy']): s1='{0:0>2d}'.format(sd) s2='{0:0>2d}'.format(sm) s3='{0:0>4d}'.format(sy) ss=ss+[s1+'/'+s2+'/'+s3] df.index=pd.to_datetime(ss, format='%d/%m/%Y') # reservoir water level input fnameR='xls_v-notch.xlsx' dfr = pd.read_excel(fnameR,usecols=[0,13],index_col=0) dfr.index = pd.to_datetime(dfr.index, format='%d/%m/%Y') return df,dfr def drawfig(df,dfr): fsz=12 plt.figure(figsize=(10,6),facecolor='w') plt.rcParams['font.size']=fsz sxmin='2015-03-01' sxmax='2019-03-31' xmin = datetime.datetime.strptime(sxmin, '%Y-%m-%d') xmax = datetime.datetime.strptime(sxmax, '%Y-%m-%d') plt.xlim([xmin,xmax]) plt.ylim([0,500]) plt.xlabel('Date') plt.ylabel('Discharge (Liter/min)') plt.grid(which='major',axis='both',color='#999999',linestyle='--') plt.plot(df.index,df['Q'],'-',color='#ff0000',label='Discharge') qs=165.0; spot='2016-05-31' dsp = datetime.datetime.strptime(spot, '%Y-%m-%d') plt.plot([dsp],[qs],'o',color='#ff0000') ss='31/05/2016\n{0:.0f}L/min'.format(qs) plt.text(dsp,qs-10,ss,va='top',ha='center',fontsize=fsz-2) plt.title('Discharge of Calvert at River Outlet Bay',loc='left',fontsize=fsz) plt.twinx() plt.ylim([65,90]) plt.ylabel('Reservoir Water Level (EL.m)') plt.plot(dfr.index,dfr['RWL'],'-',lw=2,color='#0000ff',label='RWL') plt.plot([0],[0],'-',color='#ff0000',label='Discharge') # dummy for legend plt.legend(loc='lower right',fontsize=fsz,shadow=True) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%d-%b-%Y')) plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=6)) plt.gca().xaxis.set_minor_locator(mdates.MonthLocator(interval=1)) plt.gcf().autofmt_xdate() fnameF='fig_calvert.jpg' plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.1) plt.show() def main(): df,dfr=inpdata() drawfig(df,dfr) #============== # Execution #============== if __name__ == '__main__': main()