{"spec_id":"scatter-connected-temporal","library":"muix","language":"javascript","code":"// anyplot.ai\n// scatter-connected-temporal: Connected Scatter Plot with Temporal Path\n// Library: muix 7.29.1 | JavaScript 22.22.3\n// Quality: 90/100 | Updated: 2026-06-10\n\nimport { LineChart, useXScale, useYScale } from \"@mui/x-charts\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// US Phillips curve: unemployment rate (%) vs. inflation rate (%), 1970–2009\nconst unemployment = [\n  4.9, 5.9, 5.6, 4.9, 5.6, 8.5, 7.7, 7.1, 6.1, 5.8, // 1970-1979\n  7.1, 7.6, 9.7, 9.6, 7.5, 7.2, 7.0, 6.2, 5.5, 5.3, // 1980-1989\n  5.6, 6.8, 7.5, 6.9, 6.1, 5.6, 5.4, 4.9, 4.5, 4.2, // 1990-1999\n  4.0, 4.7, 5.8, 6.0, 5.5, 5.1, 4.6, 4.6, 5.8, 9.3, // 2000-2009\n];\n\nconst inflation = [\n   5.7,  4.4,  3.2,  6.2, 11.0,  9.1,  5.8,  6.5,  7.6, 11.3, // 1970-1979\n  13.5, 10.3,  6.2,  3.2,  4.3,  3.6,  1.9,  3.6,  4.1,  4.8, // 1980-1989\n   5.4,  4.2,  3.0,  3.0,  2.6,  2.8,  3.0,  2.3,  1.6,  2.2, // 1990-1999\n   3.4,  2.8,  1.6,  2.3,  2.7,  3.4,  3.2,  2.9,  3.8, -0.4, // 2000-2009\n];\n\n// Decade segments — overlap at boundary indices for seamless path connection\nconst s1970s = inflation.map((v, i) => (i <= 9 ? v : null));\nconst s1980s = inflation.map((v, i) => (i >= 9 && i <= 19 ? v : null));\nconst s1990s = inflation.map((v, i) => (i >= 19 && i <= 29 ? v : null));\nconst s2000s = inflation.map((v, i) => (i >= 29 ? v : null));\n\n// Decade start/end + notable event year annotations [index, label, dx, dy]\nconst KEY_POINTS = [\n  { i:  0, label: \"1970\", dx: -30, dy: -10 },\n  { i:  3, label: \"1973\", dx:   8, dy: -10 }, // oil shock\n  { i:  9, label: \"1979\", dx:  10, dy:  -8 },\n  { i: 10, label: \"1980\", dx: -30, dy: -10 },\n  { i: 19, label: \"1989\", dx:  12, dy:  12 },\n  { i: 20, label: \"1990\", dx: -30, dy:  -8 },\n  { i: 29, label: \"1999\", dx:  12, dy:   6 },\n  { i: 30, label: \"2000\", dx: -30, dy:  -8 },\n  { i: 38, label: \"2008\", dx:  10, dy: -10 }, // financial crisis\n  { i: 39, label: \"2009\", dx:  10, dy:   8 },\n];\n\n// One directional arrow per decade at its midpoint to show temporal flow\nconst ARROWS = [\n  { i:  5, color: t.palette[0] }, // 1975 (1970s midpoint)\n  { i: 15, color: t.palette[1] }, // 1985 (1980s midpoint)\n  { i: 24, color: t.palette[2] }, // 1994 (1990s midpoint)\n  { i: 34, color: t.palette[3] }, // 2004 (2000s midpoint)\n];\n\n// Custom overlay rendered inside the LineChart SVG via the children prop.\n// Uses useXScale/useYScale (MUI X composition hooks) to convert data coordinates\n// to SVG pixel positions for year annotations and directional arrows.\nfunction TemporalOverlay() {\n  const xScale = useXScale();\n  const yScale = useYScale();\n  if (!xScale || !yScale) return null;\n\n  return (\n    <g>\n      <defs>\n        {ARROWS.map(({ color }, idx) => (\n          <marker key={idx} id={`arr${idx}`} markerWidth=\"8\" markerHeight=\"8\" refX=\"6\" refY=\"3\" orient=\"auto\">\n            <path d=\"M0,0 L0,6 L8,3 z\" fill={color} />\n          </marker>\n        ))}\n      </defs>\n\n      {/* Direction arrows at decade midpoints */}\n      {ARROWS.map(({ i, color }, idx) => {\n        const x1 = xScale(unemployment[i - 1]);\n        const y1 = yScale(inflation[i - 1]);\n        const x2 = xScale(unemployment[i + 1]);\n        const y2 = yScale(inflation[i + 1]);\n        if (x1 == null || y1 == null || x2 == null || y2 == null) return null;\n        const mx = (x1 + x2) / 2;\n        const my = (y1 + y2) / 2;\n        const dx = x2 - x1;\n        const dy = y2 - y1;\n        const len = Math.sqrt(dx * dx + dy * dy) || 1;\n        const s = 20 / len;\n        return (\n          <line\n            key={idx}\n            x1={mx - dx * s * 0.5}\n            y1={my - dy * s * 0.5}\n            x2={mx + dx * s * 0.5}\n            y2={my + dy * s * 0.5}\n            stroke={color}\n            strokeWidth={2.5}\n            markerEnd={`url(#arr${idx})`}\n          />\n        );\n      })}\n\n      {/* Year annotations at decade boundaries and notable events */}\n      {KEY_POINTS.map(({ i, label, dx, dy }) => {\n        const x = xScale(unemployment[i]);\n        const y = yScale(inflation[i]);\n        if (x == null || y == null) return null;\n        return (\n          <text\n            key={label}\n            x={x + dx}\n            y={y + dy}\n            fontSize={12}\n            fill={t.inkSoft}\n            fontFamily=\"system-ui, sans-serif\"\n          >\n            {label}\n          </text>\n        );\n      })}\n    </g>\n  );\n}\n\n// Larger filled markers (r=6) with page-bg outline to distinguish connected-scatter from plain line\nfunction CustomMark({ x, y, color }) {\n  return <circle cx={x} cy={y} r={6} fill={color} stroke={t.pageBg} strokeWidth={1.5} />;\n}\n\nconst TITLE_H = 52;\n\nexport default function Chart() {\n  const W = window.ANYPLOT_SIZE.width;\n  const H = window.ANYPLOT_SIZE.height;\n\n  return (\n    <Box\n      sx={{\n        width: W,\n        height: H,\n        bgcolor: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n      }}\n    >\n      <Typography\n        sx={{\n          color: t.ink,\n          fontSize: 19,\n          fontWeight: 500,\n          textAlign: \"center\",\n          height: TITLE_H,\n          lineHeight: `${TITLE_H}px`,\n          flexShrink: 0,\n        }}\n      >\n        Phillips Curve · scatter-connected-temporal · javascript · muix · anyplot.ai\n      </Typography>\n      <LineChart\n        width={W}\n        height={H - TITLE_H}\n        skipAnimation\n        grid={{ horizontal: true, vertical: true }}\n        xAxis={[{\n          data: unemployment,\n          scaleType: \"linear\",\n          label: \"Unemployment Rate (%)\",\n          min: 3.5,\n          max: 11.0,\n          tickMinStep: 1,\n          tickLabelStyle: { fontSize: 14 },\n          labelStyle: { fontSize: 16 },\n        }]}\n        yAxis={[{\n          label: \"Inflation Rate (%)\",\n          min: -2,\n          max: 15,\n          tickMinStep: 2,\n          tickLabelStyle: { fontSize: 14 },\n          labelStyle: { fontSize: 16 },\n        }]}\n        series={[\n          { data: s1970s, label: \"1970s\", color: t.palette[0], showMark: true, curve: \"linear\" },\n          { data: s1980s, label: \"1980s\", color: t.palette[1], showMark: true, curve: \"linear\" },\n          { data: s1990s, label: \"1990s\", color: t.palette[2], showMark: true, curve: \"linear\" },\n          { data: s2000s, label: \"2000s\", color: t.palette[3], showMark: true, curve: \"linear\" },\n        ]}\n        slots={{ mark: CustomMark }}\n        slotProps={{\n          legend: {\n            direction: \"row\",\n            position: { vertical: \"top\", horizontal: \"right\" },\n            itemMarkWidth: 14,\n            itemMarkHeight: 14,\n            labelStyle: { fontSize: 14 },\n          },\n        }}\n        sx={{\n          \"& .MuiLineElement-root\": { strokeWidth: 2.5 },\n          \"& .MuiChartsGrid-root line\": { strokeOpacity: 0.25 },\n        }}\n      >\n        <TemporalOverlay />\n      </LineChart>\n    </Box>\n  );\n}\n"}