diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index acbb91bd..6b991c7b 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -17,6 +17,14 @@ Upcoming Release To use the features already you have to install the ``master`` branch, e.g. ``pip install git+https://github.com/pypsa/atlite``. +**Bug fixes** + +* Fix ``ExclusionContainer.add_raster`` ignoring ``codes=0``. The code ``0`` was + treated like a missing ``codes`` argument, so all non-zero cells were excluded + instead of the cells with value ``0``. Numpy arrays are now accepted as + ``codes``, and an empty list excludes no cells + (https://github.com/PyPSA/atlite/pull/525). + `v0.7.0 `__ (3rd October 2026) ======================================================================================= diff --git a/atlite/gis.py b/atlite/gis.py index 21efc60e..7e2286a0 100644 --- a/atlite/gis.py +++ b/atlite/gis.py @@ -459,7 +459,7 @@ def shape_availability( masked, transform = projected_mask( d["raster"], geometry, transform, shape, excluder.crs, **kwargs ) - if d["codes"]: + if d["codes"] is not None: if callable(d["codes"]): masked_ = d["codes"](masked).astype(bool) else: @@ -598,7 +598,7 @@ def add_raster( which takes the mask (np.array) as argument and performs a elementwise condition (must not change the shape). The function may not be an anonymous (lambda) function. - The default is 1. + The default is None, which excludes all non-zero cells. buffer : int, optional Buffer around the excluded areas in units of ExclusionContainer.crs. Use this to create a buffer around the excluded/included area. diff --git a/test/test_gis.py b/test/test_gis.py index 89210b33..e19a0d50 100755 --- a/test/test_gis.py +++ b/test/test_gis.py @@ -636,6 +636,23 @@ def test_shape_availability_exclude_raster_codes(ref, raster_codes): assert ratio == masked.sum() / masked.size +@pytest.mark.parametrize("codes", [0, np.array([0])]) +def test_shape_availability_exclude_raster_code_zero(ref, raster, codes): + """Code 0 is excluded like any other code, not treated as a missing code.""" + shapes = gpd.GeoSeries([box(X0, Y0, X1, Y1)], crs=ref.crs) + res = 0.01 + + excluder = ExclusionContainer(ref.crs, res=res) + excluder.add_raster(raster, codes=[0]) + expected, transform = shape_availability(shapes, excluder) + + excluder = ExclusionContainer(ref.crs, res=res) + excluder.add_raster(raster, codes=codes) + masked, transform = shape_availability(shapes, excluder) + assert (masked == expected).all() + assert round(masked.sum() / masked.size, 2) == raster_clip + + def test_plot_shape_availability(ref, raster): """Test plotting of shape availability.""" shapes = gpd.GeoSeries([box(X0, Y0, X1, Y1)], crs=ref.crs)