Skip to content

Saved notebook output; this documentation build does not execute cells. Download the notebook.

One GOES infrared scene

Fetch a single GOES-18 ABI channel-13 CONUS scene, open its NetCDF4 locally, and inspect brightness temperature with the source quality flags. Available since v0.8 with usdata[netcdf] and the optional examples environment.

Saved outputs record one execution. Restart the kernel and run all cells to refresh it. This is a whole satellite scene (~3.8 MB), selected by its exact scan-start timestamp. It is not geographically cropped.

import sys
from datetime import UTC, datetime
from pathlib import Path

import h5netcdf
import h5py
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr

import usdata
from usdata.pull import pull, verify

manifest = Path("examples/goes-imagery/dataset.yaml")
if not manifest.is_file():
    manifest = Path("dataset.yaml")
print("Executed (UTC):", datetime.now(UTC).isoformat(timespec="seconds"))
print(f"Python {sys.version.split()[0]}; h5netcdf {h5netcdf.__version__}; h5py {h5py.__version__}")
print(f"usdata {usdata.__version__}; xarray {xr.__version__}; NumPy {np.__version__}")
Executed (UTC): 2026-09-09T00:46:04+00:00
Python 3.14.7; h5netcdf 1.8.1; h5py 3.16.0
usdata 0.7.0; xarray 2026.7.0; NumPy 2.5.2

Fetch and preserve the input

The manifest explicitly selects satellite 18, channel 13, and ABI-L2-CMIPC. Both bounds equal the scan start, including its tenth of a second. The first pull creates a lockfile; later pulls restore its pinned URL and checksum.

result = pull(manifest)
(item,) = result.fetched
print("Source:", item.provenance.source_url)
print("Retrieved (UTC):", item.provenance.retrieved_at.isoformat())
print("Input checksum:", item.provenance.checksum)
print("Bytes:", item.provenance.size)
print("Scan:", item.asset.time.start.isoformat(), "to", item.asset.time.end.isoformat())
assert verify(manifest) == []
Source: s3://noaa-goes18/ABI-L2-CMIPC/2024/127/12/OR_ABI-L2-CMIPC-M6C13_G18_s20241271201181_e20241271203566_c20241271204061.nc
Retrieved (UTC): 2026-09-09T00:46:05.647041+00:00
Input checksum: sha256:3331dc3dcf67f3015e221484750fefebead4c51d728272045c3e31c9123a0c0a
Bytes: 3821830
Scan: 2024-05-06T12:01:18.100000+00:00 to 2024-05-06T12:03:56.600000+00:00

Open, decode, and keep quality information

open() loads the root NetCDF4 Dataset and closes its file handles before returning. CF scale/offset and fill values are decoded, while coordinate units, projection metadata, and quality flags remain available. It does not crop, reproject, or decide which quality flags to accept. Here the analysis explicitly keeps only DQF == 0 (the source's good_pixel_qf).

scene = item.open()
assert scene["CMI"].attrs["units"] == "K"
assert scene["CMI"].dims == ("y", "x")
assert "good_pixel_qf" in scene["DQF"].attrs["flag_meanings"]
assert scene.attrs["usdata"]["provenance"]["checksum"] == item.provenance.checksum
brightness = scene["CMI"].where(scene["DQF"] == 0)
print("Grid:", dict(scene.sizes))
print("CMI:", scene["CMI"].attrs["long_name"])
print("Units:", scene["CMI"].attrs["units"])
print("Quality flags:", scene["DQF"].attrs["flag_meanings"])
print("Accepted finite pixels:", int(brightness.count()), "of", brightness.size)
print(
    f"Pixel mean: {float(brightness.mean()):.2f} K; range: "
    f"{float(brightness.min()):.2f}-{float(brightness.max()):.2f} K"
)
Grid: {'y': 1500, 'x': 2500, 'number_of_time_bounds': 2, 'number_of_image_bounds': 2, 'band': 1}
CMI: ABI L2+ Cloud and Moisture Imagery brightness temperature
Units: K
Quality flags: good_pixel_qf conditionally_usable_pixel_qf out_of_range_pixel_qf no_value_pixel_qf focal_plane_temperature_threshold_exceeded_qf
Accepted finite pixels: 3750000 of 3750000
Pixel mean: 273.10 K; range: 208.29-296.29 K

Inspect scan coordinates and pixel temperatures

Channel 13 measures infrared brightness temperature, not necessarily surface air temperature: clouds and the surface both contribute to the observed scene. The image below uses the file's geostationary scan angles in radians, not a latitude/longitude map. The plot uses every fourth grid point for a compact render; the summary and histogram use every accepted finite pixel. The mean is a pixel mean, not an area-weighted regional temperature.

fig, axes = plt.subplots(1, 2, figsize=(10, 3.8), constrained_layout=True)
preview = brightness.isel(y=slice(None, None, 4), x=slice(None, None, 4))
mesh = axes[0].pcolormesh(
    preview.x, preview.y, preview, shading="auto", cmap="magma", vmin=200, vmax=310, rasterized=True
)
axes[0].set(
    xlabel="East-west scan angle (rad)",
    ylabel="North-south scan angle (rad)",
    title=(
        f"{scene.attrs['platform_ID']} C{int(scene.band_id.item()):02d} · "
        f"{item.asset.time.start:%Y-%m-%d %H:%M UTC}"
    ),
)
fig.colorbar(mesh, ax=axes[0], label="Brightness temperature (K)")
values = brightness.values
axes[1].hist(values[np.isfinite(values)], bins=50, color="#345c80")
axes[1].set(
    xlabel="Brightness temperature (K)",
    ylabel="Accepted pixel count",
    title="Scene distribution · DQF = 0",
)
axes[1].ticklabel_format(axis="y", style="sci", scilimits=(0, 0))
plt.show()

png

Verify the source after analysis

Reading and plotting change neither the cached source nor its provenance. The returned Dataset is already detached from the file, so it stays usable without an open HDF5 handle. Keep the manifest, lockfile, and cached bytes for long-lived reproducibility; upstream revisions can fail a future locked restore.

assert verify(manifest) == []
again = pull(manifest)
assert again.from_lockfile and all(asset.from_cache for asset in again.fetched)
print("Input verified; repeat pull used the lockfile and cache.")
print("Projection:", scene["goes_imager_projection"].attrs["grid_mapping_name"])
print("Original checksum:", scene.attrs["usdata"]["provenance"]["checksum"])
Input verified; repeat pull used the lockfile and cache.
Projection: geostationary
Original checksum: sha256:3331dc3dcf67f3015e221484750fefebead4c51d728272045c3e31c9123a0c0a

Source documentation: NOAA ABI/CMIP, NODD public archive, and usdata GOES access notes.