Dashで更新可能な地図を表示する

はじめに

選択した項目に対して、インタラクティブに地図を更新するwebアプリを作成したいと思いました。 最初はstreamlitのpydeckで試していたのですが、地図を複数回レンダリングすると発生するバグが解消できなかったため、今回はDashで実装しました。

実施事項とデータについて

住民基本台帳の都道府県間の住所移動のデータを用いて、 移動後の都道府県を選択した場合に、各都道府県の移動前の人数を地図上に可視化します。

地図上にレンダリングするのに必要な都道府県のgeojsonファイルはこちらのサイトのものを使用させていただきました。

地図描写に使用する都道府県間の移動データはこのような形になります。 全国・都道府県・大都市が移動先の都道府県、valueが人数になります。

f:id:rmizutaa:20200815212925p:plain

実装

import plotly.express as px
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import pandas as pd
import json
import geopandas as gpd
import numpy as np


GEOJONFILE = "japan.geojson"
DATAFILE = "FEH.csv"

df = pd.read_csv(DATAFILE)
df = df[(df["性別"] == "総数") & (df["時間軸(年次)"] == "2019年") & (df["国籍"] == "移動者")]
df = df[df["value"] != "-"]
df["value"] = df["value"].astype(int)  # colorに使用するカラムは数値型に

jsonfile = gpd.read_file(GEOJONFILE)
dfjson = json.loads(jsonfile.to_json())

app = dash.Dash(__name__)
app.layout = html.Div([
    html.Div(
        html.H1('都道府県間の住所移動者(2019)',
                style={'textAlign': 'center'})
    ),
    dcc.Dropdown(
        id='selectplace',
        options=[{'label': i, 'value': i}
                 for i in df["全国・都道府県・大都市"].unique()],
        placeholder="移動先都道府県を選択",
        value="東京都"
    ),
    dcc.Loading(
        dcc.Graph(id='japanmap')
    )
])

@ app.callback(
    dash.dependencies.Output('japanmap', 'figure'),
    [dash.dependencies.Input('selectplace', 'value')])
def update_output(selectplace_value):
    selectdf = df[df["全国・都道府県・大都市"] == selectplace_value]
    fig = px.choropleth_mapbox(selectdf,
                               geojson=dfjson,
                               locations=selectdf['移動前の住所地'],
                               color=selectdf["value"],
                               featureidkey='properties.nam_ja',
                               color_continuous_scale="Viridis",
                               mapbox_style="carto-positron",
                               zoom=5,
                               center={"lat": 36, "lon": 138},
                               opacity=0.5,
                               labels={"value": "人数"}
                               )

    fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
    return fig

if __name__ == '__main__':
    app.run_server(debug=True)

https://github.com/rmizuta3/blog/tree/master/dash_chropleth

実装メモ

  • px.choropleth_mapboxについて
    • selectdfのlocationsとdfjsonのfeatureidkeyのカラムを紐づけて地図表示をしている。
    • colorに入る値は数値型にしておかないとレンダリングが終わらなくなる。
    • 地図のレンダリング速度は渡すjsonfileの大きさに依存する。今回の都道府県単位のデータだと2~3秒くらいだが、市区町村単位などより細かい地図を使用したい場合はjsonfileの方もデータを絞る必要が出てくる。

結果

このように、selectboxに入力した都道府県に対する各都道府県からの移動人数で色分けされた図ができました。 マウスオーバで各県からの移動人数の数値も確認できます。

f:id:rmizutaa:20200816131422g:plain