COVID-19のデータでネットワーク図を作成した。

## はじめに

[厚生労働省のCOVID-19の感染状況](https://www.mhlw.go.jp/stf/newpage_09964.html)のデータを基に、グラフやネットワーク図、データテーブルを作成し、Webアプリケーション化しました。作成したアプリは下のリンクのものとなります。

[アプリリンク: https://chomoku.herokuapp.com/covid-19](https://chomoku.herokuapp.com/covid-19)


下はネットワーク図の画面です。

<a href="https://gyazo.com/b1fc10768c9728c17da2cd872d296266"><img src="https://i.gyazo.com/b1fc10768c9728c17da2cd872d296266.gif" alt="Image from Gyazo" width="912.5"/></a>

利用しているデータは厚生労働省のサイトから取得しています。スクレイピングといっても、pandasのread_html関数を使っているだけです。下のgithubからも取得できますが、後述するようにアプリからも取得できます。

https://github.com/mazarimono/chomoku/blob/master/src/kosei.csv

今回アプリを作成したきっかけは、[東洋経済さんの可視化](https://toyokeizai.net/sp/visual/tko/covid19/)を見て、自分ではこういうところを見てみたいなと思うところがあったのがきっかけでした。


アプリはタブでページが切り替えられ、次の3つの部分に分かれます。

1つ目は普通のグラフを表示するページ。
2つ目がネットワーク図を表示するページ。
3つ目が用いているCSVファイルをテーブルとして表示し、またそのデータをダウンロードできるページ。

アプリはWebフレームワークのDashを用いて作成しました。環境は以下のようになります。

Python 3.7.4
dash 1.9.0
dash-core-components 1.8.0
dash-html-components 1.0.2
dash-cytoscape 0.1.1
dash-table 4.6.0
plotly 4.5.0 

## 濃厚接触者数と患者数
今回様々なニュースを見ていて気になったのが、近くに長い時間いると感染するのか？ということでした。そこで、厚生省のウェブサイトの数値を見ていると、濃厚接触者数と周囲の患者の発生というデータがありました（ちなみに周囲の患者の発生はあまり更新されないので、データが正確に状況を表しているかどうかという点は不明瞭です）。

そこで、まずはそのデータを可視化してみることにしました。

患者数グラフのページの左下にそのグラフがあります。これはx軸が濃厚接触者数、y軸が患者数です。

![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85433/ff4e5cb0-bc1e-9a8d-3d22-490b0e3f1eee.png)

ちなみにこの可視化にはPlotly Expressを使っています。DashではGraphコンポーネントにfigureを渡してグラフを表示させます。コードは次のような感じです。

```python

import dash_core_components as dcc 
import plotly.express as px 

dcc.Graph(
                    id="ratio_scatter",
                    figure=px.scatter(
                        df_covid,
                        x="contact_num",
                        y="infection_num",
                        title="接触者数（x軸）と周囲の患者発生（y軸）",
                        hover_data=["新No."],
                    ),
                    className="six columns",
                )
```



## ネットワーク図

次に、データの「周囲の患者の発生」というところに、患者のナンバーが書かれています。元のデータに「新No.」と「旧No.」があり、どちらを指すのか微妙なところですが、「新No.」を指すと仮定して、ネットワーク図を作成します。

今回ネットワーク図の作成に用いたdash-cytoscapeは、cytoscapeを利用したコンポーネントで、ノードは新No.と居住地を使って作成し、エッジを周囲の患者の発生の番号とつなぎます。そうして、ノードの並びの種類はcoseを選択しています。すると下のようにつながりがあるものを良い感じに並べて表示してくれます。

<a href="https://gyazo.com/958e4769b0f830795f0aa1982fa6eb45"><img src="https://i.gyazo.com/958e4769b0f830795f0aa1982fa6eb45.gif" alt="Image from Gyazo" width="1325"/></a>

周囲の患者の発生のデータが「旧No.」で作られていると、このネットワーク図は間違っています。「新No.」で作られているとすると、横につけたデータと比較すると、間違いはなさそうな感じでした。

こうしてみると、かなり患者同士のつながりがありそうにも見えました。ちなみにこの部分の作成はcsvのデータを使って、ノードデータとエッジのデータを作って、cytoscapeで可視化するという感じになっております。コードは次のような感じです。

```python

import dash_cytoscape as cyto
import pandas as pd 
import ast 

# CSVファイルの読み込み
df_covid = pd.read_csv("./src/kosei.csv", index_col=0, parse_dates=["date"])

# cytoscapeのelementsに渡すデータの作成
covid_el = []
for i in range(len(df_covid)):
    covid_el.append(
        {
           # ノードのデータの作成
            "data": {
                "id": f"No.{df_covid.iloc[i, 0]}",
                "label": f"No.{df_covid.iloc[i, 0]} / {df_covid.iloc[i, 5]}",
            }
        }
    )
    # エッジのデータの作成
    contact_list = []
    for i2 in ast.literal_eval(df_covid.iloc[i, -2]):
        if i2.startswith("No."):
            covid_el.append(
                {"data": {"source": f"No.{df_covid.iloc[i, 0]}", "target": f"{i2}"}}
            )

network = html.Div(
    [
        html.Div(
            [
                html.H4("周囲の患者発生のネットワーク図"),
                cyto.Cytoscape(
                    id="covid_cyto",
                    layout={"name": "cose"}, # layout coseの選択
                    elements=covid_el,   # ネットワーク図で可視化するデータ
                    style={
                        "width": "100%",
                        "height": "80vh",
                        "backgroundColor": "white",
                        "borderRadius": "10px",
                    },
                ),
            ],
            className="eight columns",
        ),])
```

## CSVファイルをテーブルで表示

Dashではテーブルの作成方法は色々とあるのですが、ここではdash-tableを用いてテーブルを作成しています。このテーブルの良いところは、いろいろと編集できる点と、その編集したテーブルのデータを可視化に再利用したり、CSVファイルとしてユーザがダウンロードできる点です。ちなみにデータはCCなのでご自由にお使いください。

例えば「旧No.」以外のデータが欲しいと思った場合、下のようにテーブルのヘッダにあるゴミ箱をクリックしたあと、exportボタンを押すとCSVファイルがダウンロードされます。

<a href="https://gyazo.com/f7310d8a1e7acfe7ba922db25bc4c2e6"><img src="https://i.gyazo.com/f7310d8a1e7acfe7ba922db25bc4c2e6.gif" alt="Image from Gyazo" width="1342.5"/></a>

テーブルへのcsvファイルのダウンロード機能の付け方ですが、dash-tableパッケージのDataTableインスタンスのexport_formatに"csv"を渡すだけです。ここで作成しているテーブルのコードは次のようになります。

```python 

import dash_table

table = html.Div(
    [
        dash_table.DataTable(
            id="covid_table",
            columns=[{"name": i, "id": i, "deletable": True} for i in df_covid.columns],
            data=df_covid.to_dict("records"),
            fixed_rows={"headers": True, "data": 0},
            editable=True,
            filter_action="native",
            row_deletable=True,
            sort_action="native",
            export_format="csv",
            fill_width=False,
            virtualization=True,
            style_cell={"textAlign": "left"},
        ),
        html.Img(src="assets/cc.png"),
    ]
)
```

## まとめ

以上、厚生労働省のデータから気になった部分を抜き出して可視化したものをアプリ化してみました。

昨年、EthereumのイベントDevconに参加した時に、[台湾のオードリー・タンさん](https://news.yahoo.co.jp/feature/1517)が講演されていたんですね。その時に質問で「日本ではあんま何もわかってないおじいさんがIT担当大臣になったけど、どう思うか」ってのがあって、おいおいそんな答えにくい質問やめとけよと思ったけど、まぁその時質問した人の懸念が[現在実現化してしまった](https://www.fnn.jp/posts/00433267CX/202003041943_CX_CX)みたいなところがあります。

でも、昨日はちょうど[東京都が凄いサイト](https://stopcovid19.metro.tokyo.lg.jp/)も発表しましたし、どんどん使えるデータが増えて、それを使って役立つものがまた作られてみたいなサイクルができると良いですね。

ちなみにアプリケーションのコードはgithubにあります。アプリケーションは少しずつアップデートしていこうと思います。

https://github.com/mazarimono/chomoku/blob/master/app.py#L837

## 追記
たくさんのLGTMありがとうございます。アプリケーションを支えるフレームワークDashの簡単なハンズオンを「はんなりPython」で行います。ご関心を持たれた方はぜひ！     
      
https://hannari-python.connpass.com/event/170431/