Skills › Scientific Agent Skills › scanpy › plot.py
plot.py
80 lines · skills/scanpy/scripts/plot.py at 5f2bc03
1#!/usr/bin/env python3
2"""
3Generate common single-cell plots from a processed AnnData object.
5A flexible plotting front-end so the agent doesn't hand-write matplotlib /
6scanpy plotting calls. Pick a plot type and the keys/genes to show.
8Plot types:
9 umap / tsne / pca : embedding colored by --color obs columns and/or --genes
10 violin : --genes (or QC metrics) split by --groupby
11 dotplot / matrixplot / heatmap / tracksplot / stacked_violin : --genes by --groupby
13Examples:
14 python plot.py annotated.h5ad --kind umap --color leiden cell_type
15 python plot.py annotated.h5ad --kind umap --genes CD3D MS4A1 NKG7 --use-raw
16 python plot.py annotated.h5ad --kind dotplot --genes CD3D CD14 MS4A1 --groupby cell_type
17 python plot.py annotated.h5ad --kind violin --genes CD3D --groupby leiden
18"""
20import argparse
22from _common import configure_scanpy, die, info, load_anndata
25def main():
26 p = argparse.ArgumentParser(description=__doc__,
27 formatter_class=argparse.RawDescriptionHelpFormatter)
28 p.add_argument("input", help="Input .h5ad")
29 p.add_argument("--kind", required=True,
30 choices=["umap", "tsne", "pca", "violin", "dotplot",
31 "matrixplot", "heatmap", "tracksplot", "stacked_violin"])
32 p.add_argument("--color", nargs="+", default=None, help="obs columns to color by")
33 p.add_argument("--genes", nargs="+", default=None, help="genes to display")
34 p.add_argument("--groupby", default=None, help="obs column to group by (violin/dotplot/...)")
35 p.add_argument("--use-raw", action="store_true", help="Use adata.raw (normalized log values)")
36 p.add_argument("--figdir", default="figures", help="Figure output directory")
37 p.add_argument("--save", default=None, help="Filename suffix (default derived from --kind)")
38 args = p.parse_args()
40 sc = configure_scanpy(figdir=args.figdir)
41 adata = load_anndata(args.input)
42 # scanpy prepends the plot-function name, so ".png" yields e.g. "umap.png".
43 save = args.save or ".png"
44 if args.use_raw and adata.raw is None:
45 die("--use-raw requested but .raw is missing")
46 use_raw = args.use_raw
48 var_names = adata.raw.var_names if use_raw else adata.var_names
49 genes = [g for g in (args.genes or []) if g in var_names]
50 if args.genes and len(genes) < len(args.genes):
51 missing = set(args.genes) - set(genes)
52 info(f"Genes not found (skipped): {sorted(missing)}")
54 if args.kind in ("umap", "tsne", "pca"):
55 color = (args.color or []) + genes
56 if not color:
57 die("provide --color and/or --genes for embedding plots")
58 fn = {"umap": sc.pl.umap, "tsne": sc.pl.tsne, "pca": sc.pl.pca}[args.kind]
59 fn(adata, color=color, use_raw=use_raw, show=False, save=save)
60 elif args.kind == "violin":
61 keys = genes or [c for c in (args.color or []) if c in adata.obs.columns]
62 if not keys:
63 die("provide --genes (or obs keys via --color) for violin")
64 sc.pl.violin(adata, keys, groupby=args.groupby, use_raw=use_raw,
65 show=False, save=save)
66 else:
67 if not genes or not args.groupby:
68 die(f"{args.kind} requires --genes and --groupby")
69 fn = {
70 "dotplot": sc.pl.dotplot, "matrixplot": sc.pl.matrixplot,
71 "heatmap": sc.pl.heatmap, "tracksplot": sc.pl.tracksplot,
72 "stacked_violin": sc.pl.stacked_violin,
73 }[args.kind]
74 fn(adata, genes, groupby=args.groupby, use_raw=use_raw, show=False, save=save)
76 info(f"Saved {args.figdir}/{args.kind}{save}")
79if __name__ == "__main__":
80 main()