# Py-ART: a Python toolkit for working with weather radar data

> The Python ARM Radar Toolkit is a scientific Python module of radar algorithms and utilities, built around a common data model so that files from many different radars can be read, corrected, and plotted with the same code. It grew out of the needs of the Atmospheric Radiation Measurement facility and is distributed under a permissive three clause BSD licence.

**ARM-DOE/pyart** — The Python-ARM Radar Toolkit. A data model driven interactive toolkit for working with weather radar data. 

- Repository: https://github.com/ARM-DOE/pyart
- Website: https://arm-doe.github.io/pyart/
- Stars: 609 · Forks: 286
- Language: Python
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/arm-doe-pyart

## What the toolkit does

The Python ARM Radar Toolkit, Py-ART, is described as an open source Python module containing a growing collection of weather radar algorithms and utilities, built on top of the scientific Python stack and distributed under the three clause BSD licence.

The important phrase is the last one in the description: it has been designed so that it can be used by others in the radar and atmospheric communities to examine, process, and analyse data from many types of weather radars. Py-ART is used by the Atmospheric Radiation Measurement facility for working with data from a number of precipitation and cloud radars, but the design goal is broader than that one facility.

The design goal is what a common data model buys you. Weather radars from different vendors do not agree on much: the file formats differ, the field names differ, the conventions for a reflectivity value differ, and the metadata is different. A toolkit whose value is a shared model of a radar volume solves the problem that every new data source otherwise recreates.

That model is what the configuration file is about, and the readme says so directly: the configuration specifies the default metadata, the field names, the colour maps, and the plot limits. So the same plot code produces the same picture whichever radar the data came from, and the differences live in one file rather than scattered through the analysis.

The readme is written in reStructuredText, which is a small signal about the audience: this is a document that will be read by scientists rather than by developers, and the reStructuredText is what the documentation site is built from.

There is an examples site, an HTML documentation site, a mailing list on a Discourse forum with a tag for the project, and an issue tracker. The citation instruction is unusually prominent, and it is in two parts. If you use the toolkit to prepare a publication, cite the paper for the toolkit itself, which is a journal article in the Journal of Open Research Software with a digital object identifier. And then a second instruction that is easy to miss: Py-ART implements many published scientific methods which should also be cited if you make use of them, with a pointer to the references section in the documentation of the functions you used.

That second part is the difference between a citation and a habit. The toolkit is a catalogue of published algorithms, and the documentation records where each one came from, so that a user can find the original paper for the algorithm they are relying on. The project is careful about the difference between citing the code and citing the science.

## Installation, and the conda first decision

The install section leads with the conda packages from the latest release and Python 3, and it explains why: Python 2 support ended on the first of January 2020, and many packages including Py-ART no longer support Python 2.

That is a dated sentence, and it is in the current readme, which tells you that this section has not been rewritten in a while and is still carrying the era when the transition was news. It is also a reminder that the project is old enough to have been through the Python 2 to 3 transition as a public event.

The recommendation is to install Anaconda or Miniconda, and then to create a new conda environment when using Py-ART, or even for other packages. The environment file route is one command.

```bash
conda env create -f environment.yml
```

And the basic route, which creates a named environment with a specific Python version and the package from the community channel.

```bash
conda create -n pyart_env -c conda-forge python=3.13 arm_pyart
```

Then there is the plain install, the update path for an older version, and the variant for users of the alternative package manager.

```bash
conda install -c conda-forge arm_pyart
```

```bash
conda update -c conda-forge arm_pyart
```

The whole section ends with a pointer to the source install for people who do not want Anaconda or Miniconda, or who want the latest unreleased version.

That the conda route is the recommended one rather than the package index route is worth a moment, because it is a choice about the dependency tree. The project depends on a scientific stack that includes a geospatial projection library and a C extension toolchain, and those packages are the ones that are reliably available as conda packages built against each other. Installing them from source with pip is possible and is a common source of broken environments, and the environment file is the answer to that.

The package name on the channel is the distribution name with underscores, and the readme is careful to name the channel explicitly, because the community channel is where the scientific stack lives.

## Configuration, and the environment variable that selects it

The configuration section is short and it is the part of the toolkit most likely to matter to a user who is not doing exactly what the examples do.

The configuration file specifies the default metadata, the field names, the colour maps, and the plot limits. A custom configuration can be loaded automatically by setting the environment variable named for the configuration to point at a custom configuration file, and the documentation on the load configuration function has the details of the process.

So the mechanism is: one file holds the conventions, and an environment variable selects which file is in use. That is a design decision with a specific consequence, and it is a good one for the use case the toolkit is built for.

A research group that works with two radars, one from one vendor and one from another, has field names that differ, metadata that differs, and plotting conventions they want to be the same. With a per-installation configuration file, the analysis code does not change, the environment variable does, and a colleague running the same analysis on their machine gets the same picture provided they have the same configuration.

The alternative, which is the usual design, is a global default with per-call overrides. That is simpler to implement and worse to operate, because the overrides end up scattered through the analysis scripts, and then the configuration is no longer in one place. Putting the whole convention set in one file and selecting it with one environment variable keeps the promise that the same code produces the same figure.

The four things the configuration holds are worth naming separately, because they are four different kinds of knowledge. The default metadata is what the toolkit assumes about an instrument when the data does not say. The field names are the mapping between the vendor's names and the toolkit's. The colour maps are the display conventions, which are the part most likely to be a matter of taste or of house style. And the plot limits are the value ranges the plots use, which are the part most likely to be specific to a dataset rather than to a radar.

The documentation pointer is to a function rather than to a page, which is a hint that the process is a programmatic one and not just an environment variable.

## The extensions, and what each one adds

The extensions section lists six projects that build on Py-ART, and the list is a good map of the field, because between them they cover the whole workflow of a radar study.

The first is an interactive radar viewing browser. It is the tool you use when you want to look at a volume rather than analyse it, and the fact that it is a separate project rather than a mode of the toolkit is a sensible division: a viewer is an application with a user interface, and the toolkit is a library.

The second is a real time data processing framework, developed by a national weather service and a research institute. That is a strong signal, because it means the toolkit's data model is good enough to be the foundation of an operational pipeline rather than only of a research script.

The third is a turbulence detection algorithm, and the fourth is a single Doppler retrieval toolkit. The fifth is a Python interface to dual polarisation radar algorithms, and the sixth is a polarimetric radar beam blockage calculation.

Read as a set, those are the four hard problems in weather radar analysis. Turbulence detection is a retrieval problem, where the goal is to estimate turbulence characteristics from the radar's velocity measurements rather than a reflectivity field. Single Doppler retrieval is the same problem in a more limited form, since one radar gives you velocity along a beam and not the full vector. Dual polarisation is about the extra information that comes from measuring the polarisation state of the returned energy, which is what makes rain type classification and hail detection possible. Beam blockage is a measurement quality problem, where the question is how much of the radar's view is blocked by the terrain and by the structures around the radar.

All six are in Python and all six sit on top of Py-ART, which is the point: the common data model and the common file handling are what make a retrieval toolkit possible at all, because a retrieval algorithm that had to open the vendor format itself could not be reused across radars.

The readme distinguishes these from the related software, which is a separate list of projects that work with weather radar data without being extensions of the toolkit. There is an open source library for weather radar data processing, a community-based weather radar networking effort, a toolkit for the radar mosaic product, a set of radar tools from a university, a package for one vendor's radial data format, and a package for retrieving wind kinematics in precipitation storm systems from one or more radars.

## The dependency set, and what it implies

The dependency list is the most honest part of any scientific Python package, and this one is long enough to say a lot.

The readme says Py-ART is tested to work under Python 3.11, 3.12, and 3.13, and the manifest requires 3.11 or newer, so the supported range is the three most recent versions. The classifiers list those three versions explicitly, and the release is marked as production and stable, with the intended audience given as science and research as well as developers.

The required dependencies in the readme start with the obvious ones and then get interesting. NumPy and SciPy are the numerical foundation. Matplotlib is the plotting, and the manifest even lists it as a framework in the classifiers, which is unusual and honest about the fact that this is a plotting library as much as a processing one.

Then there is netCDF4, which is the file format that weather radar data conventionally travels in, and which is why the toolkit is not a pure in-memory library. There is pooch, which is a downloader with a cache, and that tells you the toolkit can fetch sample data for its examples, which is how a user can run the documentation without their own radar. There is Cython and setuptools, which are the build tools rather than runtime ones, and their presence in the runtime list is a leftover of the older packaging style.

The more distinctive ones are cartopy, which is the geospatial projection library and the reason the toolkit can put a radar scan on a map, and xarray, which is the labelled array library that the modern scientific Python stack uses for anything with dimensions. There is xradar, which is the emerging standard for reading radar data in an open format, and there is an open radar data package on the distribution index, which is a curated sample dataset. There is fsspec and its S3 companion, which is the filesystem abstraction that lets the toolkit read from object storage, which is how modern radar archives are actually laid out. There is a units library, which matters more than it sounds in a field where reflectivity is measured in different units at different radars, and there is a time library, which is the perennial problem in radar data because the conventions for scan time are not standard.

So the dependency list is a map of the domain: geometry, labelled arrays, units, time, files, and the network. A user who has installed this has, in effect, installed a working scientific geospatial environment.

The test group in the manifest is a single entry, the test framework at a recent version, and the repository has a coverage configuration, a continuous integration directory, and a pre-commit configuration, so the quality gates are all present.

## Cython, the build, and a note about Python 2

The last thing worth reading is the setup file, because it contains a comment that explains a decision most people would otherwise find strange.

The build requirements are setuptools at a recent version, a version control aware setuptools plugin, Cython, and NumPy at version 2 or later. The backend is the standard setuptools one, and the version and the readme are declared as dynamic, which is what the version control plugin is for: the version comes from the tag rather than from a number somebody edits.

The setup file itself is short and does the three things a scientific package with compiled parts has to do. It imports the Cython build helper, imports the NumPy include path helper, and builds the extension modules from the sources. Then it does the rest of the configuration, including a lookup for the path of the RSL library if it is present on the machine.

The comment that stands out is about a global variable. The file says it is a bit hackish, that a global variable is being set so that the package's init module can detect that it is being loaded by the setup routine, in order to avoid attempting to load components that are not built yet, and that while ugly it is far less likely to break than what was previously being used.

That is a good example of a comment explaining not only what a piece of code does but why it exists, and it names the alternative it replaced. The problem it solves is real: during a build, the package's init runs before the compiled modules exist, and without the guard the build fails on an import that cannot succeed yet.

And then there is the note about Python 2. The file says it must remain Python 2 compatible for the foreseeable future, to ensure that it errors out properly for people with outdated setuptools and pip, and the version check below it refuses to continue on anything older than a stated version, with a formatted error message that tells the user how to check their version and how to upgrade pip, and mentions that the failure may be due to an out of date pip and that pip nine or later is needed.

That is a deliberate constraint on a modern package, and the reason given is not elegance but error quality. The file is parsed by the setup tools of that era, and if it used syntax that old setuptools cannot parse, the user gets a syntax error instead of a clear message telling them to upgrade. Keeping the file parseable by the oldest tooling is what makes the nice error message reachable.

And there is a mild irony worth naming: the manifest requires Python 3.11 or newer, while the setup file is written so that it stays parseable by Python 2. The compatibility requirement is not about the code running, it is about the error message being seen at all.

The rest of the repository is the standard set for a project of this age: a package directory, a tests directory, a documentation directory with a build configuration, an examples directory, a guides directory, a roadmaps directory, a scripts directory, a continuous integration directory, an environment file, a mail map file for contributor attribution, and a change log.

## Conclusion

Py-ART fits a researcher or an operational team that has to work with data from more than one radar vendor, since the point of the common data model is that the code you write against it survives the next data source. It does not fit somebody who needs a real time feed rather than a file, since the companion project for that is separate, and it does not fit a project that cannot take a conda environment. Verify first which Python version you are on, because the supported range starts at 3.11, that the radar you work with has a reader for its file format, and that you read the citation requirements, because the toolkit implements published methods that have to be cited individually as well as the toolkit itself.

## FAQ

### What is the Py-ART Python toolkit?

It is an open source Python module of weather radar algorithms and utilities built on the scientific Python stack, distributed under the three clause BSD licence. It is used by the Atmospheric Radiation Measurement facility for precipitation and cloud radar data, and is designed for use by others in the radar and atmospheric communities across many radar types.

### How do I install Py-ART?

With conda, from the community channel, either by creating an environment from the repository's environment file or by creating a named environment with the package and a Python version. The readme recommends a separate environment, and points to the source install for people who do not want Anaconda or Miniconda or who want the latest unreleased version.

### What does the Py-ART configuration file control?

The default metadata, the field names, the colour maps, and the plot limits. A custom configuration is selected by pointing an environment variable at it, and the details are in the documentation of the load configuration function. The point is that the same analysis code produces the same figure on another machine as long as the configuration matches.

### What projects extend Py-ART?

Six are listed: an interactive radar viewing browser, a real time data processing framework built by a weather service and a research institute, a turbulence detection algorithm, a single Doppler retrieval toolkit, a Python interface to dual polarisation radar algorithms, and a polarimetric radar beam blockage calculation. Together they cover the retrieval, polarisation, and measurement quality problems in radar analysis.

### What do I need to cite if I publish using Py-ART?

The toolkit's own journal article, with its digital object identifier, and also the original papers for the published scientific methods you used, which the documentation records per function in its references section. The project is explicit that citing the code is not the same as citing the science.

## Sources

- [ARM-DOE/pyart on GitHub](https://github.com/ARM-DOE/pyart)
- [Issues](https://github.com/ARM-DOE/pyart/issues)
- [Project website](https://arm-doe.github.io/pyart/)
- [README](https://github.com/ARM-DOE/pyart/blob/main/README.md)
- [Releases](https://github.com/ARM-DOE/pyart/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/arm-doe-pyart
