Europe has a well-developed aviation network, making it an interesting subject for analysis. European air traffic is influenced by various factors, such as economic conditions, regulatory policies, seasonal trends, and international travel demand. This dataset allows for a broad analysis of European aviation trends, including: The busiest airports in terms of traffic, The most active countries for flight departures, Seasonal and yearly fluctuations in air traffic, The relationship between arrivals and departures and the map visualization of the busiest air traffic cities in Europe.
df <- read.csv('flights.csv')
dt <- data.table(df)
str(dt)
## Classes 'data.table' and 'data.frame': 688099 obs. of 14 variables:
## $ YEAR : int 2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
## $ MONTH_NUM : int 1 1 1 1 1 1 1 1 1 1 ...
## $ MONTH_MON : chr "JAN" "JAN" "JAN" "JAN" ...
## $ FLT_DATE : chr "2016-01-01T00:00:00Z" "2016-01-01T00:00:00Z" "2016-01-01T00:00:00Z" "2016-01-01T00:00:00Z" ...
## $ APT_ICAO : chr "EBAW" "EBBR" "EBCI" "EBLG" ...
## $ APT_NAME : chr "Antwerp" "Brussels" "Charleroi" "Liège" ...
## $ STATE_NAME : chr "Belgium" "Belgium" "Belgium" "Belgium" ...
## $ FLT_DEP_1 : int 4 174 45 6 7 98 18 1 401 3 ...
## $ FLT_ARR_1 : int 3 171 47 7 7 99 21 1 341 4 ...
## $ FLT_TOT_1 : int 7 345 92 13 14 197 39 2 742 7 ...
## $ FLT_DEP_IFR_2: int NA 174 45 NA NA NA NA NA 401 NA ...
## $ FLT_ARR_IFR_2: int NA 161 45 NA NA NA NA NA 306 NA ...
## $ FLT_TOT_IFR_2: int NA 335 90 NA NA NA NA NA 707 NA ...
## $ Pivot.Label : chr "Antwerp (EBAW)" "Brussels (EBBR)" "Charleroi (EBCI)" "Liège (EBLG)" ...
## - attr(*, ".internal.selfref")=<externalptr>
summary(dt)
## YEAR MONTH_NUM MONTH_MON FLT_DATE
## Min. :2016 Min. : 1.000 Length:688099 Length:688099
## 1st Qu.:2017 1st Qu.: 3.000 Class :character Class :character
## Median :2019 Median : 6.000 Mode :character Mode :character
## Mean :2019 Mean : 6.301
## 3rd Qu.:2020 3rd Qu.: 9.000
## Max. :2022 Max. :12.000
##
## APT_ICAO APT_NAME STATE_NAME FLT_DEP_1
## Length:688099 Length:688099 Length:688099 Min. : 0.00
## Class :character Class :character Class :character 1st Qu.: 5.00
## Mode :character Mode :character Mode :character Median : 17.00
## Mean : 63.24
## 3rd Qu.: 71.00
## Max. :847.00
##
## FLT_ARR_1 FLT_TOT_1 FLT_DEP_IFR_2 FLT_ARR_IFR_2
## Min. : 0.00 Min. : 0.0 Min. : 0.0 Min. : 0.0
## 1st Qu.: 5.00 1st Qu.: 10.0 1st Qu.: 38.0 1st Qu.: 38.0
## Median : 17.00 Median : 35.0 Median : 91.0 Median : 91.0
## Mean : 63.28 Mean : 126.5 Mean : 143.7 Mean :143.6
## 3rd Qu.: 71.00 3rd Qu.: 141.0 3rd Qu.: 195.0 3rd Qu.:195.0
## Max. :813.00 Max. :1628.0 Max. :1039.0 Max. :817.0
## NA's :479785 NA's :479785
## FLT_TOT_IFR_2 Pivot.Label
## Min. : 0.0 Length:688099
## 1st Qu.: 76.0 Class :character
## Median : 182.0 Mode :character
## Mean : 287.3
## 3rd Qu.: 390.0
## Max. :1624.0
## NA's :479785
The dataset contains 688,099 observations and 14 variables, representing flight activity at various European airports from 2016 to 2022. The data includes information about flight counts, airport details, and Instrument Flight Rules (IFR) statistics. Missing Values: IFR-related data has 479,785 missing values, indicating that a large portion of flights may not have IFR classifications.
Bar chart shows the total number of flights per year from 2016 to 2022. The number of flights increases from 2016 to 2019, reaching a peak in 2019. However, there isn’t a sharp decline in 2020, which doesn’t align with the impact of the COVID-19 pandemic on global air travel.
ggplot(dt, aes(x = YEAR)) +
geom_bar() +
theme_bw() +
labs(title = "Total Flights per Year", x = "Year", y = "Count")
This histogram shows the distribution of flight departures. The majority of airports have a relatively low number of departures by the high frequency of lower values. A few airports have significantly higher departures, creating a right-skewed distribution, meaning a small number of airports handle a disproportionately large share of departures.
ggplot(dt, aes(x = FLT_DEP_1)) +
geom_histogram() +
theme_bw() +
labs(title = "Distribution of Flight Departures", x = "Number of Departures", y = "Frequency")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
This faceted histogram shows the distribution of total flights for each year. The pattern is similar across years, with most airports operating at lower flight volumes. However, the total number of flights significantly drops in 2020 and 2021 , witha lot of airports operating close to 0.
ggplot(dt, aes(x = FLT_TOT_1)) +
geom_histogram() +
facet_wrap(~YEAR) +
theme_bw() +
labs(title = "Distribution of Total Flights per Year", x = "Total Flights", y = "Frequency")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
This line graph represents the total number of departures per year over the observed period. The trend shows a steady increase from 2016 to 2019, reaching its peak in 2019. However, there is a sharp decline in 2020, which aligns with the impact of the COVID-19 pandemic.
dt_yearly <- dt[, .(total_departures = sum(FLT_DEP_1, na.rm = TRUE)), by = YEAR]
ggplot(dt_yearly, aes(x = YEAR, y = total_departures)) +
geom_point() +
geom_line() +
theme_bw() +
labs(title = "Total Departures by Year", x = "Year", y = "Total Departures")
In This bar chart we can see the top 10 busiest airports based on total flight volume.
top_airports <- dt %>%
group_by(APT_NAME) %>%
summarise(total_flights = sum(FLT_TOT_1, na.rm = TRUE)) %>%
arrange(desc(total_flights)) %>%
slice(1:10)
ggplot(top_airports, aes(x = reorder(APT_NAME, total_flights), y = total_flights)) +
geom_col(fill = "#756bb1") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +
labs(title = "Top 10 Busiest Airports", x = "Airport", y = "Total Flights")
This bar chart ranks countries based on their total IFR (Instrument Flight Rules) departures. Western European countries have the highest IFR departures, indicatingt their role as major global aviation hubs.
state_departures <- dt %>%
group_by(STATE_NAME) %>%
summarise(total_departures = sum(FLT_DEP_1, na.rm = TRUE))
ggplot(state_departures, aes(x = reorder(STATE_NAME, -total_departures), y = total_departures)) +
geom_bar(stat = "identity", fill = "#dd1c77") +
theme_bw() +
labs(title = "Total IFR Departures by Country",
x = "Country",
y = "Number of Departures") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5))
This faceted chart shows the number of flights per country over time. The trends vary across countries, with smaller countries exhibiting relatively stable trends.
ggplot(dt, aes(x = fct_infreq(STATE_NAME))) +
geom_bar() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +
facet_wrap(~YEAR) +
labs(title = "Number of Flights per Country", x = "Country", y = "Flight Count")
This bar chart displays the number of IFR departures at different airports. A small number of airports take a majority of IFR departures, while most airports have relatively low IFR activity.
dt_filt <- dt[FLT_DEP_IFR_2 > 0]
ggplot(dt_filt, aes(x = fct_reorder(APT_NAME, -FLT_DEP_IFR_2), y = FLT_DEP_IFR_2)) +
geom_bar(stat = "identity") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +
labs(title = "IFR Departures by Airport", x = "Airport", y = "Number of IFR Departures")
This faceted bar chart shows yearly IFR departures for different countries. We can see clear trend with specific countries consistently dominating each year.
ggplot(dt_filt, aes(x = reorder(STATE_NAME, -FLT_DEP_IFR_2), y = FLT_DEP_IFR_2, fill = as.factor(YEAR))) +
geom_bar(stat = "identity", show.legend = FALSE) +
theme_bw() +
facet_wrap(~ YEAR, scales = "free_y") +
labs(title = "Yearly IFR Departures by Country",
x = "Airport",
y = "Number of Departures") +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5)) # Adjust alignment
This box plot shows the distribution of IFR departures across different airports. The red dots highlight outliers, which indicate airports with higher or lower than usual flight activity.
ggplot(dt_filt, aes(x = APT_NAME, y = FLT_DEP_IFR_2)) +
geom_boxplot(outlier.colour = "red") +
theme_bw() +
labs(title = "Distribution of IFR Departures by Airport",
x = "Airport",
y = "Number of Departures") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
This boxplot shows the distribution of flight departures from 2016 to 2022. The number of departures remains relatively stable from 2016 to 2019, followed by a steep drop in 2020.
ggplot(dt, aes(x = factor(YEAR), y = FLT_DEP_1)) +
geom_boxplot(outlier.colour = "blue") +
theme_bw() +
labs(title = "Departures Over Time", x = "Year", y = "Number of Departures")
This faceted box plot displays monthly departures across different years. Each small panel represents a month within each, bars show the number of flights per month. We can see the seasonal trend each year before 2020, and big sudden decline in April, May, and June of 2020.
ggplot(dt, aes(x = factor(MONTH_NUM), y = FLT_DEP_1)) +
geom_boxplot(outlier.colour = "blue") +
facet_wrap(~YEAR) +
theme_bw() +
labs(title = "Monthly Departures by Year", x = "Month", y = "Number of Departures")
This bar chart represents the total number of flight movements (departures + arrivals) for each country. Because there were a lot of close to 0 values for European cities this graph wasn’t successfull. The total flights that we want to observe here shown as outliers.
dt[, FLT_TOT_1 := FLT_DEP_1 + FLT_ARR_1]
ggplot(dt, aes(x = STATE_NAME, y = FLT_TOT_1)) +
geom_boxplot(outlier.colour = "blue") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +
labs(title = "Total Flight Movements by Country", x = "Country", y = "Total Flights")
The next two graphs are just to confirm the accuracy of the data. A regression plot showing the relationship between departures and arrivals. The near-perfect diagonal alignment confirms a high correlation, meaning most airports have a balanced number of departing and arriving flights.
ggplot(dt, aes(x = FLT_DEP_1, y = FLT_ARR_1)) +
geom_point(alpha = 0.3) +
geom_smooth(method = "lm") +
theme_bw() +
labs(title = "Correlation Between Departures and Arrivals", x = "Departures", y = "Arrivals")
## `geom_smooth()` using formula = 'y ~ x'
This scatter plot compares the number of departures and arrivals for different countries. Each point represents a country with their color-coding.The strong diagonal trend again shows that most countries have close to equal departures and arivals, which is expected, but there are some slight deviations.
ggplot(dt_filt, aes(x = FLT_DEP_IFR_2, y = FLT_ARR_IFR_2, color = STATE_NAME)) +
geom_point(alpha = 0.5) +
theme_bw() +
labs(title = "Departures vs Arrivals by Country",
x = "IFR Departures",
y = "IFR Arrivals") +
geom_smooth(method = "lm", se = FALSE, color = "black", linetype = "dashed")
## `geom_smooth()` using formula = 'y ~ x'
I wanted to show the map by flight volume, but when i merged the cities lat and long data there were a lot of missing values
A world map visualizing total flights handled by different cities globally. The color gradient represents flight volume, with darker shades indicating airports with higher traffic. This map isn’t particularly useful, as cities in Europe are not clearly visible, and there are limited observations outside of Europe.
# Download city coordinates data
cities_url <- "https://simplemaps.com/static/data/world-cities/basic/simplemaps_worldcities_basicv1.75.zip"
temp <- tempfile()
download.file(cities_url, temp)
unzip(temp, files = "worldcities.csv")
cities <- fread("worldcities.csv")
unique_cities <- unique(dt$APT_NAME)
european_cities <- cities[city %in% unique_cities, .(APT_NAME = city, lat, lng)]
european_cities[, .N, by = APT_NAME][N > 1]
## APT_NAME N
## <char> <int>
## 1: Santiago 11
## 2: Barcelona 3
## 3: Vienna 4
## 4: Hamburg 2
## 5: Valencia 7
## 6: Birmingham 3
## 7: Athens 6
## 8: Riga 2
## 9: Dublin 4
## 10: Lisbon 3
## 11: Naples 2
## 12: Sevilla 2
## 13: Zaragoza 4
## 14: Stuttgart 2
## 15: Rotterdam 2
## 16: Glasgow 3
## 17: Bristol 7
## 18: Bremen 2
## 19: Manchester 10
## 20: Newcastle 4
## 21: Valladolid 3
## 22: Santa Maria 9
## 23: Southampton 6
## 24: Venice 2
## 25: Bergen 5
## 26: Porto 2
## 27: Granada 4
## 28: Geneva 4
## 29: Groningen 2
## 30: Aberdeen 7
## 31: Santander 2
## 32: Burgos 6
## 33: Flores 2
## 34: Farnborough 2
## 35: Faro 2
## 36: Waterford 7
## 37: La Palma 4
## 38: Weston 4
## 39: Hanover 9
## 40: Montijo 2
## 41: Malta 2
## 42: Shannon 2
## 43: Madeira 2
## APT_NAME N
european_cities <- european_cities[!duplicated(APT_NAME)]
merged_data <- merge(dt, european_cities, by = "APT_NAME", all.x = TRUE)
sum(is.na(merged_data$lat)) ## A lot of missing values
## [1] 411872
city_flights <- merged_data %>%
group_by(APT_NAME, lat, lng) %>%
summarise(total_flights = sum(FLT_TOT_1, na.rm = TRUE)) %>%
ungroup()
## `summarise()` has grouped output by 'APT_NAME', 'lat'. You can override using
## the `.groups` argument.
world_map <- ne_countries(scale = "medium", returnclass = "sf")
ggplot() +
geom_sf(data = world_map, fill = "gray90", color = "black") +
geom_point(data = city_flights, aes(x = lng, y = lat, color = total_flights),
alpha = 0.7, size = 3) +
theme_minimal() +
labs(title = "Global Airports by Total Flights",
subtitle = "Color represents the number of flights", color = "Total Flights")
## Warning: Removed 204 rows containing missing values or values outside the scale range
## (`geom_point()`).
Here we keep only European cities and limit the map to the European region. Unfortunately, this was not very helpful due to the absence of latitude and longitude values for certain cities.
europe_cities <- city_flights %>%
filter(lat >= 35, lat <= 72, lng >= -25, lng <= 40)
ggplot() +
geom_sf(data = world_map, fill = "gray90", color = "black") +
geom_point(data = europe_cities, aes(x = lng, y = lat, color = total_flights),
alpha = 0.7, size = 3) +
theme_bw() +
labs(title = "European Airports by Total Flights",
subtitle = "Color represents the number of flights", color = "Total Flights") +
coord_sf(xlim = c(-25, 40), ylim = c(35, 72), expand = FALSE) # Limit map to Europe
In this analysis of European flight data, we observed clear seasonal trends in air traffic. The total departures by year highlighted dominant countries in air travel. In a lot of graphs that we observed we can see clear decline in 2020 flights due to the impact of the COVID-19 pandemic. By refining the scope to European cities, we obtained more meaningful insights into air traffic patterns.