Bangladesh-Flight-Network/bangladesh_flight_network.R
MD. PARVEJ HOSSAIN 099dc96aed FIrst Commit
2025-05-20 19:39:36 +06:00

137 lines
5.9 KiB
R

# Load packages
if (!require("pacman")) install.packages("pacman")
pacman::p_load(tidyverse, sf, igraph, tidygraph, ggraph, ggplot2,
ggspatial, rnaturalearth, rnaturalearthdata, maps, ggrepel, RColorBrewer)
# ---- Set File Paths ----
base_dir <- "E:/All Project/R Project"
bangladesh_shp_path <- file.path(base_dir, "Shapefile/Bangladesh/bgd_admbnda_adm1_bbs_20201113.shp")
world_shp_path <- file.path(base_dir, "Shapefile/World/world-administrative-boundaries.shp")
airport_file <- file.path(base_dir, "Data/airports.dat")
routes_file <- file.path(base_dir, "Data/routes.dat")
output_path <- file.path(base_dir, "Shapefile/Output/bangladesh_international_flight_network.png")
# ---- Load Shapefiles ----
bangladesh <- st_read(bangladesh_shp_path) %>% st_transform(4326)
world <- st_read(world_shp_path) %>% st_transform(4326)
# ---- Load Airport Data ----
airport_url <- "https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat"
if (!file.exists(airport_file)) download.file(airport_url, airport_file, mode = "wb")
airport <- read.csv(airport_file, header = FALSE)
colnames(airport)[1:14] <- c("ID", "Name", "City", "Country", "IATA", "ICAO",
"Latitude", "Longitude", "Altitude", "Timezone",
"DST", "Tz", "Type", "Source")
# Filter Bangladesh airports
ind_airport <- airport %>% filter(Country == "Bangladesh", IATA != "\\N")
ind_iata <- ind_airport$IATA
# ---- Load Route Data ----
routes_url <- "https://raw.githubusercontent.com/jpatokal/openflights/master/data/routes.dat"
if (!file.exists(routes_file)) download.file(routes_url, routes_file, mode = "wb")
routes <- read.csv(routes_file, header = FALSE)
colnames(routes) <- c("Airline", "Airline_ID", "Source_Airport", "Source_ID",
"Destination_Airport", "Destination_ID", "Codeshare", "Stops", "Equipment")
# Filter international routes from Bangladesh
ind_flights <- routes %>%
filter((Source_Airport %in% ind_iata & !Destination_Airport %in% ind_iata)) %>%
distinct(Source_Airport, Destination_Airport)
# ---- Prepare Nodes and Edges ----
all_iatas <- unique(c(ind_flights$Source_Airport, ind_flights$Destination_Airport))
vertices <- airport %>%
filter(IATA %in% all_iatas) %>%
mutate(lon = Longitude, lat = Latitude)
# Add color by Bangladeshi origin airport
airport_colors <- RColorBrewer::brewer.pal(n = min(8, nrow(ind_airport)), name = "Set2")
ind_airport <- ind_airport %>%
mutate(color = airport_colors[as.numeric(factor(IATA))])
edges <- ind_flights %>%
left_join(ind_airport[, c("IATA", "color")], by = c("Source_Airport" = "IATA")) %>%
rename(origin = Source_Airport, dest = Destination_Airport)
# ---- Build Graph ----
graph <- tbl_graph(nodes = vertices, edges = edges, node_key = "IATA")
# ---- Filter World Data to Connected Countries Only ----
connected_countries <- unique(left_join(edges, vertices, by = c("dest" = "IATA"))$Country)
filtered_world <- world %>% filter(name %in% connected_countries | name == "Bangladesh")
# ---- Dynamic Zoom with Extra 2° Margin ----
airport_points <- st_as_sf(vertices, coords = c("lon", "lat"), crs = 4326)
combined_geometry <- st_union(c(st_geometry(bangladesh), st_geometry(airport_points)))
zoom_bbox <- st_buffer(combined_geometry, dist = 42) # Original 30 + 2°
bbox <- st_bbox(zoom_bbox)
x_buffer_left <- 5 # Increase this to show more to the west (e.g., beyond UK)
x_buffer_right <- 5 # Increase to show more of East Asia
y_buffer_bottom <- 5 # More south (e.g., Indian Ocean)
y_buffer_top <- 5 # More north (e.g., Russia/Central Asia)
xlim <- c(bbox["xmin"] - x_buffer_left, bbox["xmax"] + x_buffer_right)
ylim <- c(bbox["ymin"] - y_buffer_bottom, bbox["ymax"] + y_buffer_top)
# ---- Plotting ----
flight_map <- ggraph(graph, layout = "manual", x = vertices$lon, y = vertices$lat) +
# Filtered world map
geom_sf(data = filtered_world, fill = "#232120", color = "NA", linewidth = 0.3, inherit.aes = FALSE) +
# Bangladesh boundary
geom_sf(data = bangladesh, fill = NA, color = "#575250", linewidth = 0.5, inherit.aes = FALSE) +
# Flight paths: colored per origin airport
geom_edge_arc(aes(color = color),
width = 0.3, alpha = 0.7, strength = 0.2,
arrow = arrow(length = unit(0.1, "cm")),
show.legend = FALSE) +
# All destination airports
geom_node_point(color = "darkgreen", size = 1.5, alpha = 0.8) +
# Highlighted Bangladesh airports (reduced size 20%)
geom_point(data = ind_airport,
aes(x = Longitude, y = Latitude),
color = "green", size = 0.5, alpha = 0.95, inherit.aes = FALSE) +
# Airport labels with bold text and dark halo
geom_text_repel(
data = left_join(edges, vertices, by = c("dest" = "IATA")) %>%
distinct(dest, City, Country, lon, lat),
aes(x = lon, y = lat, label = paste0(Country)),
color = "#A0C878", size = 2.5, fontface = "bold",
segment.color = NA, direction = "both", force = 0.5, max.overlaps = 20,
bg.color = "#1a1a1a", bg.r = 0.15
) +
# Scale and North arrow
annotation_scale(location = "bl", width_hint = 0.15, text_cex = 0.6, line_col = "white", text_col = "white") +
annotation_north_arrow(location = "tr", style = north_arrow_fancy_orienteering(fill = c("white", "white")),
height = unit(0.8, "cm"), width = unit(0.8, "cm")) +
# Zoom bounds
coord_sf(xlim = xlim, ylim = ylim, crs = st_crs(4326)) +
# Title and theme
ggtitle("International Flight Network of Bangladesh") +
theme_void() +
theme(
plot.title = element_text(hjust = 0.5, color = "white", size = 16, face = "bold"),
panel.background = element_rect(fill = "#1a1a1a"),
plot.background = element_rect(fill = "#1a1a1a"),
plot.margin = margin(5, 5, 5, 5, "mm")
)
# ---- Save Output ----
ggsave(output_path, plot = flight_map,
width = 11.7, height = 8.3,
dpi = 600, bg = "#1a1a1a", limitsize = FALSE)