1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

どの駅からも若干遠い場所を徒歩到達圏で可視化してみる ― 国土数値情報×OSM

1
Posted at

はじめに

前回の記事では、国土数値情報の鉄道データを使い、
駅を起点とした 徒歩圏を円形バッファ で可視化しました。

円形バッファは、

  • 実装がシンプル
  • 見た目が直感的
  • 広域を一度に把握しやすい

といったメリットがある一方で、
実際に歩くことを考える次の課題があります。

  • 川や線路を横断できない場所でも塗られてしまう
  • 直線距離では近く見えるが、実際には遠回りになる場所がある
  • 「塗られている=歩ける」と誤解しやすい

そこで本記事では、
「歩ける範囲」を前提とした徒歩到達圏を、道路ネットワークを使って可視化してみます。

なお、駅の位置情報については OpenStreetMap の駅ノードを用いることも可能ですが、
本記事では前回記事と同様に、国土数値情報の鉄道データから抽出した駅位置を使用しています。

OSM の駅データは柔軟に利用できる一方で、
駅の定義や位置の粒度が路線や編集状況によって異なる場合があります。
今回は「駅という拠点をどのように扱うか」を一定の条件で揃えるため、
国土数値情報の駅データを用いています。

徒歩到達圏

  • 駅を起点にする
  • 徒歩用の道路ネットワーク上で距離を計算する
  • 徒歩10分(800m)以内で到達できる範囲を抽出する

エッジを基準に徒歩到達圏を作る

徒歩到達圏を面として表現するため、道路エッジを基準にします。

  • 徒歩10分以内に到達できるノードを求める
  • 両端が到達可能な道路エッジのみを対象にする
  • 道路エッジを太くし面として扱う

この方法では、

  • 道路に沿った形で徒歩到達圏が広がる
  • 境界部分を無理に含めない
  • 到達できない場所は塗られない

結果として、徒歩到達圏の中に が残りますが、
これは到達できない可能性がある場所がそのまま表現されている状態です。

c7bfb2b6a58e96818aea-1.png

一駅で徒歩到達圏を作る最小コード

ここでは一駅を例に、徒歩到達圏を 道路ネットワーク上の距離 で求めます。

  • 起点:駅(緯度経度)
  • 徒歩ネットワーク:OSMnx で取得
  • 到達可能ノード:Dijkstra(距離 cutoff)
  • 到達エッジ:両端が到達可能なものだけ
  • 面:到達エッジを buffer して union

必要なライブラリ

pip install osmnx geopandas shapely networkx matplotlib numpy
single_station_isochrone_edges_min.py
from __future__ import annotations

from pathlib import Path

import matplotlib.pyplot as plt
import geopandas as gpd
import networkx as nx
import numpy as np
import osmnx as ox
from shapely.geometry import Point


# ==========================
# 設定(ここだけ触ればOK)
# ==========================
STATION_NAME = "Shinjuku Station"
STATION_LAT = 35.690921
STATION_LON = 139.700258

WALK_MINUTES = 10
WALK_SPEED_M_PER_MIN = 80  # 4.8km/h相当
CUTOFF_M = WALK_MINUTES * WALK_SPEED_M_PER_MIN  # 10分=800m

NETWORK_DIST_M = 2000  # 取得する徒歩ネットワーク半径
EDGE_BUFFER_M = 25     # エッジを太くする幅(m)

CACHE_DIR = Path("cache_osm")
CACHE_DIR.mkdir(exist_ok=True)
GRAPHML_PATH = CACHE_DIR / f"walk_graph_{STATION_NAME.replace(' ', '_')}_{NETWORK_DIST_M}m.graphml"


def main() -> None:
    ox.settings.use_cache = True
    ox.settings.log_console = True

    # --------------------------
    # 1) 徒歩ネットワーク取得(キャッシュ)
    # --------------------------
    if GRAPHML_PATH.exists():
        G = ox.load_graphml(GRAPHML_PATH)
    else:
        G = ox.graph_from_point(
            center_point=(STATION_LAT, STATION_LON),
            dist=NETWORK_DIST_M,
            network_type="walk",
            simplify=True,
            retain_all=False,
            truncate_by_edge=True,
        )
        ox.save_graphml(G, GRAPHML_PATH)

    # --------------------------
    # 2) 投影(buffer用にメートル座標へ)
    # --------------------------
    Gp = ox.project_graph(G)

    nodes_gdf, edges_gdf = ox.graph_to_gdfs(Gp, nodes=True, edges=True)

    # 駅ポイント(投影座標系)
    station_pt = (
        gpd.GeoSeries([Point(STATION_LON, STATION_LAT)], crs="EPSG:4326")
        .to_crs(nodes_gdf.crs)
        .iloc[0]
    )

    # --------------------------
    # 3) 起点ノード(簡易的に最近傍を探索)
    # --------------------------
    # OSMnxの距離関数はメートルで返る(投影済みなので)
    dists = ox.distance.euclidean(station_pt.x, station_pt.y, nodes_gdf["x"], nodes_gdf["y"])
    orig = nodes_gdf.index.to_numpy()[int(np.argmin(dists))]

    # --------------------------
    # 4) Dijkstra(cutoff付き)で到達可能ノード
    # --------------------------
    dist = nx.single_source_dijkstra_path_length(Gp, orig, cutoff=CUTOFF_M, weight="length")
    reachable_nodes = set(dist.keys())

    print(f"[info] reachable nodes: {len(reachable_nodes):,}")
    print(f"[info] cutoff: {CUTOFF_M} m")

    # --------------------------
    # 5) 到達エッジ抽出(両端到達)
    # --------------------------
    u = edges_gdf.index.get_level_values(0)
    v = edges_gdf.index.get_level_values(1)
    reachable_edges = edges_gdf[u.isin(reachable_nodes) & v.isin(reachable_nodes)].copy()

    print(f"[info] reachable edges (both-ends): {len(reachable_edges):,}")

    # --------------------------
    # 6) エッジを太くしてポリゴン化(union)
    # --------------------------
    buffered = reachable_edges.geometry.buffer(EDGE_BUFFER_M)

    # unary_union は deprecated → union_all()
    isochrone_poly = buffered.union_all()

    # --------------------------
    # 7) 可視化(最小)
    # --------------------------
    fig, ax = plt.subplots(figsize=(10, 10))

    edges_gdf.plot(ax=ax, linewidth=0.5, alpha=0.2)
    reachable_edges.plot(ax=ax, linewidth=1.5, alpha=0.8)
    gpd.GeoSeries([isochrone_poly], crs=edges_gdf.crs).plot(ax=ax, alpha=0.35)
    gpd.GeoSeries([station_pt], crs=edges_gdf.crs).plot(ax=ax, markersize=80)

    ax.set_title(f"{STATION_NAME} | Walk {WALK_MINUTES} min (both-ends edges + buffer)")
    ax.set_axis_off()
    plt.tight_layout()
    plt.show()


if __name__ == "__main__":
    main()

全駅(東京23区)を対象に徒歩到達圏を算出する

一駅で示した徒歩到達圏の考え方を、同じ条件のまま全駅に適用します。

処理の流れはシンプルで、

  • 各駅を起点として徒歩到達圏を算出する
  • それらを重ね合わせる

という手順を繰り返します。

全駅の徒歩到達圏ポリゴンを結合する

全駅の徒歩到達圏は、各駅で作った到達圏ポリゴンを順次 union していくことで表現できます。

  • 駅ごとに徒歩到達圏ポリゴンを作る
  • それを union_poly に重ねていく
ポリゴン結合の処理部分
# 事前に以下が用意されている想定
# - Gp: 投影済み徒歩グラフ(osmnx.project_graph)
# - edges_gdf: 投影済みエッジGeoDataFrame(ox.graph_to_gdfs)
# - station_node_ids: 各駅の起点ノードIDの配列(nearest_nodesで事前計算)

# shapely 2.x
from shapely import union_all
import networkx as nx

union_poly = None

for orig in station_node_ids:
    # 徒歩10分以内の到達ノード
    dist = nx.single_source_dijkstra_path_length(Gp, orig, cutoff=CUTOFF_M, weight="length")
    reachable = set(dist.keys())

    # 両端が到達可能なエッジだけ残す
    u = edges_gdf.index.get_level_values(0)
    v = edges_gdf.index.get_level_values(1)
    reach_edges = edges_gdf[u.isin(reachable) & v.isin(reachable)]

    if len(reach_edges) == 0:
        continue

    # 駅ごとの到達圏ポリゴン
    poly_i = reach_edges.geometry.buffer(EDGE_BUFFER_M).union_all()

    # 全駅を順次 union
    union_poly = poly_i if union_poly is None else union_all([union_poly, poly_i])

東京23区全体で見た徒歩到達圏と空白地帯

東京23区内の全駅を対象に算出した徒歩到達圏を重ね合わせることで、
「徒歩10分で、いずれかの駅に到達できる範囲」を可視化します。

c7bfb2b6a58e96818aea-2.png

c7bfb2b6a58e96818aea-3.png

徒歩到達圏は円状には広がらず、道路ネットワークに沿った不均一な形で分布します。

  • 徒歩10分で到達できる範囲は塗られている
  • 塗られていない部分は、駅から徒歩10分では到達しにくい

まとめ

本記事では、
駅徒歩圏を円形バッファで表現する方法から一歩進めて、
道路ネットワークを用いた徒歩到達圏の可視化を行いました。

  • 直線距離ではなく、道路ネットワーク上の距離を用いる
  • 一駅を例に、徒歩到達圏の形がどのようになるかを確認する
  • 同じ定義のまま、東京23区内の全駅に適用する
  • 徒歩10分で到達できる範囲を地図上に重ねて表示する

という流れで進めています。

徒歩到達圏を用いることで、円形バッファでは見えにくかった差が、
そのまま地図上に現れます。

徒歩到達圏という視点で見ると、駅の数だけでは捉えきれない都市の構造が見えてきます。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?