Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion openeo_processes_dask/process_implementations/cubes/indices.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import numpy as np
import xarray as xr

from openeo_processes_dask.process_implementations.data_model import RasterCube
Expand All @@ -12,6 +13,47 @@
__all__ = ["ndvi"]


def _dummy_value(dtype):
"""A sensible 'missing' fill value for a given numpy dtype."""
if np.issubdtype(dtype, np.floating):
return np.nan
if np.issubdtype(dtype, np.datetime64):
return np.datetime64("NaT")
if np.issubdtype(dtype, np.timedelta64):
return np.timedelta64("NaT")
if np.issubdtype(dtype, np.integer):
return -1 # ints can't hold NaN
if np.issubdtype(dtype, np.bool_):
return False
return "" # str / object


def _add_missing_coords(target, reference, dim):
Comment thread
jonas-hurst marked this conversation as resolved.
Resolved
"""
Ensure `target` has every coordinate that `reference` has.
Missing coordinates are created with a dummy value
"""
missing = {}
for name, coord in reference.coords.items():
if name in target.coords:
continue

fill = _dummy_value(coord.dtype)

if coord.dims == (): # scalar coordinate
Comment thread
jonas-hurst marked this conversation as resolved.
Resolved
missing[name] = ((), np.array(fill, dtype=coord.dtype))

elif coord.dims == (dim,): # coordinate along concat dim
missing[name] = (dim, np.full(target.sizes[dim], fill, dtype=coord.dtype))

elif all(d in target.dims for d in coord.dims): # other dims
shape = tuple(target.sizes[d] for d in coord.dims)
missing[name] = (coord.dims, np.full(shape, fill, dtype=coord.dtype))
Comment thread
jonas-hurst marked this conversation as resolved.
Resolved
# else: dims don't exist in target -> can't sensibly create it, skip

return target.assign_coords(**missing) if missing else target


def ndvi(data: RasterCube, nir="nir", red="red", target_band=None):
if len(data.openeo.band_dims) == 0:
raise DimensionAmbiguous(
Expand Down Expand Up @@ -54,6 +96,10 @@ def ndvi(data: RasterCube, nir="nir", red="red", target_band=None):
if target_band in data.coords:
raise BandExists("A band with the specified target name exists.")
nd = nd.expand_dims(band_dim).assign_coords({band_dim: [target_band]})
nd = xr.merge([data, nd])

# add potentially missing coords from data to nd, so that xr.concat works
nd = _add_missing_coords(nd, data, band_dim)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 4 consecutive assignments to a variable called "nd" (which I assume is short for normalized difference), and it seems unlikely that all 4 are the normalized difference.

If you rewrite this as:

thing = _add_missing_coords(nd.expand_dims(band_dim).assign_coords({band_dim: [target_band]}), data, band_dim)
nd = xr.concat([data, thing], dim=band_dim)

we can reduce that to 2 consecutive assignments, and the surrounding code still works.

(I don't know what "thing" should be called instead, but you probably know what it is and can name it properly since you're in the process of modifying this code.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagree. Normalized difference is first computed, then dims and coords are changed to match the original datacube to which it will be added.
Also, your proposed change limits readability.

nd = xr.concat([data, nd], dim=band_dim)

nd.attrs = data.attrs
return nd
4 changes: 4 additions & 0 deletions tests/test_indices.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import numpy as np
import pytest
import xarray as xr

from openeo_processes_dask.process_implementations.cubes.indices import ndvi
from openeo_processes_dask.process_implementations.exceptions import (
Expand Down Expand Up @@ -73,11 +74,14 @@ def test_ndvi(temporal_interval, bounding_box, random_raster_data, process_regis

target_band = "yay"
output_with_extra_dim = ndvi(input_cube, target_band=target_band)
assert isinstance(output_with_extra_dim, xr.DataArray)
assert len(output_with_extra_dim.dims) == len(output.dims) + 1
assert (
len(output_with_extra_dim.coords[band_dim])
== len(input_cube.coords[band_dim]) + 1
)
assert output_with_extra_dim.coords[band_dim].values[-1] == target_band
assert output_with_extra_dim.coords["common_name"][-1] == ""

with pytest.raises(BandExists):
output_with_extra_dim = ndvi(input_cube, target_band="t")
Loading