{"spec_id":"pp-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' pp-basic: Probability-Probability (P-P) Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-06-09\n\nlibrary(ggplot2)\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\"\n\n# Imprint palette (canonical order)\nIMPRINT_PALETTE <- c(\n  \"#009E73\",  # 1 — brand green (first 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: reaction time measurements (ms) for a quality control process\n# 200 observations with a slight right tail — compared against a fitted normal\nn_obs        <- 200\nbase_times   <- rnorm(160, mean = 145, sd = 12)\ndelayed_obs  <- rnorm(40,  mean = 162, sd = 8)\nobserved     <- c(base_times, delayed_obs)\n\n# Fit normal distribution parameters (MLE)\nfit_mean <- mean(observed)\nfit_sd   <- sd(observed)\n\n# Empirical CDF via Hazen plotting positions: (i - 0.5) / n\nsorted_obs      <- sort(observed)\nempirical_cdf   <- (seq_len(n_obs) - 0.5) / n_obs\ntheoretical_cdf <- pnorm(sorted_obs, fit_mean, fit_sd)\n\ndf <- data.frame(\n  theoretical = theoretical_cdf,\n  empirical   = empirical_cdf\n)\n\n# Build plot\nplot_title <- \"pp-basic · r · ggplot2 · anyplot.ai\"\n\np <- ggplot(df, aes(x = theoretical, y = empirical)) +\n  geom_abline(\n    slope     = 1,\n    intercept = 0,\n    color     = INK_SOFT,\n    linewidth = 0.8,\n    linetype  = \"dashed\"\n  ) +\n  geom_point(\n    color = IMPRINT_PALETTE[1],\n    size  = 2.5,\n    alpha = 0.75\n  ) +\n  scale_x_continuous(\n    limits = c(0, 1),\n    breaks = seq(0, 1, 0.2),\n    expand = c(0.02, 0)\n  ) +\n  scale_y_continuous(\n    limits = c(0, 1),\n    breaks = seq(0, 1, 0.2),\n    expand = c(0.02, 0)\n  ) +\n  coord_equal() +\n  labs(\n    x        = \"Theoretical Cumulative Probability\",\n    y        = \"Empirical Cumulative Probability\",\n    title    = plot_title,\n    subtitle = \"Fitted normal — right-tail deviation visible above 0.6\"\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(\n      color     = scales::alpha(INK, 0.15),\n      linewidth = 0.5\n    ),\n    panel.grid.minor = element_blank(),\n    panel.border     = element_blank(),\n    axis.line        = element_line(color = INK_SOFT, linewidth = 0.5),\n    axis.title       = element_text(color = INK,      size = 10),\n    axis.text        = element_text(color = INK_SOFT, size = 8),\n    plot.title       = element_text(color = INK,      size = 12),\n    plot.subtitle    = element_text(color = INK_SOFT, size = 9),\n    plot.margin      = margin(20, 20, 20, 20)\n  )\n\n# Save — square canvas: 6×6 in @ 400 dpi = 2400×2400 px\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 6,\n  height   = 6,\n  units    = \"in\",\n  dpi      = 400\n)\n"}