「新型コロナウィルス感染者数の推移を詳しく知りたい」で、使用しているスクリプト(神奈川県版)
神奈川県の新規感染者数と、その内訳の世代別のデータをグラフ化している。
◆スクリプト
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型にする
"""
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の表を作成する
"""
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 = plt.figure("神奈川県感染者推移",figsize=(8,8))
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 = plt.figure(charttitle,figsize=(10,10))
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("件数")
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("件数")
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("件数")
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("件数")
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("件数")
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("件数")
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
def CreateMatplotTable(df):
"""
/// Matplotのテーブルを作成する
"""
len_sanagiList = len(df)
tableName = '神奈川県コロナウィルス感染者数の推移'
fig = PltTable(
df,
tableName,
len_sanagiList
)
return fig
def PltTable(df,titleName,length):
"""
///テーブル(表)を作成する///
"""
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
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")
URL_csv = "https://www.pref.kanagawa.jp/osirase/1369/data/csv/patient.csv"
df = pd.read_csv(URL_csv, encoding="SHIFT_JIS")
colname_time = '発表日'
df = ChangeDataToDatetime(df,colname_time)
df = df[df['発表日'] >= datetime.datetime(2021,7,1)]
df.set_index("発表日",inplace=True)
df = df.drop(columns ='居住地')
df['count'] = 1
df0 = df
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)
df0,df1,df2,df3,df4,df5,df6,df7 = DfSum(df0,df1,df2,df3,df4,df5,df6,df7)
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)
charttitle = 'covid19'
fig1,fig2 = CreatPltChart(df0,df1,df2,df3,df4,df5,df6,df7,charttitle,a,b,c,d,e,f,g,h)
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} )
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)
figtable = CreateMatplotTable(joinResultData)
SaveDataAsJpeg(figtable)
SaveChart(fig1,fig2)
◆データ取得方法
API、取得したCSV、CSV掲載WEBアドレス、この3つの方法で作成したが、現状はCSV掲載WEBアドレスを直接読みにいく。そのため、スクリプト実行の連打はNG
◆データはDtaFrameに
取得したデータは、pandas/DataFrameに入れて表形式に。新規感染者数全体はそのデータフレーム情報でいいのだが、内訳である世代別を抽出するために世代別ごとにデータフレームを作成。
◆matplotlib
上記のデータフレームの情報をmatplotlibでグラフ化している。作成したときはとにかくすぐに情報を見たかったので、「手続き型」のスクリプトになってしまっている。。。とりあえず見たいデータを可視化して活用できているのでそれでOK。
当初作ったときは、APIを使用してデータを引っ張ることを目的にしたが、なんか途中で止まったりよくわからん状況が続いたので、CSVをダウンロードしてデータ分析することに。その後、CSVを都度ダウンロードするのが面倒なので、CSVデータの掲載先へWEBアクセスして引っ張ることにした。
神奈川県、横浜市、この2つについては上記方法でデータ取得可能。しかし、横浜市の療養者数はCSV掲載先アドレスが日ごとに変わるので、現状は手打ちして引っ張りにいっている・・・ぁあ、スクリプトをスクレイピング用に修正するのも面倒だしね。。。。