アメグラ2号のブログ

1980年代後半の古き良きビデオゲームのほか、オッサンの個人的備忘録

python 新型コロナウィルス感染者数の推移を詳しく知りたい(神奈川県版)

「新型コロナウィルス感染者数の推移を詳しく知りたい」で、使用しているスクリプト(神奈川県版)

神奈川県の新規感染者数と、その内訳の世代別のデータをグラフ化している。

スクリプト

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、取得したCSVCSV掲載WEBアドレス、この3つの方法で作成したが、現状はCSV掲載WEBアドレスを直接読みにいく。そのため、スクリプト実行の連打はNG

◆データはDtaFrameに

取得したデータは、pandas/DataFrameに入れて表形式に。新規感染者数全体はそのデータフレーム情報でいいのだが、内訳である世代別を抽出するために世代別ごとにデータフレームを作成。

◆matplotlib

上記のデータフレームの情報をmatplotlibでグラフ化している。作成したときはとにかくすぐに情報を見たかったので、「手続き型」のスクリプトになってしまっている。。。とりあえず見たいデータを可視化して活用できているのでそれでOK。

当初作ったときは、APIを使用してデータを引っ張ることを目的にしたが、なんか途中で止まったりよくわからん状況が続いたので、CSVをダウンロードしてデータ分析することに。その後、CSVを都度ダウンロードするのが面倒なので、CSVデータの掲載先へWEBアクセスして引っ張ることにした。 神奈川県、横浜市、この2つについては上記方法でデータ取得可能。しかし、横浜市の療養者数はCSV掲載先アドレスが日ごとに変わるので、現状は手打ちして引っ張りにいっている・・・ぁあ、スクリプトスクレイピング用に修正するのも面倒だしね。。。。