{"spec_id":"count-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' count-basic: Basic Count Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 87/100 | Updated: 2026-09-30\n\nlibrary(ggplot2)\nlibrary(dplyr)\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\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\nBAR_FILL    <- IMPRINT_PALETTE[1]\n# Bar edge uses the ink token -- the style guide's endorsed outline pattern --\n# never a custom hex; a crisp stroke for depth, not a second color encoding.\nBAR_EDGE    <- INK\n# Faint gridline tone -- ggplot2 has no grid alpha, so blend INK ~15% into\n# PAGE_BG instead of using full-opacity INK (which reads as bold as the axis).\nGRID_COLOR  <- colorRampPalette(c(PAGE_BG, INK))(100)[15]\n\n# --- Data ---------------------------------------------------------------\n# Raw, uncounted survey responses -- ggplot2's geom_bar() tallies them itself.\nsupport_levels <- c(\n  \"Strongly Agree\", \"Agree\", \"Neutral\", \"Disagree\", \"Strongly Disagree\"\n)\nresponse_weights <- c(0.32, 0.30, 0.19, 0.13, 0.06)\nsurvey_responses <- sample(\n  support_levels,\n  size = 480,\n  replace = TRUE,\n  prob = response_weights\n)\n\ndf <- tibble::tibble(\n  response = factor(survey_responses, levels = support_levels)\n)\n\n# Order categories by descending frequency for readability\nfreq_order <- df %>%\n  count(response, name = \"n\") %>%\n  arrange(desc(n)) %>%\n  pull(response)\ndf$response <- factor(df$response, levels = freq_order)\nn_total <- nrow(df)\n\n# --- Plot -----------------------------------------------------------------\ntitle_text <- \"count-basic · r · ggplot2 · anyplot.ai\"\n\n# Basic variant: single categorical variable, one bar color, no reference\n# line, highlighted bar or second grouping. geom_text(stat = \"count\") tallies\n# and labels the bars in the same pass as geom_bar() -- no separate\n# dplyr::count() table needed for the labels.\np <- ggplot(df, aes(x = response)) +\n  geom_bar(width = 0.62, fill = BAR_FILL, color = BAR_EDGE, linewidth = 0.4) +\n  geom_text(\n    stat = \"count\",\n    aes(\n      label = sprintf(\n        \"%s (%s)\",\n        scales::comma(after_stat(count)),\n        scales::percent(after_stat(count) / n_total, accuracy = 1)\n      ),\n      # Most-frequent bar's label reads bolder and larger for a single focal\n      # point -- same fill color throughout, emphasis from type weight alone.\n      fontface = ifelse(after_stat(count) == max(after_stat(count)), \"bold\", \"plain\"),\n      size     = ifelse(after_stat(count) == max(after_stat(count)), 3.8, 3.2)\n    ),\n    vjust = -0.7,\n    color = INK\n  ) +\n  scale_size_identity() +\n  # Extra headroom above the tallest bar (was 0.14) so its bold label sits\n  # clear of the panel edge -- a deliberate breathing-room refinement, not a\n  # change to the data-to-baseline mapping.\n  scale_y_continuous(expand = expansion(mult = c(0, 0.19))) +\n  labs(\n    title    = title_text,\n    subtitle = sprintf(\"Likert-scale survey responses, n = %d\", n_total),\n    x = \"Survey Response\",\n    y = \"Count\"\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.title        = element_text(color = INK, size = 10),\n    axis.text         = element_text(color = INK_SOFT, size = 8),\n    axis.text.x       = element_text(margin = margin(t = 6)),\n    axis.ticks         = element_blank(),\n    axis.line.x        = element_line(color = INK_SOFT, linewidth = 0.3),\n    plot.title        = element_text(color = INK, size = 12, face = \"bold\"),\n    plot.subtitle     = element_text(color = INK_SOFT, size = 8.5, margin = margin(b = 8)),\n    # Title/subtitle flush to the full plot width (not just the panel) and a\n    # touch more canvas whitespace all around -- a spacing/typography-only\n    # refinement, no new marks or color.\n    plot.title.position = \"plot\",\n    plot.margin          = margin(t = 14, r = 18, b = 10, l = 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"}