{"spec_id":"bar-pareto","library":"muix","language":"javascript","code":"// anyplot.ai\n// bar-pareto: Pareto Chart with Cumulative Line\n// Library: muix 7.29.1 | JavaScript 22.22.3\n// Quality: 88/100 | Created: 2026-06-20\n//# anyplot-orientation: landscape\n// anyplot.ai\n// bar-pareto: Pareto Chart with Cumulative Line\n// Library: MUI X Charts | React | Node 22\n// License: @mui/x-charts — MIT (community). Pro/Premium are out of scope.\n// Quality: pending | Created: 2026-06-20\n\nimport { ChartContainer } from \"@mui/x-charts/ChartContainer\";\nimport { BarPlot } from \"@mui/x-charts/BarChart\";\nimport { LinePlot, MarkPlot } from \"@mui/x-charts/LineChart\";\nimport { ChartsXAxis } from \"@mui/x-charts/ChartsXAxis\";\nimport { ChartsYAxis } from \"@mui/x-charts/ChartsYAxis\";\nimport { ChartsGrid } from \"@mui/x-charts/ChartsGrid\";\nimport { ChartsReferenceLine } from \"@mui/x-charts/ChartsReferenceLine\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Manufacturing QC: defect frequency analysis — sorted descending\nconst categories = [\n  \"Scratches\", \"Dents\", \"Cracks\", \"Warping\",\n  \"Discolor.\", \"Miss. Part\", \"Wrong Size\", \"Surf. Flaw\",\n];\nconst counts = [412, 298, 187, 143, 98, 76, 54, 32];\nconst total = counts.reduce((a, b) => a + b, 0); // 1300\n\n// Cumulative percentages (0–100 range): 31.7, 54.6, 69.0, 80.0, 87.5, 93.4, 97.5, 100.0\nlet running = 0;\nconst cumPercent = counts.map((c) => {\n  running += c;\n  return parseFloat(((running / total) * 100).toFixed(1));\n});\n\nconst COUNT_MAX = 500; // multiple of 500 ensures left ticks (100,200,300,400,500) align with right ticks (20,40,60,80,100%) at exact 20% intervals\n\nconst MARGIN = { top: 24, right: 90, bottom: 80, left: 80 };\n\nexport default function Chart() {\n  const W = window.ANYPLOT_SIZE.width;   // 1600 CSS px (landscape)\n  const H = window.ANYPLOT_SIZE.height;  // 900 CSS px\n  const TITLE_H = 72;\n  const LEGEND_H = 44;\n  const chartH = H - TITLE_H - LEGEND_H; // 784\n\n  return (\n    <Box\n      sx={{\n        width: W,\n        height: H,\n        bgcolor: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        fontFamily: \"'Roboto', 'Helvetica Neue', Arial, sans-serif\",\n        boxSizing: \"border-box\",\n      }}\n    >\n      {/* Title */}\n      <Box sx={{ height: TITLE_H, display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}>\n        <Typography sx={{ color: t.ink, fontSize: 22, fontWeight: 600 }}>\n          bar-pareto · javascript · muix · anyplot.ai\n        </Typography>\n      </Box>\n\n      {/* Chart */}\n      <ChartContainer\n        width={W}\n        height={chartH}\n        series={[\n          {\n            type: \"bar\",\n            id: \"defect-counts\",\n            yAxisId: \"counts\",\n            data: counts,\n            label: \"Defect Count\",\n            color: t.palette[0],\n          },\n          {\n            type: \"line\",\n            id: \"cum-line\",\n            yAxisId: \"percent\",\n            data: cumPercent,\n            label: \"Cumulative %\",\n            color: t.palette[1],\n            showMark: true,\n            curve: \"linear\",\n          },\n        ]}\n        xAxis={[\n          {\n            id: \"x\",\n            scaleType: \"band\",\n            data: categories,\n            categoryGapRatio: 0.38,\n            tickLabelStyle: { fontSize: 14, fill: t.inkSoft },\n          },\n        ]}\n        yAxis={[\n          {\n            id: \"counts\",\n            min: 0,\n            max: COUNT_MAX,\n            tickMinStep: 100,\n            tickLabelStyle: { fontSize: 13, fill: t.inkSoft },\n          },\n          {\n            // Right axis: 0–100% domain. Aligned with left axis (100/500 = 20/100).\n            id: \"percent\",\n            position: \"right\",\n            min: 0,\n            max: 100,\n            tickMinStep: 20,\n            valueFormatter: (v) => `${v}%`,\n            tickLabelStyle: { fontSize: 13, fill: t.inkSoft },\n          },\n        ]}\n        margin={MARGIN}\n        skipAnimation\n        sx={{\n          \"& .MuiChartsAxis-line\": { stroke: t.inkSoft, strokeOpacity: 0.4 },\n          \"& .MuiChartsGrid-line\": { stroke: t.grid },\n        }}\n      >\n        <ChartsGrid horizontal />\n        <BarPlot />\n        <LinePlot />\n        <MarkPlot />\n        {/* 80% threshold on the percentage axis — y=80 == 80% cumulative */}\n        <ChartsReferenceLine\n          y={80}\n          axisId=\"percent\"\n          label=\"80%\"\n          labelAlign=\"end\"\n          lineStyle={{ stroke: t.amber, strokeDasharray: \"8 5\", strokeWidth: 2.5 }}\n          labelStyle={{ fill: t.amber, fontSize: 14, fontWeight: 700 }}\n        />\n        <ChartsXAxis axisId=\"x\" position=\"bottom\" label=\"Defect Type\" labelStyle={{ fontSize: 14, fill: t.ink }} />\n        <ChartsYAxis axisId=\"counts\" position=\"left\" label=\"Defect Count\" labelStyle={{ fontSize: 14, fill: t.ink }} />\n        <ChartsYAxis axisId=\"percent\" position=\"right\" label=\"Cumulative %\" labelStyle={{ fontSize: 14, fill: t.ink }} disableLine disableTicks />\n      </ChartContainer>\n\n      {/* Legend */}\n      <Box sx={{ height: LEGEND_H, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", gap: \"36px\" }}>\n        <Box sx={{ display: \"flex\", alignItems: \"center\", gap: \"8px\" }}>\n          <Box sx={{ width: 22, height: 14, bgcolor: t.palette[0], borderRadius: \"2px\", flexShrink: 0 }} />\n          <Typography sx={{ color: t.inkSoft, fontSize: 14 }}>Defect Count</Typography>\n        </Box>\n        <Box sx={{ display: \"flex\", alignItems: \"center\", gap: \"8px\" }}>\n          <Box sx={{ width: 24, height: 3, bgcolor: t.palette[1], borderRadius: \"2px\", flexShrink: 0 }} />\n          <Typography sx={{ color: t.inkSoft, fontSize: 14 }}>Cumulative %</Typography>\n        </Box>\n        <Box sx={{ display: \"flex\", alignItems: \"center\", gap: \"8px\" }}>\n          <Box sx={{ width: 24, height: 0, borderTop: `2.5px dashed ${t.amber}`, flexShrink: 0 }} />\n          <Typography sx={{ color: t.inkSoft, fontSize: 14 }}>80% Threshold</Typography>\n        </Box>\n      </Box>\n    </Box>\n  );\n}\n"}