{"spec_id":"pp-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// pp-basic: Probability-Probability (P-P) Plot\n// Library: muix 7.29.1 | JavaScript 22.22.3\n// Quality: 87/100 | Created: 2026-06-09\n//# anyplot-orientation: square\n// anyplot.ai\n// pp-basic: Probability-Probability (P-P) Plot\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-09\nimport { ScatterChart } from \"@mui/x-charts/ScatterChart\";\nimport { useDrawingArea } from \"@mui/x-charts/hooks\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Utilities ---------------------------------------------------------------\n\nfunction lcgRng(seed) {\n  let s = seed >>> 0;\n  return () => {\n    s = (Math.imul(s, 1664525) + 1013904223) >>> 0;\n    return s / 4294967296;\n  };\n}\n\nfunction boxMuller(u1, u2) {\n  const mag = Math.sqrt(-2 * Math.log(Math.max(u1, 1e-10)));\n  return [mag * Math.cos(2 * Math.PI * u2), mag * Math.sin(2 * Math.PI * u2)];\n}\n\n// Standard normal CDF (Abramowitz & Stegun 26.2.17)\nfunction normCDF(x) {\n  const p = 0.2316419;\n  const b = [0.31938153, -0.356563782, 1.781477937, -1.821255978, 1.330274429];\n  const k = 1.0 / (1.0 + p * Math.abs(x));\n  const poly = k * (b[0] + k * (b[1] + k * (b[2] + k * (b[3] + k * b[4]))));\n  const phi = Math.exp(-0.5 * x * x) / Math.sqrt(2 * Math.PI);\n  return x >= 0 ? 1.0 - phi * poly : phi * poly;\n}\n\n// --- Data (200 samples from a mildly right-skewed log-normal distribution) ---\n\nconst rng = lcgRng(42);\nconst samples = [];\nfor (let i = 0; i < 100; i++) {\n  const [z0, z1] = boxMuller(rng(), rng());\n  samples.push(Math.exp(0.35 * z0));\n  samples.push(Math.exp(0.35 * z1));\n}\nsamples.sort((a, b) => a - b);\n\nconst N = samples.length;\nconst mean = samples.reduce((s, x) => s + x, 0) / N;\nconst variance = samples.reduce((s, x) => s + (x - mean) ** 2, 0) / (N - 1);\nconst std = Math.sqrt(variance);\n\n// Weibull plotting positions: i / (N+1), i = 1..N\nconst empirical = samples.map((_, i) => (i + 1) / (N + 1));\n// Theoretical normal CDF with MLE-fitted mean and std\nconst theoretical = samples.map((x) => normCDF((x - mean) / std));\n\nconst ppData = theoretical.map((thCdf, i) => ({\n  id: String(i),\n  x: thCdf,\n  y: empirical[i],\n}));\n\n// --- Custom SVG components ---------------------------------------------------\n\n// 45-degree reference diagonal and annotations within the drawing area\nfunction Overlay() {\n  const { left, top, width, height } = useDrawingArea();\n  return (\n    <g>\n      {/* 45° reference diagonal: data (0,0)→(1,1) maps to drawing-area corners */}\n      <line\n        x1={left}\n        y1={top + height}\n        x2={left + width}\n        y2={top}\n        stroke={t.inkSoft}\n        strokeWidth={1.5}\n        strokeDasharray=\"8 4\"\n        strokeLinecap=\"round\"\n      />\n      {/* \"Perfect fit\" label — at ~78% along diagonal, clear of the upper-right data cluster */}\n      <text\n        x={left + width * 0.74}\n        y={top + height * 0.24}\n        textAnchor=\"end\"\n        fill={t.inkSoft}\n        fontSize={13}\n        fontFamily=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\"\n      >\n        Perfect fit\n      </text>\n      {/* S-curve deviation annotation near the peak separation (theoretical CDF ~0.45) */}\n      <text\n        x={left + width * 0.36}\n        y={top + height * 0.29}\n        textAnchor=\"end\"\n        fill={t.inkSoft}\n        fontSize={12}\n        fontStyle=\"italic\"\n        fontFamily=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\"\n      >\n        log-normal\n      </text>\n      <text\n        x={left + width * 0.36}\n        y={top + height * 0.29 + 15}\n        textAnchor=\"end\"\n        fill={t.inkSoft}\n        fontSize={12}\n        fontStyle=\"italic\"\n        fontFamily=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\"\n      >\n        deviation →\n      </text>\n    </g>\n  );\n}\n\nfunction ChartTitle() {\n  const { left, width } = useDrawingArea();\n  return (\n    <text\n      x={left + width / 2}\n      y={26}\n      textAnchor=\"middle\"\n      dominantBaseline=\"middle\"\n      fill={t.ink}\n      fontSize={20}\n      fontWeight=\"600\"\n      fontFamily=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\"\n    >\n      pp-basic · javascript · muix · anyplot.ai\n    </text>\n  );\n}\n\n// --- Chart -------------------------------------------------------------------\n\nexport default function Chart() {\n  return (\n    <ScatterChart\n      width={window.ANYPLOT_SIZE.width}\n      height={window.ANYPLOT_SIZE.height}\n      colors={t.palette}\n      skipAnimation\n      margin={{ top: 55, bottom: 90, left: 95, right: 30 }}\n      sx={{\n        \"& .MuiChartsGrid-line\": { opacity: 0.15 },\n      }}\n      xAxis={[{\n        min: 0,\n        max: 1,\n        label: \"Theoretical CDF (Normal)\",\n        labelStyle: { fontSize: 16 },\n        tickLabelStyle: { fontSize: 12 },\n      }]}\n      yAxis={[{\n        min: 0,\n        max: 1,\n        label: \"Empirical CDF\",\n        labelStyle: { fontSize: 16 },\n        tickLabelStyle: { fontSize: 12 },\n      }]}\n      series={[{\n        data: ppData,\n        label: \"Observed (log-normal)\",\n        markerSize: 6,\n        valueFormatter: (v) =>\n          `Theoretical: ${v.x.toFixed(3)}, Empirical: ${v.y.toFixed(3)}`,\n      }]}\n      slotProps={{\n        legend: {\n          position: { vertical: \"bottom\", horizontal: \"middle\" },\n          itemMarkWidth: 10,\n          itemMarkHeight: 10,\n          labelStyle: { fontSize: 13, fontWeight: 500 },\n        },\n      }}\n    >\n      <Overlay />\n      <ChartTitle />\n    </ScatterChart>\n  );\n}\n"}