{"spec_id":"bar-diverging-likert","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' bar-diverging-likert: Likert Scale Diverging Bar Chart\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-06-01\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\"\nINK_MUTED   <- if (THEME == \"light\") \"#6B6A63\" else \"#A8A79F\"\n\n# Diverging colors from Imprint palette: red (bad) -> muted (neutral) -> blue (good)\n# Semantic exception: negative sentiment = red (#AE3030), positive = blue (#4467A3)\nlikert_palette <- colorRampPalette(c(\"#AE3030\", \"#6B6A63\", \"#4467A3\"))(5)\n\n# --- Survey data: Employee Benefits Survey ---\nquestions <- c(\n  \"Health insurance\",\n  \"PTO allowance\",\n  \"Dental & vision\",\n  \"Flexible hours\",\n  \"Remote work options\",\n  \"Parental leave\",\n  \"Retirement plan\",\n  \"Prof. development\",\n  \"Mental health support\",\n  \"Annual bonus\"\n)\n\nsurvey_raw <- data.frame(\n  question          = questions,\n  strongly_disagree = c( 4,  5,  6,  8, 10,  8, 12, 15, 18, 22),\n  disagree          = c( 8, 10, 11, 12, 15, 18, 20, 20, 22, 28),\n  neutral           = c(12, 15, 18, 20, 18, 20, 18, 22, 20, 18),\n  agree             = c(45, 42, 40, 38, 35, 32, 30, 28, 25, 22),\n  strongly_agree    = c(31, 28, 25, 22, 22, 22, 20, 15, 15, 10)\n)\n\n# Sort by net agreement (agree + strongly_agree - disagree - strongly_disagree)\nsurvey_sorted <- survey_raw %>%\n  mutate(net_agreement = (agree + strongly_agree) - (disagree + strongly_disagree)) %>%\n  arrange(net_agreement) %>%\n  mutate(question = factor(question, levels = question))\n\n# Reshape to long format for diverging bar chart\n# Neutral is split in half: negative half on left, positive half on right\n# Factor level order controls stacking direction: neutral nearest center, strong responses outermost\ndf_long <- survey_sorted %>%\n  select(question, strongly_disagree, disagree, neutral, agree, strongly_agree) %>%\n  mutate(\n    neutral_neg       = -neutral / 2,\n    neutral_pos       =  neutral / 2,\n    disagree          = -disagree,\n    strongly_disagree = -strongly_disagree\n  ) %>%\n  select(-neutral) %>%\n  pivot_longer(\n    cols      = -question,\n    names_to  = \"response\",\n    values_to = \"pct\"\n  ) %>%\n  mutate(\n    # For horizontal diverging bars in ggplot2 position_stack:\n    # negatives: lowest factor level = innermost (nearest 0)\n    # positives: highest factor level = innermost (nearest 0)\n    # So positive levels must be ordered: strongly_agree < agree < neutral_pos\n    response = factor(response, levels = c(\n      \"neutral_neg\", \"disagree\", \"strongly_disagree\",\n      \"strongly_agree\", \"agree\", \"neutral_pos\"\n    )),\n    abs_pct    = abs(pct),\n    label_text = ifelse(abs_pct >= 8, paste0(round(abs_pct), \"%\"), \"\")\n  )\n\n# Fill colors: neutral_neg and neutral_pos share the muted center color\nfill_colors <- c(\n  \"neutral_neg\"       = likert_palette[3],\n  \"disagree\"          = likert_palette[2],\n  \"strongly_disagree\" = likert_palette[1],\n  \"neutral_pos\"       = likert_palette[3],\n  \"agree\"             = likert_palette[4],\n  \"strongly_agree\"    = likert_palette[5]\n)\n\n# Title: 66 chars (within 67-char baseline → fontsize stays at 12)\nplot_title <- \"Employee Benefits · bar-diverging-likert · r · ggplot2 · anyplot.ai\"\n\n# --- Plot ---\np <- ggplot(df_long, aes(x = pct, y = question, fill = response)) +\n  geom_col(position = \"stack\", width = 0.72) +\n  geom_text(\n    aes(label = label_text),\n    position = position_stack(vjust = 0.5),\n    color    = \"#FAF8F1\",\n    size     = 2.2,\n    fontface = \"bold\"\n  ) +\n  geom_vline(xintercept = 0, color = INK_SOFT, linewidth = 0.6) +\n  scale_fill_manual(\n    values = fill_colors,\n    breaks = c(\"strongly_disagree\", \"disagree\", \"neutral_neg\", \"agree\", \"strongly_agree\"),\n    labels = c(\"Strongly Disagree\", \"Disagree\", \"Neutral\", \"Agree\", \"Strongly Agree\"),\n    name   = NULL\n  ) +\n  scale_x_continuous(\n    labels = function(x) paste0(abs(x), \"%\"),\n    expand = expansion(mult = c(0.03, 0.03))\n  ) +\n  labs(\n    title = plot_title,\n    x     = \"Percentage of Respondents\",\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.grid.major.x = element_line(color = INK_SOFT, linewidth = 0.15),\n    panel.grid.major.y = element_blank(),\n    panel.grid.minor   = element_blank(),\n    panel.border       = element_blank(),\n    axis.title.x       = element_text(color = INK, size = 10, margin = margin(t = 6)),\n    axis.title.y       = element_blank(),\n    axis.text.x        = element_text(color = INK_SOFT, size = 8),\n    axis.text.y        = element_text(color = INK, size = 9, hjust = 1),\n    axis.line.x        = element_line(color = INK_SOFT, linewidth = 0.4),\n    axis.line.y        = element_blank(),\n    axis.ticks         = element_blank(),\n    plot.title         = element_text(\n      color  = INK,\n      size   = 12,\n      hjust  = 0.5,\n      margin = margin(b = 12)\n    ),\n    legend.background  = element_rect(fill = ELEVATED_BG, color = INK_SOFT, linewidth = 0.3),\n    legend.text        = element_text(color = INK_SOFT, size = 8),\n    legend.title       = element_blank(),\n    legend.position    = \"bottom\",\n    legend.direction   = \"horizontal\",\n    legend.key.size    = unit(10, \"pt\"),\n    legend.margin      = margin(4, 4, 4, 4),\n    plot.margin        = margin(15, 20, 5, 10)\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"}