Skip to content

workflows module

Coastal workflow presets for hyperspectral datasets.

WorkflowPreset dataclass

Describe a coastal workflow preset.

Parameters:

Name Type Description Default
name str

Workflow identifier.

required
description str

Human-readable workflow description.

required
kind str

Workflow algorithm kind.

required
wavelengths Dict[str, float]

Named wavelength parameters in nanometers.

required
variable Optional[str]

Optional default data variable.

None
Source code in hypercoast/workflows.py
@dataclass(frozen=True)
class WorkflowPreset:
    """Describe a coastal workflow preset.

    Args:
        name: Workflow identifier.
        description: Human-readable workflow description.
        kind: Workflow algorithm kind.
        wavelengths: Named wavelength parameters in nanometers.
        variable: Optional default data variable.
    """

    name: str
    description: str
    kind: str
    wavelengths: Dict[str, float]
    variable: Optional[str] = None

    def as_dict(self) -> Dict[str, Any]:
        """Return serializable workflow metadata."""
        return asdict(self)

as_dict(self)

Return serializable workflow metadata.

Source code in hypercoast/workflows.py
def as_dict(self) -> Dict[str, Any]:
    """Return serializable workflow metadata."""
    return asdict(self)

apply_workflow(data, workflow, variable=None, **kwargs)

Apply a named coastal workflow to hyperspectral data.

Parameters:

Name Type Description Default
data xr.Dataset | xr.DataArray

Input dataset or data array.

required
workflow str

Workflow preset name.

required
variable Optional[str]

Optional data variable for xarray datasets.

None
**kwargs Any

Optional workflow overrides.

{}

Returns:

Type Description
xr.DataArray

Workflow output.

Source code in hypercoast/workflows.py
def apply_workflow(
    data: xr.Dataset | xr.DataArray,
    workflow: str,
    variable: Optional[str] = None,
    **kwargs: Any,
) -> xr.DataArray:
    """Apply a named coastal workflow to hyperspectral data.

    Args:
        data: Input dataset or data array.
        workflow: Workflow preset name.
        variable: Optional data variable for xarray datasets.
        **kwargs: Optional workflow overrides.

    Returns:
        xr.DataArray: Workflow output.
    """
    key = workflow.lower().strip()
    if key not in WORKFLOW_PRESETS:
        available = ", ".join(sorted(WORKFLOW_PRESETS))
        raise KeyError(
            f"Unknown workflow '{workflow}'. Available workflows: {available}"
        )

    preset = WORKFLOW_PRESETS[key]
    da = _as_data_array(data, variable or preset.variable)
    wavelengths = dict(preset.wavelengths)
    wavelengths.update(kwargs.pop("wavelengths", {}) or {})

    if preset.kind == "normalized_difference":
        return normalized_difference(da, wavelengths["a"], wavelengths["b"])
    if preset.kind == "ratio":
        return band_ratio(da, wavelengths["a"], wavelengths["b"])
    if preset.kind == "spectral_anomaly":
        return spectral_anomaly(da)
    raise ValueError(f"Unsupported workflow kind: {preset.kind}")

band_ratio(data, numerator, denominator, variable=None)

Calculate a ratio between two wavelengths.

Parameters:

Name Type Description Default
data xr.Dataset | xr.DataArray

Input dataset or data array.

required
numerator float

Numerator wavelength in nanometers.

required
denominator float

Denominator wavelength in nanometers.

required
variable Optional[str]

Optional data variable for xarray datasets.

None

Returns:

Type Description
xr.DataArray

Ratio output.

Source code in hypercoast/workflows.py
def band_ratio(
    data: xr.Dataset | xr.DataArray,
    numerator: float,
    denominator: float,
    variable: Optional[str] = None,
) -> xr.DataArray:
    """Calculate a ratio between two wavelengths.

    Args:
        data: Input dataset or data array.
        numerator: Numerator wavelength in nanometers.
        denominator: Denominator wavelength in nanometers.
        variable: Optional data variable for xarray datasets.

    Returns:
        xr.DataArray: Ratio output.
    """
    da = _as_data_array(data, variable)
    a = _select_wavelength(da, numerator)
    b = _select_wavelength(da, denominator)
    with np.errstate(divide="ignore", invalid="ignore"):
        result = a / b
    result.name = f"ratio_{int(numerator)}_{int(denominator)}"
    return result

list_workflows()

Return serializable workflow preset metadata.

Returns:

Type Description
dict

Mapping of workflow names to metadata.

Source code in hypercoast/workflows.py
def list_workflows() -> Dict[str, Dict[str, Any]]:
    """Return serializable workflow preset metadata.

    Returns:
        dict: Mapping of workflow names to metadata.
    """
    return {name: preset.as_dict() for name, preset in WORKFLOW_PRESETS.items()}

normalized_difference(data, wavelength_a, wavelength_b, variable=None)

Calculate a normalized difference between two wavelengths.

Parameters:

Name Type Description Default
data xr.Dataset | xr.DataArray

Input dataset or data array.

required
wavelength_a float

First wavelength in nanometers.

required
wavelength_b float

Second wavelength in nanometers.

required
variable Optional[str]

Optional data variable for xarray datasets.

None

Returns:

Type Description
xr.DataArray

Normalized difference output.

Source code in hypercoast/workflows.py
def normalized_difference(
    data: xr.Dataset | xr.DataArray,
    wavelength_a: float,
    wavelength_b: float,
    variable: Optional[str] = None,
) -> xr.DataArray:
    """Calculate a normalized difference between two wavelengths.

    Args:
        data: Input dataset or data array.
        wavelength_a: First wavelength in nanometers.
        wavelength_b: Second wavelength in nanometers.
        variable: Optional data variable for xarray datasets.

    Returns:
        xr.DataArray: Normalized difference output.
    """
    da = _as_data_array(data, variable)
    a = _select_wavelength(da, wavelength_a)
    b = _select_wavelength(da, wavelength_b)
    with np.errstate(divide="ignore", invalid="ignore"):
        result = (a - b) / (a + b)
    result.name = f"nd_{int(wavelength_a)}_{int(wavelength_b)}"
    return result

spectral_anomaly(data, variable=None)

Calculate the maximum absolute spectral z-score per pixel.

Parameters:

Name Type Description Default
data xr.Dataset | xr.DataArray

Input dataset or data array.

required
variable Optional[str]

Optional data variable for xarray datasets.

None

Returns:

Type Description
xr.DataArray

Maximum absolute spectral anomaly score.

Source code in hypercoast/workflows.py
def spectral_anomaly(
    data: xr.Dataset | xr.DataArray,
    variable: Optional[str] = None,
) -> xr.DataArray:
    """Calculate the maximum absolute spectral z-score per pixel.

    Args:
        data: Input dataset or data array.
        variable: Optional data variable for xarray datasets.

    Returns:
        xr.DataArray: Maximum absolute spectral anomaly score.
    """
    da = _as_data_array(data, variable)
    dim = _wavelength_dim(da)
    mean = da.mean(dim=dim, skipna=True)
    std = da.std(dim=dim, skipna=True)
    with np.errstate(divide="ignore", invalid="ignore"):
        zscore = (da - mean) / std
    result = np.abs(zscore).max(dim=dim, skipna=True)
    result.name = "spectral_anomaly"
    return result