PACE ocean-colour chlorophyll (NASA Earthdata)¶
Download a daily PACE OCI Level-3 mapped chlorophyll-a field from the OB.DAAC and map it on a log scale. This is a gridded raster product, fetched through one Earthdata Login.
Live query — needs the
[earthdata]extra and EDL credentials.
Setup¶
Import the unified EarthLens entry point and prepare a local output directory for the downloaded granule.
from pathlib import Path
from earthlens.core import EarthLens
OUT_DIR = Path('earthdata_output')
OUT_DIR.mkdir(exist_ok=True)
1 · Download the chlorophyll granule¶
Earthdata is a raster backend, so download() writes the granule(s) to disk and returns the list of written paths. We build the request first — the dataset, the chlor_a variable, a single day, and a global-ish bounding box.
Chlorophyll ships inside PACE's Level-3 mapped biogeochemistry collection, PACE_OCI_L3M_BGC, alongside poc, pic and carbon_phyto — there is no standalone chlorophyll collection to ask for.
ocean = EarthLens(
data_source='earthdata',
dataset='PACE_OCI_L3M_BGC',
variables=['chlor_a'],
start='2024-06-01',
end='2024-06-01',
aoi=[-180.0, -60.0, 180.0, 60.0],
path=OUT_DIR,
)
One date does not mean one file: an L3M collection publishes several aggregations of the same day — daily, 8-day and monthly — each at both 0.1° and 4 km. The request therefore returns six granules, so we pick the one we actually want by name instead of trusting the order of the list.
paths = ocean.download(progress_bar=False)
print(len(paths), 'granule(s):')
for p in paths:
print(' ', Path(p).name)
granule = next(p for p in paths if '.DAY.' in Path(p).name and '0p1deg' in Path(p).name)
print('\nusing:', Path(granule).name)
2 · Map the chlorophyll field¶
Open the granule with pyramids and plot chlor_a on a logarithmic colour scale — chlorophyll spans several orders of magnitude, so a log scale keeps both clear open-ocean water and productive coastal blooms legible.
from pyramids.netcdf import NetCDF
from pyramids.plot import ColorBar, ColorScaling
nc = NetCDF.read_file(granule, read_only=True)
print('variables:', nc.variable_names)
chl = nc.get_variable('chlor_a')
stats = chl.stats(approx_ok=False)
print(f'grid {chl.rows} x {chl.columns}, epsg {chl.epsg}')
print(
f'chlor_a min/max: {float(stats["min"].iloc[0]):.3f} / {float(stats["max"].iloc[0]):.3f} mg m-3'
)
# chlorophyll spans orders of magnitude, so a log scale is the readable one.
chl.plot(
cmap='viridis',
color=ColorScaling.log(),
colorbar=ColorBar(label='chlorophyll-a (mg m-3)'),
title='PACE OCI chlorophyll-a, 2024-06-01',
)
nc.close()