Library / SDK
xoolive/traffic avatar
xoolive/traffic

traffic: a Python toolbox for air traffic data and trajectories

A toolbox for processing and analysing air traffic data

520 stars98 forksPythonMIT

At a glance

What is it?
traffic is a Python library for working with ADS-B air traffic data, providing analysis methods for trajectories and airspaces on top of pandas, with parsing for OpenSky Network and Eurocontrol sources and rendering through Cartopy, ipyleaflet, altair, CesiumJS or Google Earth. It is a research tool, and it says so in its dependency list.
Who is it for?
traffic suits a researcher or data scientist who already works in a conda environment, who needs trajectory and airspace analysis over OpenSky or Eurocontrol ADS-B data, and who wants a rendered map without writing the geospatial plumbing.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A pandas escape hatch under every analysis method

traffic describes itself as a toolbox for processing and analysing air traffic data. Its stated main purpose is to provide data analysis methods commonly applied to trajectories and airspaces, and the design decision that matters is what happens when a specific function is not provided: the access to the underlying structure is direct, through an attribute pointing to a pandas dataframe.

That single sentence sets the character of the library. It is not a closed box with a method for every operation. It is a layer of domain methods over a pandas data structure, and where the layer runs out, you drop down to pandas yourself rather than fighting an abstraction.

For researchers this is the right default. Air traffic analysis questions tend to be specific: what is the distribution of climb rates in this airspace, how many tracks crossed this waypoint in a given week, which aircraft types are missing callsigns. Encoding each of those as a general purpose library method would be guesswork, so the library instead ships the parts that are genuinely reusable and leaves the dataframe visible.

The project states that it is designed to be easily extendable to other sources of data, which is the other half of the same philosophy. New data providers are meant to be added rather than worked around, and the topic list, with adsb, mode-s, trajectory and air-traffic-data among the tags, matches a library that handles raw transponder data and turns it into tracks.

The package metadata describes it as a toolbox for manipulating and analysing air traffic data, authored by Xavier Olive, licensed MIT, with the version declared as dynamic in the pyproject file rather than hard coded there.

ADS-B sources and the parsing layer

The library offers facilities to parse and/or access traffic data from open sources of ADS-B traffic, and the README names two of them directly: the OpenSky Network and Eurocontrol DDR files.

Those two represent different shapes of problem. OpenSky is an aggregated crowd sourced feed queried over the network, so the library needs a client, credentials handling and a way to deal with the API's rate and coverage behaviour. Eurocontrol DDR files are bulk downloads of recorded surveillance data, so the library needs file parsing, decompression and indexing rather than a network client.

The dependency list in the pyproject file is where this shows up in detail. pyopensky is there for the OpenSky side, rs1090 is there for Mode S decoding, openap handles the Open Aircraft Publishing aircraft database, metar supplies meteorological data, pitot is the air data decoder for the aircraft performance model, and impunity provides the aircraft library with the associated 3D models and liveries. pyarrow and py7zr sit on the file side for columnar and archive handling, and httpx is the HTTP client.

The presence of impunity and pitot is a design statement worth noting. Traffic is not only about plotting dots on a map. The dependency set includes aircraft geometry and an air data model, which means the library can reason about the aircraft as a physical object and its position in three dimensional space, not only as a point with an altitude.

That also has a cost. The dependency list is long for a data library, and onnxruntime is included, which means a machine learning runtime comes along with it. Whatever the project uses it for, it is not optional baggage for the average user, and it is the single biggest argument for working inside the conda environment the documentation recommends rather than adding traffic to an existing application environment.

Two rendering paths, from static images to Google Earth

Visualisation is where the library splits its audience, and the split is explicit in the README.

Static visualization, meaning image exports, is accessible via Matplotlib and Cartopy. That is the path for a paper figure or a report: you get a map you can save and put in a document, and Cartopy is the projection aware Matplotlib layer that makes the map look like a map rather than a rectangle of longitude and latitude.

More dynamic visualization frameworks are easily accessible in Jupyter environments with ipyleaflet and altair. The first is a Leaflet based interactive map widget that works inside a notebook, and the second is a declarative charting library, which pairs naturally with a trajectory dataframe that already has columns for time, position and altitude. In a notebook you can therefore explore the data and draw the map in the same session, which is the workflow the library is really built around.

There is a third route for moving the result elsewhere: exports to other formats, including CesiumJS or Google Earth. CesiumJS is the globe renderer used for three dimensional geospatial scenes, and the Google Earth export is the classic kml style handoff for a review in a mapping application. For a colleague who will not run your Python environment, that export is how the work leaves the notebook.

The tangram/ directory at the root of the repository is separate from the plotting stack and appears to hold data rather than code, and the docker/ directory plus the .devcontainer/ configuration point at the same reproducibility story as the conda instructions.

Install into a fresh conda environment, not into your project

The installation instructions are unusually emphatic, and the reason is dependency resolution. The README advises anyone not familiar or comfortable with their Python environment to install the latest traffic release in a new, fresh conda environment:

sh
  conda create -n traffic -c conda-forge python=3.12 traffic

Then the environment is activated every time the library is needed:

sh
  conda activate traffic

You adjust the Python version you need and append the packages you want to work efficiently with, such as Jupyter Lab, xarray or PyTorch. The stated floor is Python 3.10 in the README, while the pyproject file declares requires-python = >= 3.11 and the classifier list runs from 3.10 to 3.13. That gap is small but real, and it is the kind of detail that bites when you create the environment with the older version the README suggests.

The warning is about mixed package managers. Dependency resolution may be tricky, especially if you use an old conda environment where you overwrote conda libraries with pip installs, and the README asks that installation issues be reported only in new, fresh conda environments. There is a fallback if conda fails to resolve in a reasonable time: a Docker image with a working installation, documented on the installation page, and a troubleshooting section for the common failures.

A Jupyter notebook is the intended working environment, which is why Jupyter Lab appears in the list of packages to append rather than being optional.

Ruff, mypy and pytest gate every contribution

The quality story is well documented, which matters for a library that other researchers build on.

Unit and non-regression tests are written in the tests/ directory, and you may run pytest from the root directory. The tests are checked on GitHub Actions upon each commit, with the status and coverage shown as badges. Beyond unit tests, the code is checked against linting and formatting with ruff, and against static typing with mypy, and the README carries a checked with mypy badge and a code coverage badge pointing at codecov.

The typing discipline is worth noting separately, because it changes what you can do with the library. The package metadata includes a Typing :: Typed classifier, and the development group in pyproject.toml pins mypy, plus a second type checker called ty, ruff, pytest with coverage and a timeout plugin, and Sphinx with the read the docs theme and autodoc type hints for the documentation build. The dependencies themselves carry typing-extensions, so the annotations are meant to be consumed by downstream editors and checkers.

The contribution guidance is specific in a way that tells you how the project actually evolves. If you intend to contribute or file a pull request, the best way to ensure continuous integration does not break is to reproduce an environment with the same exact versions of all dependency libraries, and the documentation has a section for that. The maintainer also asks you to say what you intend to do, in case the same implementation is already underway, and asks that tests be added for any new functions.

Pre-commit hooks are available in the repository, and there is a .pre-commit-config.yaml at the root, which is the usual way those lint and type checks get enforced locally rather than only in CI.

A library with a slower release rhythm than its commit rate

The maintenance record needs two separate readings, because they do not match.

The last push was on 2026-10-14, and the repository is not archived, so work is still landing. The recent release tags, however, are v2.13 from 2025-07-22, v2.12 from 2025-03-06 and v2.11.1 from 2024-12-13. That is a release every few months on a two year branch, with nothing newer than July 2025 in the visible tag list.

So the sensible reading is a library with an active master branch and a slow release train. If you pin a version, you are pinning something from mid 2025 unless you build from the branch. If you need a fix that landed after the last tag, the git history is where it is, and the project does not publish a rolling release channel in the README.

The version itself is declared as dynamic in pyproject.toml, which means it comes from the source tree rather than from the manifest, and the repository carries a uv.lock file and a uv based dependency sources section, with commented out local path overrides for cartes and impunity that would let a contributor work against a checkout of a dependency instead of the released package.

The licence is MIT, in the metadata and in license.md at the root. For academic use there is a formal citation: the project has a JOSS paper, and the README gives the bibtex entry for it, with the author, the journal, the year 2019, the volume and page numbers and the DOI. A citation.cff file at the root carries the same metadata for tooling that reads it. If you use this in a paper, cite the paper rather than the repository, which is what the authors ask.

Against writing your own pipeline on raw ADS-B

The real alternative is not another library but the do it yourself route, and it is more common than it should be.

The DIY pipeline looks like this: fetch or download raw ADS-B messages, decode Mode S with a decoder of your own, reassemble tracks with a clustering algorithm, then build a dataframe and finally draw a map. The traffic library collapses that into a single import, and the parts it collapses are exactly the parts that are tedious and error prone. rs1090 does the Mode S decoding, openap supplies aircraft metadata, impunity gives the aircraft library, and the library handles the trajectory assembly so that you receive tracks rather than positions.

A second, smaller alternative is to use the OpenSky Python client on its own. pyopensky is a direct dependency of traffic, so it is on your machine either way, and if your analysis is only about positions and altitudes in a given region, calling the client and working in pandas may be all you need.

The difference between traffic and the DIY route is the layers above the data. traffic adds airspace analysis, the aircraft performance and geometry models, and the visualisation stack that outputs Cartopy images, ipyleaflet maps and CesiumJS or Google Earth exports. If your research question needs only where planes were, the smaller route is faster to build and has fewer dependencies to keep alive. If it needs how they flew, what they were, and how to show it, the toolbox is the shorter path.

One practical caveat applies to both routes. ADS-B coverage is not uniform, and neither the OpenSky Network nor Eurocontrol data is complete everywhere. Any analysis built on this data inherits that, and traffic does not claim otherwise.

Editorial conclusion

traffic suits a researcher or data scientist who already works in a conda environment, who needs trajectory and airspace analysis over OpenSky or Eurocontrol ADS-B data, and who wants a rendered map without writing the geospatial plumbing. It does not suit an application that needs a supported service level, since the most recent tagged release is v2.13 from 2025-07-22 and the release cadence in the visible history is a version every few months, and it does not suit someone who wants a small dependency footprint, because the manifest pulls in a machine learning runtime and a mapping stack by default. Verify first by creating the fresh conda environment exactly as the documentation describes, since the maintainers ask that installation problems be reported only against a clean environment.

Frequently asked questions

How do I install the traffic library?

The README recommends a new, fresh conda environment created with conda create -n traffic -c conda-forge python=3.12 traffic, then activated with conda activate traffic. Full instructions are in the documentation, and a Docker image is offered as a fallback when conda fails to resolve.

Which data sources does traffic read?

It parses and accesses traffic data from open ADS-B sources, and the README names the OpenSky Network and Eurocontrol DDR files. The package also depends on pyopensky for the OpenSky side and rs1090 for Mode S decoding.

Can I use traffic with my own pandas code?

Yes. The README states that when a specific function is not provided, access to the underlying structure is direct, through an attribute pointing to a pandas dataframe, so analysis methods are provided for common trajectory and airspace operations without hiding the table.

What can traffic draw?

Static image exports through Matplotlib and Cartopy, interactive visualisation in Jupyter with ipyleaflet and altair, and exports to other formats including CesiumJS and Google Earth.

How are contributions tested?

Unit and non-regression tests live in the tests/ directory and are run with pytest from the root directory, with GitHub Actions checking each commit. The code is also linted with ruff, type checked with mypy, and pre-commit hooks are available in the repository.

When was the last traffic release?

The most recent listed release is v2.13 from 2025-07-22, preceded by v2.12 in March 2025 and v2.11.1 in December 2024. The repository itself is not dormant, since the last push was on 2026-10-14.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. xoolive/traffic on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xoolive-traffic.svg)](https://hysenlabs.com/projects/xoolive-traffic)

Was this useful?