{"spec_id":"span-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' span-basic: Basic Span Plot (Highlighted Region)\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 92/100 | Created: 2026-07-25\n\nlibrary(ggplot2)\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\"\nNEUTRAL     <- INK  # theme-adaptive anchor for the span highlight (reference region)\nAMBER       <- \"#DDCC77\"  # semantic anchor: warning / caution threshold band\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\n\n# ggplot2 does not expose per-element grid alpha, so blend INK toward PAGE_BG\n# to get a faint tint instead of passing the full-opacity ink color.\nmix_color <- function(c1, c2, amount) {\n  m <- col2rgb(c1) * (1 - amount) + col2rgb(c2) * amount\n  rgb(m[1, ], m[2, ], m[3, ], maxColorValue = 255)\n}\nGRID_COLOR <- mix_color(PAGE_BG, INK, 0.18)\n\n# --- Data --------------------------------------------------------------------\ndates <- seq(as.Date(\"2000-01-01\"), as.Date(\"2012-12-01\"), by = \"month\")\nn     <- length(dates)\n\nrecessions <- tibble::tibble(\n  start = as.Date(c(\"2001-03-01\", \"2007-12-01\")),\n  end   = as.Date(c(\"2001-11-01\", \"2009-06-01\")),\n  label = c(\"2001\", \"2008\")\n)\n\nrecession_flag <- rep(0, n)\nfor (i in seq_len(nrow(recessions))) {\n  recession_flag <- recession_flag +\n    as.numeric(dates >= recessions$start[i] & dates <= recessions$end[i])\n}\n\nmonthly_step <- ifelse(recession_flag > 0,\n                        rnorm(n, mean = -0.9, sd = 1.0),\n                        rnorm(n, mean = 0.5, sd = 1.0))\nmarket_index <- tibble::tibble(\n  date  = dates,\n  index = 100 + cumsum(monthly_step)\n)\n\n# Horizontal span: caution zone whenever the index falls below its starting\n# baseline of 100 (demonstrates the spec's \"horizontal\" direction alongside\n# the vertical recession spans above).\nbaseline_zone <- tibble::tibble(\n  xmin = min(dates),\n  xmax = max(dates),\n  ymin = floor(min(market_index$index)) - 1,\n  ymax = 100\n)\n\n# --- Title (scaled for length per anyplot title-fontsize rule) --------------\nplot_title <- \"Market Index · span-basic · r · ggplot2 · anyplot.ai\"\ntitle_size <- round(12 * min(1.0, 67 / nchar(plot_title)))\ntitle_size <- max(title_size, 8)\n\n# --- Plot ---------------------------------------------------------------------\np <- ggplot(market_index, aes(x = date, y = index)) +\n  geom_rect(\n    data        = baseline_zone,\n    aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),\n    inherit.aes = FALSE,\n    fill        = AMBER,\n    alpha       = 0.2\n  ) +\n  geom_rect(\n    data        = recessions,\n    aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf),\n    inherit.aes = FALSE,\n    fill        = NEUTRAL,\n    alpha       = 0.25\n  ) +\n  geom_text(\n    data        = recessions,\n    aes(x = start + (end - start) / 2, y = Inf, label = label),\n    inherit.aes = FALSE,\n    vjust       = 1.6,\n    size        = 2.6,\n    color       = INK_SOFT\n  ) +\n  annotate(\n    \"text\",\n    x     = dates[round(n * 0.97)],\n    y     = (baseline_zone$ymin + baseline_zone$ymax) / 2,\n    label = \"Below baseline\",\n    hjust = 1,\n    size  = 2.6,\n    color = INK_SOFT\n  ) +\n  geom_line(color = IMPRINT_PALETTE[1], linewidth = 1.0) +\n  scale_x_date(date_breaks = \"2 years\", date_labels = \"%Y\") +\n  labs(\n    title = plot_title,\n    x     = \"Year\",\n    y     = \"Market Index Value\"\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.major.y = element_line(color = GRID_COLOR, linewidth = 0.3),\n    panel.grid.minor  = element_blank(),\n    panel.border      = element_blank(),\n    axis.line         = element_line(color = INK_SOFT),\n    axis.ticks        = element_blank(),\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  )\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"}