Working with a radar archive means reading and decoding volume after volume before the observations reach your analysis or model. A few seconds per file adds up when you repeat that work across a training dataset.
Through our collaboration with NOAA on compact radar representations, we needed a faster path from radar files to model inputs. We built radrs, an open-source NEXRAD Level 2 reader with a Rust parsing core and a Python interface.
You can load observations into a familiar xarray DataTree, organized by sweep, or use the Raystack representation to assemble observations from multiple volumes for training.
From a radar file to an xarray array
Open a volume directly from the public NEXRAD archive and access its reflectivity:
import radrs.xradar as rxr
source = (
"s3://unidata-nexrad-level2/"
"2024/03/15/KTLX/KTLX20240315_000217_V06"
)
volume = rxr.open_datatree(source, sort_by_azimuth=True)
reflectivity = volume["sweep_0"]["DBZH"]Figure 1: KTLX reflectivity at 00:02 UTC on 15 March 2024, decoded with radrs. Range rings are 100 km apart.
The result is an xarray DataArray with azimuth and range dimensions. You can also pass a local file path.
For workflows already using xradar’s NEXRAD reader, radrs provides the same style of sweep_N organization and radar variable names. Two differences matter: radrs preserves file order unless you request azimuth sorting, and it represents below-threshold and range-folded gates as NaN. The compatibility guide explains these choices and how to compare outputs.
Measured loading performance
We compared release builds of radrs with xradar on the NEXRAD volume KTLX20240315_000217_V06. Both readers returned all 20 sweeps, and both timings include opening the file and materializing every variable with DataTree.load(). Median times across nine measured runs were:
Figure 2: Nine runs per reader after one warmup, using the same local file with a warm OS cache. radrs was sorted by azimuth; network transfer was excluded. Whiskers show the observed minimum and maximum. The GCE VM had concurrent workloads.
On this volume, radrs was approximately 17x faster on an Apple M2 Max and 8.2x faster on a Google Compute Engine VM. These results cover one volume. The benefit to a complete pipeline depends on how much time it spends loading observations.
From individual volumes to training samples
When training a model, we often use observations from consecutive scans. radrs supports concurrent fetching and batched Raystack construction, overlapping network reads with parsing.
Raystacks store observations in flat arrays, splitting each ray into fixed-width chunks of range gates while retaining time and spatial metadata. We can then assemble training samples across sweep and volume boundaries.
Our companion post, Finding models in a Raystack, describes the representation and its tradeoffs.
Try it on your machine
Install radrs with Python 3.11 or later:
uv add radrsGet started with the documentation, browse the source code, or find the package on PyPI.
radrs currently reads NEXRAD Level 2 data and is available under the Apache 2.0 license.



