はじめに
前回の記事で、13年分のGoogle Mapsタイムラインから銭湯・サウナの訪問履歴を抽出し、ランキングを作りました。76施設・354回という結果が出て満足していたのですが、ランキング表だけだと「どこに行ったか」の空間的な広がりが見えません。
地図にプロットしたら、行動圏の変化や旅先での銭湯訪問が可視化できて面白いのでは?と思い、Leafletを使った静的Webアプリを作ってみました。

完成した銭湯マップ。訪問回数に応じてマーカーの大きさが変わる(デモサイト)
使った技術
| 技術 | 用途 | 選定理由 |
|---|---|---|
| Leaflet | 地図表示 | 無料、軽量、APIキー不要 |
| Leaflet.heat | ヒートマップ | Leafletのプラグインとして簡単に導入できる |
| CARTO Voyager | 地図タイル | 明るく温かみのあるデザイン。無料 |
| GitHub Pages | ホスティング | 静的サイトなのでこれで十分。docs/配置で設定するだけ |
| Python | データ前処理 | 前回のCSVをWebアプリ用のJSファイルに変換 |
地図ライブラリはGoogle Maps JavaScript APIも候補でしたが、APIキーが必要で読者が試しにくいためLeafletにしました。ビルドツールも使わず、HTML + JS + CSSのシンプルな構成です。
デザインはどこかで見たことがあるようなサウナ検索サイト風にしてみました。白背景にブルーのアクセントカラーで、施設のカード型UIやpill型の年フィルターなど、銭湯好きには馴染みのある雰囲気を目指しています。
データの準備
前回の出力を結合する
前回の記事で生成した2つのCSVを使います。
-
sento-visits.csv— 全訪問記録(日付、施設名、緯度経度) -
sento-ranking-with-urls.csv— 施設ランキング(施設名、訪問回数、公式サイトURL)
訪問CSVには緯度経度があり、ランキングCSVには公式サイトURLがあるので、施設名をキーにして結合します。出力は file:// で直接開いてもCORSエラーにならないよう、const SENTO_DATA = [...] というJSファイルとして生成しています。
# 施設ごとに訪問日・座標を集約し、ランキング情報と結合してJSファイルを生成
result.append({
"name_ja": "○○温泉",
"lat": 35.xxxxx,
"lng": 139.xxxxx,
"total_visits": 43,
"first_visit": "2018-07-21",
"last_visit": "2023-02-04",
"visits_by_year": {"2018": 8, "2019": 12, ...},
"url": "https://example.com/",
})
名前の表記揺れへの対処
ここで1つハマりポイントがありました。ランキングCSVと訪問CSVで施設名の表記が微妙にずれているケースがあったのです。
Google Places APIが返す施設名は時期やタイミングによって変わることがあるようで、同じ施設でも引用符の有無や旧名の括弧書きが付くなど、2つのCSV間で名前が一致しないことがありました。
完全一致だと76施設中2施設が欠落したので、引用符を除去した上で前方一致マッチに変更して解決しました。
visit_clean = visit_name.replace('"', '').replace("'", "")
for rname in ranking:
rname_clean = rname.replace('"', '').replace("'", "")
if (visit_clean.startswith(rname_clean)
or rname_clean.startswith(visit_clean)):
name = rname
break
placeId で結合するのが本来は確実ですが、今回はCSV同士の結合だったのでこの方法で対処しました。
地図アプリの実装
マーカー表示
各施設を L.circleMarker で表示します。訪問回数に応じて半径を6〜30pxの範囲で変化させています。
const radius = 6 + (f.total_visits / maxVisits) * 24;
const marker = L.circleMarker([f.lat, f.lng], {
radius: radius,
fillColor: '#2233a1',
fillOpacity: 0.65,
color: '#fff',
weight: 2,
});
77回訪問した施設と1回だけの施設の差がマーカーの大きさで直感的にわかります。
ポップアップ
マーカーをクリックすると、施設名・訪問回数・期間・年別の内訳バーチャート・公式サイトリンクが表示されます。
ヒートマップ
Leaflet.heatプラグインで訪問頻度のヒートマップを表示します。ライトテーマの地図に合わせて、水色から濃紺へのグラデーションを設定しました。
heatLayer = L.heatLayer(points, {
radius: 35,
blur: 25,
minOpacity: 0.35,
gradient: {
0.1: '#bfdbfe',
0.3: '#93c5fd',
0.5: '#3b82f6',
0.7: '#2233a1',
0.85: '#1e3a8a',
1.0: '#172554',
},
});

東京エリアのヒートマップ。豊島区〜北区・台東区あたりが「銭湯ホットスポット」
年別フィルター
年ボタンで絞り込むと、統計・ランキング・地図がすべて連動して更新されます。「2021年はどこに行っていたか」が一目でわかります。
フィルター処理は元データを変換するだけのシンプルな実装です。
function getFilteredData() {
if (!selectedYear) return allData;
return allData
.filter(f => f.visits_by_year[selectedYear])
.map(f => ({
...f,
total_visits: f.visits_by_year[selectedYear],
visit_dates: f.visit_dates.filter(d => d.startsWith(selectedYear)),
}))
.sort((a, b) => b.total_visits - a.total_visits);
}
ランキングサイドバー
左サイドバーに訪問回数順のリストを表示し、クリックすると地図がその施設にフライしてポップアップが開きます。
データから見えた発見
地図にしてみると、CSVの表やランキングでは見えなかったパターンが浮かび上がりました。
2016年から銭湯にハマり始めた
年別フィルターで見ると、2013〜2015年はほぼ訪問がなく(年0〜3回)、2016年に26回と急増しています。近所の温泉施設に通い始めたのがきっかけでした。
時期ごとに「ホーム銭湯」が変わる
| 時期 | エリア | 傾向 |
|---|---|---|
| 2016-2017 | 都内東部 | 近所の温泉施設に通い詰め |
| 2018-2019 | 都内北東部 | 人気銭湯を開拓 |
| 2020-2021 | 都内西部 | コロナ禍でも最多ペース |
| 2022-2023 | 埼玉南部 | スーパー銭湯がホームに |
| 2024-2026 | 埼玉南部 | サウナ施設も加わり2拠点体制 |
生活圏の変化がそのまま銭湯の変遷に反映されています。ヒートマップで見ると、光っているエリアが時期ごとに移動していくのが面白いです。
旅先でも銭湯に寄る
マーカーを引いて全国表示にすると、沖縄、山形、京都、箱根、鬼怒川など、旅行先でも温泉・銭湯に立ち寄っていることがわかります。1回だけの小さなマーカーが全国に散らばっているのを見ると、旅の記憶が蘇ります。
GitHub Pagesへのデプロイ
ビルドツールを使っていないので、デプロイは非常にシンプルです。
-
docs/ディレクトリにindex.htmlとsento-data.jsを配置 - GitHubリポジトリの Settings → Pages → Source で
mainブランチの/docsを選択
これだけで公開されます。
まとめ
- LeafletでAPIキー不要、ビルド不要
- マーカーサイズ可変で訪問頻度が直感的にわかる
- ヒートマップで「銭湯ホットスポット」が浮かび上がる
- 年別フィルターで行動圏の変遷が見える
ランキング表だけでは数字の羅列だったデータが、地図にすることで「どこに住んでいた時期にどの銭湯に通っていたか」というストーリーが見えるようになりました。自分の生活史を銭湯で振り返るのは、なかなか楽しい体験です。
データの抽出方法は前回の記事を参照してください。カフェやラーメン屋など、キーワードを変えれば同じように可視化できます。
