「新型コロナウィルス感染者数の推移を詳しく知りたい」で、使用しているスクリプト(神奈川県版)
神奈川県の新規感染者数と、その内訳の世代別のデータをグラフ化している。
import requests import json import pandas as pd from pandas import json_normalize import matplotlib.pyplot as plt import japanize_matplotlib import datetime import os import csv import sys # =================================== # 関数 # =================================== def GetTimeStamp(): """ ///ファイル保存用のタイムスタンプ文字列 ///戻り値:文字列 """ dt = datetime.datetime.now() dt = dt.strftime('%Y_%m%d_%H%M_%S') return dt def CheckCsvFolderExists(): """ ///CSVファイルの保存先フォルダ有無チェック、作成/// ///戻り値:フォルダ名(string) """ # 探すべきフォルダ名 s1 = "csv_read_fld" s2 = "csv_out_fld" s3 = "table_out_fld" s_array = (s1,s2,s3) for s in s_array: if not os.path.exists(s): # ディレクトリが存在しない場合、ディレクトリを作成する print("Not exists, and created") os.makedirs(s) return s1,s2,s3 def ChangeDataToDatetime(df,colname_time): """ ///時刻表示をdatetime型にする """ #colname = 'axes.time' df[colname_time] = pd.to_datetime(df[colname_time]) return df def PickupDataFromDf(a,b,c,d,e,f,g,h): """ ///グラフ用にdataframeを用意する """ a = a b = b c = c d = d e = e f = f g = g h = h df1 = df[df[a].isin([b])] df2 = df[df[a].isin([c])] df3 = df[df[a].isin([d])] df4 = df[df[a].isin([e])] df5 = df[df[a].isin([f])] df6 = df[df[a].isin([g])] df7 = df[df[a].isin([h])] return df1,df2,df3,df4,df5,df6,df7 def DfSum(df0,df1,df2,df3,df4,df5,df6,df7): """ ///1日ごとの合計を算出 """ df0 = df0.resample('D').sum() df1 = df1.resample('D').sum() df2 = df2.resample('D').sum() df3 = df3.resample('D').sum() df4 = df4.resample('D').sum() df5 = df5.resample('D').sum() df6 = df6.resample('D').sum() df7 = df7.resample('D').sum() return df0,df1,df2,df3,df4,df5,df6,df7 def DfResetIndex(df0,df1,df2,df3,df4,df5,df6,df7): """ ///デフォルトindexを削除、index="発表日"にする """ df0 = df0.reset_index() df1 = df1.reset_index() df2 = df2.reset_index() df3 = df3.reset_index() df4 = df4.reset_index() df5 = df5.reset_index() df6 = df6.reset_index() df7 = df7.reset_index() return df0,df1,df2,df3,df4,df5,df6,df7 def CreatPltChart(df0,df1,df2,df3,df4,df5,df6,df7,charttitle,a,b,c,d,e,f,g,h): """ ///Matplotの表を作成する """ # グラフ上限値を決めておく(5℃~25℃) #tempMin = 10 #tempMax = 35 y0 = df0['count'] x0 = df0['発表日'] y1 = df1['count'] x1 = df1['発表日'] y2 = df2['count'] x2 = df2['発表日'] y3 = df3['count'] x3 = df3['発表日'] y4 = df4['count'] x4 = df4['発表日'] y5 = df5['count'] x5 = df5['発表日'] y6 = df6['count'] x6 = df6['発表日'] y7 = df7['count'] x7 = df7['発表日'] # グラフ設定値 ymin_all = 0 ymax_all = 3000 ymin = 0 ymax = 1000 ylines_1 = 100 ylines_2 = 500 ylines_3 = 300 xmin = datetime.date(2021,7,1) xmax = datetime.date(2021,9,30) # 日付情報取得 td2 = GetTimeStamp() # fig0 ------------------------------- fig0 = plt.figure("神奈川県感染者推移",figsize=(8,8)) # (data)---------------------------- chart0 = fig0.add_subplot(1,1,1) chart0.plot(x0, y0) plt.ylim(ymin_all, ymax_all) plt.xticks(rotation=90) plt.hlines(1000,xmin,xmax,"red",linestyle="solid") plt.hlines(2000,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart0.set_title(td2 + "/") chart0.set_xlabel("Time") chart0.set_ylabel("件数") # fig1------------------------------- fig1 = plt.figure(charttitle,figsize=(10,10)) # (data)---------------------------- chart1 = fig1.add_subplot(4,2,1) chart1.plot(x1, y1) plt.ylim(ymin, ymax) plt.xticks(rotation=90) plt.hlines(ylines_1,xmin,xmax,"red",linestyle="solid") plt.hlines(ylines_2,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart1.set_title(td2 + "/" + b) chart1.set_xlabel("Time") chart1.set_ylabel("件数") # (data)---------------------------- chart2 = fig1.add_subplot(4,2,2) chart2.plot(x2, y2) plt.ylim(ymin, ymax) plt.xticks(rotation=90) plt.hlines(ylines_1,xmin,xmax,"red",linestyle="solid") plt.hlines(ylines_2,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart2.set_title(td2 + "/" + c) chart2.set_xlabel("Time") chart2.set_ylabel("件数") # (data)---------------------------- chart3 = fig1.add_subplot(4,2,3) chart3.plot(x3, y3) plt.ylim(ymin, ymax) plt.xticks(rotation=90) plt.hlines(ylines_1,xmin,xmax,"red",linestyle="solid") plt.hlines(ylines_2,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart3.set_title(td2 + "/" + d) chart3.set_xlabel("Time") chart3.set_ylabel("件数") # (data)---------------------------- chart4 = fig1.add_subplot(4,2,4) chart4.plot(x4, y4) plt.ylim(ymin, ymax) plt.xticks(rotation=90) plt.hlines(ylines_1,xmin,xmax,"red",linestyle="solid") plt.hlines(ylines_2,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart4.set_title(td2 + "/" + e) chart4.set_xlabel("Time") chart4.set_ylabel("件数") # (data)---------------------------- chart5 = fig1.add_subplot(4,2,5) chart5.plot(x5, y5) plt.ylim(ymin, ymax) plt.xticks(rotation=90) plt.hlines(ylines_1,xmin,xmax,"red",linestyle="solid") plt.hlines(ylines_2,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart5.set_title(td2 + "/" + f) chart5.set_xlabel("Time") chart5.set_ylabel("件数") # (data)---------------------------- chart6 = fig1.add_subplot(4,2,6) chart6.plot(x6, y6) plt.ylim(ymin, ymax) plt.xticks(rotation=90) plt.hlines(ylines_1,xmin,xmax,"red",linestyle="solid") plt.hlines(ylines_2,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart6.set_title(td2 + "/" + g) chart6.set_xlabel("Time") chart6.set_ylabel("件数") # (data)---------------------------- chart7 = fig1.add_subplot(4,2,7) chart7.plot(x7, y7) plt.ylim(ymin, ymax) plt.xticks(rotation=90) plt.hlines(ylines_1,xmin,xmax,"red",linestyle="solid") plt.hlines(ylines_2,xmin,xmax,"red",linestyle="solid") # グラフ内のラベル表記 chart7.set_title(td2 + "/" + h) chart7.set_xlabel("Time") chart7.set_ylabel("件数") #----------------------------- # グラフの設定 #----------------------------- fig0.tight_layout() fig1.tight_layout() #----------------------------- # 戻り値 #----------------------------- return fig0,fig1 #plt.show() def CreateMatplotTable(df): """ /// Matplotのテーブルを作成する """ len_sanagiList = len(df) tableName = '神奈川県コロナウィルス感染者数の推移' # PltTable関数へ fig = PltTable( df, tableName, len_sanagiList ) return fig def PltTable(df,titleName,length): """ ///テーブル(表)を作成する/// """ # index number(1-) row_names=[] for i in range(1,length + 1,1): row_names.append(i) fig, ax = plt.subplots(figsize=(8, 8)) ax.set(title= titleName) ax.axis('off') ax.axis('tight') tb = ax.table(cellText=df.values, colLabels=df.columns,rowLabels=row_names,loc='left', bbox=[0, 0, 1, 1] ) tb.auto_set_font_size(False) tb.auto_set_column_width(col=list(range(len(df.columns)))) tb.set_fontsize(8) return fig def SaveDataAsJpeg(fig): """ ///テーブル(表)をjpgとして保存する/// """ currentdir = os.getcwd() timestamp = Timestamp() figName = "_Kanagawa" fig.savefig(currentdir + '/fig/' + timestamp + figName + "_.jpg") def Timestamp(): """ ///タイムスタンプ取得/// """ dt1 = datetime.datetime.now() dt2 = dt1.strftime('%Y_%m%d_%H%M_%S') return dt2 # save fig data as jpg file(weather info as chart) def SaveChart(fig1,fig2): currentdir = os.getcwd() dt2 = Timestamp() fig1.savefig(currentdir + '/fig/' + dt2 + "_Kanagawa_All.jpg") fig2.savefig(currentdir + '/fig/' + dt2 + "_Kanagawa_ByGenaration.jpg") # ====================================================================== # data # (1)APIリクエストによりjsonデータで情報取得する(※サーバ不可考慮必須) # (2)別途ダウンロードしたCSVファイルを読み込む # (3)Web上のCSVファイルを読み込む (※サーバ不可考慮必須) # 形式:data ⇒ DataFrame # ====================================================================== # ---------------------------------------------------- # (1)APIリクエストの場合 # ---------------------------------------------------- # ---------------------------------------------------- # (2)ローカル/CSVの読み込みの場合 # ---------------------------------------------------- # ---------------------------------------------------- # (3)Web上のCSV読み込みの場合 # ---------------------------------------------------- URL_csv = "https://www.pref.kanagawa.jp/osirase/1369/data/csv/patient.csv" df = pd.read_csv(URL_csv, encoding="SHIFT_JIS") # =================================================================================== # dataframeの修正 # データ中身:発表日、居住地、年代 # =================================================================================== # 日付 ⇒ Datetime型 colname_time = '発表日' df = ChangeDataToDatetime(df,colname_time) # 期間の絞り込み df = df[df['発表日'] >= datetime.datetime(2021,7,1)] # デフォルトindexを削除、index="発表日"にする(発表日で集計するため) df.set_index("発表日",inplace=True) # 「居住地」列を削除 df = df.drop(columns ='居住地') # カウンター設置 df['count'] = 1 # ------------------------- # データ作成 / 全年代データ # ------------------------- df0 = df # ------------------------- # データ作成 / 年代別データ(10代~70代) # ------------------------- # 絞り込み a = '年代' b = '10代' c = '20代' d = '30代' e = '40代' f = '50代' g = '60代' h = '70代' ageCategoryArray = (a,b,c,d,e,f,g,h) df1,df2,df3,df4,df5,df6,df7 = PickupDataFromDf(a,b,c,d,e,f,g,h) # ------------------------- # 1日毎の合計値の計算 # ------------------------- df0,df1,df2,df3,df4,df5,df6,df7 = DfSum(df0,df1,df2,df3,df4,df5,df6,df7) # ------------------------- # デフォルトindexを削除、index="発表日"にする # ------------------------- df0,df1,df2,df3,df4,df5,df6,df7 = DfResetIndex(df0,df1,df2,df3,df4,df5,df6,df7) dfa = (df0,df1,df2,df3,df4,df5,df6,df7) # ----------------- # matplot / chart # ----------------- charttitle = 'covid19' fig1,fig2 = CreatPltChart(df0,df1,df2,df3,df4,df5,df6,df7,charttitle,a,b,c,d,e,f,g,h) # ----------------- # matplot / table # ----------------- # カラム名を付けなおす df0 = df0.rename( columns = {'count': a} ) df1 = df1.rename( columns = {'count': b} ) df2 = df2.rename( columns = {'count': c} ) df3 = df3.rename( columns = {'count': d} ) df4 = df4.rename( columns = {'count': e} ) df5 = df5.rename( columns = {'count': f} ) df6 = df6.rename( columns = {'count': g} ) df7 = df7.rename( columns = {'count': h} ) # dataframeのマージ(df0~df7) joinResultData = pd.merge(df0,df1,on='発表日') joinResultData = pd.merge(joinResultData,df2,on='発表日') joinResultData = pd.merge(joinResultData,df3,on='発表日') joinResultData = pd.merge(joinResultData,df4,on='発表日') joinResultData = pd.merge(joinResultData,df5,on='発表日') joinResultData = pd.merge(joinResultData,df6,on='発表日') joinResultData = pd.merge(joinResultData,df7,on='発表日') # 期間の絞り込み joinResultData = joinResultData[joinResultData['発表日'] >= datetime.datetime(2021,7,1)] # 画面出力 pd.set_option('display.max_rows', None) print(joinResultData) # Matlibテーブル作成 figtable = CreateMatplotTable(joinResultData) SaveDataAsJpeg(figtable) SaveChart(fig1,fig2) # Matlib出力の実行 #plt.show()
◆データ取得方法
API、取得したCSV、CSV掲載WEBアドレス、この3つの方法で作成したが、現状はCSV掲載WEBアドレスを直接読みにいく。そのため、スクリプト実行の連打はNG
◆データはDtaFrameに
取得したデータは、pandas/DataFrameに入れて表形式に。新規感染者数全体はそのデータフレーム情報でいいのだが、内訳である世代別を抽出するために世代別ごとにデータフレームを作成。
◆matplotlib
上記のデータフレームの情報をmatplotlibでグラフ化している。作成したときはとにかくすぐに情報を見たかったので、「手続き型」のスクリプトになってしまっている。。。とりあえず見たいデータを可視化して活用できているのでそれでOK。
当初作ったときは、APIを使用してデータを引っ張ることを目的にしたが、なんか途中で止まったりよくわからん状況が続いたので、CSVをダウンロードしてデータ分析することに。その後、CSVを都度ダウンロードするのが面倒なので、CSVデータの掲載先へWEBアクセスして引っ張ることにした。 神奈川県、横浜市、この2つについては上記方法でデータ取得可能。しかし、横浜市の療養者数はCSV掲載先アドレスが日ごとに変わるので、現状は手打ちして引っ張りにいっている・・・ぁあ、スクリプトをスクレイピング用に修正するのも面倒だしね。。。。