python folium で、都内の公園にまつわる情報を地図上に描画する


地図上に、描画可能なオープンデータを探してたところ、以下のデータを見つけました。

東京都の区市町村ごとの1人あたりの公園面積等、少しの加工で地図上に描画できそうなデータです。
取り込んで描画してみようと思います。

作成したスクリプト、入力ファイル、出力HTML 一式は以下にUPしてあります。
folium_example/per_capita_park_area_in_tokyo at master · kemsakurai/folium_example


前提

以下環境で作業を実施しています。

  • OS

    % sw_vers 
    ProductName:    Mac OS X
    ProductVersion: 10.12.6
    BuildVersion:   16G29
    

  • pythonのverion

    % python -V
    Python 2.7.10   
    

  • 使用したfolium のversion

    % pip list | grep folium
    folium (0.5.0)
    
    何があったのかはわかりませんが、前回似たようなことを実施してから、1,2週間たらずで、version up していました。。


folium インストール方法

pip でインストールします。
pandas も必要なので、pandas も。

pip install pandas
pip install folium        


地図表示についての前提

23区のみの表示に絞ります。理由は以下になります。
* 地域コード付きのGeoJsonデータがすぐに利用可能なもので見つからなかった。
作るのは、、ちょっと面倒かなと思ってしまいました。すみません。


実施作業の流れ

以下の通り作業は実施していきました。
時系列順に記載します。

  1. GeoJSON ファイルの準備

  2. データセットの加工

  3. 地図を描画(コロプレス図)

4 地図を描画(ポップアップ付きのコロプレス図)


GeoJSON ファイルの準備

前回実施時は、日本の都道府県のデータが必要でしたが、今回は東京都の情報が必要になります。
おそらく誰かが作成してくれているだろうと、思っていたらやはり作成してくれている方がいましたので、拝借して使用させて頂きます。
JapanCityGeoJson/geojson/13 at master · niiyz/JapanCityGeoJson

以下、上記から取得したtokyo23.json を読み込んで、東京23区を描画するスクリプトになります。

plot_map.py

# -*- coding: utf-8 -
import folium


def main():

    # 東京都港区芝公園を設定
    tokyo23_location = [35.658593, 139.745441]
    m = folium.Map(location=tokyo23_location,
                   tiles='https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}.png',
                   attr='OpenStreetMap',
                   zoom_start=11)
    geojson = r'tokyo23.json'
    # geojson読み込み
    m.choropleth(geo_data=geojson)
    # 地図をhtml形式で出力
    m.save(outfile="map.html")

if __name__ == "__main__":
    main()

スクリプトの補足説明

  • 地図の中心点について
    東京都23区の中心部なので、港区あたりかなということで、港区芝公園を設定しました。
    経度、緯度などを計算しての結果ではないですが、表示させたところいい感じにはなったので、こちらを採用しています。

    tokyo23_location = [35.658593, 139.745441]
    

  • zoom_start 初期表示時の地図の拡大倍率になります。
    これも、値を切り替えて地図出力、表示確認を行って、ちょうど良い大きさsになったのが、11 でそちらを採用しました。

    zoom_start=11
    

  • 使用しているtilesについて
    folium に バンドルされているもの以外でだと、以下のtile が使用できるようです。
    Leaflet Provider Demo
    今回使用しているtilesも上記から探して設定しました。

map.html

以下、出力される map.html の描画結果です。
tokyo23


データセットの加工

東京都都市公園等区市町村別面積・人口割比率表 - データセット - 東京オープンデータカタログサイト からcsvをダウンロードします。
地図上にデータを描画するために、geojson上に存在する行政区分コードが必要になります。
csvには、行政区分コードがないため、先頭列に行政区分コードを追加します。

地域名と、地域コードのマッピング表は、やはりJapanCityGeoJson/README.md at master · niiyz/JapanCityGeoJson から取得しました。
Google スプレッドシートで、VLOOKUPして、行政区分コードを追加します。

上記作業を実施後のデータをスクリプトの入力ファイルとしています。
folium_example/koen.csv at master · kemsakurai/folium_example

CSV出力の段階で不要データを排除すべきかとは思いますが、pandas でも加工はできるのでスクリプト上でデータを加工することにしました。


地図を描画(コロプレス図)

データ上、都市公園の指標と、都市公園以外の指標に分かれていて、その合計もあります。
一人当たり面積(ホ/B)(平米) を用いてコロプレス図を描画します。

作成したスクリプト

長いので、Github上のスクリプトを参照ください。
folium_example/plot_choropleth_map.py at master · kemsakurai/folium_example

スクリプトの補足説明

  • Pandasでのデータ付与について
    csv のヘッダーカラムが日本語で、取得の際にエラーとなるため、以下でヘッダ名の変更を行っています。
    取得方法があるのかもしれません。

        # カラムを再設定
        df.columns = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
                      "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ"]
    

  • geojonとのマッピングのための加工 geojsonには、id が String型で定義されています。
    A列に行政区分コードが含まれますが、値にNaNが存在するため、float64 になり、このままではマッピングができませんでした。
    まず、NaNを0に置き換え、その後 int型に変換し、23区の行政区分コードを含む行のみを抽出。
    抽出結果のA列を、String型に変換しています。

        # 列Aをint型に変換
        df['A'] = df['A'].fillna(0).astype(int)
        # 23区の地域コードに合致する列のみを抽出
        df = df[df['A'].isin([13101, 13102, 13103, 13104, 13105, 13106, 13107, 13108, 13109, 13110,
                              13111, 13112, 13113, 13114, 13115, 13116, 13117, 13118, 13119, 13120, 13121, 13122, 13123])]
    
        # 列、A を文字列に変換 (これをやらないと、数値側と文字列の突き合わせになり、マッピングができない。)
        df['A'] = df['A'].astype('str')
    

  • fill_colorの設定について
    default は blue です。
    公園なので緑かなということで、'YlGn' を指定するようにしました。
    どんな色が設定できるかですが、folium — Folium 0.5.0+15.gecd5052 documentation に以下のように記載されています。
    こちらは、別途まとめようかと思います。

    • fill_color (string, default ‘blue’) – Area fill color. Can pass a hex code, color name, or if you are binding data, one of the following color brewer palettes: ‘BuGn’, ‘BuPu’, ‘GnBu’, ‘OrRd’, ‘PuBu’, ‘PuBuGn’, ‘PuRd’, ‘RdPu’, ‘YlGn’, ‘YlGnBu’, ‘YlOrBr’, and ‘YlOrRd’.

choropleth_map.html

以下のようなコロプレス図が描画できました。
千代田区が、1人あたりの公園面積が一番広いようです。住んでいる人が少ない、且つ、大きな公園が多いので、納得はしました。
江戸川区が比較的公園面積が広くて、人もたくさん住んでそうですし、そこはちょっとうらやしいかもしれません。
tokyo23_choropleth


地図を描画(ポップアップ付きのコロプレス図)

一人当たり面積(ホ/B)(平米) と、総合計((ホ)八+二)数 を使用してポップアップ付きのコロプレス図を描画します。
マーカをクリックすると、ポップアップが表示されるようにします。

作成したスクリプト

長いので、Github上のスクリプトを参照ください。
folium_example/plot_choropleth_map_with_popup.py at master · kemsakurai/folium_example

スクリプトの補足説明

  • ピンを設定している経度、緯度について
    ピンを立てる位置は、区の中心がよいかと思い、区の中心の経度、緯度の情報を探したのですが、見つけることができず、geojsonの値から経度、緯度の平均値を導出しました。
    以下のメソッド内で計算しています。

        # 区の中央部の経度緯度をgeojsonから計算
        city_center = __calulate_city_center(data)
    

  • popup内に表示するtextについて
    こちらは、html形式で設定を行う必要があります。
    各項目ごとに改行させたかったのですが、\n記述では設定できず、以下のように<br/>で記載しました。

        city_name = df.loc[(df['A'] == k), 'B'].values[0]
        poput_text = u"区の名前:" + city_name.decode('utf-8') + "<br/>"
        square_meter = df.loc[(df['A'] == k), 'AH'].values[0]
        poput_text = poput_text + u"区の人口一人当たりの公園面積:" + \
            str(square_meter) + " " + "m2" + "<br/>"
        park_count = df.loc[(df['A'] == k), 'AF'].values[0]
        poput_text = poput_text + u"区の総公園数:" + str(park_count)
    

choropleth_map_with_popup.html

以下のような地図が描画できました。
公園数を赤系の色で地図に反映、一人あたりの公園面積をピンの大きさに反映させました。
奥さんにできあがったものを見てもらいましたが、奥さんには不評でした。
tokyo23_choropleth_popup


まとめ

python folium を使い、都道府県の夫婦年齢差をプロットする | Monotalk に続いて、folium で 地図を描きました。
データ取得後、地図に描画するまで、結構なデータ加工が必要です。
それも含めて楽しいといえば楽しいですが、このあたりもうちょっと効率良くできるようになりたいです。
まだ、folium 、leaflet.js の使い方がわかってないところが多く、もっといい感じ描画できないかなと思うようになりました。
もうちょっとドキュメントを読んだりしながら、継続して使い方を調べていこうかと思います。
以上です。

コメント


カテゴリー