Stacked Bar Chart with Total Labels in ggplot2 (R)

The same plot in 14 other libraries — Python: Altair, Bokeh, lets-plot, Matplotlib, Plotly, plotnine, Pygal, Seaborn; Julia: Makie.jl; JavaScript: Chart.js, D3.js, Apache ECharts, Highcharts, MUI X Charts. Compare all 15 side by side: Stacked Bar Chart with Total Labels in Python, R, Julia and JavaScript.

A stacked bar chart that displays multiple data series stacked on top of each other with total value labels prominently shown above each bar stack. This variant combines part-to-whole visualization with explicit numerical annotations, making it easy to read both individual segment contributions and cumulative totals at a glance. The total labels eliminate the need for mental arithmetic when comparing overall values across categories.

Stacked Bar Chart with Total Labels rendered with ggplot2

Renders

R source (ggplot2)

#' anyplot.ai
#' bar-stacked-labeled: Stacked Bar Chart with Total Labels
#' Library: ggplot2 3.5.1 | R 4.4.1
#' Quality: 92/100 | Created: 2026-05-18

library(ggplot2)
library(dplyr)
library(ragg)

set.seed(42)

# --- Theme tokens -----------------------------------------------------------
THEME       <- Sys.getenv("ANYPLOT_THEME", "light")
PAGE_BG     <- if (THEME == "light") "#FAF8F1" else "#1A1A17"
INK         <- if (THEME == "light") "#1A1A17" else "#F0EFE8"
INK_SOFT    <- if (THEME == "light") "#4A4A44" else "#B8B7B0"
IMPRINT   <- c("#009E73", "#C475FD", "#4467A3", "#BD8233",
                 "#AE3030", "#2ABCCD", "#954477")

# --- Data -------------------------------------------------------------------
# Quarterly revenue by product category
df <- data.frame(
  quarter = rep(c("Q1", "Q2", "Q3", "Q4"), each = 3),
  product = rep(c("Electronics", "Apparel", "Home"), 4),
  revenue = c(
    450000, 320000, 280000,  # Q1
    520000, 380000, 310000,  # Q2
    580000, 420000, 350000,  # Q3
    650000, 480000, 400000   # Q4
  )
)

# Calculate totals for each quarter (for labels above bars)
df_totals <- df %>%
  group_by(quarter) %>%
  summarize(total = sum(revenue), .groups = "drop")

# --- Plot -------------------------------------------------------------------
p <- ggplot(df, aes(x = quarter, y = revenue, fill = product)) +
  geom_col(position = "stack", width = 0.6) +
  geom_text(
    data = df_totals,
    aes(x = quarter, y = total, label = paste0("$", round(total / 1e6, 1), "M")),
    vjust = -0.3,
    size = 6,
    fontface = "bold",
    color = INK,
    inherit.aes = FALSE
  ) +
  scale_fill_manual(values = IMPRINT[1:3], name = "Product") +
  labs(
    title = "bar-stacked-labeled · R · ggplot2 · anyplot.ai",
    x = "Quarter",
    y = "Revenue ($)",
    caption = "Total quarterly revenue by product category"
  ) +
  scale_y_continuous(labels = function(x) paste0("$", round(x / 1e6, 1), "M")) +
  theme_minimal(base_size = 14) +
  theme(
    plot.background  = element_rect(fill = PAGE_BG, color = PAGE_BG),
    panel.background = element_rect(fill = PAGE_BG, color = NA),
    panel.grid.major = element_line(color = INK, linewidth = 0.2),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank(),
    axis.title       = element_text(color = INK, size = 20, face = "bold"),
    axis.text        = element_text(color = INK_SOFT, size = 16),
    plot.title       = element_text(color = INK, size = 24, face = "bold", margin = margin(b = 15)),
    plot.caption     = element_text(color = INK_SOFT, size = 12, margin = margin(t = 10)),
    legend.background = element_rect(fill = PAGE_BG, color = NA),
    legend.text      = element_text(color = INK_SOFT, size = 16),
    legend.title     = element_text(color = INK, size = 18, face = "bold"),
    legend.position  = "right",
    plot.margin      = margin(20, 20, 20, 20)
  )

# --- Save -------------------------------------------------------------------
ggsave(
  filename = sprintf("plot-%s.png", THEME),
  plot     = p,
  device   = ragg::agg_png,
  width    = 16,
  height   = 9,
  units    = "in",
  dpi      = 300
)

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/bar-stacked-labeled/ggplot2/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "bar-stacked-labeled",
  "language": "r",
  "library": "ggplot2",
  "page": "https://anyplot.ai/bar-stacked-labeled/r/ggplot2",
  "hub": "https://anyplot.ai/bar-stacked-labeled",
  "code_json": "https://api.anyplot.ai/specs/bar-stacked-labeled/ggplot2/code",
  "spec_json": "https://api.anyplot.ai/specs/bar-stacked-labeled",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/bar-stacked-labeled/r/ggplot2/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/bar-stacked-labeled/r/ggplot2/plot-dark.png",
  "quality_score": 92.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Stacked Bar Chart with Total Labels on anyplot.ai.

Other implementations