{"spec_id":"manhattan-gwas","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nmanhattan-gwas: Manhattan Plot for GWAS\nLibrary: letsplot 4.9.0 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-15\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import *\n\n\nLetsPlot.setup_html()\n\n# Theme-adaptive colors\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nRULE = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette for alternating chromosomes\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\"]\n\n# Set seed for reproducibility\nnp.random.seed(42)\n\n# Generate simulated GWAS data\nn_snps_per_chrom = 2000\nchromosomes = [str(i) for i in range(1, 23)]\n\ndata = []\ncumulative_pos = 0\nchrom_centers = {}\n\nfor i, chrom in enumerate(chromosomes):\n    # Random positions within chromosome (scaled by chromosome \"size\")\n    chrom_size = 250_000_000 - i * 5_000_000\n    positions = np.sort(np.random.randint(1, chrom_size, n_snps_per_chrom))\n\n    # Generate p-values - mostly non-significant with some peaks\n    p_values = np.random.uniform(0, 1, n_snps_per_chrom)\n\n    # Add some significant peaks (simulate real GWAS signals)\n    if chrom in [\"2\", \"6\", \"11\", \"17\"]:\n        peak_idx = np.random.choice(n_snps_per_chrom, size=15, replace=False)\n        p_values[peak_idx] = 10 ** (-np.random.uniform(6, 12, 15))\n\n    # Add suggestive signals to more chromosomes\n    if chrom in [\"1\", \"5\", \"8\", \"14\", \"19\"]:\n        suggestive_idx = np.random.choice(n_snps_per_chrom, size=10, replace=False)\n        p_values[suggestive_idx] = 10 ** (-np.random.uniform(4.5, 7, 10))\n\n    # Calculate cumulative position for x-axis\n    cumulative_positions = positions + cumulative_pos\n\n    # Store chromosome center for labeling\n    chrom_centers[chrom] = cumulative_pos + chrom_size / 2\n\n    for pos, cum_pos, pval in zip(positions, cumulative_positions, p_values):\n        data.append(\n            {\n                \"chromosome\": chrom,\n                \"position\": pos,\n                \"cumulative_pos\": cum_pos,\n                \"p_value\": pval,\n                \"neg_log10_p\": -np.log10(pval),\n            }\n        )\n\n    cumulative_pos += chrom_size\n\ndf = pd.DataFrame(data)\n\n# Assign alternating colors using Okabe-Ito palette\ndf[\"chrom_idx\"] = df[\"chromosome\"].astype(int) % 2\ndf[\"color_group\"] = df[\"chrom_idx\"].map({0: IMPRINT[0], 1: IMPRINT[1]})\n\n# Significance thresholds\ngenome_wide_threshold = -np.log10(5e-8)  # ~7.3\nsuggestive_threshold = -np.log10(1e-5)  # 5\n\n# Mark significant SNPs\ndf[\"significant\"] = df[\"neg_log10_p\"] >= genome_wide_threshold\n\n# Create x-axis tick positions and labels\ntick_positions = [chrom_centers[c] for c in chromosomes]\n\n# Create the Manhattan plot\nplot = (\n    ggplot(df, aes(x=\"cumulative_pos\", y=\"neg_log10_p\", color=\"color_group\"))\n    + geom_point(size=2, alpha=0.7)\n    + scale_color_identity()\n    # Highlight significant points\n    + geom_point(\n        data=df[df[\"significant\"]],\n        mapping=aes(x=\"cumulative_pos\", y=\"neg_log10_p\"),\n        color=IMPRINT[4],\n        size=3.5,\n        alpha=0.9,\n    )\n    # Genome-wide significance threshold line\n    + geom_hline(yintercept=genome_wide_threshold, linetype=\"dashed\", color=IMPRINT[4], size=1)\n    # Suggestive threshold line\n    + geom_hline(yintercept=suggestive_threshold, linetype=\"dotted\", color=INK_MUTED, size=0.7)\n    + labs(title=\"manhattan-gwas · letsplot · anyplot.ai\", x=\"Chromosome\", y=\"-log₁₀(p-value)\")\n    + scale_x_continuous(breaks=tick_positions, labels=chromosomes)\n    + theme_minimal()\n    + theme(\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_grid_major_y=element_line(color=RULE, size=0.3),\n        panel_grid_major_x=element_blank(),\n        panel_grid_minor=element_blank(),\n        plot_title=element_text(size=28, face=\"bold\", color=INK),\n        axis_title_x=element_text(size=22, color=INK),\n        axis_title_y=element_text(size=22, color=INK),\n        axis_text_x=element_text(size=16, color=INK_SOFT),\n        axis_text_y=element_text(size=16, color=INK_SOFT),\n        axis_line_x=element_line(color=INK_SOFT, size=0.6),\n        axis_line_y=element_line(color=INK_SOFT, size=0.6),\n    )\n    + ggsize(1600, 900)\n)\n\n# Save as PNG and HTML with theme suffix\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=3)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}