History of opensky_flights_full
The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.
[entries] New entry: opensky_flights_full ceaf68c
diff --git a/entries/opensky_flights_full/__init__.py b/entries/opensky_flights_full/__init__.py
new file mode 100644
index 0000000..dccfc31
--- /dev/null
+++ b/entries/opensky_flights_full/__init__.py
@@ -0,0 +1,162 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import csv
+from collections import Counter
+
+from .. import *
+
+# The monthly files (the one of May 2021 is named as ending on the 30th)
+fnames = ["flightlist_20190101_20190131",
+ "flightlist_20190201_20190228",
+ "flightlist_20190301_20190331",
+ "flightlist_20190401_20190430",
+ "flightlist_20190501_20190531",
+ "flightlist_20190601_20190630",
+ "flightlist_20190701_20190731",
+ "flightlist_20190801_20190831",
+ "flightlist_20190901_20190930",
+ "flightlist_20191001_20191031",
+ "flightlist_20191101_20191130",
+ "flightlist_20191201_20191231",
+ "flightlist_20200101_20200131",
+ "flightlist_20200201_20200229",
+ "flightlist_20200301_20200331",
+ "flightlist_20200401_20200430",
+ "flightlist_20200501_20200531",
+ "flightlist_20200601_20200630",
+ "flightlist_20200701_20200731",
+ "flightlist_20200801_20200831",
+ "flightlist_20200901_20200930",
+ "flightlist_20201001_20201031",
+ "flightlist_20201101_20201130",
+ "flightlist_20201201_20201231",
+ "flightlist_20210101_20210131",
+ "flightlist_20210201_20210228",
+ "flightlist_20210301_20210331",
+ "flightlist_20210401_20210430",
+ "flightlist_20210501_20210530",
+ "flightlist_20210601_20210630",
+ "flightlist_20210701_20210731",
+ "flightlist_20210801_20210831",
+ "flightlist_20210901_20210930",
+ "flightlist_20211001_20211031",
+ "flightlist_20211101_20211130",
+ "flightlist_20211201_20211231",
+ "flightlist_20220101_20220131",
+ "flightlist_20220201_20220228",
+ "flightlist_20220301_20220331",
+ "flightlist_20220401_20220430",
+ "flightlist_20220501_20220531",
+ "flightlist_20220601_20220630",
+ "flightlist_20220701_20220731",
+ "flightlist_20220801_20220831",
+ "flightlist_20220901_20220930",
+ "flightlist_20221001_20221031",
+ "flightlist_20221101_20221130",
+ "flightlist_20221201_20221231"]
+
+title = "OpenSky airport networks, non-commercial release (2019-2022)"
+description = r"""Monthly networks of flights between airports worldwide, from January 2019 to December 2022, derived from the crowdsourced air traffic data of the OpenSky Network, a network of more than 2500 receivers of the ADS-B and Mode S messages broadcast by aircraft. The data were compiled by Strohmeier, Olive, Lübbe, Schäfer and Lenders to illustrate the development of air traffic during the COVID-19 pandemic. This is the last release (v23.00, of May 2023) of the version of the data set with non-anonymized aircraft information, which extends to December 2022, and whose files of earlier months were corrected ("fixed after a thorough sanity check") with respect to the previous releases; the version with anonymized aircraft information and a CC BY license, which ends in December 2021, is in the entry `opensky_flights`. The data lists every flight seen by the network, with its origin and destination airports, which were inferred from the trajectory of the aircraft on takeoff and approach, without cross-checking with other sources.
+
+**This entry is restricted** because the license of this release of the data (the OpenSky Network's General Terms of Use & Data License Agreement) does not allow distributing the data to other persons, and limits its use to non-profit research and education, commercial internal testing and evaluation, and government purposes.
+
+Each network covers one month, and is named by it (e.g. `2022-04`); the month of a flight is the (UTC) day of the last message received from it. Nodes are airports, identified by their four-letter (ICAO) codes, and a directed edge from one airport to another is weighted by the number of flights from the first to the second in that month. The individual flights are aggregated into these weighted edges (about 72 million flights over the four years, of those whose origin and destination are known). The networks of 2019 to 2021 differ from those of `opensky_flights` in some months (e.g. September 2019, December 2019 and September 2021), because of the corrections. Flights whose origin or destination airport could not be determined (which are many, e.g. flights that left the coverage of the network) are left out. Flights that took off and landed at the same airport (e.g. training or test flights) are kept as self-loops. Only airports with at least one flight in the month are included.
+
+The names, positions and types of the airports come from the OurAirports database (public domain; a snapshot of January 2022), matched by their ICAO code or, failing that, by their GPS code; for airport codes that are not found there, these properties are empty (`NaN` for the coordinates).
+
+The networks have the following properties:
+
+- Nodes: `code`, the four-letter code of the airport (as given by OpenSky); `name`, the name of the airport; `lat` and `lon`, its latitude and longitude; `type`, the type of airport in OurAirports (e.g. `large_airport`, `small_airport`, `heliport`); `country`, the ISO 3166-1 code of its country.
+- Edges: `weight`, the number of flights from the origin to the destination airport in the month."""
+tags = ['Transportation', 'Airport', 'Weighted', 'Temporal', 'Metadata']
+url = ['https://doi.org/10.5281/zenodo.7923702',
+ 'https://github.com/davidmegginson/ourairports-data']
+citation = [('M. Strohmeier, X. Olive, J. Lübbe, M. Schäfer, V. Lenders, "Crowdsourced air traffic data from the OpenSky Network 2019–2020." Earth System Science Data 13(2), 357-366 (2021)', 'https://doi.org/10.5194/essd-13-357-2021')]
+icon_hash = None
+upstream_license = ("OpenSky Network General Terms of Use & Data License Agreement (non-commercial; no redistribution); the OurAirports data is in the public domain",
+ "https://zenodo.org/records/7923702/files/LICENSE.txt")
+restricted = True
+# Release v23.00 of the non-commercial version (Zenodo record, not the
+# concept record)
+upstream_prefix = 'https://zenodo.org/records/7923702/files'
+files = [(f"{fn}.csv.gz", f"{fn[11:15]}-{fn[15:17]}", None) for fn in fnames]
+
+# OurAirports, at a fixed commit (January 2022)
+airports_prefix = 'https://raw.githubusercontent.com/davidmegginson/ourairports-data/ec71345bc713a944088f48eb7884bea763045ec9'
+airports_files = [('airports.csv', None, None)]
+
+def fetch_upstream(force=False):
+ name = __name__.split(".")[-1]
+ fetch_upstream_files(name, upstream_prefix, files, force)
+ return fetch_upstream_files(name, airports_prefix, airports_files, force)
+
+def get_airports(name):
+ airports = {}
+ gps = {}
+ with open_upstream_file(name, "airports.csv", "r") as f:
+ for row in csv.DictReader(f):
+ vals = (row["name"], float(row["latitude_deg"]),
+ float(row["longitude_deg"]), row["type"],
+ row["iso_country"])
+ airports[row["ident"]] = vals
+ if row["gps_code"]:
+ gps.setdefault(row["gps_code"], vals)
+ for code, vals in gps.items():
+ airports.setdefault(code, vals)
+ return airports
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ global files
+ name = __name__.split(".")[-1]
+ airports = None
+ for fnames, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ if airports is None:
+ airports = get_airports(name)
+ # The flights are streamed, and counted for each pair of airports
+ count = Counter()
+ with open_upstream_file(name, fnames, "r") as f:
+ reader = csv.reader(f)
+ header = next(reader)
+ io_, id_ = header.index("origin"), header.index("destination")
+ for row in reader:
+ o, d = row[io_], row[id_]
+ if o and d:
+ count[(o, d)] += 1
+ g = Graph(directed=True)
+ g.ep.weight = g.new_ep("int")
+ g.vp.code = g.add_edge_list(((o, d, w) for (o, d), w in sorted(count.items())),
+ hashed=True, hash_type="string",
+ eprops=[g.ep.weight])
+ g.vp.name = g.new_vp("string")
+ g.vp.lat = g.new_vp("double", val=numpy.nan)
+ g.vp.lon = g.new_vp("double", val=numpy.nan)
+ g.vp.type = g.new_vp("string")
+ g.vp.country = g.new_vp("string")
+ for v in g.vertices():
+ a = airports.get(g.vp.code[v])
+ if a is None:
+ continue
+ (g.vp.name[v], g.vp.lat[v], g.vp.lon[v], g.vp.type[v],
+ g.vp.country[v]) = a
+ yield alt, g