はじめに
Google Maps Platform や Mapbox など、クラウドAPIを利用した経路探索や到達圏分析が一般的になっています。
しかし、こうした外部サービスには コスト・API制限・データ共有の制約 など、運用上の課題も少なくありません。
そこで本記事では、OpenStreetMap(OSM)データを使ってローカル環境でGraphHopperを動かし、
徒歩10分圏などの到達圏(Isochrone)を生成する方法 を解説します。
GraphHopperはJava製の高性能なルーティングエンジンであり、
クラウドに依存せずに、自前でOSMデータを解析・APIサーバとして提供 できます。
本記事では、徒歩到達圏をローカル環境で生成・可視化する手順をハンズオン形式で紹介します。
対象読者
- OpenStreetMapを活用したルーティング・到達圏分析を行いたいエンジニア
- 商用APIを避けて自社・ローカル環境で完結させたい方
- GraphHopperを実際に動かし、Isochrone APIを試してみたい方
このあとの章では、GraphHopperの構成と仕組みを確認しながら、
実際に .osm.pbf ファイルを読み込み、徒歩到達圏をGeoJSONで出力・地図上で可視化するまでを解説します。
ローカル実装の意義とGraphHopperの位置づけ
Google Maps Platform や Mapbox などのクラウドAPIで経路探索や到達圏分析を行うことが一般的になりました。
しかし、商用APIにはコストや仕様変更、データ共有の制約といった課題もあります。
到達圏検索をローカル環境で実現する3つの方法 — OSMデータの活用
こうした課題を解決する方法の一つが、
OpenStreetMap(OSM)データを使って自前のルーティングサーバを構築すること です。
GraphHopperはその代表的な実装であり、
シンプルな設定で起動でき、徒歩・自転車・車など複数モードの経路探索に対応しています。
また、到達圏(Isochrone)機能を標準で備えており、
ローカル環境で商圏分析や徒歩圏解析を行いたい場面に最適です。
GraphHopperとは
GraphHopperは、OpenStreetMap(OSM)の道路データを基に経路探索を行う Java製のルーティングエンジン です。
ローカル環境で .osm.pbf ファイルを解析し、HTTP API を通じてルート検索や到達圏(Isochrone)を提供できます。
特徴
- ローカル実行可能:クラウドに依存せず、自社環境やオフライン環境で動作
- 複数モード対応:徒歩・自転車・車など、用途に応じたルーティングを切り替え可能
- Isochrone API 搭載:任意の地点から到達できる範囲をポリゴンとして取得
- カスタムモデル対応:速度制限や道路条件を反映したルーティング設定が可能
- 拡張機能:標高データ(Elevation)やターンコストなどにも対応
GraphHopperは単なるルーティングエンジンではなく、
OSMデータを前処理して独自のグラフ構造を生成し、そこに最適化アルゴリズムを適用する仕組み を持ちます。
そのため、同じデータでもプロファイル設定(車・徒歩など)によって異なる探索結果が得られます。
OSRMとの違い
| 項目 | GraphHopper | OSRM |
|---|---|---|
| 実装言語 | Java | C++ |
| 主な用途 | ルーティング、到達圏分析 | ルーティング専用 |
| API構成 | Directions / Isochrone / Matrix など | Route / Table / Match / Trip |
| 設定方法 | YAML構成ファイル+カスタムモデル | コマンドライン+Luaプロファイル |
| 拡張性 | 高い(カスタムモデル対応) | 限定的 |
| 実行方式 | Java実行(JAR) | Docker / Linux中心 |
実行環境の目安
- Java 21 以上(OpenJDK / Temurinなど)
- メモリ 4〜6GB 程度を推奨(対象エリアにより変動)
- OS:Windows / macOS / Linux いずれでも実行可能
GraphHopper公式では Java 17 以上が推奨されていますが、
本記事では安定動作を確認した Java 21 環境 を使用します。
OSMデータを取得する
GraphHopperは、OpenStreetMap(OSM)の道路ネットワークをもとにグラフを生成します。
そのため、まずは対象エリアのOSMデータ(.osm.pbf 形式)と、
GraphHopper本体(.jar ファイルと設定ファイル)を用意する必要があります。
GraphHopper本体の取得
- 公式リリースページ にアクセス
- 最新の安定版(例:
graphhopper-web-11.0.jar)をダウンロード -
config-example.ymlも合わせて取得し、同一ディレクトリに保存します
# GraphHopper公式から取得したJARと設定ファイルを同一フォルダに配置
graphhopper/
├─ graphhopper-web-11.0.jar
└─ config-example.yml
GraphHopper本体をcurlで取得する場合
# 作業ディレクトリを作成
mkdir -p graphhopper && cd graphhopper
# GraphHopper本体(JAR)をダウンロード
curl -L -O https://github.com/graphhopper/graphhopper/releases/download/11.0/graphhopper-web-11.0.jar
# 設定ファイル(YAML)をダウンロード
curl -L -O https://github.com/graphhopper/graphhopper/releases/download/11.0/config-example.yml
Geofabrikとは
Geofabrik は、OpenStreetMapのデータを地域別に配布しているサイトです。
国単位・地方単位で .osm.pbf ファイルをダウンロードでき、GraphHopperやOSRMなど多くのGISツールで利用されています。
OSMデータのダウンロード
-
Geofabrikにアクセス
https://download.geofabrik.de/ -
対象エリアを選択
- 日本の場合は「Asia → Japan」へ進みます
- 関東地方のみを使いたい場合は
https://download.geofabrik.de/asia/japan/kanto.html
-
ページ内のリンクから
.osm.pbfファイルを取得します。
今回はkanto-latest.osm.pbfを使用します。ダウンロード後、GraphHopperを実行するディレクトリ(例:
graphhopper/)に配置します。
ディレクトリ構成例
graphhopper/
├─ graphhopper-web-11.0.jar ← GraphHopper本体
├─ config-example.yml ← 設定ファイル
└─ kanto-latest.osm.pbf ← Geofabrikから取得したOSMデータ
GraphHopperを起動する(ローカル実行)
ここからは、ローカル環境でGraphHopperを起動し、.osm.pbf をもとにHTTP APIを動かします。設定は「最小で確実に動く」構成に絞ります。
設定ファイルの編集(最小構成)
まずは config-example.yml を、本記事で実際に動作確認した最小構成に整えます。
(Elevationはサブ要素のため触れず、到達圏と基本ルーティングに必要な項目だけを残します)
# === 最小で確実に動く GraphHopper v11 用設定 ===
logging:
level: INFO
loggers:
com.graphhopper: INFO
graphhopper:
# 読み込む PBF
datareader.file: kanto-latest.osm.pbf
# キャッシュ出力先(削除で再生成)
graph.location: graph-cache
# ビルトインのカスタムモデルを使用(ローカルに同名jsonを置かないこと)
profiles:
- name: car
custom_model_files: [car.json]
- name: foot
custom_model_files: [foot.json, foot_elevation.json]
graph.encoded_values: car_access, car_average_speed, foot_access, hike_rating, foot_priority, country, road_class, foot_road_access, mtb_rating, foot_average_speed, average_slope
graph.elevation.provider: srtm
graph.elevation.dataaccess: RAM_STORE
# まずは前処理なしでOK(必要なら後で追加)
profiles_ch: []
profiles_lm: []
import.osm.ignored_highways: []
graph.dataaccess.default_type: RAM_STORE
# Dropwizard server configuration
server:
application_connectors:
- type: http
port: 8989
# for security reasons bind to localhost
bind_host: localhost
# increase GET request limit - not necessary if /maps UI is not used or used without custom models
max_request_header_size: 50k
request_log:
appenders: []
admin_connectors:
- type: http
port: 8990
bind_host: localhost
# See https://www.dropwizard.io/en/latest/manual/core.html#logging
logging:
appenders:
- type: file
time_zone: UTC
current_log_filename: logs/graphhopper.log
log_format: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
archive: true
archived_log_filename_pattern: ./logs/graphhopper-%d.log.gz
archived_file_count: 30
never_block: true
- type: console
time_zone: UTC
log_format: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
loggers:
"com.graphhopper.osm_warnings":
level: DEBUG
additive: false
appenders:
- type: file
currentLogFilename: logs/osm_warnings.log
archive: false
logFormat: '[%level] %msg%n'
-
profilesはcarとfootの2つを有効化 -
custom_model_filesはビルトイン(JAR内)を参照し、ローカルに同名JSONを置かない -
import.osm.ignored_highwaysは空配列でも キーを必ず定義 - キャッシュは
graph-cache/に生成(設定変更時は削除→再生成)
初回インポートとキャッシュ生成
初回起動時は、.osm.pbf からルーティング用グラフを構築します。
対象エリアが大きいほど時間とメモリを消費します(関東で数分〜十数分目安)。
次のコマンドで起動します。
java -Xmx4g -jar graphhopper-web-11.0.jar server config-example.yml
補足
-
-XmxはPCのメモリに合わせて調整(4〜8GB目安) - 画面にインポートや前処理のログが流れ、完了後にサーバがListen状態になる
この状態で http://localhost:8989/ にアクセスします。
ルート検索結果例
APIの動作確認(footルート)
APIを直接叩いて動作確認します。
例:東京駅 → 新宿駅(徒歩)
curl "http://localhost:8989/route?point=35.681236,139.767125&point=35.689592,139.700413&profile=foot&locale=ja"
レスポンス(抜粋)は以下のような構造です。
{
"hints": {
"visited_nodes.sum": 55120,
"visited_nodes.average": 55120.0
},
"info": {
"copyrights": [
"GraphHopper",
"OpenStreetMap contributors"
],
"took": 60,
"road_data_timestamp": "2025-10-18T20:20:55Z"
},
"paths": [
{
"distance": 7938.0,
"time": 6176793,
"points_encoded": true,
"bbox": [139.70027, 35.67736, 139.768168, 35.690526],
"points": "(中略: LineString 形式の座標データ)",
"instructions": [
{ "text": "進む", "distance": 9.4 },
{ "text": "右に曲がる(中央通路)", "distance": 1.5 },
{ "text": "左に曲がる", "distance": 12.4 },
{ "text": "(中略)" },
{ "text": "右に曲がる(JR新宿駅, 南口改札に入る)", "distance": 23.4 },
{ "text": "目標達成", "distance": 0.0 }
],
"ascend": 217.0,
"descend": 179.0
}
]
}
- 利用可能なプロファイルは
/infoで確認できます(car/footなど)。 -
/routeが通れば/isochroneも同様のprofile指定で呼び出せます。
ハマりどころ
| 症状 / メッセージ | 主な原因 | 対処 |
|---|---|---|
Missing 'import.osm.ignored_highways' |
必須キー未定義 |
import.osm.ignored_highways: [] を定義 |
vehicle no longer accepted in profile |
旧形式(v9+非対応) |
vehicle: を使わず custom_model_files: を使う |
Custom model file name 'car.json' is already used |
ローカルに同名JSONを配置 | ローカル同名ファイルを削除 or 別名化 |
| 起動はするがUIが開けない | ポート競合/localhost制限 |
server設定を見直す or 競合プロセス停止 |
| 設定を変えても反映されない | 旧キャッシュが残存 |
graph-cache/ を削除して再起動 |
| OutOfMemory系で落ちる | メモリ不足 |
-Xmx6g などへ増量、対象エリアを小さく |
徒歩到達圏(Isochrone API)をGeoJSONで取得する
GraphHopperは、経路探索だけでなく「到達圏(Isochrone)」も標準APIとして備えています。
特定の地点から、指定した移動時間(または距離)内で到達可能な範囲をGeoJSON形式で取得できます。
ここでは、東京駅を中心に「徒歩10分圏(600秒)」を取得してみます。
Isochrone APIの概要
Isochrone APIは /isochrone エンドポイントを使用します。
主なパラメータは以下の通りです。
| パラメータ | 説明 | 例 |
|---|---|---|
point |
出発地点の緯度・経度 | 35.681236,139.767125 |
time_limit |
到達時間(秒) |
600 = 10分 |
profile |
使用プロファイル(car, foot など) |
foot |
buckets |
段階的に等時間帯を出す場合の分割数(任意) |
3 など |
APIを呼び出す
徒歩10分圏をGeoJSONで取得します。
curl "http://localhost:8989/isochrone?point=35.681236,139.767125&time_limit=600&profile=foot" -o isochrone_10min.geojson
このリクエストにより、指定座標から徒歩600秒以内に到達可能な範囲をポリゴンで返します。
レスポンス例(GeoJSON抜粋)
{
"polygons": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[139.7603893, 35.68285085],
[139.7603567, 35.6826253],
[139.7607457, 35.6825358],
"...(中略:多数の頂点座標が続く)...",
[139.7603893, 35.68285085]
]
]
},
"properties": { "bucket": 0 }
}
],
"info": {
"took": 116,
"road_data_timestamp": "2025-10-18T20:20:55Z"
}
}
GraphHopper の /isochrone API は、GeoJSON 互換の構造でレスポンスを返します。
ただし、トップレベルは "FeatureCollection" ではなく、"polygons" 配列の中に複数の Feature が含まれます。
Folium などで直接読み込む場合は、{"type": "FeatureCollection", "features": data["polygons"]} のように明示的に FeatureCollection 形式に変換して利用します。
Foliumで可視化(GeoJSON描画)
/isochrone で取得した GeoJSON(例:isochrone_10min.geojson)を、ローカルで Folium(Leaflet)を使って地図上に重ねて表示します。
GeoJSONを読み込み・描画して保存
以下のスクリプトは、GeoJSON を読み込み、中心点(東京駅)を初期表示に設定し、ポリゴンを重ねて isochrone_10min.html として保存します。
import json
import folium
# 中心(東京駅)
center = [35.681236, 139.767125]
m = folium.Map(location=center, zoom_start=14, tiles="OpenStreetMap")
# GraphHopper Isochrone のレスポンスを読み込み
with open("isochrone_10min.geojson", "r", encoding="utf-8") as f:
data = json.load(f)
# GraphHopper形式 → FeatureCollection へ変換
if "polygons" in data:
feature_collection = {
"type": "FeatureCollection",
"features": data["polygons"], # そのままfeaturesへ
}
elif data.get("type") == "FeatureCollection":
feature_collection = data
else:
# 単一Featureで返ってきた場合などに備えたフォールバック
feature_collection = {
"type": "FeatureCollection",
"features": [data],
}
# GeoJSONを重ねる
folium.GeoJson(
feature_collection,
name="Isochrone 10min (foot)",
style_function=lambda feature: {
"fillColor": "#3186cc",
"color": "#3186cc",
"weight": 2,
"fillOpacity": 0.4,
},
tooltip=folium.GeoJsonTooltip(fields=[], aliases=[]),
).add_to(m)
# 中心点(任意)
folium.Marker(center, tooltip="Origin").add_to(m)
# 保存
m.save("isochrone_10min.html")
print("saved: isochrone_10min.html")
作成したHTMLを確認
補足:到達圏ポリゴンの「尖り」について
/isochrone API が生成するポリゴンは、到達可能ノードを基に自動的に外周を補間して形成されます。
そのため、一部の辺が“尖った形状”になりますが、これは「地理的なネットワーク構造(道路の枝状部分)」を反映した結果です。
ただし、塗りつぶされた領域すべてが到達可能とは限らない点に注意が必要です。
ポリゴンは「外接形」として描かれるため、実際には通行不能な空間(河川・施設内部など)を含む場合があります。
厳密な可達範囲を評価する際は、ノード単位での可視化やルートサンプリングを併用するとより正確です。
まとめ:ローカルで動かす到達圏分析の意義
本記事では、GraphHopper v11 を用いて ローカル環境で徒歩到達圏を算出・可視化 するまでの手順を解説しました。
SaaSや外部APIに依存せず、手元で地理解析が完結する点が大きな特徴です。
- OSMデータ(PBF)を取得し、GraphHopperへ読み込む
-
config-example.ymlを最小構成に調整し、徒歩プロファイルを有効化 -
/isochroneAPI で到達圏ポリゴンを取得 - Python+FoliumでGeoJSONを描画し、地図上で可視化
これにより、都市・地域スケールでの徒歩圏分析をクラウド環境を使わず再現できるようになりました。
今後の発展例
- 複数条件の到達圏比較(徒歩5分/10分圏など)
- 勾配情報(elevation)を考慮した徒歩コスト評価
- 公共交通や自転車ルートとの組み合わせ
- PostGIS・QGISとの統合分析
GraphHopperは商用ルーティングエンジンにも採用される成熟度を持ちながら、
個人のローカル環境でも軽量に動作します。
これを活用することで、オープンデータを用いた再現性の高い地理分析 が可能となります。


