API reference¶
High-level entry points are exported from the top-level geohalo package. Each
workflow comes in a convenience form (builds the operator for you) and a
precomputed form (you pass a cached object).
| Convenience | Precomputed | Builds |
|---|---|---|
reduce |
reduce_with_stencil / reduce_with_operator |
Stencil / ReduceOperator |
resample_grid |
resample_grid_with_matrix |
Resampler |
aggregate_bias |
aggregate_bias_with_tree |
BiasTree |
Reduction¶
geohalo.reduce ¶
reduce(
grid: T,
geoms: GeoSeries,
*,
target_resolution: float | None = None,
resample_iterations: int = 1,
spherical_correction: bool = True,
lat_dim: str = "latitude",
lon_dim: str = "longitude",
geom_dim: str = "geom",
weight_key: str | None = None,
how: Literal["mean", "sum"] = "mean",
preserve_dtype: bool = False,
period: float | None = None,
) -> T
Build a float64 stencil and reduce polygons in caller order.
preserve_dtype=True retains each floating input variable's result dtype;
integer means remain floating. For float32 coefficients, prebuild a stencil
or operator with dtype=np.float32 and use its corresponding reducer.
period=360 enables cyclic longitude resampling and generates a full
cycle when target_resolution is set. Geometries themselves do not wrap.
geohalo.reduce_with_stencil ¶
reduce_with_stencil(
grid: T,
stencil: Stencil,
*,
resample_iterations: int = 1,
lat_dim: str = "latitude",
lon_dim: str = "longitude",
geom_dim: str = "geom",
weight_key: str | None = None,
how: Literal["mean", "sum"] = "mean",
preserve_dtype: bool = False,
period: float | None = None,
) -> T
Reduce in stencil row order, automatically handling NaNs and cell weights.
preserve_dtype=True retains each floating input variable's result dtype;
integer means remain floating. Clean fusion uses the stencil's coefficient
dtype. Masked/weighted normalization retains its existing arithmetic precision.
period=360 wraps resampling in longitude; stencil coordinates and
polygon geometries are not wrapped or changed.
geohalo.reduce_with_operator ¶
reduce_with_operator(
grid: T,
operator: ReduceOperator,
*,
how: Literal["mean", "sum"] = "mean",
skipna: bool = False,
preserve_dtype: bool = False,
lat_dim: str = "latitude",
lon_dim: str = "longitude",
geom_dim: str = "geom",
) -> T
Reduce grid to per-polygon values using the fused source-grid operator.
By default, contributing NaNs propagate. skipna=True omits missing
source cells and renormalizes means over their surviving signed weights;
nonpositive denominators return NaN. Sums omit missing contributions,
returning zero when all are missing. With fused resampling, source masking
differs from resample-then-mask and negative weights can cause overshoots.
For target-cell masking or per-cell weights, use reduce_with_stencil.
Large grids gather contributing cells per batch slice, retaining the
operator's precision without copying or upcasting the entire batch.
preserve_dtype=True retains each floating input variable's dtype in the
result, without lowering matrix precision. Integer means remain floating.
geohalo.reduce_with_restricted_operator ¶
reduce_with_restricted_operator(
grid: T,
operator: RestrictedOperator,
*,
how: Literal["mean", "sum"] = "mean",
skipna: bool = False,
preserve_dtype: bool = False,
lat_dim: str = "latitude",
lon_dim: str = "longitude",
geom_dim: str = "geom",
) -> T
Reduce data, reading only the plan's contributing spatial chunks.
Returns an eager result, preserving batch coordinates, names, and attrs. Each batch chunk is processed separately; only one spatial window and its gathered cells are held at a time. Without batch chunk metadata, blocks target 8 MiB of working data (at least one slice). Native chunks may exceed this.
Coordinates must match the plan's stored latitude order and longitude grid.
Known spatial chunk layouts must also match; rebuild the plan after changing
either. Dataset variables without both spatial dimensions pass through.
NaNs propagate by default. skipna=True omits missing source cells,
renormalizing means over surviving signed weights (NaN if nonpositive).
Sums omit missing contributions, returning zero if all are missing. With
fused resampling this is not resample-then-mask. Per-cell weights and
target-cell masking still require reduce_with_stencil.
preserve_dtype=True retains each floating input variable's result dtype;
integer inputs keep normal promotion, including floating-point means.
Resampling¶
geohalo.resample_grid ¶
resample_grid(
source: T,
target_resolution: float,
*,
lat_dim: str = "latitude",
lon_dim: str = "longitude",
iterations: int = 1,
period: float | None = None,
method: ResampleMethod = "meanpreserving",
normalization: Normalization = "destination",
source_bounds: GridBounds | None = None,
skipna: bool = False,
preserve_dtype: bool = False,
) -> T
Resample at a target spacing; period makes longitude a full cycle.
period=360 wraps interpolation and parent assignment at the seam. The
generated longitude centres start at the source minimum and exclude its
repeated endpoint. period=None retains clamped, min/max-based targets.
method='conservative' uses spherical area overlaps, with optional
normalization='covered' or apply-time skipna=True. Target generation
still uses source centres, not their outer cell bounds; use an explicitly
built Resampler for matched source/target footprints. source_bounds is
an optional pair of latitude/longitude edge arrays (conservative only).
preserve_dtype=True retains each real floating variable's result dtype
for either method, with existing computation and normalization precision.
Integer, boolean, and complex inputs retain normal promotion.
geohalo.resample_grid_with_matrix ¶
resample_grid_with_matrix(
source: T,
resampler: Resampler,
*,
lat_dim: str = "latitude",
lon_dim: str = "longitude",
skipna: bool = False,
preserve_dtype: bool = False,
) -> T
Resample a matching source grid, accepting either latitude orientation.
Raises ValueError if the source coordinates differ from the resampler's
source grid. Output coordinates follow the resampler's target order.
For conservative resamplers, skipna=True averages only valid covered
area; by default contributing NaNs propagate. Unmapped cells return NaN.
preserve_dtype=True retains each real floating variable's result dtype
without lowering computation or normalization precision. Integer, boolean,
and complex inputs retain normal promotion. Applies to both methods.
Hierarchical rollups¶
geohalo.aggregate_bias ¶
aggregate_bias(
reduced: T,
edges: DataFrame,
*,
geom_dim: str = "geom",
parent_col: str = "parent",
weight_col: str | None = None,
how: Literal["mean", "sum"] = "mean",
) -> T
geohalo.aggregate_bias_with_tree ¶
Precomputed operators¶
All five classes support obj.to_npz() -> bytes and
Class.from_npz(blob: bytes) -> Class. These versioned, non-pickle artifacts can
be stored independently of the built-in caches. See
portable operator artifacts for supported keys,
the array schema, validation, and migration from older caches.
geohalo.Stencil
dataclass
¶
Bases: NPZSerializable
compute
classmethod
¶
compute(
lats: ndarray,
lons: ndarray,
geoms: GeoSeries,
*,
spherical_correction: bool = True,
dtype: DTypeLike = np.float64,
) -> Stencil
Build caller-ordered rows with float64 (default) or float32 coefficients.
Geometry calculations use float64 before casting stored coefficients. Row sums accumulate those stored weights in float64. Coordinates remain float64; dtype is part of the canonical digest, with old float64 keys intact.
geohalo.ReduceOperator
dataclass
¶
Bases: NPZSerializable
apply_grid ¶
apply_grid(
values: ndarray,
*,
descending: bool = False,
how: Literal["mean", "sum"] = "sum",
skipna: bool = False,
preserve_dtype: bool = False,
) -> np.ndarray
Project (..., latitude, longitude) values; default to an unnormalized sum.
Large grids gather only referenced cells, one batch slice at a time.
descending=True interprets source rows in descending latitude order.
The canonical matrix and its arithmetic precision are unchanged.
how="mean" divides by row_sums. With skipna=True, sums omit
missing source cells and means divide by the surviving signed weight
(NaN if nonpositive). This is source-cell masking, not resample-then-mask.
preserve_dtype=True returns floating inputs in their own dtype.
Multiplication and normalization keep their existing precision; integer
inputs retain normal promotion, so means are never truncated to integers.
compute
classmethod
¶
compute(
stencil: Stencil,
source_lat: ndarray,
source_lon: ndarray,
*,
iterations: int = 1,
dtype: DTypeLike = np.float64,
period: float | None = None,
) -> ReduceOperator
Fuse with float64 (default) or float32 stored coefficients.
Fusion uses the existing float64 resampling math before casting. The
stencil's float64 row sums are retained; casting does not sort entries.
Request float32 explicitly even if the stencil already uses float32.
period=360 wraps resampling in longitude, not polygon geometries.
geohalo.RestrictedOperator
dataclass
¶
Bases: NPZSerializable
Reusable chunk-aligned read plan for a :class:ReduceOperator.
Latitude coordinates and windows are in stored order, not canonical order. A plan is specific to that orientation and the spatial chunk layout. The compact matrix keeps the original coefficient accumulation order.
gather ¶
Gather already-read windows into (..., contributing_cells).
Supply exactly one NumPy array per entry in windows, in that order.
Each array must have trailing (rows, columns) dimensions matching its
window and the same leading batch shape. Coordinates cannot be checked:
the caller is responsible for reading in the plan's stored grid order.
Iterators are consumed one window at a time, without retaining earlier
arrays or flattening whole noncontiguous windows. A common input dtype
is preserved; mixed dtypes are promoted with numpy.result_type.
No I/O, xarray objects, or Dask scheduling is involved.
With no windows, gather([]) returns an empty float64 vector. For a
batched empty plan, pass np.empty((*batch_shape, 0), dtype=...)
directly to apply instead.
apply ¶
apply(
gathered: ndarray,
*,
how: Literal["mean", "sum"] = "mean",
skipna: bool = False,
preserve_dtype: bool = False,
) -> np.ndarray
Reduce (..., contributing_cells) to (..., zones) in keys order.
gathered must be in the column order produced by gather. Sum
returns the sparse projection; mean additionally divides by row_sums.
Matrix precision and coefficient accumulation order are preserved, with
per-batch-slice products to avoid upcasting or copying an entire batch.
preserve_dtype=True stores results in a floating input's dtype;
integer inputs keep normal promotion, including floating-point means.
By default, contributing NaNs propagate. skipna=True omits missing
source cells: sums return the remaining weighted contributions (zero if
all are missing), and means divide by the surviving signed weight (NaN
if nonpositive). With fused resampling this differs from masking after
resampling; negative coefficients can still produce overshoots.
This method does not read data or require xarray objects or Dask.
compute
classmethod
¶
compute(
operator: ReduceOperator,
source_lat: ndarray,
lat_chunks: ChunkSizes,
lon_chunks: ChunkSizes,
) -> RestrictedOperator
Build from stored latitudes and chunks, inheriting the operator's dtype.
from_grid
classmethod
¶
from_grid(
operator: ReduceOperator,
grid: DataArray,
*,
lat_dim: str = "latitude",
lon_dim: str = "longitude",
) -> RestrictedOperator
Infer layout from Dask chunks or backend encoding, without reading values.
For a Dataset, pass one spatial variable; reuse the plan for variables
with the same layout. For missing/stale metadata, use compute with
explicit chunk sizes instead. Dask and Zarr are not required dependencies.
geohalo.Resampler
dataclass
¶
Bases: NPZSerializable
Grid transform whose source columns use ascending latitude, then longitude.
Target rows retain the supplied coordinate order. Direct matrix callers must
flatten source values in (source_lat, source_lon) order; the xarray API
handles descending source latitudes automatically.
The default mean-preserving method stores transform_matrix. Conservative
resampling instead stores axis_weights=(latitude, longitude) and leaves
transform_matrix=None; use apply_grid for either representation.
coverage
property
¶
Source-covered fraction of each target cell (conservative only).
apply_grid ¶
apply_grid(
values: ndarray,
*,
descending: bool = False,
skipna: bool = False,
preserve_dtype: bool = False,
) -> np.ndarray
Transform (..., latitude, longitude) values into (..., n_target).
descending=True interprets source rows in descending latitude order.
Temporary dense allocations are bounded per slice or small batch block.
Conservative resamplers use two 1-D contractions per slice. Uncovered
cells return NaN. For this method only, skipna=True renormalizes over
valid covered area, overriding destination-area normalization; all
missing cells return NaN. The default propagates contributing NaNs.
preserve_dtype=True returns real floating inputs in their own dtype
for either method. Computation and normalization retain their existing
precision; only result storage changes. Integer, boolean, and complex
inputs retain normal promotion. Defaults are unchanged.
compute
classmethod
¶
compute(
source_lat: ndarray,
source_lon: ndarray,
target_lat: ndarray,
target_lon: ndarray,
*,
iterations: int = 1,
period: float | None = None,
method: ResampleMethod = "meanpreserving",
normalization: Normalization = "destination",
source_bounds: GridBounds | None = None,
target_bounds: GridBounds | None = None,
) -> Resampler
Build a mean-preserving or separable conservative grid transform.
The default clamps both axes. Set period=360 for cyclic longitude,
with no repeated source endpoint. Explicit target coordinates retain
their values and order, including targets outside the source cycle.
method='conservative' averages spherical cell overlaps using two
1-D axis_weights; transform_matrix is None. normalization is
'destination' (full target area) or 'covered' (source-covered area).
Optional source_bounds/target_bounds are (latitude, longitude)
edge arrays, each one longer than its coordinate axis, in that axis's
order. Otherwise midpoint edges are inferred (latitude clipped at the
poles, cyclic source longitude when periodic). Singleton noncyclic axes
require bounds. Conservative axes must be strictly monotonic, and
iterations must remain 1. Geometries and existing reducers are not
changed by this grid-resampling option.
geohalo.BiasTree
dataclass
¶
Bases: NPZSerializable
Caching¶
geohalo.LocalCache ¶
Bases: _Cache
NPZ files under path/<namespace>/<key>.npz; legacy entries are ignored.
geohalo.RedisCache ¶
Bases: _Cache
Values under <prefix>:<key> in Redis.
Geometry areas¶
These helpers live in geohalo.geometry. See
latitude correction for the
coordinate convention and the distinction between polygon areas and stencil weights.
geohalo.geometry.polygon_areas ¶
Spherical areas in m², using the same radius as :func:cell_areas.
Accept a GeoSeries or a one-dimensional sequence of Shapely geometries in longitude/latitude degrees. Return a float64 array in input order, without index labels. Missing geometries return NaN; empty geometries and non-area geometries return zero. Polygon holes are subtracted and multipart or collection areas are added (not unioned). Z coordinates are ignored.
Edges are straight segments in the supplied lon/lat coordinates, not geodesics. Integration is analytic, including sloped edges. Longitudes are NOT wrapped: a box from -170 to 170 spans 340 degrees, while a narrow seam-crossing box can use 170 to 190, or be split at the antimeridian. Each polygon must span at most 360 degrees. Full-globe boxes are supported.
Coordinates must be finite, latitudes within [-90, 90], and geometries topologically valid. Invalid inputs raise ValueError; non-geometries raise TypeError. A GeoSeries CRS, when set, must be EPSG:4326 (or equivalent). No reprojection, repair, clipping, or longitude unwrapping is performed.
Stencil weights use planar cell-coverage fractions times spherical cell
areas. They share these units and radius, but only approximate this area
in partially covered cells. For planar areas, use Shapely's area.
geohalo.geometry.cell_areas ¶
Per-cell area. spherical=True → m²; spherical=False → all 1.0.
Exceptions¶
geohalo.EmptyOverlapError ¶
Bases: Exception