{"spec_id":"step-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' step-basic: Basic Step Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 83/100 | Created: 2026-07-25\n\nlibrary(ggplot2)\nlibrary(dplyr)\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\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nIMPRINT_PALETTE <- c(\n  \"#009E73\", # 1 -- first categorical series (brand green)\n  \"#C475FD\", # 2 -- lavender\n  \"#4467A3\", # 3 -- blue\n  \"#BD8233\", # 4 -- ochre\n  \"#AE3030\", # 5 -- matte red (semantic anchor for bad / loss / error)\n  \"#2ABCCD\", # 6 -- cyan\n  \"#954477\", # 7 -- rose\n  \"#99B314\"  # 8 -- lime\n)\n\n# --- Data ---------------------------------------------------------------\n# Central bank policy rate held constant between meetings, stepping up or\n# down whenever the committee votes to change it.\nmeeting_dates <- seq(as.Date(\"2023-01-01\"), as.Date(\"2024-12-01\"), by = \"month\")\npolicy_rate <- c(\n  4.50, 4.50, 4.75, 4.75, 5.00, 5.00, 5.25, 5.25, 5.25, 5.50, 5.50, 5.50,\n  5.50, 5.50, 5.50, 5.50, 5.50, 5.50, 5.25, 5.25, 5.00, 5.00, 4.75, 4.75\n)\ndf <- tibble::tibble(date = meeting_dates, rate = policy_rate)\n\n# Highlight only the meetings that actually changed the rate\nchanges <- df %>%\n  filter(row_number() == 1 | rate != lag(rate))\n\n# Mark the first meeting the cycle reached its peak rate, for a callout\npeak_rate <- max(df$rate)\npeak_date <- df$date[df$rate == peak_rate][1]\n\n# --- Plot -----------------------------------------------------------------\np <- ggplot(df, aes(x = date, y = rate)) +\n  geom_step(color = IMPRINT_PALETTE[1], linewidth = 1.2, direction = \"hv\") +\n  geom_point(data = changes, color = IMPRINT_PALETTE[1], size = 3.8) +\n  annotate(\n    \"text\",\n    x = peak_date, y = peak_rate + 0.18,\n    label = sprintf(\"Cycle peak: %.2f%%\", peak_rate),\n    color = INK_SOFT, size = 3, hjust = 0\n  ) +\n  scale_x_date(date_breaks = \"3 months\", date_labels = \"%b %Y\") +\n  scale_y_continuous(\n    labels = function(x) paste0(x, \"%\"),\n    expand = expansion(mult = c(0.05, 0.16))\n  ) +\n  labs(\n    x = \"Meeting Date\",\n    y = \"Policy Rate (%)\",\n    title = \"Central Bank Policy Rate · step-basic · r · ggplot2 · anyplot.ai\"\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.minor.x = element_blank(),\n    panel.grid.minor.y = element_blank(),\n    panel.grid.major.y = element_line(color = scales::alpha(INK, 0.15), linewidth = 0.6),\n    axis.line         = element_line(color = INK_SOFT, linewidth = 0.4),\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    axis.text.x       = element_text(angle = 30, hjust = 1),\n    plot.title        = element_text(color = INK, size = 12, face = \"plain\"),\n    plot.margin       = margin(t = 12, r = 20, b = 8, l = 8)\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"}