- Part I. The Bad Vis
- Part II. A Better Vis
Optional:
- Part III. Code Implementation
Optional:
Improved Readability (Gradient Background)
Clarity in Trends (Distinct Line Styles and Colors)
Focus on Key Insights (Max and Min Annotations)
Better Use of Symbols (Flags for Regions)
Enhanced Aesthetic and Accessibility (color choices)
library(ggplot2) library(ggflags) library(dplyr) library(tidyr) library(grid)
# Load the dataset (update the path if necessary)
data <- read.csv("data/transposed_dataset.csv", header = TRUE)
# Ensure the first column is correctly named as "Year"
colnames(data)[1] <- "Year"
# Reshape the data into long format using tidyr
data_long <- pivot_longer(data,
cols = -Year,
names_to = "Region",
values_to = "Equity_Return")
# Add ISO country codes for flags (ensure lowercase for ggflags)
data_long <- data_long %>%
mutate(Country = case_when(
Region == "USA" ~ "us", # United States
Region == "UK" ~ "gb", # United Kingdom
Region == "EM" ~ "un", # Emerging Markets (custom, replace if needed)
Region == "JAP" ~ "jp", # Japan
Region == "EUR" ~ "eu" # Europe
))
# Ensure Year is numeric for proper plotting
data_long <- data_long %>%
mutate(Year = as.numeric(Year))
# Calculate max and min values per year
annotations <- data_long %>%
group_by(Year) %>%
summarise(
max_val = max(Equity_Return),
max_region = Region[which.max(Equity_Return)],
max_country = Country[which.max(Equity_Return)],
min_val = min(Equity_Return),
min_region = Region[which.min(Equity_Return)],
min_country = Country[which.min(Equity_Return)]
)
# Set symmetric y-domain for the plot
y_abs_max <- max(abs(data_long$Equity_Return)) # Find the maximum absolute value
y_min <- -y_abs_max # Set y_min to negative absolute maximum
y_max <- max(data_long$Equity_Return) + 10 # Extend y_max beyond dataset maximum
# Create the plot
ggplot(data_long, aes(x = Year, y = Equity_Return)) +
# Add the gradient background with a smoother and symmetric transition
annotation_raster(
raster = as.raster(matrix(colorRampPalette(c("#98FB98", "gray", "#E35335"))(100), nrow = 100, ncol = 1)),
xmin = -Inf, xmax = Inf,
ymin = y_min, ymax = y_max # Adjusted y-axis domain
) +
# Add lines for each region with proper linetypes and colors
geom_line(data = filter(data_long, Region == "EM"), aes(x = Year, y = Equity_Return, linetype = "Emerging Markets", color = "Emerging Markets"),
alpha = 0.8, linewidth = 0.6) +
geom_line(data = filter(data_long, Region == "USA"), aes(x = Year, y = Equity_Return, linetype = "USA", color = "USA"),
alpha = 0.7, linewidth = 1.5) +
geom_line(data = filter(data_long, Region == "EUR"), aes(x = Year, y = Equity_Return, linetype = "EUR", color = "EUR"),
alpha = 0.9, linewidth = 1.3) +
geom_line(data = filter(data_long, Region == "JAP"), aes(x = Year, y = Equity_Return, linetype = "JPN", color = "JPN"),
alpha = 1, linewidth = 0.6) +
geom_line(data = filter(data_long, Region == "UK"), aes(x = Year, y = Equity_Return, linetype = "UK", color = "UK"),
alpha = 0.4, linewidth = 0.6) +
# Add flags for valid country codes (on top of curves)
geom_flag(data = filter(data_long, Country != "un"), aes(country = Country), size = 10, show.legend = FALSE) +
# Add custom points for 'EM'
geom_point(data = filter(data_long, Country == "un"), aes(x = Year, y = Equity_Return),
color = "black", size = 3, shape = 21, fill = "gray", show.legend = FALSE) +
# Add text annotations for max and min values per year
geom_text(data = annotations, aes(x = Year, y = max_val + 5, label = max_val), size = 5, color = "black") + # Max above dot
geom_text(data = annotations, aes(x = Year, y = min_val - 5, label = min_val), size = 5, color = "black") + # Min below dot
# Add text annotation close to x-axis
annotate("text", x = 2010, y = y_min + 25,
label = "2008 Global Crisis", color = "black", size = 4, hjust = 0.5) +
# Add labels and theme
labs(
title = "30+ years of Global Equity Returns by Region",
x = "Year",
y = "Global Equity Returns (%)",
color = "Legend",
linetype = "Legend"
) +
# Customize theme with gridlines and axis on top of background
theme_minimal() +
theme(
panel.background = element_blank(), # Transparent background to allow gradient visibility
panel.grid.major = element_line(color = "black", size = 0.1), # Major gridlines on top
panel.grid.minor = element_blank(), # Remove minor gridlines
panel.ontop = TRUE, # Place axes and gridlines on top
axis.line = element_line(color = "black"), # Add x and y axis lines
axis.ticks = element_line(color = "black"), # Add axis ticks
plot.title = element_text(hjust = 0.5, size = 18, face = "bold", color = "black"), # Black title text
axis.text = element_text(color = "black"), # Black axis text
axis.title = element_text(color = "black"), # Black axis labels
legend.position = "top", # Legend at the top
legend.title = element_blank(),
legend.text = element_text(color = "black", size = 14), # Black legend text
legend.background = element_rect(fill = "gray85", color = "gray85") # Legend background
) +
# Customize legend colors and linetypes with updated labels
scale_color_manual(
values = c(
"USA" = "black",
"UK" = "firebrick",
"EUR" = "blue",
"JPN" = "white",
"Emerging Markets" = "darkgreen"
)
) +
scale_linetype_manual(
values = c(
"USA" = "twodash",
"UK" = "longdash",
"EUR" = "dotted",
"JPN" = "dashed",
"Emerging Markets" = "solid"
)
)