Animate Aircraft Traffic
========================
Introduction
------------
Sq1090 project decodes ADS-B messages into aircraft position data. Use the
data to animate aircraft traffic during specific period of time and over
a defined geographical area.
On October 31, 2025, some flights were delayed at Dublin Airport. Aircraft
traffic was established in holiding patterns at KERAV and SORIN fixes near
the airport. This lasted from about 09:45 to 12:30 UTC.
In this tutorial you will
- create an SQL query to retrieve aircraft locations within
the geographical area covering SORIN holding fix and Dublin Airport;
we will exclude KERAV holding fix traffic for a cleaner animation
- prepare geographical data for the holding fix and the airport with
`sf R library `_
- transform aircraft locations to create animation data with
`dplyr R library `_
- animate aircraft traffic with
`tmap R library `_
The outcome of the tutorial is presented in the video below. The animation
shows airplanes in `holding pattern
`_ at SORIN holding
fix. The airport is marked with 5-kilometre buffer to display number of
aircrafts in that area.
.. video:: images/traffic-on-hold-anim.mp4
:loop:
:width: 640
:align: center
:caption: Aircraft traffic at SORIN holding fix near Dublin Airport on
31 October, 2025.
.. note::
This tutorial is similar to the one in the :numref:`sect-traffic-vis`.
The other tutorial plots flight data in 15-minute time intervals over
at SORIN and KERAV holding fixes near Dublin Airport. That visualisation
can help in choosing an aircraft traffic time for this tutorial.
Assumptions
-----------
At a technical level, this tutorial assumes familiarity with
1. `Structured Query Language (SQL)
`_
and `Common Table Expressions (CTEs)
`_ within
PostgreSQL relational database system.
2. `TimescaleDB hyperfunctions
`_
and `PostGIS spatial functions
`_.
3. `R `_ programming language for statistical
analysis.
4. `tmap `_,
`sf `_ , and
`dplyr `_ R language libraries.
Find Aircraft Locations
-----------------------
Sq1090 project decodes ADS-B messages into aircraft positions and stores the
data in the ``position`` database table. The table has time, aircraft ICAO
address, and aircraft location columns (see the :numref:`sec-data-model` for
details)
``time``
Time of receiving a raw message with aircraft location and altitude.
``icao``
ICAO address of an aircraft. It is an integer number displayed as
a hexadecimal number.
``location``
Location and altitude of an aircraft. The positions are stored using
`WGS 84 `_
coordinate system.
Query the ``position`` table to find positions of each aircraft, including
its bearing, within the geographical area covering SORIN holding fix and
Dublin Airport on October 31, 2025
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: sql
:start-at: with timeline as (
:end-at: from timeline
:dedent:
:linenos:
The query
- ``[3-5]`` extracts positions of each aircraft at one-second intervals,
calculating average position if multiple data points exist within the
same second
- ``[7]`` finds aircrafts within the geographical area using a PostGIS
spatial index to optimise execution of the predicate function
- ``[8]`` filters the data leveraging TimescaleDB time index to optimise
bucketing and finding aircraft positions within the specified time
interval
- ``[15]`` calculates bearing of an aircraft at each aircraft position; the
bearing is measured in degrees
Read and Visualise Data
-----------------------
Sq1090 database can be queried with SQL by many applications and
programming languages. This tutorial uses R programming language to read
and animate the data.
In R, use `RPostgreSQL` library to execute queries against Sq1090 database.
There are many options to visualise the data on a map in R. `tmap` is an
R package for drawing thematic maps using `grammar of graphics concept
`_.
It integrates with `sf` package, which in conjunction with `dplyr` library,
enables creating and manipulating geographical data (`simple features
`_).
Additionally, use
- `av` library to create a video from a series of plots
- `urltools` library to pass database system parameters to the script
developed in this tutorial
.. note::
When writing the script for this tutorial, the author has found memory
issues in `tmap` package animation code, see
https://github.com/r-tmap/tmap/issues/1237.
The problem forces us to abandon use of `tm_animate` function. Instead,
at the price of the increasing complexity of the tutorial, we roll our
custom code to generate plots for the video.
Install the libraries in R language environment, for example using its
shell and ``install.packages`` function
.. code-block::
$ R
> install.packages(c('av', 'dplyr', 'grid', 'RPostgreSQL', 'sf', 'tidyr', 'tmap', 'urltools', 'vctrs'))
In R IDE or a text editor, create file with name ``traffic-on-hold-anim``.
We will populate the R script with commands to read aircraft positions from
database, create animation data, animate the traffic on a map, and save it
into a MP4 video file.
Import the libraries
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: library(dplyr)
:end-at: library(urltools)
:dedent:
:linenos:
Parse database connection and output file arguments
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: args = commandArgs
:end-at: output = args
:dedent:
:linenos:
Connect to Sq1090 database and execute SQL query (``QUERY`` variable is the
query defined in previous section)
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: pg_drv = dbDriver
:end-at: data = dbGetQuery
:dedent:
:linenos:
Define geographical features for Dublin Airport and SORIN holding fix. The
airport's 5-kilometre buffer will be used later to count airplanes within
its area.
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: airport.pos =
:end-at: -5.806250, 53.141472
:dedent:
:linenos:
Create the base dataframe for animation, containing aircraft flight tracks
and indicator whether an aircraft is within the airport area (``TIME_END``
variable is set to 60 seconds)
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: data.base =
:end-at: icon=intToUtf8(0x01f6e7)
:dedent:
:linenos:
When creating the base dataframe
- ``[2-4]`` identtify start and end of a flight of each aircraft, extend
every flight by 60 seconds (``TIME_END``) to show an airplane on a map for
context
- ``[5-6]`` create aircrafts' flight timeline, second-by-second
- ``[7-10]`` merge the aircrafts' flight timeline with the original dataset;
fill missing aircraft location and bearing with last known data to avoid
gaps in the animation
- ``[11]`` convert aircraft location fetched from database to `sf` vector
- ``[12]`` change sign of aircraft bearing to allow rotation of aircraft
symbol on the plot
- ``[13]`` identify if a location is within the airport area
- ``[14-15]`` calculate text position under aircraft symbol on the map
- ``[16]`` define symbol for aircraft position using `Unicode up-pointing
airplane `_
Prepare data for aircrafts in-flight (outside the airport area)
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: data.plane =
:end-at: data.plane =
:dedent:
:linenos:
Count aircrafts within the airport area and prepare data to be displayed on
the map
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: data.airport =
:end-at: location=airport.pos
:dedent:
:linenos:
Prepare the basemap for the animation. The basemap uses positron tiles from
CartoDB project, and displays both the SORIN holding fix and the area of
the airport. The rendered basemap is stored as R's grid graphical object
(grob) to enable efficient generation of frames of the animation.
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: selector = vars
:end-at: p.base.grob = tmap_grob(p.base)
:dedent:
:linenos:
Create frame for each second of the aircrafts' flight timeline and encode
them at 60 frames per second into a video file
.. literalinclude:: ../scripts/traffic-on-hold-anim
:language: R
:start-at: frame_dir = sprintf
:end-at: unlink(frame_dir, recursive=T)
:dedent:
:linenos:
Execute the script to create the animation in MP4 format
.. code-block::
Rscript traffic-on-hold-anim postgresql://localhost:5432/sq1090 traffic-on-hold-anim.mp4
Conclusions
-----------
Sq1090 decodes ADS-B messages into aircraft position data.
The position data is stored in Sq1090 database ``position`` table.
Query the table to determine flight timeline of each aircraft within
a geographical area.
In this tutorial, we have implemented the R script to animate aircraft
traffic at SORIN holding fix near Dublin Airport.
The source code of the script can be found in Sq1090 project repository
https://gitlab.com/sq1090/sq1090/-/blob/master/scripts/traffic-on-hold-anim
You can study Sq1090 project data model by reading its reference
documentation, the :numref:`sec-data-model`.
.. vim: sw=4:et:ai