Server-side temporal aggregation with aggregate=¶
On openEO, aggregate=AggregationConfig(...) is a native aggregate_temporal_period node in the graph - the only backend where the aggregator costs no client compute. Here we load a plain Sentinel-2 collection (B04, B08) over a year and reduce it to a monthly mean server-side. The aggregator's pandas freq maps to an openEO calendar period and its op to an openEO reducer.
pip install earthlens[openeo]
Setup¶
A couple of stdlib imports plus the earthlens surface: the unified EarthLens entry point and AggregationConfig, the typed request that describes the temporal reduction.
import os
from pathlib import Path
from earthlens import EarthLens
from earthlens.aggregate import AggregationConfig
Credentials¶
openEO authenticates with CDSE via OIDC. The download cell below runs for real when credentials are present (env OPENEO_CLIENT_ID / OPENEO_CLIENT_SECRET, or a cached refresh token from a prior interactive login) and prints a skip note otherwise - so this notebook executes cleanly with or without secrets. See the Authentication page.
Detecting available credentials¶
has_openeo_credentials() reports whether any OIDC credential source is configured: a client-id/secret pair, a refresh-token env var, or a cached ~/.openeo from a prior interactive sign-in.
def has_openeo_credentials() -> bool:
"""Whether some openEO OIDC credential source is available."""
if os.environ.get("OPENEO_CLIENT_ID") and os.environ.get("OPENEO_CLIENT_SECRET"):
return True
if os.environ.get("OPENEO_REFRESH_TOKEN"):
return True
return (Path.home() / ".openeo").exists()
A graceful-skip wrapper¶
run_or_skip() triggers the live download() only when credentials exist, and otherwise prints a skip note. This keeps the notebook executing top-to-bottom with no errors whether or not CDSE OIDC credentials are configured, so the docs build never needs secrets.
def run_or_skip(facade, **download_kwargs):
"""Run the live download when credentials exist, else print a skip note.
Keeps the notebook executing top-to-bottom with no errors whether or not
CDSE OIDC credentials are configured (so the docs build never needs secrets).
"""
if not has_openeo_credentials():
print(
"No openEO OIDC credentials found - skipping the live download.\n"
"Set OPENEO_CLIENT_ID / OPENEO_CLIENT_SECRET (headless) or sign in once\n"
"interactively (see the Authentication page) to run this cell for real."
)
return []
paths = facade.download(**download_kwargs)
for path in paths:
print(path)
return paths
Build the request¶
Construct the EarthLens facade for the openEO backend - a Sentinel-2 L2A collection (B04, B08) over 2023 across a small AOI off the Spanish coast, capped at 40% cloud cover.
facade = EarthLens(
data_source='openeo',
dataset='sentinel-2-l2a',
variables=['B04', 'B08'],
start='2023-01-01',
end='2023-12-31',
aoi=[3.67, 40.40, 3.72, 40.45],
path='data/openeo-aggregate',
max_cloud_cover=40,
)
The aggregation config¶
AggregationConfig(freq='1MS', op='mean') asks for a monthly mean. On openEO this becomes a native aggregate_temporal_period graph node.
config = AggregationConfig(freq='1MS', op='mean')
config
How it maps to openEO¶
The aggregator's pandas-style fields translate to openEO terms: the mapping is 1MS -> month and mean -> mean.
from earthlens.openeo._helpers import period_for, reducer_for
print('period:', period_for(config.freq))
print('reducer:', reducer_for(config.op))
Download (server-side execution)¶
Hand the request and the aggregate=config to run_or_skip(). With credentials it executes the monthly-mean reduction server-side on openEO and returns the written paths; without them it prints the skip note.
paths = run_or_skip(facade, aggregate=config)
paths