| """dingwall UMAP: (a) PANDA-predicted class, (b) en1 genotype.""" | |
| from pathlib import Path | |
| import warnings | |
| warnings.filterwarnings("ignore") | |
| import numpy as np | |
| import pandas as pd | |
| import anndata as ad | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt | |
| import umap | |
| import os as _os | |
| from pathlib import Path as _Path | |
| PANDA_ROOT = _Path(_os.environ.get("PANDA_ROOT", str(_Path(__file__).resolve().parents[2]))) | |
| FIG = Path(str(PANDA_ROOT / "figures")) | |
| FIG.mkdir(exist_ok=True) | |
| CLASS_COLORS = { | |
| "fibroblast-reticular": "#66c2a5", | |
| "basal-IFE": "#fc8d62", | |
| "endothelial": "#8da0cb", | |
| "immune": "#e78ac3", | |
| "fibroblast-papillary": "#a6d854", | |
| "melanocyte": "#ffd92f", | |
| "spinous": "#e5c494", | |
| "granular": "#b3b3b3", | |
| "HF-ORS": "#1b9e77", | |
| "HF-DP": "#d95f02", | |
| "HF-placode": "#7570b3", | |
| "eccrine-duct": "#666666", | |
| "eccrine-placode": "#000000", | |
| } | |
| def main(): | |
| p = ad.read_h5ad(str(PANDA_ROOT / "discovery/pan_skin/marker/50_aldrich_projections.h5ad")) | |
| print(f"[umap] Dingwall projection shape {p.shape}", flush=True) | |
| if "Z_projection" not in p.obsm: | |
| print(f"[umap] no Z_projection in obsm; keys: {list(p.obsm.keys())}") | |
| return | |
| Z = np.asarray(p.obsm["Z_projection"]) | |
| print(f"[umap] Z shape {Z.shape}", flush=True) | |
| print(f"[umap] fitting UMAP …", flush=True) | |
| reducer = umap.UMAP(n_neighbors=30, min_dist=0.3, random_state=42, | |
| metric="cosine", n_components=2) | |
| emb = reducer.fit_transform(Z) | |
| print(f"[umap] UMAP done, emb shape {emb.shape}", flush=True) | |
| pred = p.obs["pred_bbse_label"] if "pred_bbse_label" in p.obs else p.obs.get("pred_label") | |
| genotype = p.obs.get("genotype", pd.Series(index=p.obs.index, data="unknown")) | |
| fig, axes = plt.subplots(1, 2, figsize=(14, 6)) | |
| ax = axes[0] | |
| for cls in pred.unique(): | |
| m = pred == cls | |
| ax.scatter(emb[m, 0], emb[m, 1], s=1.5, alpha=0.4, | |
| c=CLASS_COLORS.get(cls, "#999999"), label=f"{cls} (n={int(m.sum())})") | |
| ax.set_title("Dingwall (25,344 cells) — PANDA-predicted class (BBSE)") | |
| ax.set_xlabel("UMAP 1"); ax.set_ylabel("UMAP 2") | |
| ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left", fontsize=7, | |
| markerscale=6, frameon=False) | |
| ax = axes[1] | |
| gcolors = {"WT": "#2b83ba", "En1-cKO": "#d7191c", "unknown": "#999999"} | |
| for g in ["WT", "En1-cKO"]: | |
| m = genotype == g | |
| ax.scatter(emb[m, 0], emb[m, 1], s=1.5, alpha=0.35, | |
| c=gcolors[g], label=f"{g} (n={int(m.sum())})") | |
| ax.set_title("Dingwall — En1 genotype") | |
| ax.set_xlabel("UMAP 1"); ax.set_ylabel("UMAP 2") | |
| ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left", markerscale=6, frameon=False) | |
| plt.tight_layout() | |
| plt.savefig(FIG / "fig5_dingwall_umap.pdf", bbox_inches="tight") | |
| plt.close() | |
| print(f"[umap] wrote {FIG}/fig5_dingwall_umap.pdf") | |
| if __name__ == "__main__": | |
| main() | |