Created
April 16, 2025 23:17
-
-
Save bjulius/1c5c32b14029cbac0815ec3370ae791e to your computer and use it in GitHub Desktop.
ggplot2 R Code for Horizontal Waterfall Chart
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
library(tidyverse) | |
library(patchwork) | |
library(ggtext) | |
# Create the data frame | |
df <- data.frame( | |
category = c( | |
"Machine sales", "Accessories sales", "Sales", | |
"Cost of sales", "Gross profit", "R&D costs", | |
"Sales costs", "Administration costs", "Net income" | |
), | |
value = c(1529, 468, 1997, -1011, 986, -200, -359, -170, 257) | |
) | |
# Identify total/subtotal rows according to IBCS | |
subtotal_categories <- c("Sales", "Gross profit", "Net income") | |
df$is_total <- df$category %in% subtotal_categories | |
# Prepare data for waterfall - Calculate cumulative sums | |
df <- df %>% | |
mutate( | |
end = cumsum(value), | |
start = lag(end, default = 0), | |
type = case_when( | |
is_total ~ "total", | |
value >= 0 ~ "increase", | |
value < 0 ~ "decrease" | |
), | |
ypos = n():1, | |
label_value = abs(value) | |
) | |
# Define IBCS colors | |
ibcs_colors <- c( | |
increase = "#BBBBBB", | |
decrease = "#333333", | |
total = "#FFFFFF" | |
) | |
ibcs_outline_colors <- c( | |
increase = NA, | |
decrease = NA, | |
total = "#000000" | |
) | |
# Horizontal waterfall chart with label extensions | |
p1 <- ggplot(df, aes(y = ypos)) + | |
geom_vline(xintercept = 0, linewidth = 0.5) + | |
geom_rect(aes( | |
xmin = start, xmax = end, | |
ymin = ypos - 0.35, ymax = ypos + 0.35, | |
fill = type, color = type | |
), linewidth = ifelse(df$is_total, 0.7, 0)) + | |
geom_text(aes( | |
x = end + ifelse(value >= 0, 40, -40), | |
label = label_value | |
), | |
hjust = ifelse(df$value >= 0, 0, 1), | |
size = 3.5, color = "black", vjust = 0.5) + | |
scale_y_continuous( | |
breaks = df$ypos, | |
labels = df$category, | |
expand = expansion(add = c(0.5, 0.5)) | |
) + | |
scale_x_continuous( | |
labels = NULL, name = NULL, | |
expand = expansion(mult = c(0.1, 0.2)) | |
) + | |
scale_fill_manual(values = ibcs_colors, guide = "none") + | |
scale_color_manual(values = ibcs_outline_colors, guide = "none") + | |
coord_cartesian(clip = "off") + # extend labels beyond plot | |
theme_minimal() + | |
theme( | |
panel.grid = element_blank(), | |
axis.text.y = element_text(size = 10, color = "black"), | |
axis.text.x = element_blank(), | |
axis.title = element_blank(), | |
axis.ticks = element_blank(), | |
plot.margin = margin(t = 10, r = 60, b = 20, l = 20) # tighten top margin, expand right | |
) | |
# Annotated layout with markdown subtitle and tighter spacing | |
combined_plot <- p1 + | |
plot_annotation( | |
title = "Alpha Corporation", | |
subtitle = "**Income Statement** in mUSD<br>Q2 2019", | |
theme = theme( | |
plot.title = element_text(size = 12, hjust = 0, margin = margin(b = 2)), | |
plot.subtitle = ggtext::element_markdown(size = 10, hjust = 0, lineheight = 1.05), | |
plot.margin = margin(t = 5, b = 10) | |
) | |
) | |
# Display | |
combined_plot |
Author
bjulius
commented
Apr 16, 2025

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