一键导入
hplot
Install and operate hplot for spatial heterogeneity visualization of cell-type proportions across tissue distance layers
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Install and operate hplot for spatial heterogeneity visualization of cell-type proportions across tissue distance layers
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | hplot |
| description | Install and operate hplot for spatial heterogeneity visualization of cell-type proportions across tissue distance layers |
Purpose: Enable an agentic AI (Claude, OpenClaw, Hermes, or any tool-using LLM agent) to autonomously install and operate hplot for generating H-Plot spatial heterogeneity visualizations from cell-proportion data across tissue distance layers.
hplot is a Python package that produces H-Plots, a visualization introduced by Huang et al. as a Kaplan-Meier-inspired curve showing how cell-type proportions change across concentric distance layers measured from a tissue boundary (e.g., a tumor border). Layer index replaces time on the x-axis; cell proportion is on the y-axis; per-layer confidence intervals capture across-case variability.
python run_hplot.py (batch CLI) or from hplot.core import HPlot (Python API)| Package | Version | Why |
|---|---|---|
| matplotlib | ≥ 3.0 | Plotting engine |
| pandas | ≥ 1.0 | Data handling |
| scipy | ≥ 1.6 | Confidence interval stats |
| numpy | ≥ 1.18 | Numerical computation |
Optional extras (only for the AnnData / scanpy / squidpy interface, § 5.x):
| Extra | Adds | Install |
|---|---|---|
hplot[anndata] | anndata ≥ 0.8 | pip install "hplot[anndata]" |
hplot[squidpy] | anndata + squidpy ≥1.2 | pip install "hplot[squidpy]" |
cd hplot
pip install -e .
pip install matplotlib pandas scipy numpy
# then use the package directly from the repository root
hplot expects a CSV file (or a pandas DataFrame) where each row represents one tissue region (case) at one spatial layer.
| Column | Type | Description |
|---|---|---|
layer | int | Layer index. 0 = tissue boundary; negative = outside; positive = inside. |
target_prop | float | Proportion of the target cell type in that layer for that case. |
| Column | Type | Description |
|---|---|---|
base_prop | float | Proportion of a reference cell type (e.g., epithelial) to overlay. |
case_id | str | Identifies individual cases for confidence interval computation. |
group | str | Groups rows into separate H-Plot lines (e.g., tumor subtype). |
distance | float | Mean physical distance (µm) for each layer; enables dual x-axis. |
case_id,layer,target_prop,base_prop,subtype,distance
C1,-2,0.05,0.40,hot,210.3
C1,-1,0.08,0.38,hot,105.1
C1,0,0.15,0.35,hot,0.0
C1,1,0.20,0.30,hot,98.7
C2,-1,0.03,0.50,cold,112.0
C2,0,0.10,0.45,cold,0.0
C2,1,0.12,0.42,cold,95.5
The batch CLI reads a CSV, optionally groups by a column, and saves one plot per group.
python run_hplot.py \
--input input.csv \
--targets target_prop base_prop \
--layer layer \
--group subtype \
--distance distance \
--unit µm \
--output hplots \
--prefix case \
--format svg \
--dpi 300 \
--ci
Alternatively, invoke via the module:
python -m hplot.cli \
--input input.csv \
--targets target_prop \
--layer layer \
--output hplots \
--ci
| Argument | Short | Default | Description |
|---|---|---|---|
--input | -i | (required) | Path to input CSV file. |
--targets | target_prop | One or more column names for cell proportions. Each becomes a separate line. | |
--layer | layer | Column for the layer index. | |
--group | None | Column to split into separate output files. | |
--distance | None | Column for physical distance per layer (enables dual x-axis). | |
--unit | -u | None | Physical distance unit label (e.g., µm). |
--output | -o | hplots | Directory for output files. |
--prefix | -p | hplot | Prefix for output filenames. |
--format | -f | svg | Output format: svg, pdf, or png. |
--dpi | 300 | DPI for raster output (PNG). | |
--ci | flag (off) | Show confidence interval bands. |
Files are written to <output>/<prefix>_<group>.{svg,pdf,png}. If --group
is not specified, a single file <prefix>_all.<format> is produced.
screen / loci)Beyond single-target plotting, the hplot sub-command CLI can screen many
features at once and render the result as an H-Loci Summary. These are two
separate steps on purpose: screen is the slow permutation stage (run once →
ranking CSV); loci is the fast render (iterate freely).
# 1) slow: cluster-mass screen over every `unit` in a long CSV -> ranking table
python -m hplot.cli screen -i long.csv \
--sample sample --layer layer --unit unit --value value \
--distance dist --grid -6 12 --baseline far_stroma \
--band-mode dominant --min-per-group 3 --permutations 1000 \
-o ranking.csv
# 2) fast: render an H-Loci Summary panel from the ranking table
python -m hplot.cli loci -i ranking.csv --kind bands \
--sort outer_to_inner --top-n 24 --fdr-col fdr --fdr-max 0.1 \
-o hloci.svg
# one-shot: chain the screen inside loci from a raw long CSV
python -m hplot.cli loci -i long.csv --screen --kind bands \
--sample sample --layer layer --unit unit --value value \
--grid -6 12 --min-per-group 3 -o hloci.png
| Command | Key arguments | Purpose |
|---|---|---|
screen | --sample --layer --unit --value, --grid LO HI, --baseline window|far_stroma|far_tumor|"a,b", --band-mode dominant|bidirectional, --permutations, -o ranking.csv | Screen every feature → banded ranking table. |
loci | --kind bands|summary|bidirectional, --sort, --top-n, --fdr-col/--fdr-max, column-name flags, --screen, -o fig.svg | Render an H-Loci Summary from a ranking CSV. bands (default) = the canonical view: horizontal band bars filled by direction (up_color/down_color) with a vertical tick at the cluster-mass peak. summary = legacy strip+triangle view. |
The screen ranking CSV holds one row per banded feature (direction,
band_start_layer, band_end_layer, peak_layer, cluster_mass, fdr, and
*_um distance columns when --distance is given), which loci maps onto the
plotters. When those *_um columns are present, loci reconstructs the
layer→µm map from them and draws the same dual x-axis as the H-Plot curves
(bottom = physical distance in µm, top = border layer L, boundary at 0) —
automatically, whether you pass a precomputed ranking CSV or chain --screen.
import pandas as pd
from hplot.core import HPlot
df = pd.read_csv("input.csv")
hplot = HPlot()
hplot.fit(
df,
targets="target_prop", # single target column
layer="layer",
)
hplot.savefig("hplot.svg", format="svg")
import pandas as pd
from hplot.core import HPlot
df = pd.read_csv("input.csv")
hplot = HPlot()
hplot.fit(
df,
targets=["target_prop", "base_prop"], # two lines per group
layer="layer",
group="subtype", # one line set per group value
distance="distance", # enables physical distance on x-axis
unit="µm",
ci=0.95, # 95% confidence intervals
)
hplot.savefig("hplot_grouped.svg", format="svg")
import matplotlib.pyplot as plt
from hplot.core import HPlot
fig, ax = plt.subplots(figsize=(8, 5))
hplot = HPlot()
hplot.fit(df, targets="target_prop", layer="layer", group="subtype")
hplot.plot(
ci_show=True,
ax=ax,
display_base_type="tumor",
display_target_type="lymphocytes",
)
plt.tight_layout()
plt.savefig("hplot_custom.png", dpi=300)
hplot = HPlot()
hplot.fit(
df,
targets="target_prop",
layer="layer",
group="subtype",
color_map={"hot": "red", "cold": "blue"},
legend_order=["hot", "cold"],
legend_title="Tumor Subtype",
legend_kwargs={"loc": "upper right", "fontsize": 10},
)
hplot.savefig("hplot_styled.pdf", format="pdf")
import pandas as pd
from hplot.runners import run_hplot_batch
df = pd.read_csv("input.csv")
run_hplot_batch(
df=df,
targets=["target_prop", "base_prop"],
layer="layer",
group="subtype",
distance="distance",
unit="µm",
output="hplots",
prefix="case",
ci_show=True,
format="svg",
dpi=300,
)
This writes one file per unique value in the group column to the output
directory.
When the input is an AnnData rather than a tidy CSV, use the scanpy-style
pp/tl/pl API (requires pip install "hplot[anndata]", or
"hplot[squidpy]" for spatial graphs):
import hplot
# 1) assign a signed border layer to every cell (Delaunay fallback if no graph)
hplot.pp.border_layers(adata, cluster_key="cell_type",
base_categories=["tumour"], sample_key="sample_id")
# 2) fit and stash the H-Plot in adata.uns["hplot"] (survives write_h5ad)
hplot.tl.hplot(adata, target="CD8A", groupby="cell_subtype",
value_kind="expression", sample_key="sample_id")
# 3) draw (returns a matplotlib Axes)
hplot.pl.hplot(adata)
Notes:
pp.border_layers reuses adata.obsp["spatial_connectivities"] if present
(e.g. from sq.gr.spatial_neighbors), else builds a Delaunay graph from
adata.obsm["spatial"].value_kind="proportion" profiles a cell-type fraction from an .obs
categorical target; value_kind="expression" profiles a gene from .X.exclude_base=True (proportion modes) divides by non-base cells only
(all − base, using the base_categories from pp.border_layers); base
categories are dropped from the curve set. Use min_base_excluded_count to
NaN-out sparse layers. The CLI equivalents are --exclude-base /
--min-base-excluded-count on hplot plot|test|gam, which derive the target
from target_count / (all_count − base_count).hplot.pl.hplot_from_csv("hplot-outputs.csv").anndata lazily, so import hplot still works without
the extra installed.The engine above profiles one target across layers. To summarize a
screen over many features (genes, ligand→receptor pairs, or cell-type
fractions), each feature is first reduced to a scored cluster band — the run
of border layers where it departs from baseline — with a direction, a centre
(peak layer), and a magnitude (cluster mass). Those are produced by
hplot.stats.gradient_cluster_mass_screen() / directional_cluster_bands()
and rendered by the H-Loci Summary family:
| Function | One row per feature shows | Use when |
|---|---|---|
plot_hloci_summary() | a strip at the band position; thickness = cluster mass, ▲/▼ = direction | overview of hundreds of features |
plot_hloci_bands() | a horizontal bar over [band_lo, band_hi], filled by direction, peak tick | where + how wide each band sits |
plot_hloci_bands_bidirectional() | two bars (elevated + depressed) per row | features banded on both sides |
import hplot
rank = screen_df[screen_df["peak_layer"].notna()].sort_values("peak_layer")
ax = hplot.plot_hloci_bands(
rank["band_lo"], rank["band_hi"], rank["direction"],
peak=rank["peak_layer"], labels=rank["gene"],
sort=None, # keep caller order
)
# optional: add a physical-distance (µm) axis under the layer axis
layer2um = hplot.build_layer_distance_map(
[(res[sid]["layers"], res[sid]["distances"]) for sid in sample_ids])
hplot.add_border_distance_axis(ax, layer2um)
up_color / down_color are direction-neutral ("up" = above baseline,
"down" = below), so the same panel serves intensity readouts (elevated /
depressed expression or interaction score) and compositional ones (enriched /
depleted cell fraction) — the caption supplies the domain wording. Pass
sort=None to keep your row order, or sort="outer_to_inner" /
"inner_to_outer" to order by band centre.
build_layer_distance_map(layers, distances=None) averages the physical
distance (µm) per signed layer L (two flat arrays, or one iterable of
per-slide (layers, distances) pairs). add_border_distance_axis(ax, layer_to_distance) re-labels the panel's bottom axis in µm and adds a twin top
axis in layer L, preserving the x-limits so the band bars stay aligned.
HPlot.fit() Parameters| Parameter | Type | Default | Description |
|---|---|---|---|
df | pd.DataFrame | — | Input data frame. |
targets | str | list[str] | — | Column name(s) for cell proportions. |
layer | str | — | Column for the layer index. |
group | str | None | None | Column to split into separate lines. |
distance | str | None | None | Column for mean physical distance per layer. |
unit | str | None | None | Unit label for the x-axis (e.g., "µm"). |
ci | float | 0.95 | Confidence level. t-distribution for n ≤ 30, z for n > 30. |
color_map | dict | None | None | Explicit {label: color} mapping. Overrides palette. |
palette | sequence | None | None | Color sequence. Defaults to plt.cm.tab10.colors. |
legend_order | list | None | None | Order of legend entries. |
legend_title | str | None | None | Title for the legend box. |
legend_kwargs | dict | None | None | Extra kwargs forwarded to ax.legend(). |
HPlot.plot() Parameters| Parameter | Type | Default | Description |
|---|---|---|---|
ci_show | bool | True | Draw shaded confidence interval bands. |
ax | Axes | None | None | Existing matplotlib axis. Creates a new figure if None. |
display_base_type | str | "tumor" | Reference tissue type (used in title, x-axis). |
display_target_type | str | "immune cells" | Target quantity name, interpolated into the y-axis label. |
value_kind | str | "proportion" | Y-axis label phrasing: "proportion" → Proportion of {target}; "fraction" → Fraction of cells in {target} (niche/CME); "expression" → Mean expression of {target} (gene); "interaction" → Mean interaction score of {target} (ligand-receptor CCI). Ignored when ylabel is set. |
ylabel | str | None | None | Explicit y-axis label; overrides value_kind. |
A typical agent-driven workflow pairs WSInsight inference with hplot visualization:
ncomp) to compute per-layer cell-type
proportions relative to a tissue boundary.# Step 1-3: WSInsight inference and spatial analytics (produces layers.csv)
wsinsight run --wsi-dir slides/ --results-dir results/ --model CellViT-SAM-H-x40
# Step 4: Generate H-Plots
python run_hplot.py \
--input results/layers.csv \
--targets immune_prop epithelial_prop \
--layer layer \
--group tumor_subtype \
--distance distance \
--unit µm \
--output figures/ \
--format svg \
--ci
| Agent Goal | Action |
|---|---|
| Visualize immune infiltration gradient | fit(df, targets="immune_prop", layer="layer") |
| Compare subtypes | Add group="subtype" to fit() |
| Show physical distances instead of layer indices | Add distance="distance", unit="µm" to fit() |
| Overlay multiple cell types | Pass targets=["immune_prop", "epithelial_prop"] |
| Generate batch plots for a full cohort | Use run_hplot_batch() or the CLI with --group |
| Customize colors to match publication style | Use color_map={"hot": "red", "cold": "blue"} |
| Embed plot in a larger multi-panel figure | Pass an existing ax to plot() |
| Summarize a many-feature screen (genes / LR / fractions) | plot_hloci_bands() / plot_hloci_summary() on the screen output (§ 5.7) |
| Add a physical-distance (µm) axis to an H-Loci panel | add_border_distance_axis(ax, build_layer_distance_map(...)) |
| Symptom | Cause | Fix |
|---|---|---|
RuntimeError: Call fit() before plot() | plot() called without fit() | Call hplot.fit(df, ...) first. |
ValueError: missing ci_lower/ci_upper | ci_show=True but layer has n=1 case | Ensure each layer has ≥ 2 cases, or set ci_show=False. |
| Empty plot | All rows have NaN in target column | Check CSV for missing values in target columns. |
| No dual x-axis | distance or unit not provided | Pass both distance= and unit= to fit(). |
| Colors don't match expectation | color_map missing a group label | Ensure every group value has a key in color_map. |