Air Flow Visualisation by Country#

This notebook analyses and visualises air freight and passenger flows for a selected country. It integrates airport infrastructure data, air OD (Origin-Destination) matrices, and country boundaries to provide insights into inbound and outbound flows at each airport. The workflow includes data loading, filtering, aggregation, visualisation, and summary statistics, supporting both freight and passenger air flows. The output includes maps and tables summarizing flows for each airport, with a focus on the selected country.

1. Import Required Libraries and Country Boundaries#

This section imports all necessary Python libraries and loads the country boundaries dataset. It ensures the spatial data is in the correct coordinate reference system and filters the boundaries to the European region, preparing the context for subsequent air flow analysis.

Hide code cell source

# HIDE CODE
import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt
import warnings
from pathlib import Path
import sys

from miraca_book.download import download
sys.path.append(str(Path().resolve().parent))

from utils.miraca_flow_utils import (
    plot_bubble_map, get_country_geometry, get_id_column, 
    aggregate_od_flows, merge_flows_with_nodes, print_transport_summary,
    load_europe_countries
)

warnings.filterwarnings('ignore')

outpath = Path('~/.miraca').expanduser() / "output"
outpath.mkdir(exist_ok=True, parents=True)
base_path = download('https://zenodo.org/records/18428552/files/MIRACA_Transport_Flow_Model.zip?download=1') / 'data'
# Load European countries using shared function
europe_countries = load_europe_countries(base_path)
Loaded 54 countries in Europe region

2. Load air Network and OD Data#

This section loads the air network data, including airport locations and air OD (Origin-Destination) matrices for freight and passengers. It identifies the selected country, extracts its geometry, and filters the airport dataset to include only airports within the country’s boundaries. This prepares the data for flow aggregation and analysis.

# Load air data
print("Loading air network data...")

air_freight_od = pd.read_parquet(base_path / 'ODs_BE/belgium_air_freight_OD.parquet')
air_passenger_od = pd.read_parquet(base_path / 'ODs_BE/belgium_air_passenger_OD.parquet')
airports_gdf = gpd.read_parquet(base_path / "Infra_BE/belgium_airports.parquet").to_crs("EPSG:4326")

# Set the selected country
SELECTED_COUNTRY = "Belgium"

# Extract country geometry using helper function
country_row, country_geom = get_country_geometry(europe_countries, SELECTED_COUNTRY)

# Filter airports by spatial relation
country_airports = airports_gdf[airports_gdf.within(country_geom)].copy()

# Determine ID column for airports using helper function
port_id_candidates = ['icao', 'id', 'node_id', 'code', 'UNLOCODE', 'unlocode']
port_id_col = get_id_column(country_airports, port_id_candidates)

# Build code lists used for OD filtering
icaos = country_airports[port_id_col].astype(str).tolist()

print("... network loaded")
Loading air network data...
... network loaded

3. Calculate air Flows (Inbound and Outbound)#

This section filters and aggregates the air OD data to calculate inbound and outbound freight and passenger flows for each port in the selected country. It merges these flows with airport data and prepares summary tables for both freight and passenger movements.

# --- Process Air Freight Flows ---
air_freight_inbound, air_freight_outbound, freight_inbound_agg, freight_outbound_agg = \
    aggregate_od_flows(air_freight_od, icaos)

print("Air freight flows:")
print(f"  Inbound: {len(air_freight_inbound)} connections")
print(f"  Outbound: {len(air_freight_outbound)} connections")
print(f"  Total inbound flow: {air_freight_inbound['value'].sum():,.0f} tons/day")
print(f"  Total outbound flow: {air_freight_outbound['value'].sum():,.0f} tons/day")

country_airports_flow = merge_flows_with_nodes(
    country_airports, port_id_col, freight_inbound_agg, freight_outbound_agg,
    name_col=None, corridor_col='CORRIDORS'
)
print(f"\n✓ Aggregated flows for {len(country_airports_flow)} airports (terminals combined)")

# --- Process Air Passenger Flows ---
air_passenger_inbound, air_passenger_outbound, pass_inbound_agg, pass_outbound_agg = \
    aggregate_od_flows(air_passenger_od, icaos)

# Rename columns for passengers
pass_inbound_agg.columns = ['port_id', 'inbound_passengers']
pass_outbound_agg.columns = ['port_id', 'outbound_passengers']

print(f"\nAir passenger flows:")
print(f"  Inbound: {len(air_passenger_inbound)} connections")
print(f"  Outbound: {len(air_passenger_outbound)} connections")
print(f"  Total inbound flow: {air_passenger_inbound['value'].sum():,.0f} passengers/day")
print(f"  Total outbound flow: {air_passenger_outbound['value'].sum():,.0f} passengers/day")

country_airports_passengers = merge_flows_with_nodes(
    country_airports, port_id_col, pass_inbound_agg, pass_outbound_agg,
    inbound_col='inbound_passengers', outbound_col='outbound_passengers',
    name_col=None, corridor_col='CORRIDORS'
)
print(f"✓ Aggregated passenger flows for {len(country_airports_passengers)} airports (terminals combined)")
Air freight flows:
  Inbound: 6 connections
  Outbound: 1 connections
  Total inbound flow: 818 tons/day
  Total outbound flow: 0 tons/day

✓ Aggregated flows for 42 airports (terminals combined)

Air passenger flows:
  Inbound: 110 connections
  Outbound: 102 connections
  Total inbound flow: 109,306,168 passengers/day
  Total outbound flow: 114,859,784 passengers/day
✓ Aggregated passenger flows for 42 airports (terminals combined)

4. Visualise Air Flows#

This section generates visualisations of air flows using bubble maps. It displays inbound and outbound freight and passenger flows for each airport, highlighting the spatial distribution and magnitude of flows across the selected country’s airports.

# Visualise all air flows
print("Generating bubble map subplots...")
country_name='BELGIUM'
fig, axes = plt.subplots(2, 2, figsize=(24, 18))
axes = axes.flatten()

# 1. Freight Outbound
plot_bubble_map(
    axes[0], country_airports_flow, 'outbound_flow', 'CORRIDORS', country_row, SELECTED_COUNTRY,
    'Outbound', 'Freight', outpath, scale_factor=100, flow_values=[1, 100, 10000, 1000000]
)
axes[0].set_title('Freight Outbound')

# 2. Freight Inbound
plot_bubble_map(
    axes[1], country_airports_flow, 'inbound_flow', 'CORRIDORS', country_row, SELECTED_COUNTRY,
    'Inbound', 'Freight', outpath, scale_factor=100, flow_values=[1, 100, 10000, 1000000]
)
axes[1].set_title('Freight Inbound')

# 3. Passenger Outbound
plot_bubble_map(
    axes[2], country_airports_passengers, 'outbound_passengers', 'CORRIDORS', country_row, SELECTED_COUNTRY,
    'Outbound', 'Passenger', outpath, scale_factor=100, flow_values=[10, 1000, 100000, 10000000000]
)
axes[2].set_title('Passenger Outbound')

# 4. Passenger Inbound
plot_bubble_map(
    axes[3], country_airports_passengers, 'inbound_passengers', 'CORRIDORS', country_row, SELECTED_COUNTRY,
    'Inbound', 'Passenger', outpath, scale_factor=150, flow_values=[10, 1000, 100000, 10000000000]
)
axes[3].set_title('Passenger Inbound')

filename = f'Air_bubbles_{country_name.replace(" ", "_")}.png'
plt.savefig(outpath / filename, dpi=300, bbox_inches='tight')
plt.tight_layout()
plt.show()
Generating bubble map subplots...
../../../_images/2b15af323ce76f47b477b76550aa6a5255cd73c5f25fa9ef84bab917a02a6404.png

5. Summary Statistics#

This section provides summary statistics for the selected country’s air infrastructure and flows. It reports the number of airports, total inbound and outbound freight and passenger flows, and net flows, offering a concise overview of the country’s air activity.

print_transport_summary(
    SELECTED_COUNTRY, len(country_airports),
    country_airports_flow, country_airports_passengers,
    'inbound_flow', 'outbound_flow',
    'inbound_passengers', 'outbound_passengers',
    freight_unit='tons/day', passenger_unit='passengers/day',
    node_type='Airports'
)
============================================================
SUMMARY FOR Belgium
============================================================

Infrastructure:
  Airports: 42

Freight Flows:
  Airports with inbound flow: 2
  Airports with outbound flow: 1
  Total inbound: 818 tons/day
  Total outbound: 0 tons/day
  Net flow: -818 tons/day

Passenger Flows:
  Airports with inbound flow: 4
  Airports with outbound flow: 3
  Total inbound: 109,306,168 passengers/day
  Total outbound: 114,859,784 passengers/day
  Net flow: 5,553,616 passengers/day
============================================================