ソニックPythonで本格的な地図ダッシュボードを作る
「店舗や顧客の住所を、もっと本格的な地図で可視化したい」「マーカーをクリックすると詳細が出るような、インタラクティブな地図を作りたい」「地図に色分けやヒートマップを重ねたい」
そんなニーズに応えるのが、Pythonの「folium」ライブラリです。
以前の記事ではplotlyで地図を作る方法を紹介しましたが、foliumは「地図そのものに特化」したライブラリ。OpenStreetMapをベースに、より本格的で表現力豊かな地図ダッシュボードが作れます。
foliumは、地図可視化の決定版。マーカー・ポップアップ・ヒートマップ・エリア色分けまで、すべてHTMLで出力できます。
この記事では、foliumで地図ダッシュボードを作る方法を、コピペで動くコード付きで完全解説します。
こんな方におすすめ
- 店舗・顧客・物件などの位置データを本格的に可視化したい方
- クリックで詳細が出るインタラクティブな地図を作りたい方
- plotlyの次に、地図特化ツールを学びたい方
第1章|foliumとは?plotlyとの違い
foliumの特徴
foliumは、JavaScriptの地図ライブラリ「Leaflet.js」をPythonから使えるようにしたものです。地図可視化に特化しています。
- **地図特化**:マーカー・ポップアップ・ヒートマップなど地図機能が豊富
- **HTML出力**:誰でもブラウザで開ける
- **無料**:OpenStreetMapベースでAPIキー不要
- **インタラクティブ**:ズーム・パン・クリックが自由自在
foliumとplotlyの使い分け
| 観点 | folium | folium |
|---|---|---|
| 得意分野 | 地図に特化 | グラフ全般 |
| マーカー表現 | 非常に豊富 | 標準的 |
| エリア色分け | 得意(GeoJSON) | 可能 |
| グラフ併用 | 地図のみ | グラフと統合可 |
「地図を主役にしたい」ならfolium、「グラフの中の1つとして地図も使いたい」ならplotly。場面で使い分けます。
第2章|環境準備(uv環境前提)
この記事は、uv環境でPythonを使う前提で進めます。まだuvをインストールしていない方は、別記事「【完全版】uv入門」をご覧ください。
必要なライブラリ
uv add folium pandas各ライブラリの役割
| ライブラリ | 役割 |
|---|---|
| folium | 地図の作成・マーカー配置・HTML出力 |
| pandas | 位置データ(緯度経度)の読み込み・加工 |
第3章|基本|初めての地図を作る
最小の地図
import folium
# 地図の中心と初期ズームを指定して地図を作成
# location は [緯度, 経度]
m = folium.Map(
location=[35.6812, 139.7671], # 東京駅
zoom_start=12 # ズームレベル(大きいほど詳細)
)
# HTMLとして保存
m.save("地図_テスト.html")
print("地図を保存しました")マーカーを置く
import folium
m = folium.Map(location=[35.6812, 139.7671], zoom_start=12)
# マーカーを追加
folium.Marker(
location=[35.6812, 139.7671],
popup="東京駅", # クリックで表示される
tooltip="ここをクリック", # ホバーで表示される
icon=folium.Icon(color="blue", icon="info-sign")
).add_to(m)
m.save("マーカー地図.html")マーカーの色とアイコン
# colorで色を変えられる
# red, blue, green, purple, orange, darkred など
folium.Marker(
location=[35.68, 139.76],
icon=folium.Icon(color="red", icon="home")
).add_to(m)

第4章|複数地点をデータから一括プロット
CSVから複数マーカーを配置
import folium
import pandas as pd
df = pd.DataFrame({
"店舗名": ["東京店", "大阪店", "名古屋店", "札幌店", "福岡店"],
"lat": [35.6812, 34.6937, 35.1815, 43.0642, 33.5904],
"lon": [139.7671, 135.5023, 136.9066, 141.3469, 130.4017],
"売上": [1500, 1200, 900, 700, 1100]
})
m = folium.Map(location=[36.0, 138.0], zoom_start=5)
for _, row in df.iterrows():
folium.Marker(
location=[row["lat"], row["lon"]],
popup=f"{row['店舗名']}<br>売上:{row['売上']}万円",
tooltip=row["店舗名"],
icon=folium.Icon(color="blue")
).add_to(m)
m.save("全店舗地図.html")
print("全店舗地図を作成しました")売上に応じてマーカーの大きさを変える(CircleMarker)
import folium
import pandas as pd
df = pd.DataFrame({
"店舗名": ["東京店", "大阪店", "名古屋店"],
"lat": [35.6812, 34.6937, 35.1815],
"lon": [139.7671, 135.5023, 136.9066],
"売上": [1500, 1200, 900]
})
m = folium.Map(location=[36.0, 138.0], zoom_start=5)
for _, row in df.iterrows():
folium.CircleMarker(
location=[row["lat"], row["lon"]],
radius=row["売上"] / 100, # 売上に応じて半径を変える
popup=f"{row['店舗名']}:{row['売上']}万円",
color="#0066ff",
fill=True,
fill_color="#0066ff",
fill_opacity=0.6
).add_to(m)
m.save("売上バブル地図.html")

第5章|ヒートマップで密度を可視化
HeatMapプラグイン
「顧客が密集しているエリア」「イベントの集中地点」などを、ヒートマップで可視化できます。
import folium
from folium.plugins import HeatMap
import pandas as pd
import numpy as np
# サンプル:東京周辺の300人の顧客
np.random.seed(42)
n = 300
df = pd.DataFrame({
"lat": np.random.normal(35.68, 0.05, n),
"lon": np.random.normal(139.77, 0.06, n)
})
m = folium.Map(location=[35.68, 139.77], zoom_start=12)
# ヒートマップ用のデータ([緯度, 経度]のリスト)
heat_data = df[["lat", "lon"]].values.tolist()
# ヒートマップを追加
HeatMap(heat_data, radius=15).add_to(m)
m.save("顧客ヒートマップ.html")
print("ヒートマップを作成しました")重み付きヒートマップ
# 各地点に「重み」を付ける(売上が大きいほど濃く)
heat_data = df[["lat", "lon", "売上"]].values.tolist()
HeatMap(heat_data, radius=20).add_to(m)
# [緯度, 経度, 重み] の3要素で重み付け第6章|マーカークラスターとレイヤー
マーカークラスター(大量のマーカーをまとめる)
マーカーが数百個になると地図が見づらくなります。クラスター機能で、近いマーカーを自動でグループ化できます。
import folium
from folium.plugins import MarkerCluster
import pandas as pd
df = pd.read_csv("顧客リスト.csv") # lat, lon列があるCSV
m = folium.Map(location=[35.68, 139.77], zoom_start=10)
# クラスターを作成
marker_cluster = MarkerCluster().add_to(m)
# クラスターにマーカーを追加
for _, row in df.iterrows():
folium.Marker(
location=[row["lat"], row["lon"]],
popup=row.get("名前", "")
).add_to(marker_cluster)
m.save("クラスター地図.html")ズームアウトすると「ここに50件」のようにまとまり、ズームインすると個別マーカーに展開されます。
レイヤーコントロール(表示の切り替え)
import folium
m = folium.Map(location=[35.68, 139.77], zoom_start=11)
# レイヤー1:店舗
store_layer = folium.FeatureGroup(name="店舗")
folium.Marker([35.68, 139.76], popup="東京店").add_to(store_layer)
store_layer.add_to(m)
# レイヤー2:顧客
customer_layer = folium.FeatureGroup(name="顧客")
folium.CircleMarker([35.69, 139.70], radius=5).add_to(customer_layer)
customer_layer.add_to(m)
# レイヤー切り替えコントロールを追加
folium.LayerControl().add_to(m)
m.save("レイヤー地図.html")レイヤーコントロールを使えば、「店舗だけ」「顧客だけ」と表示を切り替えられる、本格的なダッシュボードになります。
第7章|実務スクリプト|店舗網ダッシュボード
シナリオ
店舗データから、売上に応じたバブルマーカー+顧客ヒートマップを重ねた、本格的な店舗網ダッシュボードを作る。
完成スクリプト
"""
店舗網ダッシュボード
- 店舗を売上バブルで表示
- 顧客分布をヒートマップで表示
- レイヤーで切り替え可能
"""
import folium
from folium.plugins import HeatMap
import pandas as pd
# === データ読み込み ===
stores = pd.read_csv("店舗データ.csv") # 店舗名, lat, lon, 売上
customers = pd.read_csv("顧客データ.csv") # lat, lon
# === ベース地図 ===
m = folium.Map(
location=[stores["lat"].mean(), stores["lon"].mean()],
zoom_start=11,
tiles="OpenStreetMap"
)
# === レイヤー1:店舗(売上バブル) ===
store_layer = folium.FeatureGroup(name="店舗(売上)")
for _, row in stores.iterrows():
folium.CircleMarker(
location=[row["lat"], row["lon"]],
radius=row["売上"] / 100,
popup=f"{row['店舗名']}<br>売上:{row['売上']}万円",
tooltip=row["店舗名"],
color="#003d99",
fill=True,
fill_color="#0066ff",
fill_opacity=0.7
).add_to(store_layer)
store_layer.add_to(m)
# === レイヤー2:顧客ヒートマップ ===
customer_layer = folium.FeatureGroup(name="顧客分布")
heat_data = customers[["lat", "lon"]].values.tolist()
HeatMap(heat_data, radius=15).add_to(customer_layer)
customer_layer.add_to(m)
# === レイヤーコントロール ===
folium.LayerControl().add_to(m)
# === 保存 ===
m.save("店舗網ダッシュボード.html")
print("店舗網ダッシュボードを作成しました")
print(f"店舗数:{len(stores)}、顧客数:{len(customers)}")このダッシュボードでできること
- 店舗を売上に応じたバブルで表示
- 顧客分布をヒートマップで重ねて表示
- レイヤーで「店舗だけ」「顧客だけ」を切り替え
- マーカークリックで店舗詳細を表示
- HTMLとして保存し、誰でもブラウザで閲覧可能
「店舗の空白エリア」と「顧客の密集エリア」を重ねれば、新規出店の最適地が一目で分かります。
第8章|つまずき対処&まとめ
よくあるトラブル
トラブル1:地図が表示されない・真っ白
対処:
生成されたHTMLファイルをブラウザで開いているか確認。Jupyter内で表示されない場合は、m.save()でHTML保存して開くのが確実です。インターネット接続も必要(地図タイルをオンライン取得するため)。
トラブル2:マーカーが表示されない
対処:
緯度・経度が正しいか確認。日本国内なら緯度は約24〜46、経度は約123〜146の範囲。lat と lon を逆に指定していないかもチェック。
トラブル3:住所しかなく緯度経度がない
対処:
geopyライブラリでジオコーディング(住所→緯度経度変換)します。plotly地図の記事でも解説した方法が使えます。
# uv add geopy
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="my_app")
location = geolocator.geocode("東京都千代田区丸の内1-9-1")
print(location.latitude, location.longitude)トラブル4:ポップアップで日本語が文字化け
対処:
foliumは内部的にUTF-8を使うため通常は問題ありません。HTMLを開くブラウザの文字コード設定がUTF-8になっているか確認します。
この記事のまとめ
- foliumは地図可視化に特化したPythonライブラリ
- マーカー・ポップアップ・CircleMarkerで柔軟な表現
- HeatMapで密度、MarkerClusterで大量データを整理
- レイヤーコントロールで本格的なダッシュボードに
- すべてHTML出力で、誰でもブラウザで閲覧可能
FAQ
次にやるべき3つの行動
- **今すぐ**:自社・自校で「地図にできそうな住所データ」を探す
- **今日中**:第3章のコードで、地図に1つマーカーを置いてみる
- **今週中**:自分のデータで、複数マーカー+ヒートマップの地図を作る
住所データを「眠らせる」から「地図で活かす」へ。foliumなら、本格的な地図ダッシュボードが数十行で作れます。
foliumで、位置データが武器になる
店舗網の分析、顧客分布の把握、配送エリアの最適化――位置データの可視化は、ビジネスの意思決定を大きく変えます。
plotlyとfolium、2つの地図可視化ツールを使い分ければ、あらゆる地理データを表現できます。当ブログのダッシュボードカテゴリで、ぜひ他の手法も学んでください。
最新の解説記事は、新着記事から順次公開しています。X(旧Twitter)でも更新情報を発信していますので、ぜひフォローしてください。
この記事を書いた人
ソニック|バックオフィス出身の業務効率化ブロガー。学校事務員時代に生徒の住所データを地図化した経験を活かし、現在のデータサイエンス業務では顧客分析・店舗分析の地図ダッシュボードをfoliumとplotlyで制作中。リアルな実体験をもとにしたノウハウを発信中。


コメント