よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【foliumのPlugins】FeatureGroupとLayerControlで層を重ねた地図を作成する

今回は、地図作成ライブラリfoliumの大量にあるPluginsの1つ「FeatureGroup」と、層を分けて表示できるようにする「LayerControl」の使い方。

FeatureGroupfeatureは特徴という意味で、地図を特徴ごとに層で別けて地図に追加します。

LayerControlは、ラジオボタン・チェックボタンで層の表示を選択でできるようにする優れものです。

特徴が分かりやすいように、電車の路線図ごとに層を分けて作ってみます。



【実行環境】

  • Android
  • Termux
  • Python 3.9.6
  • Jupyter Notebook 6.4.0
  • Pandas1.2.5、folium0.12.1



座標の準備

適当に座標を用意します。FeatureGroupで地図の層を分けますので、グループ分けしやすい感じのが面白いかと思います。縄文遺跡と弥生遺跡の座標とか。

今回はJR長崎本線と、JR大村線島原鉄道の各駅の座標ごとを3層に分けて地図を作ります。
座標のデータはgeocoding.jpで集めていた自家製ファイルを使います。

そのファイルを読み込みます。座標のデータを整えてるだけなのでこの部分は無視でいいです。

import pandas as pd

# 座標を溜め込んだ自作のファイル
fname = 'latlng_list.csv'

# CSVを読み込み
df = pd.read_csv(fname, header=None)
# 条件抽出
df = df[df[0].str.contains("長崎本線|大村線|島原鉄道")]
# カラム名の変更
df = df.rename(columns={0:"駅名", 1:"緯度", 2:"経度"})
# 表示
df
駅名 緯度 経度
141 JR長崎本線新鳥栖駅 33.370455 130.491052
142 JR長崎本線肥前麓駅 33.365995 130.478120
143 JR長崎本線吉野ヶ里公園駅 33.324845 130.399378
144 JR長崎本線神埼駅 33.315766 130.374474
145 JR長崎本線伊賀屋駅 33.290268 130.336784
... ... ... ...
226 島原鉄道三会駅 32.814989 130.357183
227 島原鉄道島原駅 32.790225 130.370594
228 島原鉄道霊丘公園体育館駅 32.782476 130.374161
229 島原鉄道島原船津駅 32.775957 130.375543
230 島原鉄道島原港 32.768873 130.370548

77 rows × 3 columns



地図の中心座標を算出する

上のデータフレームから列で平均値を算出し、中心座標とします。

# 中心座標を平均値で求める
center = df.mean(axis=0).tolist()
center
[33.01485233766233, 130.22280514285708]



各層に設置するマーカーの座標を準備する

路線ごとに色分けしたマーカーを駅の座標に差します。条件抽出で路線ごとの座標を抽出します。

# 長崎本線の駅の座標を抽出
Nagasaki_data = df[df["駅名"].str.contains("長崎本線")]
# 2行のみ表示
Nagasaki_data.head(2)
駅名 緯度 経度
141 JR長崎本線新鳥栖駅 33.370455 130.491052
142 JR長崎本線肥前麓駅 33.365995 130.478120
# JR大村線の座標データを抽出
Oomura_data = df[df['駅名'].str.contains("大村線")]

# 島原鉄道の座標データを抽出
Shimabara_data = df[df['駅名'].str.contains("島原鉄道")]



座標の準備ができました。

地図を描く

  1. ベースとなる地図を作成
  2. 各層を作成
  3. 各層にマーカーを追加
  4. ベース地図に各層を追加

の手順で作成します。



ベースの地図作成

import folium
from folium import FeatureGroup, LayerControl

# ベースとなる地図を作成
m = folium.Map(
    location = center, # 中心座標
    zoom_start=9
)

各層を作成

# 長崎本線の層を作成
Nagasaki_group = FeatureGroup(name="JR長崎本線")

# 長崎本線グループにマーカーを差す
ng_popups = Nagasaki_data["駅名"].values.tolist() # popup用の駅名配列
ng_latlngs = Nagasaki_data.iloc[:,1:3].values.tolist() # 座標の2次元配列

# 赤のマーカーを各駅の座標に差し、グループに追加
for name, latlng in zip(ng_popups, ng_latlngs): 
    folium.Marker(
        location=latlng, 
        popup=name,
        icon = folium.Icon(color="red")
    ).add_to(Nagasaki_group)


# 大村線も以下同様
Oomura_group = FeatureGroup(name="JR大村線")

Oo_popups = Oomura_data["駅名"].values.tolist()
Oo_latlngs = Oomura_data.iloc[:,1:3].values.tolist()

for name, latlng in zip(Oo_popups, Oo_latlngs):
    folium.Marker(
        location=latlng,
        popup=name,
        icon = folium.Icon(color="green")
    ).add_to(Oomura_group)
# 島原鉄道も同様
Shimabara_group = FeatureGroup(name="島原鉄道")

sb_popups = Shimabara_data["駅名"].values
sb_latlngs = Shimabara_data.iloc[:,1:3].values.tolist()

for name, latlng in zip(sb_popups, sb_latlngs):
    folium.Marker(
        location=latlng,
        popup=name,
        icon=folium.Icon(color="purple")
    ).add_to(Shimabara_group)
    

ベースの地図に層を追加

# 1層だけ地図に追加
Nagasaki_group.add_to(m)
# 表示
m
<folium.map.FeatureGroup at 0x7fd4fa598b20>

20210801090611



他の層も地図に追加させてみる。

# 残り2層も地図に追加
Oomura_group.add_to(m)
Shimabara_group.add_to(m)

# 表示
m
<folium.map.FeatureGroup at 0x7fd4fa5984c0>

20210801090639

これは3層が重なった状態。

路線図であることとマーカーを色分けしているので違いが分かりますが、そうでない場合は混ざって表示されますので見にくいかと思います。

そこで登場するのが次です。

LayerControlで層を分離

地図に層を追加させたたけだと上のように全部一緒くたに表示してしまいますので、LayerControlを使うことによって層を任意に分離できるようにします。

# 層をラジオボタンで表示選択可能に
LayerControl().add_to(m)

# 表示
m

f:id:chayarokurokuro:20210801090735j:plain


f:id:chayarokurokuro:20210801090801j:plain


f:id:chayarokurokuro:20210801090830j:plain


f:id:chayarokurokuro:20210801090851j:plain


f:id:chayarokurokuro:20210801090913j:plain



層ごとにチェックボタンで表示の切り替えができる。
ナイスです (*´・ω・`)b!



参考リンク

  • folium公式

plugins — Folium 0.12.1 documentation


Jupyter Notebook Viewer



おわりに

地図をブログにすべて貼り付けたら投稿文字数が40万字近くなり、下書き時点でプレビューの表示がバグったので、地図の代わりに画像を貼り付けました。座標が多すぎた。

層ごとにグループ分けができるので、いろんな使い途がありそうですね。

以上です。