{"spec_id":"manhattan-gwas","library":"muix","language":"javascript","code":"// anyplot.ai\n// manhattan-gwas: Manhattan Plot for GWAS\n// Library: muix 7.29.1 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-05\nimport { ScatterChart } from \"@mui/x-charts/ScatterChart\";\nimport { ChartsReferenceLine } from \"@mui/x-charts/ChartsReferenceLine\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Deterministic PRNG (LCG, no seeded Math.random in the browser) ---------\nlet seed = 42;\nfunction rand() {\n  seed = (seed * 1664525 + 1013904223) % 4294967296;\n  return seed / 4294967296;\n}\n\n// --- Chromosome layout (approximate relative lengths, Mb) -------------------\nconst CHROM_LENGTHS = [\n  248, 242, 198, 190, 181, 170, 159, 145, 138, 133, 135, 133, 114, 107, 101, 90,\n  83, 80, 58, 63, 46, 50,\n];\n\nlet cursor = 0;\nconst chromRanges = CHROM_LENGTHS.map((length, i) => {\n  const start = cursor;\n  cursor += length;\n  return { label: String(i + 1), start, length, center: start + length / 2 };\n});\nconst genomeLength = cursor;\n\n// --- Simulated association signal -------------------------------------------\n// Null-model baseline: for p ~ Uniform(0,1), -log10(p) is Exponential(ln 10).\n// A few chromosomes additionally carry a genuine association peak — a dense\n// cluster of points near one locus whose height decays with distance from it.\nconst PEAK_CHROM_INDICES = [5, 10, 16]; // chr6, chr11, chr17 (0-indexed)\nconst PEAK_HEIGHTS = [14.5, 9.6, 11.3];\n\nconst GENOME_WIDE_SIGNIFICANCE = -Math.log10(5e-8); // ≈ 7.3\nconst SUGGESTIVE_THRESHOLD = -Math.log10(1e-5); // 5\n\nconst oddPoints = [];\nconst evenPoints = [];\nconst significantPoints = [];\nlet pointId = 0;\n\nfunction pushPoint(chromIndex, position, negLogP) {\n  const y = Math.min(negLogP, 16);\n  const point = { x: position, y, id: pointId };\n  pointId += 1;\n  if (y >= GENOME_WIDE_SIGNIFICANCE) {\n    significantPoints.push(point);\n  } else if (chromIndex % 2 === 0) {\n    oddPoints.push(point);\n  } else {\n    evenPoints.push(point);\n  }\n}\n\nchromRanges.forEach((range, chromIndex) => {\n  // Baseline scatter across the whole chromosome.\n  const numPoints = Math.round(range.length / 3);\n  for (let i = 0; i < numPoints; i += 1) {\n    const position = range.start + rand() * range.length;\n    const negLogP = -Math.log(rand()) / Math.LN10;\n    pushPoint(chromIndex, position, negLogP);\n  }\n\n  // Associated locus: a denser cluster around a peak position, height\n  // decaying with distance (an approximate-normal jitter via Irwin-Hall).\n  const peakIdx = PEAK_CHROM_INDICES.indexOf(chromIndex);\n  if (peakIdx >= 0) {\n    const peakPos = range.start + range.length * (0.3 + rand() * 0.4);\n    const peakHeight = PEAK_HEIGHTS[peakIdx];\n    const spread = range.length * 0.08;\n    for (let i = 0; i < 45; i += 1) {\n      const jitter = (rand() + rand() + rand() - 1.5) * spread;\n      const position = Math.min(Math.max(peakPos + jitter, range.start), range.start + range.length);\n      const distance = (position - peakPos) / (spread * 2);\n      const negLogP = -Math.log(rand()) / Math.LN10 + peakHeight * Math.exp(-distance * distance);\n      pushPoint(chromIndex, position, negLogP);\n    }\n  }\n});\n\nconst centerToLabel = new Map(chromRanges.map((r) => [r.center, r.label]));\nconst tickCenters = chromRanges.map((r) => r.center);\n\n// Dense baseline/peak points get a touch of transparency to combat\n// overplotting in the association clusters; the sparse highlighted hits\n// below stay fully opaque.\nconst MARKER_ALPHA = \"CC\"; // ~80% opacity, appended as 8-digit hex alpha\n\n// --- Chart (default-exported component — the harness mounts it) -------------\nexport default function Chart() {\n  const W = window.ANYPLOT_SIZE.width;\n  const H = window.ANYPLOT_SIZE.height;\n  const TITLE_H = 54;\n\n  return (\n    <div\n      style={{\n        width: W,\n        height: H,\n        background: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        fontFamily: \"'Roboto', 'Helvetica Neue', Arial, sans-serif\",\n      }}\n    >\n      <div\n        style={{\n          height: TITLE_H,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          fontSize: 26,\n          fontWeight: 600,\n          color: t.ink,\n          letterSpacing: 0.15,\n        }}\n      >\n        manhattan-gwas · javascript · muix · anyplot.ai\n      </div>\n      <ScatterChart\n        width={W}\n        height={H - TITLE_H}\n        series={[\n          {\n            id: \"odd\",\n            label: \"Odd chromosomes\",\n            color: `${t.palette[0]}${MARKER_ALPHA}`,\n            markerSize: 3,\n            data: oddPoints,\n          },\n          {\n            id: \"even\",\n            label: \"Even chromosomes\",\n            color: `${t.palette[1]}${MARKER_ALPHA}`,\n            markerSize: 3,\n            data: evenPoints,\n          },\n          {\n            id: \"significant\",\n            label: \"Genome-wide significant\",\n            color: `${t.amber}${MARKER_ALPHA}`,\n            markerSize: 5,\n            data: significantPoints,\n          },\n        ]}\n        xAxis={[\n          {\n            scaleType: \"linear\",\n            min: 0,\n            max: genomeLength,\n            label: \"Chromosome\",\n            tickInterval: tickCenters,\n            valueFormatter: (value) => centerToLabel.get(value) ?? \"\",\n            tickLabelStyle: { fontSize: 13 },\n            labelStyle: { fontSize: 15 },\n          },\n        ]}\n        yAxis={[\n          {\n            scaleType: \"linear\",\n            min: 0,\n            label: \"-log10(p-value)\",\n            tickLabelStyle: { fontSize: 13 },\n            labelStyle: { fontSize: 15 },\n          },\n        ]}\n        grid={{ horizontal: true }}\n        disableVoronoi\n        skipAnimation\n        slotProps={{ legend: { position: { vertical: \"top\", horizontal: \"middle\" } } }}\n      >\n        <ChartsReferenceLine\n          y={GENOME_WIDE_SIGNIFICANCE}\n          label=\"Genome-wide significance (p < 5×10⁻⁸)\"\n          labelAlign=\"end\"\n          lineStyle={{ stroke: t.amber, strokeDasharray: \"8 6\", strokeWidth: 2 }}\n          labelStyle={{ fill: t.ink, fontSize: 13 }}\n        />\n        <ChartsReferenceLine\n          y={SUGGESTIVE_THRESHOLD}\n          label=\"Suggestive (p < 1×10⁻⁵)\"\n          labelAlign=\"end\"\n          lineStyle={{ stroke: t.inkSoft, strokeDasharray: \"4 4\", strokeWidth: 1.5 }}\n          labelStyle={{ fill: t.inkSoft, fontSize: 12 }}\n        />\n      </ScatterChart>\n    </div>\n  );\n}\n"}