{"spec_id":"heatmap-mandelbrot","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' heatmap-mandelbrot: Mandelbrot Set Fractal Visualization\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 85/100 | Created: 2026-05-30\n\nlibrary(ggplot2)\nlibrary(ragg)\n\n# Theme tokens (Imprint palette)\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 sequential colormap for continuous escape iterations\nSEQ_LOW  <- \"#009E73\"  # Imprint position 1 — brand green (boundary region)\nSEQ_HIGH <- \"#4467A3\"  # Imprint position 3 — blue (far exterior)\n\n# Mandelbrot parameters\nMAX_ITER <- 200\nNX       <- 800\nNY       <- 572  # maintains 3.5 : 2.5 complex-plane aspect ratio\n\nx_seq <- seq(-2.5,  1.0,  length.out = NX)\ny_seq <- seq(-1.25, 1.25, length.out = NY)\n\n# Build flat grid vectors (all NX * NY coordinate pairs)\nreal_vec <- rep(x_seq, times = NY)\nimag_vec <- rep(y_seq, each  = NX)\n\n# Vectorized Mandelbrot iteration\n# Narrows the active-index set each loop so work shrinks as points escape.\nzr      <- numeric(NX * NY)\nzi      <- numeric(NX * NY)\nescape  <- rep(NA_real_, NX * NY)  # NA = inside the set\nlog_mag <- rep(NA_real_, NX * NY)  # log2(log2(|z|)) at escape — for smooth coloring\n\nfor (i in seq_len(MAX_ITER)) {\n    idx <- which(is.na(escape))\n    if (length(idx) == 0L) break\n\n    zr_new <- zr[idx]^2 - zi[idx]^2 + real_vec[idx]\n    zi_new <- 2.0 * zr[idx] * zi[idx] + imag_vec[idx]\n    zr[idx] <- zr_new\n    zi[idx] <- zi_new\n\n    mod_sq <- zr[idx]^2 + zi[idx]^2\n    hit    <- mod_sq > 4.0\n    if (any(hit)) {\n        hit_idx         <- idx[hit]\n        escape[hit_idx] <- as.numeric(i)\n        # Smooth coloring: log2(0.5 * log2(|z|^2)) = log2(log2(|z|))\n        # Stable when mod_sq > 4 because 0.5 * log2(mod_sq) > 1 always holds.\n        log_mag[hit_idx] <- log2(0.5 * log2(mod_sq[hit]))\n    }\n}\n\n# Smooth escape count — eliminates integer banding at iteration boundaries\n# escape + 1 - log2(log2(|z|)) : fractional part interpolates between iterations\nescape_smooth <- escape + 1.0 - log_mag  # NA (interior) passes through as NA\nescape_vis    <- sqrt(pmax(escape_smooth, 0.0))  # sqrt spreads boundary detail\n\ndf <- data.frame(\n    real = real_vec,\n    imag = imag_vec,\n    esc  = escape_vis\n)\n\nTITLE <- \"heatmap-mandelbrot · r · ggplot2 · anyplot.ai\"\n\np <- ggplot(df, aes(x = real, y = imag, fill = esc)) +\n    geom_raster(interpolate = TRUE) +\n    scale_fill_gradient(\n        low      = SEQ_LOW,\n        high     = SEQ_HIGH,\n        na.value = \"#050503\",  # fixed dark interior independent of theme\n        name     = \"Escape\\ncount\\n(√)\",\n        guide    = guide_colorbar(\n            title.position = \"top\",\n            barwidth       = 0.7,\n            barheight      = 8\n        )\n    ) +\n    coord_fixed(ratio = 1) +\n    labs(\n        title = TITLE,\n        x     = \"Real axis\",\n        y     = \"Imaginary axis\"\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_blank(),\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        plot.title        = element_text(color = INK,        size = 12, face = \"bold\"),\n        legend.background = element_rect(fill = ELEVATED_BG, color = INK_SOFT,\n                                         linewidth = 0.3),\n        legend.text       = element_text(color = INK_SOFT,   size = 8),\n        legend.title      = element_text(color = INK,        size = 10),\n        plot.margin       = margin(12, 12, 12, 12)\n    )\n\n# Save — square canvas: width = 6, height = 6, dpi = 400 → 2400 × 2400 px\nggsave(\n    filename = sprintf(\"plot-%s.png\", THEME),\n    plot     = p,\n    device   = ragg::agg_png,\n    width    = 6,\n    height   = 6,\n    units    = \"in\",\n    dpi      = 400\n)\n"}