はじめに
国土数値情報では、行政区域や道路、鉄道など、
さまざまな地理空間データがオープンデータとして公開されています。
本記事では、その中から 行政区域データ(N03) を対象に、
Python と folium を使って、都道府県ポリゴンを地図上に表示します。
行政区域データを地図に重ねるだけであれば特別な工夫は不要ですが、
実際に folium で可視化してみると、
- 生成される HTML ファイルが非常に大きくなる
- 軽量化を行うと、境界線に不自然な隙間や線が現れる
といった問題が発生します。
本記事では、これらの事象を通して、
- Web 地図(ブラウザ表示)を前提としたデータの扱い方
- 表示用途における精度と軽量化の考え方
- 軽量化とトポロジ(境界構造)の関係
を整理していきます。
使用するデータと環境
本記事で使用するデータは、
国土数値情報が公開している 行政区域データ(N03) です。
N03 データには、都道府県・市区町村といった行政区域の境界情報が含まれています。
今回はその中から 都道府県レベルのポリゴン を使用します。
データ形式は GeoJSON を利用します。
都道府県ポリゴンを folium に重ねてみる
まずは、行政区域データ(N03)から都道府県ポリゴンを抽出し、
folium を使って地図上に表示します。
処理の流れは以下のとおりです。
- N03 データの読み込み
- 都道府県単位での集約(dissolve)
- 座標参照系を EPSG:4326 に変換
- folium による地図表示
Python 側では geopandas を使ってポリゴンを集約し、
folium で GeoJSON として地図に重ねます。
import geopandas as gpd
import folium
from pathlib import Path
# 入力データ
INPUT = Path("data/N03-20230101_GML/N03-23_230101.geojson")
# 都道府県ポリゴンを読み込み
gdf = gpd.read_file(INPUT)
# 都道府県単位で集約
pref = gdf.dissolve(by="N03_001", as_index=False)
# folium 用に EPSG:4326 へ変換
pref = pref.to_crs(epsg=4326)
# 地図作成
m = folium.Map(
location=[36.0, 138.0],
zoom_start=5,
tiles="CartoDB positron"
)
# GeoJSON を重ねる
folium.GeoJson(
pref,
name="prefecture",
style_function=lambda f: {
"fillOpacity": 0.0,
"color": "#000000",
"weight": 1.2,
},
).add_to(m)
folium.LayerControl().add_to(m)
# 出力
m.save("prefecture_map.html")
この状態でも、都道府県ポリゴンは問題なく地図上に表示されます。
見た目としては、目的どおり「日本全国の都道府県境界」を確認できます。
一方で、この時点で生成される HTML ファイルは非常に大きくなります。
GeoJSON がそのまま HTML 内に埋め込まれるため、
ファイルサイズは数百 MB 規模になります。
表示用途を前提とした軽量化と、その副作用
表示用途を前提として、データの軽量化を行います。
まずは、ポリゴン形状の簡略化と座標精度の調整を行いました。
# ポリゴン形状の簡略化(頂点数削減)
pref["geometry"] = pref["geometry"].simplify(
tolerance=0.001, # 約100m
preserve_topology=True
)
# 座標精度の調整(小数6桁相当)
pref["geometry"] = pref["geometry"].apply(
lambda geom: set_precision(geom, grid_size=1e-6)
)
これらの処理によってデータサイズは大きく削減されますが、
軽量化後のデータを地図上に表示すると、以下のような現象が確認できます。
- 隣接する都道府県ポリゴン間の隙間
- 境界線の重なりや二重表示
- 都道府県内部に現れる不自然な線
これは、ポリゴンを個別に簡略化・精度調整したことで、
共有されていた境界構造(トポロジ)が維持されなかったことによるものです。
トポロジを意識した解決と mapshaper の利用
都道府県ポリゴンを GeoJSON として作成し、
そのデータに対して mapshaper を適用します。
この章で行う処理は次のとおりです。
- N03 データから都道府県ポリゴンを作成
- EPSG:4326 に変換した GeoJSON を生成
- 生成した GeoJSON に対して mapshaper を適用
都道府県ポリゴンの作成
まず、N03 データから都道府県単位のポリゴンを作成し、
mapshaper に渡す入力データを用意します。
import geopandas as gpd
from pathlib import Path
# ==============================
# 入力・出力
# ==============================
INPUT = Path("data/N03-20230101_GML/N03-23_230101.geojson")
OUT_DIR = Path("data/processed")
OUT_DIR.mkdir(parents=True, exist_ok=True)
OUT_PREF_4326 = OUT_DIR / "n03_pref_4326.geojson"
# ==============================
# 処理
# ==============================
# N03 データ読み込み
gdf = gpd.read_file(INPUT)
# 都道府県単位に集約
# N03_001 : 都道府県名
pref = gdf.dissolve(by="N03_001", as_index=False)
# folium / Web 地図向けに EPSG:4326 へ変換
pref = pref.to_crs(epsg=4326)
# GeoJSON として保存
pref.to_file(OUT_PREF_4326, driver="GeoJSON")
print(f"written: {OUT_PREF_4326}")
print(f"rows: {len(pref)}")
print(f"crs: {pref.crs}")
このスクリプトでは、以下のみを行っています。
- 都道府県単位での集約(dissolve)
- Web 地図向けに EPSG:4326 へ変換
- GeoJSON として保存
mapshaper によるトポロジを維持した処理
mapshaper data/processed/n03_pref_4326.geojson \
-clean \
-simplify 10% keep-shapes \
-o format=geojson precision=0.000001 \
data/processed/n03_pref_4326_clean_s10_p6.geojson
mapshaper では、隣接するポリゴンが共有する境界を考慮したまま処理が行われます。
この結果、
軽量化と表示品質を両立した都道府県ポリゴンの GeoJSON を
作成することができます。
まとめ
本記事では、国土数値情報の行政区域データ(N03)を題材に、
都道府県ポリゴンを Web 地図(folium)で扱う際の実践的な処理手順を整理しました。
単純な軽量化では、境界構造(トポロジ)が崩れ、隙間や不自然な境界線が発生します。
そこで、都道府県ポリゴンを一度まとめた上で、
mapshaper を用いてトポロジを維持したまま処理することで、
表示品質を保ったままデータを軽量化しました。
事前処理でデータ量を調整しておくことで、実用上扱いやすいデータにできます。


