Mandelbrot Set Fractal Visualization — Apache ECharts

A visualization of the Mandelbrot set, the most iconic fractal in mathematics. Each pixel represents a complex number c on the complex plane, colored by how quickly the iteration z(n+1) = z(n)^2 + c diverges. The boundary between convergent and divergent regions reveals infinitely complex, self-similar structure including the characteristic cardioid and period-2 bulb.

Mandelbrot Set Fractal Visualization rendered with Apache ECharts

Renders

JavaScript source (Apache ECharts)

// anyplot.ai
// heatmap-mandelbrot: Mandelbrot Set Fractal Visualization
// Library: echarts 6.1.0 | JavaScript 22.23.2
// Quality: 82/100 | Created: 2026-08-25

//# anyplot-orientation: landscape
const t = window.ANYPLOT_TOKENS;
const size = window.ANYPLOT_SIZE || { width: 1600, height: 900 };

// --- Complex-plane window & escape parameters -------------------------------
const X_MIN = -2.5;
const X_MAX = 1.0;
const Y_MIN = -1.25;
const Y_MAX = 1.25;
const MAX_ITER = 100;
const DATA_ASPECT = (X_MAX - X_MIN) / (Y_MAX - Y_MIN);

// --- Raster resolution (>= spec's 800x600 minimum, matches the plane's aspect) --
const GRID_H = 800;
const GRID_W = Math.round(GRID_H * DATA_ASPECT);

// --- Colors: Imprint sequential gradient for escaped points, a fixed solid --
// --- color for the bounded interior (a data color, so it must stay identical
// --- across themes rather than following the theme-adaptive ink token) ------
function hexToRgb(hex) {
  const n = parseInt(hex.slice(1), 16);
  return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
}
const seqStart = hexToRgb(t.seq[0]);
const seqEnd = hexToRgb(t.seq[1]);
const insideRgb = hexToRgb("#1A1A17");

// z(n+1) = z(n)^2 + c, smooth-colored via the normalized (fractional) escape
// count so bands don't appear at integer iteration boundaries.
function escapeColor(cx, cy) {
  let zx = 0;
  let zy = 0;
  let n = 0;
  while (zx * zx + zy * zy <= 4 && n < MAX_ITER) {
    const zxNext = zx * zx - zy * zy + cx;
    zy = 2 * zx * zy + cy;
    zx = zxNext;
    n++;
  }
  if (n === MAX_ITER) return insideRgb;
  const logZn = Math.log(zx * zx + zy * zy) / 2;
  const smoothN = n + 1 - Math.log(logZn / Math.LN2) / Math.LN2;
  // Gentle gamma so mid-range iteration counts don't crowd the dark end.
  const frac = Math.pow(Math.max(0, Math.min(1, smoothN / MAX_ITER)), 0.42);
  return [
    Math.round(seqStart[0] + (seqEnd[0] - seqStart[0]) * frac),
    Math.round(seqStart[1] + (seqEnd[1] - seqStart[1]) * frac),
    Math.round(seqStart[2] + (seqEnd[2] - seqStart[2]) * frac),
  ];
}

// --- Render the raster once into an offscreen canvas -------------------------
const raster = document.createElement("canvas");
raster.width = GRID_W;
raster.height = GRID_H;
const rasterCtx = raster.getContext("2d");
const imageData = rasterCtx.createImageData(GRID_W, GRID_H);
for (let row = 0; row < GRID_H; row++) {
  const cy = Y_MAX - (row / (GRID_H - 1)) * (Y_MAX - Y_MIN);
  for (let col = 0; col < GRID_W; col++) {
    const cx = X_MIN + (col / (GRID_W - 1)) * (X_MAX - X_MIN);
    const [r, g, b] = escapeColor(cx, cy);
    const idx = (row * GRID_W + col) * 4;
    imageData.data[idx] = r;
    imageData.data[idx + 1] = g;
    imageData.data[idx + 2] = b;
    imageData.data[idx + 3] = 255;
  }
}
rasterCtx.putImageData(imageData, 0, 0);
const fractalImage = raster.toDataURL("image/png");

// --- Fit the plane's true aspect ratio inside the mount (letterboxed) --------
const MARGIN = { top: 130, bottom: 100, left: 120, right: 50 };
const availW = size.width - MARGIN.left - MARGIN.right;
const availH = size.height - MARGIN.top - MARGIN.bottom;
let plotW = availW;
let plotH = plotW / DATA_ASPECT;
if (plotH > availH) {
  plotH = availH;
  plotW = plotH * DATA_ASPECT;
}
const padW = (availW - plotW) / 2;
const padH = (availH - plotH) / 2;
const gridLeft = MARGIN.left + padW;
const gridRight = MARGIN.right + padW;
const gridTop = MARGIN.top + padH;
const gridBottom = MARGIN.bottom + padH;

// --- Init ---------------------------------------------------------------------
const chart = echarts.init(document.getElementById("container"));

// --- Option ---------------------------------------------------------------------
chart.setOption({
  animation: false,
  backgroundColor: "transparent",
  title: {
    text: "heatmap-mandelbrot · javascript · echarts · anyplot.ai",
    subtext: "Color: smooth escape-iteration count · Solid fill: bounded orbit (never escapes)",
    left: "center",
    top: 18,
    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },
    subtextStyle: { color: t.inkSoft, fontSize: 14 },
  },
  grid: { left: gridLeft, right: gridRight, top: gridTop, bottom: gridBottom },
  xAxis: {
    type: "value",
    min: X_MIN,
    max: X_MAX,
    name: "Real axis (Re)",
    nameLocation: "middle",
    nameGap: 36,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    axisLabel: { color: t.inkSoft, fontSize: 14, formatter: (v) => v.toFixed(2) },
    axisLine: { onZero: false, lineStyle: { color: t.inkSoft } },
    axisTick: { onZero: false, lineStyle: { color: t.inkSoft } },
    splitLine: { show: false },
  },
  yAxis: {
    type: "value",
    min: Y_MIN,
    max: Y_MAX,
    name: "Imaginary axis (Im)",
    nameLocation: "middle",
    nameGap: 46,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    axisLabel: { color: t.inkSoft, fontSize: 14, formatter: (v) => v.toFixed(2) },
    axisLine: { onZero: false, lineStyle: { color: t.inkSoft } },
    axisTick: { onZero: false, lineStyle: { color: t.inkSoft } },
    splitLine: { show: false },
  },
  series: [
    {
      type: "custom",
      coordinateSystem: "cartesian2d",
      data: [[X_MIN, Y_MIN, 0]],
      renderItem: (_params, api) => {
        const corner1 = api.coord([X_MIN, Y_MIN]);
        const corner2 = api.coord([X_MAX, Y_MAX]);
        return {
          type: "image",
          style: {
            image: fractalImage,
            x: Math.min(corner1[0], corner2[0]),
            y: Math.min(corner1[1], corner2[1]),
            width: Math.abs(corner2[0] - corner1[0]),
            height: Math.abs(corner1[1] - corner2[1]),
          },
        };
      },
    },
  ],
});
chart.on("finished", () => {
  window.__anyplotReady = true;
});

Part of Mandelbrot Set Fractal Visualization on anyplot.ai.

Other implementations