{"spec_id":"pp-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// pp-basic: Probability-Probability (P-P) Plot\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 90/100 | Created: 2026-06-09\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data -------------------------------------------------------------------\n// Deterministic LCG for reproducibility (no seeded Math.random in browser)\nlet rngState = 42;\nfunction lcgRand() {\n  rngState = ((rngState * 1664525 + 1013904223) | 0) >>> 0;\n  return rngState / 4294967296;\n}\n\nfunction randNormal() {\n  const u1 = lcgRand();\n  const u2 = lcgRand();\n  return Math.sqrt(-2 * Math.log(u1 + 1e-10)) * Math.cos(2 * Math.PI * u2);\n}\n\n// 200 process measurement samples with mild right skew (positive half-normal component)\nconst n = 200;\nconst rawData = [];\nfor (let i = 0; i < n; i++) {\n  const z = randNormal();\n  const skew = Math.max(0, randNormal()) * 0.35;\n  rawData.push(z + skew);\n}\n\n// Fit normal distribution parameters to the sample\nconst mean = rawData.reduce((a, b) => a + b, 0) / n;\nconst variance = rawData.reduce((a, b) => a + (b - mean) ** 2, 0) / n;\nconst std = Math.sqrt(variance);\n\n// Normal CDF via Abramowitz & Stegun 7.1.26 (|error| < 1.5e-7)\nfunction normalCDF(x) {\n  const z = (x - mean) / (std * Math.SQRT2);\n  const absZ = Math.abs(z);\n  const t2 = 1 / (1 + 0.3275911 * absZ);\n  const poly =\n    (0.254829592 +\n      t2 * (-0.284496736 + t2 * (1.421413741 + t2 * (-1.453152027 + t2 * 1.061405429)))) *\n    t2;\n  const erfc = poly * Math.exp(-absZ * absZ);\n  return z >= 0 ? 1 - 0.5 * erfc : 0.5 * erfc;\n}\n\n// Sort and compute empirical CDF with Weibull plotting positions i/(n+1)\nconst sorted = [...rawData].sort((a, b) => a - b);\nconst scatterData = sorted.map((x, i) => [normalCDF(x), (i + 1) / (n + 1)]);\n\n// --- Init -------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option -----------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  textStyle: { color: t.inkSoft },\n\n  title: {\n    text: \"pp-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 24,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: \"normal\" },\n  },\n\n  legend: {\n    data: [\"Observations\", \"Perfect fit\"],\n    bottom: 24,\n    textStyle: { color: t.inkSoft, fontSize: 14 },\n    itemGap: 24,\n  },\n\n  // Equal margins so the grid area is square (1200 - 120 - 80 = 1000 each axis)\n  grid: { left: 120, right: 80, top: 90, bottom: 110 },\n\n  xAxis: {\n    type: \"value\",\n    name: \"Theoretical Cumulative Probability\",\n    nameLocation: \"middle\",\n    nameGap: 52,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    min: 0,\n    max: 1,\n    interval: 0.25,\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { show: true, lineStyle: { color: t.inkSoft } },\n    axisTick: { show: true, lineStyle: { color: t.inkSoft } },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n\n  yAxis: {\n    type: \"value\",\n    name: \"Empirical Cumulative Probability\",\n    nameLocation: \"middle\",\n    nameGap: 68,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    min: 0,\n    max: 1,\n    interval: 0.25,\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    axisLine: { show: true, lineStyle: { color: t.inkSoft } },\n    axisTick: { show: true, lineStyle: { color: t.inkSoft } },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n\n  series: [\n    {\n      name: \"Perfect fit\",\n      type: \"line\",\n      data: [\n        [0, 0],\n        [1, 1],\n      ],\n      symbol: \"none\",\n      lineStyle: { color: t.inkSoft, width: 2.5, type: \"dashed\" },\n      z: 1,\n    },\n    {\n      name: \"Observations\",\n      type: \"scatter\",\n      data: scatterData,\n      symbolSize: 7,\n      itemStyle: {\n        color: t.palette[0],\n        opacity: 0.75,\n        borderColor: t.pageBg,\n        borderWidth: 0.5,\n      },\n      z: 2,\n    },\n  ],\n});\n"}