{"spec_id":"scatter-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// scatter-basic: Basic Scatter Plot\n// Library: echarts 5.5.1 | JavaScript 22.23.0\n// Quality: 88/100 | Updated: 2026-06-25\n\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic LCG) -----------------------------------\n// Health study: height (cm) vs weight (kg), 120 participants, r ≈ 0.7\nlet seed = 42;\nconst rng = () => { seed = (seed * 1664525 + 1013904223) >>> 0; return seed / 4294967296; };\nconst randn = () => {\n  const u = rng() + 1e-10;\n  const v = rng();\n  return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);\n};\n\nconst n = 120;\nconst heightMean = 170, heightStd = 10;\nconst weightMean = 70, weightStd = 12, r = 0.7;\nconst points = [];\nfor (let i = 0; i < n; i++) {\n  const h = heightMean + randn() * heightStd;\n  const noise = randn() * weightStd * Math.sqrt(1 - r * r);\n  const w = weightMean + r * (weightStd / heightStd) * (h - heightMean) + noise;\n  points.push([+h.toFixed(1), +w.toFixed(1)]);\n}\n\n// Trend line endpoints from population parameters (slope = r·σy/σx)\nconst slope = r * (weightStd / heightStd);\nconst intercept = weightMean - slope * heightMean;\n\n// --- Init -------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option -----------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"scatter-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 24,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: \"bold\" },\n  },\n  tooltip: {\n    trigger: \"item\",\n    formatter: (p) => `Height: ${p.value[0]} cm<br/>Weight: ${p.value[1]} kg`,\n    backgroundColor: t.elevatedBg,\n    borderColor: t.grid,\n    textStyle: { color: t.ink, fontSize: 14 },\n  },\n  // borderWidth: 0 removes the default 1px grid box — leaves only L-shaped axes\n  grid: { left: 110, right: 70, top: 90, bottom: 90, borderWidth: 0 },\n  xAxis: {\n    type: \"value\",\n    min: 140,\n    max: 205,\n    name: \"Height (cm)\",\n    nameLocation: \"middle\",\n    nameGap: 52,\n    nameTextStyle: { color: t.inkSoft, fontSize: 16, fontWeight: \"normal\" },\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { lineStyle: { color: t.inkSoft } },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  yAxis: {\n    type: \"value\",\n    min: 35,\n    max: 100,\n    name: \"Weight (kg)\",\n    nameLocation: \"middle\",\n    nameRotate: 90,\n    nameGap: 68,\n    nameTextStyle: { color: t.inkSoft, fontSize: 16, fontWeight: \"normal\" },\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { lineStyle: { color: t.inkSoft } },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  series: [\n    {\n      type: \"scatter\",\n      data: points,\n      symbolSize: 14,\n      itemStyle: {\n        color: t.palette[0],\n        opacity: 0.65,\n        borderColor: t.pageBg,\n        borderWidth: 1,\n      },\n      // emphasis + blur: focused points enlarge, unfocused dim — idiomatic ECharts\n      emphasis: {\n        scale: 1.4,\n        itemStyle: { opacity: 1, borderWidth: 2 },\n      },\n      blur: {\n        itemStyle: { opacity: 0.25 },\n      },\n      // markLine: ECharts-native annotation that overlays the regression line\n      markLine: {\n        silent: true,\n        symbol: \"none\",\n        lineStyle: { color: t.palette[0], opacity: 0.45, width: 2.5, type: \"dashed\" },\n        label: {\n          show: true,\n          formatter: \"r ≈ 0.7\",\n          position: \"insideEndTop\",\n          color: t.inkSoft,\n          fontSize: 13,\n        },\n        data: [\n          [\n            { coord: [140, +(intercept + slope * 140).toFixed(1)] },\n            { coord: [205, +(intercept + slope * 205).toFixed(1)] },\n          ],\n        ],\n      },\n    },\n  ],\n});\n"}