Skip to content

Instantly share code, notes, and snippets.

@bjulius
Created April 16, 2025 23:17
Show Gist options
  • Save bjulius/1c5c32b14029cbac0815ec3370ae791e to your computer and use it in GitHub Desktop.
Save bjulius/1c5c32b14029cbac0815ec3370ae791e to your computer and use it in GitHub Desktop.
ggplot2 R Code for Horizontal Waterfall Chart
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
@bjulius
Copy link
Author

bjulius commented Apr 16, 2025

horizontal waterfall

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