{"spec_id":"bifurcation-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' bifurcation-basic: Bifurcation Diagram for Dynamical Systems\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-06-17\n\nlibrary(ggplot2)\nlibrary(ragg)\n\nset.seed(42)\n\n# Theme tokens (Imprint palette — see prompts/default-style-guide.md)\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\"\nINK_MUTED   <- if (THEME == \"light\") \"#6B6A63\" else \"#A8A79F\"\nGRID        <- adjustcolor(INK, alpha.f = 0.15)\nCHAOS_BG    <- adjustcolor(INK_SOFT, alpha.f = 0.07)\n\nIMPRINT_PALETTE <- c(\n  \"#009E73\",  # 1 — brand green (always first series)\n  \"#C475FD\",  # 2 — lavender\n  \"#4467A3\",  # 3 — blue\n  \"#BD8233\",  # 4 — ochre\n  \"#AE3030\",  # 5 — matte red (semantic: bad/loss/error)\n  \"#2ABCCD\",  # 6 — cyan\n  \"#954477\",  # 7 — rose\n  \"#99B314\"   # 8 — lime\n)\n\n# Data: logistic map x(n+1) = r * x(n) * (1 - x(n))\nr_values  <- seq(2.5, 4.0, length.out = 1000)\nn_discard <- 200\nn_keep    <- 100\nn_r       <- length(r_values)\n\nr_vec <- numeric(n_r * n_keep)\nx_vec <- numeric(n_r * n_keep)\n\nfor (i in seq_along(r_values)) {\n  r <- r_values[i]\n  x <- 0.5\n  for (j in seq_len(n_discard)) {\n    x <- r * x * (1.0 - x)\n  }\n  for (j in seq_len(n_keep)) {\n    x <- r * x * (1.0 - x)\n    idx <- (i - 1L) * n_keep + j\n    r_vec[idx] <- r\n    x_vec[idx] <- x\n  }\n}\n\ndf <- data.frame(r = r_vec, x = x_vec)\n\n# Period-doubling bifurcation annotations\n# y staggered: 3.449 and 3.544 are only 0.095 apart in x, so elevate 3.449\nbif_r     <- c(3.0, 3.449, 3.544)\nbif_label <- c(\n  \"r ≈ 3.0\\nperiod-2\",\n  \"r ≈ 3.449\\nperiod-4\",\n  \"r ≈ 3.544\\nperiod-8\"\n)\nbif_y     <- c(0.06, 0.16, 0.06)   # stagger so crowded labels don't overlap\n\n# Title with length-aware font sizing (67-char baseline, default 12pt)\ntitle_str <- \"bifurcation-basic · r · ggplot2 · anyplot.ai\"\ntitle_n   <- nchar(title_str)\ntitle_fs  <- max(8L, round(12.0 * min(1.0, 67.0 / title_n)))\n\n# Plot: chaotic-regime rect placed first so it renders behind data\np <- ggplot(df, aes(x = r, y = x)) +\n  annotate(\n    \"rect\",\n    xmin = 3.57, xmax = 4.005,\n    ymin = 0,    ymax = 1,\n    fill  = CHAOS_BG,\n    color = NA\n  ) +\n  geom_point(\n    size  = 0.05,\n    alpha = 0.10,\n    color = IMPRINT_PALETTE[1],\n    shape = 16\n  ) +\n  geom_vline(\n    xintercept = bif_r,\n    color      = INK_SOFT,\n    linewidth  = 0.35,\n    linetype   = \"dashed\"\n  ) +\n  annotate(\n    \"text\",\n    x          = bif_r,\n    y          = bif_y,\n    label      = bif_label,\n    size       = 3.0,\n    color      = INK_MUTED,\n    hjust      = 0.5,\n    vjust      = 0,\n    lineheight = 0.9\n  ) +\n  annotate(\n    \"text\",\n    x        = 3.785,\n    y        = 0.96,\n    label    = \"Chaotic\\nregime\",\n    size     = 3.0,\n    color    = INK_MUTED,\n    hjust    = 0.5,\n    vjust    = 1,\n    fontface = \"italic\",\n    lineheight = 0.9\n  ) +\n  labs(\n    title = title_str,\n    x     = \"Growth Rate Parameter (r)\",\n    y     = \"Population (x)\"\n  ) +\n  scale_x_continuous(\n    breaks = seq(2.5, 4.0, by = 0.25),\n    expand = expansion(mult = 0.02)\n  ) +\n  scale_y_continuous(\n    limits = c(0, 1),\n    breaks = seq(0, 1, by = 0.2),\n    expand = expansion(mult = 0.02)\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 = element_line(color = GRID,     linewidth = 0.3),\n    panel.grid.minor = element_blank(),\n    panel.border     = element_blank(),\n    axis.title       = element_text(color = INK,      size = 10),\n    axis.text        = element_text(color = INK_SOFT, size = 8),\n    axis.ticks       = element_line(color = INK_SOFT, linewidth = 0.3),\n    axis.line        = element_line(color = INK_SOFT, linewidth = 0.4),\n    plot.title       = element_text(color = INK,      size = title_fs,\n                                    margin = margin(b = 10)),\n    plot.margin      = margin(12, 16, 12, 12)\n  )\n\n# Save (landscape: 3200x1800 via 8in x 4.5in at 400 dpi)\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"}