{"spec_id":"bar-pareto","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' bar-pareto: Pareto Chart with Cumulative Line\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 91/100 | Created: 2026-06-20\n\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(scales)\nlibrary(ragg)\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\"\nIMPRINT_PALETTE <- c(\n    \"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n    \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"\n)\nANYPLOT_AMBER <- \"#DDCC77\"\n\n# --- Data ---\n# Manufacturing defect data: two root causes dominate (Pareto principle)\ndefect_data <- data.frame(\n    category = c(\n        \"Surface Scratches\", \"Misalignment\", \"Paint Defects\",\n        \"Weld Flaws\", \"Assembly Gaps\", \"Contamination\",\n        \"Thread Damage\", \"Other\"\n    ),\n    count = c(500, 300, 80, 55, 30, 18, 10, 7)\n)\n\n# Sort descending and compute cumulative sums\ndefect_data <- defect_data |>\n    arrange(desc(count)) |>\n    mutate(\n        category  = factor(category, levels = category),\n        cum_count = cumsum(count)\n    )\n\ntotal_count     <- sum(defect_data$count)\nthreshold_count <- 0.8 * total_count\n\n# --- Plot ---\nplot_title <- \"Manufacturing Defects · bar-pareto · r · ggplot2 · anyplot.ai\"\n\np <- ggplot(defect_data, aes(x = category)) +\n\n    # Bars (primary axis: raw counts, fill-mapped for legend)\n    geom_col(\n        aes(y = count, fill = \"Defect count\"),\n        width = 0.7,\n        alpha = 0.92\n    ) +\n\n    # 80% Pareto threshold reference line (color-mapped for legend)\n    geom_hline(\n        aes(yintercept = threshold_count, color = \"80% threshold\"),\n        linewidth = 0.85,\n        linetype  = \"dashed\"\n    ) +\n\n    # Cumulative percentage line (color-mapped for legend)\n    geom_line(\n        aes(y = cum_count, group = 1, color = \"Cumulative %\"),\n        linewidth = 1.3\n    ) +\n\n    # Markers at center-top of each bar\n    geom_point(\n        aes(y = cum_count, color = \"Cumulative %\"),\n        size  = 3.5,\n        shape = 19\n    ) +\n\n    # Annotation: highlight where cumulative % crosses 80%\n    annotate(\n        \"text\",\n        x     = 2.5,\n        y     = threshold_count + total_count * 0.04,\n        label = \"Top 2 → 80% of defects\",\n        color = ANYPLOT_AMBER,\n        size  = 2.6,\n        hjust = 0\n    ) +\n\n    # Dual y-axis: primary = count, secondary = cumulative %\n    scale_y_continuous(\n        name     = \"Defect count\",\n        limits   = c(0, total_count),\n        expand   = expansion(mult = c(0, 0)),\n        labels   = scales::comma,\n        sec.axis = sec_axis(\n            ~ . / total_count * 100,\n            name   = \"Cumulative percentage (%)\",\n            breaks = seq(0, 100, 20),\n            labels = function(x) paste0(x, \"%\")\n        )\n    ) +\n\n    scale_x_discrete(expand = expansion(add = c(0.6, 0.6))) +\n\n    # Legend: fill scale for bars\n    scale_fill_manual(\n        name   = NULL,\n        values = c(\"Defect count\" = IMPRINT_PALETTE[1])\n    ) +\n\n    # Legend: color scale for line and reference\n    scale_color_manual(\n        name   = NULL,\n        values = c(\n            \"Cumulative %\"  = IMPRINT_PALETTE[3],\n            \"80% threshold\" = ANYPLOT_AMBER\n        ),\n        guide = guide_legend(\n            override.aes = list(\n                linetype  = c(\"solid\", \"dashed\"),\n                shape     = c(16, NA),\n                linewidth = c(1.3, 0.85)\n            )\n        )\n    ) +\n\n    labs(\n        x     = \"Defect category\",\n        title = plot_title\n    ) +\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        # L-frame: bottom and left axis lines only (remove full box border)\n        panel.border       = element_blank(),\n        axis.line.x.bottom = element_line(color = INK_SOFT, linewidth = 0.4),\n        axis.line.y.left   = element_line(color = INK_SOFT, linewidth = 0.4),\n        panel.grid.major.y = element_line(\n            color     = adjustcolor(INK, alpha.f = 0.12),\n            linewidth = 0.35\n        ),\n        panel.grid.major.x = element_blank(),\n        panel.grid.minor   = element_blank(),\n        axis.title.x       = element_text(color = INK,                size = 10),\n        axis.title.y.left  = element_text(color = INK,                size = 10),\n        axis.title.y.right = element_text(color = IMPRINT_PALETTE[3], size = 10),\n        axis.text.x        = element_text(color = INK_SOFT, size = 7.5, angle = 32, hjust = 1),\n        axis.text.y.left   = element_text(color = INK_SOFT,           size = 8),\n        # Use INK_SOFT for right-axis ticks in dark mode (better contrast vs. #1A1A17)\n        axis.text.y.right  = element_text(\n            color = if (THEME == \"dark\") INK_SOFT else IMPRINT_PALETTE[3],\n            size  = 8\n        ),\n        axis.ticks         = element_line(color = INK_SOFT, linewidth = 0.3),\n        plot.title         = element_text(color = INK, size = 12, face = \"bold\",\n                                          margin = margin(b = 8)),\n        plot.margin        = margin(t = 15, r = 15, b = 10, l = 10, unit = \"pt\"),\n        legend.position    = \"bottom\",\n        legend.background  = element_rect(fill = ELEVATED_BG, color = NA),\n        legend.text        = element_text(color = INK_SOFT, size = 8),\n        legend.key         = element_rect(fill = NA, color = NA),\n        legend.key.size    = unit(1, \"lines\"),\n        legend.box         = \"horizontal\",\n        legend.margin      = margin(t = 2, b = 4, l = 4, r = 4)\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"}