Skip to content

Commit

Permalink
Merge branch 'spatial_extent_param'
Browse files Browse the repository at this point in the history
  • Loading branch information
soxofaan committed Sep 16, 2024
2 parents dcaf0c3 + a436592 commit 33a1860
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `load_stac`/`metadata_from_stac`: add support for extracting actual temporal dimension metadata ([#567](https://github.com/Open-EO/openeo-python-client/issues/567))
- `MultiBackendJobManager`: add `cancel_running_job_after` option to automatically cancel jobs that are running for too long ([#590](https://github.com/Open-EO/openeo-python-client/issues/590))
- Added `openeo.api.process.Parameter` helper to easily create a "spatial_extent" UDP parameter

### Changed

- `MultiBackendJobManager`: changed job metadata storage API, to enable working with large databases
- `MultiBackendJobManager`: changed job metadata storage API, to enable working with large databases

### Removed

Expand Down
82 changes: 81 additions & 1 deletion openeo/api/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(
self,
name: str,
description: Optional[str] = None,
schema: Union[dict, str, None] = None,
schema: Union[list, dict, str, None] = None,
default=_DEFAULT_UNDEFINED,
optional: Optional[bool] = None,
):
Expand Down Expand Up @@ -279,6 +279,86 @@ def bounding_box(
}
return cls(name=name, description=description, schema=schema, **kwargs)

_spatial_extent_description = """Limits the data to process to the specified bounding box or polygons.
For raster data, the process loads the pixel into the data cube if the point at the pixel center intersects with the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC).
For vector data, the process loads the geometry into the data cube if the geometry is fully within the bounding box or any of the polygons (as defined in the Simple Features standard by the OGC). Empty geometries may only be in the data cube if no spatial extent has been provided.
Empty geometries are ignored.
Set this parameter to null to set no limit for the spatial extent. """

@classmethod
def spatial_extent(
cls,
name: str = "spatial_extent",
description: str = _spatial_extent_description,
**kwargs,
) -> Parameter:
"""
Helper to easily create a 'spatial_extent' parameter, which is compatible with the 'load_collection' argument of
the same name. This allows to conveniently create user-defined processes that can be applied to a bounding box and vector data
for spatial filtering. It is also possible for users to set to null, and define spatial filtering using other processes.
:param name: parameter name, which will be used to assign concrete values to.
It is recommended to stick to the convention of snake case naming (using lowercase with underscores).
:param description: human-readable description of the parameter.
See the generic :py:class:`Parameter` constructor for information on additional arguments (except ``schema``).
.. versionadded:: 0.32.0
"""
schema = [
{
"title": "Bounding Box",
"type": "object",
"subtype": "bounding-box",
"required": ["west", "south", "east", "north"],
"properties": {
"west": {"description": "West (lower left corner, coordinate axis 1).", "type": "number"},
"south": {"description": "South (lower left corner, coordinate axis 2).", "type": "number"},
"east": {"description": "East (upper right corner, coordinate axis 1).", "type": "number"},
"north": {"description": "North (upper right corner, coordinate axis 2).", "type": "number"},
"base": {
"description": "Base (optional, lower left corner, coordinate axis 3).",
"type": ["number", "null"],
"default": None,
},
"height": {
"description": "Height (optional, upper right corner, coordinate axis 3).",
"type": ["number", "null"],
"default": None,
},
"crs": {
"description": "Coordinate reference system of the extent, specified as as [EPSG code](http://www.epsg-registry.org/) or [WKT2 CRS string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html). Defaults to `4326` (EPSG code 4326) unless the client explicitly requests a different coordinate reference system.",
"anyOf": [
{
"title": "EPSG Code",
"type": "integer",
"subtype": "epsg-code",
"minimum": 1000,
"examples": [3857],
},
{"title": "WKT2", "type": "string", "subtype": "wkt2-definition"},
],
"default": 4326,
},
},
},
{
"title": "Vector data cube",
"description": "Limits the data cube to the bounding box of the given geometries in the vector data cube. For raster data, all pixels inside the bounding box that do not intersect with any of the polygons will be set to no data (`null`). Empty geometries are ignored.",
"type": "object",
"subtype": "datacube",
"dimensions": [{"type": "geometry"}],
},
{
"title": "No filter",
"description": "Don't filter spatially. All data is included in the data cube.",
"type": "null",
},
]
return cls(name=name, description=description, schema=schema, **kwargs)

@classmethod
def date(cls, name: str, description: str = "A date.", **kwargs) -> Parameter:
"""
Expand Down
87 changes: 87 additions & 0 deletions tests/api/test_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,90 @@ def test_parameter_reencode(kwargs, expected):
assert d == expected
q = Parameter(**d)
assert q.to_dict() == expected


def test_parameter_spatial_extent():
assert Parameter.spatial_extent().to_dict() == {
"description": "Limits the data to process to the specified bounding box or "
"polygons.\n"
"\n"
"For raster data, the process loads the pixel into the data "
"cube if the point at the pixel center intersects with the "
"bounding box or any of the polygons (as defined in the Simple "
"Features standard by the OGC).\n"
"For vector data, the process loads the geometry into the data "
"cube if the geometry is fully within the bounding box or any "
"of the polygons (as defined in the Simple Features standard "
"by the OGC). Empty geometries may only be in the data cube if "
"no spatial extent has been provided.\n"
"\n"
"Empty geometries are ignored.\n"
"Set this parameter to null to set no limit for the spatial "
"extent. ",
"name": "spatial_extent",
"schema": [
{
"properties": {
"base": {
"default": None,
"description": "Base (optional, lower " "left corner, coordinate " "axis 3).",
"type": ["number", "null"],
},
"crs": {
"anyOf": [
{
"examples": [3857],
"minimum": 1000,
"subtype": "epsg-code",
"title": "EPSG Code",
"type": "integer",
},
{"subtype": "wkt2-definition", "title": "WKT2", "type": "string"},
],
"default": 4326,
"description": "Coordinate reference "
"system of the extent, "
"specified as as [EPSG "
"code](http://www.epsg-registry.org/) "
"or [WKT2 CRS "
"string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html). "
"Defaults to `4326` (EPSG "
"code 4326) unless the "
"client explicitly requests "
"a different coordinate "
"reference system.",
},
"east": {"description": "East (upper right corner, " "coordinate axis 1).", "type": "number"},
"height": {
"default": None,
"description": "Height (optional, upper " "right corner, " "coordinate axis 3).",
"type": ["number", "null"],
},
"north": {"description": "North (upper right " "corner, coordinate axis " "2).", "type": "number"},
"south": {"description": "South (lower left " "corner, coordinate axis " "2).", "type": "number"},
"west": {"description": "West (lower left corner, " "coordinate axis 1).", "type": "number"},
},
"required": ["west", "south", "east", "north"],
"subtype": "bounding-box",
"title": "Bounding Box",
"type": "object",
},
{
"description": "Limits the data cube to the bounding box of the "
"given geometries in the vector data cube. For "
"raster data, all pixels inside the bounding box "
"that do not intersect with any of the polygons "
"will be set to no data (`null`). Empty geometries "
"are ignored.",
"dimensions": [{"type": "geometry"}],
"subtype": "datacube",
"title": "Vector data cube",
"type": "object",
},
{
"description": "Don't filter spatially. All data is included in " "the data cube.",
"title": "No filter",
"type": "null",
},
],
}

0 comments on commit 33a1860

Please sign in to comment.