{"spec_id":"contour-3d","library":"d3","language":"javascript","code":"// anyplot.ai\n// contour-3d: 3D Contour Plot\n// Library: d3 7.9.0 | JavaScript 22.23.2\n// Quality: 92/100 | Created: 2026-09-10\n\nconst t = window.ANYPLOT_TOKENS;\nconst { width, height } = window.ANYPLOT_SIZE;\nconst margin = { top: 130, right: 260, bottom: 90, left: 100 };\nconst iw = width - margin.left - margin.right;\nconst ih = height - margin.top - margin.bottom;\n\n// --- Data: optimization-landscape potential field (two Gaussian extrema) ---\n// z(x,y) is a signed \"objective value\" surface with one maximum and one\n// minimum — the classic critical-point landscape from the spec's\n// optimization-landscape application.\nconst GRID_N = 42;\nconst AXIS_RANGE = 5;\nconst Z_EXAGGERATION = 1.3;\n\nconst xs = d3.range(GRID_N).map((i) => -AXIS_RANGE + (2 * AXIS_RANGE * i) / (GRID_N - 1));\nconst ys = d3.range(GRID_N).map((i) => -AXIS_RANGE + (2 * AXIS_RANGE * i) / (GRID_N - 1));\n\nconst gaussian = (x, y, cx, cy, sigma) => Math.exp(-((x - cx) ** 2 + (y - cy) ** 2) / (2 * sigma * sigma));\nconst objective = (x, y) => 3.2 * gaussian(x, y, -2, -1.5, 1.8) - 2.6 * gaussian(x, y, 2, 1.8, 2.0);\n\nconst zGrid = ys.map((y) => xs.map((x) => objective(x, y)));\nconst zFlat = zGrid.flat();\nconst zRawMin = d3.min(zFlat);\nconst zRawMax = d3.max(zFlat);\nconst zAbsMax = Math.max(Math.abs(zRawMin), Math.abs(zRawMax));\n\n// The two critical points of the landscape (found directly on the grid) —\n// labeled on the surface to sharpen the data story beyond color alone.\nlet maxI = 0,\n  maxJ = 0,\n  maxVal = -Infinity;\nlet minI = 0,\n  minJ = 0,\n  minVal = Infinity;\nfor (let j = 0; j < GRID_N; j++) {\n  for (let i = 0; i < GRID_N; i++) {\n    const v = zGrid[j][i];\n    if (v > maxVal) {\n      maxVal = v;\n      maxI = i;\n      maxJ = j;\n    }\n    if (v < minVal) {\n      minVal = v;\n      minI = i;\n      minJ = j;\n    }\n  }\n}\nconst extrema = [\n  { x: xs[maxI], y: ys[maxJ], z: maxVal, label: \"Maximum\" },\n  { x: xs[minI], y: ys[minJ], z: minVal, label: \"Minimum\" },\n];\n\n// --- Contour bands + isolines via marching squares on the raw grid ---------\nconst N_BANDS = 9;\nconst levels = d3.range(1, N_BANDS).map((k) => -zAbsMax + (k * 2 * zAbsMax) / N_BANDS);\nconst boundaries = [-zAbsMax, ...levels, zAbsMax];\nconst divScale = d3.scaleSequential(d3.interpolateRgbBasis(t.div)).domain([-zAbsMax, zAbsMax]);\nconst bandColors = d3.range(N_BANDS).map((k) => divScale((boundaries[k] + boundaries[k + 1]) / 2));\n\nconst contourGen = d3.contours().size([GRID_N, GRID_N]).thresholds(levels);\nconst bands = contourGen(zFlat); // ascending features; bands[k].value === levels[k]\n\nconst gridToX = (i) => xs[0] + (i / (GRID_N - 1)) * (xs[GRID_N - 1] - xs[0]);\nconst gridToY = (j) => ys[0] + (j / (GRID_N - 1)) * (ys[GRID_N - 1] - ys[0]);\n\n// --- Camera: elevation/azimuth orthographic projection (drag-to-orbit) -----\nconst INITIAL_ELEVATION = 30;\nconst INITIAL_AZIMUTH = -55;\n\nconst cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];\nconst normalize = (v) => {\n  const len = Math.hypot(v[0], v[1], v[2]);\n  return [v[0] / len, v[1] / len, v[2] / len];\n};\nconst dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n\n// --- Surface geometry: true grid height, banded fill by contour level -------\nconst zMinScaled = zRawMin * Z_EXAGGERATION;\nconst zMaxScaled = zRawMax * Z_EXAGGERATION;\nconst floorZ = zMinScaled - 0.35 * (zMaxScaled - zMinScaled);\nconst zToHeight = (v) => floorZ + ((v - zRawMin) / (zRawMax - zRawMin)) * (zMaxScaled - floorZ);\n\n// --- Floor corners (data-space, camera-independent) -------------------------\nconst xMin = xs[0];\nconst xMax = xs[GRID_N - 1];\nconst yMin = ys[0];\nconst yMax = ys[GRID_N - 1];\nconst floorCorners = [\n  [xMin, yMin, floorZ],\n  [xMax, yMin, floorZ],\n  [xMax, yMax, floorZ],\n  [xMin, yMax, floorZ],\n];\n\nconst TICK_LEN = 0.7;\nconst LABEL_LEN = 2.5;\nconst Z_TICK_LEN = TICK_LEN * 0.72;\nconst Z_LABEL_LEN = LABEL_LEN * 0.72;\nconst CORNER_GUARD = 0.15;\n\n// --- SVG mount ----------------------------------------------------------------\nconst svg = d3.select(\"#container\").append(\"svg\").attr(\"width\", width).attr(\"height\", height);\nconst sceneGroup = svg.append(\"g\"); // rebuilt on every camera change (drag-to-orbit)\n\n// Recomputes the camera basis, re-projects every surface/floor/axis element,\n// and redraws the scene — invoked once on load and again on every pointer\n// drag so the spec's \"enable rotation for interactive libraries\" note is a\n// genuine interaction, not a fixed static render.\nfunction render(elevation, azimuth) {\n  const elRad = (elevation * Math.PI) / 180;\n  const azRad = (azimuth * Math.PI) / 180;\n  const camDir = [Math.cos(elRad) * Math.cos(azRad), Math.cos(elRad) * Math.sin(azRad), Math.sin(elRad)];\n  const worldUp = [0, 0, 1];\n  const right = normalize(cross(worldUp, camDir));\n  const up = normalize(cross(camDir, right));\n  const project = (x, y, z) => [dot([x, y, z], right), dot([x, y, z], up)];\n  const depthOf = (x, y, z) => dot([x, y, z], camDir);\n\n  const surfacePoints = ys.map((yy, j) =>\n    xs.map((xx, i) => {\n      const zd = zGrid[j][i] * Z_EXAGGERATION;\n      const [vx, vy] = project(xx, yy, zd);\n      return { vx, vy, depth: depthOf(xx, yy, zd), zRaw: zGrid[j][i] };\n    })\n  );\n\n  const quads = [];\n  for (let j = 0; j < GRID_N - 1; j++) {\n    for (let i = 0; i < GRID_N - 1; i++) {\n      const p00 = surfacePoints[j][i];\n      const p10 = surfacePoints[j][i + 1];\n      const p11 = surfacePoints[j + 1][i + 1];\n      const p01 = surfacePoints[j + 1][i];\n      const avgZ = (p00.zRaw + p10.zRaw + p11.zRaw + p01.zRaw) / 4;\n      const avgDepth = (p00.depth + p10.depth + p11.depth + p01.depth) / 4;\n      quads.push({\n        pts: [\n          [p00.vx, p00.vy],\n          [p10.vx, p10.vy],\n          [p11.vx, p11.vy],\n          [p01.vx, p01.vy],\n        ],\n        // Continuous shading on the true surface geometry — the discrete\n        // banding lives on the floor projection below, so the two never\n        // fight each other at the grid's finite resolution.\n        color: divScale(avgZ),\n        depth: avgDepth,\n      });\n    }\n  }\n  quads.sort((a, b) => a.depth - b.depth); // far to near — later draws sit on top\n\n  // Isolines draped directly on the surface at each level's true height —\n  // the precise level curves the spec calls for, distinct from the base map below.\n  const surfaceIsolines = [];\n  for (const feature of bands) {\n    const levelZ = feature.value * Z_EXAGGERATION;\n    for (const polygon of feature.coordinates) {\n      for (const ring of polygon) {\n        const pts = ring.map(([gi, gj]) => project(gridToX(gi), gridToY(gj), levelZ));\n        const depth = d3.mean(ring, ([gi, gj]) => depthOf(gridToX(gi), gridToY(gj), levelZ));\n        surfaceIsolines.push({ pts, depth });\n      }\n    }\n  }\n  surfaceIsolines.sort((a, b) => a.depth - b.depth);\n\n  // Floor: the same contour bands flattened onto the base plane, a classic\n  // topographic reference map beneath the 3D surface (per spec notes).\n  const floorLayers = [{ rings: [floorCorners.map((p) => project(...p))], color: bandColors[0] }];\n  bands.forEach((feature, idx) => {\n    const color = bandColors[idx + 1];\n    for (const polygon of feature.coordinates) {\n      const rings = polygon.map((ring) => ring.map(([gi, gj]) => project(gridToX(gi), gridToY(gj), floorZ)));\n      floorLayers.push({ rings, color });\n    }\n  });\n\n  const extremaPts = extrema.map((e) => {\n    const zd = e.z * Z_EXAGGERATION;\n    const [vx, vy] = project(e.x, e.y, zd);\n    return { ...e, vx, vy };\n  });\n\n  // --- Axis frame (floor corner behind the mesh, relative to the camera) ---\n  let anchorX = xMin;\n  let anchorY = yMin;\n  let bestVx = Infinity;\n  for (const cx of [xMin, xMax]) {\n    for (const cy of [yMin, yMax]) {\n      const [vx] = project(cx, cy, floorZ);\n      if (vx < bestVx) {\n        bestVx = vx;\n        anchorX = cx;\n        anchorY = cy;\n      }\n    }\n  }\n  const xAxisOtherEnd = anchorX === xMin ? xMax : xMin;\n  const yAxisOtherEnd = anchorY === yMin ? yMax : yMin;\n  const outwardXSign = anchorX > xAxisOtherEnd ? 1 : -1;\n  const outwardYSign = anchorY > yAxisOtherEnd ? 1 : -1;\n\n  const axisLines = [\n    [\n      [anchorX, anchorY, floorZ],\n      [xAxisOtherEnd, anchorY, floorZ],\n    ],\n    [\n      [anchorX, anchorY, floorZ],\n      [anchorX, yAxisOtherEnd, floorZ],\n    ],\n    [\n      [anchorX, anchorY, floorZ],\n      [anchorX, anchorY, zMaxScaled],\n    ],\n  ];\n\n  const xTicks = d3\n    .ticks(xMin, xMax, 4)\n    .filter((v) => Math.abs(v - anchorX) > CORNER_GUARD * (xMax - xMin))\n    .map((v) => ({\n      a: [v, anchorY, floorZ],\n      b: [v, anchorY + outwardYSign * TICK_LEN, floorZ],\n      label: [v, anchorY + outwardYSign * LABEL_LEN, floorZ],\n      text: d3.format(\".0f\")(v),\n    }));\n  const yTicks = d3\n    .ticks(yMin, yMax, 4)\n    .filter((v) => Math.abs(v - anchorY) > CORNER_GUARD * (yMax - yMin))\n    .map((v) => ({\n      a: [anchorX, v, floorZ],\n      b: [anchorX + outwardXSign * TICK_LEN, v, floorZ],\n      label: [anchorX + outwardXSign * LABEL_LEN, v, floorZ],\n      text: d3.format(\".0f\")(v),\n    }));\n  const zTicks = d3.ticks(zRawMin, zRawMax, 4).map((v) => ({\n    a: [anchorX, anchorY, zToHeight(v)],\n    b: [anchorX + outwardXSign * Z_TICK_LEN, anchorY + outwardYSign * Z_TICK_LEN, zToHeight(v)],\n    label: [anchorX + outwardXSign * Z_LABEL_LEN, anchorY + outwardYSign * Z_LABEL_LEN, zToHeight(v)],\n    text: d3.format(\".1f\")(v),\n  }));\n  const allTicks = [...xTicks, ...yTicks, ...zTicks];\n\n  const axisLabels = [\n    { pos: [xAxisOtherEnd, anchorY + outwardYSign * 2.5, floorZ], text: \"Parameter X\" },\n    { pos: [anchorX + outwardXSign * 2.5, yAxisOtherEnd, floorZ], text: \"Parameter Y\" },\n    { pos: [anchorX + outwardXSign * 2.5, anchorY, zMaxScaled], text: \"Objective Value\" },\n  ];\n\n  // --- Fit view-space extent (surface + floor + axis frame) into the mount -\n  const extentSource = [\n    ...quads.flatMap((q) => q.pts),\n    ...floorLayers.flatMap((f) => f.rings.flat()),\n    ...axisLines.flatMap(([a, b]) => [project(...a), project(...b)]),\n    ...allTicks.flatMap((tk) => [project(...tk.a), project(...tk.label)]),\n    ...axisLabels.map((l) => project(...l.pos)),\n    ...extremaPts.map((e) => [e.vx, e.vy]),\n  ];\n  const extMinX = d3.min(extentSource, (d) => d[0]);\n  const extMaxX = d3.max(extentSource, (d) => d[0]);\n  const extMinY = d3.min(extentSource, (d) => d[1]);\n  const extMaxY = d3.max(extentSource, (d) => d[1]);\n  const midX = (extMinX + extMaxX) / 2;\n  const midY = (extMinY + extMaxY) / 2;\n  const fitScale = 0.92 * Math.min(iw / (extMaxX - extMinX), ih / (extMaxY - extMinY));\n  const toScreen = ([vx, vy]) => [\n    margin.left + iw / 2 + (vx - midX) * fitScale,\n    margin.top + ih / 2 - (vy - midY) * fitScale,\n  ];\n  const ringPath = (ring) =>\n    ring\n      .map(toScreen)\n      .map((p, k) => `${k === 0 ? \"M\" : \"L\"}${p[0].toFixed(2)},${p[1].toFixed(2)}`)\n      .join(\" \") + \" Z\";\n  const polygonPath = (rings) => rings.map(ringPath).join(\" \");\n\n  // --- Redraw the camera-dependent scene -------------------------------------\n  sceneGroup.selectAll(\"*\").remove();\n\n  sceneGroup\n    .append(\"g\")\n    .attr(\"fill-rule\", \"evenodd\")\n    .attr(\"stroke\", \"none\")\n    .selectAll(\"path\")\n    .data(floorLayers)\n    .join(\"path\")\n    .attr(\"d\", (d) => polygonPath(d.rings))\n    .attr(\"fill\", (d) => d.color)\n    .attr(\"fill-opacity\", 0.55);\n\n  sceneGroup\n    .append(\"path\")\n    .attr(\"d\", ringPath(floorCorners.map((p) => project(...p))))\n    .attr(\"fill\", \"none\")\n    .attr(\"stroke\", t.inkSoft)\n    .attr(\"stroke-width\", 1.2)\n    .attr(\"stroke-opacity\", 0.6);\n\n  const surfaceGroup = sceneGroup.append(\"g\").attr(\"stroke-width\", 0.6);\n  surfaceGroup\n    .selectAll(\"path\")\n    .data(quads)\n    .join(\"path\")\n    .attr(\"d\", (d) => ringPath(d.pts))\n    .attr(\"fill\", (d) => d.color)\n    .attr(\"stroke\", (d) => d.color);\n\n  sceneGroup\n    .append(\"g\")\n    .attr(\"fill\", \"none\")\n    .attr(\"stroke\", t.pageBg)\n    .attr(\"stroke-width\", 1.6)\n    .attr(\"stroke-opacity\", 0.85)\n    .selectAll(\"path\")\n    .data(surfaceIsolines)\n    .join(\"path\")\n    .attr(\"d\", (d) => ringPath(d.pts));\n\n  // Direct \"Maximum\"/\"Minimum\" markers at the two critical points sharpen the\n  // focal point beyond color/contour encoding alone.\n  const extremaGroup = sceneGroup.append(\"g\");\n  extremaGroup\n    .selectAll(\"circle\")\n    .data(extremaPts)\n    .join(\"circle\")\n    .attr(\"cx\", (d) => toScreen([d.vx, d.vy])[0])\n    .attr(\"cy\", (d) => toScreen([d.vx, d.vy])[1])\n    .attr(\"r\", 4)\n    .attr(\"fill\", t.pageBg)\n    .attr(\"stroke\", t.ink)\n    .attr(\"stroke-width\", 1.4);\n  extremaGroup\n    .selectAll(\"text\")\n    .data(extremaPts)\n    .join(\"text\")\n    .attr(\"x\", (d) => toScreen([d.vx, d.vy])[0])\n    .attr(\"y\", (d) => toScreen([d.vx, d.vy])[1] - 12)\n    .attr(\"text-anchor\", \"middle\")\n    .attr(\"fill\", t.ink)\n    .attr(\"stroke\", t.pageBg)\n    .attr(\"stroke-width\", 3)\n    .attr(\"paint-order\", \"stroke\")\n    .style(\"font-size\", \"13px\")\n    .style(\"font-weight\", \"600\")\n    .text((d) => d.label);\n\n  const axisGroup = sceneGroup.append(\"g\").attr(\"stroke\", t.inkSoft).attr(\"stroke-width\", 2);\n  axisGroup\n    .selectAll(\"line\")\n    .data(axisLines)\n    .join(\"line\")\n    .attr(\"x1\", (d) => toScreen(project(...d[0]))[0])\n    .attr(\"y1\", (d) => toScreen(project(...d[0]))[1])\n    .attr(\"x2\", (d) => toScreen(project(...d[1]))[0])\n    .attr(\"y2\", (d) => toScreen(project(...d[1]))[1]);\n\n  sceneGroup\n    .append(\"g\")\n    .attr(\"stroke\", t.inkSoft)\n    .attr(\"stroke-width\", 1.4)\n    .selectAll(\"line\")\n    .data(allTicks)\n    .join(\"line\")\n    .attr(\"x1\", (d) => toScreen(project(...d.a))[0])\n    .attr(\"y1\", (d) => toScreen(project(...d.a))[1])\n    .attr(\"x2\", (d) => toScreen(project(...d.b))[0])\n    .attr(\"y2\", (d) => toScreen(project(...d.b))[1]);\n\n  sceneGroup\n    .append(\"g\")\n    .attr(\"fill\", t.inkSoft)\n    .style(\"font-size\", \"13px\")\n    .selectAll(\"text\")\n    .data(allTicks)\n    .join(\"text\")\n    .attr(\"x\", (d) => toScreen(project(...d.label))[0])\n    .attr(\"y\", (d) => toScreen(project(...d.label))[1])\n    .attr(\"text-anchor\", \"middle\")\n    .attr(\"dominant-baseline\", \"middle\")\n    .text((d) => d.text);\n\n  sceneGroup\n    .append(\"g\")\n    .attr(\"fill\", t.ink)\n    .style(\"font-size\", \"18px\")\n    .style(\"font-weight\", \"600\")\n    .selectAll(\"text\")\n    .data(axisLabels)\n    .join(\"text\")\n    .attr(\"x\", (d) => toScreen(project(...d.pos))[0])\n    .attr(\"y\", (d) => toScreen(project(...d.pos))[1])\n    .attr(\"text-anchor\", \"middle\")\n    .attr(\"dominant-baseline\", \"middle\")\n    .text((d) => d.text);\n}\n\n// --- Interaction: drag-to-orbit (spec asks for rotation on interactive libs) -\nlet elevation = INITIAL_ELEVATION;\nlet azimuth = INITIAL_AZIMUTH;\nrender(elevation, azimuth);\n\nconst ORBIT_SENSITIVITY = 0.35;\nconst ELEVATION_LIMIT = 85;\nsvg.style(\"cursor\", \"grab\").call(\n  d3\n    .drag()\n    .on(\"start\", () => svg.style(\"cursor\", \"grabbing\"))\n    .on(\"drag\", (event) => {\n      azimuth += event.dx * ORBIT_SENSITIVITY;\n      elevation = Math.max(-ELEVATION_LIMIT, Math.min(ELEVATION_LIMIT, elevation - event.dy * ORBIT_SENSITIVITY));\n      render(elevation, azimuth);\n    })\n    .on(\"end\", () => svg.style(\"cursor\", \"grab\"))\n);\n\n// --- Colorbar: discrete contour-band legend for the value scale -------------\nconst cbWidth = 26;\nconst cbX = width - margin.right + 90;\nconst cbTop = margin.top + 30;\nconst cbBottom = height - margin.bottom - 30;\nconst cbScale = d3.scaleLinear().domain([-zAbsMax, zAbsMax]).range([cbBottom, cbTop]);\nconst colorbarSegments = d3.range(N_BANDS).map((k) => ({\n  y0: cbScale(boundaries[k]),\n  y1: cbScale(boundaries[k + 1]),\n  color: bandColors[k],\n}));\n\nconst cbGroup = svg.append(\"g\");\ncbGroup\n  .selectAll(\"rect\")\n  .data(colorbarSegments)\n  .join(\"rect\")\n  .attr(\"x\", cbX)\n  .attr(\"y\", (d) => Math.min(d.y0, d.y1))\n  .attr(\"width\", cbWidth)\n  .attr(\"height\", (d) => Math.abs(d.y1 - d.y0))\n  .attr(\"fill\", (d) => d.color);\n\ncbGroup\n  .append(\"rect\")\n  .attr(\"x\", cbX)\n  .attr(\"y\", cbTop)\n  .attr(\"width\", cbWidth)\n  .attr(\"height\", cbBottom - cbTop)\n  .attr(\"fill\", \"none\")\n  .attr(\"stroke\", t.inkSoft)\n  .attr(\"stroke-width\", 1.2);\n\nconst cbTicks = d3.ticks(-zAbsMax, zAbsMax, 6);\ncbGroup\n  .selectAll(\"line.cb-tick\")\n  .data(cbTicks)\n  .join(\"line\")\n  .attr(\"class\", \"cb-tick\")\n  .attr(\"x1\", cbX + cbWidth)\n  .attr(\"x2\", cbX + cbWidth + 8)\n  .attr(\"y1\", (d) => cbScale(d))\n  .attr(\"y2\", (d) => cbScale(d))\n  .attr(\"stroke\", t.inkSoft)\n  .attr(\"stroke-width\", 1.2);\n\ncbGroup\n  .selectAll(\"text.cb-label\")\n  .data(cbTicks)\n  .join(\"text\")\n  .attr(\"class\", \"cb-label\")\n  .attr(\"x\", cbX + cbWidth + 14)\n  .attr(\"y\", (d) => cbScale(d))\n  .attr(\"dominant-baseline\", \"middle\")\n  .attr(\"fill\", t.inkSoft)\n  .style(\"font-size\", \"13px\")\n  .text((d) => d3.format(\".1f\")(d));\n\ncbGroup\n  .append(\"text\")\n  .attr(\"x\", cbX + cbWidth / 2)\n  .attr(\"y\", cbTop - 18)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"15px\")\n  .style(\"font-weight\", \"600\")\n  .text(\"Objective Value\");\n\n// --- Title ----------------------------------------------------------------\nconst TITLE = \"Optimization Landscape · contour-3d · javascript · d3 · anyplot.ai\";\nconst TITLE_BASE_FONT = 22;\nconst TITLE_FLOOR_FONT = 15;\nconst titleFontSize = Math.max(TITLE_FLOOR_FONT, Math.round(TITLE_BASE_FONT * Math.min(1, 67 / TITLE.length)));\n\nsvg\n  .append(\"text\")\n  .attr(\"x\", width / 2)\n  .attr(\"y\", 56)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", `${titleFontSize}px`)\n  .style(\"font-weight\", \"600\")\n  .text(TITLE);\n"}