{"spec_id":"box-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// box-basic: Basic Box Plot\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 89/100 | Created: 2026-08-24\nimport { ChartContainer } from \"@mui/x-charts/ChartContainer\";\nimport { ChartsGrid } from \"@mui/x-charts/ChartsGrid\";\nimport { ChartsXAxis } from \"@mui/x-charts/ChartsXAxis\";\nimport { ChartsYAxis } from \"@mui/x-charts/ChartsYAxis\";\nimport { useXScale, useYScale } from \"@mui/x-charts/hooks\";\n\nconst t = window.ANYPLOT_TOKENS;\nconst TITLE = \"box-basic · javascript · muix · anyplot.ai\";\nconst TITLE_HEIGHT = 56;\n\n// --- Data (in-memory, deterministic LCG — no seeded RNG in the browser) -----\nfunction lcg(seed) {\n  let state = seed;\n  return () => {\n    state = (state * 1664525 + 1013904223) % 4294967296;\n    return state / 4294967296;\n  };\n}\n\nfunction randomNormal(rand, mean, stdDev) {\n  const u1 = Math.max(rand(), 1e-9);\n  const u2 = rand();\n  const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n  return mean + z * stdDev;\n}\n\n// Exam scores across 5 classes — deliberately different spreads so the\n// distributions read differently at a glance.\nconst classes = [\n  { name: \"Class A\", mean: 78, std: 7, size: 62 },\n  { name: \"Class B\", mean: 71, std: 13, size: 58 },\n  { name: \"Class C\", mean: 85, std: 5, size: 74 },\n  { name: \"Class D\", mean: 68, std: 11, size: 55 },\n  { name: \"Class E\", mean: 80, std: 9, size: 66 },\n];\n\nconst rand = lcg(42);\n\nfunction quantile(sorted, q) {\n  const pos = (sorted.length - 1) * q;\n  const base = Math.floor(pos);\n  const rest = pos - base;\n  return base + 1 < sorted.length\n    ? sorted[base] + rest * (sorted[base + 1] - sorted[base])\n    : sorted[base];\n}\n\n// A couple of classes get one deliberate, deterministic extreme score on top\n// of the random draws (e.g. a single struggling or exceptional student) so\n// the outlier-marker feature is demonstrated in more than one class instead\n// of relying on chance alone.\nconst injectedOutliers = { \"Class B\": 18, \"Class D\": 24 };\n\nconst boxStats = classes.map(({ name, mean, std, size }) => {\n  const scores = Array.from({ length: size }, () =>\n    Math.min(100, Math.max(0, randomNormal(rand, mean, std))),\n  );\n  if (name in injectedOutliers) scores.push(injectedOutliers[name]);\n  scores.sort((a, b) => a - b);\n\n  const q1 = quantile(scores, 0.25);\n  const median = quantile(scores, 0.5);\n  const q3 = quantile(scores, 0.75);\n  const iqr = q3 - q1;\n  const lowerFence = q1 - 1.5 * iqr;\n  const upperFence = q3 + 1.5 * iqr;\n  const inliers = scores.filter((s) => s >= lowerFence && s <= upperFence);\n  const outliers = scores.filter((s) => s < lowerFence || s > upperFence);\n\n  return {\n    name,\n    q1,\n    median,\n    q3,\n    whiskerLow: inliers.length ? Math.min(...inliers) : q1,\n    whiskerHigh: inliers.length ? Math.max(...inliers) : q3,\n    outliers,\n  };\n});\n\nconst categories = boxStats.map((s) => s.name);\n\n// The tightest, highest-scoring distribution is the clearest \"best in class\"\n// story the data tells on its own — give it a subtle visual focal point\n// (bolder stroke + soft shadow) rather than a text callout.\nconst focalClass = boxStats.reduce((best, s) =>\n  s.q3 - s.q1 < best.q3 - best.q1 ? s : best,\n).name;\n\n// --- Box-and-whisker overlay -------------------------------------------------\n// The community package (7.29.1) has no BoxPlot component (Pro-only in other\n// charting suites is irrelevant here — @mui/x-charts community simply doesn't\n// ship one). A custom SVG layer positioned via the chart's own band/linear\n// scale hooks reproduces it while staying entirely within the community\n// ChartContainer surface — the same technique used for span overlays.\nfunction BoxWhiskers() {\n  const xScale = useXScale();\n  const yScale = useYScale();\n  const bandwidth = xScale.bandwidth();\n  const boxWidth = bandwidth * 0.5;\n\n  return (\n    <g>\n      <defs>\n        <filter id=\"box-focal-shadow\" x=\"-40%\" y=\"-40%\" width=\"180%\" height=\"180%\">\n          <feDropShadow dx=\"0\" dy=\"2\" stdDeviation=\"3\" floodOpacity={0.35} />\n        </filter>\n      </defs>\n      {boxStats.map((s, i) => {\n        const center = xScale(s.name) + bandwidth / 2;\n        const left = center - boxWidth / 2;\n        const right = center + boxWidth / 2;\n        const color = t.palette[i % t.palette.length];\n        const isFocal = s.name === focalClass;\n        const boxStroke = isFocal ? 3.5 : 2.5;\n\n        return (\n          <g\n            key={s.name}\n            filter={isFocal ? \"url(#box-focal-shadow)\" : undefined}\n          >\n            <line\n              x1={center}\n              x2={center}\n              y1={yScale(s.whiskerHigh)}\n              y2={yScale(s.q3)}\n              stroke={color}\n              strokeWidth={2}\n              strokeLinecap=\"round\"\n            />\n            <line\n              x1={center}\n              x2={center}\n              y1={yScale(s.q1)}\n              y2={yScale(s.whiskerLow)}\n              stroke={color}\n              strokeWidth={2}\n              strokeLinecap=\"round\"\n            />\n            <line\n              x1={left}\n              x2={right}\n              y1={yScale(s.whiskerHigh)}\n              y2={yScale(s.whiskerHigh)}\n              stroke={color}\n              strokeWidth={2}\n              strokeLinecap=\"round\"\n            />\n            <line\n              x1={left}\n              x2={right}\n              y1={yScale(s.whiskerLow)}\n              y2={yScale(s.whiskerLow)}\n              stroke={color}\n              strokeWidth={2}\n              strokeLinecap=\"round\"\n            />\n            <rect\n              x={left}\n              y={yScale(s.q3)}\n              width={boxWidth}\n              height={Math.max(1, yScale(s.q1) - yScale(s.q3))}\n              rx={4}\n              ry={4}\n              fill={color}\n              fillOpacity={0.28}\n              stroke={color}\n              strokeWidth={boxStroke}\n            />\n            <line\n              x1={left}\n              x2={right}\n              y1={yScale(s.median)}\n              y2={yScale(s.median)}\n              stroke={color}\n              strokeWidth={3.5}\n              strokeLinecap=\"round\"\n            />\n            {s.outliers.map((v, j) => (\n              <circle\n                key={j}\n                cx={center}\n                cy={yScale(v)}\n                r={5}\n                fill={t.pageBg}\n                stroke={color}\n                strokeWidth={2}\n              />\n            ))}\n          </g>\n        );\n      })}\n    </g>\n  );\n}\n\nexport default function Chart() {\n  const chartHeight = window.ANYPLOT_SIZE.height - TITLE_HEIGHT;\n\n  return (\n    <div\n      style={{\n        width: window.ANYPLOT_SIZE.width,\n        height: window.ANYPLOT_SIZE.height,\n      }}\n    >\n      <div\n        style={{\n          height: TITLE_HEIGHT,\n          lineHeight: `${TITLE_HEIGHT}px`,\n          paddingLeft: 24,\n          fontSize: 22,\n          fontWeight: 500,\n          color: t.ink,\n        }}\n      >\n        {TITLE}\n      </div>\n      <ChartContainer\n        width={window.ANYPLOT_SIZE.width}\n        height={chartHeight}\n        series={[]}\n        skipAnimation\n        margin={{ top: 20, right: 40, bottom: 64, left: 80 }}\n        xAxis={[\n          {\n            id: \"classes\",\n            data: categories,\n            scaleType: \"band\",\n            label: \"Class\",\n            labelStyle: { fontSize: 16 },\n            tickLabelStyle: { fontSize: 14 },\n          },\n        ]}\n        yAxis={[\n          {\n            id: \"scores\",\n            min: 0,\n            max: 100,\n            label: \"Exam Score (%)\",\n            labelStyle: { fontSize: 16 },\n            tickLabelStyle: { fontSize: 14 },\n          },\n        ]}\n      >\n        <ChartsGrid\n          horizontal\n          sx={{\n            \"& .MuiChartsGrid-line\": {\n              opacity: 0.55,\n              strokeDasharray: \"2 5\",\n            },\n          }}\n        />\n        <BoxWhiskers />\n        <ChartsXAxis axisId=\"classes\" />\n        <ChartsYAxis axisId=\"scores\" />\n      </ChartContainer>\n    </div>\n  );\n}\n"}