Files
RGC-ADOA/script/15_umap_tsne_2x2.py
rain 092f39a662 chore: 初始化 RGC-ADOA 分析仓库
纳入 script/doc/ref/output 及配置;忽略 data/(26G 原始/中间数据)。
git 身份:rain <wjs_Rain@126.com>。
2026-09-18 18:21:19 +08:00

82 lines
3.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
15_umap_tsne_2x2.py — 2×2 降维可视化对照:UMAP / tSNE × 细胞类型 / 基因型
tSNE 在 Harmony 校正的 PCA 空间(X_pca_harmonyn_pcs=50)计算,与 UMAP 同输入,
仅作可视化对照(两者都不参与聚类与任何定量,见报告说明)。
着色:细胞类型(14 类,小群置顶以便可见)与基因型(WT vs V291D)。
产出:output/03_cluster/umap_tsne_2x2.pngtSNE 坐标写回 data/04_scored.h5ad (obsm["X_tsne"])。
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
import scanpy as sc
OUT = Path("output/03_cluster")
plt.rcParams.update({"figure.dpi": 300, "savefig.dpi": 300, "font.size": 9})
adata = sc.read_h5ad("data/04_scored.h5ad")
# ---- 计算 tSNE(若尚未计算) ----
if "X_tsne" not in adata.obsm:
sc.tl.tsne(adata, use_rep="X_pca_harmony", n_pcs=50, random_state=0, perplexity=30)
adata.write_h5ad("data/04_scored.h5ad")
print("X_tsne 就绪:", adata.obsm["X_tsne"].shape)
# ---- 细胞类型调色板(14 类,高区分度;LowConf 用灰色表"低置信度" ----
cts = adata.obs["cell_type"].astype(str)
ct_order = cts.value_counts().index.tolist() # 大类在前,先画底层
CT_COLORS = {
"Rod": "#4e79a7", "LowConf": "#a8a8a8", "Muller": "#f28e2b", "Amacrine": "#e15759",
"Bipolar": "#76b7b2", "Cone": "#59a14f", "RGC": "#edc948", "Pericyte": "#b07aa1",
"Uveal_Melanocyte": "#9c755f", "Oligodendrocyte": "#ff9da7", "Endothelial": "#8cd17d",
"Horizontal": "#86bcb6", "Microglia": "#d37295", "Astrocyte": "#f7b6d2",
}
cmap_ct = {ct: CT_COLORS[ct] for ct in ct_order}
# 小群手工放大,便于在散点中辨认
SIZE = {"Microglia": 16, "Astrocyte": 16, "RGC": 11, "Horizontal": 11, "Endothelial": 9}
ALPHA = {"Rod": 0.55, "Amacrine": 0.6, "Muller": 0.6}
fig, axes = plt.subplots(2, 2, figsize=(11, 11))
def draw(ax, emb, color_by):
if color_by == "cell_type":
# 大类先画底层,小群后画顶层
for ct in reversed(ct_order): # 反过来:最小的最后画 -> 顶层
m = (cts == ct).values
ax.scatter(emb[m, 0], emb[m, 1], s=SIZE.get(ct, 5), c=[cmap_ct[ct]],
alpha=ALPHA.get(ct, 0.75), linewidths=0, rasterized=True, label=ct)
ax.legend(markerscale=2.2, fontsize=6.5, frameon=False, loc="center left",
bbox_to_anchor=(1.0, 0.5), ncol=1)
else:
# 少数样本(WT)画顶层并放大加白边,避免被多数组(V291D)淹没
mu = (adata.obs["genotype"] == "V291D").values
wt = (adata.obs["genotype"] == "WT").values
ax.scatter(emb[mu, 0], emb[mu, 1], s=4, c="#d62728", alpha=0.30,
linewidths=0, rasterized=True, label=f"V291D (n={mu.sum()})")
ax.scatter(emb[wt, 0], emb[wt, 1], s=15, c="#1f77b4", alpha=0.95,
edgecolors="white", linewidths=0.3, rasterized=True, label=f"WT (n={wt.sum()})")
ax.legend(markerscale=2.2, fontsize=7, frameon=False, loc="best")
ax.set_xticks([]); ax.set_yticks([])
for sp in ax.spines.values():
sp.set_visible(False)
draw(axes[0, 0], adata.obsm["X_umap"], "cell_type")
draw(axes[0, 1], adata.obsm["X_umap"], "genotype")
draw(axes[1, 0], adata.obsm["X_tsne"], "cell_type")
draw(axes[1, 1], adata.obsm["X_tsne"], "genotype")
axes[0, 0].set_title("UMAP — cell type")
axes[0, 1].set_title("UMAP — genotype")
axes[1, 0].set_title("tSNE (Harmony) — cell type")
axes[1, 1].set_title("tSNE (Harmony) — genotype")
fig.suptitle("UMAP vs tSNE embedding comparison (both on Harmony-corrected PCA)", y=0.98)
fig.tight_layout(rect=[0, 0, 1, 0.96])
fig.savefig(OUT / "umap_tsne_2x2.png", bbox_inches="tight")
print("Done ->", OUT / "umap_tsne_2x2.png")