Getting started๏ƒ

The motivation for this page/notebook is to take the reader through all basic functionalities of the traffic library. In particular, we will cover:

  1. a basic introduction about Flight and Traffic structures;

  2. how to produce visualisations of trajectory data;

  3. a use case to display trajectories around Paris area;

  4. an introduction to declarative trajectory processing through lazy iteration

Tip

This page is also available as a notebook which can be downloaded and executed locally; or loaded and executed in Google Colab.

Basic introduction๏ƒ

The traffic library provides natural methods and attributes that can be applied on trajectories and collection of trajectories, all represented as pandas DataFrames.

Flight objects๏ƒ

Flight is the core class offering representations, methods and attributes to single trajectories. Trajectories can either:

The Belevingsvlucht from the sample trajectory set is present throughout the documentation:

from traffic.data.samples import belevingsvlucht

Many representations are available:

  • in a Python interpreter:

    print(belevingsvlucht)
    
    Flight(icao24='484506', callsign='TRA051')
    
  • with rich simple or advanced representations:

    from rich.pretty import pprint
    pprint(belevingsvlucht)
    
    Flight(icao24='484506', callsign='TRA051')
    
    # the console is not necessary if you ran pretty.install()
    from rich.console import Console
    console = Console()
    console.print(belevingsvlucht)
    
    Flight 
      - callsign: TRA051   
      - aircraft: 484506 ยท ๐Ÿ‡ณ๐Ÿ‡ฑ PH-HZO (B738)
      - start: 2018-05-30 15:21:38Z 
      - stop: 2018-05-30 20:22:56Z
      - duration: 0 days 05:01:18
      - sampling rate: 1 second(s)
      - features:
        o altitude, int64
        o groundspeed, int64
        o latitude, double
        o longitude, double
        o timestamp, timestamp
        o track, int64
        o vertical_rate, int64
    
  • in a Jupyter notebook:
    belevingsvlucht
    

    Flight

    • callsign: TRA051
    • aircraft: 484506 ยท ๐Ÿ‡ณ๐Ÿ‡ฑ PH-HZO (B738)
    • start: 2018-05-30 15:21:38+00:00
    • stop: 2018-05-30 20:22:56+00:00
    • duration: 0 days 05:01:18
    • sampling rate: 1 second(s)

Information about each Flight is available through attributes or properties:

dict(belevingsvlucht)
{'callsign': 'TRA051',
 'icao24': '484506',
 'aircraft': Tail(icao24='484506', registration='PH-HZO', typecode='B738', flag='๐Ÿ‡ณ๐Ÿ‡ฑ'),
 'start': Timestamp('2018-05-30 15:21:38+0000', tz='UTC'),
 'stop': Timestamp('2018-05-30 20:22:56+0000', tz='UTC'),
 'duration': Timedelta('0 days 05:01:18')}

Methods are provided to select relevant parts of the flight, e.g.ย based on timestamps. The start and stop properties refer to the timestamps of the first and last recorded samples. Note that all timestamps are by default set to universal time (UTC) as it is common practice in aviation.

(belevingsvlucht.start, belevingsvlucht.stop)
(Timestamp('2018-05-30 15:21:38+0000', tz='UTC'),
 Timestamp('2018-05-30 20:22:56+0000', tz='UTC'))
belevingsvlucht.first(minutes=30)

Flight

  • callsign: TRA051
  • aircraft: 484506 ยท ๐Ÿ‡ณ๐Ÿ‡ฑ PH-HZO (B738)
  • start: 2018-05-30 15:21:38+00:00
  • stop: 2018-05-30 15:51:37+00:00
  • duration: 0 days 00:29:59
  • sampling rate: 1 second(s)

Warning

Note the difference between the โ€œstrictโ€ comparison (\(>\)) vs. โ€œor equalโ€ comparison (\(\geq\))

belevingsvlucht.after("2018-05-30 19:00", strict=False)

Flight

  • callsign: TRA051
  • aircraft: 484506 ยท ๐Ÿ‡ณ๐Ÿ‡ฑ PH-HZO (B738)
  • start: 2018-05-30 19:00:00+00:00
  • stop: 2018-05-30 20:22:56+00:00
  • duration: 0 days 01:22:56
  • sampling rate: 1 second(s)

Note

Each Flight is wrapped around a pandas.DataFrame: when no method is available for your particular need, you can always access the underlying dataframe.

belevingsvlucht.between("2018-05-30 19:00", "2018-05-30 20:00").data
timestamp icao24 latitude longitude groundspeed track vertical_rate callsign altitude
11750 2018-05-30 19:00:01+00:00 484506 52.839973 5.793947 290 52 -1664 TRA051 8233
11751 2018-05-30 19:00:02+00:00 484506 52.840747 5.79568 290 52 -1664 TRA051 8200
11752 2018-05-30 19:00:03+00:00 484506 52.841812 5.797501 290 52 -1664 TRA051 8200
11753 2018-05-30 19:00:04+00:00 484506 52.842609 5.799133 290 52 -1599 TRA051 8149
11754 2018-05-30 19:00:05+00:00 484506 52.843277 5.80101 289 52 -1599 TRA051 8125
... ... ... ... ... ... ... ... ... ...
14750 2018-05-30 19:59:54+00:00 484506 52.84964 5.357513 277 280 0 TRA051 6000
14751 2018-05-30 19:59:56+00:00 484506 52.850104 5.351205 277 277 640 TRA051 6025
14752 2018-05-30 19:59:57+00:00 484506 52.850281 5.349197 277 277 640 TRA051 6050
14753 2018-05-30 19:59:58+00:00 484506 52.85043 5.347046 277 277 1088 TRA051 6050
14754 2018-05-30 19:59:59+00:00 484506 52.850601 5.344849 278 277 1216 TRA051 6075

3005 rows ร— 9 columns

Traffic objects๏ƒ

Traffic is the core class to represent collections of trajectories. In practice, all trajectories are flattened in the same pandas.DataFrame.

from traffic.data.samples import quickstart

The basic representation of a Traffic object is a summary view of the data: the structure tries to infer how to separate trajectories in the data structure based on customizable heuristics, and returns a number of sample points for each trajectory.

quickstart

Traffic

with 236 identifiers
    count
icao24 callsign  
39d300 TVF91KQ 3893
39b002 FHMAC 3360
3aabfc FMY8055 2669
39c82b PEA501 2247
4241bb VPCAL 2168
02a195 TAR722 2166
398495 CCM774V 2134
4bc844 PGT90Y 2124
39ceb4 TVF19YP 2076
4d02be JFA12P 2057
Traffic objects offer the ability to index and iterate on all flights contained in the structure.
In order to separate and identify trajectories (Flight), Traffic objects will use either:
  • a customizable flight identifier (flight_id); or

  • a combination of timestamp and icao24 (aircraft identifier);

Indexation will be made on:

  • icao24, callsign (or flight_id if available):

    quickstart["TAR722"]  # return type: Flight, based on callsign
    quickstart["39b002"]  # return type: Flight, based on icao24
    

    Flight

    • callsign: FHMAC
    • aircraft: 39b002 ยท ๐Ÿ‡ซ๐Ÿ‡ท F-HMAC (EC20)
    • start: 2021-10-07 13:21:56+00:00
    • stop: 2021-10-07 14:17:57+00:00
    • duration: 0 days 00:56:01
    • sampling rate: 1 second(s)
  • an integer or a slice, to take flights in order in the collection:

    quickstart[0]  # return type: Flight, the first trajectory in the collection
    quickstart[:10]  # return type: Traffic, the 10 first trajectories in the collection
    

    Traffic

    with 10 identifiers
        count
    icao24 callsign  
    02a195 TAR722 2166
    0a0046 DAH1011 1323
    0101de MSR799 1290
    34150e IBE34AK 1152
    06a2b1 QTR9UU 1144
    0a0047 DAH1000 1111
    300789 IWALK 1024
    06a1e7 QTR23JR 874
    06a133 QQE940 803
    0a0047 DAH1001 798
  • a subset of trajectories can also be selected:

    • if a list is passed an index:

      quickstart[['AFR83HQ', 'AFR83PX', 'AFR84UW', 'AFR91QD']]
      

      Traffic

      with 4 identifiers
          count
      icao24 callsign  
      394c04 AFR83PX 1274
      3946e2 AFR84UW 1112
      3946e0 AFR91QD 1078
      3950d0 AFR83HQ 650
    • with a pandas-like query():

      quickstart.query('callsign.str.startswith("AFR")')
      

      Traffic

      with 84 identifiers
          count
      icao24 callsign  
      393324 AFR69CR 1992
      393320 AFR85FF 1975
      398564 AFR9455 1666
      3985a4 AFR19BH 1636
      3944f1 AFR15AH 1546
      3944f0 AFR51LU 1525
      393321 AFR18KJ 1486
      3944ed AFR71ZP 1463
      3950cd AFR26TR 1396
      394c13 AFR1753 1346

There are several ways to assign a flight identifier. The most simple one that you will use in 99% of situations involves the flight_id() method.

quickstart.assign_id().eval()

Traffic

with 238 identifiers
  count
flight_id  
TVF91KQ_137 3893
FHMAC_116 3360
VPCAL_156 2168
TAR722_001 2166
CCM774V_087 2134
PGT90Y_196 2124
TVF19YP_134 2076
JFA12P_207 2057
AFR69CR_025 1992
AFR85FF_023 1975

We will explain further what the eval() method is about.

Data visualization๏ƒ

The traffic library offers facilities to leverage the power of common visualization renderers including Matplotlib and Altair.

  • with Matplotlib, the traffic style context (optional) offers a convenient initial stylesheet:

    import matplotlib.pyplot as plt
    from matplotlib.dates import DateFormatter
    
    with plt.style.context("traffic"):
    
        fig, ax = plt.subplots(figsize=(10, 7))
    
        (
            belevingsvlucht
            .between("2018-05-30 19:00", "2018-05-30 20:00")
            .plot_time(
                ax=ax,
                y=["altitude", "groundspeed"],
                secondary_y=["groundspeed"]
            )
        )
    
        ax.set_xlabel("")
        ax.tick_params(axis='x', labelrotation=0)
        ax.xaxis.set_major_formatter(DateFormatter("%H:%M"))
    
    _images/quickstart_18_0.png
  • The chart() method triggers an initial representation with Altair which can be further refined.
    For example, with the following subset of trajectories:
    subset = quickstart[["TVF22LK", "EJU53MF", "TVF51HP", "TVF78YY", "VLG8030"]]
    
    subset[0].chart()
    

    Even a simple visualization without a physical features plotted on the y-channel can be meaningful. The following proposition helps visualizing when aircraft are airborne:

    import altair as alt
    
    # necessary line if you see an error about a maximum number of rows
    alt.data_transformers.disable_max_rows()
    
    alt.layer(
        *(
            flight.chart().encode(
                alt.Y("callsign", sort="x", title=None),
                alt.Color("callsign", legend=None),
            )
            for flight in subset
        )
    ).configure_line(strokeWidth=4)
    

    The y-channel is however most often used to plot physical quantities such as altitude, ground speed, or more.

    alt.layer(
        *(
            flight.chart().encode(
                alt.Y("altitude"),
                alt.Color("callsign"),
            )
            for flight in subset
        )
    )
    

    Simple plots are beautiful by default, but it is still possible to further refine them. For more advanced tricks with Altair, refer to their online documentation.

    chart = (
        alt.layer(
            *(
                flight.chart().encode(
                    alt.X(
                        "utcdayhoursminutesseconds(timestamp)",
                        axis=alt.Axis(format="%H:%M"),
                        title=None,
                    ),
                    alt.Y("altitude", title=None, scale=alt.Scale(domain=(0, 18000))),
                    alt.Color("callsign"),
                )
                for flight in subset
            )
        )
        .properties(title="altitude (in ft)")  # "trick" to display the y-axis title horizontally
        .configure_legend(orient="bottom")
        .configure_title(anchor="start", font="Lato", fontSize=16)
    )
    chart