core_lens.utils.spatial#

Spatial helpers for in-memory index construction and geometry filtering.

Functions#

resolve_path(→ str)

Return an absolute path or cloud URI string, resolving local relative paths against cwd.

build_bbox_index(→ polars.DataFrame)

Build the in-memory (key_cols..., minx, miny, maxx, maxy) index.

bbox_intersects_geometry(→ polars.DataFrame)

Return the index rows whose bounding box overlaps geometry's bounds.

exact_spatial_filter(→ polars.DataFrame)

Refine a bbox candidate set to rows that match aoi_geometry.

execute_spatial_join(→ polars.DataFrame)

Materialise a cross-entity spatial join and return enriched DataFrame.

point_in_entities(→ dict[str, Any | None])

Return the entity-id in which a lat/lon point falls, per entity.

Module Contents#

core_lens.utils.spatial.resolve_path(path: str) str#

Return an absolute path or cloud URI string, resolving local relative paths against cwd.

Parameters:

path (str) – A filesystem path (absolute or relative) or cloud URI.

Returns:

An absolute path string or cloud URI.

Return type:

str

Raises:

FileNotFoundError – If the resolved local path does not exist.

core_lens.utils.spatial.build_bbox_index(static_path: str, key_cols: list[str], bbox_cols: tuple[str, str, str, str] | None, geometry_col: str, geometry_type: str, storage_options: dict[str, Any] | None = None) polars.DataFrame#

Build the in-memory (key_cols..., minx, miny, maxx, maxy) index.

Reads the static GeoParquet file using only the key and spatial columns — no attribute data is pulled into memory. If pre-computed bbox columns are present in the file they are read directly; otherwise the geometry column is decoded and bounds are computed via Shapely.

Parameters:
  • static_path (str) – Absolute path or cloud URI to the static GeoParquet file.

  • key_cols (list[str]) – Column name(s) that form the entity’s unique key.

  • bbox_cols (tuple[str, str, str, str] | None) – Four-column (minx, miny, maxx, maxy) tuple if the static file carries pre-computed bounding boxes, otherwise None.

  • geometry_col (str) – Name of the geometry column.

  • geometry_type (str) – One of "wkb", "wkt", or "latlon".

  • storage_options (dict[str, Any] | None, optional) – Cloud credential / configuration options forwarded to pyarrow.fs and polars.read_parquet. None uses ambient credentials.

Returns:

A pl.DataFrame with columns (*key_cols, minx, miny, maxx, maxy).

Return type:

pl.DataFrame

core_lens.utils.spatial.bbox_intersects_geometry(index_df: polars.DataFrame, geometry: shapely.Geometry) polars.DataFrame#

Return the index rows whose bounding box overlaps geometry’s bounds.

This is a fast rectangular pre-filter in pure Polars — no STRtree. It returns a superset of the exact result, which is then refined by exact_spatial_filter().

Parameters:
  • index_df (pl.DataFrame) – The in-memory index DataFrame with minx, miny, maxx, maxy columns produced by build_bbox_index().

  • geometry (shapely.Geometry) – Any Shapely geometry representing the area of interest.

Returns:

The subset of index_df whose rows overlap the geometry bounds.

Return type:

pl.DataFrame

core_lens.utils.spatial.exact_spatial_filter(candidates: polars.DataFrame, static_path: str, key_cols: list[str], geometry_col: str, geometry_type: str, aoi_geometry: shapely.Geometry, relationship: str = 'centroid', threshold: float = 0.5) polars.DataFrame#

Refine a bbox candidate set to rows that match aoi_geometry.

Reads only the key and geometry columns for the candidate rows, decodes each geometry, and tests for the requested spatial relationship.

Parameters:
  • candidates (pl.DataFrame) – The DataFrame from bbox_intersects_geometry() — only the key columns are used here; the bbox columns are ignored.

  • static_path (str) – Absolute path to the static GeoParquet file.

  • key_cols (list[str]) – Column name(s) that form the entity’s unique key.

  • geometry_col (str) – Name of the geometry column in the static file.

  • geometry_type (str) – One of "wkb" or "wkt".

  • aoi_geometry (shapely.Geometry) – The Area of Interest geometry to test against.

  • relationship (str, optional) –

    Spatial relationship mode.

    • "centroid" (default) — entity centroid must lie within aoi_geometry.

    • "area" — fraction of the entity’s area covered by the intersection must exceed threshold.

  • threshold (float, optional) – Minimum intersection-to-entity area ratio used in "area" mode. Ignored in "centroid" mode. Default 0.5.

Returns:

A pl.DataFrame containing only the key columns for entities that satisfy the spatial relationship.

Return type:

pl.DataFrame

Raises:

ValueError – If relationship is not one of the valid options.

core_lens.utils.spatial.execute_spatial_join(primary_df: polars.DataFrame, primary_key_cols: list[str], primary_geom_col: str, primary_geom_type: str, other_entity: Any, agg: dict[str, str], other_entity_name: str) polars.DataFrame#

Materialise a cross-entity spatial join and return enriched DataFrame.

For each entity in primary_df, finds the overlapping entities in other_entity and aggregates the requested columns. Result columns are named {other_entity_name}_{column_name} to avoid clashes.

Parameters:
  • primary_df (pl.DataFrame) – The primary entity DataFrame (must contain primary_geom_col unless geometry is in a separate column).

  • primary_key_cols (list[str]) – Key column(s) of the primary entity.

  • primary_geom_col (str) – Name of the WKB geometry column in primary_df.

  • primary_geom_type (str) – Geometry encoding — "wkb" or "wkt".

  • other_entity (BaseEntity) – A BaseEntity instance to join against.

  • agg (dict[str, str]) – Mapping {column: aggregation} — which columns from other_entity to bring in and how to aggregate them. Valid aggregations: "count", "mean", "sum", "min", "max", "area".

  • other_entity_name (str) – Used to prefix result column names.

Returns:

primary_df with additional columns {other_entity_name}_{col} appended for each agg entry.

Return type:

pl.DataFrame

core_lens.utils.spatial.point_in_entities(latlon: dict[str, float], entities: list[Any]) dict[str, Any | None]#

Return the entity-id in which a lat/lon point falls, per entity.

For each entity, performs a two-phase lookup:

  1. Bbox pre-filter — eliminates entities whose bounding box doesn’t contain the point using the in-memory _index (no I/O).

  2. Exact containment — loads geometry only for bbox candidates and runs a vectorised Shapely contains test.

The function is designed for repeated hot-path calls; it relies on entity._index and entity.geometry_lazy which are both process-level cached after first access.

Parameters:
  • latlon (dict[str, float]) – Point coordinates with keys "lat" and "lon" (or "lng" as an alias for longitude).

  • entities (list[BaseEntity]) – List of entity instances to test against. Each must expose _index, key_cols, schema_profile, _resolve, and static_path.

Returns:

Mapping of entity_class_name entity_id (the value of the first key_col). None if the point doesn’t fall inside any geometry of that entity.

Return type:

dict[str, Any | None]

Raises:

KeyError – If neither "lon" nor "lng" key exists in latlon.

Example:

result = point_in_entities(
    {"lat": 28.6139, "lon": 77.2090},
    [district_entity, block_entity],
)
# {"DistrictEntity": "DEL_001", "BlockEntity": None}