可視化フレームワークDashで世界統計地図を描いてみた
Dashとはカナダに拠点をおくPlotly社が開発しているPythonから利用できるWebフレームワークで、様々なデータの可視化・グラフ化に利用できます。
以前紹介したPlotlyというPythonライブラリもこのDashで使えますし、Dashでは独自にグラフ化のためのコンポーネントを用意しているほか、htmlのタグ等もコンポーネント化していますので、簡単なWebページが作成できるというものです。Plotlyと同様にインタラクティブにグラフの操作が可能です。また、pandasのDataFrameを使えるのも良いですよね。
今回は、世界銀行が公表しているデータをworld_data_bank
というライブラリを使って取得。このデータをDash上にグラフ化し、Herokuにデプロイしました。画面はこんな感じ。
サイトへのリンクはこちら↓
https://world-bank-map.herokuapp.com
左上のドロップダウンにて「一人当たりGDP(ドル)」「平均寿命」「人口」。隣のドロップダウンで「西暦年」を選択すると、グラフが表示されます。右のドロップダウンはDashで利用可能なカラーパレットです。いろいろなカラースケールを確かめたく、選択できるようにしてみました。また、グラフ表示だけでなく、タブでテーブルを選択するとグラフ表示で利用したデータをテーブル形式で見られるようにもしました。
世界銀行の公表データの取得
世界銀行(World Bank)は数多くのデータを公表していて、APIを利用して取得することができます。Pythonの場合、世界銀行のAPIを直接利用しなくても、このAPIを利用したモジュールがいくつかあります。
有名どころではpandas_datareader
を利用することができます。
pandas-datareader.readthedocs.io
今回は、公表データの一覧表等を比較的入手しやすいworld_bank_data
というモジュールを利用しました。
pypi.org
インストールは以下の通り。
pip install world_bank_data --upgrade
どんな感じのデータか見てみましょう。world_bank_data
とpandas
をインポートしておきます。
import world_bank_data as wbd import pandas as pd
データを取得するには何のデータか特定する必要があります。World BankではIndicatorと呼んでいますが、こちらのサイトから検索できます。
Data Catalog | Data Catalog
あるいは、world_bank_data
のget_indicators()
メソッドで全てのIndicatorを取得(17473 行!)して探すか、あるいはsearch_indicators('キーワード')
で検索するかして、入手したいデータのindicatorを特定します。
今回は、「一人当たりGDP(ドル)」「平均寿命」「人口」を取得したいと思います。それぞれindicatorはNY.GDP.PCAP.KD
, SP.DYN.LE00.IN
, SP.POP.TOTL
となります。
get_series('インディケーター')
メソッドで取得すると
MultiIndexのDataFrameが返されます。MultiIndexのうち、CountryとYearを軸にこれら3つのDataFrameをpandasのmergeを使って統合します。ついでに、indicatorをわかりやすい日本語に変えておきます。
_df = pd.merge(df_gdp_pcap,df_lifeexp, on=['Country', 'Year']) _df = pd.merge(_df, df_pops, on=['Country', 'Year']) _df.columns = ['一人当たりGDP(ドル)', '平均寿命(歳)', '人口(人)']
Dashのコロプレス図(choropleth map)を描くには、3文字の国コードが必要になります。幸いworld_bank_data
では簡単に国・地域の一覧が入手できます。
df_all_countries = wbd.get_countries()
結果を見てみると、一番左のidが3文字の国コードですね。
これを先ほどの_df
と統合します。_dfのCountry欄とdf_all_countriesのname欄の紐つけています。
df = pd.merge(_df.reset_index(), df_all_countries.reset_index(), left_on='Country', right_on='name')
これだと、Country 欄にはまだ、国以外に地域(東アジア、ヨーロッパ等)が残っていますので、国だけのリストにします。ついでに、不要な欄を削除し、Year欄を文字列から整数列に変えておきます。
df = df[df['region'] != 'Aggregates'].reset_index(drop=True) df = df.drop(['iso2Code','name', 'adminregion', 'incomeLevel', 'lendingType', 'capitalCity', 'longitude','latitude'], axis=1).reset_index(drop=True) df['Year'] = df['Year'].astype(int)
Dashアプリを作成する
Dashについて、細かく説明するのは大変なので、省略します。すみません(笑)。詳しくは、本家の英語のTutorialを参照いただくか、日本語でチュートリアルを解説されているサイトをご参照いただければと思います。
ここではチュートリアルに書かれていないポイントを中心にいくつか記載します。
DashでBootstrapを利用する
今回タブを使っています。Dashにおいて標準で提供されているタブはdash_core_component
のTabなんですが、横に間延びしてしまって、格好が悪いんですよね。なので、dashでBootstrapを利用するためのモジュールであるdash_bootstrap_components
をインストールして利用しています。
このdash_bootstrap_components
のTabは、すっきりしていて良いのですが、標準では使わなくてよいcallback関数を使わないといけなくなるのが若干のマイナスポイントですかね。
コロプレス図はplotly.graph_objectsを利用する
Plotlyが最近導入したplotly.expressは、グラフを簡単に描くためのモジュールで、Dashでも使えます。ただし、コロプレス図においてcallback関数を使う場合には、ページがリフレッシュされないという問題がPlotly Community Forumにも報告されています。なので、Dashにてコロプレス図を書く場合にはplotly.graph_objects.Choroplethを利用します。
棒グラフ(Bar Chart)にカラーパレットを適用する
go.Barの属性にmarker
を設定します。
go.Bar( x=df_selected['Country'], y=df_selected[item], marker={ 'color': df['人口'], # データ系列をセット 'colorscale': 'viridis' # カラーパレットを設定 } )
テーブルのフォーマットを変更する
以下の通り、設定します。
dash_table.DataTable( # 省略 # 特定のカラムのセルを左寄せにする style_cell_conditional = [ { 'if': {'column_id': c}, 'textAlign': 'left' } for c in ['Country', 'id', 'region'] ], # 1行おきに背景色を変える style_data_conditional = [ { 'if': {'row_index': 'odd'}, 'backgroundColor': 'rgb(248, 248, 248)' }, ], # タイトル行の背景色を変える・太字にする style_header={ 'backgroundColor': 'rgb(230, 230, 230)', 'fontWeight': 'bold' } )
なお、特定行の小数点を2桁にしたいと思って色々と試したけど、うまくいきませんでした。ご存知の方がいたら教えていただけると助かります。
スクリプト全体はこちら↓をご参照ください。