Airspaces from Eurocontrol NM

The first thing to do is to put the path to a directory containing your files from the Eurocontrol NM in your configuration file.

You will need to put the three following files from the same AIRAC cycle in the same directory:

/home/xo/Documents/data/AIRAC_1703
├── Sectors_1703_Collapse.spc
├── Sectors_1703_Sectors.are
└── Sectors_1703_Sectors.sls

Identify the path to your configuration file here:

>>> import traffic
>>> traffic.config_file
PosixPath('/home/xo/.config/traffic/traffic.conf')

Then edit the following line accordingly:

[global]
nm_path = /home/xo/Documents/data/AIRAC_1703

Basic usage

The basic way to access an airspace is by its name:

from traffic.data import nm_airspaces
nm_airspaces['LFBBFIR']
LFBBFIR (FIR)
  • -inf, 195.0

Most airspaces are a composition of elementary airspaces. Their union is computed and yields a list of polygons associated with minimum and maximum flight levels.

nm_airspaces['LFBBBDX']
BORDEAUX TOTAL (CS)
  • 145.0, 155.0
  • 155.0, 195.0
  • 195.0, 265.0
  • 265.0, inf

Some basic looping can help finding the airspaces your need. Two methods are provided:

  • the parse method yields only metadata about the airspace (basically name and type);
  • the search method computes the actual shape of the airspace to you get for example the area of its 2D projection. Here, we use it to find the biggest control sector with a name starting with LFBB.
# get all types of airspaces provided (you only need metadata)
>>> set(a.type for a in nm_airspaces.parse('.*'))
{'AREA', 'AUA', 'AUAG', 'CLUS', 'CRAS', 'CRSA', 'CS', 'ERAS', 'ERSA', 'ES', 'FIR', 'NAS', 'REG'}
# Find the biggest CS in Bordeaux ACC
from operator import attrgetter
max(nm_airspaces.search('LFBB.*/CS'), key=attrgetter('area'))
BORDEAUX TOTAL (CS)
  • 145.0, 155.0
  • 155.0, 195.0
  • 195.0, 265.0
  • 265.0, inf

Use cases

The provided infrastructure lets you find all elementary sectors crossed by a trajectory (here from the so6 file)

from traffic.data import SO6
so6 = SO6.from_file('data/sample_m3.so6.7z')

with plt.style.context('traffic'):
    fig = plt.figure()
    ax = plt.axes(projection=Lambert93())

    ax.add_feature(countries())
    ax.gridlines()
    ax.set_extent(nm_airspaces['LFFFUIR'])

    nm_airspaces['LFFFUIR'].plot(ax, lw=2, alpha=.5, linestyle='dashed')
    so6['DAH1008'].plot(ax, marker='.')

    # display elementary sectors (ES) crossed by the trajectory
    for airspace in nm_airspaces.search("LF.*/ES"):
        if so6['DAH1008'].intersects(airspace):
            airspace.plot(ax, alpha=.5, lw=2)
Trajectories over Bordeaux AAC

Another use case could be to plot all flights going through an airspace at noon.

# callsigns at noon inside LFBBBDX
bdx_noon = (
    so6.at("2018-01-01 12:00")
    .inside_bbox(nm_airspaces['LFBBBDX'])
    .intersects(nm_airspaces['LFBBBDX'])
)

# full so6 limited to flights hereabove
so6_bdx_noon = so6.select(bdx_noon)
from traffic.drawing import EuroPP, countries

with plt.style.context('traffic'):
    fig = plt.figure()
    ax = plt.axes(projection=EuroPP())

    ax.add_feature(countries())
    ax.gridlines()
    ax.set_extent((-10, 15, 35, 55))

    nm_airspaces['LFBBBDX'].plot(ax, lw=2, alpha=.5)

    for _, flight in so6_bdx_noon:
        flight.plot(ax, color='#aa3a3a', lw=.4, alpha=.5)
Trajectories over Bordeaux AAC