James Smyth

An image showing many lines between Europe and North America
Nov 30, 2020

Visualising ADS-B Flight Data with QGIS and Leaflet

Most modern aircraft use a system called ADS-B (Automatic Dependent Surveillance-Broadcast) to transmit their location, speed and altitude while in flight. These transmissions can be picked up using a SDR receiver.

The Opensky Network is a network of ADS-B receivers around the world. Each month they release a 24 hour extract of their network data.

Processing 75 million Records

Back in July 2018, I downloaded a complete day's worth of data, 24 hourly CSV files in total. Uncompressed it was 7GB of text data and contained 75 million records.

I merged the files into a single CSV and imported them into PostgreSQL (PostGIS). This spatial database could then be visualised in QGIS.

Studying the data in QGIS revealed some additional processing steps I could take.

  • Resample from 10-second intervals to 1-minute intervals.
  • Interpolate the plane's position when they go out of coverage range.

I wrote a script to perform the resampling. This reduced each flight down to a maximum of 1440 points.

The next step was to find gaps where a plane had left receiver range and then reappeared at a later time. For each gap, I used GeographicLib to create a great circle arc between the last and the next position. I then sampled this curve to find the position for each missing minute interval.

The final issue that I needed to solve was crossing the 180th meridian. Usually, I would use the QGIS "Points to Path" tool to create my lines. An issue arises when a flight crossed the antimeridian, as it would incorrectly draw a straight line from one side of the world to the other.

To solve this problem, I added an additional check in my processing script. I calculate the distance between the previous longitude and the next longitude. If the distance was greater than 340 then it must have crossed. In QGIS I was grouping the flights by their ICAO code so in order to split the flight I added "_1" to the ICAO of any record after I detected the jump which had the affect of splitting the flight into 2 lines.

Once I had loaded the processed data back into QGIS, the "Points to Path" tool now worked correctly. I set the order of the points in the path to be the UTC timestamp field.

I gave each path a small amount of thickness and had the feature blend mode set to additive. This resulted in the areas with the most flights being the brightest.

A web of lines connecting the major cities in Europe such as London, Paris and Rome

Web Mapping with Leaflet.js

Once I was happy with the way the map looked, I rendered it out to "XYZ Web Tiles". To reduce bandwidth, I only rendered out the lines which I set to be transparent pngs. I could add a country outlines basemap later with a GeoJSON file.

Unfortunately, QGIS will generate map tiles even if the tile itself is empty. To save from uploading a large amount of empty files, I used Imagemagick in a shell script to delete any image that had an empty alpha channel.

I used Leaflet.js as the web mapping library. Adding the CSS property filter:hue-rotate() to the tiles would enable the viewer to dynamically color the lines.

Click here or on the image below to view the map.

Screenshot of the Interactive Flight Map

QGIS Animation

I also used QGIS temporal controller to create an animation of the flights over Taiwan.

© 2020-2023 James Smyth