aperta.geo_mapping¶
Map geographic features from one GeoDataFrame onto another.
Four primitives, distinguished by the shape of the source/target geometries:
map_points_to_polygons: for each point, find the containing polygon (with optional nearest-polygon fallback for points just outside any polygon).
map_polygons_to_points: for each polygon, find points falling inside.
map_points_to_points: nearest-neighbor matching between two point sets.
map_points_to_filtered_lines: snap points to the nearest line within a candidate-line subset selected by a per-point callback (used for bearing-aware traffic-counter snapping in calibration).
Distinct from geo_processing, which handles geometry construction and raster sampling rather than mapping data between layers.
- aperta.geo_mapping.map_points_to_polygons(points, polygons, *, allow_nearest=True, max_distance=None)[source]¶
For each point, find the polygon containing it.
With allow_nearest=True, points not within any polygon fall back to the nearest polygon — capped at max_distance if given (CRS units).
See also map_polygons_to_points for the inverse mapping (each polygon → a point it contains).
- Parameters:
points (GeoDataFrame) – GeoDataFrame of points to assign. Output is indexed by points.index.
polygons (GeoDataFrame) – GeoDataFrame of candidate polygons.
allow_nearest (bool) – fallback to nearest polygon when a point isn’t inside any polygon.
max_distance (float | None) – distance cap for the nearest-fallback (CRS units). None = no cap.
- Returns:
ids: the matched polygon ID for each point. NaN where no match (e.g. point outside all polygons and allow_nearest=False, or beyond max_distance).
distances: distance to the matched polygon (CRS units). NaN for points matched by “within” (inside the polygon — no meaningful distance) and for unmatched points. Only finite for points assigned via nearest-fallback.
- Return type:
(ids, distances) tuple, both indexed by points.index
Points that match multiple polygons (overlapping) take the first match.
- aperta.geo_mapping.map_polygons_to_points(polygons, points, *, allow_nearest=True, max_distance=None)[source]¶
For each polygon, find a point it contains.
With allow_nearest=True, polygons that contain no point fall back to the nearest point — capped at max_distance if given (CRS units). Polygons containing multiple points keep the first match.
See also map_points_to_polygons for the inverse mapping (each point → the polygon containing it).
- Parameters:
polygons (GeoDataFrame) – GeoDataFrame of polygons to assign. Output is indexed by polygons.index.
points (GeoDataFrame) – GeoDataFrame of candidate points.
allow_nearest (bool) – fallback to nearest point when a polygon contains no point.
max_distance (float | None) – distance cap for the nearest-fallback (CRS units). None = no cap.
- Returns:
ids: the matched point ID for each polygon. NaN where no match (no contained point and either allow_nearest=False or beyond max_distance).
distances: distance from the polygon to the matched point (CRS units). NaN for polygons matched by “contains” (point inside the polygon — no meaningful distance) and for unmatched polygons. Only finite for polygons assigned via nearest-fallback.
- Return type:
(ids, distances) tuple, both indexed by polygons.index
- aperta.geo_mapping.map_points_to_points(left_points, right_points, *, max_distance=None)[source]¶
For each point in left_points, find the nearest point in right_points.
For the common special case where right_points are the nodes of a networkx graph (or similar), use aperta.network_snap.snap_to_network_nodes instead — it takes the graph directly, skipping the boilerplate of extracting node (x, y) coordinates and wrapping them in a GeoDataFrame.
- Parameters:
left_points (GeoDataFrame) – GeoDataFrame of query points. Output is indexed by left_points.index.
right_points (GeoDataFrame) – GeoDataFrame of candidate points.
max_distance (float | None) – distance cap (CRS units). None = no cap. Query points with no match within max_distance get NaN ID and NaN distance.
- Returns:
ids: the nearest-point ID from right_points. NaN if no match within max_distance.
distances: distance to the matched point (CRS units). NaN if no match.
- Return type:
(ids, distances) tuple, both indexed by left_points.index
- aperta.geo_mapping.map_points_to_filtered_lines(points, lines, search_radius, *, eligible_lines=None, accept=None)[source]¶
For each point, find the nearest line that passes per-point filters.
Matching is sequential per point: candidate lines within search_radius are optionally pre-filtered, sorted by cartesian distance to the point, then walked in increasing-distance order. The first line accept returns True for is the match. If accept is None, the nearest eligible line is matched.
- Parameters:
points (GeoDataFrame) – GeoDataFrame of point geometries.
lines (GeoDataFrame) – GeoDataFrame of LineString / MultiLineString geometries. Must be in the same CRS as points.
search_radius (float | Series) – max distance (CRS units) for candidate lines. Scalar applies to all points; pass a pd.Series aligned to points.index for per-point radii (e.g. a wider radius for highway counters).
eligible_lines (Callable[[Series, GeoDataFrame], GeoDataFrame] | None) – optional per-point pre-filter (point_row, candidate_lines) -> eligible_lines. Receives only candidates already within search_radius of the point; should return a subset (typically candidate_lines[mask]).
accept (Callable[[Series, Series, dict], bool] | None) – optional per-candidate acceptance test (point_row, line_row, ctx) -> bool, where ctx is a dict with ‘distance’ (cartesian point-to-line), ‘dist_along’ (arclength along the line to the point closest to point), and ‘nearest_point’ (the shapely Point on the line nearest point). Walked in order of increasing distance; the first True is the match. None = accept the nearest eligible line.
- Returns:
line_id: index of matched line (or pd.NA if no match)
distance: cartesian distance to matched line (or NaN)
dist_along: distance along matched line to nearest point (or NaN)
- Return type:
DataFrame indexed like points with three columns