{"spec_id":"manhattan-gwas","library":"echarts","language":"javascript","code":"// anyplot.ai\n// manhattan-gwas: Manhattan Plot for GWAS\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 94/100 | Created: 2026-09-05\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Deterministic PRNG (32-bit LCG via Math.imul, never returns exactly 0) -\nlet seed = 42;\nfunction rand() {\n  seed = (Math.imul(seed, 1103515245) + 12345) | 0;\n  return (seed >>> 0) / 4294967296 + 1e-9;\n}\n\n// --- Chromosome layout (approximate GRCh38 lengths, Mb) ---------------------\nconst CHROMOSOMES = [\n  [\"1\", 249],\n  [\"2\", 243],\n  [\"3\", 198],\n  [\"4\", 190],\n  [\"5\", 182],\n  [\"6\", 171],\n  [\"7\", 159],\n  [\"8\", 145],\n  [\"9\", 138],\n  [\"10\", 134],\n  [\"11\", 135],\n  [\"12\", 133],\n  [\"13\", 114],\n  [\"14\", 107],\n  [\"15\", 102],\n  [\"16\", 90],\n  [\"17\", 83],\n  [\"18\", 80],\n  [\"19\", 59],\n  [\"20\", 64],\n  [\"21\", 47],\n  [\"22\", 51],\n  [\"X\", 156],\n];\n\n// --- Simulated GWAS association peaks (chromosome index, position fraction,\n// peak height added to the null -log10(p), and width of the LD-decay window) -\nconst PEAKS = [\n  { chrIdx: 1, frac: 0.62, height: 12.5, width: 1.2 }, // chr2 — genome-wide hit\n  { chrIdx: 5, frac: 0.3, height: 9.8, width: 1.0 }, // chr6 — genome-wide hit\n  { chrIdx: 8, frac: 0.75, height: 15.4, width: 1.4 }, // chr9 — strongest hit\n  { chrIdx: 11, frac: 0.55, height: 6.4, width: 0.9 }, // chr12 — suggestive only\n  { chrIdx: 14, frac: 0.45, height: 8.1, width: 0.8 }, // chr15 — genome-wide hit\n  { chrIdx: 22, frac: 0.2, height: 10.6, width: 1.1 }, // chrX — genome-wide hit\n];\n\nconst GENOME_WIDE = 7.3; // -log10(5e-8)\nconst SUGGESTIVE = 5; // -log10(1e-5)\n\n// --- Build points -------------------------------------------------------------\nlet offset = 0;\nconst primaryChr = []; // odd-numbered chromosomes (1, 3, 5, ...) — brand green\nconst secondaryChr = []; // even-numbered chromosomes (2, 4, 6, ...) — blue\nconst significant = []; // genome-wide significant SNPs — matte red\nconst tickPositions = [];\n\nCHROMOSOMES.forEach(([, lengthMb], idx) => {\n  const nPoints = Math.round(lengthMb * 30);\n  const peak = PEAKS.find((p) => p.chrIdx === idx);\n  for (let i = 0; i < nPoints; i += 1) {\n    const posMb = rand() * lengthMb;\n    let negLogP = -Math.log10(rand());\n    if (peak) {\n      const dist = posMb - peak.frac * lengthMb;\n      negLogP +=\n        peak.height * Math.exp(-(dist * dist) / (2 * peak.width * peak.width));\n    }\n    negLogP = Math.min(negLogP, 20);\n    const point = [offset + posMb, negLogP];\n    if (negLogP >= GENOME_WIDE) significant.push(point);\n    else if (idx % 2 === 0) primaryChr.push(point);\n    else secondaryChr.push(point);\n  }\n  tickPositions.push(offset + lengthMb / 2);\n  offset += lengthMb;\n});\n\nconst totalLength = offset;\nconst chrNameByTick = new Map(\n  tickPositions.map((pos, idx) => [pos, CHROMOSOMES[idx][0]]),\n);\n\n// --- Chart --------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  color: t.palette,\n  title: {\n    text: \"manhattan-gwas · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 24,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n  },\n  grid: { left: 100, right: 60, top: 100, bottom: 90 },\n  xAxis: {\n    type: \"value\",\n    min: 0,\n    max: totalLength,\n    name: \"Chromosome\",\n    nameLocation: \"center\",\n    nameGap: 44,\n    nameTextStyle: { color: t.inkSoft, fontSize: 16 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n    axisLabel: {\n      color: t.inkSoft,\n      fontSize: 14,\n      customValues: tickPositions,\n      formatter: (value) => chrNameByTick.get(value) ?? \"\",\n    },\n  },\n  yAxis: {\n    type: \"value\",\n    name: \"-log10(p)\",\n    nameLocation: \"end\",\n    nameGap: 20,\n    nameTextStyle: { color: t.inkSoft, fontSize: 16, align: \"left\" },\n    min: 0,\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisLabel: { color: t.inkSoft, fontSize: 14 },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  series: [\n    {\n      name: \"Odd chromosomes\",\n      type: \"scatter\",\n      data: primaryChr,\n      symbolSize: 6,\n      itemStyle: { color: t.palette[0], opacity: 0.75 },\n      markLine: {\n        symbol: \"none\",\n        silent: true,\n        animation: false,\n        lineStyle: { type: \"dashed\", width: 2 },\n        label: {\n          show: true,\n          position: \"insideStartTop\",\n          align: \"left\",\n          color: t.inkSoft,\n          fontSize: 13,\n          formatter: \"{b}\",\n          padding: [4, 8],\n        },\n        data: [\n          {\n            yAxis: GENOME_WIDE,\n            name: \"Genome-wide (p<5×10⁻⁸)\",\n            lineStyle: { color: t.palette[4] },\n          },\n          {\n            yAxis: SUGGESTIVE,\n            name: \"Suggestive (p<1×10⁻⁵)\",\n            lineStyle: { color: t.amber },\n          },\n        ],\n      },\n    },\n    {\n      name: \"Even chromosomes\",\n      type: \"scatter\",\n      data: secondaryChr,\n      symbolSize: 6,\n      itemStyle: { color: t.palette[1], opacity: 0.75 },\n    },\n    {\n      name: \"Genome-wide significant\",\n      type: \"scatter\",\n      data: significant,\n      symbolSize: 8,\n      itemStyle: { color: t.palette[4], opacity: 0.95 },\n    },\n  ],\n});\n\nchart.on(\"finished\", () => {\n  window.__anyplotReady = true;\n});\n"}