River_Network / scripts /cross_check_catchments.py
ageraustine's picture
Upload folder using huggingface_hub
a74054f verified
Raw
History Blame Contribute Delete
2.31 kB
"""
Spatially match each station to the catchment polygon that actually
contains it (point-in-polygon), rather than guessing at a shared ID
field across BD TOPO and Hub'Eau. This is the correct approach when
two datasets don't share a clean join key.
"""
import sys
sys.path.insert(0, ".")
from pathlib import Path
import pandas as pd
import geopandas as gpd
from src.data.loaders.bdtopo_hydro import BDTopoHydroLoader
loader = BDTopoHydroLoader(data_path=Path("datasets/bdtopo_hydro"))
catchments = loader.load_catchments()
catchments_metric = catchments.to_crs(epsg=2154) # Lambert-93 for accurate area in meters
catchments["area_km2"] = catchments_metric.geometry.area / 1e6
stations = pd.read_csv("datasets/station_elevations.csv")
hubeau = pd.read_csv("datasets/catchment_area.csv").dropna(subset=["catchment_area_km2"])
stations_gdf = gpd.GeoDataFrame(
stations,
geometry=gpd.points_from_xy(stations["longitude"], stations["latitude"]),
crs="EPSG:4326",
).to_crs(catchments.crs)
# Spatial join: which catchment polygon contains each station?
joined = gpd.sjoin(stations_gdf, catchments[["area_km2", "toponyme", "geometry"]],
how="left", predicate="within")
result = joined[["station_code", "toponyme", "area_km2"]].rename(
columns={"area_km2": "bdtopo_area_km2", "toponyme": "bdtopo_catchment_name"}
)
result = result.merge(hubeau[["station_code", "catchment_area_km2"]], on="station_code", how="left")
result = result.rename(columns={"catchment_area_km2": "hubeau_area_km2"})
result["ratio"] = result["bdtopo_area_km2"] / result["hubeau_area_km2"]
print(result.to_string(index=False))
print()
matched = result.dropna(subset=["bdtopo_area_km2", "hubeau_area_km2"])
print(f"Stations with BOTH a containing BD TOPO polygon AND a Hub'Eau value: {len(matched)}")
if len(matched) > 0:
print(f"Area ratio (BD TOPO / Hub'Eau) — mean: {matched['ratio'].mean():.2f}, "
f"median: {matched['ratio'].median():.2f}")
print("(A ratio near 1.0 across most stations would confirm both sources agree; "
"large/inconsistent ratios would suggest the polygons represent something "
"other than the gauge's own catchment -- e.g. a downstream aggregate, or "
"no polygon actually contains that point due to bbox edge effects.)")