Skip to content

Instantly share code, notes, and snippets.

@bjulius
Created March 21, 2025 04:46
Show Gist options
  • Save bjulius/e4ab68e67c982e6c00dfe3e7e216d9ae to your computer and use it in GitHub Desktop.
Save bjulius/e4ab68e67c982e6c00dfe3e7e216d9ae to your computer and use it in GitHub Desktop.
R Arrow Chart Code
# Load necessary libraries
library(ggplot2)
library(dplyr)
library(tidyr)
library(gridExtra)
library(grid)
# Create the dataframe with the data from the image
sales_data <- data.frame(
Country = c("Finland", "Finland", "France", "France", "Netherlands", "Netherlands",
"Norway", "Norway", "Poland", "Poland"),
Year = c(2023, 2024, 2023, 2024, 2023, 2024, 2023, 2024, 2023, 2024),
TotalSales = c(160994, 186026, 360184, 652563, 818001, 400207,
272589, 157921, 943896, 1186120)
)
# Calculate changes from 2023 to 2024
sales_summary <- sales_data %>%
pivot_wider(names_from = Year, values_from = TotalSales) %>%
mutate(
Change_K = (`2024` - `2023`) / 1000, # Convert to $K
Change_Percent = (`2024` - `2023`) / `2023` * 100
)
# Set breaks for x-axes
k_breaks <- seq(-400, 300, 100)
pct_breaks <- seq(-40, 80, 20)
# Create plot for Change in $K
p1 <- ggplot(sales_summary) +
geom_segment(
aes(x = 0, y = Country, xend = Change_K, yend = Country, color = Change_K >= 0),
arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
size = 1
) +
geom_point(aes(x = 0, y = Country), color = "darkgrey", size = 3) +
scale_color_manual(values = c("FALSE" = "#F44336", "TRUE" = "#4CAF50")) +
scale_x_continuous(
breaks = k_breaks,
labels = function(x) paste0("$", x)
) +
labs(title = "Change in $K", x = NULL, y = NULL) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 12),
legend.position = "none",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_blank(),
axis.text.y = element_text(size = 10)
)
# Create plot for Change in %
p2 <- ggplot(sales_summary) +
geom_segment(
aes(x = 0, y = Country, xend = Change_Percent, yend = Country, color = Change_Percent >= 0),
arrow = arrow(length = unit(0.3, "cm"), type = "closed"),
size = 1
) +
geom_point(aes(x = 0, y = Country), color = "darkgrey", size = 3) +
scale_color_manual(values = c("FALSE" = "#F44336", "TRUE" = "#4CAF50")) +
scale_x_continuous(
breaks = pct_breaks,
labels = function(x) paste0(x, "%")
) +
labs(title = "Change in %", x = NULL, y = NULL) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 12),
legend.position = "none",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_blank(),
axis.text.y = element_blank() # Remove y-axis text for the second plot
)
# Combine the plots with a shared title
grid.arrange(
p1, p2,
ncol = 2,
widths = c(1, 1),
top = textGrob(
"Change in Sales by Country from 2023 to 2024",
gp = gpar(fontsize = 16, fontface = "bold")
)
)
@bjulius
Copy link
Author

bjulius commented Mar 21, 2025

Nick had some suggested edits. Here is the revised code:

Load necessary libraries

library(ggplot2)
library(dplyr)
library(tidyr)
library(gridExtra)
library(grid)

Create the dataframe with the data

sales_data <- data.frame(
Country = c("Finland", "Finland", "France", "France", "Netherlands", "Netherlands",
"Norway", "Norway", "Poland", "Poland"),
Year = c(2023, 2024, 2023, 2024, 2023, 2024, 2023, 2024, 2023, 2024),
TotalSales = c(160994, 186026, 360184, 652563, 818001, 400207, 272589, 157921,
943896, 1208230)
)

Calculate changes and sort countries by 2023 sales in descending order

sales_summary <- sales_data %>%
pivot_wider(names_from = Year, values_from = TotalSales) %>%
mutate(
Change_K = (2024 - 2023) / 1000, # Convert to $K
Change_Percent = (2024 - 2023) / 2023 * 100
) %>%
arrange(desc(2023)) # Sort by 2023 sales in descending order

Create an explicit vector of countries in descending order of 2023 sales

ordered_countries <- sales_summary$Country

Set the factor levels explicitly to ensure correct ordering

sales_summary$Country <- factor(sales_summary$Country, levels = ordered_countries)

Set breaks for x-axes with adjusted ranges

k_breaks <- seq(-600, 600, 100)
pct_breaks <- seq(-60, 100, 20)

Create plot for nominal values (but keep "Change in $K" title)

p1 <- ggplot(sales_summary) +
geom_segment(
aes(x = 2023, y = Country, xend = 2024, yend = Country,
color = 2024 >= 2023),
arrow = arrow(length = unit(0.12, "cm"), type = "open"),
size = 0.8
) +
geom_point(aes(x = 2023, y = Country, color = 2024 >= 2023), size = 2) +
scale_color_manual(values = c("FALSE" = "#F44336", "TRUE" = "#4CAF50")) +
scale_x_continuous(
breaks = seq(0, 1300000, 200000),
labels = function(x) paste0("$", x/1000, "K"),
limits = c(0, 1300000) # Ensure no values extend off chart
) +
scale_y_discrete(limits = rev(ordered_countries)) +
labs(title = "Change in $K", x = NULL, y = NULL) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 12),
legend.position = "none",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_blank(),
axis.text.y = element_text(size = 10),
axis.text.x = element_text(size = 6) # Even smaller x-axis labels
)

Create plot for Change in %

p2 <- ggplot(sales_summary) +
geom_segment(
aes(x = 0, y = Country, xend = Change_Percent, yend = Country,
color = Change_Percent >= 0),
arrow = arrow(length = unit(0.12, "cm"), type = "open"),
size = 0.8
) +
geom_point(aes(x = 0, y = Country, color = Change_Percent >= 0), size = 2) +
scale_color_manual(values = c("FALSE" = "#F44336", "TRUE" = "#4CAF50")) +
scale_x_continuous(
breaks = pct_breaks,
labels = function(x) paste0(x, "%"),
limits = c(-60, 100) # Extended axis from -60% to 100%
) +
scale_y_discrete(limits = rev(ordered_countries)) +
labs(title = "Change in %", x = NULL, y = NULL) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 12),
legend.position = "none",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(size = 6) # Even smaller x-axis labels
)

Combine the plots with a shared title

Extended width by 30% by adjusting the relative widths

grid.arrange(
p1, p2,
ncol = 2,
widths = c(1.3, 1.3), # Increased widths by 30%
top = textGrob(
"Change in Sales by Country from 2023 to 2024",
gp = gpar(fontsize = 16, fontface = "bold")
)
)

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment