LoginSignup
17
12

More than 3 years have passed since last update.

python のデータ可視化のフレームワークに Dash(https://dash.plotly.com/) があります。

これが Google Colab でも利用可能に、、と思ったのですが、すでに解説されている良記事を見つけてしまいました。
https://qiita.com/OgawaHideyuki/items/725f4ffd93ffb0d30b6c

ということで、この記事は参考にさせていただいて自分の手を動かしました、という記録です。
お題は安直に各国のコロナ感染者数の可視化です。地図と時系列のグラフを表示してみます。

2020-12-27 追記: 地図表示を追加しました。

使用する環境やリソースなど

Google Colaboratory を使用します。

各種リソース
  • Dash https://dash.plotly.com/
    • グラフライブラリである Plotly と Flask を使用して、インンタラクティブなデータ可視化画面を簡単に作れる Python フレームワークです。
  • 国・地域別感染者データ https://github.com/CSSEGISandData/COVID-19
    • Johns Hopkins 大学の国・地域別感染者データを使用します。
  • Mapbox https://www.mapbox.com/
    • 地図上の散布図表示で使用する地図サービスです。
今回のノートブック

マップの散布図表示は Mapbox の token と Google drive を使用するため、ノートブックは時系列とマップで 2つに分けています。

時系列のグラフ表示

実行準備とデータ

まず Google Colab/Jupyter ノートブックから Dash を使用するためのパッケージをインストールします。

! pip install jupyter_dash
! pip install --upgrade plotly

Dash と関連するパッケージを import します。

import dash 
from jupyter_dash import JupyterDash 
import dash_core_components as dcc 
import dash_html_components as html 
import plotly.express as px
from dash.dependencies import Input, Output

コロナの感染者データを GitHub から取得します。
データに関しては下記のページを参考にさせていただいています。
https://dodotechno.com/covd-19-visualization/

! wget https://github.com/CSSEGISandData/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv

データフレームにダウンロードした csv を読み込みます。

import pandas as pd
df = pd.read_csv("time_series_covid19_confirmed_global.csv")

region ごとの集計、緯度経度の削除、国ごとの列に転置し、date 列の追加を行います。

df = df.groupby(['Country/Region'], as_index=False).sum()
df.drop(["Lat","Long"], axis=1,inplace=True)
df = df.T
df.columns =  df.iloc[0]    
df = df[1:]
df.reset_index(inplace=True)
df.rename(columns={'index': 'date'},inplace=True)
df

結果、得られる表は以下のようになります。

image.png

ノートブックに表示してみる

まず日本の感染者数をグラフ化してみます。
横軸を日付、縦軸が感染者数としており、第一波(4月下旬)、第二波(8月上旬)、第三波(11月)らしき増加が見えます。

px.line(df, x="date", y="Japan")

image.png

つづいて任意の国をドロップダウンで選択可能にしてみます。
ノートブック上で選択できますので、試してみてください。ランタイムが停止している場合は、メニューの「ランタイム」→「すべてのセルを実行」を行ってみてください。
https://colab.research.google.com/drive/1fUP4818fSsFFFlUHlLGNoTxq8uoL2VAu#scrollTo=Kr-FsvLIpCoN&line=1&uniqifier=1

app = JupyterDash(__name__)

app.layout = html.Div([
  dcc.Dropdown(id="my_dropdown",
    options=[{"value": country, "label": country} for country in df.columns.unique()],
    value=["Japan"],
    multi=True
    ),
  dcc.Graph(id="my_graph")
])

@app.callback(Output("my_graph", "figure"), Input("my_dropdown", "value"))
def update_graph(selected_country):
  return px.line(df, x="date", y=selected_country)

app.run_server(mode="inline")

ドロップダウンから、日本とカナダを選択して表示します。カナダも増加傾向のようですね。

image.png

続いてアメリカを追加してみると、本当に日本の比ではないですね。。やはりグラフで見るとインパクトがあります。
ワクチンが有効打になって欲しいです(人ごとではありませんが)。

image.png

地図上に表示

同じデータを使用して地図上で散布図を表示してみます。

実行準備とデータ

Mapbox という地図サービスを利用します。利用にはアクセストークンが必要になります。アカウントがない場合は、下記から sign up してアスセストークンを取得してください。
https://account.mapbox.com/
最低限、ID, パスワード, メールアドレスがあれば利用できます。

今回は Google drive にトークンを格納します。ご自身で実行される場合は、文字列としてコードに埋め込んで実行することも可能です。

ここでは例として、Mapbox のトークンの内容を貼り付けたテキストファイル mapbox-token.txt を Google drive のマイドライブ直下にアップロードします。

image.png

Google drive をマウントして、Mapbox のトークンを読み込みます。
マウント時の OAuth のトークンは実行時に表示される URL のページに飛ぶと表示されるので、コピー&ペーストなどで入力します。

from google.colab import drive
drive.mount('/content/drive')

f = open('/content/drive/My Drive/mapbox-token.txt', 'r')
MAPBOX_TOKEN = f.read()
f.close()

Jupyter dash の import は時系列のグラフと同様です。

! pip install jupyter_dash
! pip install --upgrade plotly
import dash 
from jupyter_dash import JupyterDash 
import dash_core_components as dcc 
import dash_html_components as html 
import plotly.express as px
from dash.dependencies import Input, Output

コロナの感染者データも同様に取得します。

! wget https://github.com/CSSEGISandData/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv

データフレームにダウンロードした csv を読み込みます。

df_map = pd.read_csv("./time_series_covid19_confirmed_global.csv")
df_map

今回は地域ごとの集計のみ取り、緯度経度を残して転置は行わない形にします。

df_map = df_map.groupby(['Country/Region'], as_index=False).sum()
df_map

image.png

準備ができましたので、地図で表示します。

地図上で表示

日付と色指定の基準を選択可能にして表示します。
こちらを参考にしています。
https://qiita.com/banquet_kuma/items/e02ba60661cf91af37de

  • color_opt, date_opt はデータフレームの列名から、緯度経度、緯度経度+国名を除いています。
  • MAPBOX_TOKEN は先ほど Google drive にアップしたファイルから読み込んだ値です。お手元で実行する場合は、文字列でそのまま貼り付けても OK です。
    • ノートブックのコードで、実行される方の Google アカウントのドライブにアクセスできるはずですが、自分のアカウント以外では試せていないので、うまくいかなかったらご指摘ください。
  • 見た目も色々と変更できます。オプションについて後述します。
app = JupyterDash(__name__)

color_opt = [dict(label=x, value=x) for x in df_map.columns]
del color_opt[2]
del color_opt[1]
date_opt = color_opt.copy()
del date_opt[0]

app.layout = html.Div(
    [
        html.Div(
            [
                html.P(["date:", dcc.Dropdown(id='date', options=date_opt)]),
                html.P(["color:", dcc.Dropdown(id='color', options=color_opt)]),
            ],
            style={"width": "20%", "float": "left"}
        ),
        dcc.Graph(id="graph", style={"width": "80%", "display": "inline-block"}),
    ]
)

@app.callback(Output("graph", "figure"), [Input("date", "value"), Input("color", "value")])
def update_graph(date, color):
  px.set_mapbox_access_token(MAPBOX_TOKEN)
  if not color:
    color = date
  return  px.scatter_mapbox(df_map,
                        lat="Lat",
                        lon="Long",
                        color=color,
                        size=date,
                        size_max=20,
                        zoom=0,
                        center={'lat': 35, 'lon': 135},
                        title="各国のコロナ感染者数",
                        color_continuous_scale=px.colors.diverging.BrBG,
                        hover_name=date)

app.run_server(mode="inline")

実行するとこんな感じです。表示がキレイです。
image.png

日付を選択すると、その時点の累積の感染者を表示します。
2020-12-01 はこんな感じです。
image.png

表示は plotly.express.scatter_mapbox という関数で行なっています。
plotly.express.scatter_mapbox のパラメーターの日本語の説明が見当たらなかったので参考に簡単な説明を載せておきます(よい情報源をご存知の方、コメントなどで教えてください)。

  • data_frame (DataFrame or array-like or dict) – 列名でデータを渡すための DataFrame です。
  • lat (str or int or Series or array-like) – 地図上の緯度です。
  • lon (str or int or Series or array-like) – 地図上の経度です。
  • color (str or int or Series or array-like) – 地図上のマーカーに色を割り当てるための指定です。
  • text (str or int or Series or array-like) – figure 中の表示のためのテキストラベルです。
  • hover_name (str or int or Series or array-like) – マウスのホバー時のツールチップ表示名です。
  • hover_data (list of str or int, or Series or array-like, or dict) – マウスのホバー時のツールチップデータです。2つ要素を指定でき、1番目の要素は表示の True(デフォルト)/False またはデータ表示フォーマットを指定します。2番目の要素は表示する値です。
  • custom_data (list of str or int, or Series or array-like) – ウィジットや Dash コールバックで使用する追加のデータです。ユーザーには表示されませんが figure のイベント(投げ縄ツール、註:たぶん範囲選択)などで使用します。
  • size (str or int or Series or array-like) – 地図上のマークのサイズです。
  • animation_frame (str or int or Series or array-like) – アニメーションフレーム(註:アニメーションフレームがよくわかっていません。。)にマークを割り当てをするために使用します。
  • animation_group (str or int or Series or array-like) – アニメーションフレーム全体で不変のオブジェクトを提供し、同一の animation_group は各フレームで同じオブジェクトを記述するように扱います。
  • category_orders 軸、凡例、ファセットのカテゴリ値の順序を指定します(デフォルトは {} )。python 3.6 以前では順序が保証されません。
  • labels (dict with str keys and str values (default {})) – デフォルトでは列名は、軸のタイトル、凡例のエントリ、およびホバーの図で使用されます。これを上書きする列名に対応する dict です。
  • color_discrete_sequence (list of str) – 色の循環指定です。CSS として有効な色指定を行います。
    • plotly.express.colors 特に plotly.express.colors.qualitative は便利なカラーシーケンスがあります。
  • color_discrete_map (dict with str keys and str values (default {})) – 有効な CSS 色の指定列です。
  • color_continuous_scale (list of str) – カラーで指定された列が連続値の数値データである場合のカラースケールを指定します。
    • 便利なカラースケール plotly.express.colors 特に plotly.express.colors.sequential, plotly.express.colors.diverging and plotly.express.colors.cyclical で使用できます。
  • range_color (list of two numbers) – 指定すると連続するカラースケールの指定を上書きします。
  • color_continuous_midpoint (number (default None)) – 連続カラースケールの中間の境界点を指定します。 plotly.express.colors.diverging を使用する場合に推奨されます。
  • opacity (float) – マーカーの透明度を指定します。
  • size_max (int (default 20)) – マーカーの最大サイズを指定します。
  • zoom (int (default 8)) – マップのズームサイズを 0〜20 で指定します。
  • center (dict) – マップの中央を緯度経度(lat, lon をキーとする dict)で指定します。
  • mapbox_style (str (default 'basic', needs Mapbox API token)) – マップのスタイルを指定します。スタイルによっては、Mapbox API token が必要です。
    • 'open-street-map', 'white-bg', 'carto-positron', 'carto-darkmatter', 'stamen- terrain', 'stamen-toner', 'stamen-watercolor' は token が不要です。
    • 'basic', 'streets', 'outdoors', 'light', 'dark', 'satellite', 'satellite- streets' は token が必要です。
  • title (str) – タイトルを指定します。
  • template (str or dict or plotly.graph_objects.layout.Template instance) – テンプレート名または定義を指定します。
  • width (int (default None)) – 幅を pixels で指定します。
  • height (int (default None)) – 高さを pixels で指定します。

多い。。

残課題

課題点をいくつか挙げておきます。

  • 日付はスライバーバー選択などが嬉しい。
  • 値の桁数が違うせいか、ほとんど見えない国があるので調整が必要か(対数で出すとか?)。
  • ツールチップが表示されていない。原因不明。

おわりに

ちょっとした可視化なら簡単に実装でき、Google Colab でインターネット公開も容易です。
csv の加工が一番手間かも。

地図上の可視化なども追加してみたいと思います。(→2020-12-27 地図表示を追加しました、残課題あり)
まだ色々可視化できそうなので、そのうちやるかもしれません。

実行してみてわかりましたが、Google Colab のランタイム停止時にグラフの表示が残らないので、公開が必要な場合は Heroku かノートブックなら他の方法(matplotlib, plotly など)も併用した方が良いかもしれません。

関連・参考 URL

Dash 関連
データ関連
Mapbox 表示関連
17
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
12