{"spec_id":"bar-diverging","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' bar-diverging: Diverging Bar Chart\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 86/100 | Created: 2026-08-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_PALETTE <- c(\n  \"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n  \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"\n)\n\n# --- Data -----------------------------------------------------------------\n# Employee engagement survey: net promoter score per department\n# (% promoters - % detractors), sentiment polarity -> green/red semantic exception\ndf <- tibble::tibble(\n  department = c(\n    \"Product Design\", \"Data Science\", \"Customer Success\", \"Engineering\",\n    \"Marketing\", \"R&D\", \"Human Resources\", \"Legal & Compliance\",\n    \"Finance\", \"Procurement\", \"Facilities\", \"IT Support\",\n    \"Sales\", \"Call Center\", \"Warehouse Ops\", \"Field Service\"\n  ),\n  nps = c(\n    62, 54, 47, 41, 33, 28, 19, 12,\n    -6, -14, -19, -22, -27, -34, -41, -49\n  )\n) %>%\n  mutate(\n    sentiment = ifelse(nps >= 0, \"Promoters lead\", \"Detractors lead\"),\n    department = factor(department, levels = department[order(nps)])\n  )\n\n# Direct-label only the two extremes (best/worst department) so the funnel's\n# endpoints carry their exact score without cluttering the 14 bars in between.\ntop_row <- df[which.max(df$nps), ]\nbottom_row <- df[which.min(df$nps), ]\n\n# --- Plot -------------------------------------------------------------------\np <- ggplot(df, aes(x = nps, y = department, fill = sentiment)) +\n  geom_col(width = 0.7) +\n  geom_vline(xintercept = 0, color = INK_SOFT, linewidth = 0.5) +\n  annotate(\n    \"text\",\n    x = top_row$nps, y = top_row$department,\n    label = sprintf(\"%+d\", top_row$nps), hjust = -0.25,\n    size = 3, color = INK, fontface = \"bold\"\n  ) +\n  annotate(\n    \"text\",\n    x = bottom_row$nps, y = bottom_row$department,\n    label = sprintf(\"%+d\", bottom_row$nps), hjust = 1.25,\n    size = 3, color = INK, fontface = \"bold\"\n  ) +\n  scale_fill_manual(\n    values = c(\n      \"Promoters lead\" = IMPRINT_PALETTE[1],\n      \"Detractors lead\" = IMPRINT_PALETTE[5]\n    ),\n    name = NULL\n  ) +\n  scale_x_continuous(breaks = seq(-60, 60, 20), expand = expansion(mult = 0.08)) +\n  labs(\n    title = \"bar-diverging · r · ggplot2 · anyplot.ai\",\n    x = \"Net Promoter Score\",\n    y = NULL\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.border = element_blank(),\n    panel.grid.major.y = element_blank(),\n    panel.grid.minor = element_blank(),\n    panel.grid.major.x = element_line(color = INK, linewidth = 0.25),\n    axis.title = element_text(color = INK, size = 10),\n    axis.text = element_text(color = INK_SOFT, size = 8),\n    axis.ticks = element_blank(),\n    plot.title = element_text(color = INK, size = 12, face = \"bold\"),\n    plot.title.position = \"plot\",\n    plot.margin = margin(t = 10, r = 18, b = 8, l = 10),\n    legend.position = \"top\",\n    legend.justification = \"left\",\n    legend.margin = margin(t = 2, b = 4),\n    legend.spacing.x = unit(6, \"pt\"),\n    legend.text = element_text(color = INK_SOFT, size = 8),\n    legend.key.size = unit(10, \"pt\")\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"}