国土数値情報「海岸線」データ(全国版 Shapefile)

国土数値情報「海岸線」データ(全国版 Shapefile)のURL
を調べたが全国版はない

都道府県別に Shapefile 形式や GML 形式で取得可能な国土数値情報「海岸線」データのダウンロードページがある

https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-C23.html?utm_source=chatgpt.com
が海岸線データのリンクだけど
最新のデータは2006年度(平成18年度)版

他を調べてみると

の情報があった
https://nlftp.mlit.go.jp/ksj/index.html

これらを元にGPTで調べてみる

📊 スクショにあるデータの役割
* 津波浸水想定区域データ
→ 津波が来た場合の浸水範囲(自治体がハザードマップで使う)。
* 洪水浸水想定区域データ
→ 河川ごと、メッシュごとの洪水想定範囲。
* 高潮・雨水出水・多段階浸水データ
→ 津波以外の沿岸・豪雨災害関連のリスク領域。
* 避難所・避難道路系(行政区、緊急輸送道路など)
→ 避難経路や防災拠点の把握に必須。

🌊 あなたの用途別の適材適所
1. 「海岸線」データ(国土数値情報 2006年版)
* 海と陸の境界を決める基盤。
* 最新ではないが行政基準値。
* → 基準線として使う。
2. スクショの「津波浸水想定区域データ」
* シミュレーション済みの「どこまで水が来るか」。
* → 津波到達後の浸水エリア算出に必須。
3. スクショの「洪水・高潮データ」
* 津波以外のリスクも扱える。
* → 家族の防災マップを広くカバー。
4. 避難所・緊急輸送道路データ
* 実際の「どこに逃げるか」「どう行くか」。
* → GraphDBの避難所ノード・道路ノードに登録。

✅ 推奨データ利用の組み合わせ
* ベース地図:
* 国土数値情報「海岸線」 + OSM Coastlines(更新補完)
* リスク領域:
* 津波浸水想定区域データ(スクショにある)
* 洪水・高潮想定区域データ
* 地形:
* DEM(国土地理院/GEBCO)
* 避難系:
* 避難所・緊急輸送道路・行政区データ
* GraphDB:
* ノード:震源・海岸線・浸水想定区域・避難所・道路・家族
* リレーション:到達時間・避難経路・所要時間・備蓄品

🔑 結論:
スクショにある「津波浸水想定区域データ」や「洪水浸水想定区域データ」は 必ず併用すべきデータ です。
単なる「海岸線」だけでは津波到達範囲はわからないので、
* 海岸線 = 境界線
* 浸水想定区域 = 被害範囲
として 両方組み合わせるのがベスト

まずは居住区域のみで作成して動くようなら適用範囲を拡大していく

pip install geopandas shapely rtree pyproj osmnx networkx fiona

で必要なパッケージのインストール

📦 パッケージ解説
1. GeoPandas
* 役割: pandas の DataFrame に地理情報(ポリゴンやポイントなどのジオメトリ)を扱えるようにした拡張版。
* 特徴:
* shapefile や GeoJSON など GIS ファイルを直接読み書きできる。
* 空間結合(spatial join)、バッファリング(一定距離の範囲作成)、重なり判定などが簡単にできる。
* 用途例: 避難所の位置と自宅の位置から最寄り避難所を検索。

2. Shapely
* 役割: ジオメトリ(点、線、面)の作成・操作・解析を行うライブラリ。
* 特徴:
* ポリゴンの交差判定やバッファリング、距離計算が可能。
* GeoPandas 内部でも Shapely が使われている。
* 用途例: 津波の浸水範囲ポリゴンと建物の位置の交差判定。

3. Rtree
* 役割: 空間インデックスを構築して、高速に空間検索を行うためのライブラリ。
* 特徴:
* 例えば「ある点から半径 1km 以内の避難所を検索」といった処理が高速化できる。
* GeoPandas で .sindex を使うと裏で Rtree が動作。
* 用途例: 半径○km以内の避難場所を効率的に抽出。

4. PyProj
* 役割: 座標系(緯度経度、UTMなど)の変換を行うライブラリ。
* 特徴:
* EPSG コードを指定して座標変換ができる。
* GeoPandas で .to_crs() を使うと内部で PyProj が使われる。
* 用途例: 世界測地系(WGS84, EPSG:4326)から日本の平面直角座標系(EPSG:6677など)への変換。

5. OSMnx
* 役割: OpenStreetMap (OSM) データを Python で取得・解析するライブラリ。
* 特徴:
* 道路ネットワークや建物形状を簡単にダウンロード可能。
* networkx 形式で道路ネットワークを解析できる。
* 用途例: 自宅から避難所までの徒歩ルート検索。

6. NetworkX
* 役割: グラフ(ネットワーク)解析ライブラリ。
* 特徴:
* 最短経路探索、中心性、連結成分などのネットワーク理論を使った解析が可能。
* OSMnx が取得した道路データを解析するのに必須。
* 用途例: 最短避難経路の算出(Dijkstra アルゴリズムなど)。

7. Fiona
* 役割: 各種 GIS ファイルの入出力を行うためのライブラリ。
* 特徴:
* shapefile や GeoJSON を読み込むときに GeoPandas が内部で使用。
* GDAL(GIS の基盤ライブラリ)の Python バインディング的な存在。
* 用途例: 国土地理院の災害情報シェープファイルの読み込み。

🔗 関係性まとめ
* GeoPandas = GIS用 DataFrame(中心的存在)
* 内部で Shapely(ジオメトリ処理)、PyProj(座標変換)、Fiona(ファイルIO)、Rtree(高速検索)を利用。
* OSMnx = OpenStreetMap から道路や建物を取得 → NetworkX で解析。

✅ あなたの防災マップ用途との対応
* 津波浸水範囲と建物位置の判定 → Shapely / GeoPandas
* 避難所の検索(近い順) → Rtree / GeoPandas
* ルート案内 → OSMnx + NetworkX
* 座標変換(地図投影法の切り替え) → PyProj
* データの入出力(shapefile, GeoJSONなど) → Fiona

👉 この7つをまとめてインストールしておくと、ほぼ PythonでGIS + 避難経路システムを自作できる環境が揃います。

まずは全国ではなく居住区域の静岡県のみで作成して、テストして動くようなら適用範囲を拡大していく

まずは静岡県のみで最小セットを作って、表示・経路探索・レイヤ結合が全部通るか確認

「海岸線(KSJ)+津波浸水想定(KSJ)+道路(OSM)+避難所(自治体オープンデータがあれば)」をGeoPackage 1ファイルにまとめて、テスト用に「自宅→最寄り避難所の最短経路(浸水域は回避)」まで動かす

使うデータ(静岡県のみ)
* 海岸線:国土数値情報 C23 海岸線(Shapefile/GML)
※ページ:国土数値情報ダウンロード → C23(都道府県別を選択して「静岡県」をDL)
* 津波浸水想定区域:国土数値情報(都道府県別配布の「津波浸水想定」)
※静岡県のファイルをDL
* 道路:OSMnxでOSMから静岡県全域の道路グラフを取得(最新更新が反映されやすい)
* 避難所:静岡県/市町のオープンデータ(CSV/GeoJSON、なければ後で追加)
ポイント
* 最初は海岸線+津波浸水+道路の3つでOK。
* 経路探索やバッファ計算など**距離単位(m)**が必要になるので、計算時は **WGS84/UTM Zone 54N(EPSG:32654)**に投影して処理します(静岡は概ね54N)。

このために必要なファイルのダウンロード
https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-C23.html?utm_source=chatgpt.com
から海岸線データのダウンロード
今回は静岡県のみ

次に
津波浸水想定区域データのダウンロード
https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A40-2024.html
からダウンロード
これもまずは静岡県のみ
ただし更新が2016年になっている
他の地域だと2024年まで更新されている

難所:静岡県/市町のオープンデータ(CSV/GeoJSON、なければ後で追加)
をやろうとしたけど
居住の市にCSVファイルがない…

https://www.city.fukuroi.shizuoka.jp/opendata/opendata/data/1490706118930.html

ふじのくにオープンデータカタログ
にあるらしいがリンクが違っているので検索する

https://opendata.pref.shizuoka.jp/dataset/

ふじのくにオープンデータカタログ

https://opendata.pref.shizuoka.jp/dataset/search/?s%5Barea_id%5D=36
に袋井市があった

指定緊急避難場所一覧
https://opendata.pref.shizuoka.jp/dataset/10246.html
最新版は
20250801_指定緊急避難場所一覧 (CSV 17.8KB)
なので
これをダウンロードする

次にプロジェクトフォルダの作成

mkdir FamilySafetyMap

名前を決めるのは苦手なので gemini を使った

源地から津波が到達するまでの時間と津波の高さを計算し GIS情報を使い避難するエリアを算出しルート案内できるようにしたい 家族の避難経路・地域防災マップをGraphDBで整理 避難所や重要連絡先も紐付け 使い方例: 「地震が来たら最寄りの避難所はどこ?」 「非常食の賞味期限が近いものは?」 など この用途で使うプロジェクトファイル名を決めたい。
使用するのは家族がメイン

実用・機能重視FamilySafetyMap家族の安全と地図(避難経路、GIS情報)という機能が明確。シンプルで覚えやすい。

が答え

cd FamilySafetyMap 
mkdir -p data/coastline_shizuoka/
mkdir -p data/tsunami_shizuoka/  

ファイルを設置しようとしたけど
どれを入れるかわからなくなったので

どっちが海岸線?どっちが津波浸水想定?
* C23-06_22_GML → 中に *_Coastline.* があり、これは 海岸線(C23)
例:C23-06_22-g_Coastline.shp ← これを 海岸線 として使う
* A40-16_22_GML → A40-16_22.* は 津波浸水想定区域(A40) のシェープ
つまり:
海岸線 = C23、津波浸水 = A40 です(認識を入れ替えてください)。

置くべきファイル(Shapefileの必須構成)
各フォルダに、少なくとも下記が同じ名前で揃っていればOK:
* *.shp(本体)
* *.shx(インデックス)
* *.dbf(属性)
* *.prj(座標系:あると良い・ほぼ入ってます)
*.xml(メタデータ)はあって良い(無くても読み込みは可能)。

あなたの手元の例
* 海岸線フォルダ(C23-06_22_GML)
* C23-06_22-g_Coastline.shp / .shx / .dbf / .prj … 使用するのはこれ
* C23-06_22-g.xml, KS-META-*.xml … メタデータ(任意)
* 津波浸水フォルダ(A40-16_22_GML)
* A40-16_22.shp / .shx / .dbf / .prj … これを使う
* A40-16_22.xml, KS-META-*.xml … メタデータ(任意)

スクリプトに設定するパス(例)

COAST_SHP   = "data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp"
TSUNAMI_SHP = "data/tsunami_shizuoka/A40-16_22_GML/A40-16_22.shp"

あと
20250801_指定緊急避難場所一覧.CSV
の文字コードを調べる

file -I 20250801_指定緊急避難場所一覧.CSV
20250801_指定緊急避難場所一覧.CSV: text/csv; charset=unknown-8bit

となるので

brew install nkf uchardet

としたが

Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
To rerun under ARM use:
    arch -arm64 brew install ...
To install under x86_64, install Homebrew into /usr/local.

となる
久々で忘れていたけど
M1Mac の場合は

arch -arm64 brew install nkf uchardet

となる

uchardet 20250801_指定緊急避難場所一覧.CSV
SHIFT_JIS
 nkf -g 20250801_指定緊急避難場所一覧.CSV
CP932

このため

import pandas as pd
df = pd.read_csv("20250801_指定緊急避難場所一覧.CSV", encoding="cp932")

の文字コードはそのままにする

これらを元に

import pandas as pd
import geopandas as gpd
from shapely.geometry import Point
import osmnx as ox
import networkx as nx
import folium
import numpy as np
import os

# =========================
# 0) 入力(あなたの実ファイルに合わせて修正)
# =========================
COAST_SHP   = "data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp"  # C23=海岸線
TSUNAMI_SHP = "data/tsunami_shizuoka/A40-16_22_GML/A40-16_22.shp"                # A40=津波浸水想定
SHELTER_CSV = "data/20250801_指定緊急避難場所一覧.CSV"                            # cp932想定

OUT_GPKG = "outputs/shizuoka_hazard.gpkg"
os.makedirs(os.path.dirname(OUT_GPKG), exist_ok=True)

# 自宅の位置(WGS84)※必ずあなたの座標に置換(lat, lon)
home_wgs = (34.728, 137.978)  # 例: 袋井市周辺

# OSM道路グラフ取得範囲(自宅中心 半径[m])
GRAPH_RADIUS_M = 10000  # 10km程度で様子見。広げたければ 15000~20000


# =========================
# 1) データ読み込み・CRS整備
# =========================
# 海岸線(C23)/ 津波浸水想定(A40)をWGS84に
coast = gpd.read_file(COAST_SHP)
if coast.crs is None:
    raise ValueError("海岸線ShapefileにCRSがありません(.prjが同フォルダにあるか確認)")
coast = coast.to_crs(4326)

tsunami = gpd.read_file(TSUNAMI_SHP)
if tsunami.crs is None:
    raise ValueError("津波浸水想定ShapefileにCRSがありません(.prjが同フォルダにあるか確認)")
tsunami = tsunami.to_crs(4326)
tsunami_union = tsunami.unary_union  # 高速化用

# 避難所CSV(cp932想定)→ 可能な列名を自動検出して点に
df = pd.read_csv(SHELTER_CSV, encoding="cp932")
# 緯度・経度列の候補(大小・日本語をカバー)
lat_candidates = 
lon_candidates = 

if not lat_candidates or not lon_candidates:
    raise ValueError("CSV内に緯度/経度の列が見つかりません。列名を教えてください。")

lat_col = lat_candidates[0]
lon_col = lon_candidates[0]

# 数値に変換(欠損/文字混入対策)
df[lat_col] = pd.to_numeric(df[lat_col], errors="coerce")
df[lon_col] = pd.to_numeric(df[lon_col], errors="coerce")
df = df.dropna(subset=[lat_col, lon_col])

shelters = gpd.GeoDataFrame(
    df.copy(),
    geometry=gpd.points_from_xy(df[lon_col], df[lat_col], crs="EPSG:4326")
)

# 浸水域外の避難所のみを「安全」とする
safe_shelters = shelters.loc[~shelters.intersects(tsunami_union)].copy()


# =========================
# 2) 道路グラフ(OSMnx)
# =========================
# 自宅中心の徒歩グラフ(避難行動向け)。範囲広すぎると重いので半径で制限
G = ox.graph_from_point(home_wgs, dist=GRAPH_RADIUS_M, network_type="walk", simplify=True, retain_all=False)
nodes, edges = ox.graph_to_gdfs(G, nodes=True, edges=True)
# 以降WGS84で統一
if edges.crs is None:
    edges.set_crs(4326, inplace=True)
elif edges.crs.to_epsg() != 4326:
    edges = edges.to_crs(4326)

# 浸水域と交差する道路エッジを除去(形状は切らず、そのまま抜く)
bad = edges.intersects(tsunami_union)
edges_keep = edges.loc[~bad].copy()

# 使われるノードだけに絞る
used_node_ids = pd.unique(edges_keep[["u", "v"]].values.ravel())
nodes_keep = nodes.loc[nodes.index.isin(used_node_ids)].copy()

# サブグラフ再構築
G2 = ox.utils_graph.graph_from_gdfs(nodes_keep, edges_keep, graph_attrs=G.graph)

# =========================
# 3) 出発・目的地ノード
# =========================
home_point = Point(home_wgs[1], home_wgs[0])

# 目的地:安全な避難所のうち「自宅に最も近い」1つ(直線距離)
if len(safe_shelters) == 0:
    # もし全て浸水域なら、とりあえず最も近い避難所を使う(要検討)
    target_shelters = shelters.copy()
else:
    target_shelters = safe_shelters.copy()

# 距離計算はメートル系CRSで
METRIC_CRS = "EPSG:32654"  # 静岡周辺
tp = target_shelters.to_crs(METRIC_CRS)
hp = gpd.GeoSeries([home_point], crs=4326).to_crs(METRIC_CRS).iloc[0]
tp["__dist_m__"] = tp.geometry.distance(hp)
dest_pt = target_shelters.loc[tp["__dist_m__"].idxmin(), "geometry"]

# 近傍ノード
orig = ox.distance.nearest_nodes(G2, X=home_point.x, Y=home_point.y)
dest = ox.distance.nearest_nodes(G2, X=dest_pt.x, Y=dest_pt.y)

# =========================
# 4) 最短経路(浸水域エッジを除去済みグラフ)
# =========================
try:
    route = nx.shortest_path(G2, orig, dest, weight="length")
except nx.NetworkXNoPath:
    # 到達不能の場合は半径を増やす or 車道(network_type="drive")に切替など検討
    raise RuntimeError("安全な避難所へ到達するパスが見つかりません。半径を増やす/目的地を変更してください。")

# ルート形状(LineString)を作成
route_coords = [(G2.nodes[n]["x"], G2.nodes[n]["y"]) for n in route]
# GeoDataFrame化(WGS84)
route_gdf = gpd.GeoDataFrame(geometry=[gpd.GeoSeries([Point(xy) for xy in route_coords]).unary_union.convex_hull], crs=4326)
# ↑簡易化:見た目重視ならPolylineをFoliumへ直接渡す(下でやります)

# =========================
# 5) 出力(GeoPackage)& Folium 可視化
# =========================
# GPKGへ保存(必要なら既存を削除)
if os.path.exists(OUT_GPKG):
    os.remove(OUT_GPKG)

coast.to_file(OUT_GPKG, layer="coastline", driver="GPKG")
tsunami.to_file(OUT_GPKG, layer="tsunami_inundation", driver="GPKG")
shelters.to_file(OUT_GPKG, layer="shelters_all", driver="GPKG")
safe_shelters.to_file(OUT_GPKG, layer="shelters_safe", driver="GPKG")

# 走行可能エッジ(浸水交差なし)だけ保存
edges_keep.to_file(OUT_GPKG, layer="roads_safe", driver="GPKG")

# ルートはFolium用に直接線で描くので、GPKGは省略してもOK
# 保存したいなら下のようにLineStringを作って保存
from shapely.geometry import LineString
route_line = LineString(route_coords)
gpd.GeoDataFrame(geometry=[route_line], crs=4326).to_file(OUT_GPKG, layer="route", driver="GPKG")

print(f"✓ 出力: {OUT_GPKG}")

# Folium地図
m = folium.Map(location=[home_wgs[0], home_wgs[1]], zoom_start=12, control_scale=True)

# 津波浸水想定
folium.GeoJson(tsunami.__geo_interface__, name="津波浸水想定(A40)", tooltip=None).add_to(m)

# 海岸線
folium.GeoJson(coast.__geo_interface__, name="海岸線(C23)", tooltip=None).add_to(m)

# 避難所(安全/全体)
folium.GeoJson(safe_shelters.__geo_interface__, name="安全な避難所", 
               marker=folium.CircleMarker(radius=4),
               tooltip=folium.GeoJsonTooltip(fields=[:5])
               ).add_to(m)
folium.GeoJson(shelters.__geo_interface__, name="避難所(全体・灰)", 
               marker=folium.CircleMarker(radius=3, color="gray", fill=True),
               tooltip=folium.GeoJsonTooltip(fields=[:3])
               ).add_to(m)

# ルート線(G2ノード列から)
route_latlon = [(G2.nodes[n]["y"], G2.nodes[n]["x"]) for n in route]
folium.PolyLine(route_latlon, weight=5, opacity=0.9, tooltip="避難経路").add_to(m)

# 出発/目的地
folium.Marker(location=[home_wgs[0], home_wgs[1]], popup="現在地", icon=folium.Icon(color="green")).add_to(m)
folium.Marker(location=[dest_pt.y, dest_pt.x], popup="避難所", icon=folium.Icon(color="blue")).add_to(m)

folium.LayerControl().add_to(m)
m  # Jupyterならこれで表示。スクリプトなら m.save("evac.html")

としたが

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[2], line 33
     31 coast = gpd.read_file(COAST_SHP)
     32 if coast.crs is None:
---> 33     raise ValueError("海岸線ShapefileにCRSがありません(.prjが同フォルダにあるか確認)")
     34 coast = coast.to_crs(4326)
     36 tsunami = gpd.read_file(TSUNAMI_SHP)

ValueError: 海岸線ShapefileにCRSがありません(.prjが同フォルダにあるか確認)

対処としては
海岸線(C23)の .prj が無いため CRS が未設定になっています。
C23 の公式仕様は JGD2000(経緯度) です。つまり EPSG:4612 を与えればOK。

対処方法は
A40(津波浸水想定)は配布物に .prj が入っていることが多いので、そのまま読める想定です。データ仕様の説明はここ(CRSは配布年度によりJGD2000/2011ですが、多くは .prj に記載あり)

coast = gpd.read_file(COAST_SHP)
if coast.crs is None:
    # C23 海岸線は JGD2000 (経緯度) → EPSG:4612
    coast = coast.set_crs(epsg=4612)
coast = coast.to_crs(4326)  # Folium等で扱いやすいWGS84へ

もしくは
コマンドで WKT を出して .prj として保存

# EPSG:4612 のWKTを出力(どちらか)
gdalsrsinfo EPSG:4612 -o wkt > C23-06_22-g_Coastline.prj
# または
projinfo EPSG:4612 --wkt2=EPSG > C23-06_22-g_Coastline.prj

念のための確認ポイント
* coast.total_bounds を見て、経度 ~122–154、緯度 ~20–46 の範囲に収まっていれば経緯度(度)の座標と判断可。
* メタデータXML(C23-06_22-g.xml など)に「座標系: JGD2000 / (B,L)」の記述があります。国土数値情報
これで ValueError は解消できます。次に進めて、浸水域クリップや経路探索を回してみてください

GPTで
対処(最短)と代替(.prj を作ってしまう) どちらが良い? その根拠は?
と調べてみる

結論:.prj を作って“直す”方(恒久対処)がオススメ。
理由は下記のとおりです。
どちらが良い?(要点)
* .prj を作成(恒久対処)
* 一度直せば QGIS/GeoPandas/同僚PC すべてで自動認識。再発しない。
* 将来の再利用・共有・配布に強い(ミスの温床を潰せる)。
* 前提:正しいCRSが確定していること(C23=JGD2000)。国土数値情報
* コード内で set_crs(暫定対処)
* いま手元のスクリプトをすぐ動かすなら最短。
* ただし、毎回コード側で設定を忘れるリスク、他ツール(QGIS等)を使うたびに同じエラーが再発。
このC23「海岸線」は仕様上 JGD2000(緯度経度)= EPSG:4612。
一方、A40「津波浸水想定」は JGD2011(緯度経度) が明記されています(年度によるが少なくとも2020版でJGD2011)。
→ どのみち最終的に同一CRS(例:WGS84=EPSG:4326)へ統一してから解析・可視化します。

これを実行するためのコマンドをインストール

arch -arm64 brew install gdal proj

🧭 1. PROJ(座標変換ライブラリ)
概要
PROJ は、地理座標系(緯度・経度など)と投影座標系(メートル単位の平面座標など)を相互変換するためのオープンソースライブラリです。
* URL: https://proj.org/
* 開発元: OSGeo Foundation
* 最新バージョン例: PROJ 9.x(2025年現在)
主な機能
機能 説明
座標変換 緯度経度(WGS84など)↔ 平面直角座標(UTM、EPSG:2451など)の変換
測地計算 2点間距離、方位角などを地球楕円体上で計算
EPSG対応 EPSGコード(例: 4326, 6674, 2451など)を使って簡単に座標系を指定可能
datum変換 世界測地系(WGS84)↔ 日本測地系(Tokyo Datum)などの変換
WKT/WKT2対応 座標系定義をWKT形式で入出力できる
利用例(コマンドライン)

projinfo EPSG:4326

→ WGS84の詳細を表示します。

🌍 2. GDAL(Geospatial Data Abstraction Library)
概要
GDAL は、地理空間データ(ラスタ・ベクタ形式)を読み書き・変換するためのライブラリ群です。
* URL: https://gdal.org/
* 開発元: OSGeo Foundation
* Pythonから利用するときは import gdal または from osgeo import gdal として使用可能。
主な機能
分類 説明
ファイル形式サポート GeoTIFF, Shapefile, GPKG, KML, GML, CSV, NetCDF など300以上
座標変換 内部的にPROJを使用して座標系を変換
ベクタ操作 属性情報付きの地理データ(例: Shapefile)を読み書き
ラスタ操作 画像や地形データ(DEMなど)の切り出し、リサンプリング、投影変換
コマンドツール ogr2ogr, gdalinfo, gdalwarp, gdalsrsinfo など多機能CLIツールを提供
利用例

gdalinfo sample.tif

→ GeoTIFFファイルのメタデータ(座標系・範囲など)を表示。

ogr2ogr -f "GPKG" output.gpkg input.shp

→ ShapefileをGeoPackage形式に変換。

🧠 まとめ
項目 内容
PROJ 座標変換ライブラリ(EPSGコード、測地変換)
GDAL 地理空間データ入出力ライブラリ(ShapefileやGeoTIFFの変換)
arch -arm64 Apple SiliconでARMネイティブ実行を強制
主な用途 GeoPandas, Rasterio, QGIS, OSMnx, PyProjなどのPython地理ライブラリの基盤

インストール完了後

==> Running `brew cleanup gdal`...
Disable this behaviour by setting `HOMEBREW_NO_INSTALL_CLEANUP=1`.
Hide these hints with `HOMEBREW_NO_ENV_HINTS=1` (see `man brew`).
==> Running `brew cleanup proj`...
==> No outdated dependents to upgrade!

となるので
バージョンを確認

 gdalinfo --version

を実行するとGPTで書いてあったが

GDAL 3.11.4 "Eganville", released 2025/09/04

 projinfo --version
Unrecognized option: --version
usage: projinfo [-o formats] [-k crs|operation|datum|ensemble|ellipsoid] [--summary] [-q]
                ([--area name_or_code] | [--bbox west_long,south_lat,east_long,north_lat]) 
                [--spatial-test contains|intersects]
                [--crs-extent-use none|both|intersection|smallest]
                [--grid-check none|discard_missing|sort|known_available] 
                [--pivot-crs always|if_no_direct_transformation|never|{auth:code[,auth:code]*}]
                [--show-superseded] [--hide-ballpark] [--accuracy {accuracy}]
                [--allow-ellipsoidal-height-as-vertical-crs]
                [--boundcrs-to-wgs84]
                [--authority name]
                [--main-db-path path] [--aux-db-path path]*
                [--identify] [--3d]
                [--output-id AUTH:CODE]
                [--c-ify] [--single-line]
                --searchpaths | --remote-data |
                --list-crs [list-crs-filter] |
                --dump-db-structure [{object_definition} | {object_reference}] |
                {object_definition} | {object_reference} |
                (-s {srs_def} [--s_epoch {epoch}] -t {srs_def} [--t_epoch {epoch}]) |
                ({srs_def} {srs_def})

-o: formats is a comma separated combination of: all,default,PROJ,WKT_ALL,WKT2:2015,WKT2:2019,WKT1:GDAL,WKT1:ESRI,PROJJSON,SQL
    Except 'all' and 'default', other format can be preceded by '-' to disable them

list-crs-filter is a comma separated combination of: allow_deprecated,geodetic,geocentric,
geographic,geographic_2d,geographic_3d,vertical,projected,compound

{object_definition} might be a PROJ string, a WKT string, a AUTHORITY:CODE, or urn:ogc:def:OBJECT_TYPE:AUTHORITY::CODE

となる

正確には

proj          

を実行

Rel. 9.7.0, September 1st, 2025
usage: proj [-bdeEfiIlmorsStTvVwW [args]] [+opt[=arg] ...] [file ...]

これで準備ができたので
.prj を作成
海岸線の .shp と同じフォルダ(= data/coastline_shizuoka/C23-06_22_GML)で、同じベース名の .prj を作ればOKです。
(津波浸水想定 A40 側は既に A40-16_22.prj があるので不要)

とのことなので

cd data/coastline_shizuoka/C23-06_22_GML

次にコマンドの実行だが
提案されたコマンドは2つ

# どちらか一方でOK(ESRI形式のほうがShapefileと相性が良い)
gdalsrsinfo EPSG:4612 -o wkt_esri > C23-06_22-g_Coastline.prj

# または

projinfo EPSG:4612 --wkt2=EPSG > C23-06_22-g_Coastline.prj

どちらが良い?

結論:gdalsrsinfo -o wkt_esri を推奨です。
理由(短く)
* Shapefile は ESRI 由来なので、.prj は ESRI 方言(wkt_esri)が最も相性◎。
* 互換性が広い(ArcGIS/QGIS/古いツールでもズレにくい)。
* EPSG WKT2 でも動きますが、古いツールで軸順やデータム解釈の差がまれに出ます。

ということなので

gdalsrsinfo EPSG:4612 -o wkt_esri > C23-06_22-g_Coastline.prj

を実行

結果は

head -n 3 data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.prj

で確認

GEOGCS["GCS_JGD_2000",
DATUM["D_JGD_2000",

しかし

python - <<'PY'
import geopandas as gpd
gdf = gpd.read_file("data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp")
print(gdf.crs) # → EPSG:4612 と出ればOK
PY
None

となる

ベース名が1文字でも違う(拡張子以外が完全一致でない)
GDAL/FionaがESRI方言(wkt_esri)をうまく読めない環境
.prjは正しいが、別の場所の同名SHPを読んでいる/パス違い
まれに .prj はあるが内容が空/壊れている
が主な原因らしい

ls data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.*
data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.dbf
data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.prj
data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp
data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shx

次に

ogrinfo -so data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp C23-06_22-g_Coastline


OGRがSRSを認識しているか

ogrinfo -so data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp C23-06_22-g_Coastline
INFO: Open of `data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp'
      using driver `ESRI Shapefile' successful.

Layer name: C23-06_22-g_Coastline
Metadata:
  DBF_DATE_LAST_UPDATE=1941-11-24
Geometry: Line String
Feature Count: 1141
Extent: (137.484966, 34.572136) - (139.176559, 35.144928)
Layer SRS WKT:
(unknown)
C23_001: String (5.0)
C23_002: String (1.0)
C23_003: String (4.0)
C23_004: String (46.0)
C23_005: String (1.0)
C23_006: String (10.0)
C23_007: String (5.0)

これらにより
.prj を置いたのに GDAL が Layer SRS WKT: (unknown)。
これは その環境の GDAL/Fiona が WKT をうまく解釈できていない ケース

ogr2ogr -a_srs で“CRS付きの新ファイル”を作るのが一番おすすめです。
理由:
* その場しのぎではなく恒久対処(QGIS/GeoPandas/他PCでも確実に認識)。
* .prj の方言差や環境差に左右されにくい(今回まさに .prj を置いても読まれなかった)。
* 元データを壊さず安全に複製できる。

ということで
CRSを付与した“新しい”SHPを作成(EPSG:4612 = JGD2000)

cd data/coastline_shizuoka/C23-06_22_GML

で移動

ogr2ogr -a_srs EPSG:4612 C23_4612.shp C23-06_22-g_Coastline.shp

しかし

Warning 1: One or several characters couldn't be converted correctly from UTF-8 to ISO-8859-1.  This warning will not be emitted anymore.

となる

この警告は属性の文字エンコード(日本語)が
Shapefile の既定(ISO-8859-1)に合わず、
変換できない文字があったという意味で
幾何やCRS付与は完了しているが、属性が文字化けする可能性がある

解決策は
1) Shapefileのエンコーディングを指定して作り直す(手早い)
2) いっそ GeoPackage にする(おすすめ:今後楽)

どの方法が良いかを相談

コンセプトが

使用する用途のコンセプト また震源地から津波が到達するまでの時間と津波の高さを計算し GIS情報を使い避難するエリアを算出しルート案内できるようにしたい 家族の避難経路・地域防災マップをGraphDBで整理 避難所や重要連絡先も紐付け 使い方例: 「地震が来たら最寄りの避難所はどこ?」 「非常食の賞味期限が近いものは?」 など この用途で使うならどれを推奨する?

✅ あなたの用途の要件
* 精度:震源→沿岸までの到達時間・波高推定の入力に使うので、誤差が大きすぎると危険。
* 範囲:主に日本周辺で十分。全球は必須ではない。
* 更新頻度:将来的に OSM/防災機関の最新データと連携したい。
* GraphDB連携:避難所・道路・避難経路・浸水域をノード/リレーションで管理。
* 利用イメージ:
* 「地震が来たら最寄りの避難所はどこ?」 → 避難所ノード+道路グラフ
* 「非常食の賞味期限が近いものは?」 → 在庫管理ノード
* 「津波到達までに何分ある?」 → 震源ノード→海岸ノードのコスト距離

✅ データセットごとの特徴
1. 国土数値情報「海岸線データ」
* 日本限定。行政データとして信頼性が高い。
* GML/Shapefile 提供。
* 避難計画(住民向け防災マップ)に最も適する。
➡ 推奨(基準データにする)
2. OSM Coastlines / Land polygons
* 更新頻度が高い(週次〜月次)。
* 最新の人工改変(埋立地・護岸)も比較的反映。
* 避難経路や実際の生活圏との整合性が良い。
➡ 補助データ(現況把握用)
3. Natural Earth
* 全球対応、軽量。
* 精度は粗い(1:10mでも数百 m〜km の誤差)。
* 可視化や概念実証には便利。
➡ プロトタイプ用のみ
4. GSHHG
* 全球対応、高解像度あり。
* ファイルが大きく、取り回しに手間。
* 学術研究向き。
➡ 専門シミュレーション以外では過剰

✅ 推奨構成(防災マップ+GraphDB向け)
1. 海岸線:
* 基本 → 国土数値情報(海岸線)
* 最新の現況補正 → OSM Coastlines
2. 標高/地形:
* 陸域 DEM → 国土地理院 DEM / ALOS / SRTM
* 海域 DEM → GEBCO
3. 避難所・道路:
* 避難所 → 自治体オープンデータ(CSV/GeoJSON)
* 道路 → OSMnx で抽出
4. GraphDBに格納:
* ノード:震源・海岸・浸水域・避難所・家庭・在庫
* リレーション:到達時間・避難経路・所要時間・備蓄品管理

✅ まとめ
ご提示の用途(家族避難+地域防災+GraphDB管理)なら:
* **国土数値情報(海岸線)**をメイン
* OSM Coastlinesで現況更新
* DEM(陸域+海域)+道路+避難所を組み合わせ
* GraphDBでノード/リレーションを整理して「質問に答えられる防災知識ベース」を構築
なら、どの方法を推奨する?

結論:公的データ優先の“ハイブリッド型”を強く推奨します。
「浸水範囲は公式シミュ結果(A40)」「到達時刻・高さは公的速報を取り込む」「経路はOSM+浸水域回避」で組むのが、安全・現実的・拡張容易です。
推奨アーキテクチャ(段階導入)
フェーズ1:静岡・オフライン基盤(最小成功)
* 海岸線:KSJ C23(CRS整備済み)
* 津波浸水想定:KSJ A40(静岡)を絶対基準に採用
* 道路:OSMnx(walk/drive)取得 → A40と交差するエッジを除去
* 避難所:自治体CSV(cp932)→ GeoDataFrame(WGS84)
* 結果:
* 「自宅 → 最寄り“安全な”避難所」の最短経路
* 到達圏(isochrone):歩行/車速で10分・20分…を事前計算
* 保存:1つの GeoPackage(coastline / tsunami / roads_safe / shelters_safe / routes / isochrones)
ここまでで、「地震が来たら最寄りの避難所は?」に即答できます。
高度な波高計算はまだ入れず、安全サイドの浸水域回避を徹底。
フェーズ2:リアルタイム連携(到達“時刻”の提示)
* 到達時刻・津波高の“情報源”は公的速報(気象庁の津波警報・到達予想)。
* ワークフロー:
1. 速報の沿岸予報区ごとの到達見込み時刻/高さを取得
2. 県内の該当海岸セグメントへ付与(C23を海岸線ノードに分割)
3. 自宅の最短海岸ノードまでの**“海→陸の到達時刻”を速報値**で表示
4. ルート案内UIに「残り時間(ETA)」を明示(保守的に短めに表示)
物理モデルでの即時計算は難度・不確実性が高いので、公式速報を真に受ける方が安全かつ信用性◎。
どうしても“目安”を補うなら、深海平均水深での線形速波
c
=
g
h
c=gh による暫定下限ETAを併記(保守的に短く)。
フェーズ3:GraphDB連携(質問に答える防災知識ベース)
* ノード:Home / Shelter / RoadNode|RoadEdge / TsunamiPolygon(A40) / CoastNode / Item(備蓄) / Contact
* リレーション:ROUTE_TO(time,length) / INTERSECTS / AVOIDS / NEAREST / EXPIRING_SOON
* QA例:
* 「津波到達まで何分?」→ 最近接 CoastNode の公式ETA(フェーズ2)
* 「最短でどの避難所?」→ ROUTE_TO の最小 time を返す
* 「非常食の賞味期限近い?」→ EXPIRING_SOON <= 14d の Item 列挙 この方式を推す理由 * 安全性:浸水範囲は公式A40で担保。到達時刻・高さも公的速報準拠。独自計算の誤差リスクを避ける。 * 実装容易 & 拡張性:いまのPython+OSMnxコードの発展で実装可能。将来は別県や別ハザード(洪水・高潮)も流用可。 * 運用:GeoPackageに集約→QGIS/GeoPandas両対応。GraphDBで家族向けの質問応答が作りやすい。 実装メモ(最短でやるなら) * まずはフェーズ1を静岡で完成:A40で道路遮断 → 最短経路 & isochrone 出力。 * フェーズ2は速報取り込みのI/Oだけ追加し、海岸ノードにETA属性を付与。UIで「残り時間」を表示。 * すべて保守的(安全側)に倒す:ETAは短め、通行可能性に不確実があれば通れない扱い。 要約:
あなたの要求(精度・安全・拡張性)に最も合うのは、A40×OSM×公的速報のハイブリッド。
先に静岡でフェーズ1を完成させ、問題なければ**速報連携(フェーズ2)→GraphDB化(フェーズ3)**へ進めましょう。 となる つまり、今回なら 1) Shapefileのエンコーディングを指定して作り直す(手早い) 2) いっそ GeoPackage にする(おすすめ:今後楽) はどちらにする? それとも別の方法をとる? 結論:② GeoPackage(GPKG)に統一するのがベストです。 理由:文字化け・.prj問題・属性名10文字制限・2GB制限など Shapefileの弱点を一掃でき、今後の拡張(複数レイヤ管理、QGIS/GeoPandas/GraphDB連携)が安定します やることは 出力は一つの outputs/shizuoka_hazard.gpkg にレイヤ分けして格納 らしいが # 1) 海岸線(C23):CRS未付与なので付けてから WGS84 へ投影して GPKG へ を実行する前に気になるので確認しておく 現在 # 1) 海岸線(C23):CRS未付与なので付けてから WGS84 へ投影して GPKG へ[shell] ogr2ogr -a_srs EPSG:4612 -t_srs EPSG:4326 \ -f GPKG outputs/shizuoka_hazard.gpkg \ data/coastline_shizuoka/C23-06_22_GML/C23-06_22-g_Coastline.shp \ -nln coastline [/shell] # 2) 津波浸水想定(A40):.prj あり → そのCRSから WGS84 へ投影して同じ GPKG に追加[shell] ogr2ogr -t_srs EPSG:4326 \ -f GPKG -update outputs/shizuoka_hazard.gpkg \ data/tsunami_shizuoka/A40-16_22_GML/A40-16_22.shp \ -nln tsunami_inundation[/shell] を実行する前のフォルダ構成として [shell] data/coastline_shizuoka/C23-06_22_GML C23-06_22-g.xml C23_4612.dbf C23-06_22-g_Coastline.dbf C23_4612.prj C23-06_22-g_Coastline.prj C23_4612.shp C23-06_22-g_Coastline.shp C23_4612.shx C23-06_22-g_Coastline.shx KS-META-C23-06_22-g.xml[/shell] となっているが .prj ファイルは一度削除した方が良いか? 結論:消さなくてOKです。 大事なのは「どのSHPを入力に使うか」と「source SRS を明示して出力する」こと。GPKGを作るときに正しく指定すれば、フォルダ内に .prj が残っていても問題ありません 既にCRS付きコピーを作ってあるので、それを入力にして WGS84 で GPKG に出力すればOK 先に outputsフォルダの作成が必要なので [shell] cd -[/shell] で移動しておく ~/aw10s/FamilySafetyMap へ移動して [shell] mkdir -p outputs[/shell] でフォルダ作成し[shell] ogr2ogr -t_srs EPSG:4326 \ -f GPKG outputs/shizuoka_hazard.gpkg \ data/coastline_shizuoka/C23-06_22_GML/C23_4612.shp \ -nln coastline[/shell] で 既にCRS付きコピーを作ってあるので、それを入力にして WGS84 で GPKG に出力。 動作確認[shell] ogrinfo -so outputs/shizuoka_hazard.gpkg coastline INFO: Open of `outputs/shizuoka_hazard.gpkg' using driver `GPKG' successful. Layer name: coastline Metadata: DBF_DATE_LAST_UPDATE=2025-10-10 Geometry: Line String Feature Count: 1141 Extent: (137.484966, 34.572136) - (139.176559, 35.144928) Layer SRS WKT: GEOGCRS["WGS 84", ENSEMBLE["World Geodetic System 1984 ensemble", MEMBER["World Geodetic System 1984 (Transit)"], MEMBER["World Geodetic System 1984 (G730)"], MEMBER["World Geodetic System 1984 (G873)"], MEMBER["World Geodetic System 1984 (G1150)"], MEMBER["World Geodetic System 1984 (G1674)"], MEMBER["World Geodetic System 1984 (G1762)"], MEMBER["World Geodetic System 1984 (G2139)"], MEMBER["World Geodetic System 1984 (G2296)"], ELLIPSOID["WGS 84",6378137,298.257223563, LENGTHUNIT["metre",1]], ENSEMBLEACCURACY[2.0]], PRIMEM["Greenwich",0, ANGLEUNIT["degree",0.0174532925199433]], CS[ellipsoidal,2], AXIS["geodetic latitude (Lat)",north, ORDER[1], ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], ANGLEUNIT["degree",0.0174532925199433]], USAGE[ SCOPE["Horizontal component of 3D system."], AREA["World."], BBOX[-90,-180,90,180]], ID["EPSG",4326]] Data axis to CRS axis mapping: 2,1 FID Column = fid Geometry Column = geom C23_001: String (5.0) C23_002: String (1.0) C23_003: String (4.0) C23_004: String (46.0) C23_005: String (1.0) C23_006: String (10.0) C23_007: String (5.0) ogrinfo -so outputs/shizuoka_hazard.gpkg tsunami_inundation INFO: Open of `outputs/shizuoka_hazard.gpkg' using driver `GPKG' successful. ERROR 1: Couldn't fetch requested layer tsunami_inundation. [/shell] となった tsunami_inundation レイヤが GPKGに存在していない いま入っているレイヤ一覧を確認[shell] ogrinfo outputs/shizuoka_hazard.gpkg INFO: Open of `outputs/shizuoka_hazard.gpkg' using driver `GPKG' successful. 1: coastline (Line String) [/shell] A40 のソースCRSを確認[shell] ogrinfo -so data/tsunami_shizuoka/A40-16_22_GML/A40-16_22.shp A40-16_22 INFO: Open of `data/tsunami_shizuoka/A40-16_22_GML/A40-16_22.shp' using driver `ESRI Shapefile' successful. Layer name: A40-16_22 Metadata: DBF_DATE_LAST_UPDATE=2016-12-08 Geometry: Polygon Feature Count: 113272 Extent: (137.483132, 34.594813) - (139.176599, 35.163526) Layer SRS WKT: GEOGCRS["JGD2011", DATUM["Japanese Geodetic Datum 2011", ELLIPSOID["GRS 1980",6378137,298.257222101, LENGTHUNIT["metre",1]]], PRIMEM["Greenwich",0, ANGLEUNIT["degree",0.0174532925199433]], CS[ellipsoidal,2], AXIS["geodetic latitude (Lat)",north, ORDER[1], ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], ANGLEUNIT["degree",0.0174532925199433]], USAGE[ SCOPE["Horizontal component of 3D system."], AREA["Japan - onshore and offshore."], BBOX[17.09,122.38,46.05,157.65]], ID["EPSG",6668]] Data axis to CRS axis mapping: 2,1 A40_001: String (10.0) A40_002: String (2.0) A40_003: String (40.0) [/shell] この結果から A40 はちゃんと EPSG:6668 (JGD2011) で読めています。あとは GPKG に “追記” できればOK 進捗表示・無効ジオメトリを自動修復・マルチ化・空間インデックス作成する [shell] ogr2ogr -progress -t_srs EPSG:4326 \ -makevalid -nlt PROMOTE_TO_MULTI \ -f GPKG -update -lco SPATIAL_INDEX=YES -lco GEOMETRY_NAME=geom \ outputs/shizuoka_hazard.gpkg \ data/tsunami_shizuoka/A40-16_22_GML/A40-16_22.shp \ -nln tsunami_inundation [/shell] を実行 補足(なぜこのオプション?) * -update:既存 GPKG に 追記 * -nln tsunami_inundation:レイヤ名を固定 * -t_srs EPSG:4326:WGS84 に統一(Folium/QGISで扱いやすい) * -makevalid:自己交差などの 無効ポリゴンを自動修復(A40は件数多く、稀に必要) * -nlt PROMOTE_TO_MULTI:MultiPolygon に正規化(後段の処理が安定) * -lco SPATIAL_INDEX=YES:高速化のための 空間インデックス 付与 次に動作確認 [shell] ogrinfo -so outputs/shizuoka_hazard.gpkg tsunami_inundation INFO: Open of `outputs/shizuoka_hazard.gpkg' using driver `GPKG' successful. Layer name: tsunami_inundation Metadata: DBF_DATE_LAST_UPDATE=2016-12-08 Geometry: Multi Polygon Feature Count: 113272 Extent: (137.483133, 34.594813) - (139.176599, 35.163526) Layer SRS WKT: GEOGCRS["WGS 84", ENSEMBLE["World Geodetic System 1984 ensemble", MEMBER["World Geodetic System 1984 (Transit)"], MEMBER["World Geodetic System 1984 (G730)"], MEMBER["World Geodetic System 1984 (G873)"], MEMBER["World Geodetic System 1984 (G1150)"], MEMBER["World Geodetic System 1984 (G1674)"], MEMBER["World Geodetic System 1984 (G1762)"], MEMBER["World Geodetic System 1984 (G2139)"], MEMBER["World Geodetic System 1984 (G2296)"], ELLIPSOID["WGS 84",6378137,298.257223563, LENGTHUNIT["metre",1]], ENSEMBLEACCURACY[2.0]], PRIMEM["Greenwich",0, ANGLEUNIT["degree",0.0174532925199433]], CS[ellipsoidal,2], AXIS["geodetic latitude (Lat)",north, ORDER[1], ANGLEUNIT["degree",0.0174532925199433]], AXIS["geodetic longitude (Lon)",east, ORDER[2], ANGLEUNIT["degree",0.0174532925199433]], USAGE[ SCOPE["Horizontal component of 3D system."], AREA["World."], BBOX[-90,-180,90,180]], ID["EPSG",4326]] Data axis to CRS axis mapping: 2,1 FID Column = fid Geometry Column = geom A40_001: String (10.0) A40_002: String (2.0) A40_003: String (40.0) [/shell] これだけだとわからないのでGPTで解説を依頼 これは `ogrinfo -so` コマンド(GDALのツール)で、 GeoPackage ファイル(`outputs/shizuoka_hazard.gpkg`)のレイヤー `tsunami_inundation`(津波浸水想定区域)に関する**メタデータと構造情報**を表示した結果です。 以下に各項目の意味を解説します👇 --- ## 🗂 基本情報 | 項目 | 内容 | | ------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | **Open of ... using driver 'GPKG' successful** | GeoPackage 形式(`.gpkg`)のファイルを正常に開けたことを示します。GDALドライバ `GPKG`(GeoPackageフォーマット)を使用しています。 | | **Layer name: tsunami_inundation** | レイヤー名(地理データの層の名前)。ここでは津波浸水区域を示すレイヤーです。 | | **Geometry: Multi Polygon** | 地物のジオメトリ(形状)が「複数ポリゴン」で構成されていることを示します。津波の浸水区域など、面(エリア)を表現するために使われます。 | | **Feature Count: 113272** | 含まれる地物(フィーチャー)の総数。ここでは 113,272 個の津波浸水ポリゴンが含まれています。 | | **Extent: (137.483133, 34.594813) - (139.176599, 35.163526)** | データがカバーしている範囲の外接矩形(最小緯度経度と最大緯度経度)。静岡県の東西南北の境界座標です。 | | **Layer SRS WKT** | 空間参照系(Spatial Reference System)の詳細情報。ここでは世界測地系(WGS84 / EPSG:4326)です。 | --- ## 🌍 空間参照系(SRS: Spatial Reference System) ``` GEOGCRS["WGS 84", ... ID["EPSG",4326]] ``` これは座標系の定義で、簡単に言うと: * **EPSG:4326** → 世界測地系(WGS 84)。 GPSなどで使われる緯度経度座標系。 * **CS[ellipsoidal,2]** → 2次元の楕円体座標系(緯度・経度)。 * **PRIMEM["Greenwich",0]** → 基準子午線はグリニッジ子午線。 * **ANGLEUNIT["degree",...]** → 度単位で表されている。 つまり、データは**緯度経度(度単位)**で表現されており、地図投影(メートル単位の平面座標変換)はまだ行われていません。 --- ## 📊 属性カラム(テーブル構造) | カラム名 | データ型 | 意味(推定) | | ----------- | ------------- | -------------------- | | **A40_001** | String (10.0) | コードやID(市区町村や地域コードなど) | | **A40_002** | String (2.0) | 区分や種別(例:津波の想定区分など) | | **A40_003** | String (40.0) | 名称(例:「静岡県○○市△△地区」など) | これらのフィールド名は国土数値情報(国交省が公開する津波浸水想定データ)と一致しています。 具体的な意味はデータ仕様書により異なりますが、概ね以下の通りです: | フィールド名 | 意味(国交省仕様例) | | ------- | --------------------- | | A40_001 | 行政コード(市区町村コード) | | A40_002 | 津波区分(1:想定, 2:最大クラスなど) | | A40_003 | 地域名・想定名などのラベル | --- ## 🧭 Data axis to CRS axis mapping: 2,1 これは軸の並び順を示します。 * 通常は **(緯度, 経度)** の順ですが、 * このデータでは **(経度, 緯度)** の順に格納されていることを意味します。 GDALで処理する際、軸の順序に注意が必要です(例:FoliumやGeoPandasで描画する際に位置がズレる場合があります)。 --- ## 🔍 FID / Geometry Column | 項目 | 内容 | | -------------------------- | -------------------------- | | **FID Column = fid** | 各地物を識別する一意のID(Feature ID)。 | | **Geometry Column = geom** | ポリゴン形状が格納されているカラム名。 | --- ## 🧩 まとめ このGeoPackageは、 **「静岡県内の津波浸水想定区域」**をWGS84座標で格納したもので、 113,272件のポリゴンが `geom` フィールドに保存されています。 主な使い方の例: [shell] import geopandas as gpd gdf = gpd.read_file("outputs/shizuoka_hazard.gpkg", layer="tsunami_inundation") print(gdf.head()) ``` 出力例: | fid | A40_001 | A40_002 | A40_003 | geometry | | --- | ------- | ------- | ------- | ----------------- | | 1 | 22210 | 1 | 静岡市駿河区 | MULTIPOLYGON(...) | [/shell] ご希望であれば、このデータを **Folium地図上に可視化するコード例** や **GeoPandasでの属性抽出・座標変換(EPSG:4326 → EPSG:6677など)** の実例も示せます

海岸線データの取得

海岸線データの取得

import numpy as np
import geopandas as gpd
import rasterio
from rasterio import features
from shapely.geometry import Point
from skimage.graph import route_through_array  # 1対1のとき
import osmnx as ox
import networkx as nx
import folium

# --------------------
# 0) 入力
# --------------------
epicenter_wgs = (35.5, 142.0)  # 例: 緯度, 経度(仮)
gebco_tif = "data/gebco_bathymetry.tif"   # 海底地形(m, 海は正の深さ or 負の標高のことも)
dem_tif   = "data/dem_coast.tif"          # 陸域標高(m)
coastline = gpd.read_file("data/coastline.gpkg")  # 海岸線
shelters  = gpd.read_file("data/shelters.geojson")# 避難所点データ(WGS84想定)

# 便利関数:WGS84→ラスタ座標系へ
def to_crs_point(lat, lon, crs_epsg):
    g = gpd.GeoSeries([Point(lon, lat)], crs=4326).to_crs(crs_epsg)
    p = g.iloc[0]
    return p.y, p.x  # (Y, X) in projected CRS

# --------------------
# 1) 海上到達時間ラスタ(簡易)
# --------------------
with rasterio.open(gebco_tif) as src:
    bathy = src.read(1).astype("float32")
    prof  = src.profile
    # 海域の水深(m)に統一(負の標高なら反転)
    depth = np.where(bathy < 0, -bathy, bathy)  # 例:負値を深さに
    depth = np.where(depth<=0, np.nan, depth)

    g = 9.81
    v = np.sqrt(g * depth)  # m/s
    cost = 1.0 / v          # s/m(セル通過時間はこれ×セルサイズ)

    # 震源セル
    epic_y, epic_x = to_crs_point(epicenter_wgs[0], epicenter_wgs[1], src.crs.to_epsg())
    row, col = src.index(epic_x, epic_y)

    # coast マスク(海→陸境界の近傍)を後で使うためにベクタ→ラスタ化しておくのも可

# ここではデモとして「震源→任意の海岸点」1対1のrouteで travel time を出す例。
# 実際は multi-source 最短時間(fast marching/多点Dijkstra)が望ましい。
# skimage.graphの route_through_array はコスト配列にセルサイズを掛けて合計。
# セルサイズ(m):
pix_m = (prof["transform"][0])  # x解像度(m/px)。投影ラスタ前提
# 到達時間ラスタの厳密生成はここでは割愛(本格的には多源最短経路/コスト距離を実装)

# --------------------
# 2) 浸水域(閾値で簡易)
# --------------------
with rasterio.open(dem_tif) as demsrc:
    dem = demsrc.read(1).astype("float32")
    # 仮の沿岸波高 H(m)を設定(現実は断層モデルや公表想定を用いる)
    H0 = 1.0      # 沖合初期波高 1 m(例)
    h0 = 3000.0   # 沖合水深 3000 m(例)
    h_coast = 10.0# 沿岸水深(例)
    H_coast = H0*((h0/h_coast)**0.25)

    tide = 0.5    # 満潮加算(例)
    safety_margin = 0.5
    flood_threshold = H_coast + tide + safety_margin  # m

    # 海から連結する低地 = 浸水候補
    flood_mask = (dem <= flood_threshold).astype(np.uint8)

# flood_mask をポリゴン化(例)
shapes = features.shapes(flood_mask, transform=demsrc.transform)
flood_polys = [sh for sh, val in shapes if val == 1]
flood = gpd.GeoDataFrame(geometry=gpd.GeoSeries.from_iterable(flood_polys), crs=demsrc.crs)

# 海から連結していない内陸窪地は除外(簡易には海ポリゴンとの接触でフィルタ)
# coastlineを同一CRSへ
coastline_proj = coastline.to_crs(flood.crs)
flood = flood[flood.intersects(coastline_proj.unary_union)].buffer(0)

# --------------------
# 3) 安全エリア&避難所(浸水域の外)
# --------------------
shelters_proj = shelters.to_crs(flood.crs)
safe_shelters = shelters_proj[~shelters_proj.intersects(flood.unary_union)]

# --------------------
# 4) 避難ルート(浸水域の道路を除外)
# --------------------
place = "Sumida-ku, Tokyo, Japan"
G = ox.graph_from_place(place, network_type="walk")  # 徒歩網の方が避難向き

nodes, edges = ox.graph_to_gdfs(G)
edges_proj = edges.to_crs(flood.crs)

# 浸水と交差するエッジを除外
bad = edges_proj.intersects(flood.unary_union)
edges_keep = edges_proj.loc[~bad]

# サブグラフ再構築
G2 = ox.utils_graph.graph_from_gdfs(nodes.to_crs(edges_keep.crs), edges_keep)

# 出発地(例:現在地)と最寄り安全避難所
current_wgs = (35.71, 139.81)  # 例
cur_pt = gpd.GeoSeries([Point(current_wgs[1], current_wgs[0])], crs=4326).to_crs(edges_keep.crs).iloc[0]
dest_pt = safe_shelters.geometry.iloc[0] if len(safe_shelters) else shelters_proj.geometry.iloc[0]

orig = ox.distance.nearest_nodes(G2, X=cur_pt.x, Y=cur_pt.y)
dest = ox.distance.nearest_nodes(G2, X=dest_pt.x, Y=dest_pt.y)

route = nx.shortest_path(G2, orig, dest, weight="length")

# --------------------
# 5) Foliumで可視化
# --------------------
center = (current_wgs[0], current_wgs[1])
m = folium.Map(location=center, zoom_start=13)

# 浸水域
flood_wgs = flood.to_crs(4326)
folium.GeoJson(flood_wgs.__geo_interface__, name="Flood (simple)").add_to(m)

# ルート
route_latlon = [(G2.nodes[n]["y"], G2.nodes[n]["x"]) for n in route]
folium.PolyLine(route_latlon, color="red", weight=5, opacity=0.9, tooltip="Evacuation Route").add_to(m)

# 出発・目的地
folium.Marker(location=[cur_pt.y, cur_pt.x], popup="Start", icon=folium.Icon(color="green")).add_to(m)
folium.Marker(location=[dest_pt.to_crs(4326).y, dest_pt.to_crs(4326).x], popup="Shelter", icon=folium.Icon(color="blue")).add_to(m)

# 避難所レイヤ
folium.GeoJson(safe_shelters.to_crs(4326).__geo_interface__, name="Safe shelters",
               tooltip=folium.GeoJsonTooltip(fields=[:4])
               ).add_to(m)

folium.LayerControl().add_to(m)

# Jupyterなら m だけで表示
m  # もしくは m.save("evac.html")

を実行しても

DataSourceError: data/coastline.gpkg: No such file or directory 

となるため
データの取得先を調べる

data/coastline.gpkg は自分で用意する必要があります。用途(全球/日本のみ、精度、更新頻度)に応じて、下のどれかをダウンロード→GeoPackage に変換すれば OK です。
入手先(おすすめ順)
1. Natural Earth – Coastline(手軽・軽量)
1:10m/50m/110m の海岸線 Shapefile。全球で数MB、試作には十分です。Natural Earth Data+2Natural Earth Data+2
2. OSM Coastlines / Land polygons(高頻度更新・実用)
OpenStreetMap から抽出された最新の海岸線。WGS84 / Web Mercator の Shapefile がそのまま落とせます。OpenStreetMap Data+1
3. GSHHG(高解像度・全球)
解像度別(c/l/i/h/f)で海岸線を配布。Shapefile もあり。厳密な可視化に向く一方、古い部分もあるので用途に注意。ngdc.noaa.gov+2ngdc.noaa.gov+2
4. 国土数値情報「海岸線データ」(日本限定・行政用途向け属性つき)
都道府県ごとに海岸線(線)を提供。JPGIS/GML と Shapefile が選べます。nlftp.mlit.go.jp+2geospatial.jp+2

使うときの注意
* CRS を統一:あなたの dem_tif / gebco_tif / 道路網(OSMnx)と同じ座標系に coastline を揃えてください。
例:coastline = coastline.to_crs(flood.crs)(すでにコードでやっている通り)
* 粒度の選択:
* 試作:Natural Earth(軽い)
* 実運用・最新形状:OSM Coastlines
* 日本限定・行政属性重視:国土数値情報
* ライン or ポリゴン:浸水域との連結判定には、**海岸線(ライン)**だけでなく 陸/水ポリゴンがあると便利です(OSM の Land/Water polygons 参照)。

種類が多いためGPTで候補を割り出す

使用する用途のコンセプト また震源地から津波が到達するまでの時間と津波の高さを計算し GIS情報を使い避難するエリアを算出しルート案内できるようにしたい 家族の避難経路・地域防災マップをGraphDBで整理 避難所や重要連絡先も紐付け 使い方例: 「地震が来たら最寄りの避難所はどこ?」 「非常食の賞味期限が近いものは?」 など この用途で使うならどれを推奨する?

✅ あなたの用途の要件
* 精度:震源→沿岸までの到達時間・波高推定の入力に使うので、誤差が大きすぎると危険。
* 範囲:主に日本周辺で十分。全球は必須ではない。
* 更新頻度:将来的に OSM/防災機関の最新データと連携したい。
* GraphDB連携:避難所・道路・避難経路・浸水域をノード/リレーションで管理。
* 利用イメージ:
* 「地震が来たら最寄りの避難所はどこ?」 → 避難所ノード+道路グラフ
* 「非常食の賞味期限が近いものは?」 → 在庫管理ノード
* 「津波到達までに何分ある?」 → 震源ノード→海岸ノードのコスト距離

✅ データセットごとの特徴
1. 国土数値情報「海岸線データ」
* 日本限定。行政データとして信頼性が高い。
* GML/Shapefile 提供。
* 避難計画(住民向け防災マップ)に最も適する。
➡ 推奨(基準データにする)
2. OSM Coastlines / Land polygons
* 更新頻度が高い(週次〜月次)。
* 最新の人工改変(埋立地・護岸)も比較的反映。
* 避難経路や実際の生活圏との整合性が良い。
➡ 補助データ(現況把握用)
3. Natural Earth
* 全球対応、軽量。
* 精度は粗い(1:10mでも数百 m〜km の誤差)。
* 可視化や概念実証には便利。
➡ プロトタイプ用のみ
4. GSHHG
* 全球対応、高解像度あり。
* ファイルが大きく、取り回しに手間。
* 学術研究向き。
➡ 専門シミュレーション以外では過剰

✅ 推奨構成(防災マップ+GraphDB向け)
1. 海岸線:
* 基本 → 国土数値情報(海岸線)
* 最新の現況補正 → OSM Coastlines
2. 標高/地形:
* 陸域 DEM → 国土地理院 DEM / ALOS / SRTM
* 海域 DEM → GEBCO
3. 避難所・道路:
* 避難所 → 自治体オープンデータ(CSV/GeoJSON)
* 道路 → OSMnx で抽出
4. GraphDBに格納:
* ノード:震源・海岸・浸水域・避難所・家庭・在庫
* リレーション:到達時間・避難経路・所要時間・備蓄品管理

✅ まとめ
ご提示の用途(家族避難+地域防災+GraphDB管理)なら:
* **国土数値情報(海岸線)**をメイン
* OSM Coastlinesで現況更新
* DEM(陸域+海域)+道路+避難所を組み合わせ
* GraphDBでノード/リレーションを整理して「質問に答えられる防災知識ベース」を構築

震源地から津波が到達するまでの時間と津波の高さを計算

震源地から津波が到達するまでの時間と津波の高さを計算

✅ 津波の到達時間の基本式
津波は浅水波近似で速度が次の式で表されます:
v=√g⋅h

v:津波の速度 (m/s)
g:重力加速度 (9.81 m/s²)
h:海の水深 (m)


水深 4000 m → 速度 ≈ 200 m/s (720 km/h)
水深 100 m → 速度 ≈ 31 m/s (110 km/h)

✅ 津波の高さ(沿岸での増幅)
震源での初期波高
H
0
H0 は断層変位や地殻変動から推定されます。
沿岸での津波高さ
H
H は「グリーンの法則」によって水深比に応じて増幅します:

h0 :沖合の水深
h:沿岸の水深

つまり、水深が浅くなるにつれて波高は増大します。

✅ Pythonでの計算イメージ

import math

def tsunami_travel_time(distance_km, depth_m):
    g = 9.81
    v = math.sqrt(g * depth_m)  # m/s
    t_sec = (distance_km*1000) / v
    return t_sec / 60  # 分

def tsunami_height(H0, h0, h):
    return H0 * ((h0 / h) ** 0.25)

# 例: 震源から200 km, 平均水深 3000 m
t = tsunami_travel_time(200, 3000)
print(f"到達時間 ≈ {t:.1f} 分")

# 例: 初期波高 1m, 沖合水深 3000 m, 沿岸水深 10 m
H = tsunami_height(1.0, 3000, 10)
print(f"沿岸波高 ≈ {H:.2f} m")

✅ データが必要になる部分
* 震源位置と震源から沿岸までの距離 → ジオデータ(緯度経度)を使って測る
* 海底地形(バソメトリー)データ → GEBCO や NOAA の水深データが必要
* 初期波高 → 地震断層モデルから計算(研究所や気象庁の速報値を利用するのが実務的)

✅ まとめ
* 津波高さは「水深比の1/4乗則(グリーンの法則)」で沿岸増幅を近似
* 実務では GEBCO の海底地形データを組み合わせて地図上で計算する


震源地から津波が到達するまでの時間と津波の高さを計算し GIS情報を使い避難するエリアを算出しルート案内できるようにしたい

精密な津波シミュレータではなく、GIS+簡易物理モデルで「到達時間」「想定浸水域」「安全エリア」「避難ルート」を一気通貫で出す手順と最小コード


※簡易近似。自治体ハザードマップがあればそれを優先
1. 想定浸水域の作成(簡易版)
陸域DEMから標高閾値(例:満潮+推定波高+α)以下の連結領域を抽出し、海から連結する部分を浸水ポリゴンとする。
(精密な遡上計算は専門コードが必要。ここでは避難計画用の予防的ゾーニング)
2. 安全エリアの抽出
浸水ポリゴン外かつ標高>閾値(例:5–10m以上)&避難所候補のある場所を安全エリアとする。
3. 避難ルート
OSMnxで道路グラフを取得し、浸水ポリゴン内のエッジを除外して、現在地→最寄り安全避難所までの最短路(距離 or 時間)を算出。Foliumで地図化。

必要なパッケージ

pip install geopandas rasterio shapely numpy scikit-image osmnx folium contextily networkx

でインストール

ミニマル実装(雛形)
ファイルパスはあなたの環境に合わせて置き換え。座標系は**投影座標(m単位)**に揃えるのがコツ(例:対象地域のUTM帯、または EPSG:3857)。日本なら JGD2011 の平面直角系でもOK。

import numpy as np
import geopandas as gpd
import rasterio
from rasterio import features
from shapely.geometry import Point
from skimage.graph import route_through_array  # 1対1のとき
import osmnx as ox
import networkx as nx
import folium

# --------------------
# 0) 入力
# --------------------
epicenter_wgs = (35.5, 142.0)  # 例: 緯度, 経度(仮)
gebco_tif = "data/gebco_bathymetry.tif"   # 海底地形(m, 海は正の深さ or 負の標高のことも)
dem_tif   = "data/dem_coast.tif"          # 陸域標高(m)
coastline = gpd.read_file("data/coastline.gpkg")  # 海岸線
shelters  = gpd.read_file("data/shelters.geojson")# 避難所点データ(WGS84想定)

# 便利関数:WGS84→ラスタ座標系へ
def to_crs_point(lat, lon, crs_epsg):
    g = gpd.GeoSeries([Point(lon, lat)], crs=4326).to_crs(crs_epsg)
    p = g.iloc[0]
    return p.y, p.x  # (Y, X) in projected CRS

# --------------------
# 1) 海上到達時間ラスタ(簡易)
# --------------------
with rasterio.open(gebco_tif) as src:
    bathy = src.read(1).astype("float32")
    prof  = src.profile
    # 海域の水深(m)に統一(負の標高なら反転)
    depth = np.where(bathy < 0, -bathy, bathy)  # 例:負値を深さに
    depth = np.where(depth<=0, np.nan, depth)

    g = 9.81
    v = np.sqrt(g * depth)  # m/s
    cost = 1.0 / v          # s/m(セル通過時間はこれ×セルサイズ)

    # 震源セル
    epic_y, epic_x = to_crs_point(epicenter_wgs[0], epicenter_wgs[1], src.crs.to_epsg())
    row, col = src.index(epic_x, epic_y)

    # coast マスク(海→陸境界の近傍)を後で使うためにベクタ→ラスタ化しておくのも可

# ここではデモとして「震源→任意の海岸点」1対1のrouteで travel time を出す例。
# 実際は multi-source 最短時間(fast marching/多点Dijkstra)が望ましい。
# skimage.graphの route_through_array はコスト配列にセルサイズを掛けて合計。
# セルサイズ(m):
pix_m = (prof["transform"][0])  # x解像度(m/px)。投影ラスタ前提
# 到達時間ラスタの厳密生成はここでは割愛(本格的には多源最短経路/コスト距離を実装)

# --------------------
# 2) 浸水域(閾値で簡易)
# --------------------
with rasterio.open(dem_tif) as demsrc:
    dem = demsrc.read(1).astype("float32")
    # 仮の沿岸波高 H(m)を設定(現実は断層モデルや公表想定を用いる)
    H0 = 1.0      # 沖合初期波高 1 m(例)
    h0 = 3000.0   # 沖合水深 3000 m(例)
    h_coast = 10.0# 沿岸水深(例)
    H_coast = H0*((h0/h_coast)**0.25)

    tide = 0.5    # 満潮加算(例)
    safety_margin = 0.5
    flood_threshold = H_coast + tide + safety_margin  # m

    # 海から連結する低地 = 浸水候補
    flood_mask = (dem <= flood_threshold).astype(np.uint8)

# flood_mask をポリゴン化(例)
shapes = features.shapes(flood_mask, transform=demsrc.transform)
flood_polys = [sh for sh, val in shapes if val == 1]
flood = gpd.GeoDataFrame(geometry=gpd.GeoSeries.from_iterable(flood_polys), crs=demsrc.crs)

# 海から連結していない内陸窪地は除外(簡易には海ポリゴンとの接触でフィルタ)
# coastlineを同一CRSへ
coastline_proj = coastline.to_crs(flood.crs)
flood = flood[flood.intersects(coastline_proj.unary_union)].buffer(0)

# --------------------
# 3) 安全エリア&避難所(浸水域の外)
# --------------------
shelters_proj = shelters.to_crs(flood.crs)
safe_shelters = shelters_proj[~shelters_proj.intersects(flood.unary_union)]

# --------------------
# 4) 避難ルート(浸水域の道路を除外)
# --------------------
place = "Sumida-ku, Tokyo, Japan"
G = ox.graph_from_place(place, network_type="walk")  # 徒歩網の方が避難向き

nodes, edges = ox.graph_to_gdfs(G)
edges_proj = edges.to_crs(flood.crs)

# 浸水と交差するエッジを除外
bad = edges_proj.intersects(flood.unary_union)
edges_keep = edges_proj.loc[~bad]

# サブグラフ再構築
G2 = ox.utils_graph.graph_from_gdfs(nodes.to_crs(edges_keep.crs), edges_keep)

# 出発地(例:現在地)と最寄り安全避難所
current_wgs = (35.71, 139.81)  # 例
cur_pt = gpd.GeoSeries([Point(current_wgs[1], current_wgs[0])], crs=4326).to_crs(edges_keep.crs).iloc[0]
dest_pt = safe_shelters.geometry.iloc[0] if len(safe_shelters) else shelters_proj.geometry.iloc[0]

orig = ox.distance.nearest_nodes(G2, X=cur_pt.x, Y=cur_pt.y)
dest = ox.distance.nearest_nodes(G2, X=dest_pt.x, Y=dest_pt.y)

route = nx.shortest_path(G2, orig, dest, weight="length")

# --------------------
# 5) Foliumで可視化
# --------------------
center = (current_wgs[0], current_wgs[1])
m = folium.Map(location=center, zoom_start=13)

# 浸水域
flood_wgs = flood.to_crs(4326)
folium.GeoJson(flood_wgs.__geo_interface__, name="Flood (simple)").add_to(m)

# ルート
route_latlon = [(G2.nodes[n]["y"], G2.nodes[n]["x"]) for n in route]
folium.PolyLine(route_latlon, color="red", weight=5, opacity=0.9, tooltip="Evacuation Route").add_to(m)

# 出発・目的地
folium.Marker(location=[cur_pt.y, cur_pt.x], popup="Start", icon=folium.Icon(color="green")).add_to(m)
folium.Marker(location=[dest_pt.to_crs(4326).y, dest_pt.to_crs(4326).x], popup="Shelter", icon=folium.Icon(color="blue")).add_to(m)

# 避難所レイヤ
folium.GeoJson(safe_shelters.to_crs(4326).__geo_interface__, name="Safe shelters",
               tooltip=folium.GeoJsonTooltip(fields=[:4])
               ).add_to(m)

folium.LayerControl().add_to(m)

# Jupyterなら m だけで表示
m  # もしくは m.save("evac.html")

実装のコツ
* CRSを徹底:ラスタ・ベクタ・OSMのCRSを揃える(距離・面積は投影座標)
* 閾値は保守的に:不確実性を考慮し安全側に(潮位・護岸・地形・内水氾濫は別論点)
* 道路グラフのカット:浸水ポリゴンだけでなく河川・橋梁も個別判定できると尚良
* 到達時間:本気でやるなら海上は1/vのコスト面で多源最短時間、陸上は時々刻々の浸水到達時刻 vs. 歩行速度で**到達可能圏(isochrone)**を比較

重要な注意(精度・安全)
* ここで示したのは教育・訓練用の簡易推定です。実運用や避難計画は、自治体のハザードマップ・気象庁/JMA・国研のモデル結果を最優先してください。
* グリーンの法則や低地抽出は大まかな上限見積に有効ですが、局所地形(湾形状、護岸、河口、運河)で大きな差が出ます。

次の拡張
海上到達時間:ラスタ全域での多源Dijkstra / Fast Marching(skfmm等)で全海岸の到達時刻マップを作る
公式ハザードデータ(津波浸水想定、指定緊急避難場所)との連携

とりあえずコードを jupyter で実行してみる

OSMxを使い最短経路の算出

OSMxを使い最短経路の算出

東京スカイツリーから
江戸東京博物館への最短経路を算出する

まずはスカイツリーと江戸東京博物館の座標をセットする

skytree = (35.7100,139.8180)
museum = (35.6963,139.7967)

次に一番近い node つまり交差点を取得

始点はスカイツリーなので

start = ox.get_nearest_node(G,skytree)

としたがエラー

--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[15], line 1 ----> 1 start = ox.get_nearest_node(G,skytree) AttributeError: module 'osmnx' has no attribute 'get_nearest_node'

これもバージョンの違いが原因

OSMnx 2.x では廃止され、ox.distance サブモジュールに移動
引数は (X=経度, Y=緯度) の順番で渡す必要があります
普通の Point(lon, lat) と同じ並び

start = ox.distance.nearest_nodes(G, X=skytree[1], Y=skytree[0])

とすればOK

同様に終点も

end = ox.distance.nearest_nodes(G,museum[1],museum[0])

次に最短経路

shortest_path = ox.shortest_path(G,start,end)

Foliumで表示できないので調べた

plot_route_folium
https://github.com/gboeing/osmnx/issues/1252
によれば

release (currently 1.9.4), then run your code. The latest v1 release will remain compatible with the v1 API, but any deprecated functionality you're using will issue a FutureWarning with simple guidance to make it v2 compatible.
Yes, the folium module was deprecated with a warning for removal back in 2023, and finally removed in v2.0.0. The good news: interactive web mapping with folium remains easy to do with OSMnx in ~2 lines of code! See this example in the Examples Gallery for a demonstration.

となっていて
foliumモジュールは2023年に削除の警告とともに非推奨となり、最終的にv2.0.0で削除されました。

とのこと

https://github.com/gboeing/osmnx-examples/blob/main/notebooks/11-interactive-web-mapping.ipynb
のサンプルが参考になりそう

OSMnx 2.0.6 には Folium 専用関数は無い → 自分で PolyLine を追加すればOK

再度GPTでコード生成

route = nx.shortest_path(G, orig, dest, weight="length")

というように
weight=”length”)
があるので調べた

✅ weight の意味
networkx.shortest_path の weight 引数は、**「どのエッジ属性を最短経路計算に使うか」**を指定するものです。
OSMnx で作成した G(道路グラフ)には、各エッジ(道路の区間)に様々な属性があります:
* “length” : 区間の長さ(メートル単位) ← デフォルトでよく使う
* “travel_time” : 区間の推定走行時間(秒単位)※ ox.add_edge_speeds / ox.add_edge_travel_times を実行した場合のみ
* その他、highway(道路種別)や lanes(車線数)など

✅ 例
1. 最短距離ルート(距離を最小化)

route = nx.shortest_path(G, orig, dest, weight="length")

2. 最短時間ルート(所要時間を最小化)
まず速度と所要時間をエッジに付与してから:

import osmnx as ox

G = ox.add_edge_speeds(G)        # 各道路に推定速度 (km/h) を追加
G = ox.add_edge_travel_times(G)  # 各道路に travel_time (秒) を追加

route = nx.shortest_path(G, orig, dest, weight="travel_time")

✅ まとめ
* weight=”length” → 「最短距離ルート」
* weight=”travel_time” → 「最短時間ルート」
* 他のエッジ属性を指定すれば、それに基づいた経路探索ができる

シェープファイルへの書き出し

シェープファイルへの書き出し

今回は作成した world を書き出す

これは GeodataFlameになっていれば簡単にできる

保存するときにはto_file を使う

シェープファイルで保存するなら

world.to_file(driver='ESRI Shapefile',filename='test_shape_world.shp')

というように
driverへ ESRI Shapefileを指定すればいい

でも

/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 328239523 of field POP_EST of feature 4 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 270625568 of field POP_EST of feature 8 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 144373535 of field POP_EST of feature 18 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 127575529 of field POP_EST of feature 27 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 211049527 of field POP_EST of feature 29 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 200963599 of field POP_EST of feature 56 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 1366417754 of field POP_EST of feature 98 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 163046161 of field POP_EST of feature 99 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 216565318 of field POP_EST of feature 102 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 1397715000 of field POP_EST of feature 139 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 108116615 of field POP_EST of feature 147 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 126264931 of field POP_EST of feature 155 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 100388073 of field POP_EST of feature 163 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(
/Users/snowpool/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pyogrio/raw.py:723: RuntimeWarning: Value 112078730 of field POP_EST of feature 165 not successfully written. Possibly due to too larger number with respect to field width
  ogr_write(

となる

GPTによれば
併せて知っておくと良い Shapefile の制約
* フィールド名は最大 10 文字(長い列名は切られる)
* 文字列の最大長、数値の幅と小数点以下桁を持つ
* 64bit 整数を正式には持てない
* 複数のファイル(.shp/.shx/.dbf …)が必要

警告は Shapefile のフィールド幅不足。
ベストは GeoPackage/GeoJSON へ保存。
Shapefile が必須なら layer_options で幅指定を。

これは Shapefile(.shp)側の制約で数値フィールドの桁数が足りないために出る警告です。
Shapefile は属性を dBase(DBF) で持ちますが、各数値フィールドには「幅(桁数)と小数桁」を設定する必要があり、デフォルト推定だと POP_EST のような 10桁超え(例: 1,306,370,000) が収まりきらずに “not successfully written / too large for field width” になります。

Shapefile は古く、制限が多いです。GeoPackageやGeoJSONなら桁数制限に悩まされません。

このためGeoJSONでj保存する

world.to_file(driver='GeoJSON',filename='test_shape_world.geojson')

driverにGeoJSON ファイル拡張子を .geojsonにすればOK

GeoDataFlame の集計

GeoDataFlame の集計

これは dissolve を使う

これを使い地理データの集計を行う

# world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowers'))
# cities = gpd.read_file(gpd.datasets.get_path('naturalearth_cities'))
import geopandas as gpd
import requests, zipfile, io

# 世界地図(国境)
url_world = "https://naturalearth.s3.amazonaws.com/110m_cultural/ne_110m_admin_0_countries.zip"
r = requests.get(url_world)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("naturalearth_data")
world = gpd.read_file("naturalearth_data/ne_110m_admin_0_countries.shp")

# 都市データ
url_cities = "https://naturalearth.s3.amazonaws.com/110m_cultural/ne_110m_populated_places.zip"
r = requests.get(url_cities)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("naturalearth_data")
cities = gpd.read_file("naturalearth_data/ne_110m_populated_places.shp")

print(world.head())
print(cities.head())

で世界地理情報の取得

国名はADMINになっているので
日本の情報を取得するのなら

world[world['ADMIN']=='Japan']

とすれば

	featurecla	scalerank	LABELRANK	SOVEREIGNT	SOV_A3	ADM0_DIF	LEVEL	TYPE	TLC	ADMIN	...	FCLASS_TR	FCLASS_ID	FCLASS_PL	FCLASS_GR	FCLASS_IT	FCLASS_NL	FCLASS_SE	FCLASS_BD	FCLASS_UA	geometry
155	Admin-0 country	1	2	Japan	JPN	0	2	Sovereign country	1	Japan	...	None	None	None	None	None	None	None	None	None	MULTIPOLYGON (((141.8846 39.18086, 140.95949 3...
world[world['ADMIN']=='Japan'].plot()

で日本地図の表示

この世界データは国ごとの情報になっている

これを国ではなく大陸ごとに変えたい
この時に位置情報などを取り扱うには dissolve を使う

その前に人口が出てないので調べた

「人口情報が出てこない」のは、表示されていないだけの可能性が高い
Natural Earth の属性は列数が多く、print(df.head()) だと途中で省略される

# 国ごとの推定人口
print(world[['ADMIN','ISO_A3','POP_EST']].head())

# 都市の人口(大きい順に上位10件)
print(cities[['NAME','ADM0NAME','POP_MAX','POP_MIN']].sort_values('POP_MAX', ascending=False).head(10))

とすると

                         ADMIN ISO_A3      POP_EST
0                         Fiji    FJI     889953.0
1  United Republic of Tanzania    TZA   58005463.0
2               Western Sahara    ESH     603253.0
3                       Canada    CAN   37589262.0
4     United States of America    USA  328239523.0
             NAME                  ADM0NAME   POP_MAX   POP_MIN
233         Tokyo                     Japan  35676000   8336599
218      New York  United States of America  19040000   8008278
224   Mexico City                    Mexico  19028000  10811002
234        Mumbai                     India  18978000  12691836
239     São Paulo                    Brazil  18845000  10021295
232      Shanghai                     China  14987000  14608512
237       Kolkata                     India  14787000   4631392
171         Dhaka                Bangladesh  12797394   7000940
210  Buenos Aires                 Argentina  12795000  10929146
216   Los Angeles  United States of America  12500000   3694820

というように表示された

なので

japan = world[world['ADMIN'] == 'Japan']
print(japan[['ADMIN','ISO_A3','POP_EST']])

とすれば

     ADMIN ISO_A3      POP_EST
155  Japan    JPN  126264931.0

というように表示された

Natural Earth の Admin-0 Countries データには continent というカラムがあり

continent の意味
* 各国・地域が属している 大陸名 を示す属性です。
* 値の例:
* “Asia”(日本、中国、インドなど)
* “Europe”(フランス、ドイツなど)
* “Africa”
* “North America”
* “South America”
* “Oceania”
* “Seven seas (open ocean)”(公海などの海洋エリア)
* “Antarctica”

ということで大陸名を調べようと

japan = world[world['ADMIN'] == 'Japan']
print(japan[['ADMIN','continent']])

としたが

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[53], line 2
      1 japan = world[world['ADMIN'] == 'Japan']
----> 2 print(japan[['ADMIN','continent']])

File ~/.pyenv/versions/3.11.0/lib/python3.11/site-packages/geopandas/geodataframe.py:1896, in GeoDataFrame.__getitem__(self, key)
   1890 def __getitem__(self, key):
   1891     """
   1892     If the result is a column containing only 'geometry', return a
   1893     GeoSeries. If it's a DataFrame with any columns of GeometryDtype,
   1894     return a GeoDataFrame.
   1895     """
-> 1896     result = super().__getitem__(key)
   1897     # Custom logic to avoid waiting for pandas GH51895
   1898     # result is not geometry dtype for multi-indexes
   1899     if (
   1900         pd.api.types.is_scalar(key)
   1901         and key == ""
   (...)   1904         and not is_geometry_type(result)
   1905     ):

File ~/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pandas/core/frame.py:4108, in DataFrame.__getitem__(self, key)
   4106     if is_iterator(key):
   4107         key = list(key)
-> 4108     indexer = self.columns._get_indexer_strict(key, "columns")[1]
   4110 # take() does not accept boolean indexers
   4111 if getattr(indexer, "dtype", None) == bool:

File ~/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pandas/core/indexes/base.py:6200, in Index._get_indexer_strict(self, key, axis_name)
   6197 else:
   6198     keyarr, indexer, new_indexer = self._reindex_non_unique(keyarr)
-> 6200 self._raise_if_missing(keyarr, indexer, axis_name)
   6202 keyarr = self.take(indexer)
   6203 if isinstance(key, Index):
   6204     # GH 42790 - Preserve name from an Index

File ~/.pyenv/versions/3.11.0/lib/python3.11/site-packages/pandas/core/indexes/base.py:6252, in Index._raise_if_missing(self, key, indexer, axis_name)
   6249     raise KeyError(f"None of [{key}] are in the [{axis_name}]")
   6251 not_found = list(ensure_index(key)[missing_mask.nonzero()[0]].unique())
-> 6252 raise KeyError(f"{not_found} not in index")

KeyError: "['continent'] not in index"

となる
どうやら変更されている

print(world.columns.tolist())

の結果は

['featurecla', 'scalerank', 'LABELRANK', 'SOVEREIGNT', 'SOV_A3', 'ADM0_DIF', 'LEVEL', 'TYPE', 'TLC', 'ADMIN', 'ADM0_A3', 'GEOU_DIF', 'GEOUNIT', 'GU_A3', 'SU_DIF', 'SUBUNIT', 'SU_A3', 'BRK_DIFF', 'NAME', 'NAME_LONG', 'BRK_A3', 'BRK_NAME', 'BRK_GROUP', 'ABBREV', 'POSTAL', 'FORMAL_EN', 'FORMAL_FR', 'NAME_CIAWF', 'NOTE_ADM0', 'NOTE_BRK', 'NAME_SORT', 'NAME_ALT', 'MAPCOLOR7', 'MAPCOLOR8', 'MAPCOLOR9', 'MAPCOLOR13', 'POP_EST', 'POP_RANK', 'POP_YEAR', 'GDP_MD', 'GDP_YEAR', 'ECONOMY', 'INCOME_GRP', 'FIPS_10', 'ISO_A2', 'ISO_A2_EH', 'ISO_A3', 'ISO_A3_EH', 'ISO_N3', 'ISO_N3_EH', 'UN_A3', 'WB_A2', 'WB_A3', 'WOE_ID', 'WOE_ID_EH', 'WOE_NOTE', 'ADM0_ISO', 'ADM0_DIFF', 'ADM0_TLC', 'ADM0_A3_US', 'ADM0_A3_FR', 'ADM0_A3_RU', 'ADM0_A3_ES', 'ADM0_A3_CN', 'ADM0_A3_TW', 'ADM0_A3_IN', 'ADM0_A3_NP', 'ADM0_A3_PK', 'ADM0_A3_DE', 'ADM0_A3_GB', 'ADM0_A3_BR', 'ADM0_A3_IL', 'ADM0_A3_PS', 'ADM0_A3_SA', 'ADM0_A3_EG', 'ADM0_A3_MA', 'ADM0_A3_PT', 'ADM0_A3_AR', 'ADM0_A3_JP', 'ADM0_A3_KO', 'ADM0_A3_VN', 'ADM0_A3_TR', 'ADM0_A3_ID', 'ADM0_A3_PL', 'ADM0_A3_GR', 'ADM0_A3_IT', 'ADM0_A3_NL', 'ADM0_A3_SE', 'ADM0_A3_BD', 'ADM0_A3_UA', 'ADM0_A3_UN', 'ADM0_A3_WB', 'CONTINENT', 'REGION_UN', 'SUBREGION', 'REGION_WB', 'NAME_LEN', 'LONG_LEN', 'ABBREV_LEN', 'TINY', 'HOMEPART', 'MIN_ZOOM', 'MIN_LABEL', 'MAX_LABEL', 'LABEL_X', 'LABEL_Y', 'NE_ID', 'WIKIDATAID', 'NAME_AR', 'NAME_BN', 'NAME_DE', 'NAME_EN', 'NAME_ES', 'NAME_FA', 'NAME_FR', 'NAME_EL', 'NAME_HE', 'NAME_HI', 'NAME_HU', 'NAME_ID', 'NAME_IT', 'NAME_JA', 'NAME_KO', 'NAME_NL', 'NAME_PL', 'NAME_PT', 'NAME_RU', 'NAME_SV', 'NAME_TR', 'NAME_UK', 'NAME_UR', 'NAME_VI', 'NAME_ZH', 'NAME_ZHT', 'FCLASS_ISO', 'TLC_DIFF', 'FCLASS_TLC', 'FCLASS_US', 'FCLASS_FR', 'FCLASS_RU', 'FCLASS_ES', 'FCLASS_CN', 'FCLASS_TW', 'FCLASS_IN', 'FCLASS_NP', 'FCLASS_PK', 'FCLASS_DE', 'FCLASS_GB', 'FCLASS_BR', 'FCLASS_IL', 'FCLASS_PS', 'FCLASS_SA', 'FCLASS_EG', 'FCLASS_MA', 'FCLASS_PT', 'FCLASS_AR', 'FCLASS_JP', 'FCLASS_KO', 'FCLASS_VN', 'FCLASS_TR', 'FCLASS_ID', 'FCLASS_PL', 'FCLASS_GR', 'FCLASS_IT', 'FCLASS_NL', 'FCLASS_SE', 'FCLASS_BD', 'FCLASS_UA', 'geometry']
The history saving thread hit an unexpected error (OperationalError('unable to open database file')).History will not be written to the database.

カラム一覧を見ると、このデータでは
* 大陸は CONTINENT(全部大文字)
* 地域は REGION_UN、SUBREGION

これを元に

# 日本だけ絞り込み
japan = world[world["ADMIN"] == "Japan"]

# 大陸名を見る(大文字の CONTINENT)
print(japan[["ADMIN", "CONTINENT"]])

# 代替として地域区分を見る
print(japan[["ADMIN", "REGION_UN", "SUBREGION"]])

とすれば

  ADMIN CONTINENT
155  Japan      Asia
     ADMIN REGION_UN     SUBREGION
155  Japan      Asia  Eastern Asia

となる

これで世界の大陸ごとに分けることができそうなので
大陸列に対して dissolve で集計する

集計方法は
aggfuncで指定する
今回は sum

continents = world.dissolve(by='CONTINENT',aggfunc='sum')
continents

とすると

geometry	featurecla	scalerank	LABELRANK	SOVEREIGNT	SOV_A3	ADM0_DIF	LEVEL	TYPE	TLC	ADMIN	ADM0_A3	GEOU_DIF	GEOUNIT	GU_A3	SU_DIF	SUBUNIT	SU_A3	BRK_DIFF	NAME	NAME_LONG	BRK_A3	BRK_NAME	BRK_GROUP	ABBREV	POSTAL	FORMAL_EN	FORMAL_FR	NAME_CIAWF	NOTE_ADM0	NOTE_BRK	NAME_SORT	NAME_ALT	MAPCOLOR7	MAPCOLOR8	MAPCOLOR9	MAPCOLOR13	POP_EST	POP_RANK	POP_YEAR	GDP_MD	GDP_YEAR	ECONOMY	INCOME_GRP	FIPS_10	ISO_A2	ISO_A2_EH	ISO_A3	ISO_A3_EH	ISO_N3	ISO_N3_EH	UN_A3	WB_A2	WB_A3	WOE_ID	WOE_ID_EH	WOE_NOTE	ADM0_ISO	ADM0_DIFF	ADM0_TLC	ADM0_A3_US	ADM0_A3_FR	ADM0_A3_RU	ADM0_A3_ES	ADM0_A3_CN	ADM0_A3_TW	ADM0_A3_IN	ADM0_A3_NP	ADM0_A3_PK	ADM0_A3_DE	ADM0_A3_GB	ADM0_A3_BR	ADM0_A3_IL	ADM0_A3_PS	ADM0_A3_SA	ADM0_A3_EG	ADM0_A3_MA	ADM0_A3_PT	ADM0_A3_AR	ADM0_A3_JP	ADM0_A3_KO	ADM0_A3_VN	ADM0_A3_TR	ADM0_A3_ID	ADM0_A3_PL	ADM0_A3_GR	ADM0_A3_IT	ADM0_A3_NL	ADM0_A3_SE	ADM0_A3_BD	ADM0_A3_UA	ADM0_A3_UN	ADM0_A3_WB	REGION_UN	SUBREGION	REGION_WB	NAME_LEN	LONG_LEN	ABBREV_LEN	TINY	HOMEPART	MIN_ZOOM	MIN_LABEL	MAX_LABEL	LABEL_X	LABEL_Y	NE_ID	WIKIDATAID	NAME_AR	NAME_BN	NAME_DE	NAME_EN	NAME_ES	NAME_FA	NAME_FR	NAME_EL	NAME_HE	NAME_HI	NAME_HU	NAME_ID	NAME_IT	NAME_JA	NAME_KO	NAME_NL	NAME_PL	NAME_PT	NAME_RU	NAME_SV	NAME_TR	NAME_UK	NAME_UR	NAME_VI	NAME_ZH	NAME_ZHT	FCLASS_ISO	TLC_DIFF	FCLASS_TLC	FCLASS_US	FCLASS_FR	FCLASS_RU	FCLASS_ES	FCLASS_CN	FCLASS_TW	FCLASS_IN	FCLASS_NP	FCLASS_PK	FCLASS_DE	FCLASS_GB	FCLASS_BR	FCLASS_IL	FCLASS_PS	FCLASS_SA	FCLASS_EG	FCLASS_MA	FCLASS_PT	FCLASS_AR	FCLASS_JP	FCLASS_KO	FCLASS_VN	FCLASS_TR	FCLASS_ID	FCLASS_PL	FCLASS_GR	FCLASS_IT	FCLASS_NL	FCLASS_SE	FCLASS_BD	FCLASS_UA	
CONTINENT																																																																																																																																																																								
Africa	MULTIPOLYGON (((-11.43878 6.78592, -11.70819 6.8601, -12.4281 7.26294, -12.94905 7.79865, -13.12403 8.16395, -13.24655 8.90305, -13.68515 9.49474, -14.07404 9.88617, -14.33008 10.01572, -14.5797 10.21447, -14.69323 10.6563, -14.83955 10.87657, -15.13031 11.04041, -15.66418 11.45847, -16.08521 11.52459, -16.31479 11.80651, -16.30895 11.9587, -16.61384 12.17091, -16.67745 12.38485, -16.84152 13.15139, -16.71373 13.59496, -17.12611 14.37352, -17.62504 14.72954, -17.18517 14.91948, -16.70071 15.62153, -16.4631 16.13504, -16.54971 16.67389, -16.27055 17.16696, -16.14635 18.10848, -16.25688 19.09672, -16.37765 19.59382, -16.27784 20.09252, -16.53632 20.56787, -17.06342 20.99975, -17.02043 21.42231, -16.97325 21.88574, -16.58914 22.15823, -16.26192 22.67934, -16.32641 23.01777, -15.98261 23.72336, -15.426 24.35913, -15.08933 24.52026, -14.82465 25.10353, -14.80093 25.63626, -14.43994 26.25442, -13.7738 26.61889, -13.13994 27.64015, -13.12161 27.65415, -12.61884 28.03819, -11.68892 28.14864, -10.90096 28.83214, -10.39959 29.09859, -9.56481 29.93357, -9.81472 31.17774, -9.43479 32.0381, -9.30069 32.56468, -8.65748 33.24025, -7.65418 33.69706, -6.91254 34.11048, -6.24434 35.14587, -5.92999 35.75999, -5.19386 35.75518, -4.59101 35.33071, -3.64006 35.39986, -2.60431 35.17909, -2.16991 35.1684, -1.2086 35.71485, -0.12745 35.88866, 0.50388 36.30127, 1.46692 36.60565, 3.1617 36.7839, 4.81576 36.86504, 5.32012 36.71652, 6.26182 37.11066, 7.33038 37.11838, 7.73708 36.88571, 8.42096 36.94643, 9.50999 37.34999, 10.21 37.23, 10.18065 36.72404, 11.02887 37.0921, 11.10003 36.9, 10.6 36.41, 10.59329 35.94744, 10.93952 35.69898, 10.80785 34.83351, 10.14959 34.33077, 10.33966 33.78574, 10.85684 33.76874, 11.1085 33.29334, 11.48879 33.137, 12.66331 32.79278, 13.08326 32.87882, 13.91868 32.71196, 15.24563 32.26508, 15.71394 31.37626, 16.61162 31.18218, 18.02109 30.76357, 19.08641 30.26639, 19.57404 30.52582, 20.05335 30.98576, 19.82033 31.75179, 20.13397 32.2382, 20.85452 32.7068, 21.54298 32.8432, 22.89576 32.63858, 23.2368 32.19149, 23.60913 32.18726, 23.9275 32.01667, 24.92114 31.89936, 25.16482 31.56915, 26.49533 31.58568, 27.45762 31.32126, 28.45048 31.02577, 28.91353 30.87005, 29.68342 31.18686, 30.09503 31.4734, 30.97693 31.55586, 31.68796 31.4296, 31.96041 30.9336, 32.19247 31.26034, 32.99392 31.02407, 33.7734 30.96746, 34.26543 31.21936, 34.26544 31.21936, 34.82324 29.76108, 34.9226 29.50133, 34.64174 29.09942, 34.42655 28.34399, 34.15451 27.8233, 33.92136 27.6487, 33.58811 27.97136, 33.13676 28.41765, 32.42323 29.85108, 32.32046 29.76043, 32.73482 28.70523, 33.34876 27.69989, 34.10455 26.14227, 34.47387 25.59856, 34.79507 25.03375, 35.69241 23.92671, 35.49372 23.75237, 35.52598 23.10244, 36.69069 22.20485, 36.86623 22, 37.18872 21.01885, 36.96941 20.83744, 37.1147 19.80796, 37.48179 18.61409, 37.86276 18.36786, 38.41009 17.99831, 38.99062 16.84063, 39.26611 15.92272, 39.81429 15.43565, 41.17927 14.49108, 41.73495 13.92104, 42.27683 13.34399, 42.58958 13.00042, 43.08123 12.69964, 43.31785 12.39015, 43.28638 11.97493, 42.71587 11.73564, 43.1453 11.46204, 43.47066 11.27771, 43.66667 10.86417, 44.1178 10.44554, 44.61426 10.44221, 45.55694 10.69803, 46.6454 10.81655, 47.52566 11.12723, 48.0216 11.19306, 48.37878 11.37548, 48.94821 11.41062, 48.9482 11.41062, 49.26776 11.43033, 49.72862 11.5789, 50.25878 11.67957, 50.73202 12.0219, 51.1112 12.02464, 51.13387 11.74815, 51.04153 11.16651, 51.04531 10.6409, 50.83418 10.27972, 50.55239 9.19874, 50.07092 8.08173, 49.4527 6.80466, 48.59455 5.33911, 47.74079 4.2194, 46.56476 2.85529, 45.56399 2.04576, 44.06815 1.05283, 43.13597 0.2922, 42.04157 -0.91916, 41.81095 -1.44647, 41.58513 -1.68325, 40.88477 -2.08255, 40.63785 -2.49979, 40.26304 -2.57309, 40.12119 -3.27768, 39.80006 -3.68116, 39.60489 -4.34653, 39.20222 -4.67677, 38.74054 -5.90895, 38.79977 -6.47566, 39.44 -6.84, 39.47 -7.1, 39.19469 -7.7039, 39.25203 -8.00781, 39.18652 -8.48551, 39.53574 -9.11237, 39.9496 -10.0984, 40.31659 -10.3171, 40.31659 -10.3171, 40.47839 -10.76544, 40.43725 -11.76171, 40.56081 -12.63918, 40.59962 -14.20198, 40.77548 -14.69176, 40.47725 -15.40629, 40.08926 -16.10077, 39.45256 -16.72089, 38.53835 -17.10102, 37.41113 -17.58637, 36.28128 -18.65969, 35.8965 -18.84226, 35.1984 -19.55281, 34.78638 -19.78401, 34.70189 -20.49704, 35.17613 -21.25436, 35.37343 -21.84084, 35.38585 -22.14, 35.56255 -22.09, 35.53393 -23.07079, 35.37177 -23.53536, 35.60747 -23.70656, 35.45875 -24.12261, 35.04073 -24.47835, 34.21582 -24.81631, 33.01321 -25.35757, 32.57463 -25.72732, 32.66036 -26.14858, 32.91596 -26.21587, 32.83012 -26.74219, 32.58026 -27.47016, 32.46213 -28.30101, 32.20339 -28.7524, 31.521 -29.25739, 31.32556 -29.40198, 30.90176 -29.90996, 30.62281 -30.42378, 30.05572 -31.14027, 28.92555 -32.17204, 28.21976 -32.77195, 27.46461 -33.22696, 26.41945 -33.61495, 25.90966 -33.66704, 25.78063 -33.94465, 25.17286 -33.79685, 24.67785 -33.98718, 23.59404 -33.79447, 22.98819 -33.91643, 22.57416 -33.86408, 21.5428 -34.25884, 20.68905 -34.41718, 20.07126 -34.79514, 19.61641 -34.81917, 19.19328 -34.4626, 18.85531 -34.44431, 18.42464 -33.99787, 18.37741 -34.13652, 18.2445 -33.86775, 18.25008 -33.28143, 17.92519 -32.61129, 18.24791 -32.42913, 18.22176 -31.66163, 17.56692 -30.72572, 17.06442 -29.87864, 17.06292 -29.87595, 16.34498 -28.57671, 15.60182 -27.82125, 15.21047 -27.09096, 14.98971 -26.11737, 14.74321 -25.39292, 14.40814 -23.85301, 14.38572 -22.65665, 14.25771 -22.11121, 13.86864 -21.69904, 13.3525 -20.87283, 12.82685 -19.67317, 12.60856 -19.04535, 11.79492 -18.06913, 11.7342 -17.30189, 11.6401 -16.67314, 11.77854 -15.79382, 12.12358 -14.87832, 12.17562 -14.44914, 12.5001 -13.5477, 12.73848 -13.13791, 13.31291 -12.48363, 13.63372 -12.03864, 13.73873 -11.29786, 13.68638 -10.73108, 13.38733 -10.37358, 13.12099 -9.7669, 12.87537 -9.16693, 12.92906 -8.95909, 13.23643 -8.56263, 12.93304 -7.59654, 12.7283 -6.92712, 12.22735 -6.29445, 12.32243 -6.10009, 12.18234 -5.78993, 11.91496 -5.03799, 11.09377 -3.97883, 10.06614 -2.96948, 9.40525 -2.14431, 8.798 -1.1113, 8.83009 -0.77907, 9.04842 -0.45935, 9.29135 0.26867, 9.49289 1.01012, 9.30561 1.16091, 9.64916 2.28387, 9.7952 3.0734, 9.40437 3.73453, 8.94812 3.90413, 8.74492 4.35222, 8.48882 4.49562, 8.50029 4.77198, 7.46211 4.41211, 7.0826 4.46469, 6.69807 4.24059, 5.89817 4.26245, 5.3628 4.88797, 5.03357 5.6118, 4.32561 6.27065, 3.57418 6.2583, 2.6917 6.25882, 1.86524 6.14216, 1.06012 5.92884, -0.50764 5.34347, -1.06362 5.00055, -1.96471 4.71046, -2.85613 4.99448, -3.31108 4.9843, -4.00882 5.17981, -4.64992 5.16826, -5.8345 4.9937, -6.52877 4.70509, -7.51894 4.33829, -7.71216 4.36457, -7.97411 4.35576, -9.00479 4.83242, -9.91342 5.59356, -10.76538 6.14071, -11.43878 6.78592)), ((50.20027 -16.00026, 49.86061 -15.41425, 49.67261 -15.7102, 49.86334 -16.45104, 49.77456 -16.87504, 49.49861 -17.10604, 49.43562 -17.95306, 49.04179 -19.11878, 48.54854 -20.49689, 47.93075 -22.3915, 47.54772 -23.78196, 47.09576 -24.94163, 46.28248 -25.17846, 45.40951 -25.60143, 44.83357 -25.3461, 44.03972 -24.98835, 43.76377 -24.46068, 43.69778 -23.57412, 43.34565 -22.7769, 43.25419 -22.05741, 43.4333 -21.33648, 43.89368 -21.16331, 43.89637 -20.83046, 44.37433 -20.07237, 44.4644 -19.43545, 44.23242 -18.96199, 44.04298 -18.33139, 43.96308 -17.40994, 44.31247 -16.8505, 44.44652 -16.21622, 44.94494 -16.17937, 45.50273 -15.97437, 45.87299 -15.79345, 46.31224 -15.78002, 46.88218 -15.21018, 47.70513 -14.5943, 48.00521 -14.09123, 47.86905 -13.66387, 48.29383 -13.78407, 48.84506 -13.08917, 48.86351 -12.48787, 49.19465 -12.04056, 49.54352 -12.46983, 49.80898 -12.89528, 50.05651 -13.55576, 50.21743 -14.75879, 50.47654 -15.22651, 50.37711 -15.70607, 50.20027 -16.00026)))			

というようになってしまうので方法を変える

continents = world.dissolve(
    by='CONTINENT',
    aggfunc={
        'POP_EST': 'sum',
        'GDP_MD': 'sum'
    }
).reset_index()

continents[['CONTINENT','POP_EST','GDP_MD']]

としたが

CONTINENT	POP_EST	GDP_MD	
0	Africa	1.306370e+09	2455514
1	Antarctica	4.490000e+03	898
2	Asia	4.550277e+09	32725478
3	Europe	7.454125e+08	21587850
4	North America	5.837560e+08	25075988
5	Oceania	4.120487e+07	1647113
6	Seven seas (open ocean)	1.400000e+02	16
7	South America	4.270667e+08	3852015

となって geometry が無くなっている

計後に列を選び直したときに geometry 列を外してしまい、ただの DataFrame になったからです。geometry が無いと GeoDataFrame ではなくなるので地理情報が消えたように見える

これだと使えないので別の方法にする

GPTで調べたら
pandas の表示設定で抑える(geometryはそのまま)
Shapelyオブジェクトは文字列化されると長い座標列が出ますが、
pd.set_option を調整すると途中で省略される

import pandas as pd
pd.set_option("display.max_colwidth", 80)  # 長さ制限
continents.head()

とすれば
これなら geometry は Shapely のまま保持され、
計算や可視化にもそのまま使える

CONTINENT	geometry	POP_EST	GDP_MD	
0	Africa	MULTIPOLYGON (((-11.43878 6.78592, -11.70819 6.8601, -12.4281 7.26294, -12.9...	1.306370e+09	2455514
1	Antarctica	MULTIPOLYGON (((-61.13898 -79.98137, -60.61012 -79.62868, -59.57209 -80.0401...	4.490000e+03	898
2	Asia	MULTIPOLYGON (((48.67923 14.0032, 48.23895 13.94809, 47.93891 14.00723, 47.3...	4.550277e+09	32725478
3	Europe	MULTIPOLYGON (((-53.55484 2.3349, -53.77852 2.3767, -54.08806 2.10556, -54.5...	7.454125e+08	21587850
4	North America	MULTIPOLYGON (((-155.22217 19.23972, -155.54211 19.08348, -155.68817 18.9161...	5.837560e+08	25075988

座標系の変換

座標系の変換

緯度経度は度になっているが
面積、距離などを求める時には変換が必要

https://sorabatake.jp/20670/
も参考にする

Name: WGS 84

– Lat[north]: Geodetic latitude (degree)
– Lon[east]: Geodetic longitude (degree)

がよく使われる
これはGPSで使われる

WGS 84
これを
EPSGにすると4326
https://epsg.io/4326
単位は度

これは世界

日本近辺に特化したものが
EPSG:6668
https://epsg.io/6668
単位は度

日本付近に絞るならこちらを使う方が良さそう

EPSG:6691
https://epsg.io/6691
これは
単位がメートルになっている
こちらも日本周辺がメイン

Area of use: Japan – between 138°E and 144°E, onshore and offshore.
となっているので
それ以外のエリアの精度が正しくないことがあるので注意

とりあえず品川の情報を表示

shinagawa
	N03_001	N03_002	N03_003	N03_004	N03_007	geometry
87	東京都	None	品川区	None	13109	POLYGON ((139.75501 35.61771, 139.75507 35.617...
88	東京都	None	品川区	None	13109	POLYGON ((139.77231 35.62188, 139.77302 35.621...
89	東京都	None	品川区	None	13109	POLYGON ((139.75953 35.625, 139.75966 35.6216,...
90	東京都	None	品川区	None	13109	POLYGON ((139.71943 35.64167, 139.71953 35.641...

座標情報を見るなら crs で表示できる

shinagawa.crs

結果は

<Geographic 2D CRS: EPSG:6668>
Name: JGD2011
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: Japan - onshore and offshore.
- bounds: (122.38, 17.09, 157.65, 46.05)
Datum: Japanese Geodetic Datum 2011
- Ellipsoid: GRS 1980
- Prime Meridian: Greenwich

この中で注目するのは

EPSG:6668

- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)

から
単位は度であることがわかる

同様に路線図の crs も確認する

gdf.crs

結果は

<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World.
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich

こちらも

EPSG:4326

- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)

から単位は度であることがわかる

この2つはEPSGコードが異なるため
このままだと一緒に使えないので変換をして合わせる

今回は路線図のEPSGコードを6668に変換するので
to_crs を使う

gdf.to_crs(epsg=6668,inplace=True)
gdf.crs

これで

<Geographic 2D CRS: EPSG:6668>
Name: JGD2011
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: Japan - onshore and offshore.
- bounds: (122.38, 17.09, 157.65, 46.05)
Datum: Japanese Geodetic Datum 2011
- Ellipsoid: GRS 1980
- Prime Meridian: Greenwich

となる

OSMxを使い最短経路の算出

OSMxを使い最短経路の算出

東京スカイツリーから
江戸東京博物館への最短経路を算出する

まずはスカイツリーと江戸東京博物館の座標をセットする

skytree = (35.7100,139.8180)
museum = (35.6963,139.7967)

次に一番近い node つまり交差点を取得

始点はスカイツリーなので

start = ox.get_nearest_node(G,skytree)

としたがエラー

--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[15], line 1 ----> 1 start = ox.get_nearest_node(G,skytree) AttributeError: module 'osmnx' has no attribute 'get_nearest_node'

これもバージョンの違いが原因

OSMnx 2.x では廃止され、ox.distance サブモジュールに移動
引数は (X=経度, Y=緯度) の順番で渡す必要があります
普通の Point(lon, lat) と同じ並び

start = ox.distance.nearest_nodes(G, X=skytree[1], Y=skytree[0])

とすればOK

同様に終点も

end = ox.distance.nearest_nodes(G,museum[1],museum[0])

次に最短経路

shortest_path = ox.shortest_path(G,start,end)

Foliumで表示できないので調べた

plot_route_folium
https://github.com/gboeing/osmnx/issues/1252
によれば

release (currently 1.9.4), then run your code. The latest v1 release will remain compatible with the v1 API, but any deprecated functionality you’re using will issue a FutureWarning with simple guidance to make it v2 compatible.
Yes, the folium module was deprecated with a warning for removal back in 2023, and finally removed in v2.0.0. The good news: interactive web mapping with folium remains easy to do with OSMnx in ~2 lines of code! See this example in the Examples Gallery for a demonstration.

となっていて
foliumモジュールは2023年に削除の警告とともに非推奨となり、最終的にv2.0.0で削除されました。

とのこと

https://github.com/gboeing/osmnx-examples/blob/main/notebooks/11-interactive-web-mapping.ipynb
のサンプルが参考になりそう

OSMnx 2.0.6 には Folium 専用関数は無い → 自分で PolyLine を追加すればOK

再度GPTでコード生成

route = nx.shortest_path(G, orig, dest, weight="length")

というように

weight="length")

があるので調べた

✅ weight の意味
networkx.shortest_path の weight 引数は、**「どのエッジ属性を最短経路計算に使うか」**を指定するものです。
OSMnx で作成した G(道路グラフ)には、各エッジ(道路の区間)に様々な属性があります:
* “length” : 区間の長さ(メートル単位) ← デフォルトでよく使う
* “travel_time” : 区間の推定走行時間(秒単位)※ ox.add_edge_speeds / ox.add_edge_travel_times を実行した場合のみ
* その他、highway(道路種別)や lanes(車線数)など

✅ 例
1. 最短距離ルート(距離を最小化)

route = nx.shortest_path(G, orig, dest, weight="length")

2. 最短時間ルート(所要時間を最小化)
まず速度と所要時間をエッジに付与してから:

import osmnx as ox

G = ox.add_edge_speeds(G)        # 各道路に推定速度 (km/h) を追加
G = ox.add_edge_travel_times(G)  # 各道路に travel_time (秒) を追加

route = nx.shortest_path(G, orig, dest, weight="travel_time")

✅ まとめ
* weight=”length” → 「最短距離ルート」
* weight=”travel_time” → 「最短時間ルート」
* 他のエッジ属性を指定すれば、それに基づいた経路探索ができる

OSMnxについて

OSMnxについて

OSMは
Open street map の略

pythonで道路ネットワーク分析

も参考にする

先にインストール

pip install osmnx

でインストールできる

import folium
import osmnx as ox
import matplotlib.pyplot as plt
from shapely.geometry import Point,LineString,Polygon

で必要なものをインポート

まずは道路データの取得
今回は取得するのは道路なので drive にする
歩道なら walkなどを指定

Queryでどこの道路データを取るか指定
今回は
日本の東京都の墨田区にするので

query ="Sumidaku,Tokyo,Japan"
G = ox.graph_from_place(query,network_type="drive")

とする

print(G)で表示すると

MultiDiGraph with 3000 nodes and 7834 edges

となる

Nodes は交差点
Edges は道路の数
みたいな感じ

これを foliumで表示する

しかし

ox.plot_graph_folium(G)

だと

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[9], line 1
----> 1 ox.plot_graph_folium(G)

AttributeError: module 'osmnx' has no attribute 'plot_graph_folium'

✅ 背景
* 以前の OSMnx (v1.x くらいまで) には ox.plot_graph_folium(G) がありました。
* しかし OSMnx 2.0 以降では Folium 連携機能は 専用モジュールに移動しています。

from osmnx import folium as ox_folium

を追加
しかしエラーになる

ラッキーピエロ全店を最短でめぐりたい

では

ox.plot.plot_graph_folium

を使っている

ちなみにドキュメントは
https://osmnx.readthedocs.io/en/stable/index.html

調べてもバージョンは2.06で最新

GPTは2.1が最新と言っているが実際は2.06が最新

https://speakerdeck.com/mopinfish/osmnxniyorujie-lu-gou-zao-nofen-xi-toke-shi-hua?slide=20
を参考に行う

pip install contextily
でインストール

📌 まとめ
* contextily = 背景地図を GeoPandas/Matplotlib に簡単に追加するモジュール
* OpenStreetMap などのタイルを呼び出せる
* EPSG:3857(Web地図座標系)に自動変換してくれる

https://qiita.com/yutowac/items/b8e3d7653d3dcad16faf
の場合使っているバージョンが古い可能性がある

import osmnx as ox
import matplotlib.pyplot as plt
import contextily as cx

# 道路ネットワークの取得
place = "Higashi-ku, Sapporo, Hokkaido, Japan"
G = ox.graph_from_place(place, network_type="drive")

# グラフを GeoDataFrame に変換
nodes, edges = ox.graph_to_gdfs(G)

# 地図の作成
fig, ax = plt.subplots(figsize=(15, 15))

# エッジの描画
edges.plot(ax=ax, linewidth=0.5, edgecolor="dimgray")

# 背景地図の追加(OpenStreetMap)
cx.add_basemap(ax, crs=edges.crs.to_string(),
               source=cx.providers.OpenStreetMap.Mapnik)

# 地図の表示
plt.show()

で表示できたので
これを元にGPTでコード生成

import osmnx as ox
import matplotlib.pyplot as plt
import contextily as cx

# 墨田区の道路ネットワークを取得
query = "Sumida-ku, Tokyo, Japan"
G = ox.graph_from_place(query, network_type="drive")

# グラフを GeoDataFrame に変換
nodes, edges = ox.graph_to_gdfs(G)

# 描画
fig, ax = plt.subplots(figsize=(12, 12))

# 道路(edges)を描く
edges.plot(ax=ax, linewidth=0.7, edgecolor="blue")

# 背景地図を追加(OpenStreetMap)
cx.add_basemap(ax,
               crs=edges.crs.to_string(),
               source=cx.providers.OpenStreetMap.Mapnik)

# 表示
plt.show()

これで地図と情報が表示できた

あとは別の方法として
交差点を赤
道路を青
背景を白
で表示する

ox.plot_graph(G,bgcolor="white",node_color="red",edge_color="blue",node_size=2)

で表示はされる
ただし地図にはならない

座標系の変換

座標系の変換

緯度経度は度になっているが
面積、距離などを求める時には変換が必要

https://sorabatake.jp/20670/
も参考にする

Name: WGS 84

– Lat[north]: Geodetic latitude (degree)
– Lon[east]: Geodetic longitude (degree)

がよく使われる
これはGPSで使われる

WGS 84
これを
EPSGにすると4326
https://epsg.io/4326
単位は度

これは世界

日本近辺に特化したものが
EPSG:6668
https://epsg.io/6668
単位は度

日本付近に絞るならこちらを使う方が良さそう

EPSG:6691
https://epsg.io/6691
これは
単位がメートルになっている
こちらも日本周辺がメイン

Area of use: Japan – between 138°E and 144°E, onshore and offshore.
となっているので
それ以外のエリアの精度が正しくないことがあるので注意

とりあえず品川の情報を表示

shinagawa
	N03_001	N03_002	N03_003	N03_004	N03_007	geometry
87	東京都	None	品川区	None	13109	POLYGON ((139.75501 35.61771, 139.75507 35.617...
88	東京都	None	品川区	None	13109	POLYGON ((139.77231 35.62188, 139.77302 35.621...
89	東京都	None	品川区	None	13109	POLYGON ((139.75953 35.625, 139.75966 35.6216,...
90	東京都	None	品川区	None	13109	POLYGON ((139.71943 35.64167, 139.71953 35.641...

座標情報を見るなら crs で表示できる

shinagawa.crs

結果は

<Geographic 2D CRS: EPSG:6668>
Name: JGD2011
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: Japan - onshore and offshore.
- bounds: (122.38, 17.09, 157.65, 46.05)
Datum: Japanese Geodetic Datum 2011
- Ellipsoid: GRS 1980
- Prime Meridian: Greenwich

この中で注目するのは

EPSG:6668

- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)

から
単位は度であることがわかる

同様に路線図の crs も確認する

gdf.crs

結果は

<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World.
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich

こちらも

EPSG:4326

- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)

から単位は度であることがわかる

この2つはEPSGコードが異なるため
このままだと一緒に使えないので変換をして合わせる

今回は路線図のEPSGコードを6668に変換するので
to_crs を使う

gdf.to_crs(epsg=6668,inplace=True)
gdf.crs

これで

<Geographic 2D CRS: EPSG:6668>
Name: JGD2011
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: Japan - onshore and offshore.
- bounds: (122.38, 17.09, 157.65, 46.05)
Datum: Japanese Geodetic Datum 2011
- Ellipsoid: GRS 1980
- Prime Meridian: Greenwich

となる