Imported from huangch/hplot (
AGENTS.md). Install upstream withnpx skills add huangch/hplot. Copyright stays with the author.
hplot — Agent Guide
H-Plot: Kaplan-Meier-style curves of tissue composition vs signed distance from a tissue boundary (e.g. tumor–stroma interface). Layer 0 = boundary, >0 inside, <0 outside; per-layer CI across cases. Python >=3.11, Apache-2.0, v0.1.0.
What this package is
The user-facing analysis layer of the ecosystem. It is a library + thin CLI, not a data pipeline, and it sits downstream of the pipelines:
wsinsight / sptxinsight -> CSV / h5ad / GeoJSON on disk
|
v
hplot (Jupyter environment)
|
v
clawpyter drives it
- Installed in the JupyterLab environment, where
clawpyterdrives it to analyse outputs the pipelines have already written. - The pipelines do NOT depend on this package.
wsinsightandsptxinsighteach ship their owninsightlib/and neither importshplot. That is deliberate — do not "de-duplicate" by making a pipeline import this package; it would invert the layering. - Their
hplot/hplot-finalizesubcommands are a name collision only: those run the pipeline's owninsightlib.insight_helpers.compute_hplot, which is a separate implementation from theHPlotclass here.
Layout
cli.py—hplotentry point (hplot.cli:main); includeshplot schema, which serialises themcp/schema.pycommand table.core.py—HPlotfit (Stage 0: per-layer mean ± CI).stats.py— inference:gradient_cluster_mass_screen(Stage 1: Mann-Whitney U per layer, contiguous significant runs as statistic, slide-level sign-flip permutation null, FDR),deviation_tensor,directional_cluster_bands.pathways.py— H-Pathway: rank-baseducell_scores+pathway_layer_profile. Deliberately no self-contained per-cell UCell-average test — that's false-positive-prone on targeted panels. Scoring is separated from inference on purpose; don't "simplify" it back.plotting.py—plot_hloci_bands/strip/fdr/dotplot,plot_hpathway_dotplot, etc.tl.py/pp.py/pl.py— scanpy-style layers;_anndata.py— AnnData I/O.mcp/—hplot-mcpFastMCP server (optionalmcpextra).
The three stages (don't conflate)
- Stage 0 — per-layer mean ± CI (
HPlot.fit()). - Stage 1 — cluster-mass permutation test (handles spatial autocorrelation).
- Stage 2 — GAM effect size + confounder adjustment (pygam, penalised B-spline, GCV smoothing).
H-Loci summary: deviation_tensor → cross-slide signed z → cluster-mass bands → sign-flip null → FDR; its gene_bands table feeds H-Pathway ORA (hpathway_layer_ora = competitive counting of flagged genes per pathway).
How it differs from squidpy var_by_distance
squidpy: unsigned distance from anchor points + polynomial fit, descriptive only. hplot: signed border layers + cohort-level inference (CI, permutation, GAM). If asked "why not just use squidpy", that's the answer.
MCP server (hplot-mcp)
- Entry point
hplot.mcp.__main__:main; extramcp = ["fastmcp>=4.0,<5"]. stdio by default;--http HOST:PORT(suggested port 8767, after wsinsight 8765 / sptxinsight 8766).--max-concurrent N(default 1 — pure CPU). - The tool surface is a hand-written command table in
hplot/mcp/schema.py(one entry per sub-command) — unlike wsinsight, which generates one. Keep it in sync withhplot/cli.pywhenever the CLI changes. hplot schemaserialises that same table, so the CLI and MCP surfaces cannot drift. Every engine in the family exposes<cli> schemaemitting{"schema_version": 1, "commands": {...}}.- Tools: one per sub-command, faithful per-parameter mirrors of
hplot <sub> --help. Long-running (test,screen,loci— permutation-heavy) return ajob_id; polljob_status/job_logs/cancel_job/list_jobs. Short (plot,gam) run synchronously (600 s timeout) and return{status, returncode, argv, duration_s, log_tail}. - Resource
hplot://schema(the command table) + prompthplot_workflow. - Adapter (
hplot/mcp/adapters.py) translates snake_case args → kebab-case--flags; bool flags only when truthy;nargsargs repeated; no positional args.
Tests
python -m pytest test/(note:test/, nottests/).- No CI workflow in this repo (no
.github/); it's validated from the sibling repos' pipelines.
Environment
- Standalone env:
sh ./conda-setup.sh hplot [-r|--reset] [-m|--mcp] [-d|--dev]— creates a py3.11 env with the core deps (matplotlib/pandas/scipy/numpy/pygam/anndata). No GPU/CUDA stack needed (pure CPU plotting + stats). The-m/--mcpflag addsfastmcp(thehplot-mcpserver); not installed by default (matching the wsinsight/sptxinsight convention). Add-d/--devto also install pytest/pytest-cov/ruff/pre_commit for running the test suite; add-r/--resetto nuke and recreate the env. Run./conda-setup.sh --helpfor the full CLI. - Docker:
./docker-build-push.shbuildshplot:latestand pusheshuangchtw/hplot:latest. The image ships auser(uid 1000) and an entrypoint that remaps it to the mount owner at run time (same pattern as wsinsight).fastmcpis baked in, sohplot-mcpworks in the image without an extra install.
Running hplot (the unified wrapper)
./hplot.shis the single entry point for runninghplot. It manages BOTH runners —native(the hplot CLI on the host inside the activated conda env) anddocker(thehuangchtw/hplot:latestcontainer). The legacyhplot-docker-run.shwrapper has moved tobak_old_scripts/.- Subcommands:
./hplot.sh run [--runner native|docker] [--tmpdir DIR] [--no-pull] [--dry-run] [HPLOT_ARGS ...],./hplot.sh status,./hplot.sh doctor,./hplot.sh where. Run./hplot.sh --helpfor the full surface. - Why
--runner, not-b: hplot's CLI happens to have no global--backendflag, so-bwould have worked, but we standardize on--runneracross wrappers for cross-tool consistency. (If hplot ever gains a conflicting global flag, this avoids surprise.) - Param-parsing rule: everything before the first hplot subcommand name (
plot,test,gam,screen,loci,schema) is consumed by the wrapper. From (and including) the first hplot subcommand name onward, every token is passed through verbatim. Use--to force passthrough explicitly. - Default runner:
native. Override with--runner docker, or setHPLOT_RUNNER=dockerin the environment. - Discovery of hplot subcommands (for param parsing): cached at
$HOME/.cache/hplot/commands.txt(TTLHPLOT_COMMANDS_TTL_SECONDS, default 86400) viahplot schema --commands-only(added 2026-09-05 during the click migration). Falls back to a static builtin list if hplot isn't on PATH. - The
hplotCLI is built on click (as of 2026-09-05; was argparse before that). Migration rationale and surface notes live in the wrapper header comment.
Conventions
- Deps are minimal on purpose: matplotlib/pandas/scipy/numpy/pygam plus
anndata(core, because__init__exports thepp/tl/plAPI unconditionally).anndatais still imported lazily inside functions —test/test_anndata_api.pyasserts no module-level import, soimport hplot.corestays cheap.squidpyis not imported anywhere in the package; it is a convenience extra only. - No lint config in
pyproject.toml(no ruff/pytest sections); keep style consistent with existing modules.
Sibling repos (same ecosystem)
wsinsight— WSI pipeline. Produces the outputs analysed here; does not import this package.sptxinsight— spatial-transcriptomics sibling. Same relationship; itsinsightlib/was copied from wsinsight, not from this package.clawsight/clawpyter— client-side agent plugins for the ecosystem's MCP servers / Jupyter.