{"spec_id":"histogram-capability","library":"echarts","language":"javascript","code":"// anyplot.ai\n// histogram-capability: Process Capability Plot with Specification Limits\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 91/100 | Created: 2026-06-20\n\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Deterministic LCG (seed 42) — no seeded RNG in browser\nlet _seed = 42;\nfunction rand() {\n  _seed = (_seed * 1664525 + 1013904223) & 0xffffffff;\n  return (_seed >>> 0) / 0x100000000;\n}\nfunction randNorm(mu, s) {\n  const u1 = Math.max(rand(), 1e-12);\n  return mu + s * Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * rand());\n}\n\n// Process specification (shaft diameter, mm)\nconst LSL = 9.95;\nconst USL = 10.05;\nconst TARGET = 10.00;\nconst N = 200;\n\n// Generate synthetic measurements: slightly off-center, capable process\nconst meas = Array.from({ length: N }, () => randNorm(10.002, 0.0085));\n\n// Sample statistics\nconst mu = meas.reduce((a, b) => a + b, 0) / N;\nconst sigma = Math.sqrt(meas.reduce((a, v) => a + (v - mu) ** 2, 0) / (N - 1));\nconst cp  = (USL - LSL) / (6 * sigma);\nconst cpk = Math.min((USL - mu) / (3 * sigma), (mu - LSL) / (3 * sigma));\n\n// Histogram: 20 bins over [9.91, 10.09]\nconst X_LO = 9.91, X_HI = 10.09, N_BINS = 20;\nconst BW = (X_HI - X_LO) / N_BINS;\nconst counts = new Array(N_BINS).fill(0);\nmeas.forEach(v => {\n  const i = Math.floor((v - X_LO) / BW);\n  if (i >= 0 && i < N_BINS) counts[i]++;\n});\nconst barData = counts.map((c, i) => [X_LO + (i + 0.5) * BW, c]);\n\n// Fitted normal PDF curve, scaled to match count axis\nconst curve = [];\nfor (let i = 0; i <= 400; i++) {\n  const x = X_LO + (i / 400) * (X_HI - X_LO);\n  const pdf = Math.exp(-0.5 * ((x - mu) / sigma) ** 2) / (sigma * Math.sqrt(2 * Math.PI));\n  curve.push([x, pdf * N * BW]);\n}\n\nconst yMax = Math.ceil(Math.max(...counts, ...curve.map(d => d[1])) * 1.25);\n\n// Bar width: grid_px / N_BINS  (grid: left=90, right=80, mount=1600 → 1430px / 20 bins ≈ 71px)\nconst BAR_WIDTH = 71;\n\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nconst TITLE = \"histogram-capability · javascript · echarts · anyplot.ai\";\nconst titleSize = Math.max(11, Math.round(22 * Math.min(1, 67 / TITLE.length)));\n\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n\n  title: {\n    text: TITLE,\n    left: \"center\",\n    top: 18,\n    textStyle: { color: t.ink, fontSize: titleSize, fontWeight: \"normal\" }\n  },\n\n  grid: { left: 90, right: 80, top: 100, bottom: 110 },\n\n  xAxis: {\n    type: \"value\",\n    min: X_LO,\n    max: X_HI,\n    interval: 0.02,\n    name: \"Shaft Diameter (mm)\",\n    nameLocation: \"middle\",\n    nameGap: 50,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    axisLabel: {\n      color: t.inkSoft,\n      fontSize: 12,\n      formatter: v => v.toFixed(2)\n    },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    splitLine: { show: false },\n    axisTick: { lineStyle: { color: t.inkSoft } }\n  },\n\n  yAxis: {\n    type: \"value\",\n    name: \"Count\",\n    nameLocation: \"middle\",\n    nameGap: 42,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    max: yMax,\n    axisLabel: { color: t.inkSoft, fontSize: 12 },\n    axisLine: { show: true, lineStyle: { color: t.inkSoft } },\n    splitLine: { lineStyle: { color: t.grid } },\n    axisTick: { show: false }\n  },\n\n  legend: {\n    data: [\n      { name: \"Measurements\", icon: \"roundRect\" },\n      { name: \"Normal Fit\" }\n    ],\n    bottom: 14,\n    left: \"center\",\n    orient: \"horizontal\",\n    itemGap: 30,\n    textStyle: { color: t.inkSoft, fontSize: 13 }\n  },\n\n  // Cp / Cpk annotation box (upper-right — data sparse beyond USL)\n  graphic: [{\n    type: \"group\",\n    right: 84,\n    top: 108,\n    children: [\n      {\n        type: \"rect\",\n        shape: { width: 158, height: 78, r: 4 },\n        style: { fill: t.elevatedBg, stroke: t.grid, lineWidth: 1 }\n      },\n      // Brand green left-border accent\n      {\n        type: \"rect\",\n        shape: { x: 0, y: 0, width: 4, height: 78, r: [4, 0, 0, 4] },\n        style: { fill: t.palette[0], lineWidth: 0 }\n      },\n      // \"Cp\" label in brand green\n      {\n        type: \"text\",\n        top: 14,\n        left: 18,\n        style: {\n          text: \"Cp\",\n          font: \"bold 16px 'Helvetica Neue', Arial, sans-serif\",\n          fill: t.palette[0]\n        }\n      },\n      // Cp numeric value in ink\n      {\n        type: \"text\",\n        top: 14,\n        left: 62,\n        style: {\n          text: \"= \" + cp.toFixed(2),\n          font: \"bold 16px 'Helvetica Neue', Arial, sans-serif\",\n          fill: t.ink\n        }\n      },\n      // \"Cpk\" label in brand green\n      {\n        type: \"text\",\n        top: 44,\n        left: 18,\n        style: {\n          text: \"Cpk\",\n          font: \"bold 16px 'Helvetica Neue', Arial, sans-serif\",\n          fill: t.palette[0]\n        }\n      },\n      // Cpk numeric value in ink\n      {\n        type: \"text\",\n        top: 44,\n        left: 62,\n        style: {\n          text: \"= \" + cpk.toFixed(2),\n          font: \"bold 16px 'Helvetica Neue', Arial, sans-serif\",\n          fill: t.ink\n        }\n      }\n    ]\n  }],\n\n  series: [\n    {\n      name: \"Measurements\",\n      type: \"bar\",\n      data: barData,\n      barWidth: BAR_WIDTH,\n      itemStyle: { color: t.palette[0], opacity: 0.72 },\n      markLine: {\n        symbol: [\"none\", \"none\"],\n        silent: true,\n        label: {\n          show: true,\n          fontSize: 15,\n          fontWeight: \"bold\",\n          formatter: params => params.name\n        },\n        data: [\n          {\n            name: \"LSL\",\n            xAxis: LSL,\n            lineStyle: { color: t.palette[4], type: \"dashed\", width: 2.5 },\n            label: { color: t.palette[4], position: \"insideEndTop\" }\n          },\n          {\n            name: \"USL\",\n            xAxis: USL,\n            lineStyle: { color: t.palette[4], type: \"dashed\", width: 2.5 },\n            label: { color: t.palette[4], position: \"insideEndTop\" }\n          },\n          {\n            name: \"Target\",\n            xAxis: TARGET,\n            lineStyle: { color: t.inkSoft, type: \"dashed\", width: 2 },\n            label: { color: t.inkSoft, position: \"insideEndTop\" }\n          }\n        ]\n      }\n    },\n    {\n      name: \"Normal Fit\",\n      type: \"line\",\n      data: curve,\n      symbol: \"none\",\n      lineStyle: { color: t.palette[2], width: 2.5 },\n      z: 10\n    }\n  ]\n});\n"}