From 34a10accdad4d672519953685837928b598712d7 Mon Sep 17 00:00:00 2001 From: nicolasK Date: Thu, 12 Dec 2024 17:26:49 +0100 Subject: [PATCH 1/5] fix(zonal_stats) : mode and timeless dimension --- docs/CHANGELOG.md | 7 +++++++ earthdaily/__init__.py | 2 +- .../earthdatastore/cube_utils/_zonal.py | 21 +++++++------------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5e3d420c..b890bc33 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.3] - 2024-12-10 + +### Fixed + +- `mode` in `zonal_stats` +- missing support for `zonal_stats` when dataset had no time dimension + ## [0.3.2] - 2024-12-10 ### Added diff --git a/earthdaily/__init__.py b/earthdaily/__init__.py index e6d96563..5f8e8138 100644 --- a/earthdaily/__init__.py +++ b/earthdaily/__init__.py @@ -7,7 +7,7 @@ # to hide warnings from rioxarray or nano seconds conversion # warnings.filterwarnings("ignore") -__version__ = "0.3.2" +__version__ = "0.3.3" def EarthDataStore( diff --git a/earthdaily/earthdatastore/cube_utils/_zonal.py b/earthdaily/earthdatastore/cube_utils/_zonal.py index 9c3185f2..92062e50 100644 --- a/earthdaily/earthdatastore/cube_utils/_zonal.py +++ b/earthdaily/earthdatastore/cube_utils/_zonal.py @@ -14,7 +14,7 @@ from . import custom_reducers from .preprocessing import rasterize from scipy.sparse import csr_matrix - +from scipy.stats import mode def _compute_M(data): cols = np.arange(data.size) @@ -25,14 +25,6 @@ def _indices_sparse(data): M = _compute_M(data) return [np.unravel_index(row.data, data.shape) for row in M] - -def _np_mode(arr, **kwargs): - values, counts = np.unique(arr, return_counts=True) - isnan = np.isnan(values) - values, counts = values[~isnan], counts[~isnan] - return values[np.argmax(counts)] - - def datacube_time_stats(datacube, operations): datacube = datacube.groupby("time") stats = [] @@ -76,8 +68,11 @@ def _zonal_stats_ufunc(dataset, positions, reducers): field_stats = [] for reducer in reducers: field_arr = dataset[(...,) + tuple(positions[idx])] - func = f"nan{reducer}" if hasattr(np, f"nan{reducer}") else reducer - field_arr = getattr(np, func)(field_arr, axis=-1) + if reducer == 'mode': + field_arr = mode(field_arr, axis=-1, nan_policy="omit").mode + else: + func = f"nan{reducer}" if hasattr(np, f"nan{reducer}") else reducer + field_arr = getattr(np, func)(field_arr, axis=-1) field_stats.append(field_arr) field_stats = np.asarray(field_stats) zs.append(field_stats) @@ -187,8 +182,8 @@ def _loop_time_chunks(dataset, method, smart_load, time_chunks): positions = [np.asarray(yx_pos[i + 1]) for i in np.arange(geoms.shape[0])] positions = [position for position in positions if position.size > 0] del yx_pos - time_chunks = _memory_time_chunks(dataset, memory) - if smart_load: + if "time" in dataset.dims and smart_load: + time_chunks = _memory_time_chunks(dataset, memory) zs = xr.concat( [ z From 045c60e68b169489b315c6810bb0ab32751ca986 Mon Sep 17 00:00:00 2001 From: nkarasiak Date: Thu, 12 Dec 2024 16:27:22 +0000 Subject: [PATCH 2/5] style(ruff) : automatic lint/format --- earthdaily/earthdatastore/cube_utils/_zonal.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/earthdaily/earthdatastore/cube_utils/_zonal.py b/earthdaily/earthdatastore/cube_utils/_zonal.py index 92062e50..ae42df4c 100644 --- a/earthdaily/earthdatastore/cube_utils/_zonal.py +++ b/earthdaily/earthdatastore/cube_utils/_zonal.py @@ -16,6 +16,7 @@ from scipy.sparse import csr_matrix from scipy.stats import mode + def _compute_M(data): cols = np.arange(data.size) return csr_matrix((cols, (data.ravel(), cols)), shape=(data.max() + 1, data.size)) @@ -25,6 +26,7 @@ def _indices_sparse(data): M = _compute_M(data) return [np.unravel_index(row.data, data.shape) for row in M] + def datacube_time_stats(datacube, operations): datacube = datacube.groupby("time") stats = [] @@ -68,7 +70,7 @@ def _zonal_stats_ufunc(dataset, positions, reducers): field_stats = [] for reducer in reducers: field_arr = dataset[(...,) + tuple(positions[idx])] - if reducer == 'mode': + if reducer == "mode": field_arr = mode(field_arr, axis=-1, nan_policy="omit").mode else: func = f"nan{reducer}" if hasattr(np, f"nan{reducer}") else reducer From 34b7d270d0730a0c519542ef354c4fc4b4ab31b1 Mon Sep 17 00:00:00 2001 From: nicolasK Date: Thu, 12 Dec 2024 17:32:21 +0100 Subject: [PATCH 3/5] fix(requirements) : gdal --- requirements.yml | 2 +- requirements_dev.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.yml b/requirements.yml index c8039e41..4762540e 100644 --- a/requirements.yml +++ b/requirements.yml @@ -6,7 +6,7 @@ dependencies: - numpy - matplotlib - joblib -- gdal=3.7.3 +- gdal - scipy - psutil - pystac-client diff --git a/requirements_dev.yml b/requirements_dev.yml index 6fa95835..7cd92cc0 100644 --- a/requirements_dev.yml +++ b/requirements_dev.yml @@ -6,7 +6,7 @@ dependencies: - numpy - pandas - libtiff - - gdal=3.7.3 + - gdal - geopandas>=0.11 - dask>=2024.3 - shapely From d063788455e9ce27814519253d409ec1ca3f646c Mon Sep 17 00:00:00 2001 From: nicolasK Date: Fri, 13 Dec 2024 09:52:45 +0100 Subject: [PATCH 4/5] refactor(accessor) : now private --- earthdaily/__init__.py | 2 +- earthdaily/accessor/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/earthdaily/__init__.py b/earthdaily/__init__.py index 5f8e8138..d022c200 100644 --- a/earthdaily/__init__.py +++ b/earthdaily/__init__.py @@ -1,7 +1,7 @@ from typing import Optional from pathlib import Path from . import earthdatastore, datasets -from .accessor import EarthDailyAccessorDataArray, EarthDailyAccessorDataset +from .accessor import __EarthDailyAccessorDataArray, __EarthDailyAccessorDataset # import warnings # to hide warnings from rioxarray or nano seconds conversion diff --git a/earthdaily/accessor/__init__.py b/earthdaily/accessor/__init__.py index a01f5b1c..77adb19b 100644 --- a/earthdaily/accessor/__init__.py +++ b/earthdaily/accessor/__init__.py @@ -78,7 +78,7 @@ def _xr_rio_clip(datacube, geom): @xr.register_dataarray_accessor("ed") -class EarthDailyAccessorDataArray: +class __EarthDailyAccessorDataArray: def __init__(self, xarray_obj): self._obj = xarray_obj @@ -206,7 +206,7 @@ def drop_unfrozen_coords(self, keep_spatial_ref=True): @xr.register_dataset_accessor("ed") -class EarthDailyAccessorDataset(EarthDailyAccessorDataArray): +class __EarthDailyAccessorDataset(__EarthDailyAccessorDataArray): def __init__(self, xarray_obj): self._obj = xarray_obj From 8e8e1632e0f56c94061af7f40dbe8c3a7551bb97 Mon Sep 17 00:00:00 2001 From: nicolasK Date: Fri, 13 Dec 2024 09:55:29 +0100 Subject: [PATCH 5/5] chore(changelog) --- docs/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b890bc33..a8003d3c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,13 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.3.3] - 2024-12-10 +## [0.3.3] - 2024-12-13 ### Fixed - `mode` in `zonal_stats` - missing support for `zonal_stats` when dataset had no time dimension +### Changed + +- xarray accessor classes are now privates to avoid having them in autocomplementation. + ## [0.3.2] - 2024-12-10 ### Added