{"spec_id":"line-cycle-seasonal","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' line-cycle-seasonal: Cycle Plot (Seasonal Subseries)\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 88/100 | Created: 2026-06-15\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\"\nINK_MUTED   <- if (THEME == \"light\") \"#6B6A63\" else \"#A8A79F\"\nRULE_COLOR  <- if (THEME == \"light\") \"#1A1A1726\" else \"#F0EFE826\"\n\nIMPRINT_PALETTE <- c(\n  \"#009E73\",  # 1 brand green — first series\n  \"#C475FD\",  # 2 lavender\n  \"#4467A3\",  # 3 blue\n  \"#BD8233\",  # 4 ochre\n  \"#AE3030\",  # 5 matte red\n  \"#2ABCCD\",  # 6 cyan\n  \"#954477\",  # 7 rose\n  \"#99B314\"   # 8 lime\n)\n\n# Data: synthetic monthly average temperature (degC) 2000-2024\n# Scenario: temperate Northern Hemisphere city showing annual cycle + warming trend\nn_years      <- 25\nstart_year   <- 2000\nyears        <- start_year:(start_year + n_years - 1)\nmonth_nums   <- 1:12\nmonth_labels <- c(\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n                  \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\")\n\n# Seasonal baseline (degC per month)\nseasonal_base <- c(-1.8, 0.6, 5.4, 11.2, 16.5, 20.8, 23.1, 22.4, 17.3, 10.9, 4.5, -0.5)\n\n# Build observations: expand.grid cycles year fastest within each month\nraw_df <- expand.grid(year = years, month = month_nums)\nnoise  <- rnorm(nrow(raw_df), 0, 0.85)\n\ndf <- raw_df |>\n  mutate(\n    year_idx = year - start_year,                              # 0 to 24\n    temp     = seasonal_base[month] + year_idx * 0.05 + noise,\n    # Horizontal position: month integer + year offset in [-0.36, +0.36]\n    x_pos    = month + (year_idx / (n_years - 1) - 0.5) * 0.72\n  )\n\n# Seasonal group means for horizontal reference bars\ngroup_means <- df |>\n  group_by(month) |>\n  summarise(mean_temp = mean(temp), .groups = \"drop\")\n\nHALF_W <- 0.36  # half-width of each mean segment (matches x_pos spread)\n\n# Scale title font size proportionally when title > 67 chars\nplot_title <- paste0(\n  \"Monthly Temperature Trends · line-cycle-seasonal · \",\n  \"r · ggplot2 · anyplot.ai\"\n)\ntitle_size <- max(8L, round(12L * 67L / nchar(plot_title)))\n\np <- ggplot() +\n  # Subtle vertical dividers between month groups\n  geom_vline(\n    xintercept = seq(1.5, 11.5, by = 1),\n    color      = INK_MUTED,\n    linewidth  = 0.25,\n    alpha      = 0.45\n  ) +\n  # Within-month chronological trend lines (Imprint green — first series)\n  geom_line(\n    data      = df,\n    aes(x = x_pos, y = temp, group = month, color = \"Within-month trend\"),\n    linewidth = 1.05\n  ) +\n  # Seasonal mean reference segments (Imprint blue — third series)\n  geom_segment(\n    data = group_means,\n    aes(\n      x    = month - HALF_W,\n      xend = month + HALF_W,\n      y    = mean_temp,\n      yend = mean_temp,\n      color = \"Seasonal mean\"\n    ),\n    linewidth = 1.6\n  ) +\n  # Annotate warming trend on July (month 7) — warmest month, most visible slope\n  annotate(\n    \"text\",\n    x     = 7,\n    y     = max(df$temp[df$month == 7]) + 0.9,\n    label = \"+1.25 °C over 25 yrs\",\n    color = INK_SOFT,\n    size  = 2.5,\n    hjust = 0.5\n  ) +\n  annotate(\n    \"segment\",\n    x     = 6.63,\n    xend  = 7.37,\n    y     = max(df$temp[df$month == 7]) + 0.55,\n    yend  = max(df$temp[df$month == 7]) + 0.55,\n    color = INK_MUTED,\n    linewidth = 0.3\n  ) +\n  scale_x_continuous(\n    breaks = month_nums,\n    labels = month_labels,\n    expand = expansion(add = 0.55)\n  ) +\n  scale_color_manual(\n    values = c(\n      \"Within-month trend\" = IMPRINT_PALETTE[1],  # #009E73 brand green\n      \"Seasonal mean\"      = IMPRINT_PALETTE[3]   # #4467A3 blue\n    ),\n    name = NULL\n  ) +\n  labs(\n    x        = NULL,\n    y        = \"Avg. temperature (°C)\",\n    title    = plot_title,\n    subtitle = paste0(\n      \"2000–2024  |  Each line traces one month’s values across 25 years; \",\n      \"horizontal bar = that month’s mean\"\n    ),\n    caption  = \"Synthetic data — warming trend ≈0.05 °C / yr\"\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.border       = element_blank(),\n    panel.grid.major.x = element_blank(),\n    panel.grid.minor   = element_blank(),\n    panel.grid.major.y = element_line(color = RULE_COLOR, linewidth = 0.4),\n    axis.line.x        = element_line(color = INK_SOFT, linewidth = 0.35),\n    axis.ticks         = element_blank(),\n    axis.title.y       = element_text(color = INK,      size = 10),\n    axis.text.x        = element_text(color = INK_SOFT, size = 9),\n    axis.text.y        = element_text(color = INK_SOFT, size = 8),\n    plot.title         = element_text(color = INK,      size = title_size, face = \"bold\"),\n    plot.subtitle      = element_text(color = INK_SOFT, size = 8, margin = margin(b = 6)),\n    plot.caption       = element_text(color = INK_MUTED, size = 7, hjust = 0),\n    legend.background  = element_rect(fill = ELEVATED_BG, color = NA),\n    legend.text        = element_text(color = INK_SOFT, size = 8),\n    legend.position    = \"top\",\n    legend.justification = \"right\",\n    legend.key.width   = unit(20, \"pt\"),\n    plot.margin        = margin(16, 20, 12, 16, \"pt\")\n  )\n\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"}