{"spec_id":"contour-3d","library":"muix","language":"javascript","code":"// anyplot.ai\n// contour-3d: 3D Contour Plot\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 82/100 | Created: 2026-09-10\n\n// Community @mui/x-charts has no 3D/surface primitive. The elevation surface\n// is built as a genuinely data-driven ScatterChart: every grid point is a\n// real scatter datum (x, y, z) wired through a `zAxis` piecewise colorMap,\n// and a custom `slots.scatter` renderer (same pattern used by\n// heatmap-correlation) reads the library's own xScale/yScale/colorGetter to\n// draw the elevation bands, contour isolines, and a sparse sample-point\n// overlay whose marker colors come straight from that colorGetter -- not a\n// second hand-rolled palette. The spec's \"project contours onto the base\n// plane\" note is honored with a dashed, offset duplicate of the isolines\n// painted on top of the bands (clipped to the axes, no edge bleed) -- a\n// legible reference layer, not a near-duplicate of the solid ones.\n\nimport { ScatterChart } from \"@mui/x-charts/ScatterChart\";\nimport { PiecewiseColorLegend } from \"@mui/x-charts/ChartsLegend\";\nimport { ChartsText } from \"@mui/x-charts/ChartsText\";\n\nconst t = window.ANYPLOT_TOKENS;\nconst SIZE = window.ANYPLOT_SIZE;\n\n// --- Grid: deterministic chemical-process yield response surface -----------\nconst GRID_N = 34;\nconst TEMP_MIN = 150, TEMP_MAX = 250;\nconst PRESSURE_MIN = 10, PRESSURE_MAX = 50;\n\nconst temps = Array.from(\n  { length: GRID_N },\n  (_, i) => TEMP_MIN + (i / (GRID_N - 1)) * (TEMP_MAX - TEMP_MIN),\n);\nconst pressures = Array.from(\n  { length: GRID_N },\n  (_, j) => PRESSURE_MIN + (j / (GRID_N - 1)) * (PRESSURE_MAX - PRESSURE_MIN),\n);\n\n// Second-order response-surface model (classic RSM form: intercept + linear +\n// quadratic + interaction terms) with a mild ripple so contour bands aren't\n// perfectly elliptical -- gives the surface a visible saddle/critical-point\n// region, matching the spec's \"optimization landscape with critical points\".\nfunction yieldAt(temp, pressure) {\n  const u = (temp - 200) / 50;\n  const v = (pressure - 30) / 20;\n  return 90 - 15 * u * u - 20 * v * v + 8 * u * v + 3 * Math.sin(3 * u) * Math.cos(2 * v);\n}\n\n// zGrid[j][i] = yield at (temps[i], pressures[j])\nconst zGrid = pressures.map((p) => temps.map((temp) => yieldAt(temp, p)));\nconst allZ = zGrid.flat();\nconst zMin = Math.min(...allZ);\nconst zMax = Math.max(...allZ);\n\n// Locate the global optimum -- a real, computed \"critical point\" (spec:\n// \"optimization landscapes with critical points\") to annotate on the surface.\nlet optimum = { i: 0, j: 0, z: -Infinity };\nfor (let j = 0; j < GRID_N; j += 1) {\n  for (let i = 0; i < GRID_N; i += 1) {\n    if (zGrid[j][i] > optimum.z) optimum = { i, j, z: zGrid[j][i] };\n  }\n}\n\n// --- Real @mui/x-charts scatter series: every grid point is genuine data ---\n// (feeds the ScatterChart's own zAxis colorMap / colorGetter pipeline below,\n// not just a styling prop -- the library resolves per-point color from this.)\nconst points = [];\nfor (let j = 0; j < GRID_N; j += 1) {\n  for (let i = 0; i < GRID_N; i += 1) {\n    points.push({ id: `${i}-${j}`, x: temps[i], y: pressures[j], z: zGrid[j][i] });\n  }\n}\n\n// --- Imprint sequential colormap (single-polarity data: t.seq = [green, blue]) -\nfunction hexToRgb(hex) {\n  const n = parseInt(hex.slice(1), 16);\n  return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\nfunction lerpChannel(a, b, ratio) {\n  return Math.round(a + (b - a) * ratio);\n}\nfunction imprintSeqInterpolator(stops) {\n  const [lo, hi] = stops.map(hexToRgb);\n  return (position) => {\n    const [r, g, b] = [0, 1, 2].map((c) => lerpChannel(lo[c], hi[c], position));\n    return `rgb(${r}, ${g}, ${b})`;\n  };\n}\nconst seqColor = imprintSeqInterpolator(t.seq);\n\nconst NUM_BANDS = 8;\nconst bandThresholds = Array.from(\n  { length: NUM_BANDS - 1 },\n  (_, k) => zMin + ((k + 1) / NUM_BANDS) * (zMax - zMin),\n);\nconst bandColors = Array.from({ length: NUM_BANDS }, (_, k) => seqColor(k / (NUM_BANDS - 1)));\n\n// --- Marching-triangles filled-contour geometry ------------------------------\n// Each grid cell is split into 4 triangles around its centroid so every\n// super-level-set boundary resolves without the marching-squares saddle\n// ambiguity; painting bands low-to-high (painter's algorithm) then produces\n// correct filled bands regardless of how many disjoint regions a level has.\nfunction buildTriangles() {\n  const tris = [];\n  for (let j = 0; j < GRID_N - 1; j += 1) {\n    for (let i = 0; i < GRID_N - 1; i += 1) {\n      const sw = { x: temps[i], y: pressures[j], z: zGrid[j][i] };\n      const se = { x: temps[i + 1], y: pressures[j], z: zGrid[j][i + 1] };\n      const ne = { x: temps[i + 1], y: pressures[j + 1], z: zGrid[j + 1][i + 1] };\n      const nw = { x: temps[i], y: pressures[j + 1], z: zGrid[j + 1][i] };\n      const center = {\n        x: (sw.x + se.x) / 2,\n        y: (sw.y + nw.y) / 2,\n        z: (sw.z + se.z + ne.z + nw.z) / 4,\n      };\n      tris.push([sw, se, center], [se, ne, center], [ne, nw, center], [nw, sw, center]);\n    }\n  }\n  return tris;\n}\nconst triangles = buildTriangles();\n\n// Filled sub-polygon(s) of one triangle lying at/above `threshold`, plus the\n// interpolated edge (if any) that traces the exact level curve through it.\nfunction triangleFill(a, b, c, threshold) {\n  const inA = a.z >= threshold, inB = b.z >= threshold, inC = c.z >= threshold;\n  const nIn = (inA ? 1 : 0) + (inB ? 1 : 0) + (inC ? 1 : 0);\n  const cross = (p, q) => {\n    const ratio = (threshold - p.z) / (q.z - p.z);\n    return { x: p.x + ratio * (q.x - p.x), y: p.y + ratio * (q.y - p.y) };\n  };\n\n  if (nIn === 0) return { polys: [], cut: null };\n  if (nIn === 3) return { polys: [[a, b, c]], cut: null };\n\n  if (nIn === 1) {\n    if (inA) { const ab = cross(a, b), ca = cross(c, a); return { polys: [[a, ab, ca]], cut: [ab, ca] }; }\n    if (inB) { const ab = cross(a, b), bc = cross(b, c); return { polys: [[b, bc, ab]], cut: [bc, ab] }; }\n    const ca = cross(c, a), bc = cross(b, c);\n    return { polys: [[c, ca, bc]], cut: [ca, bc] };\n  }\n\n  // nIn === 2 (exactly one vertex out)\n  if (!inC) { const bc = cross(b, c), ca = cross(c, a); return { polys: [[a, b, bc, ca]], cut: [ca, bc] }; }\n  if (!inA) { const ca = cross(c, a), ab = cross(a, b); return { polys: [[b, c, ca, ab]], cut: [ab, ca] }; }\n  const ab = cross(a, b), bc = cross(b, c);\n  return { polys: [[c, a, ab, bc]], cut: [bc, ab] };\n}\n\n// Bands k=1..NUM_BANDS-1 are computed from the triangulation; band k=0 is the\n// full domain rect (everything is above zMin), painted first as the base layer.\nconst bandGeometry = [];\nconst isolineGeometry = [];\nfor (let k = 1; k < NUM_BANDS; k += 1) {\n  const threshold = bandThresholds[k - 1];\n  const polys = [];\n  const segments = [];\n  for (const tri of triangles) {\n    const { polys: p, cut } = triangleFill(tri[0], tri[1], tri[2], threshold);\n    if (p.length) polys.push(...p);\n    if (cut) segments.push(cut);\n  }\n  bandGeometry.push(polys);\n  isolineGeometry.push(segments);\n}\n\n// Sparse sample-point overlay (every 4th grid line -> ~9x9 points): a real\n// subset of `points` above, drawn through the library's own `colorGetter` so\n// the markers' colors come from the ScatterChart's zAxis colorMap, not a\n// second hand-rolled color computation.\nconst SAMPLE_STEP = 4;\nconst sampleIndices = [];\nfor (let j = 0; j < GRID_N; j += SAMPLE_STEP) {\n  for (let i = 0; i < GRID_N; i += SAMPLE_STEP) {\n    sampleIndices.push(j * GRID_N + i);\n  }\n}\n\n// --- Custom `slots.scatter` renderer: bands + isolines + sample points, all -\n// mapped through the ScatterChart's own xScale/yScale, colored through its\n// own colorGetter -- this IS the library's scatter slot, not a bolt-on layer.\nconst SHADOW_OFFSET = 30;\n\nfunction ContourSurfaceRenderer(props) {\n  const { series, xScale, yScale, colorGetter } = props;\n  const toSVG = (x, y) => [xScale(x), yScale(y)];\n\n  const polysToPath = (polys, dx = 0, dy = 0) =>\n    polys\n      .map((poly) => {\n        const pts = poly.map((p) => toSVG(p.x, p.y));\n        const head = `M ${(pts[0][0] + dx).toFixed(1)},${(pts[0][1] + dy).toFixed(1)}`;\n        const tail = pts\n          .slice(1)\n          .map(([px, py]) => `L ${(px + dx).toFixed(1)},${(py + dy).toFixed(1)}`)\n          .join(\" \");\n        return `${head} ${tail} Z`;\n      })\n      .join(\" \");\n\n  const segmentsToPath = (segments, dx = 0, dy = 0) =>\n    segments\n      .map(([p0, p1]) => {\n        const [x0, y0] = toSVG(p0.x, p0.y);\n        const [x1, y1] = toSVG(p1.x, p1.y);\n        return `M ${(x0 + dx).toFixed(1)},${(y0 + dy).toFixed(1)} L ${(x1 + dx).toFixed(1)},${(y1 + dy).toFixed(1)}`;\n      })\n      .join(\" \");\n\n  const [rx0, ry0] = toSVG(TEMP_MIN, PRESSURE_MIN);\n  const [rx1, ry1] = toSVG(TEMP_MAX, PRESSURE_MAX);\n  const baseRectPath = (dx = 0, dy = 0) =>\n    `M ${(rx0 + dx).toFixed(1)},${(ry0 + dy).toFixed(1)} L ${(rx1 + dx).toFixed(1)},${(ry0 + dy).toFixed(1)} L ${(rx1 + dx).toFixed(1)},${(ry1 + dy).toFixed(1)} L ${(rx0 + dx).toFixed(1)},${(ry1 + dy).toFixed(1)} Z`;\n\n  const [ox, oy] = toSVG(temps[optimum.i], pressures[optimum.j]);\n\n  // Clip the offset shadow layer to the plot's own rectangle so the\n  // down-right offset never bleeds into the margin past the axes.\n  const clipX = Math.min(rx0, rx1);\n  const clipY = Math.min(ry0, ry1);\n  const clipW = Math.abs(rx1 - rx0);\n  const clipH = Math.abs(ry1 - ry0);\n\n  return (\n    <g>\n      <clipPath id=\"contour-3d-plot-clip\">\n        <rect x={clipX} y={clipY} width={clipW} height={clipH} />\n      </clipPath>\n\n      {/* On-surface elevation bands, viewed from directly above */}\n      <path d={baseRectPath()} fill={bandColors[0]} stroke={bandColors[0]} strokeWidth={0.75} />\n      {bandGeometry.map((polys, idx) => (\n        <path\n          key={`band-${idx}`}\n          d={polysToPath(polys)}\n          fill={bandColors[idx + 1]}\n          stroke={bandColors[idx + 1]}\n          strokeWidth={0.75}\n        />\n      ))}\n\n      {/* Contours projected onto the base plane: the fully opaque bands above\n          tile the whole domain, so a filled shadow would never show through --\n          instead this offset+dashed duplicate of the isolines is painted on\n          TOP of the bands (still clipped to the axes, no edge bleed), reading\n          as a clearly separate reference layer rather than a near-duplicate. */}\n      <g clipPath=\"url(#contour-3d-plot-clip)\" opacity={0.75}>\n        {isolineGeometry.map((segments, idx) => (\n          <path\n            key={`shadow-iso-${idx}`}\n            d={segmentsToPath(segments, SHADOW_OFFSET, SHADOW_OFFSET)}\n            stroke={t.inkSoft}\n            strokeWidth={1.6}\n            strokeDasharray=\"9 6\"\n            fill=\"none\"\n          />\n        ))}\n      </g>\n\n      {/* Sparse sample points -- real scatter data, colored via the chart's\n          own colorGetter (zAxis piecewise colorMap), not a second palette. */}\n      {sampleIndices.map((idx) => {\n        const p = series.data[idx];\n        const [px, py] = toSVG(p.x, p.y);\n        return (\n          <circle\n            key={`sample-${p.id}`}\n            cx={px}\n            cy={py}\n            r={4}\n            fill={colorGetter ? colorGetter(idx) : t.ink}\n            stroke={t.pageBg}\n            strokeWidth={1.5}\n          />\n        );\n      })}\n\n      {/* Solid contour lines on the surface itself */}\n      {isolineGeometry.map((segments, idx) => (\n        <path\n          key={`iso-${idx}`}\n          d={segmentsToPath(segments)}\n          stroke={t.ink}\n          strokeOpacity={0.6}\n          strokeWidth={1.5}\n          fill=\"none\"\n        />\n      ))}\n\n      {/* Critical point: the computed global optimum, a genuine data callout */}\n      <circle cx={ox} cy={oy} r={6} fill=\"none\" stroke={t.ink} strokeWidth={2} />\n      <circle cx={ox} cy={oy} r={2} fill={t.ink} />\n      <text\n        x={ox}\n        y={oy - 12}\n        textAnchor=\"middle\"\n        fontSize={13}\n        fontWeight={600}\n        fill={t.ink}\n        fontFamily=\"inherit\"\n      >\n        {`Optimum ${optimum.z.toFixed(1)}%`}\n      </text>\n    </g>\n  );\n}\n\n// --- Chart (default-exported component — the harness mounts it) -------------\nconst TITLE = \"contour-3d · javascript · muix · anyplot.ai\";\nconst MARGIN = { top: 120, right: 190, bottom: 90, left: 105 };\n\n// PiecewiseColorLegend anchors flush against the literal SVG width, ignoring\n// MARGIN.right entirely (its `position: \"right\"` offset is `svgWidth -\n// legendWidth`) -- so the whole right-side cluster (legend + its rotated axis\n// title) is wrapped in this leftward shift to keep swatches off the true edge.\nconst RIGHT_EDGE_INSET = 46;\n\nfunction bandLabel({ min, max }) {\n  if (min === null) return `< ${Math.round(max)}`;\n  if (max === null) return `> ${Math.round(min)}`;\n  return `${Math.round(min)}–${Math.round(max)}`;\n}\n\nexport default function Chart() {\n  return (\n    <ScatterChart\n      width={SIZE.width}\n      height={SIZE.height}\n      margin={MARGIN}\n      skipAnimation\n      disableVoronoi\n      series={[\n        {\n          id: \"yield-surface\",\n          type: \"scatter\",\n          data: points,\n          label: \"Yield (%)\",\n          zAxisId: \"yield\",\n        },\n      ]}\n      xAxis={[\n        {\n          scaleType: \"linear\",\n          min: TEMP_MIN,\n          max: TEMP_MAX,\n          label: \"Temperature (°C)\",\n          labelStyle: { fontSize: 15, fill: t.ink },\n          tickLabelStyle: { fontSize: 14, fill: t.inkSoft },\n        },\n      ]}\n      yAxis={[\n        {\n          scaleType: \"linear\",\n          min: PRESSURE_MIN,\n          max: PRESSURE_MAX,\n          label: \"Pressure (bar)\",\n          labelStyle: { fontSize: 15, fill: t.ink },\n          tickLabelStyle: { fontSize: 14, fill: t.inkSoft },\n          slotProps: { axisLabel: { x: -58 } },\n        },\n      ]}\n      zAxis={[\n        {\n          id: \"yield\",\n          colorMap: {\n            type: \"piecewise\",\n            thresholds: bandThresholds,\n            colors: bandColors,\n          },\n        },\n      ]}\n      slots={{ scatter: ContourSurfaceRenderer }}\n      slotProps={{ legend: { hidden: true } }}\n    >\n      <g transform={`translate(${-RIGHT_EDGE_INSET}, 0)`}>\n        <PiecewiseColorLegend\n          axisId=\"yield\"\n          position={{ horizontal: \"right\", vertical: \"middle\" }}\n          direction=\"column\"\n          labelStyle={{ fontSize: 13, fill: t.inkSoft }}\n          labelFormatter={bandLabel}\n        />\n        <ChartsText\n          text=\"Yield (%)\"\n          x={SIZE.width - 40}\n          y={MARGIN.top - 24}\n          style={{ fontSize: 14, fontWeight: 500, fill: t.ink, textAnchor: \"middle\" }}\n        />\n      </g>\n      <ChartsText\n        text={TITLE}\n        x={SIZE.width / 2}\n        y={50}\n        style={{ fontSize: 22, fontWeight: 500, fill: t.ink, textAnchor: \"middle\" }}\n      />\n    </ScatterChart>\n  );\n}\n"}