Skip to content

Commit

Permalink
Add DataCube.flatten_dimensions() and DataCube.unflatten_dimension
Browse files Browse the repository at this point in the history
  • Loading branch information
soxofaan committed Mar 9, 2022
1 parent 0ceb689 commit e20b6f7
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 2 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add support for comparison operators (`<`, `>`, `<=` and `>=`) in callback process building
- Added `Connection.describe_process()` to retrieve and show a single process

- Added `DataCube.flatten_dimensions()` and `DataCube.unflatten_dimension`
([Open-EO/openeo-processes#308](https://github.com/Open-EO/openeo-processes/issues/308), [Open-EO/openeo-processes#316](https://github.com/Open-EO/openeo-processes/pull/316))

### Changed

- Include openEO API error id automatically in exception message to simplify user support and post-mortem analysis.
- Use `Connection.default_timeout` (when set) also on version discovery request


### Removed

- Removed deprecated 'zonal_statistics' method from the 1.x version of the API.
Expand Down
49 changes: 49 additions & 0 deletions openeo/rest/datacube.py
Original file line number Diff line number Diff line change
Expand Up @@ -1834,3 +1834,52 @@ def fit_class_random_forest(
)
model = MlModel(graph=pgnode, connection=self._connection, metadata=None)
return model

def flatten_dimensions(self, dimensions: List[str], target_dimension: str, label_separator: Optional[str] = None):
"""
Combines multiple given dimensions into a single dimension by flattening the values
and merging the dimension labels with the given `label_separator`. Non-string dimension labels will
be converted to strings. This process is the opposite of the process :py:meth:`unflatten_dimension()`
but executing both processes subsequently doesn't necessarily create a data cube that
is equal to the original data cube.
.. warning:: experimental process: not generally supported, API subject to change.
:param dimensions: The names of the dimension to combine.
:param target_dimension: The name of a target dimension with a single dimension label to replace.
:param label_separator: The string that will be used as a separator for the concatenated dimension labels.
:return: A data cube with the new shape.
"""
return self.process(
process_id="flatten_dimensions",
arguments=dict_no_none(
data=THIS,
dimensions=dimensions,
target_dimension=target_dimension,
label_separator=label_separator,
),
)

def unflatten_dimension(self, dimension: str, target_dimensions: List[str], label_separator: Optional[str] = None):
"""
Splits a single dimension into multiple dimensions by systematically extracting values and splitting
the dimension labels by the given `label_separator`.
This process is the opposite of the process :py:meth:`flatten_dimensions()` but executing both processes
subsequently doesn't necessarily create a data cube that is equal to the original data cube.
.. warning:: experimental process: not generally supported, API subject to change.
:param dimension: The name of the dimension to split.
:param target_dimensions: The names of the target dimensions.
:param label_separator: The string that will be used as a separator to split the dimension labels.
:return: A data cube with the new shape.
"""
return self.process(
process_id="unflatten_dimension",
arguments=dict_no_none(
data=THIS,
dimension=dimension,
target_dimensions=target_dimensions,
label_separator=label_separator,
)
)
42 changes: 42 additions & 0 deletions tests/rest/datacube/test_datacube100.py
Original file line number Diff line number Diff line change
Expand Up @@ -1441,3 +1441,45 @@ def ndvi_scaled(cube, in_max=2, out_max=3):
assert im.flat_graph()["apply1"]["arguments"]["process"]["process_graph"]["linearscalerange1"]["arguments"] == {
'inputMax': 2, 'inputMin': 0, 'outputMax': 7, 'outputMin': 0, 'x': {'from_parameter': 'x'}
}


def test_flatten_dimensions(con100):
s2 = con100.load_collection("S2")
cube = s2.flatten_dimensions(dimensions=["t", "bands"], target_dimension="features")
assert _get_leaf_node(cube) == {
"process_id": "flatten_dimensions",
"arguments": {
"data": {"from_node": "loadcollection1"}, "dimensions": ["t", "bands"], "target_dimension": "features"
},
"result": True
}
cube = s2.flatten_dimensions(dimensions=["t", "bands"], target_dimension="features", label_separator="+")
assert _get_leaf_node(cube) == {
"process_id": "flatten_dimensions",
"arguments": {
"data": {"from_node": "loadcollection1"}, "dimensions": ["t", "bands"], "target_dimension": "features",
"label_separator": "+",
},
"result": True
}


def test_unflatten_dimension(con100):
s2 = con100.load_collection("S2")
cube = s2.unflatten_dimension(dimension="features", target_dimensions=["t", "bands"])
assert _get_leaf_node(cube) == {
"process_id": "unflatten_dimension",
"arguments": {
"data": {"from_node": "loadcollection1"}, "dimension": "features", "target_dimensions": ["t", "bands"],
},
"result": True
}
cube = s2.unflatten_dimension(dimension="features", target_dimensions=["t", "bands"], label_separator="+")
assert _get_leaf_node(cube) == {
"process_id": "unflatten_dimension",
"arguments": {
"data": {"from_node": "loadcollection1"}, "dimension": "features", "target_dimensions": ["t", "bands"],
"label_separator": "+",
},
"result": True
}

0 comments on commit e20b6f7

Please sign in to comment.