{"spec_id":"calibration-beer-lambert","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' calibration-beer-lambert: Beer-Lambert Calibration Curve\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 87/100 | Created: 2026-06-03\n\nlibrary(ggplot2)\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  <- adjustcolor(INK, alpha.f = 0.15)\n\n# Imprint categorical palette (hybrid-v3 sort)\nIMPRINT_PALETTE <- c(\n  \"#009E73\",  # 1 — brand green (first series, calibration standards)\n  \"#C475FD\",  # 2 — lavender\n  \"#4467A3\",  # 3 — blue\n  \"#BD8233\",  # 4 — ochre\n  \"#AE3030\",  # 5 — matte red (semantic: unknown sample highlight)\n  \"#2ABCCD\",  # 6 — cyan\n  \"#954477\",  # 7 — rose\n  \"#99B314\"   # 8 — lime\n)\n\n# Data: iron (II) calibration by ferrozine colorimetric method (562 nm)\n# Beer-Lambert law: A = epsilon * l * C,  epsilon*l = 0.245 L/(mg·cm)\nconc_standards <- c(0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0)\neps_l          <- 0.245\nabs_noise      <- rnorm(length(conc_standards), mean = 0, sd = 0.006)\nabs_standards  <- pmax(eps_l * conc_standards + abs_noise, 0)\n\ndf <- data.frame(\n  concentration = conc_standards,\n  absorbance    = abs_standards\n)\n\n# Linear regression\nlm_fit    <- lm(absorbance ~ concentration, data = df)\nslope     <- coef(lm_fit)[[\"concentration\"]]\nintercept <- coef(lm_fit)[[\"(Intercept)\"]]\nr_sq      <- summary(lm_fit)$r.squared\n\n# Prediction interval across the fit range\nx_pred  <- data.frame(concentration = seq(0, 4.4, length.out = 200))\npred_ci <- predict(lm_fit, newdata = x_pred, interval = \"prediction\", level = 0.95)\npred_df <- data.frame(\n  concentration = x_pred$concentration,\n  fit           = pred_ci[, \"fit\"],\n  lwr           = pred_ci[, \"lwr\"],\n  upr           = pred_ci[, \"upr\"]\n)\n\n# Unknown sample: measured absorbance → derived concentration\nunknown_abs  <- 0.648\nunknown_conc <- (unknown_abs - intercept) / slope\nunknown_df   <- data.frame(concentration = unknown_conc, absorbance = unknown_abs)\n\n# Regression equation annotation text\neq_text <- sprintf(\n  \"A = %.4f × C + %.4f\\nR² = %.5f\",\n  slope, intercept, r_sq\n)\n\n# Title — font size scaled linearly if longer than the 67-char baseline\nplot_title <- \"calibration-beer-lambert · r · ggplot2 · anyplot.ai\"\ntitle_n    <- nchar(plot_title)\ntitle_size <- if (title_n > 67) round(12 * 67 / title_n) else 12\n\n# Plot\np <- ggplot(df, aes(x = concentration, y = absorbance)) +\n  # 95% prediction interval band\n  geom_ribbon(\n    data        = pred_df,\n    aes(x = concentration, ymin = lwr, ymax = upr),\n    inherit.aes = FALSE,\n    fill        = IMPRINT_PALETTE[1],\n    alpha       = 0.20\n  ) +\n  # Regression fit line\n  geom_line(\n    data        = pred_df,\n    aes(x = concentration, y = fit),\n    inherit.aes = FALSE,\n    color       = IMPRINT_PALETTE[1],\n    linewidth   = 1.2\n  ) +\n  # Unknown sample dashed guide: horizontal (absorbance → y-axis)\n  annotate(\n    \"segment\",\n    x = 0, xend = unknown_conc,\n    y = unknown_abs, yend = unknown_abs,\n    linetype  = \"dashed\",\n    color     = IMPRINT_PALETTE[5],\n    linewidth = 0.7\n  ) +\n  # Unknown sample dashed guide: vertical (concentration → x-axis)\n  annotate(\n    \"segment\",\n    x = unknown_conc, xend = unknown_conc,\n    y = 0, yend = unknown_abs,\n    linetype  = \"dashed\",\n    color     = IMPRINT_PALETTE[5],\n    linewidth = 0.7\n  ) +\n  # Calibration standard points\n  geom_point(\n    color = IMPRINT_PALETTE[1],\n    size  = 3.5,\n    shape = 19\n  ) +\n  # Unknown sample point (diamond)\n  geom_point(\n    data  = unknown_df,\n    color = IMPRINT_PALETTE[5],\n    size  = 4.5,\n    shape = 18\n  ) +\n  # Regression equation + R² annotation box\n  annotate(\n    \"label\",\n    x             = 0.08,\n    y             = 0.94,\n    label         = eq_text,\n    hjust         = 0,\n    vjust         = 1,\n    color         = INK,\n    fill          = ELEVATED_BG,\n    size          = 2.8,\n    label.size    = 0.25,\n    label.padding = unit(0.35, \"lines\"),\n    label.r       = unit(0.1, \"lines\")\n  ) +\n  # Unknown sample label\n  annotate(\n    \"text\",\n    x          = unknown_conc + 0.20,\n    y          = unknown_abs + 0.03,\n    label      = sprintf(\"Unknown\\nC = %.2f mg/L\", unknown_conc),\n    hjust      = 0,\n    vjust      = 0,\n    color      = IMPRINT_PALETTE[5],\n    size       = 2.5,\n    lineheight = 1.1\n  ) +\n  labs(\n    title = plot_title,\n    x     = \"Concentration (mg/L)\",\n    y     = \"Absorbance\"\n  ) +\n  scale_x_continuous(\n    breaks = seq(0, 4, by = 0.5),\n    expand = expansion(mult = c(0.02, 0.04))\n  ) +\n  scale_y_continuous(\n    limits = c(0, 1.15),\n    breaks = seq(0, 1.0, by = 0.2),\n    expand = expansion(mult = c(0.01, 0.03))\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.4),\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 = title_size,\n                                    hjust = 0, face = \"plain\"),\n    plot.margin      = margin(20, 30, 20, 20, \"pt\")\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"}