crisis_red <- "#C0392B" # Critically Endangered
danger_orange <- "#E67E22" # Endangered
warn_yellow <- "#F1C40F" # Vulnerable
safe_green <- "#27AE60" # Least Concern / recovered
near_blue <- "#2980B9" # Near Threatened
extinct_grey <- "#7F8C8D" # Extinct
dark_text <- "#1A1A2E"
mid_text <- "#555577"
light_bg <- "#F8F9FA"
status_palette <- c(
"Critically Endangered" = crisis_red,
"Endangered" = danger_orange,
"Vulnerable" = warn_yellow,
"Near Threatened" = near_blue,
"Least Concern" = safe_green,
"Extinct" = extinct_grey,
"Data Deficient" = "#BDC3C7"
)
theme_conservation <- function(base_size = 12) {
theme_minimal(base_size = base_size) %+replace%
theme(
plot.title = element_text(face = "bold", colour = dark_text,
size = base_size * 1.2, margin = margin(b = 5)),
plot.subtitle = element_text(colour = mid_text, size = base_size * 0.92,
margin = margin(b = 12)),
plot.caption = element_text(colour = mid_text, size = base_size * 0.75,
hjust = 0, margin = margin(t = 10)),
axis.title = element_text(colour = mid_text, size = base_size * 0.88),
axis.text = element_text(colour = mid_text, size = base_size * 0.82),
axis.line.x = element_line(colour = "#DEE2E6", linewidth = 0.4),
axis.ticks = element_blank(),
panel.grid.major.x = element_blank(),
panel.grid.major.y = element_line(colour = "#ECEFF1", linewidth = 0.3),
panel.grid.minor = element_blank(),
legend.position = "top",
legend.title = element_text(face = "bold", size = base_size * 0.85),
legend.text = element_text(size = base_size * 0.82),
plot.background = element_rect(fill = "white", colour = NA),
plot.margin = margin(12, 16, 12, 16)
)
}
polish_plotly <- function(p) {
p |>
layout(
font = list(family = "Arial, sans-serif"),
hoverlabel = list(bgcolor = "white", bordercolor = dark_text,
font = list(size = 12, color = dark_text)),
margin = list(l = 60, r = 20, t = 50, b = 60)
) |>
config(
responsive = TRUE,
displayModeBar = TRUE,
modeBarButtonsToRemove = c("pan2d","select2d","lasso2d",
"autoScale2d","hoverCompareCartesian"),
displaylogo = FALSE
)
}# Chart 1 data: IUCN Red List -Species by Kingdom and Class
# Source: IUCN Red List Summary Statistics, Table 3
# Download: https://www.iucnredlist.org/resources/summary-statistics
raw <- read_csv(
"/Users/priya/Desktop/Table3.csv",
show_col_types = FALSE
)
# Clean: strip commas from character-encoded numbers
clean_num <- function(x) as.numeric(str_remove_all(as.character(x), ","))
df_raw <- raw |>
mutate(across(c(CR, EN, VU, EX, EW,
`NT or LR/nt`, `LC or LR/lc`,
DD, Total,
`Subtotal (threatened spp.)`), clean_num))
# Assign kingdoms
animalia_classes <- c(
"ACTINOPTERYGII","AMPHIBIA","ANTHOZOA","ARACHNIDA","ASTEROIDEA","AVES",
"BIVALVIA","BRANCHIOPODA","CALCAREA","CEPHALOPODA","CHILOPODA","CHONDRICHTHYES",
"CLITELLATA","COLLEMBOLA","DEMOSPONGIAE","DIPLOPODA","ECHINOIDEA","GASTROPODA",
"HEXACTINELLIDA","HEXANAUPLIA","HOLOTHUROIDEA","HYDROZOA","INSECTA","MALACOSTRACA",
"MAMMALIA","MAXILLOPODA","MEROSTOMATA","MONOPLACOPHORA","MYXINI","NEMERTEA",
"OSTRACODA","PETROMYZONTI","POLYCHAETA","POLYPLACOPHORA","REPTILIA","SARCOPTERYGII",
"SOLENOGASTRES","TURBELLARIA","UDEONYCHOPHORA"
)
fungi_classes <- c(
"AGARICOMYCETES","ARTHONIOMYCETES","DACRYMYCETES","DOTHIDEOMYCETES","EUROTIOMYCETES",
"EXOBASIDIOMYCETES","GEOGLOSSOMYCETES","LECANOROMYCETES","LEOTIOMYCETES","NOT ASSIGNED",
"PEZIZOMYCETES","SORDARIOMYCETES","USTILAGINOMYCETES","WALLEMIOMYCETES"
)
plantae_classes <- c(
"ANDREAEOPSIDA","ANTHOCEROTOPSIDA","BRYOPSIDA","CHAROPHYCEAE","CHLOROPHYCEAE",
"CYCADOPSIDA","FLORIDEOPHYCEAE","GINKGOOPSIDA","GNETOPSIDA","JUNGERMANNIOPSIDA",
"LILIOPSIDA","LYCOPODIOPSIDA","MAGNOLIOPSIDA","MARCHANTIOPSIDA","PINOPSIDA",
"POLYPODIOPSIDA","POLYTRICHOPSIDA","SPHAGNOPSIDA","TAKAKIOPSIDA","ULVOPHYCEAE"
)
df_classes <- df_raw |>
filter(Name != "Total") |>
mutate(
kingdom = case_when(
Name %in% animalia_classes ~ "Animalia",
Name %in% fungi_classes ~ "Fungi",
Name %in% plantae_classes ~ "Plantae",
Name == "PHAEOPHYCEAE" ~ "Chromista",
TRUE ~ "Other"
),
# Human-readable class labels for top classes
class_label = str_to_title(Name) |>
str_replace("Actinopterygii", "Ray-finned Fishes") |>
str_replace("Amphibia", "Amphibians") |>
str_replace("Aves", "Birds") |>
str_replace("Chondrichthyes", "Sharks & Rays") |>
str_replace("Insecta", "Insects") |>
str_replace("Gastropoda", "Snails & Slugs") |>
str_replace("Liliopsida", "Monocots (Flowering)") |>
str_replace("Magnoliopsida", "Dicots (Flowering)") |>
str_replace("Mammalia", "Mammals") |>
str_replace("Malacostraca", "Crustaceans") |>
str_replace("Reptilia", "Reptiles") |>
str_replace("Agaricomycetes", "Mushrooms & Bracket Fungi")
)
#total threatened by status
totals_row <- df_raw |> filter(Name == "Total")
df_status_totals <- tibble(
status = c("Critically Endangered", "Endangered", "Vulnerable"),
count = c(
clean_num(totals_row$CR),
clean_num(totals_row$EN),
clean_num(totals_row$VU)
),
status_f = factor(
c("Critically Endangered", "Endangered", "Vulnerable"),
levels = c("Critically Endangered", "Endangered", "Vulnerable")
)
)
# threatened by kingdom
df_kingdom_status <- df_classes |>
group_by(kingdom) |>
summarise(
CR = sum(CR, na.rm = TRUE),
EN = sum(EN, na.rm = TRUE),
VU = sum(VU, na.rm = TRUE),
.groups = "drop"
) |>
pivot_longer(c(CR, EN, VU), names_to = "status_code", values_to = "count") |>
mutate(
status = case_when(
status_code == "CR" ~ "Critically Endangered",
status_code == "EN" ~ "Endangered",
status_code == "VU" ~ "Vulnerable"
),
status = factor(status, levels = c("Critically Endangered","Endangered","Vulnerable"))
) |>
filter(kingdom != "Other", kingdom != "Chromista")
# Top 15 classes by threatened species
df_top15 <- df_classes |>
arrange(desc(`Subtotal (threatened spp.)`)) |>
slice_head(n = 15) |>
mutate(
class_label = fct_reorder(class_label, `Subtotal (threatened spp.)`),
pct_threatened = `Subtotal (threatened spp.)` / Total,
tooltip = glue(
"<b>{class_label}</b> ({kingdom})<br>",
"Critically Endangered: {comma(CR)}<br>",
"Endangered: {comma(EN)}<br>",
"Vulnerable: {comma(VU)}<br>",
"<b>Total threatened: {comma(`Subtotal (threatened spp.)`)}</b><br>",
"% of assessed: {percent(pct_threatened, accuracy = 0.1)}"
)
)Nearly 48,650 species are currently threatened with extinction according to the IUCN Red List -Critically Endangered, Endangered, or Vulnerable. Conservation works. Not always. Not everywhere. But enough to prove the principle and to ask which approaches work best, where, and for whom.
# Chart 1-Stacked bar: top 15 classes by threatened species
# Variables: class (categorical), CR / EN / VU counts
df_c1_long <- df_top15 |>
select(class_label, kingdom, CR, EN, VU, `Subtotal (threatened spp.)`, pct_threatened, Total) |>
pivot_longer(c(CR, EN, VU), names_to = "status_code", values_to = "count_status") |>
mutate(
status = case_when(
status_code == "CR" ~ "Critically Endangered",
status_code == "EN" ~ "Endangered",
status_code == "VU" ~ "Vulnerable"
),
status = factor(status, levels = c("Vulnerable","Endangered","Critically Endangered")),
tooltip = glue(
"<b>{class_label}</b> ({kingdom})<br>",
"Status shown: {status}<br>",
"Count: {comma(count_status)}<br>",
"Total threatened: {comma(`Subtotal (threatened spp.)`)}<br>",
"% of assessed: {percent(pct_threatened, accuracy=0.1)}"
)
)
p1 <- df_c1_long |>
ggplot(aes(x = count_status, y = class_label,
fill = status, text = tooltip)) +
geom_col(position = "stack", width = 0.72, alpha = 0.92) +
scale_fill_manual(
values = c(
"Critically Endangered" = crisis_red,
"Endangered" = danger_orange,
"Vulnerable" = warn_yellow
),
name = "IUCN Status"
) +
scale_x_continuous(labels = comma, expand = expansion(mult = c(0, 0.05))) +
labs(
title = "Nearly 49,000 species face extinction-plants & fishes lead the count",
subtitle = "Top 15 taxonomic classes by total number of threatened species (CR + EN + VU combined)",
x = "Number of threatened species",
y = NULL,
caption = paste0(
"Source: IUCN Red List of Threatened Species, Summary Statistics Table 3 (2024 assessment).\n",
"CR = Critically Endangered; EN = Endangered; VU = Vulnerable.\n",
"Classes ordered by total threatened species count."
)
) +
theme_conservation() +
theme(legend.position = "top")
ggplotly(p1, tooltip = "text") |>
polish_plotly() |>
layout(
legend = list(orientation = "v", x = -0.1, y = 1.1),
barmode = "stack"
)How to read this chart: Each bar is one taxonomic class. Bars are stacked by severity — red (most critical) sits at the base. Hover over any segment to see exact counts and the percentage of assessed species that are threatened. Classes are ordered by total threatened count.
# Threatened species by country & taxonomic group
# Source: IUCN Red List Summary Statistics, Table 5
# https://www.iucnredlist.org/resources/summary-statistics
raw_t5 <- read_csv(
"/Users/priya/Desktop/table5.csv",
show_col_types = FALSE
)
# Clean
df_countries <- raw_t5 |>
rename(
country = Name,
mammals = Mammals,
birds = Birds,
reptiles = `Reptiles*`,
amphibians = Amphibians,
fishes = `Fishes*`,
molluscs = `Molluscs*`,
other_inverts = `Other Inverts*`,
plants = `Plants*`,
fungi = `Fungi*`,
chromists = `Chromists*`
) |>
mutate(
across(c(mammals, birds, reptiles, amphibians,
fishes, molluscs, other_inverts,
plants, fungi, chromists), as.numeric),
total = as.numeric(str_remove_all(as.character(Total), ","))
) |>
filter(!is.na(total), total > 0) |>
# Assign broad region for colour grouping
mutate(
region = case_when(
country %in% c("Australia","New Zealand","Papua New Guinea",
"New Caledonia","Fiji","Solomon Islands",
"Vanuatu","Samoa","Tonga","Kiribati","Palau",
"Micronesia, Federated States of",
"Marshall Islands","Nauru","Tuvalu") ~ "Oceania",
country %in% c("China","India","Indonesia","Malaysia","Philippines",
"Viet Nam","Thailand","Myanmar","Japan","Korea, Republic of",
"Sri Lanka","Bangladesh","Nepal","Pakistan","Cambodia",
"Lao People's Democratic Republic","Mongolia","Bhutan",
"Maldives","Brunei Darussalam","Timor-Leste",
"Singapore","Afghanistan") ~ "Asia",
country %in% c("Brazil","Colombia","Ecuador","Peru","Mexico",
"Venezuela, Bolivarian Republic of","Bolivia, Plurinational State of",
"Argentina","Chile","Paraguay","Uruguay","Guyana",
"Suriname","French Guiana","Panama","Costa Rica",
"Nicaragua","Honduras","Guatemala","Belize",
"El Salvador","Cuba","Haiti","Dominican Republic",
"Jamaica","Trinidad and Tobago","Bahamas") ~ "Latin America & Caribbean",
country %in% c("United States","Canada") ~ "North America",
country %in% c("Madagascar","Tanzania, United Republic of","Cameroon",
"South Africa","Democratic Republic of the Congo",
"Kenya","Ethiopia","Uganda","Ghana","Nigeria",
"Côte d'Ivoire","Mozambique","Zimbabwe","Zambia",
"Angola","Malawi","Rwanda","Burundi","Somalia",
"Sudan","South Sudan","Chad","Niger","Mali",
"Burkina Faso","Senegal","Guinea","Sierra Leone",
"Liberia","Togo","Benin","Gabon","Equatorial Guinea",
"Central African Republic","Congo","Botswana","Namibia",
"Swaziland","Lesotho","Djibouti","Eritrea",
"Algeria","Morocco","Tunisia","Libya","Egypt") ~ "Africa",
country %in% c("Greece","Spain","France","Italy","Portugal",
"Germany","United Kingdom","Sweden","Norway",
"Finland","Denmark","Netherlands","Belgium",
"Austria","Switzerland","Poland","Czechia",
"Slovakia","Hungary","Romania","Bulgaria",
"Croatia","Slovenia","Serbia","Bosnia and Herzegovina",
"North Macedonia","Albania","Kosovo","Montenegro",
"Ukraine","Russian Federation","Turkey","Cyprus") ~ "Europe",
country %in% c("Iran, Islamic Republic of","Iraq","Saudi Arabia",
"Yemen","Oman","United Arab Emirates","Jordan",
"Lebanon","Syrian Arab Republic","Israel",
"Kuwait","Qatar","Bahrain") ~ "Middle East",
TRUE ~ "Other"
),
# Most threatened taxon group per country
plants_n = as.numeric(str_remove_all(as.character(plants), ",")),
dominant_group = pmap_chr(
list(mammals, birds, reptiles, amphibians, fishes, plants_n),
function(m, b, r, a, f, p) {
groups <- c(Mammals = m, Birds = b, Reptiles = r,
Amphibians = a, Fishes = f, Plants = p)
names(which.max(replace(groups, is.na(groups), 0)))
}
)
)# Regional Bubble Chart
# Supplements the choropleth by adding the vertebrates vs plants breakdown.
# Variables: total threatened (x), plants threatened (y),
region_pal <- c(
"Asia" = "#E74C3C",
"Latin America & Caribbean" = "#27AE60",
"Africa" = "#F39C12",
"Oceania" = "#8E44AD",
"North America" = "#2980B9",
"Europe" = "#16A085",
"Middle East" = "#D35400",
"Other" = "#95A5A6"
)
df_bubble <- df_countries |>
mutate(
vertebrates = mammals + birds + reptiles + amphibians + fishes,
plants_n = as.numeric(str_remove_all(as.character(plants), ",")),
tooltip = glue(
"<b>{country}</b><br>",
"Region: {region}<br>",
"Total threatened: {comma(total)}<br>",
"Vertebrates: {comma(vertebrates)}<br>",
"Plants: {comma(plants_n)}"
)
) |>
filter(!is.na(plants_n), region != "Other")
p3b <- df_bubble |>
ggplot(aes(
x = vertebrates,
y = plants_n,
size = total,
colour = region,
text = tooltip
)) +
# Diagonal reference: equal vertebrates & plants
geom_abline(slope = 1, intercept = 0, linetype = "dashed",
colour = "#BDC3C7", linewidth = 0.5) +
annotate("text", x = 750, y = 800,
label = "Equal vertebrates\n& plants", size = 2.8,
colour = "#95A5A6", angle = 38, hjust = 0) +
geom_point(alpha = 0.72) +
scale_colour_manual(values = region_pal, name = "Region") +
scale_size_continuous(
range = c(2, 14),
name = "Total threatened",
labels = comma,
guide = guide_legend(override.aes = list(alpha = 0.6))
) +
scale_x_continuous(labels = comma) +
scale_y_continuous(labels = comma) +
labs(
title = "Plant-rich hotspots sit far above the diagonal",
subtitle = "Countries above the dashed line have disproportionately more threatened plants than vertebrates",
x = "Threatened vertebrate species (mammals + birds + reptiles + amphibians + fishes)",
y = "Threatened plant species",
caption = paste0(
"Source: IUCN Red List Summary Statistics, Table 5 (2024 assessment).\n",
"Bubble size proportional to total threatened species across all groups.\n",
"Dashed line = equal threatened vertebrates and plants."
)
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", colour = "#1A1A2E", size = 14),
plot.subtitle = element_text(colour = "#555577", size = 10),
plot.caption = element_text(colour = "#95A5A6", size = 8, hjust = 0),
legend.position = "right",
panel.grid.minor = element_blank()
)
ggplotly(p3b, tooltip = "text") |>
layout(
hoverlabel = list(bgcolor = "white",
font = list(size = 12, color = "#1A1A2E")),
legend = list(orientation = "v")
) |>
config(
responsive = TRUE,
displaylogo = FALSE,
modeBarButtonsToRemove = c("pan2d","select2d","lasso2d","autoScale2d")
)# World Database on Protected Areas, June 2026
df_wdpa <- read_csv(
"/Users/priya/Desktop/WDPA_Jun2026_Public_csv 3/WDPA.csv",
show_col_types = FALSE
) |>
mutate(
GIS_AREA = as.numeric(GIS_AREA),
STATUS_YR = as.integer(STATUS_YR)
)
#IUCN category labels
iucn_levels <- c("Ia","Ib","II","III","IV","V","VI")
iucn_labels <- c(
"Ia" = "Ia — Strict Nature Reserve",
"Ib" = "Ib — Wilderness Area",
"II" = "II — National Park",
"III" = "III — Natural Monument",
"IV" = "IV — Habitat/Species Management",
"V" = "V — Protected Landscape",
"VI" = "VI — Sustainable Use"
)
# Realm palette
realm_pal <- c(
"Terrestrial" = "#27AE60",
"Marine" = "#2980B9",
"Coastal" = "#16A085"
)
# Gov type short labels
gov_labels <- c(
"Federal or national ministry or agency" = "National Government",
"Sub-national ministry or agency" = "Sub-national Government",
"Non-profit organisations" = "Non-profit",
"Individual landowners" = "Private (Individual)",
"Collaborative governance" = "Collaborative",
"Indigenous Peoples" = "Indigenous Peoples",
"Government-delegated management" = "Gov. Delegated",
"Joint governance" = "Joint Governance",
"Local communities" = "Local Communities",
"For-profit organisations" = "Private (For-profit)",
"Transboundary governance" = "Transboundary",
"Not Reported" = "Not Reported"
)# Cumulative protected area growth over time by realm
df_growth <- df_wdpa |>
filter(
STATUS_YR >= 1950,
STATUS_YR <= 2026,
STATUS %in% c("Designated","Established","Inscribed","Adopted"),
REALM %in% c("Terrestrial","Marine","Coastal")
) |>
group_by(STATUS_YR, REALM) |>
summarise(
n_pa = n(),
area_km2 = sum(GIS_AREA, na.rm = TRUE),
.groups = "drop"
) |>
# Cumulative sum within each realm
arrange(STATUS_YR) |>
group_by(REALM) |>
mutate(
cum_n = cumsum(n_pa),
cum_area = cumsum(area_km2) / 1e6 # convert to million km²
) |>
ungroup() |>
mutate(
tooltip = glue(
"<b>{REALM} — {STATUS_YR}</b><br>",
"Cumulative protected area: {round(cum_area, 2)}M km²<br>",
"Cumulative sites: {comma(cum_n)}<br>",
"New sites this year: {comma(n_pa)}"
)
)
# Key milestones for annotation
milestones <- tibble(
year = c(1992, 2010, 2022),
label = c("Rio Earth\nSummit", "Aichi\nTargets", "Kunming-\nMontreal")
)
p3a <- df_growth |>
ggplot(aes(x = STATUS_YR, y = cum_area,
colour = REALM, group = REALM, text = tooltip)) +
# Milestone vertical lines
geom_vline(data = milestones,
aes(xintercept = year),
linetype = "dashed", colour = "#BDC3C7",
linewidth = 0.5, inherit.aes = FALSE) +
geom_text(data = milestones,
aes(x = year + 0.5, y = Inf, label = label),
inherit.aes = FALSE,
colour = "#95A5A6", size = 2.5, hjust = 0, vjust = 1.3) +
geom_line(linewidth = 1.1) +
geom_point(size = 1.8, alpha = 0.7) +
scale_colour_manual(values = realm_pal, name = "Realm") +
scale_x_continuous(breaks = seq(1950, 2025, 10)) +
scale_y_continuous(labels = function(x) paste0(x, "M km²")) +
labs(
title = "Protected areas have grown dramatically — but mostly on land",
subtitle = "Cumulative protected area (million km²) by realm, 1950–2026",
x = "Year designated",
y = "Cumulative area (million km²)",
caption = paste0(
"Source: IUCN & UNEP-WCMC, World Database on Protected Areas (WDPA), June 2026.\n",
"Designated, Established, Inscribed and Adopted sites only. Area = GIS-calculated (km²).\n",
"Dashed lines mark major international conservation agreements."
)
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", colour = "#1A1A2E", size = 14),
plot.subtitle = element_text(colour = "#555577", size = 10),
plot.caption = element_text(colour = "#95A5A6", size = 8, hjust = 0),
legend.position = "top",
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank()
)
ggplotly(p3a, tooltip = "text") |>
layout(
hoverlabel = list(bgcolor = "white",
font = list(size = 12, color = "#1A1A2E")),
legend = list(orientation = "h", x = 0.1, y = 1.1)
) |>
config(
responsive = TRUE,
displaylogo = FALSE,
modeBarButtonsToRemove = c("pan2d","select2d","lasso2d","autoScale2d")
)# IUCN category × realm × area bubble chart
# Variables: IUCN category (y), total area km² (x), number of PAs (bubble size)
df_iucn <- df_wdpa |>
filter(
IUCN_CAT %in% iucn_levels,
REALM %in% c("Terrestrial","Marine","Coastal"),
STATUS %in% c("Designated","Established","Inscribed","Adopted")
) |>
group_by(IUCN_CAT, REALM) |>
summarise(
n_pa = n(),
area_km2 = sum(GIS_AREA, na.rm = TRUE) / 1e6, # million km²
.groups = "drop"
) |>
mutate(
iucn_label = iucn_labels[IUCN_CAT],
iucn_label = factor(iucn_label, levels = rev(iucn_labels)),
tooltip = glue(
"<b>{iucn_label}</b><br>",
"Realm: {REALM}<br>",
"Total area: {round(area_km2, 2)}M km²<br>",
"Number of protected areas: {comma(n_pa)}"
)
)
p3b <- df_iucn |>
ggplot(aes(x = area_km2, y = iucn_label,
size = n_pa, colour = REALM, text = tooltip)) +
geom_point(alpha = 0.78) +
scale_colour_manual(values = realm_pal, name = "Realm") +
scale_size_continuous(
range = c(3, 16),
name = "Number of sites",
labels = comma
) +
scale_x_continuous(labels = function(x) paste0(x, "M km²"),
expand = expansion(mult = c(0.02, 0.1))) +
labs(
title = "Interpreting IUCN Site Distributions",
subtitle = "Total protected area and site count by IUCN management category and realm",
x = "Total protected area (million km²)",
y = NULL,
caption = paste0(
"Source: IUCN & UNEP-WCMC, WDPA June 2026. Sites with valid IUCN categories only (Ia–VI).\n",
"Bubble size = number of protected area sites. 'Not Reported' / 'Not Assigned' excluded."
)
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", colour = "#1A1A2E", size = 14),
plot.subtitle = element_text(colour = "#555577", size = 10),
plot.caption = element_text(colour = "#95A5A6", size = 8, hjust = 0),
legend.position = "right",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_blank()
)
ggplotly(p3b, tooltip = "text") |>
layout(
hoverlabel = list(bgcolor = "white",
font = list(size = 12, color = "#1A1A2E")),
legend = list(orientation = "v")
) |>
config(
responsive = TRUE,
displaylogo = FALSE,
modeBarButtonsToRemove = c("pan2d","select2d","lasso2d","autoScale2d")
)How to read this chart: Each bubble is one IUCN category × realm combination. Bubble size shows how many individual sites fall into that combination — not how large they are. Position on the x-axis shows total area covered. A large bubble sitting left means many small sites; a small bubble sitting right means few but very large ones.
df <- read_csv("/Users/priya/Downloads/Table7.csv")
# Rename columns
colnames(df)[1] <- "Group"
colnames(df)[2] <- "Scientific_Name"
colnames(df)[3] <- "Status_2024"
colnames(df)[4] <- "Status_2025"
colnames(df)[5] <- "Reason"
colnames(df)[6] <- "Version"
# Define risk levels to track if species went up or down in threat status
status_levels <- c("DD", "LC", "NT", "VU", "EN", "CR", "EW", "EX")
#Filter strictly for genuine ecological changes and summarize
story_data <- df %>%
filter(!is.na(Status_2024) & !is.na(Status_2025)) %>%
filter(Status_2024 != Status_2025) %>%
filter(Reason == "G") %>%
mutate(
Rank_2024 = match(Status_2024, status_levels),
Rank_2025 = match(Status_2025, status_levels),
Verdict = ifelse(Rank_2025 > Rank_2024, "Ecological Deterioration", "Conservation Success")
) %>%
count(Group, Verdict) %>%
drop_na(Group)
# Pivot data to a "wide" format
wide_data <- story_data %>%
pivot_wider(names_from = Verdict, values_from = n, values_fill = 0) %>%
mutate(Total_Changes = `Conservation Success` + `Ecological Deterioration`) %>%
arrange(Total_Changes) # Orders taxonomic groups from smallest to largest impact
# Build the Interactive Plotly Bar Chart
plot_ly(wide_data,
y = ~reorder(Group, Total_Changes),
x = ~`Conservation Success`,
type = 'bar',
name = 'Conservation Success (Real Wins)',
marker = list(color = '#2CA02C'),
hovertemplate = '<b>%{y}</b><br>Successes: %{x}<extra></extra>') %>%
add_trace(x = ~`Ecological Deterioration`,
name = 'Ecological Deterioration (Real Losses)',
marker = list(color = '#D62728'),
hovertemplate = '<b>%{y}</b><br>Deteriorations: %{x}<extra></extra>') %>%
layout(
barmode = 'stack',
title = list(
text = "<b> The Hidden Shifts</b><br><sup>Genuine species status changes (2024-2025) proving conservation works</sup>",
x = 0.05
),
xaxis = list(title = "Number of Species Experiencing Real Changes"),
yaxis = list(title = ""),
legend = list(orientation = 'h', x = 0.8, y = 1.15),
margin = list(l = 150, r = 20, t = 80, b = 50)
)1.International Union for Conservation of Nature. (n.d.). Summary statistics [Tables 3, 5, and 7]. The IUCN Red List of Threatened Species. https://www.iucnredlist.org/resources/summary-statistics
2.UNEP-WCMC and IUCN. (n.d.). Protected Planet: Discover the world’s protected and conserved areas. Protected Planet. https://www.protectedplanet.net/en
.