Show the code
library(anyflights)
library(tidyverse)
library(geosphere)
library(maps)
library(ggrepel)Seth Kasowitz
November 3, 2025
Unable to get to a computer yesterday, this challenge is off to a rocky start. To help catch up I am cheating a bit, using a single data set to tackle days 2 (Lines) and 3 (Polygons) for the 30DayMapChallenge.
Flight data from the (Bureau of Transportation Statistics)[https://www.bts.gov/].
I am focusing on flights to and from JFK airport in New York.
Rows: 590,581
Columns: 110
$ Year <dbl> 2024, 2024, 2024, 2024, 2024, 2024, 20…
$ Quarter <dbl> 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,…
$ Month <dbl> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12…
$ DayofMonth <dbl> 25, 26, 27, 28, 29, 30, 31, 19, 20, 21…
$ DayOfWeek <dbl> 3, 4, 5, 6, 7, 1, 2, 4, 5, 6, 7, 1, 2,…
$ FlightDate <date> 2024-12-25, 2024-12-26, 2024-12-27, 2…
$ Reporting_Airline <chr> "9E", "9E", "9E", "9E", "9E", "9E", "9…
$ DOT_ID_Reporting_Airline <dbl> 20363, 20363, 20363, 20363, 20363, 203…
$ IATA_CODE_Reporting_Airline <chr> "9E", "9E", "9E", "9E", "9E", "9E", "9…
$ Tail_Number <chr> "N902XJ", "N491PX", "N915XJ", "N917XJ"…
$ Flight_Number_Reporting_Airline <dbl> 5125, 5125, 5125, 5125, 5125, 5125, 51…
$ OriginAirportID <dbl> 11995, 11995, 11995, 11995, 11995, 119…
$ OriginAirportSeqID <dbl> 1199502, 1199502, 1199502, 1199502, 11…
$ OriginCityMarketID <dbl> 31995, 31995, 31995, 31995, 31995, 319…
$ Origin <chr> "GSO", "GSO", "GSO", "GSO", "GSO", "GS…
$ OriginCityName <chr> "Greensboro/High Point, NC", "Greensbo…
$ OriginState <chr> "NC", "NC", "NC", "NC", "NC", "NC", "N…
$ OriginStateFips <chr> "37", "37", "37", "37", "37", "37", "3…
$ OriginStateName <chr> "North Carolina", "North Carolina", "N…
$ OriginWac <dbl> 36, 36, 36, 36, 36, 36, 36, 22, 22, 22…
$ DestAirportID <dbl> 12953, 12953, 12953, 12953, 12953, 129…
$ DestAirportSeqID <dbl> 1295304, 1295304, 1295304, 1295304, 12…
$ DestCityMarketID <dbl> 31703, 31703, 31703, 31703, 31703, 317…
$ Dest <chr> "LGA", "LGA", "LGA", "LGA", "LGA", "LG…
$ DestCityName <chr> "New York, NY", "New York, NY", "New Y…
$ DestState <chr> "NY", "NY", "NY", "NY", "NY", "NY", "N…
$ DestStateFips <chr> "36", "36", "36", "36", "36", "36", "3…
$ DestStateName <chr> "New York", "New York", "New York", "N…
$ DestWac <dbl> 22, 22, 22, 22, 22, 22, 22, 36, 36, 36…
$ CRSDepTime <chr> "1240", "1150", "1150", "1100", "1150"…
$ DepTime <chr> "1235", "1146", "1144", "1214", "1141"…
$ DepDelay <dbl> -5, -4, -6, 74, -9, -12, -5, -7, -3, -…
$ DepDelayMinutes <dbl> 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ DepDel15 <dbl> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ DepartureDelayGroups <dbl> -1, -1, -1, 4, -1, -1, -1, -1, -1, -1,…
$ DepTimeBlk <chr> "1200-1259", "1100-1159", "1100-1159",…
$ TaxiOut <dbl> 11, 15, 13, 13, 17, 14, 13, 21, 31, 53…
$ WheelsOff <chr> "1246", "1201", "1157", "1227", "1158"…
$ WheelsOn <chr> "1350", "1305", "1301", "1333", "1303"…
$ TaxiIn <dbl> 6, 5, 6, 7, 8, 9, 6, 4, 5, 4, 4, 3, 6,…
$ CRSArrTime <chr> "1429", "1336", "1336", "1244", "1336"…
$ ArrTime <chr> "1356", "1310", "1307", "1340", "1311"…
$ ArrDelay <dbl> -33, -26, -29, 56, -25, -31, -27, -25,…
$ ArrDelayMinutes <dbl> 0, 0, 0, 56, 0, 0, 0, 0, 1, 4, 0, 0, 2…
$ ArrDel15 <dbl> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,…
$ ArrivalDelayGroups <dbl> -2, -2, -2, 3, -2, -2, -2, -2, 0, 0, -…
$ ArrTimeBlk <chr> "1400-1459", "1300-1359", "1300-1359",…
$ Cancelled <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ CancellationCode <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Diverted <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ CRSElapsedTime <dbl> 109, 106, 106, 104, 106, 106, 109, 121…
$ ActualElapsedTime <dbl> 81, 84, 83, 86, 90, 87, 87, 103, 125, …
$ AirTime <dbl> 64, 64, 64, 66, 65, 64, 68, 78, 89, 74…
$ Flights <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ Distance <dbl> 461, 461, 461, 461, 461, 461, 461, 461…
$ DistanceGroup <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,…
$ CarrierDelay <dbl> NA, NA, NA, 0, NA, NA, NA, NA, NA, NA,…
$ WeatherDelay <dbl> NA, NA, NA, 0, NA, NA, NA, NA, NA, NA,…
$ NASDelay <dbl> NA, NA, NA, 0, NA, NA, NA, NA, NA, NA,…
$ SecurityDelay <dbl> NA, NA, NA, 0, NA, NA, NA, NA, NA, NA,…
$ LateAircraftDelay <dbl> NA, NA, NA, 56, NA, NA, NA, NA, NA, NA…
$ FirstDepTime <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ TotalAddGTime <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ LongestAddGTime <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ DivAirportLandings <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ DivReachedDest <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ DivActualElapsedTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ DivArrDelay <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ DivDistance <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1Airport <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1AirportID <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1AirportSeqID <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1WheelsOn <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1TotalGTime <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1LongestGTime <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1WheelsOff <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div1TailNum <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2Airport <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2AirportID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2AirportSeqID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2WheelsOn <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2TotalGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2LongestGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2WheelsOff <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div2TailNum <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3Airport <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3AirportID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3AirportSeqID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3WheelsOn <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3TotalGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3LongestGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3WheelsOff <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div3TailNum <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4Airport <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4AirportID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4AirportSeqID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4WheelsOn <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4TotalGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4LongestGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4WheelsOff <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div4TailNum <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5Airport <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5AirportID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5AirportSeqID <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5WheelsOn <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5TotalGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5LongestGTime <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5WheelsOff <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Div5TailNum <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ ...110 <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
Rows: 1,251
Columns: 4
$ faa <chr> "AAF", "AAP", "ABE", "ABI", "ABL", "ABQ", "ABR", "ABY", "ACK", "A…
$ name <chr> "Apalachicola Regional Airport", "Andrau Airpark", "Lehigh Valley…
$ lat <dbl> 29.72750, 29.72250, 40.65210, 32.41130, 67.10630, 35.04020, 45.44…
$ lon <dbl> -85.02750, -95.58830, -75.44080, -99.68190, -157.85699, -106.6090…
I am interested in inbound and outbound flights for JFK during holiday travel at the end of the year.
Rows: 7,428
Columns: 8
$ FlightDate <date> 2024-12-20, 2024-12-21, 2024-12-22, 2024-12-23, 202…
$ Reporting_Airline <chr> "9E", "9E", "9E", "9E", "9E", "9E", "9E", "9E", "9E"…
$ Origin <chr> "BGR", "BGR", "BGR", "BGR", "BGR", "BGR", "BGR", "BG…
$ OriginCityName <chr> "Bangor, ME", "Bangor, ME", "Bangor, ME", "Bangor, M…
$ OriginState <chr> "ME", "ME", "ME", "ME", "ME", "ME", "ME", "ME", "ME"…
$ Dest <chr> "JFK", "JFK", "JFK", "JFK", "JFK", "JFK", "JFK", "JF…
$ DestCityName <chr> "New York, NY", "New York, NY", "New York, NY", "New…
$ DestState <chr> "NY", "NY", "NY", "NY", "NY", "NY", "NY", "NY", "NY"…
great_circle_arcs <- flight_counts |>
# Add a unique identifier for each flight path
mutate(id = row_number()) %>%
# Ensure all numeric values are actually finite
filter_at(vars(origin_lat:dest_lon), all_vars(is.finite(.))) %>%
rowwise() %>%
do({
# Capture the current row's ID and count before calculating the arc
current_id <- .$id
current_n <- .$n
gc <- gcIntermediate(
c(.$origin_lon, .$origin_lat),
c(.$dest_lon, .$dest_lat),
n = 50,
addStartEnd = TRUE,
breakAtDateLine = TRUE
)
# Robustly handle matrix and vector outputs, and explicitly attach ID and N
if (is.matrix(gc)) {
as.data.frame(gc) %>%
rename(long = lon) %>%
# Explicitly attach the captured ID and N
mutate(id = current_id, n = current_n)
} else {
# Handle case where gc is a simple vector (start/end points only)
tibble(
long = c(.$origin_lon, .$dest_lon),
lat = c(.$origin_lat, .$dest_lat)
) %>%
# Explicitly attach the captured ID and N
mutate(id = current_id, n = current_n)
}
}) %>%
ungroup()ggplot() +
geom_polygon(
data = us_map,
aes(
x = long,
y = lat,
group = group
),
fill = 'grey85',
color = 'grey55',
linewidth = 0.1
) +
geom_path(
data = great_circle_arcs,
aes(x = long, y = lat, group = id, alpha = n, linewidth = n),
color = 'dodgerblue'
) +
geom_point(
data = flight_counts,
aes(x = dest_lon, y = dest_lat),
color = "#D55E00",
size = 1.5
) +
geom_point(
data = flight_counts,
aes(x = origin_lon, y = origin_lat),
color = "#009E73",
size = 1.5
) +
geom_label_repel(
data = top_routes,
aes(x = dest_lon, y = dest_lat, label = Dest)
) +
coord_sf(xlim = c(-125, -65), ylim = c(25, 50), expand = FALSE) +
labs(
title = "2024 End of Year Domestic Connections to JFK"
) +
theme_minimal() +
theme(
legend.position = 'none',
plot.title = element_text(face = "bold"),
panel.grid.major = element_line(color = "grey95"),
panel.grid.minor = element_line(color = "grey95"),
axis.text = element_blank(), # Remove lat/long tick labels for a cleaner map
axis.title = element_blank() # Remove axis titles)
)
Rather than looking at specific airports at the very end of the year, this simple choropleth presents where flights from JFK departed to in December of 2024.
states_counts <- flights |>
filter(
Year == 2024, Origin == "JFK"
) |>
select(
FlightDate,
Reporting_Airline,
Origin,
OriginCityName,
OriginState,
Dest,
DestCityName,
DestState
) |>
count(DestState)
us_states <-
tibble(state_name = tolower(state.name), state_abb = state.abb)
us_states_map <- map_data("state")
jfk_departing_map_data <- us_states_map |>
rename(state_name = region) |>
left_join(us_states, by = "state_name") |>
left_join(states_counts, by = join_by("state_abb" == "DestState"))
jfk_departing_map_data$n[is.na(jfk_departing_map_data$n)] <- 0ggplot(jfk_departing_map_data,
aes(x = long, y = lat, group = group, fill = n)) +
geom_polygon(color = 'white', linewidth = 0.1) +
scale_fill_gradientn(colors = RColorBrewer::brewer.pal(9, "YlGnBu"),
name = "Flights from JFK") +
coord_map("bonne", lat0 = 45) +
labs(title = "December 2024 Flights From JFK by Destination State") +
theme_minimal() +
theme(
plot.title = element_text(face = "bold"),
axis.title = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank()
)
@online{kasowitz2025,
author = {Kasowitz, Seth},
title = {30DayMapChallenge {Days} 02 \& 03 - {Lines} \& {Polygons}},
date = {2025-11-03},
url = {https://sethkasowitz.com/posts/2025-11-03_30DayMapChallenge_Days2-3/},
langid = {en}
}