{"spec_id":"bar-stacked-labeled","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' bar-stacked-labeled: Stacked Bar Chart with Total Labels\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 92/100 | Created: 2026-05-18\n\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(ragg)\n\nset.seed(42)\n\n# --- Theme tokens -----------------------------------------------------------\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nIMPRINT   <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                 \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# --- Data -------------------------------------------------------------------\n# Quarterly revenue by product category\ndf <- data.frame(\n  quarter = rep(c(\"Q1\", \"Q2\", \"Q3\", \"Q4\"), each = 3),\n  product = rep(c(\"Electronics\", \"Apparel\", \"Home\"), 4),\n  revenue = c(\n    450000, 320000, 280000,  # Q1\n    520000, 380000, 310000,  # Q2\n    580000, 420000, 350000,  # Q3\n    650000, 480000, 400000   # Q4\n  )\n)\n\n# Calculate totals for each quarter (for labels above bars)\ndf_totals <- df %>%\n  group_by(quarter) %>%\n  summarize(total = sum(revenue), .groups = \"drop\")\n\n# --- Plot -------------------------------------------------------------------\np <- ggplot(df, aes(x = quarter, y = revenue, fill = product)) +\n  geom_col(position = \"stack\", width = 0.6) +\n  geom_text(\n    data = df_totals,\n    aes(x = quarter, y = total, label = paste0(\"$\", round(total / 1e6, 1), \"M\")),\n    vjust = -0.3,\n    size = 6,\n    fontface = \"bold\",\n    color = INK,\n    inherit.aes = FALSE\n  ) +\n  scale_fill_manual(values = IMPRINT[1:3], name = \"Product\") +\n  labs(\n    title = \"bar-stacked-labeled · R · ggplot2 · anyplot.ai\",\n    x = \"Quarter\",\n    y = \"Revenue ($)\",\n    caption = \"Total quarterly revenue by product category\"\n  ) +\n  scale_y_continuous(labels = function(x) paste0(\"$\", round(x / 1e6, 1), \"M\")) +\n  theme_minimal(base_size = 14) +\n  theme(\n    plot.background  = element_rect(fill = PAGE_BG, color = PAGE_BG),\n    panel.background = element_rect(fill = PAGE_BG, color = NA),\n    panel.grid.major = element_line(color = INK, linewidth = 0.2),\n    panel.grid.minor = element_blank(),\n    panel.grid.major.x = element_blank(),\n    axis.title       = element_text(color = INK, size = 20, face = \"bold\"),\n    axis.text        = element_text(color = INK_SOFT, size = 16),\n    plot.title       = element_text(color = INK, size = 24, face = \"bold\", margin = margin(b = 15)),\n    plot.caption     = element_text(color = INK_SOFT, size = 12, margin = margin(t = 10)),\n    legend.background = element_rect(fill = PAGE_BG, color = NA),\n    legend.text      = element_text(color = INK_SOFT, size = 16),\n    legend.title     = element_text(color = INK, size = 18, face = \"bold\"),\n    legend.position  = \"right\",\n    plot.margin      = margin(20, 20, 20, 20)\n  )\n\n# --- Save -------------------------------------------------------------------\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 16,\n  height   = 9,\n  units    = \"in\",\n  dpi      = 300\n)\n"}