{"spec_id":"heatmap-mandelbrot","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nheatmap-mandelbrot: Mandelbrot Set Fractal Visualization\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 87/100 | Updated: 2026-05-30\n\"\"\"\n\nimport os\nimport sys\n\n\n# This script is named plotnine.py which would shadow the installed package.\n# Remove the script's directory from sys.path so the library is found instead.\nsys.path = [p for p in sys.path if os.path.abspath(p or \".\") != os.path.dirname(os.path.abspath(__file__))]\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    annotate,\n    coord_fixed,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_raster,\n    ggplot,\n    guide_colorbar,\n    guides,\n    labs,\n    scale_fill_gradientn,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\n\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINTERIOR_COLOR = \"#0D0D0A\"  # Mandelbrot interior — near-black regardless of theme\nANNOT_COLOR = \"#F0EFE8\"  # near-white; annotations always on dark Mandelbrot interior\n\n# Data — Mandelbrot set: z(n+1) = z(n)² + c\nx_min, x_max = -2.5, 1.0\ny_min, y_max = -1.25, 1.25\nmax_iter = 100\nnx, ny = 1200, 857\n\nreal = np.linspace(x_min, x_max, nx)\nimag = np.linspace(y_min, y_max, ny)\nreal_grid, imag_grid = np.meshgrid(real, imag)\nc = real_grid + 1j * imag_grid\n\n# Vectorized iteration with smooth escape-time coloring\nz = np.zeros_like(c)\nescape_time = np.full(c.shape, np.nan, dtype=float)\nactive = np.ones(c.shape, dtype=bool)\n\nfor i in range(max_iter):\n    z[active] = z[active] ** 2 + c[active]\n    escaped = active & (np.abs(z) > 2)\n    escape_time[escaped] = i + 1 - np.log2(np.log2(np.abs(z[escaped])))\n    active[escaped] = False\n\n# Interior points (never escape) remain NaN → na_value in scale renders them as INTERIOR_COLOR\nescape_time = np.clip(escape_time, 0, max_iter)\n\n# Log-transform escape time so the color gradient spreads across the boundary region.\n# Without this, most exterior pixels (escape ≈ 1–5) collapse into a uniform flat green.\nescape_log = np.where(np.isnan(escape_time), np.nan, np.log1p(escape_time) / np.log1p(max_iter) * max_iter)\n\n# 3 colorbar breaks evenly spaced in log space → labeled with original iteration counts.\n_log_positions = [0.0, 50.0, 100.0]\n_orig_iters = [round(np.expm1(v / max_iter * np.log1p(max_iter))) for v in _log_positions]\n_break_labels = [str(v) for v in _orig_iters]\n\n# Long-form DataFrame for plotnine grammar of graphics\ndf = pd.DataFrame({\"real\": real_grid.ravel(), \"imag\": imag_grid.ravel(), \"escape\": escape_log.ravel()})\n\ntitle = \"heatmap-mandelbrot · python · plotnine · anyplot.ai\"\n\n# Plot — layered grammar of graphics composition\nplot = (\n    ggplot(df, aes(x=\"real\", y=\"imag\", fill=\"escape\"))\n    + geom_raster(interpolate=True)\n    + scale_fill_gradientn(\n        colors=[\"#009E73\", \"#2ABCCD\", \"#4467A3\"],  # Imprint seq: green → cyan → blue\n        limits=(0, max_iter),\n        name=\"Escape\\nIterations\",\n        na_value=INTERIOR_COLOR,\n        breaks=_log_positions,\n        labels=_break_labels,\n    )\n    + guides(fill=guide_colorbar(nbin=300))\n    + coord_fixed(ratio=1.0)\n    + scale_x_continuous(expand=(0, 0))\n    + scale_y_continuous(expand=(0, 0))\n    + annotate(\"text\", x=-0.25, y=0, label=\"Cardioid\", color=ANNOT_COLOR, size=4, alpha=0.65, fontstyle=\"italic\")\n    + annotate(\n        \"text\",\n        x=-1.0,\n        y=0,\n        label=\"Period-2\\nBulb\",\n        color=ANNOT_COLOR,\n        size=4,\n        alpha=0.65,\n        fontstyle=\"italic\",\n        ha=\"center\",\n    )\n    + labs(x=\"Re(c)\", y=\"Im(c)\", title=title)\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_title=element_text(size=12, weight=\"bold\", ha=\"center\", color=INK),\n        axis_title_x=element_text(size=10, color=INK),\n        axis_title_y=element_text(size=10, color=INK),\n        axis_text=element_text(size=8, color=INK_SOFT),\n        axis_ticks=element_blank(),\n        legend_title=element_text(size=8, weight=\"bold\", color=INK),\n        legend_text=element_text(size=8, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_position=\"right\",\n        legend_key_height=60,\n        legend_key_width=12,\n        panel_grid_major=element_blank(),\n        panel_grid_minor=element_blank(),\n        panel_background=element_rect(fill=INTERIOR_COLOR),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        plot_margin=0.02,\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}