Visualizing AVIRIS data interactively with HyperCoast¶
This notebook demonstrates how to search and visualize the newer ORNL DAAC AVIRIS-3 and AVIRIS-5 L2A orthocorrected surface reflectance products. These products include a chunked/compressed NetCDF reflectance cube (*_RFL_ORT.nc) and a quicklook Cloud Optimized GeoTIFF (*_RFL_ORT_QL.tif) that can be streamed as the map preview through NASA TiTiler CMR.
For more information about AVIRIS, please visit the links below:
- https://aviris.jpl.nasa.gov/
- https://aviris.jpl.nasa.gov/dataportal/
- https://popo.jpl.nasa.gov/mmgis-aviris/?s=ujooa
- https://github.com/ornldaac/deltax_workshop_2022/tree/main
- https://github.com/jjmcnelis/aviris-ng-notebooks/tree/master
The AVIRIS data are protected Earthdata assets. Log in with a NASA Earthdata account before streaming or downloading.
# %pip install "hypercoast[extra]" earthaccess s3fs h5netcdf
import contextlib
import io
import os
import earthaccess
import hypercoast
Authenticate with Earthdata. Use strategy="interactive" in notebooks when you have not already saved credentials.
earthaccess.login(strategy="interactive", persist=True)
Search the AVIRIS-3 L2A reflectance collection. To use AVIRIS-5 instead, set short_name="AV5_L2A_RFL_2484".
results, gdf = hypercoast.search_aviris(
short_name="AV3_L2A_RFL_2357",
count=10,
return_gdf=True,
)
gdf.head()
Inspect the reflectance NetCDF, uncertainty NetCDF, and quicklook COG assets for the first granule.
granule = results[0]
rfl_url = hypercoast.get_aviris_asset_url(granule, asset="RFL_ORT")
unc_url = hypercoast.get_aviris_asset_url(granule, asset="UNC_ORT")
quicklook_url = hypercoast.get_aviris_asset_url(granule, asset="RFL_ORT_QL")
rfl_url, unc_url, quicklook_url
For direct S3 streaming, request temporary ORNL DAAC credentials. Direct S3 access works best from AWS us-west-2. When direct S3 is not available, earthaccess.open() provides authenticated HTTPS file-like objects without downloading the full granule.
credentials = earthaccess.get_s3_credentials(results=results)
storage_options = {
"key": credentials["accessKeyId"],
"secret": credentials["secretAccessKey"],
"token": credentials["sessionToken"],
"client_kwargs": {"region_name": "us-west-2"},
}
# Make the credentials available to raster clients used by the map preview.
os.environ["AWS_ACCESS_KEY_ID"] = credentials["accessKeyId"]
os.environ["AWS_SECRET_ACCESS_KEY"] = credentials["secretAccessKey"]
os.environ["AWS_SESSION_TOKEN"] = credentials["sessionToken"]
Open the reflectance NetCDF without downloading the full cube for metadata inspection. HyperCoast normalizes the AVIRIS-3/5 NetCDF layout to y, x, and wavelength dimensions. The fallback keeps the notebook runnable from local machines that cannot reach NASA's in-region S3 buckets directly. Remote NetCDF point reads can be slow because the reflectance cube is chunked in large spatial blocks, so use a local NetCDF file for interactive spectral extraction.
rfl_s3_url = hypercoast.get_aviris_asset_url(
granule,
asset="RFL_ORT",
prefer_s3=True,
)
try:
ds = hypercoast.read_aviris(
rfl_s3_url,
storage_options=storage_options,
)
dataset_source = "direct S3"
except PermissionError:
print("Direct S3 is not available; using authenticated HTTPS instead.")
with (
contextlib.redirect_stdout(io.StringIO()),
contextlib.redirect_stderr(io.StringIO()),
):
files = earthaccess.open(results[:1])
rfl_file = next(
file
for file in files
if str(getattr(file, "full_name", "")).endswith("_RFL_ORT.nc")
)
ds = hypercoast.read_aviris(rfl_file)
dataset_source = "authenticated HTTPS"
ds
Display the quicklook COG through NASA TiTiler CMR. The footprint outline and explicit zoom_to_bounds() call make the scene extent visible on the map without reading the remote NetCDF cube for every map click.
m = hypercoast.Map()
m.add_aviris(granule, layer_name="AVIRIS-3 quicklook")
bounds = hypercoast.get_aviris_bounds(granule)
if bounds is not None:
m.add_gdf(
gdf.iloc[[0]],
layer_name="AVIRIS-3 footprint",
style={"color": "#ffcc00", "weight": 2, "fillOpacity": 0.0},
)
m.zoom_to_bounds(bounds)
m
For interactive spectral extraction, download the reflectance NetCDF locally and attach that local dataset to the map. This avoids slow remote chunk reads when clicking individual pixels.
local_files = earthaccess.download(rfl_url, local_path="data", provider="ORNL_CLOUD")
if isinstance(local_files, str):
local_files = [local_files]
local_rfl = next(path for path in local_files if str(path).endswith("_RFL_ORT.nc"))
local_ds = hypercoast.read_aviris(local_rfl, chunks=None)
m = hypercoast.Map()
m.add_aviris(granule, dataset=local_ds, layer_name="AVIRIS-3")
if bounds is not None:
m.add_gdf(
gdf.iloc[[0]],
layer_name="AVIRIS-3 footprint",
style={"color": "#ffcc00", "weight": 2, "fillOpacity": 0.0},
)
m.zoom_to_bounds(bounds)
m.add("spectral")
m