gedih3.egi.raster#

EGI (EASE Grid Index) Raster Module

This module provides rasterization functions for converting EGI-indexed GeoDataFrames to raster (xarray/GeoTIFF) format. The native alignment of EGI with EASE-Grid 2.0 allows for direct rasterization without resampling.

Attributes#

Functions#

geodf_to_raster(→ xarray.Dataset)

Convert EGI-indexed GeoDataFrame to raster (xarray Dataset).

split_by_outer_tile(→ List[tuple])

Split an EGI-indexed frame into one sub-frame per level-12 outer tile.

rasterize_partition(→ pandas.Series)

Rasterize a single EGI partition (for use with Dask map_partitions).

export_raster(→ str)

Export xarray Dataset to GeoTIFF file.

merge_raster_partitions(→ xarray.Dataset)

Merge multiple raster partitions into a single raster.

get_raster_profile(→ dict)

Generate a rasterio profile for EGI raster output.

Module Contents#

gedih3.egi.raster.logger#
gedih3.egi.raster.geodf_to_raster(geodf: geopandas.GeoDataFrame, columns: List[str] | None = None, fill_value: float = np.nan, outer_tile: int | None = None) xarray.Dataset[source]#

Convert EGI-indexed GeoDataFrame to raster (xarray Dataset).

This function creates a raster aligned to the EASE-Grid 2.0 projection, with each EGI pixel mapped directly to a corresponding raster cell using direct index assignment (no interpolation or extrapolation).

The raster covers exactly ONE level-12 outer tile. When that tile is given explicitly (outer_tile), stray pixels from any other tile are skipped with a WARNING — their inner indices are positions within their own tile and would land at wrong map coordinates in this tile’s grid (this protects legacy datasets extracted before the to_hash boundary-overflow carry and the egi_load spillover filter, which can still hold cross-tile rows). When no tile is given, the input must resolve to a single tile; a genuine multi-tile input raises GediRasterizationError instead of guessing which tile to keep — split by outer tile first (rasterize_partition) to keep every pixel.

Parameters:
geodfGeoDataFrame

EGI-indexed GeoDataFrame (index must be EGI hash values)

columnslist of str, optional

Columns to rasterize. If None, all numeric columns are used. Internal columns (egi indices, h3 indices) are automatically excluded.

fill_valuefloat

Value for pixels with no data (default: NaN)

outer_tileint, optional

Level-12 EGI hash of the tile to rasterize. Callers that know their tile (partition writers, rasterize_partition) should always pass it. When None, the input must resolve to a single outer tile; a multi-tile input with no outer_tile hint raises GediRasterizationError rather than guessing which tile to keep — split by outer tile first (rasterize_partition) so no pixels are dropped.

Returns:
xr.Dataset

Raster dataset with one data variable per column

Raises:
GediRasterizationError

If the input spans more than one outer tile and no outer_tile is given (the function rasterizes exactly one tile and will not silently drop the rest).

Notes

This implementation uses direct index-based pixel assignment: 1. Decode each EGI hash to get pixel indices within the outer tile 2. Create a raster array with exact tile dimensions 3. Assign values directly to pixel locations

This guarantees one polygon = one pixel with no extrapolation.

Examples

>>> # Rasterize aggregated GEDI data
>>> raster = geodf_to_raster(agg_gdf, columns=['agbd_mean', 'rh_098_mean'])
>>> raster.rio.to_raster("output.tif")
gedih3.egi.raster.split_by_outer_tile(gdf: geopandas.GeoDataFrame) List[tuple][source]#

Split an EGI-indexed frame into one sub-frame per level-12 outer tile.

For the callers that legitimately hold a multi-tile frame — an aggregate over an arbitrary ROI, say. A Dask partition is not one of them: it nests in exactly one outer tile by construction, which is why rasterize_partition() treats a multi-tile partition as an error to report rather than a shape to accommodate.

Parameters:
gdfGeoDataFrame

EGI-indexed GeoDataFrame (index holds EGI hashes).

Returns:
list of tuple

(egi12_id, sub_gdf) pairs, largest sub-frame first. Empty input yields an empty list.

gedih3.egi.raster.rasterize_partition(gdf: geopandas.GeoDataFrame, columns: List[str] | None = None, include_egi_id: bool = True, partition_level: int | None = None) pandas.Series[source]#

Rasterize a single EGI partition (for use with Dask map_partitions).

One partition is one raster. An EGI partition at any level <= 12 nests in exactly one level-12 outer tile, so a partition spanning several tiles is a violation of that invariant, not a case to accommodate: it is reported with a WARNING, and the tile holding the most rows is the one rasterized. That keeps the “one partition = one output file” contract every consumer downstream relies on (export_raster_partition file naming, merge_and_export_rasters, gh3_rasterize).

Parameters:
gdfGeoDataFrame

EGI-indexed GeoDataFrame partition

columnslist of str, optional

Columns to rasterize

include_egi_idbool

If True, include outer tile ID in raster attributes

partition_levelint, optional

EGI level the data is partitioned at. Drives the egiNN_id attribute that names the output file, so it must identify the partition, not the raster’s level-12 tile: when partitions are finer than level 12, several of them share one outer tile and naming by the tile makes them overwrite each other. None (the default) stamps egi12_id, which is correct for the standard level-12 partitioning.

Returns:
pd.Series

Object-dtype Series of length 0 (empty / unrasterizable partition) or 1 (the partition’s raster). Never longer — see the invariant above.

Examples

>>> # With Dask
>>> rasters = ddf.map_partitions(rasterize_partition, meta=pd.Series(dtype=object))
gedih3.egi.raster.export_raster(xras: xarray.Dataset, output_path: str, compress: str = 'LZW', tiled: bool = True, blocksize: int = 256, bigtiff: bool = True, cog: bool = True) str[source]#

Export xarray Dataset to GeoTIFF file.

Thin alias for gedih3.raster.export_raster(), kept because egi.export_raster is part of the module’s published surface. It used to be a near-copy that inlined its own creation options, so it silently missed the parent’s directory creation, its compress='NONE' handling and — latterly — Cloud Optimized GeoTIFF output.

Parameters:
xrasxr.Dataset

Raster dataset to export

output_pathstr

Output file path

compressstr

Compression method (‘LZW’, ‘ZSTD’, ‘DEFLATE’, ‘NONE’)

tiledbool

Use tiled output format. Ignored when cog is True.

blocksizeint

Tile block size in pixels

bigtiffbool

Use BigTIFF format for large files

cogbool

Write a Cloud Optimized GeoTIFF (default)

Returns:
str

Output file path

gedih3.egi.raster.merge_raster_partitions(raster_series: pandas.Series, output_path: str | None = None) xarray.Dataset[source]#

Merge multiple raster partitions into a single raster.

Parameters:
raster_seriespd.Series

Series of xarray Datasets from rasterize_partition

output_pathstr, optional

If provided, save merged raster to this path

Returns:
xr.Dataset

Merged raster dataset

gedih3.egi.raster.get_raster_profile(level: int, bounds: tuple, crs: str = EGI_CRS_STRING) dict[source]#

Generate a rasterio profile for EGI raster output.

Parameters:
levelint

EGI resolution level

boundstuple

Raster bounds (left, bottom, right, top)

crsstr

Coordinate reference system

Returns:
dict

Rasterio profile dictionary