{"spec_id":"line-annotated-events","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' line-annotated-events: Annotated Line Plot with Event Markers\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-09-05\n\nlibrary(ggplot2)\nlibrary(dplyr)\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\"\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\nBRAND <- IMPRINT_PALETTE[1]\n\n# --- Data ---------------------------------------------------------------------\ntrading_days <- seq(as.Date(\"2024-01-02\"), as.Date(\"2024-12-20\"), by = \"day\")\ntrading_days <- trading_days[!weekdays(trading_days) %in% c(\"Saturday\", \"Sunday\")]\n\ndaily_returns <- rnorm(length(trading_days), mean = 0.0006, sd = 0.016)\nclose_price   <- 148 * cumprod(1 + daily_returns)\n\nstock_df <- tibble::tibble(date = trading_days, value = close_price)\n\nevents_df <- tibble::tibble(\n  event_date  = as.Date(c(\"2024-02-01\", \"2024-04-25\", \"2024-07-24\",\n                          \"2024-09-10\", \"2024-10-30\")),\n  event_label = c(\"Q4'23 Earnings Beat\", \"Q1 Earnings Miss\", \"Q2 Earnings Beat\",\n                  \"New Product Launch\", \"Q3 Earnings Beat\"),\n  label_step  = c(1, 2, 1, 2, 1)\n)\n\nprice_range   <- range(stock_df$value)\nspan          <- diff(price_range)\nlabel_row_gap <- span * 0.09\nlabel_base_y  <- price_range[2] + span * 0.04\nevents_df <- events_df |>\n  mutate(\n    label_y = label_base_y + (label_step - 1) * label_row_gap,\n    dot_y   = approx(stock_df$date, stock_df$value, event_date)$y,\n    leader_y = label_y - span * 0.02\n  )\n\n# --- Plot -----------------------------------------------------------------\ntitle_text <- \"line-annotated-events · r · ggplot2 · anyplot.ai\"\n\np <- ggplot() +\n  geom_vline(\n    data = events_df, aes(xintercept = as.numeric(event_date)),\n    color = INK, linewidth = 0.4, linetype = \"dashed\", alpha = 0.5\n  ) +\n  geom_line(\n    data = stock_df, aes(x = date, y = value),\n    color = BRAND, linewidth = 1.0\n  ) +\n  geom_segment(\n    data = events_df,\n    aes(x = event_date, xend = event_date, y = dot_y, yend = leader_y),\n    color = IMPRINT_PALETTE[5], linewidth = 0.5, alpha = 0.55\n  ) +\n  geom_point(\n    data = events_df,\n    aes(x = event_date, y = dot_y),\n    color = IMPRINT_PALETTE[5], size = 2.8\n  ) +\n  geom_label(\n    data = events_df,\n    aes(x = event_date, y = label_y, label = event_label),\n    color = INK_SOFT, fill = ELEVATED_BG, size = 3.0,\n    hjust = 0.5, vjust = 0, lineheight = 0.9,\n    label.size = 0.2, label.padding = unit(0.18, \"lines\"),\n    label.r = unit(0.08, \"lines\")\n  ) +\n  scale_y_continuous(\n    labels = scales::dollar_format(),\n    expand = expansion(mult = c(0.06, 0.20))\n  ) +\n  scale_x_date(date_labels = \"%b\", date_breaks = \"2 months\") +\n  labs(\n    title = title_text,\n    x = \"Trading Date (2024)\",\n    y = \"Closing Price\"\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 = INK, linewidth = 0.3),\n    panel.grid.minor  = element_blank(),\n    panel.grid.major.x = element_blank(),\n    axis.title        = element_text(color = INK, size = 10),\n    axis.text         = element_text(color = INK_SOFT, size = 8),\n    axis.line         = element_line(color = INK_SOFT),\n    axis.ticks        = element_blank(),\n    plot.title        = element_text(color = INK, size = 12),\n    plot.margin       = margin(t = 10, r = 16, 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"}