Fix silent CRS mishandling in find_geometry_from_coord and geom_prop#615
Fix silent CRS mishandling in find_geometry_from_coord and geom_prop#615martinguthrie93 wants to merge 3 commits into
Conversation
|
Welcome, new contributor! It appears that this is your first Pull Request. To give credit where it's due, we ask that you add your information to the
Please make sure you've read our contributing guide. We look forward to reviewing your Pull Request shortly ✨ |
2b37fc0 to
d45c3d2
Compare
Note on the failing CI checksBoth currently-failing checks are pre-existing/environmental and are not introduced by this PR. This PR only touches 1.
This rule is newly enforced because the lint environment resolved 2. The cascade of
The failure set is identical on This PR's substantive checks pass: Happy to rebase once |
|
Feel free to rebase; the changes needed were addressed in #613 |
`find_geometry_from_coord` reprojected nothing before calling `GeoDataFrame.contains`, so a geographic query point silently failed to match (or matched the wrong feature) against a projected routing product. It now reprojects the point into the GeoDataFrame's CRS and accepts an optional `point_crs`. `geom_prop` computed area/perimeter/gravelius regardless of CRS and its warning fired for the safe (projected) case instead of the risky (decimal-degree) one. It now accepts an optional `crs` and warns when the geometry is in a geographic CRS. Returned values are unchanged. Both changes are backward compatible and covered by new regression tests. Closes CSHS-CWRA#614 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
for more information, see https://pre-commit.ci
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2f96402 to
0d8397d
Compare
|
Thanks @Zeitsperre! Rebased onto the latest |
|
Looking good! There may still be some issues with a few builds that the changes I made may have uncovered (some GDAL libraries not loading properly, maybe). Will likely look into this Monday. |
|
Rebase is in and The remaining Precise root cause (same on ubuntu and macOS): both With no vector backend, every notebook's first Nothing in this PR touches that import path — the only notebook exercising a changed function is |
Overview
Fixes two silent CRS-handling defects in the geospatial utilities. In both cases the code assumes a specific CRS, produces plausible-looking output when that assumption is violated, and raises nothing — so the error can propagate all the way into simulated streamflow.
Closes #614.
Changes
find_geometry_from_coord(ravenpy/utilities/geo.py)Previously the function built a
Point(lon, lat)and calledGeoDataFrame.containsdirectly.containscompares raw coordinates and does not reconcile CRSs, so a geographic query point never matched a routing product stored in a projected CRS (metres) — the lookup raised a misleading "not in any geometry" error or matched the wrong feature.df.crsbefore the point-in-polygon test.point_crsargument (default4326) lets callers pass a point expressed in any CRS.dfhas no CRS, a warning is emitted and the previous behavior (assume matching CRS) is preserved.dfis already in WGS84, so existing workflows (e.g.upstream_from_coords) are unaffected.geom_prop(ravenpy/utilities/analysis.py)area,perimeter, and the Gravelius shape index are only physically meaningful in a projected, equal-area CRS. The previous guard was inverted: it warned only when the centroid fell outside ±180/±90 (the projected, safe case) and stayed silent for decimal-degree geometries (the risky case).crsargument is used to detect a geographic CRS viapyproj.crs, a centroid-based heuristic flags likely decimal-degree geometries.Tests
Added
TestCrsAlignmentintests/test_geo_utilities.py:find_geometry_from_coordlocates the correct feature for a projected GeoDataFrame, for a geographic GeoDataFrame, and for a point supplied in a custompoint_crs; and still raises for a point genuinely outside all geometries.geom_propwarns for a geographic CRS (while leaving numeric output unchanged) and stays silent for a projected CRS.Backward compatibility
Both public signatures gain only optional keyword arguments with defaults that reproduce the prior behavior. Existing numeric results (including the values asserted in
test_geo_utilities.py) are unchanged.Notes for reviewers
I was unable to run the full GIS test suite locally (my environment lacks part of the RavenPy runtime stack, and the tests rely on the networked
yangtzedata fixture). I validated the new logic and every new test assertion againstgeopandas/pyproj/shapelyin isolation. CI should exercise the full suite.