よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【クラスの書き方練習】厚労省コロナデータを使ったグラフ作成

クラスの書き方を、グラフ作成で練習します。

正しい書き方なのかどうか分かりません。やったら動いたのでw
クラス内のメソッドから、同一クラス内の別メソッドを実行する方法を学びます。

先に、こちら→オープンデータ|厚生労働省 に置いてある新型コロナのデータcsvファイルをローカルにダウンロードしておきます。
ファイルのurlをそのまま指定してもできます。(実行する度にサイトにアクセスしてダウンロードする。負担。



目次




作業環境


Androidスマホ
termux
Python3.8
JupyterNotebook



仕様


  • Android上のJupyterNotebookでのみ動作確認。
  • 保存したcsvファイルを使う場合(files)
  • サイトから直接csvを読み込む場合(urls)
    • 実行するとき、リスト「files」を「urls」に書き換える。
  • ipynbのスクリプトを実行すると、リストを全て自動でグラフ化し、作業ディレクトリにグラフの画像ファイルを保存します。
  • JupyterNotebookにもグラフを表示します。合計6枚(最後のだけ2枚)



実装


ローカル保存ファイルからグラフ化する時のリスト

# ローカルに保存したファイルのリスト
files = ["pcr_positive_daily.csv",
        "pcr_tested_daily.csv",
        "cases_total.csv",
        "recovery_total.csv",
        "death_total.csv"]

↑のリストにある5つのファイルを厚労省のサイトから作業ディレクトリに保存しておきます。



厚労省サイトから直接読み込む場合

urls = ["https://www.mhlw.go.jp/content/pcr_positive_daily.csv",
       "https://www.mhlw.go.jp/content/pcr_tested_daily.csv",
       "https://www.mhlw.go.jp/content/cases_total.csv",
       "https://www.mhlw.go.jp/content/recovery_total.csv",
       "https://www.mhlw.go.jp/content/death_total.csv"]
# ライブラリのインポート
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# グラフ作図クラス
class DrawGraph:
    
    def __init__(self,url):
        self.url = url
    
    # csvファイル読込とデータフレーム作成
    def make_df(self):
        return pd.read_csv(self.url)
    
    # Numpy配列作成
    def make_np(self):
        df = self.make_df()
        return np.array(df)
    
    # x,yの配列作成
    def make_xy(self):
        ndarr = self.make_np()
        x = np.array(ndarr[:,0])
        y = np.array(ndarr[:,1])
        return x,y
    
    # タイトル作成
    def make_title(self):
        x,y = self.make_xy()
        if len(self.url) > 31:
            title = self.url  + "\n" + x[0] + "-" + x[-1]
        else:
            title = self.url[:-4] + "\n" + x[0] + "-" + x[-1]
        return title
    
    # 死亡者数データを日毎に変換
    def make_death_daily_data(self):
        x,y = self.make_xy()
        y = np.append(1,np.diff(y))
        return x,y
    
    # ファイル保存名の作成
    def make_filename(self):
        if len(self.url) > 31:
            filename = self.url[31:-4] + ".png"
        else:
            filename = self.url + ".png"
        return filename
    
    # グラフ作図
    def draw_graph(self):
        title = self.make_title()
        
        # 死亡者数グラフ
        if "death" in title:
            
            # death total graph(積算)
            plt.title(title)
            x,y = self.make_xy()
            plt.plot(x,y)
            plt.xticks(x[::14],rotation=45)
            plt.plot(x,y)
            filename = self.make_filename()
            plt.savefig(filename)
            plt.show()
            
            # death daily graph(日毎)
            x,y = self.make_death_daily_data()
            title = "death_daily" + "\n" + x[0] + "-" + x[-1]
            plt.title(title)
            plt.plot(x,y)
            plt.xticks(x[::14],rotation=45)
            plt.plot(x,y)
            filename = self.make_filename()
            plt.savefig("daily-"+filename)
            plt.show()
        
        # 死亡者数以外のグラフ
        else:
            plt.title(title)
            x,y = self.make_xy()
            plt.plot(x,y)
            plt.xticks(x[::14],rotation=45)
            plt.plot(x,y)
            filename = self.make_filename()
            plt.savefig(filename)
            plt.show()





実行


↑のスクリプトを実行しても何も起こりません。

↓のを実行するとグラフ化が始まります。
for url in ○○の所の○○を「files」「urls」のどちからに書き換えて実行。
「files」は作業ディレクトリにダウンロード済みファイルから。
「urls」はサイトから直接読み込み。

# 実行 (files か urls に書き換えること)
for url in urls:

    h = DrawGraph(url) 
    #print(h.make_df().tail()) # データフレーム表示
    #print(h.make_np()) # Numpy配列で表示
    #print(h.make_xy()) # 横・縦軸に分けて表示
    h.draw_graph() # グラフ化

f:id:chayarokurokuro:20200731155200j:plain

f:id:chayarokurokuro:20200731155221j:plain

f:id:chayarokurokuro:20200731155249j:plain

f:id:chayarokurokuro:20200731155307j:plain

f:id:chayarokurokuro:20200731155329j:plain

f:id:chayarokurokuro:20200731155344j:plain

注意)
グラフ化の実行部分でのコメントアウトを外すと、大量にデータフレームや配列が表示されます。



説明


適当にやったら動いたので説明と言って良いのか…とりあえず気がついたことだけを。

作成する際の発想の流れ


  1. クラスがファイルパスを受けとる
  2. Pandasでcsvをデータフレームに取り込む
  3. それをNumpy配列に変換する
  4. 横軸(日付)と縦軸(数値)の配列に分ける
  5. グラフのタイトル作成のメソッドも作った
  6. 死亡者数の積算データを日毎データに変換するメソッドも用意
  7. 上記をグラフ作成メソッドに渡す
    1. もし死亡者数データなら積算と日毎の2つのグラフを作成する
    2. そうでなければデータのままをグラフ化する



プログラムは、クラスやメソッドを使わなくとも書ける。なぜわざわざ使うかと言うと、メンテナンスしやすくする為だという。
だから、それらの一つひとつは単純な方が良いはず。内部で条件分岐などしない方が良い。

しかし、今回は練習ということで(言い訳)、一つのクラスにどのように詰めて書けば動くかを調べた。(嘘。適当に書いたらこうなったw)

グラフ作成部分のメソッドdraw_graph()は重複している箇所がある。これも関数やクラスにするなりして簡潔に書ける筈ですが、そのうち気が向けば改良する。



同一クラス内で、あるメソッドから別メソッドを実行する方法


class クラス名:
    def __init__(self, url): # ①
        self.url = url
        
    def ぱんだす読込(self):  # ②
        return pd.read_csv(self.url)
        
    def なんぱい変換(self):  # ③
        df = ぱんだす読込()  ← ②を実行
        return np.array(df)
        
# 実行
ins = クラス名(ファイルパス名)  # インスタンス生成
ins.なんぱい変換()  # ③メソッド実行

↑のように③だけを実行すれば、③内部に書いた②が実行されて戻り値が③に渡り、Numpy配列だけを得られる。



以上。