"""test if veres alpha-pool polyhormonal (Ins+/Gcg+/Sst+) cells form a distinct sub-cluster vs graded.""" from __future__ import annotations import json import warnings from pathlib import Path import anndata as ad import numpy as np import pandas as pd import scanpy as sc warnings.filterwarnings("ignore") sc.settings.verbosity = 0 import os as _os from pathlib import Path as _Path PANDA_ROOT = _Path(_os.environ.get("PANDA_ROOT", str(_Path(__file__).resolve().parents[2]))) ROOT = Path(str(PANDA_ROOT)) OUT = ROOT / "discovery/pancreas/marker" OUT.mkdir(parents=True, exist_ok=True) VERES = ROOT / "data/corpus/pancreas/held_out_labeled/veres_GSE114412_test.h5ad" PRED = ROOT / "discovery/pancreas/marker/veres_predictions.csv" def col(sub, g): if g not in sub.var_names: return np.zeros(sub.n_obs) j = sub.var_names.get_loc(g) x = sub.X[:, j] if hasattr(x, "toarray"): x = x.toarray() return np.asarray(x).ravel() def main(): print("[load]", flush=True) a = ad.read_h5ad(VERES) pred = pd.read_csv(PRED) pred_map = dict(zip(pred["cell_id"].astype(str), pred["pred_label"])) a.obs["pred_label"] = pd.Categorical( [pred_map.get(c, "unknown") for c in a.obs_names]) sub = a[a.obs["pred_label"].astype(str).isin( ["alpha_progenitor", "alpha"])].copy() print(f"[filter] {sub.n_obs} alpha-pool cells", flush=True) ins1 = col(sub, "Ins1"); ins2 = col(sub, "Ins2") gcg = col(sub, "Gcg"); sst = col(sub, "Sst"); iapp = col(sub, "Iapp") ins_level = ins1 + ins2 q_ins = np.quantile(ins_level, 0.75) q_gcg = np.quantile(gcg, 0.75) q_sst = np.quantile(sst, 0.75) n_pos = ( (ins_level >= q_ins).astype(int) + (gcg >= q_gcg).astype(int) + (sst >= q_sst).astype(int) ) sub.obs["INS_level"] = ins_level sub.obs["GCG_level"] = gcg sub.obs["SST_level"] = sst sub.obs["n_hormones_positive"] = n_pos print("[cluster] PCA + Leiden", flush=True) sc.pp.highly_variable_genes(sub, n_top_genes=2000, flavor="seurat_v3", subset=False, batch_key=None) sc.pp.pca(sub, n_comps=30) sc.pp.neighbors(sub, n_neighbors=15, n_pcs=30) sc.tl.leiden(sub, resolution=0.5, random_state=0, key_added="leiden_alpha") df = sub.obs[[ "pred_label", "paper_label", "leiden_alpha", "INS_level", "GCG_level", "SST_level", "n_hormones_positive" ]].copy() df["Ins1"] = ins1; df["Ins2"] = ins2; df["Gcg"] = gcg df["Sst"] = sst; df["Iapp"] = iapp df.reset_index().rename(columns={"index": "cell_id"}).to_csv( OUT / "110_veres_polyhormonal_alpha_scores.csv", index=False) baseline_polyhormonal = float((df["n_hormones_positive"] >= 2).mean()) per_clus = df.groupby("leiden_alpha", observed=True).agg( n_cells=("n_hormones_positive", "size"), frac_polyhormonal=("n_hormones_positive", lambda s: float((s >= 2).mean())), frac_gcg_hi=("GCG_level", lambda s: float((s >= q_gcg).mean())), frac_ins_hi=("INS_level", lambda s: float((s >= q_ins).mean())), frac_sst_hi=("SST_level", lambda s: float((s >= q_sst).mean())), mean_gcg=("GCG_level", "mean"), mean_ins=("INS_level", "mean"), mean_sst=("SST_level", "mean"), ).sort_values("frac_polyhormonal", ascending=False).reset_index() per_clus["enrichment_vs_baseline"] = per_clus["frac_polyhormonal"] \ / max(baseline_polyhormonal, 1e-6) per_clus.to_csv(OUT / "110_veres_polyhormonal_alpha_per_cluster.csv", index=False) n_2x_clusters = int((per_clus["enrichment_vs_baseline"] >= 2.0).sum()) verdict = ("distinct_polyhormonal_subcluster" if n_2x_clusters in (1, 2) else "graded_phenotype" if n_2x_clusters == 0 else "diffuse_enrichment") summary = { "n_alpha_pool": int(sub.n_obs), "baseline_polyhormonal_frac": round(baseline_polyhormonal, 4), "q75_thresholds": {"Ins": float(q_ins), "Gcg": float(q_gcg), "Sst": float(q_sst)}, "leiden_resolution": 0.5, "n_clusters": int(per_clus["leiden_alpha"].nunique()), "n_clusters_enriched_2x": n_2x_clusters, "verdict": verdict, "per_cluster": per_clus.to_dict("records"), } with open(OUT / "110_veres_polyhormonal_alpha_summary.json", "w") as f: json.dump(summary, f, indent=2) print("\n[done] verdict:", verdict, flush=True) print(per_clus.round(3).to_string(index=False)) if __name__ == "__main__": main()