{"spec_id":"bump-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' bump-basic: Basic Bump Chart\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-05-29\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\"\n\n# Imprint palette (canonical order, hybrid-v3)\nIMPRINT_PALETTE <- c(\n  \"#009E73\",  # 1 brand green\n  \"#C475FD\",  # 2 lavender\n  \"#4467A3\",  # 3 blue\n  \"#BD8233\",  # 4 ochre\n  \"#AE3030\",  # 5 matte red\n  \"#2ABCCD\"   # 6 cyan\n)\n\n# Data: F1 Championship Standings — Rounds 1-8\ndrivers <- c(\"Hamilton\", \"Verstappen\", \"Leclerc\", \"Norris\", \"Russell\", \"Perez\")\n\nstandings <- data.frame(\n  race   = rep(1:8, each = 6),\n  driver = factor(rep(drivers, times = 8), levels = drivers),\n  rank   = c(\n    2, 1, 3, 5, 4, 6,\n    1, 2, 3, 5, 4, 6,\n    1, 2, 4, 3, 5, 6,\n    2, 1, 4, 3, 5, 6,\n    2, 1, 3, 4, 5, 6,\n    2, 1, 3, 4, 6, 5,\n    1, 2, 3, 4, 6, 5,\n    1, 2, 3, 5, 6, 4\n  )\n)\n\n# Visual storytelling: highlight the Hamilton/Verstappen championship battle\nTOP_DRIVERS  <- c(\"Hamilton\", \"Verstappen\")\ndriver_alpha <- setNames(ifelse(drivers %in% TOP_DRIVERS, 1.0, 0.5), drivers)\n\ndriver_colors      <- setNames(IMPRINT_PALETTE, drivers)\nlabels_end         <- standings[standings$race == 8, ]\nlabels_end$x_label <- 8.35\n\n# Softer grid via embedded alpha\nGRID_COLOR <- adjustcolor(INK, alpha.f = 0.15)\n\n# Plot\np <- ggplot(standings, aes(x = race, y = rank, color = driver, group = driver)) +\n  geom_line(aes(alpha = driver), linewidth = 1.4, lineend = \"round\", linejoin = \"round\") +\n  geom_point(aes(alpha = driver), size = 3.5) +\n  geom_text(\n    data     = labels_end,\n    aes(x = x_label, label = driver, alpha = driver),\n    hjust    = 0,\n    size     = 3.5,\n    fontface = \"bold\"\n  ) +\n  scale_y_reverse(\n    breaks = 1:6,\n    labels = c(\"1st\", \"2nd\", \"3rd\", \"4th\", \"5th\", \"6th\"),\n    expand = expansion(add = 0.4)\n  ) +\n  scale_x_continuous(\n    breaks = 1:8,\n    labels = paste0(\"R\", 1:8),\n    expand = expansion(mult = c(0.03, 0.20))\n  ) +\n  scale_color_manual(values = driver_colors) +\n  scale_alpha_manual(values = driver_alpha, guide = \"none\") +\n  labs(\n    title = \"bump-basic · r · ggplot2 · anyplot.ai\",\n    x     = \"Race Round\",\n    y     = \"Championship Position\"\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.y = element_line(color = GRID_COLOR, linewidth = 0.3),\n    panel.grid.major.x = element_blank(),\n    panel.grid.minor   = element_blank(),\n    axis.title         = element_text(color = INK, size = 10),\n    axis.text          = element_text(color = INK_SOFT, size = 8),\n    axis.line.x        = element_line(color = INK_SOFT, linewidth = 0.3),\n    plot.title         = element_text(color = INK, size = 12, face = \"bold\"),\n    legend.position    = \"none\",\n    plot.margin        = margin(t = 18, r = 48, b = 18, l = 12, unit = \"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"}