Skip to content

Quickstart

Fast NEXRAD Level 2 processing for Python. This page goes from a fresh environment to a working open_datatree call against a public S3 file.

Install

uv add radrs
pip install radrs

Python 3.11+ is required. See Install for source builds and platform notes.

Open a volume as an xradar DataTree

radrs.xradar.open_datatree is a drop-in replacement for xradar.io.open_nexradlevel2_datatree. It returns an xarray.DataTree with the same sweep-per-node structure.

import radrs.xradar as rxr

src = "s3://unidata-nexrad-level2/2024/03/15/KTLX/KTLX20240315_000217_V06"
dt = rxr.open_datatree(src)

The src argument also accepts a local filesystem path or a bytes buffer of raw NEXRAD data.

Open the same volume as a raystack DataTree

The raystack format is a flat vcps / sweeps / returns / activity layout designed for ML training pipelines that want fixed-shape tensors rather than nested xradar groups.

import radrs.raystack as rrs

rdt = rrs.open_datatree(src, fold_size=128)
rdt["returns"]["DBZH"].shape  # (n_returns, 128)

fold_size chunks each radial along the range axis: a radial with n_gates > fold_size becomes ceil(n_gates / fold_size) returns of fold_size gates each, NaN-padded past the last real gate. The range coordinate is the gate's index within its fold, not a distance. See Raystack format for the array layout and for recovering physical range, and Batch iteration and folding for how fold_size trades rows against columns.

XArray integration

Both readers are also registered as xarray engines, so they can be reached through xarray.open_datatree / open_dataset dispatch instead of the radrs APIs directly:

import xarray as xr

dt = xr.open_datatree(src, engine="radrs-xradar", sort_by_azimuth=True)
sweep = xr.open_dataset(src, engine="radrs-xradar", group="sweep_0")

rs_dt = xr.open_datatree(src, engine="radrs-raystack", fold_size=128)
returns = xr.open_dataset(src, engine="radrs-raystack", group="returns")

Each engine forwards its reader's keywords (sort_by_azimuth for radrs-xradar; fold_size, qc, include_activity for radrs-raystack), plus group, drop_variables, and storage_options. Decoder keywords such as mask_and_scale are rejected — the engines return already-decoded in-memory objects. radrs.xradar and radrs.raystack remain the canonical APIs; the engines are thin adapters for pipelines built around xarray dispatch.

Anonymous S3 access

The single-volume open_datatree path fetches from S3 without signing, so public buckets like unidata-nexrad-level2 and noaa-nexrad-level2 work out of the box even without AWS credentials.

For multi-volume iteration over an archive, pass storage_options={"anon": "true"} to NexradL2ArchiveIter:

from datetime import datetime, timezone
import radrs

archive = radrs.NexradL2ArchiveIter(
    base_uri="s3://unidata-nexrad-level2",
    start_time=datetime(2024, 3, 15, tzinfo=timezone.utc),
    end_time=datetime(2024, 3, 16, tzinfo=timezone.utc),
    storage_options={"anon": "true"},
    site_filter=["KTLX"],
)

Archive bounds are UTC and half-open, [start_time, end_time): naive datetimes are read as UTC rather than as local time, and a volume exactly at end_time is excluded. See Iterating an archive for the full surface.

Accumulate a time range into one array

BatchedRaystack fills pre-allocated buffers from an archive iterator, so a whole time range becomes a single returns matrix:

import radrs.raystack as rrs

batch = rrs.BatchedRaystack(
    max_vcps=20, max_sweeps=20 * 32, max_returns=20 * 90_000,
    fold_size=256, drop_empty_returns=True,
)
n_added = batch.add_volumes_from_l2(archive, prefetch=8)
rs_dt = batch.finalize_to_rs_dt()

Capacity is reserved up front, so max_returns has to be estimated before the first fetch and n_added has to be checked afterwards. See Batch iteration and folding for the sizing arithmetic.

What's next

  • Raystack format — what vcps, sweeps, returns, and activity actually contain, with a visual folding walkthrough.
  • Batch iteration and foldingNexradL2ArchiveIter, BatchedRaystack capacity sizing, prefetch, drop_empty_returns, and fixed-shape output.
  • Quality controlRhohvThreshold, SunSpike, and VradhWindingNumber applied during raystack parsing.
  • xradar interop — sweep ordering, NaN semantics for below-threshold gates, and the sort_by_azimuth flag.
  • Visualization — the marimo viewers for a single volume and for a whole batch.