Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 61 additions & 38 deletions plots/manhattan-gwas/implementations/python/seaborn.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
""" pyplots.ai
""" anyplot.ai
manhattan-gwas: Manhattan Plot for GWAS
Library: seaborn 0.13.2 | Python 3.13.11
Quality: 92/100 | Created: 2025-12-31
Library: seaborn 0.13.2 | Python 3.13.13
Quality: 94/100 | Updated: 2026-05-15
"""

import os

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns


# Theme tokens
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"

# Okabe-Ito palette for alternating chromosomes
OKABE_ITO_1 = "#009E73" # bluish green (brand)
OKABE_ITO_2 = "#D55E00" # vermillion

# Data - Simulate GWAS data with realistic structure
np.random.seed(42)

Expand Down Expand Up @@ -68,72 +81,82 @@
df = pd.DataFrame(data)

# Create alternating color groups for chromosomes
df["color_group"] = df["chromosome"].apply(lambda x: int(x) % 2)
df["color_group"] = df["chromosome"].apply(lambda x: OKABE_ITO_1 if int(x) % 2 == 1 else OKABE_ITO_2)

# Configure theme-adaptive styling
sns.set_theme(
style="ticks",
rc={
"figure.facecolor": PAGE_BG,
"axes.facecolor": PAGE_BG,
"axes.edgecolor": INK_SOFT,
"axes.labelcolor": INK,
"text.color": INK,
"xtick.color": INK_SOFT,
"ytick.color": INK_SOFT,
"grid.color": INK,
"grid.alpha": 0.10,
"legend.facecolor": ELEVATED_BG,
"legend.edgecolor": INK_SOFT,
},
)

# Plot
fig, ax = plt.subplots(figsize=(16, 9))

# Create custom palette - Python Blue and a muted gray
palette = {0: "#306998", 1: "#8B9DC3"}

# Plot points using seaborn scatterplot with hue for alternating colors
sns.scatterplot(
data=df,
x="cumulative_position",
y="neg_log_p",
hue="color_group",
palette=palette,
s=15,
alpha=0.7,
edgecolor="none",
legend=False,
ax=ax,
)
fig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)

# Plot non-significant SNPs with alternating colors
for color in [OKABE_ITO_1, OKABE_ITO_2]:
subset = df[df["color_group"] == color]
ax.scatter(
subset["cumulative_position"], subset["neg_log_p"], c=color, s=20, alpha=0.7, edgecolor="none", rasterized=True
)

# Highlight significant SNPs (above genome-wide threshold)
significant = df[df["neg_log_p"] > 7.3]
if len(significant) > 0:
ax.scatter(
significant["cumulative_position"],
significant["neg_log_p"],
c="#FFD43B", # Python Yellow for significant hits
s=40,
edgecolor="black",
linewidth=0.5,
c=OKABE_ITO_1,
s=60,
alpha=0.9,
edgecolor=INK,
linewidth=0.8,
zorder=5,
)

# Genome-wide significance threshold
ax.axhline(y=7.3, color="#D62728", linestyle="--", linewidth=2, label="Genome-wide significance (p < 5×10⁻⁸)")
ax.axhline(y=7.3, color=INK_SOFT, linestyle="--", linewidth=2, alpha=0.6, label="Genome-wide significance (p < 5×10⁻⁸)")

# Suggestive threshold
ax.axhline(y=5, color="#7F7F7F", linestyle=":", linewidth=1.5, label="Suggestive (p < 1×10⁻⁵)")
ax.axhline(y=5, color=INK_SOFT, linestyle=":", linewidth=1.5, alpha=0.4, label="Suggestive (p < 1×10⁻⁵)")

# Set x-axis ticks at chromosome centers
ax.set_xticks([chrom_centers[c] for c in chromosomes])
ax.set_xticklabels(chromosomes)
ax.set_xticklabels(chromosomes, fontsize=16)

# Styling
ax.set_xlabel("Chromosome", fontsize=20)
ax.set_ylabel("-log₁₀(p-value)", fontsize=20)
ax.set_title("manhattan-gwas · seaborn · pyplots.ai", fontsize=24)
ax.tick_params(axis="both", labelsize=14)
ax.tick_params(axis="x", labelsize=12)
ax.set_xlabel("Chromosome", fontsize=20, color=INK)
ax.set_ylabel("-log₁₀(p-value)", fontsize=20, color=INK)
ax.set_title("manhattan-gwas · seaborn · anyplot.ai", fontsize=24, fontweight="medium", color=INK)
ax.tick_params(axis="both", labelsize=16)

# Set axis limits
ax.set_xlim(0, cumulative_pos)
ax.set_ylim(0, max(df["neg_log_p"]) * 1.05)

# Remove top and right spines for cleaner look
# Remove top and right spines
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["left"].set_color(INK_SOFT)
ax.spines["bottom"].set_color(INK_SOFT)

# Add legend
ax.legend(loc="upper right", fontsize=14, framealpha=0.9)
ax.legend(loc="upper right", fontsize=16, framealpha=0.95, edgecolor=INK_SOFT)

# Subtle grid on y-axis only
ax.yaxis.grid(True, alpha=0.3, linestyle="-")
ax.yaxis.grid(True, alpha=0.10, linewidth=0.8)
ax.xaxis.grid(False)

plt.tight_layout()
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG)
Loading
Loading