🗺️

#1 Pythonで簡単にマップ制作 ~Folium~

2024/12/13に公開

Foliumってなに?

FoliumとはPythonで地図が作れるよ!っていうものです。
もう少し詳しく説明をすると、生成されるマップはHTMLのコードで書かれたマップです。また、HTMLのコードでは「leaflet」というフレームワークが使われてます。

イメージとしてはPythonでコードを書くとFoliumがそれを勝手にHTMLに書き換えてマップにしてくれるっていうイメージです

Foliumの公式ドキュメントはこちらから(英語です...)
https://python-visualization.github.io/folium/latest/

Foliumで生成されるマップの構造

生成されるマップはOpen street Map(OSM)が使用されます。大きな特徴として自分でマップに情報を追加していってその追加情報が他の人のマップにも反映されるという仕組みになっています。
Googleマップとは違い色々なことが無料でできるのが大きな特徴です。しかし、Googleマップと比べてマップ情報が少ないのが難点です。

生成されるマップは複数のレイヤーが重なってできています。
以下のようなイメージになります。
一番下にマップ、その上に情報を順番に乗っけていきます。

実際に使ってみる

仕様

  • 不審者が出没した場所と位置情報を用意
  • 位置情報から緯度経度をAPIを使って算出(詳しくはコチラの過去記事を参照)
  • 位置情報と不審者情報を関連付けてマップに表示させる

完成イメージ

マップのピンをクリックすると詳細がポップアップでメッセージを表示する

準備

今回使用するfoliumは別途インストールが必要になるので、ダウンロードしてない場合は以下のpipコマンドでダウンロードしてください。

pip install folium

ソースコード

import folium
import requests

# 住所や名称から緯度経度を取得する
def geo_coding(address):
    url = f"https://msearch.gsi.go.jp/address-search/AddressSearch?q={address}"

    res = requests.get(
        url=url
    )
    data = res.json()

    return data[0]['geometry']['coordinates']


# 掲載する情報一覧
data_list = [
    {
        "発生場所": "各務原市那加西那加町",
        "詳細": "帰宅中の女子学生に対し、男が車で後をつける事案が発生しました。"
    },
    {
        "発生場所": "恵那市長島町正家",
        "詳細": "帰宅中の児童らに対し、男が手を振ったり、女がスマートフォンを向ける事案が発生しました。"
    },
    {
        "発生場所": "岐阜市中1丁目",
        "詳細": "下校中の児童らに対し、男が携帯電話機を向ける事案が発生しました。"
    },
    {
        "発生場所": "岐阜市中西郷",
        "詳細": "下校中の児童らに対し、男が携帯電話機のカメラを向ける事案が発生しました。"
    },
]

map_object = folium.Map(
    location=[35.4096218, 136.754722],
    zoom_start=12
)

for data in data_list:
    location = geo_coding(data["発生場所"])

    folium.Marker(
        location=[location[1], location[0]],
        tooltip=data["詳細"][0:5] + "・・・",
        popup=folium.Popup(data["詳細"], parse_html=True, max_width=100),
        icon=folium.Icon(color="green")
    ).add_to(map_object)

# 生成したマップを保存する
map_object.save("sample.html")

ソースコード解説

  1. 必要なライブラリをインポート
import folium
import requests
  1. 住所から緯度経度を算出する関数を作る
    関数の引数に住所や名称を渡すとAPIで該当する緯度経度を1つ以上返してくれるので、一番最初にある緯度経度情報をリスト型のデータで返します。
def geo_coding(address):
    url = f"https://msearch.gsi.go.jp/address-search/AddressSearch?q={address}"

    res = requests.get(
        url=url
    )
    data = res.json()

    return data[0]['geometry']['coordinates']
  1. マップに掲載する位置情報をリスト型のデータで準備する
data_list = [
    {
        "発生場所": "各務原市那加西那加町",
        "詳細": "帰宅中の女子学生に対し、男が車で後をつける事案が発生しました。"
    },
    {
        "発生場所": "恵那市長島町正家",
        "詳細": "帰宅中の児童らに対し、男が手を振ったり、女がスマートフォンを向ける事案が発生しました。"
    },
    {
        "発生場所": "岐阜市中1丁目",
        "詳細": "下校中の児童らに対し、男が携帯電話機を向ける事案が発生しました。"
    },
    {
        "発生場所": "岐阜市中西郷",
        "詳細": "下校中の児童らに対し、男が携帯電話機のカメラを向ける事案が発生しました。"
    },
]
  1. マップオブジェクトを作る
    folium.Mapでまっさらなマップを作るイメージ
    locationでマップを表示させるときの中心座標を指定し、zoom_startでマップの最初のズーム度合を指定する。
map_object = folium.Map(
    location=[35.4096218, 136.754722],
    zoom_start=12
)

他にもズームボタン(画像左上)の設置や縮尺(画像左下)の設置の有無の指定できる。詳しくは公式ドキュメント参照

  1. データリストのデータを順番に取り出してマップにピンをさす
for data in data_list:
    location = geo_coding(data["発生場所"])

    folium.Marker(
        location=[location[1], location[0]],
        tooltip=data["詳細"][0:5] + "・・・",
        popup=folium.Popup(data["詳細"], parse_html=True, max_width=100),
        icon=folium.Icon(color="green")
    ).add_to(map_object)
  1. 生成したマップをHTML形式で保存する
    save()の引数に保存するファイル名を指定するだけです
map_object.save("sample.html")

Discussion