{"spec_id":"histogram-stacked","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' histogram-stacked: Stacked Histogram\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 88/100 | Created: 2026-09-05\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\"\n# ggplot2 exposes no per-element grid alpha, so blend INK to 15% opacity instead\nGRID_COLOR  <- scales::alpha(INK, 0.15)\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\n\n# --- Data --------------------------------------------------------------------\n# Exam scores for three cohorts sitting the same test, stacked into shared bins\ndf <- bind_rows(\n  tibble::tibble(score = rnorm(600, mean = 68, sd = 9),  cohort = \"Freshman\"),\n  tibble::tibble(score = rnorm(500, mean = 76, sd = 8),  cohort = \"Sophomore\"),\n  tibble::tibble(score = rnorm(400, mean = 83, sd = 7),  cohort = \"Senior\")\n) %>%\n  mutate(score = pmin(pmax(score, 0), 100),\n         cohort = factor(cohort, levels = c(\"Freshman\", \"Sophomore\", \"Senior\")))\n\ncohort_levels <- levels(df$cohort)\nshift_note <- sprintf(\n  \"Scores skew higher across cohorts (%s → %s)\",\n  cohort_levels[1], cohort_levels[length(cohort_levels)]\n)\n\n# --- Plot ---------------------------------------------------------------------\np <- ggplot(df, aes(x = score, fill = cohort)) +\n  geom_histogram(binwidth = 4, boundary = 0, color = PAGE_BG, linewidth = 0.3) +\n  # Distinctive touch: trace the combined total (stat recomputed across all\n  # cohorts, ignoring the fill grouping) so the \"total = combined frequency\"\n  # requirement is visible as a shape, not just implied by the stacking.\n  stat_bin(\n    data        = df,\n    mapping     = aes(x = score, y = after_stat(count)),\n    inherit.aes = FALSE,\n    binwidth    = 4,\n    boundary    = 0,\n    geom        = \"step\",\n    direction   = \"mid\",\n    color       = INK,\n    linewidth   = 0.5\n  ) +\n  annotate(\n    \"text\",\n    x        = -Inf,\n    y        = Inf,\n    label    = shift_note,\n    hjust    = -0.02,\n    vjust     = 1.6,\n    size     = 2.8,\n    fontface = \"italic\",\n    color    = INK_SOFT\n  ) +\n  scale_fill_manual(values = IMPRINT_PALETTE[1:3]) +\n  scale_x_continuous(expand = expansion(mult = c(0.01, 0.03))) +\n  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +\n  labs(\n    title = \"Exam Scores by Cohort · histogram-stacked · r · ggplot2 · anyplot.ai\",\n    x = \"Exam Score\",\n    y = \"Number of Students\",\n    fill = \"Cohort\"\n  ) +\n  theme_minimal(base_size = 8) +\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.x  = element_blank(),\n    panel.grid.minor    = element_blank(),\n    panel.grid.major.y  = element_line(color = GRID_COLOR, linewidth = 0.3),\n    axis.line           = element_line(color = INK_SOFT),\n    axis.ticks          = element_blank(),\n    axis.title          = element_text(color = INK, size = 10),\n    axis.text           = element_text(color = INK_SOFT, size = 8),\n    plot.title          = element_text(color = INK, size = 12, face = \"plain\"),\n    legend.position      = \"top\",\n    legend.justification = \"right\",\n    legend.background   = element_rect(fill = PAGE_BG, color = NA),\n    legend.key           = element_rect(fill = PAGE_BG, color = NA),\n    legend.text          = element_text(color = INK_SOFT, size = 8),\n    legend.title         = element_text(color = INK, size = 10),\n    plot.margin          = margin(t = 10, r = 22, b = 8, l = 8)\n  )\n\n# --- Save ---------------------------------------------------------------------\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 8,\n  height   = 4.5,\n  units    = \"in\",\n  dpi      = 400\n)\n"}