{"spec_id":"scatter-color-mapped","library":"muix","language":"javascript","code":"// anyplot.ai\n// scatter-color-mapped: Color-Mapped Scatter Plot\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 87/100 | Created: 2026-09-05\nimport { ScatterChart } from \"@mui/x-charts/ScatterChart\";\nimport { ContinuousColorLegend } from \"@mui/x-charts/ChartsLegend\";\nimport { ChartsText } from \"@mui/x-charts/ChartsText\";\n\nconst t = window.ANYPLOT_TOKENS;\nconst { width, height } = window.ANYPLOT_SIZE;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Ocean buoy network: sea-surface temperature sampled across a survey grid.\n// A warm-core current near (0°E, 40°N) fades outward, so temperature (color)\n// traces a spatial pattern rather than pure noise.\nlet seed = 42;\nconst nextRandom = () => {\n  seed = (Math.imul(seed, 1103515245) + 12345) & 0x7fffffff;\n  return seed / 0x7fffffff;\n};\n\nconst STATION_COUNT = 160;\nconst buoys = [];\nfor (let i = 0; i < STATION_COUNT; i += 1) {\n  const longitude = -14 + nextRandom() * 26;\n  const latitude = 30 + nextRandom() * 22;\n  const distanceFromCore = Math.hypot(longitude - 0, latitude - 40);\n  const temperature = 23 - 0.42 * distanceFromCore + (nextRandom() - 0.5) * 2.4;\n  buoys.push({\n    id: i,\n    x: Number(longitude.toFixed(2)),\n    y: Number(latitude.toFixed(2)),\n    z: Number(temperature.toFixed(2)),\n  });\n}\n\nconst temperatures = buoys.map((buoy) => buoy.z);\nconst tempMin = Math.min(...temperatures);\nconst tempMax = Math.max(...temperatures);\n\n// Overlapping buoys (dense clusters near the warm core) stay distinguishable\n// with moderate transparency baked into the colormap stops themselves, since\n// the scatter series has no direct opacity prop.\nconst withAlpha = (hex: string, alpha: number) => {\n  const n = parseInt(hex.slice(1), 16);\n  const r = (n >> 16) & 255;\n  const g = (n >> 8) & 255;\n  const b = n & 255;\n  return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\nconst MARKER_ALPHA = 0.85;\n\n// --- Title (fontsize scales with title length, see plot-generator.md) -------\nconst TITLE = \"scatter-color-mapped · javascript · muix · anyplot.ai\";\nconst TITLE_FONTSIZE = Math.round(22 * (TITLE.length > 67 ? 67 / TITLE.length : 1));\n\n// --- Chart (default-exported component — the harness mounts it) ------------\nexport default function Chart() {\n  return (\n    <ScatterChart\n      width={width}\n      height={height}\n      skipAnimation\n      legend={{ hidden: true }}\n      grid={{ horizontal: true }}\n      margin={{ top: 90, right: 190, bottom: 110, left: 110 }}\n      xAxis={[\n        {\n          id: \"longitude\",\n          label: \"Longitude (°E)\",\n          labelStyle: { fontSize: 18 },\n          tickLabelStyle: { fontSize: 14 },\n          valueFormatter: (value: number) => `${value}°`,\n        },\n      ]}\n      yAxis={[\n        {\n          id: \"latitude\",\n          label: \"Latitude (°N)\",\n          labelStyle: { fontSize: 18 },\n          tickLabelStyle: { fontSize: 14 },\n          valueFormatter: (value: number) => `${value}°`,\n        },\n      ]}\n      zAxis={[\n        {\n          id: \"temperature\",\n          min: tempMin,\n          max: tempMax,\n          colorMap: {\n            type: \"continuous\",\n            min: tempMin,\n            max: tempMax,\n            color: [withAlpha(t.seq[0], MARKER_ALPHA), withAlpha(t.seq[1], MARKER_ALPHA)],\n          },\n        },\n      ]}\n      series={[\n        {\n          id: \"buoys\",\n          label: \"Ocean buoys\",\n          data: buoys,\n          markerSize: 17,\n          color: t.palette[0],\n        },\n      ]}\n    >\n      <ChartsText\n        text={TITLE}\n        x={width / 2}\n        y={40}\n        style={{\n          fontSize: TITLE_FONTSIZE,\n          fontWeight: 600,\n          fill: t.ink,\n          textAnchor: \"middle\",\n          dominantBaseline: \"hanging\",\n        }}\n      />\n      <ChartsText\n        text=\"Sea-surface temp (°C)\"\n        x={width - 95}\n        y={64}\n        style={{\n          fontSize: 14,\n          fill: t.inkSoft,\n          textAnchor: \"middle\",\n          dominantBaseline: \"hanging\",\n        }}\n      />\n      <ContinuousColorLegend\n        axisDirection=\"z\"\n        direction=\"column\"\n        position={{ horizontal: \"right\", vertical: \"middle\" }}\n        length=\"62%\"\n        thickness={22}\n        spacing={10}\n        align=\"middle\"\n        minLabel={({ value }) => `${Number(value).toFixed(1)}°C`}\n        maxLabel={({ value }) => `${Number(value).toFixed(1)}°C`}\n        labelStyle={{ fontSize: 16, fill: t.inkSoft }}\n      />\n    </ScatterChart>\n  );\n}\n"}