{"spec_id":"bar-grouped","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' bar-grouped: Grouped Bar Chart\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 92/100 | Created: 2026-08-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# element_line() has no `alpha` argument, so bake a ~20% opacity into the hex\n# itself (0x33 = 51/255) to get the style guide's \"subtle\" gridline.\nGRID_COLOR  <- paste0(INK, \"33\")\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\n\n# --- Data ---------------------------------------------------------------\nregions  <- c(\"North\", \"South\", \"East\", \"West\", \"Central\")\nproducts <- c(\"Software\", \"Hardware\", \"Services\")\n\ndf <- expand.grid(region = regions, product = products) %>%\n  mutate(\n    product = factor(product, levels = products),\n    revenue = case_when(\n      product == \"Software\" ~ round(rnorm(n(), mean = 5.8, sd = 0.9), 1),\n      product == \"Hardware\" ~ round(rnorm(n(), mean = 4.2, sd = 1.1), 1),\n      TRUE                  ~ round(rnorm(n(), mean = 3.0, sd = 0.6), 1)\n    )\n  )\n\n# Order regions by total revenue (descending) so the chart reads as a ranking\n# rather than an arbitrary list.\nregion_order <- df %>%\n  group_by(region) %>%\n  summarise(total = sum(revenue), .groups = \"drop\") %>%\n  arrange(desc(total)) %>%\n  pull(region)\n\ndf <- df %>% mutate(region = factor(region, levels = region_order))\n\n# --- Plot -----------------------------------------------------------------\np <- ggplot(df, aes(x = region, y = revenue, fill = product)) +\n  geom_col(\n    position = position_dodge(width = 0.75),\n    width = 0.68,\n    color = PAGE_BG,\n    linewidth = 0.4\n  ) +\n  geom_text(\n    aes(label = sprintf(\"%.1f\", revenue)),\n    position = position_dodge(width = 0.75),\n    vjust = -0.5,\n    size = 2.4,\n    color = INK_SOFT\n  ) +\n  scale_fill_manual(values = IMPRINT_PALETTE[1:3], name = \"Product Line\") +\n  scale_y_continuous(expand = expansion(mult = c(0, 0.14))) +\n  labs(\n    title = \"Revenue by Product Line · bar-grouped · r · ggplot2 · anyplot.ai\",\n    x = \"Region\",\n    y = \"Revenue ($M)\"\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.x  = element_blank(),\n    panel.grid.minor.y  = element_blank(),\n    panel.grid.major.y  = element_line(color = GRID_COLOR, linewidth = 0.25),\n    axis.line           = element_line(color = INK_SOFT, linewidth = 0.4),\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.position     = \"top\",\n    legend.justification = \"left\",\n    legend.background   = element_blank(),\n    legend.key          = element_blank(),\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 = 16, 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"}