{"spec_id":"histogram-capability","library":"muix","language":"javascript","code":"// anyplot.ai\n// histogram-capability: Process Capability Plot with Specification Limits\n// Library: muix 9.16.0 | JavaScript 22.23.3\n// Quality: 86/100 | Updated: 2026-10-24\nimport { ChartsContainer } from \"@mui/x-charts/ChartsContainer\";\nimport { LinePlot } from \"@mui/x-charts/LineChart\";\nimport { ChartsXAxis } from \"@mui/x-charts/ChartsXAxis\";\nimport { ChartsYAxis } from \"@mui/x-charts/ChartsYAxis\";\nimport { ChartsReferenceLine } from \"@mui/x-charts/ChartsReferenceLine\";\nimport { ChartsGrid } from \"@mui/x-charts/ChartsGrid\";\nimport { useDrawingArea } from \"@mui/x-charts/hooks\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Constants\nconst FONT = \"system-ui, -apple-system, sans-serif\";\nconst TITLE = \"histogram-capability · javascript · muix · anyplot.ai\";\n\nconst N_BINS = 15;\nconst CURVE_STEPS = 120;\nconst X_PAD_RATIO = 0.25;\nconst Y_PAD_RATIO = 0.14;\nconst CAPABLE_MIN = 1.33;\nconst MARGINAL_MIN = 1.0;\n\nconst BRAND = t.palette[0];\nconst TARGET_COLOR = t.palette[1];\nconst BLUE = t.palette[2];\nconst RED = t.palette[4];\n\n// Columns: set these to your data's column names\nconst DIAMETER = \"Shaft diameter (mm)\"; // role: measurement\nconst LSL = \"LSL\"; // role: lsl\nconst USL = \"USL\"; // role: usl\nconst TARGET = \"Target\"; // role: target\n\n// Data: replace this block with your own records\ntype CapabilityRow = {\n  [DIAMETER]: number;\n  [LSL]: number;\n  [USL]: number;\n  [TARGET]: number;\n};\n\nconst data: CapabilityRow[] = [];\nlet seed = 42 >>> 0;\nconst sampleSize = 200;\n\nfor (let i = 0; i < sampleSize; i++) {\n  seed = (Math.imul(1664525, seed) + 1013904223) >>> 0;\n  const u1 = Math.max(seed / 0x100000000, 1e-10);\n  seed = (Math.imul(1664525, seed) + 1013904223) >>> 0;\n  const u2 = seed / 0x100000000;\n  const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n  data.push({\n    [DIAMETER]: Number((10.005 + z * 0.015).toFixed(5)),\n    [LSL]: 9.95,\n    [USL]: 10.05,\n    [TARGET]: 10.0,\n  });\n}\n\n// Plot: reads only data and the constants above\nconst n = data.length;\nconst lsl = data[0][LSL];\nconst usl = data[0][USL];\nconst target = data[0][TARGET];\nconst measurements = data.map((r) => r[DIAMETER]);\n\nconst sampleMean = measurements.reduce((s, v) => s + v, 0) / n;\nconst sampleSigma = Math.sqrt(\n  measurements.reduce((s, v) => s + (v - sampleMean) ** 2, 0) / (n - 1),\n);\n\nconst Cp = (usl - lsl) / (6 * sampleSigma);\nconst Cpk = Math.min(\n  (usl - sampleMean) / (3 * sampleSigma),\n  (sampleMean - lsl) / (3 * sampleSigma),\n);\n\nconst dataMin = Math.min(...measurements);\nconst dataMax = Math.max(...measurements);\nconst binWidth = (dataMax - dataMin) / N_BINS;\n\nconst histCounts = new Array(N_BINS).fill(0);\nfor (const v of measurements) {\n  const idx = Math.min(N_BINS - 1, Math.floor((v - dataMin) / binWidth));\n  histCounts[idx]++;\n}\n\nconst specSpan = usl - lsl;\nconst xMin = Math.min(dataMin, lsl - specSpan * X_PAD_RATIO);\nconst xMax = Math.max(dataMax, usl + specSpan * X_PAD_RATIO);\n\nconst curveX = Array.from(\n  { length: CURVE_STEPS },\n  (_, i) => xMin + (i / (CURVE_STEPS - 1)) * (xMax - xMin),\n);\nconst normalValues = curveX.map((x) => {\n  const z = (x - sampleMean) / sampleSigma;\n  return (\n    (Math.exp(-0.5 * z * z) / (sampleSigma * Math.sqrt(2 * Math.PI))) *\n    n *\n    binWidth\n  );\n});\n\nconst yMax = Math.max(...histCounts, ...normalValues) * (1 + Y_PAD_RATIO);\n\nconst capStatus =\n  Cpk >= CAPABLE_MIN\n    ? \"Status: Capable\"\n    : Cpk >= MARGINAL_MIN\n      ? \"Status: Marginal\"\n      : \"Status: Not Capable\";\n\nconst unitMatch = DIAMETER.match(/\\(([^)]+)\\)/);\nconst unit = unitMatch ? ` ${unitMatch[1]}` : \"\";\nconst SUBTITLE = `${DIAMETER} (n = ${n}) · μ = ${sampleMean.toFixed(4)}${unit}, σ = ${sampleSigma.toFixed(4)}${unit} · ${LSL} = ${lsl.toFixed(2)}, ${TARGET} = ${target.toFixed(2)}, ${USL} = ${usl.toFixed(2)}${unit}`;\n\nconst LEGEND = [\n  { label: \"Observations\", kind: \"box\", color: BRAND },\n  { label: \"Normal fit\", kind: \"line\", color: BLUE, width: 3 },\n  { label: `${LSL} / ${USL}`, kind: \"line\", color: RED, width: 2.5, dash: \"6 3\" },\n  { label: TARGET, kind: \"line\", color: TARGET_COLOR, width: 2.5, dash: \"8 4\" },\n];\n\nfunction CapabilityLayer() {\n  const { left, top, width, height } = useDrawingArea();\n  const binPx = (binWidth / (xMax - xMin)) * width;\n  const px = left + width + 22;\n  const py = top + 16;\n  const lh = 28;\n\n  return (\n    <g fontFamily={FONT}>\n      {histCounts.map((c, i) => {\n        const bx = left + ((dataMin + i * binWidth - xMin) / (xMax - xMin)) * width;\n        const by = top + (1 - c / yMax) * height;\n        const bh = top + height - by;\n        return (\n          <rect\n            key={i}\n            x={bx + 0.5}\n            y={by}\n            width={binPx - 1}\n            height={bh}\n            fill={BRAND}\n            fillOpacity={0.82}\n          />\n        );\n      })}\n\n      <rect\n        x={px - 14}\n        y={py - 16}\n        width={216}\n        height={264}\n        fill={t.elevatedBg}\n        stroke={t.grid}\n        strokeWidth={1}\n        rx={6}\n      />\n      <text\n        x={px}\n        y={py + 6}\n        fontSize={14}\n        fontWeight=\"700\"\n        fill={t.inkSoft}\n        letterSpacing={1.2}\n      >\n        CAPABILITY\n      </text>\n      <text\n        x={px}\n        y={py + lh + 8}\n        fontSize={16}\n        fill={t.ink}\n        fontFamily=\"monospace\"\n        fontWeight=\"600\"\n      >\n        {`Cp  = ${Cp.toFixed(3)}`}\n      </text>\n      <text\n        x={px}\n        y={py + 2 * lh + 8}\n        fontSize={16}\n        fill={t.ink}\n        fontFamily=\"monospace\"\n        fontWeight=\"600\"\n      >\n        {`Cpk = ${Cpk.toFixed(3)}`}\n      </text>\n      <line\n        x1={px}\n        y1={py + 2 * lh + 22}\n        x2={px + 188}\n        y2={py + 2 * lh + 22}\n        stroke={t.inkSoft}\n        strokeWidth={1}\n        strokeOpacity={0.35}\n      />\n      <text\n        x={px}\n        y={py + 3 * lh + 22}\n        fontSize={14}\n        fontWeight=\"700\"\n        fill={t.ink}\n      >\n        {capStatus}\n      </text>\n\n      {LEGEND.map((e, i) => {\n        const ry = py + (4 + i) * lh + 32;\n        return (\n          <g key={e.label}>\n            {e.kind === \"box\" ? (\n              <rect\n                x={px}\n                y={ry - 6}\n                width={22}\n                height={14}\n                fill={e.color}\n                fillOpacity={0.82}\n                rx={2}\n              />\n            ) : (\n              <line\n                x1={px}\n                y1={ry}\n                x2={px + 22}\n                y2={ry}\n                stroke={e.color}\n                strokeWidth={e.width}\n                strokeDasharray={e.dash}\n              />\n            )}\n            <text x={px + 30} y={ry + 5} fontSize={14} fill={t.ink}>\n              {e.label}\n            </text>\n          </g>\n        );\n      })}\n    </g>\n  );\n}\n\nexport default function Chart() {\n  const { width, height } = window.ANYPLOT_SIZE;\n  const TITLE_H = 78;\n\n  return (\n    <Box\n      sx={{\n        width,\n        height,\n        bgcolor: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        overflow: \"hidden\",\n      }}\n    >\n      <Typography\n        sx={{\n          fontSize: 22,\n          fontWeight: 600,\n          color: t.ink,\n          pt: \"16px\",\n          px: \"40px\",\n          pb: 0,\n          lineHeight: 1.2,\n          fontFamily: FONT,\n        }}\n      >\n        {TITLE}\n      </Typography>\n      <Typography\n        sx={{\n          fontSize: 15,\n          fontWeight: 400,\n          color: t.inkSoft,\n          px: \"40px\",\n          pt: \"4px\",\n          pb: 0,\n          lineHeight: 1.2,\n          fontFamily: FONT,\n        }}\n      >\n        {SUBTITLE}\n      </Typography>\n\n      <ChartsContainer\n        width={width}\n        height={height - TITLE_H}\n        series={[\n          {\n            type: \"line\",\n            id: \"normal\",\n            data: normalValues,\n            label: \"Normal fit\",\n            color: BLUE,\n            showMark: false,\n            curve: \"catmullRom\",\n          },\n        ]}\n        xAxis={[\n          {\n            id: \"diameter-axis\",\n            data: curveX,\n            scaleType: \"linear\",\n            min: xMin,\n            max: xMax,\n            height: 60,\n            label: DIAMETER,\n            valueFormatter: (v: number) => v.toFixed(3),\n            tickLabelStyle: { fontSize: 14, fill: t.inkSoft, fontFamily: FONT },\n            labelStyle: { fontSize: 15, fill: t.ink, fontFamily: FONT },\n          },\n        ]}\n        yAxis={[\n          {\n            id: \"count-axis\",\n            min: 0,\n            max: yMax,\n            width: 76,\n            label: \"Count\",\n            tickLabelStyle: { fontSize: 14, fill: t.inkSoft, fontFamily: FONT },\n            labelStyle: { fontSize: 15, fill: t.ink, fontFamily: FONT },\n          },\n        ]}\n        margin={{ top: 24, right: 244, bottom: 20, left: 20 }}\n        skipAnimation\n      >\n        <ChartsGrid\n          horizontal\n          sx={{ \"& line\": { stroke: t.grid, strokeWidth: 0.8 } }}\n        />\n        <CapabilityLayer />\n        <LinePlot skipAnimation />\n        <ChartsReferenceLine\n          x={lsl}\n          label={LSL}\n          labelAlign=\"start\"\n          lineStyle={{ stroke: RED, strokeDasharray: \"6 3\", strokeWidth: 2.5 }}\n          labelStyle={{\n            fill: RED,\n            fontSize: 14,\n            fontWeight: \"bold\",\n            fontFamily: FONT,\n          }}\n        />\n        <ChartsReferenceLine\n          x={usl}\n          label={USL}\n          labelAlign=\"start\"\n          lineStyle={{ stroke: RED, strokeDasharray: \"6 3\", strokeWidth: 2.5 }}\n          labelStyle={{\n            fill: RED,\n            fontSize: 14,\n            fontWeight: \"bold\",\n            fontFamily: FONT,\n          }}\n        />\n        <ChartsReferenceLine\n          x={target}\n          label={TARGET}\n          labelAlign=\"start\"\n          lineStyle={{ stroke: TARGET_COLOR, strokeDasharray: \"8 4\", strokeWidth: 2.5 }}\n          labelStyle={{\n            fill: TARGET_COLOR,\n            fontSize: 14,\n            fontWeight: \"bold\",\n            fontFamily: FONT,\n          }}\n        />\n        <ChartsXAxis axisId=\"diameter-axis\" />\n        <ChartsYAxis axisId=\"count-axis\" />\n      </ChartsContainer>\n    </Box>\n  );\n}\n"}