Created
March 21, 2025 04:46
-
-
Save bjulius/e4ab68e67c982e6c00dfe3e7e216d9ae to your computer and use it in GitHub Desktop.
R Arrow Chart Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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") | |
) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 $KChange_Percent = (
2024
-2023
) /2023
* 100) %>%
arrange(desc(
2023
)) # Sort by 2023 sales in descending orderCreate 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")
)
)