The nycflights13 package contains all 336,776 flights
that departed the three New York City airports (Newark, JFK, and
LaGuardia) in 2013.
library(tidyverse)
library(nycflights13)
dim(flights)
## [1] 336776 19
I used four dplyr commands to reshape the raw flight records into one average per airport per hour:
filter drops cancelled flights, which have no departure
delay recordedgroup_by groups the remaining flights by origin airport
and scheduled departure hoursummarize computes the mean delay and counts the
flights in each groupfilter removes hour-airport combinations with
fewer than 100 flights, so a handful of unusual late-night departures
cannot swing an averagedelay_by_hour <- flights |>
filter(!is.na(dep_delay)) |>
group_by(origin, hour) |>
summarize(avg_delay = mean(dep_delay),
flights = n(),
.groups = "drop") |>
filter(flights >= 100)
head(delay_by_hour)
## # A tibble: 6 × 4
## origin hour avg_delay flights
## <chr> <dbl> <dbl> <int>
## 1 EWR 5 0.649 892
## 2 EWR 6 3.50 10959
## 3 EWR 7 4.04 8540
## 4 EWR 8 5.50 9114
## 5 EWR 9 5.84 5993
## 6 EWR 10 7.79 6571
flight_plot <- delay_by_hour |>
ggplot(aes(x = hour, y = avg_delay, color = origin)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey60") +
geom_line(linewidth = 1) +
geom_point(size = 2.5) +
scale_color_manual(name = "Origin Airport",
values = c("EWR" = "#E69F00",
"JFK" = "#0072B2",
"LGA" = "#009E73"),
labels = c("EWR (Newark)",
"JFK (Kennedy)",
"LGA (LaGuardia)")) +
scale_x_continuous(breaks = seq(5, 23, 2)) +
labs(title = "Departure Delays Build Through the Day at All Three NYC Airports",
subtitle = "Flights scheduled before 7am leave roughly on time; by 8pm the average flight is over 20 minutes late",
x = "Scheduled Departure Hour (24-hour clock)",
y = "Average Departure Delay (minutes)",
caption = "Source: nycflights13 R package (all 336,776 flights departing EWR, JFK, and LGA in 2013),
originally from the US Bureau of Transportation Statistics") +
theme_minimal(base_size = 12) +
theme(legend.position = "right",
plot.title = element_text(face = "bold"))
flight_plot
Average departure delay by scheduled hour for the three NYC airports
The visualization is a scatterplot with connecting lines, where each point is the average departure delay for one airport at one scheduled hour.
The pattern is strikingly consistent across all three airports. Flights scheduled between 5am and 7am leave essentially on time, with average delays near zero and LaGuardia’s 6am flights actually departing slightly early. From there the averages climb steadily all day. Newark peaks at 7pm around 31 minutes, while JFK and LaGuardia both sit above 20 minutes through the evening. The lines get jumpy after 8pm because far fewer flights are scheduled that late, so each remaining average rests on a smaller sample and is less stable than the daytime points.
The reason is that delay compounds. Early flights start the day with aircraft and crews already in position, so there is nothing upstream to inherit. As the day progresses, each late arrival pushes back the next departure for that plane, and congestion accumulates faster than the schedule can absorb it. The practical takeaway is straightforward: if you want to leave on time out of New York, book the earliest flight you can.
Newark sits above the other two airports for most of the day, which fits its reputation as the most delay-prone of the three. The gap widens in the afternoon, suggesting Newark absorbs accumulated delay less well than JFK or LaGuardia rather than simply starting out worse.
filter,
group_by, summarize, and a second
filternycflights13 package, originally US Bureau of
Transportation Statistics