{"spec_id":"ecdf-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' ecdf-basic: Basic ECDF Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-06-25\n\nlibrary(ggplot2)\nlibrary(scales)\nlibrary(ragg)\n\nset.seed(42)\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\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\"\nGRID_COLOR  <- if (THEME == \"light\") \"#1A1A1726\" else \"#F0EFE826\"\n\nIMPRINT_PALETTE <- c(\n  \"#009E73\",  # 1 — brand green (first categorical series)\n  \"#C475FD\",  # 2 — lavender\n  \"#4467A3\",  # 3 — blue\n  \"#BD8233\",  # 4 — ochre\n  \"#AE3030\",  # 5 — matte red\n  \"#2ABCCD\",  # 6 — cyan\n  \"#954477\",  # 7 — rose\n  \"#99B314\"   # 8 — lime\n)\n\n# Data: exam scores comparing two student cohorts\nn <- 200\nscores_a <- rnorm(n, mean = 68, sd = 14)  # standard curriculum\nscores_b <- rnorm(n, mean = 76, sd = 10)  # enriched curriculum\n\ndf <- data.frame(\n  score  = c(scores_a, scores_b),\n  cohort = rep(c(\"Class A\", \"Class B\"), each = n)\n)\n\n# Medians for reference annotations\nmedian_a <- median(scores_a)\nmedian_b <- median(scores_b)\ngap <- round(median_b - median_a)\n\n# Plot\np <- ggplot(df, aes(x = score, color = cohort, linetype = cohort)) +\n  # Horizontal dotted reference at 50th percentile for reading medians\n  geom_hline(\n    yintercept = 0.5,\n    color      = INK_SOFT,\n    linewidth  = 0.4,\n    linetype   = \"dotted\"\n  ) +\n  # ECDF step lines\n  stat_ecdf(linewidth = 1.2, pad = FALSE) +\n  # Vertical droplines from x-axis to 50th percentile for each cohort\n  annotate(\"segment\",\n    x = median_a, xend = median_a, y = 0, yend = 0.5,\n    color = IMPRINT_PALETTE[1], linewidth = 0.5, linetype = \"dotted\", alpha = 0.8\n  ) +\n  annotate(\"segment\",\n    x = median_b, xend = median_b, y = 0, yend = 0.5,\n    color = IMPRINT_PALETTE[2], linewidth = 0.5, linetype = \"dotted\", alpha = 0.8\n  ) +\n  # Markers at median intersections on each ECDF curve\n  annotate(\"point\",\n    x = median_a, y = 0.5,\n    color = IMPRINT_PALETTE[1], size = 2.0\n  ) +\n  annotate(\"point\",\n    x = median_b, y = 0.5,\n    color = IMPRINT_PALETTE[2], size = 2.0\n  ) +\n  scale_color_manual(\n    name   = \"Student Cohort\",\n    values = c(\"Class A\" = IMPRINT_PALETTE[1], \"Class B\" = IMPRINT_PALETTE[2])\n  ) +\n  scale_linetype_manual(\n    name   = \"Student Cohort\",\n    values = c(\"Class A\" = \"solid\", \"Class B\" = \"dashed\")\n  ) +\n  scale_x_continuous(breaks = seq(20, 120, by = 10)) +\n  scale_y_continuous(\n    labels = percent_format(accuracy = 1),\n    breaks = seq(0, 1, by = 0.25)\n  ) +\n  labs(\n    title    = \"Exam Score Distribution by Curriculum Type · ecdf-basic · r · ggplot2 · anyplot.ai\",\n    subtitle = sprintf(\n      \"Median: Class A (standard) = %.0f pts vs. Class B (enriched) = %.0f pts — %+.0f-pt gap at the 50th percentile\",\n      median_a, median_b, gap\n    ),\n    x = \"Exam Score\",\n    y = \"Cumulative Proportion\"\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  = element_line(color = GRID_COLOR, linewidth = 0.5),\n    panel.grid.minor  = element_blank(),\n    panel.border      = element_blank(),\n    axis.title        = element_text(color = INK, size = 10),\n    axis.text         = element_text(color = INK_SOFT, size = 8),\n    axis.line         = element_line(color = INK_SOFT, linewidth = 0.5),\n    plot.title        = element_text(color = INK, size = 10),\n    plot.subtitle     = element_text(color = INK_SOFT, size = 8),\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_text(color = INK, size = 10),\n    legend.position   = \"bottom\",\n    plot.margin       = margin(20, 20, 20, 20)\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"}