matplotlib 河川流況表示(2)
概要
河川の流況を示す作図プログラムを紹介します。 対象年数が多くなった場合の事例です。
流況図
縦軸に日平均流量、横軸に超過確率(厳密には超過率)をとった年間の流況を示す図です。 ここでは、1年毎に17年分の線を引き、赤い太線で17年間の平均を示しています。 図の下に、各年の平均・最小・最大値を画面出力したものをのせています。
------------------------- Year ave min max ------------------------- 2001 36.4 3.6 276.2 2002 32.2 3.6 315.3 2003 46.0 3.9 458.3 2004 32.8 3.6 578.1 2005 43.9 3.7 570.3 2006 36.7 3.6 306.7 2007 40.9 3.7 365.6 2008 46.4 3.7 331.0 2009 39.6 3.6 473.9 2010 56.4 5.1 407.0 2011 37.5 3.8 316.6 2012 48.3 3.9 278.0 2013 41.4 3.9 239.0 2014 39.7 3.6 259.6 2015 28.9 3.6 176.8 2016 49.4 4.8 449.9 2017 47.4 5.3 288.2 ------------------------- Ave. 41.4 3.6 578.1
月平均流量ヒートマップ
各年の月平均流量をマトリックス状に配置したヒートマップです。
月平均流量時系列図
月平均流量の時系列図を年毎にマトリックス状に示したものです。 この事例では17年分のデータなので17個の小さなグラフを4行5列のマトリックスの中に配置しています。
流況図作図プログラム
元データはエクセルファイルであり、はじめから日付と日平均流量の2カラムで構成されているので、データ読み込みの関数:rdata() では、そのまま読みってSeriesに格納し、出力しています。
データ入力時の注意事項
プログラム全文で示すプログラムは、データをエクセルから読み込んでいる。 ここで、エクセルデータでは、第一カラムは時系列データとして指定しているため、pandas で読み込んでもその属性が継続されている。 しかし、以下のように、csv あるいは text ファイルから読み込む場合、年月日はただの文字列となっているため、Series にする際に、第一カラム(この場合 df['date'] )を、明確に時系列データであることを明示しておく必要がある。そうしないとあとで年別の値を抽出する場合などに困ることになる。
def rdata(): df = pd.read_csv('inp_flow.csv', sep=',') q=df['m3/s'] d= pd.to_datetime(df['date']) # <= この操作を行うことに注意 qq=pd.Series(np.array(q),index=d) return qq
プログラム全文
import numpy as np import pandas as pd import datetime import matplotlib.pyplot as plt from scipy import interpolate # global tstr='Duration Curve at Kelaena Dam Site (2001-2017 by HEC-HMS)' ylist=['2001','2002','2003','2004','2005','2006','2007','2008','2009','2010',\ '2011','2012','2013','2014','2015','2016','2017'] # year def rdata(): fnameR='xls_qq_kuroki.xlsx' # input file name sname='Sheet1' df=pd.read_excel(fnameR, sheet_name=sname) # read excel data q=df['m3/s'] d=df['date'] qq=pd.Series(np.array(q),index=d) return qq def makedata(qq): qqq=np.zeros((101,len(ylist)+1),dtype=np.float64) # discharge ppp=np.arange(101,dtype=np.float64) # propability sta=np.zeros((len(ylist)+1,3),dtype=np.float64) # ave, min, max of a year for i,sy in enumerate(ylist): qd=np.array(qq[sy]) qd=np.sort(qd)[::-1] ii=np.arange(len(qd)) pp=ii/(len(qd)-1)*100 ff=interpolate.interp1d(pp,qd) qqq[:,i]=ff(ppp) sta[i,0]=np.average(qd) sta[i,1]=np.min(qd) sta[i,2]=np.max(qd) sta[-1,0]=np.average(qq) sta[-1,1]=np.min(qq) sta[-1,2]=np.max(qq) for j in range(len(ppp)): qqq[j,-1]=np.average(qqq[j,:]) return ppp,qqq,sta def drawfig(ppp,qqq): fsz=16 xmin=0; xmax=100; dx=10 ymin=0; ymax=200; dy=20 fig=plt.figure(figsize=(10,6),facecolor='w') plt.rcParams['font.size']=fsz plt.rcParams['font.family']='sans-serif' plt.xlim([xmin,xmax]) plt.ylim([ymin,ymax]) plt.xlabel('Non-exceedance probability (%)') plt.ylabel('River flow Q (m$^3$/s)') plt.xticks(np.arange(xmin,xmax+dx,dx)) plt.yticks(np.arange(ymin,ymax+dy,dy)) plt.grid(color='#999999',linestyle='solid') plt.title(tstr,loc='left',fontsize=fsz) for i,sy in enumerate(ylist): plt.plot(ppp,qqq[:,i],'-',color='#777777',lw=1) plt.plot(ppp,qqq[:,-1],'-',color='#ff0000',lw=3,label='Average') plt.legend() fnameF='fig_duration2.jpg' plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.1) plt.show() def main(): qq=rdata() ppp,qqq,sta=makedata(qq) drawfig(ppp,qqq) print('-------------------------') print('{0:>4s} {1:>6s} {2:>6s} {3:>6s}'.format('Year','ave','min','max')) print('-------------------------') for i,sy in enumerate(ylist): print('{0:4s} {1:6.1f} {2:6.1f} {3:6.1f}'.format(sy,sta[i,0],sta[i,1],sta[i,2])) print('-------------------------') print('{0:4s} {1:6.1f} {2:6.1f} {3:6.1f}'.format('Ave.',sta[-1,0],sta[-1,1],sta[-1,2])) #============== # Execution #============== if __name__ == '__main__': main()
月平均流量ヒートマップおよび月平均流量時系列図作図プログラム
元データは流況図用のものと同じです。 エクセルより読み取ったデータを以下のような pandas の DataFrame に書き直し、この数値をそのままヒートマップおよび時系列図にプロットしています。
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov \ Year 2001 18.1 37.7 63.2 48.2 30.1 56.3 22.3 17.6 10.6 10.2 61.6 2002 48.6 96.0 81.5 44.2 26.1 32.6 15.3 11.0 3.8 4.7 12.2 2003 46.1 145.3 80.3 45.3 32.7 23.6 25.6 24.9 22.6 10.9 26.8 2004 28.6 68.1 66.0 18.7 69.8 60.4 18.7 8.7 5.6 4.7 12.2 2005 50.9 53.3 74.9 88.8 35.7 26.2 29.6 12.7 11.7 32.3 35.7 2006 36.0 90.4 70.8 68.3 53.7 56.9 17.3 8.6 9.2 4.7 12.2 2007 35.8 62.0 57.8 99.4 33.7 78.0 26.6 19.6 13.2 7.4 26.3 2008 23.2 51.5 45.2 49.0 32.7 55.1 45.5 34.0 14.7 31.4 87.0 2009 74.7 58.8 134.6 30.4 36.0 21.4 22.7 16.5 3.9 6.5 29.6 2010 52.6 92.4 93.7 62.1 39.5 43.9 32.4 58.5 33.8 64.7 63.2 2011 33.1 58.4 55.9 53.6 45.1 32.6 32.0 8.7 23.6 11.7 25.8 2012 76.7 79.8 93.0 83.3 69.1 45.2 26.2 19.4 14.6 13.5 25.7 2013 28.3 72.0 70.2 66.0 38.6 47.3 55.8 22.9 13.7 8.4 37.5 2014 33.5 34.1 57.9 63.3 57.3 41.6 57.9 23.2 4.0 7.8 39.1 2015 33.3 77.4 66.9 39.5 41.5 21.5 15.0 8.6 3.8 4.7 12.3 2016 29.0 91.6 88.1 106.3 34.0 54.6 24.1 12.9 33.3 31.4 41.4 2017 30.6 58.0 69.2 68.8 56.5 61.3 29.1 28.2 18.5 45.2 65.6 Ave. 40.0 72.2 74.7 60.9 43.1 44.6 29.2 19.8 14.1 17.7 36.1 Dec Ave. Year 2001 62.3 36.4 2002 15.6 32.2 2003 75.4 46.0 2004 32.9 32.8 2005 75.0 43.9 2006 17.3 36.7 2007 35.0 40.9 2008 88.8 46.4 2009 39.9 39.6 2010 42.8 56.4 2011 70.5 37.5 2012 34.1 48.3 2013 38.6 41.4 2014 55.5 39.7 2015 26.1 28.9 2016 49.7 49.4 2017 39.4 47.4 Ave. 47.0 41.4
プログラム全文
import numpy as np import pandas as pd import datetime import matplotlib.pyplot as plt import seaborn as sns # global ylist=['2001','2002','2003','2004','2005','2006','2007','2008','2009','2010', \ '2011','2012','2013','2014','2015','2016','2017'] # year def rdata(): fnameR='xls_qq_kuroki.xlsx' # input file name sname='Sheet1' df=pd.read_excel(fnameR, sheet_name=sname) # read excel data q=df['m3/s'] d=df['date'] qq=pd.Series(np.array(q),index=d) return qq def makedf(qq): mlist=['-01','-02','-03','-04','-05','-06','-07','-08','-09','-10','-11','-12'] n=len(ylist) m=len(mlist) qt=np.zeros((n+1,m+1),dtype=np.float64) # sum of discharges of a month ct=np.zeros((n+1,m+1),dtype=np.int) # sum of days of a manth for i,sy in enumerate(ylist): for j,sm in enumerate(mlist): sym=sy+sm qd=np.array(qq[sym]) qt[i,j]=np.sum(qd) ct[i,j]=len(qd) for i in range(n): qt[i,m]=np.sum(qt[i,0:m]) ct[i,m]=np.sum(ct[i,0:m]) for j in range(m): qt[n,j]=np.sum(qt[0:n,j]) ct[n,j]=np.sum(ct[0:n,j]) qt[n,m]=np.sum(qq) ct[n,m]=len(qq) df = pd.DataFrame({'Year': ylist+['Ave.'], 'Jan' : qt[:,0]/ct[:,0], 'Feb' : qt[:,1]/ct[:,1], 'Mar' : qt[:,2]/ct[:,2], 'Apr' : qt[:,3]/ct[:,3], 'May' : qt[:,4]/ct[:,4], 'Jun' : qt[:,5]/ct[:,5], 'Jul' : qt[:,6]/ct[:,6], 'Aug' : qt[:,7]/ct[:,7], 'Sep' : qt[:,8]/ct[:,8], 'Oct' : qt[:,9]/ct[:,9], 'Nov' : qt[:,10]/ct[:,10], 'Dec' : qt[:,11]/ct[:,11], 'Ave.': qt[:,12]/ct[:,12]}) df=df.set_index('Year') return df def fighmap(df): wid=0.5*(len(ylist)+1) fsz=14 plt.figure(figsize=(12,wid),facecolor='w') plt.rcParams['font.size']=fsz plt.rcParams['font.family']='sans-serif' # cm='YlGnBu' cm='Blues' sns.heatmap(df,annot=True,fmt='.1f',vmin=0,vmax=160,cmap=cm,cbar=False,linewidths=0.5) plt.xlabel('Month') plt.ylabel('Year') plt.yticks(rotation=0) plt.title('Monthly Average Discharge (m$^3$/s)',loc='left') fnameF='fig_hmap2.jpg' plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.1) plt.show() def figts(df): # arrange of subplot # ---------------------------- # i= 0 i= 1 i= 2 i= 3 i= 4 # i= 5 i= 6 i= 7 i= 8 i= 9 # i=10 i=11 i=12 i=13 i=14 # i=15 i=16 # ---------------------------- icol=5 irow=4 fsz=11 xmin=0;xmax=12 ymin=0;ymax=200 x=np.array([1,2,3,4,5,6,7,8,9,10,11,12]) x=x-0.5 mlist=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] emp=['']*12 plt.figure(figsize=(12,12/icol*irow),facecolor='w') plt.rcParams['font.size']=fsz plt.rcParams['font.family']='sans-serif' plt.suptitle('Monthly Average Discharge in Each Year', x=0.5,y=0.91,fontsize=fsz+4) plt.subplots_adjust(wspace=0.07,hspace=0.07) for i,sy in enumerate(ylist): num=i+1 plt.subplot(4,5,num) plt.xlim([xmin,xmax]) plt.ylim([ymin,ymax]) if i==0 or i==5 or i==10 or i==15: plt.ylabel('Discharge (m$^3$/s)') else: plt.yticks([]) if 12<=i: plt.xticks(x,mlist,rotation=90) else: plt.xticks(x,emp,rotation=90) y=df.loc[sy][0:12] qa=df.loc[sy][12] plt.plot(x,y,'o-',color='#000080',lw=1) plt.plot([xmin,xmax],[qa,qa],'--',color='#ff0000',lw=2) plt.text(8.5,qa,'Qave',fontsize=fsz,va='bottom',ha='center', color='#ff0000') s1='Year: '+sy s2='Qave: {0:.1f}'.format(qa) textstr=s1+'\n'+s2 props = dict(boxstyle='square', facecolor='#ffffff', alpha=1) xs=xmin+0.95*(xmax-xmin); ys=ymin+0.95*(ymax-ymin) plt.text(xs,ys, textstr, fontsize=fsz+2,va='top',ha='right', bbox=props) fnameF='fig_series2.jpg' plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.1) plt.show() def main(): qq=rdata() df=makedf(qq) pd.options.display.precision = 1 print(df) fighmap(df) figts(df) #============== # Execution #============== if __name__ == '__main__': main()