Spaces:
Running on Zero
Running on Zero
File size: 2,306 Bytes
a74054f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | """
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.)") |