diff --git a/README.md b/README.md index 0ffeb12..bc48269 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This project contains tools to make it easier to analyze raster data with Xarray It currently has two pieces. 1. `RasterIndex` for indexing using the affine transform recorded in GeoTIFFs. -1. Dask-aware rasterization wrappers around `exactextract`, `rasterio.features.rasterize`, and `rasterio.features.geometry_mask`. +1. Dask-aware rasterization wrappers around `exactextract`, `rasterio.features.rasterize`, `rusterize.rusterize`, and `rasterio.features.geometry_mask`. Our intent is to provide reusable building blocks for the many sub-ecosystems around: e.g. `rioxarray`, `odc.geo`, etc. diff --git a/docs/rasterize/overview.md b/docs/rasterize/overview.md index e67e494..b4194bc 100644 --- a/docs/rasterize/overview.md +++ b/docs/rasterize/overview.md @@ -57,15 +57,15 @@ Three rasterization engines are available for the functions above: | Engine | GDAL Required | `all_touched` | Notes | | ---------------- | ------------- | ------------- | ------------------------------ | | **rasterio** | Yes | Yes | Most compatible, requires GDAL | -| **rusterize** | No | No | Fast, easy to install, no GDAL | +| **rusterize** | No | Yes | Fast, easy to install, no GDAL | | **exactextract** | No | No\* | Sub-pixel precision, no GDAL | \* exactextract naturally includes any pixel with non-zero coverage, similar to `all_touched=True` ### Choosing an Engine -- **rasterio**: Best when you need `all_touched=True` or already have GDAL installed -- **rusterize**: Best for simple rasterization without GDAL dependency (default when available) +- **rasterio**: Best when you already have a GDAL-based pipeline +- **rusterize**: Best for all-around rasterization without GDAL dependency (default when available) - **exactextract**: Best when you need sub-pixel precision without GDAL ```python diff --git a/docs/rasterize/rusterize.ipynb b/docs/rasterize/rusterize.ipynb index d147fe6..a5c6f3e 100644 --- a/docs/rasterize/rusterize.ipynb +++ b/docs/rasterize/rusterize.ipynb @@ -10,10 +10,6 @@ "\n", "```{tip}\n", "Unlike the `rasterio` engine, `rusterize` does **not** require GDAL! This makes it much easier to install and is a great choice when GDAL installation is problematic.\n", - "```\n", - "\n", - "```{note}\n", - "The `rusterize` engine does not support the `all_touched` parameter. Use `engine='rasterio'` if you need `all_touched` support.\n", "```" ] }, @@ -136,13 +132,6 @@ "source": [ "xr.testing.assert_identical(dd, d)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/pixi.toml b/pixi.toml index 3023315..d154956 100644 --- a/pixi.toml +++ b/pixi.toml @@ -46,12 +46,8 @@ pytest-xdist = "*" [feature.with-rasterio.dependencies] rasterio = "*" -[feature.with-rusterize.dependencies] -# rusterize >=0.8 no longer depends on polars, but needs it for GeoDataFrame input -polars = "*" - [feature.with-rusterize.pypi-dependencies] -rusterize = ">=0.7.1" +rusterize = ">=0.8.1" # ===== Docs feature ===== @@ -80,7 +76,7 @@ xvec = "*" polars = "*" [feature.docs.pypi-dependencies] -rusterize = ">=0.7.1" +rusterize = ">=0.8.1" [feature.docs.tasks] docs-build = { cmd = "sphinx-build -b html . _build/html", cwd = "docs" } diff --git a/pyproject.toml b/pyproject.toml index 03317f4..5b50d3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,16 +38,14 @@ dynamic=["version"] [project.optional-dependencies] dask = ["dask-geopandas"] rasterize = ["rasterio"] -# rusterize >=0.8 no longer depends on polars, but needs it for GeoDataFrame input -rusterize = ["rusterize>=0.7.1", "polars"] +rusterize = ["rusterize>=0.8.1"] exactextract = ["exactextract", "sparse"] docs = [ "geodatasets", "pooch", "dask-geopandas", "rasterio", - "rusterize>=0.7.1", - "polars", # needed by rusterize for GeoDataFrame input + "rusterize>=0.8.1", "rioxarray", "exactextract", "sparse", diff --git a/src/rasterix/rasterize/core.py b/src/rasterix/rasterize/core.py index 10443ce..96aa2c8 100644 --- a/src/rasterix/rasterize/core.py +++ b/src/rasterix/rasterize/core.py @@ -180,7 +180,7 @@ def rasterize( all_touched : bool If True, all pixels touched by geometries will be burned in. If False, only pixels whose center is within the geometry are burned. - Note: Not supported by rusterize or exactextract engines. + Note: Not supported by the exactextract engine. merge_alg : str Merge algorithm when geometries overlap. - "replace": later geometries overwrite earlier ones @@ -211,6 +211,7 @@ def rasterize( Requires GDAL. - **rusterize**: A Rust-based rasterization engine. Does not require GDAL. + Same ``all_touched`` logic as rasterio. - **exactextract**: Uses the exactextract library for precise sub-pixel coverage computation. Any pixel with non-zero coverage is burned, which diff --git a/src/rasterix/rasterize/rusterize.py b/src/rasterix/rasterize/rusterize.py index b2b3568..5c510ec 100644 --- a/src/rasterix/rasterize/rusterize.py +++ b/src/rasterix/rasterize/rusterize.py @@ -4,7 +4,6 @@ from collections.abc import Sequence from typing import Any -import geopandas as gpd import numpy as np from affine import Affine from shapely import Geometry @@ -79,24 +78,18 @@ def rasterize_geometries( """ from rusterize import rusterize - # Create GeoDataFrame with index values - # Dummy CRS required by rusterize but not used by the algorithm - # https://github.com/ttrotto/rusterize/issues/10 - values = list(range(offset, offset + len(geometries))) - gdf = gpd.GeoDataFrame({"value": values}, geometry=list(geometries), crs="EPSG:4326") - extent, (xres, yres) = _affine_to_extent_and_res(affine, shape) result = rusterize( - gdf, + list(geometries), res=(xres, yres), extent=extent, out_shape=shape, - field="value", fun=merge_alg, background=fill, all_touched=all_touched, encoding="numpy", + burn=np.arange(offset, offset + len(geometries), dtype=dtype), dtype=str(dtype), ) @@ -174,15 +167,10 @@ def np_geometry_mask( """ from rusterize import rusterize - # Create GeoDataFrame with burn value - # Dummy CRS required by rusterize but not used by the algorithm - # https://github.com/ttrotto/rusterize/issues/10 - gdf = gpd.GeoDataFrame(geometry=list(geometries), crs="EPSG:4326") - extent, (xres, yres) = _affine_to_extent_and_res(affine, shape) result = rusterize( - gdf, + list(geometries), res=(xres, yres), extent=extent, out_shape=shape,