Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extension/datacube - added variable property #645

Merged
merged 4 commits into from
Oct 28, 2021
Merged
Changes from 2 commits
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
109 changes: 107 additions & 2 deletions pystac/extensions/datacube.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@

PREFIX: str = "cube:"
DIMENSIONS_PROP = PREFIX + "dimensions"
VARIABLES_PROP = PREFIX + "variables"

# Dimension properties
DIM_TYPE_PROP = "type"
DIM_DESC_PROP = "description"
DIM_AXIS_PROP = "axis"
DIM_EXTENT_PROP = "extent"
DIM_VALUES_PROP = "values"
DIM_DIMENSIONS_PROP = "dimensions"
thomafred marked this conversation as resolved.
Show resolved Hide resolved
thomafred marked this conversation as resolved.
Show resolved Hide resolved
DIM_STEP_PROP = "step"
DIM_REF_SYS_PROP = "reference_system"
DIM_UNIT_PROP = "unit"
Expand Down Expand Up @@ -398,6 +400,102 @@ def reference_system(self, v: Optional[Union[str, float, Dict[str, Any]]]) -> No
self.properties[DIM_REF_SYS_PROP] = v


class VariableType(str, Enum):
"""Variable object types"""

DATA = "data"
AUXILIARY = "auxiliary"


class Variable:
properties: Dict[str, Any]

def __init__(self, properties: Dict[str, Any]) -> None:
self.properties = properties

@property
def dimensions(self) -> List[str]:
"""The dimensions of the variable. Should refer to keys in the `cube:dimensions` object
thomafred marked this conversation as resolved.
Show resolved Hide resolved
or be an empty list if the variable has no dimensions"""
return get_required(
self.properties.get(DIM_DIMENSIONS_PROP),
"cube:variable",
DIM_DIMENSIONS_PROP,
)

@dimensions.setter
def dimensions(self, v: List[str]) -> None:
self.properties[DIM_DIMENSIONS_PROP] = v

@property
def var_type(self) -> Union[VariableType, str]:
"""Type of the variable, either `data` or `auxiliary`"""
thomafred marked this conversation as resolved.
Show resolved Hide resolved
return get_required(
self.properties.get(DIM_TYPE_PROP), "cube:variable", DIM_TYPE_PROP
)

@var_type.setter
def var_type(self, v: Union[VariableType, str]) -> None:
self.properties[DIM_TYPE_PROP] = v

@property
def description(self) -> Optional[str]:
"""Detailed multi-line description to explain the variable. `CommonMark 0.29
<http://commonmark.org/>`__ syntax MAY be used for rich text representation."""
return self.properties.get(DIM_DESC_PROP)

@description.setter
def description(self, v: Optional[str]) -> None:
if v is None:
self.properties.pop(DIM_DESC_PROP, None)
else:
self.properties[DIM_DESC_PROP] = v

@property
def extent(self) -> List[Union[float, str, None]]:
"""If the variable consists of `ordinal values
<https://en.wikipedia.org/wiki/Level_of_measurement#Ordinal_scale>`, the extent
(lower and upper bounds) of the values as two-dimensional array. Use `None` for
thomafred marked this conversation as resolved.
Show resolved Hide resolved
open intervals"""
return get_required(
self.properties.get(DIM_EXTENT_PROP), "cube:variable", DIM_EXTENT_PROP
)

@extent.setter
def extent(self, v: List[Union[float, str, None]]) -> None:
self.properties[DIM_EXTENT_PROP] = v

@property
def values(self) -> Optional[List[Union[float, str]]]:
"""A set of all potential values, especially useful for `nominal values
<https://en.wikipedia.org/wiki/Level_of_measurement#Nominal_level>`."""
return self.properties.get(DIM_VALUES_PROP)

@values.setter
def values(self, v: Optional[List[Union[float, str]]]) -> None:
if v is None:
self.properties.pop(DIM_VALUES_PROP)
else:
self.properties[DIM_VALUES_PROP] = v

@property
def unit(self) -> Optional[str]:
"""The unit of measurement for the data, preferably compliant to `UDUNITS-2
<https://ncics.org/portfolio/other-resources/udunits2/>` units (singular)"""
return self.properties.get(DIM_UNIT_PROP)

@unit.setter
def unit(self, v: Optional[str]) -> None:
if v is None:
self.properties.pop(DIM_UNIT_PROP)
else:
self.properties[DIM_UNIT_PROP] = v

@staticmethod
def from_dict(d: Dict[str, Any]) -> "Variable":
return Variable(d)


class DatacubeExtension(
Generic[T],
PropertiesExtension,
Expand All @@ -423,8 +521,6 @@ def apply(self, dimensions: Dict[str, Dimension]) -> None:
:class:`~pystac.Collection`, :class:`~pystac.Item` or :class:`~pystac.Asset`.

Args:
bands : A list of available bands where each item is a :class:`~Band`
object. If given, requires at least one band.
dimensions : Dictionary mapping dimension name to a :class:`Dimension`
object.
"""
Expand All @@ -442,6 +538,15 @@ def dimensions(self) -> Dict[str, Dimension]:
def dimensions(self, v: Dict[str, Dimension]) -> None:
self._set_property(DIMENSIONS_PROP, {k: dim.to_dict() for k, dim in v.items()})

@property
def variables(self) -> Optional[Dict[str, Variable]]:
"""Dictionary mapping variable name to a :class:`Variable` object."""
result = self._get_property(VARIABLES_PROP, Dict[str, Any])

if result is None:
return None
return {k: Variable.from_dict(v) for k, v in result.items()}

@classmethod
def get_schema_uri(cls) -> str:
return SCHEMA_URI
Expand Down