{"spec_id":"area-cumulative-flow","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' area-cumulative-flow: Cumulative Flow Diagram for Workflow Analytics\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 90/100 | Created: 2026-08-18\n\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(tidyr)\nlibrary(scales)\nlibrary(ragg)\n\nset.seed(42)\n\n# --- Theme tokens -------------------------------------------------------------\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nELEVATED_BG <- if (THEME == \"light\") \"#FFFDF6\" else \"#242420\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\n\nIMPRINT_PALETTE <- c(\n  \"#009E73\", # 1 - Backlog (brand green, always first series)\n  \"#C475FD\", # 2 - Analysis\n  \"#4467A3\", # 3 - Development\n  \"#BD8233\", # 4 - Testing\n  \"#AE3030\"  # 5 - Done\n)\n\n# --- Data: 90-day Kanban board cumulative flow ---------------------------------\nstages   <- c(\"Backlog\", \"Analysis\", \"Development\", \"Testing\", \"Done\")\nn_stages <- length(stages)\nn_days   <- 90\ndates    <- seq(as.Date(\"2024-01-01\"), by = \"day\", length.out = n_days)\n\n# Daily items entering the pipeline\narrivals <- pmax(0, round(rnorm(n_days, mean = 9, sd = 3)))\n\ncum_matrix <- matrix(0, nrow = n_days, ncol = n_stages)\ncum_matrix[, 1] <- cumsum(arrivals)\n\n# Each downstream stage absorbs a capped number of items per day from the\n# stage upstream of it. Capacity tightens down the pipeline (8/7/6/5), so\n# every stage's queue grows over the series — demand consistently outpaces\n# throughput, the classic CFD signature of a pipeline running behind.\nthroughput_lambda <- c(8, 7, 6, 5)\nfor (i in 2:n_stages) {\n  capacity <- rpois(n_days, lambda = throughput_lambda[i - 1])\n  cur <- 0\n  for (t in seq_len(n_days)) {\n    cur <- min(cum_matrix[t, i - 1], cur + capacity[t])\n    cum_matrix[t, i] <- cur\n  }\n}\n\ndf <- as.data.frame(cum_matrix)\ncolnames(df) <- stages\ndf$date <- dates\ndf <- as_tibble(df)\n\ndf_long <- df %>%\n  pivot_longer(cols = all_of(stages), names_to = \"stage\", values_to = \"cum_count\") %>%\n  mutate(stage = factor(stage, levels = stages))\n\n# WIP per stage is the vertical gap between its cumulative curve and the next\n# stage's cumulative curve (items that entered this stage but haven't left it).\ndf_bands <- df_long %>%\n  arrange(date, stage) %>%\n  group_by(date) %>%\n  mutate(ymax = cum_count, ymin = lead(cum_count, default = 0)) %>%\n  ungroup()\n\n# --- Plot -----------------------------------------------------------------------\nanyplot_theme <- theme_minimal(base_size = 7) +\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 = INK, linewidth = 0.2),\n    axis.line.x       = element_line(color = INK_SOFT, linewidth = 0.3),\n    axis.line.y       = element_line(color = INK_SOFT, linewidth = 0.3),\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 = \"bold\"),\n    legend.background = element_rect(fill = ELEVATED_BG, color = NA),\n    legend.text       = element_text(color = INK_SOFT, size = 8),\n    legend.title      = element_text(color = INK, size = 10),\n    legend.position   = \"right\"\n  )\n\np <- ggplot(df_bands, aes(x = date, ymin = ymin, ymax = ymax, fill = stage)) +\n  geom_ribbon(color = PAGE_BG, linewidth = 0.2) +\n  scale_fill_manual(values = IMPRINT_PALETTE, name = \"Stage\") +\n  scale_x_date(date_breaks = \"2 weeks\", date_labels = \"%b %d\") +\n  scale_y_continuous(labels = scales::comma, expand = expansion(mult = c(0, 0.05))) +\n  labs(\n    title = \"area-cumulative-flow · r · ggplot2 · anyplot.ai\",\n    x     = \"Date\",\n    y     = \"Cumulative Items\"\n  ) +\n  anyplot_theme\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"}