scCS.plot¶
plot.py — Publication-quality visualizations for scCS.
- Primary visualization: plot_star_embedding()
Radial star layout with one arm per fate, cells colored by cluster, pseudotime, fate affinity, or commitment entropy. Arm axes are drawn with fate labels at the tips.
- Additional plots:
plot_rose() — polar rose of velocity magnitude by direction plot_pairwise_cs() — heatmap of pairwise nCS/unCS matrix plot_commitment_bar() — unCS/nCS bar chart per fate pair plot_commitment_heatmap() — per-cell fate affinity heatmap plot_expression_trends() — CellRank-style gene expression vs pseudotime plot_subset_comparison() — multi-subset CS comparison plot_nn_entropy_elbow() — elbow plot for k_nn selection
- Multi-condition plots (PairScorer + MultiScorer):
plot_delta_cs_heatmap() — ΔCS heatmap with CI annotation plot_compare_conditions_bar() — grouped bar chart of nCS per condition plot_commitment_vector_radar() — radar chart of commitment vectors plot_omnibus_summary() — fates × conditions heatmap with omnibus significance plot_posthoc_heatmap() — condition × condition post-hoc p-value heatmap plot_pairwise_delta_grid() — grid of ΔCS heatmaps for all condition pairs
Color maps¶
All plot functions accept an optional color_map dict mapping fate name
to a hex color string. Pass this to preserve your original cluster colors
from scanpy/Seurat across all scCS plots. Progenitor cells always use
PROGENITOR_COLOR (gray) regardless of color_map.
Example:
# Extract colors from scanpy
color_map = dict(zip(
adata.obs['cell_type'].cat.categories,
adata.uns['cell_type_colors'],
))
scorer.plot_star(result, color_map=color_map)
All plots use seaborn ticks theme. Figures are returned as matplotlib Figure objects.
Attributes¶
Functions¶
|
Radial star embedding plot — the primary scCS visualization. |
|
Elbow plots for choosing the optimal number of nearest neighbors (k_nn). |
|
Plot gene expression trends along a chosen commitment axis. |
|
Multi-panel star embedding: one panel per coloring scheme. |
|
Polar rose plot of cumulative velocity magnitudes per angular bin. |
|
Grid of polar rose plots — one per condition. |
|
Heatmap of pairwise commitment scores. |
|
Bar chart of unCS and nCS for all k populations. |
|
Heatmap of per-cell fate affinity scores (cells × fates). |
|
Compare commitment scores across multiple subsets. |
|
Heatmap of ΔCS = nCS_A − nCS_B with CI annotation. |
|
Grouped bar chart of nCS per condition. |
|
Radar / spider chart of commitment vectors per condition. |
|
Summary heatmap: fates × conditions showing omnibus significance. |
|
Condition × condition heatmap of post-hoc p-values for a given fate. |
|
Grid of ΔCS heatmaps for all condition pairs. |
Module Contents¶
- scCS.plot.FATE_PALETTE = ['#0072B2', '#D55E00', '#009E73', '#CC79A7', '#E69F00', '#56B4E9', '#F0E442', '#000000'][source]¶
- scCS.plot.CONDITION_PALETTE = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7', '#000000',...[source]¶
- scCS.plot.plot_star_embedding(adata, result: scCS.scores.CommitmentScoreResult, color_by: str = 'fate', figsize: Tuple[float, float] = (8, 8), point_size: float = 8.0, alpha: float = 0.75, arm_color: str = '#CCCCCC', arm_linewidth: float = 1.5, arm_linestyle: str = '--', show_arm_labels: bool = True, show_velocity: bool = False, velocity_scale: float = 1.0, color_map: Dict[str, str] | None = None, title: str | None = None, vmin: float | None = None, vmax: float | None = None, cmap: str | None = None, ax: matplotlib.pyplot.Axes | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Radial star embedding plot — the primary scCS visualization.
Draws the X_sccs embedding with: - Radial arm axes (dashed lines from origin to each fate tip) - Fate labels at the arm tips - Cells colored by fate, pseudotime, entropy, or per-fate affinity - Optional velocity arrows
- Parameters:
adata (AnnData) – Must have X_sccs in obsm.
result (CommitmentScoreResult)
color_by (str) –
What to color cells by: -
"fate"— cluster/arm assignment (default) -"pseudotime"— readssccs_pseudotimethenvelocity_pseudotime-"entropy"— per-cell commitment entropy (cs_entropy) -"nn_entropy"— NN-smoothed entropy (cs_nn_entropy;requires
score(k_nn=...))a fate name — per-cell affinity (
cs_{fate}; requiresscore(cell_level=True))any other str — auto-detected numeric or categorical column in
adata.obs
figsize (tuple)
point_size (float)
alpha (float)
arm_color (str) – Color of the radial arm guide lines.
arm_linewidth (float)
arm_linestyle (str)
show_arm_labels (bool) – Draw fate name labels at arm tips.
show_velocity (bool) – Overlay velocity arrows (requires velocity_sccs in obsm).
velocity_scale (float) – Scale factor for velocity arrows.
title (str, optional)
vmin (float, optional) – Color-scale limits for numeric
color_bymodes. Defaults to the finite data range, so structure is always visible regardless of the absolute entropy/affinity scale. Pass explicit values to pin limits for cross-figure comparison.vmax (float, optional) – Color-scale limits for numeric
color_bymodes. Defaults to the finite data range, so structure is always visible regardless of the absolute entropy/affinity scale. Pass explicit values to pin limits for cross-figure comparison.cmap (str, optional) – Matplotlib colormap name. Defaults:
"RdYlBu_r"for entropy,"viridis"for pseudotime/generic numeric,"Blues"for per-fate affinity.ax (matplotlib Axes, optional)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_nn_entropy_elbow(scorer, k_nn_range: List[int] | range = range(5, 51, 5), color_map: Dict[str, str] | None = None, figsize: Tuple[float, float] = (12, 5), title: str | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Elbow plots for choosing the optimal number of nearest neighbors (k_nn).
Sweeps over
k_nn_range, computing NN-smoothed cell entropy at each k, and produces two side-by-side subplots:Left: mean NN entropy across all cells vs k_nn.
Right: mean NN entropy per fate arm vs k_nn (one line per fate).
Use these plots to identify the elbow — the k_nn where entropy stabilizes, indicating that additional smoothing no longer changes the signal.
- Parameters:
scorer (SingleScorer) – A fitted scorer with
build_embedding()andfit()already called. No priorscore()call is needed — cell scores are recomputed internally from the velocity vectors.k_nn_range (list or range) – k_nn values to sweep. Default: 5, 10, 15, …, 50.
color_map (dict, optional) – Fate name -> hex color. Falls back to the default FATE_PALETTE.
figsize (tuple)
title (str, optional) – Overall figure title. Defaults to “NN Entropy Elbow”.
save_path (str, optional) – If provided, save figure to this path.
- Returns:
fig
- Return type:
matplotlib Figure
Examples
>>> scorer.build_embedding(differentiation_metric='pseudotime') >>> scorer.fit() >>> result = scorer.score(compute_cell_level=True) >>> fig = scorer.plot_nn_entropy_elbow()
- scCS.plot.plot_expression_trends(adata, result: scCS.scores.CommitmentScoreResult, genes: List[str], fate: str | None = None, x_axis: str = 'affinity', n_bins: int = 10, layer: str | None = None, smooth: bool = True, smooth_frac: float = 0.4, color_map: Dict[str, str] | None = None, figsize: Tuple[float, float] | None = None, ncols: int = 3, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Plot gene expression trends along a chosen commitment axis.
Cells are binned along the x-axis and mean expression per bin is plotted with a LOWESS smooth.
- Parameters:
adata (AnnData) – Must contain the same cells as
result.result (CommitmentScoreResult)
genes (list of str) – Gene names to plot. Must be present in
adata.var_names.fate (str, optional) – Which fate to use as the reference. Defaults to the fate with the highest M_sector.
x_axis (str) –
What to use as the x-axis for binning: -
'affinity': per-cell fate affinity score forfate(0 → 1, from compute_cell_scores).
'pseudotime'velocity_pseudotime from adata.obs(or sccs_pseudotime if available via compute_local_pseudotime()).
'radial_distance': Euclidean distance from origin in X_sccs(arm position, 0 = progenitor, arm_scale = tip).
Default:
'affinity'.n_bins (int) – Number of bins along the x-axis.
layer (str, optional) – AnnData layer to use for expression. Defaults to
adata.X.smooth (bool) – Whether to overlay a LOWESS smoothed curve.
smooth_frac (float) – LOWESS smoothing fraction (0–1).
color_map (dict, optional) – Fate name → hex color. Used to color the smoothed line.
figsize (tuple, optional)
ncols (int) – Number of columns in the subplot grid.
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_star_panels(adata, result: scCS.scores.CommitmentScoreResult, panels: List[str] | None = None, figsize_per_panel: Tuple[float, float] = (6, 6), point_size: float = 6.0, alpha: float = 0.75, color_map: Dict[str, str] | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Multi-panel star embedding: one panel per coloring scheme.
Default panels: fate assignment, pseudotime, entropy, + one per fate.
- Parameters:
adata (AnnData)
result (CommitmentScoreResult)
panels (list of str, optional) – List of color_by values. Defaults to [‘fate’, ‘pseudotime’, ‘entropy’] + fate_names.
figsize_per_panel (tuple)
point_size (float)
alpha (float)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_rose(result: scCS.scores.CommitmentScoreResult, title: str = 'Cumulative Velocity Magnitude by Direction', figsize: Tuple[float, float] = (7, 7), show_sectors: bool = True, color_map: Dict[str, str] | None = None, ax: matplotlib.pyplot.Axes | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Polar rose plot of cumulative velocity magnitudes per angular bin.
Each bin shows the total velocity magnitude pointing in that direction. Fate sectors are shaded with distinct colors.
- Parameters:
result (CommitmentScoreResult)
title (str)
figsize (tuple)
show_sectors (bool)
ax (matplotlib Axes (polar), optional)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_rose_grid(results: Dict[str, scCS.scores.CommitmentScoreResult], color_map: Dict[str, str] | None = None, figsize_per_panel: Tuple[float, float] = (5, 5), title: str | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Grid of polar rose plots — one per condition.
All panels share the same radial scale (max of all M_bin.max() across conditions), making magnitudes directly comparable. Fate sectors are shaded with FATE_PALETTE colors (consistent with single-condition plot_rose).
- Parameters:
results (dict) – Mapping of condition_label -> CommitmentScoreResult (output of PairScorer.score_all_conditions()).
color_map (dict, optional) – fate_name -> hex color. Falls back to FATE_PALETTE.
figsize_per_panel (tuple) – Size of each polar subplot.
title (str, optional) – Overall figure title.
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_pairwise_cs(result: scCS.scores.CommitmentScoreResult, normalized: bool = True, title: str | None = None, figsize: Tuple[float, float] | None = None, cmap: str = 'RdBu_r', save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Heatmap of pairwise commitment scores.
Entry [i, j] = CS(fate_i relative to fate_j). Values > 1 indicate stronger commitment to fate_i than fate_j. Color scale is log2-transformed for readability.
- Parameters:
result (CommitmentScoreResult)
normalized (bool) – Use nCS (True) or unCS (False).
title (str, optional)
figsize (tuple, optional)
cmap (str)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_commitment_bar(result: scCS.scores.CommitmentScoreResult, ref_fate: str | None = None, mode: str = 'auto', color_map: Dict[str, str] | None = None, title: str | None = None, figsize: Tuple[float, float] | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Bar chart of unCS and nCS for all k populations.
For a k-furcation, produces k subplots — one per reference fate. Each subplot shows unCS (solid) and nCS (hatched) for all other k-1 fates relative to that reference. This way every population is shown as both a query and a reference, and nothing is hidden.
For k=2 a single subplot is produced (equivalent to the old behaviour).
- Parameters:
result (CommitmentScoreResult)
ref_fate (str, optional) – If given, produce only a single subplot using this fate as reference. Useful when you want a focused comparison.
mode (str) – Kept for backward compatibility; ignored.
color_map (dict, optional) – Mapping of fate name → hex color.
title (str, optional) – Overall figure title.
figsize (tuple, optional) – Per-subplot size
(w, h). Total figure width scales with k.save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_commitment_heatmap(result: scCS.scores.CommitmentScoreResult, cell_scores: numpy.ndarray | None = None, max_cells: int = 500, title: str = 'Per-Cell Fate Affinity', figsize: Tuple[float, float] | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Heatmap of per-cell fate affinity scores (cells × fates).
- Parameters:
result (CommitmentScoreResult)
cell_scores (np.ndarray, shape (n_cells, k), optional) – If None, uses result.cell_scores.
max_cells (int) – Subsample to this many cells for readability.
title (str)
figsize (tuple, optional)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_subset_comparison(subset_results: dict, ref_fate: str | None = None, normalized: bool = True, title: str = 'Commitment Score by Subset', figsize: Tuple[float, float] = (8, 4), save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Compare commitment scores across multiple subsets.
Subsets whose chosen reference pair yields
inf(e.g. progenitor-only subsets with no fate-arm cells, sopairwise_nCSis undefined) are rendered as gray hatched placeholders at zero height with an"inf"annotation, instead of silently producing empty bars.- Parameters:
subset_results (dict) – Mapping of subset_name -> CommitmentScoreResult (from
SingleScorer.score_per_subset).ref_fate (str, optional) – Reference fate for the CS column. If None, use the fate with smallest sector magnitude (most likely to be present in all subsets).
normalized (bool) – If True use
pairwise_nCS, elsepairwise_unCS.title (str)
figsize (tuple)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_delta_cs_heatmap(delta_result: dict, title: str | None = None, figsize: Tuple[float, float] | None = None, cmap: str = 'RdBu_r', save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Heatmap of ΔCS = nCS_A − nCS_B with CI annotation.
Entry [i, j] = nCS_A(i÷j) − nCS_B(i÷j). Positive values (red) mean condition A has stronger commitment of fate i relative to fate j. Cells are annotated with Δ ± CI_half.
- Parameters:
delta_result (dict) – Output of PairScorer.compute_delta_CS().
title (str, optional)
figsize (tuple, optional)
cmap (str) – Diverging colormap. Default: ‘RdBu_r’.
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_compare_conditions_bar(results: Dict[str, scCS.scores.CommitmentScoreResult], ref_fate: str | None = None, color_map: Dict[str, str] | None = None, title: str | None = None, figsize: Tuple[float, float] | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Grouped bar chart of nCS per condition.
For each fate pair (query ÷ reference), one group of bars — one bar per condition, colored by CONDITION_PALETTE. A horizontal dashed line at CS = 1 marks the neutral point.
- Parameters:
results (dict) – Mapping of condition_label -> CommitmentScoreResult (output of PairScorer.score_all_conditions()).
ref_fate (str, optional) – Reference fate for the denominator. If None, uses the fate with the lowest mean M_sector across conditions.
color_map (dict, optional) – condition_label -> hex color. Falls back to CONDITION_PALETTE.
title (str, optional)
figsize (tuple, optional)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_commitment_vector_radar(results: Dict[str, scCS.scores.CommitmentScoreResult], color_map: Dict[str, str] | None = None, title: str | None = None, figsize: Tuple[float, float] = (6, 6), save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Radar / spider chart of commitment vectors per condition.
Each condition is one closed polygon. Axes = fate names (k spokes). Values = commitment_vector (sums to 1). Conditions colored by CONDITION_PALETTE.
For k < 3, falls back to a grouped bar chart with a warning.
- Parameters:
results (dict) – Mapping of condition_label -> CommitmentScoreResult (output of PairScorer.score_all_conditions()).
color_map (dict, optional) – condition_label -> hex color. Falls back to CONDITION_PALETTE.
title (str, optional)
figsize (tuple)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_omnibus_summary(omnibus_df, results: Dict[str, scCS.scores.CommitmentScoreResult], posthoc_df=None, figsize: Tuple[float, float] | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Summary heatmap: fates × conditions showing omnibus significance.
Left panel: heatmap of mean per-cell affinity per fate per condition, annotated with omnibus p-value stars. Right panel (if posthoc_df provided): significant pairwise comparisons as a connectivity grid.
- Parameters:
omnibus_df (pd.DataFrame) – Output of MultiScorer.compare_omnibus(). Columns: fate, test, statistic, pval, pval_adj, significant.
results (dict) – Mapping of condition_label -> CommitmentScoreResult (output of MultiScorer.score_all_conditions()).
posthoc_df (pd.DataFrame, optional) – Output of MultiScorer.compare_posthoc(). If provided, right panel shows post-hoc significance grid.
figsize (tuple, optional)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_posthoc_heatmap(posthoc_df, fate: str | None = None, figsize: Tuple[float, float] | None = None, save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Condition × condition heatmap of post-hoc p-values for a given fate.
Lower triangle: p-values (color intensity). Upper triangle: delta mean affinity. Annotated with significance stars.
- Parameters:
posthoc_df (pd.DataFrame) –
Output of MultiScorer.compare_posthoc(). Columns: fate, comparison, method, statistic, pval, pval_adj,
significant, mean_A, mean_B, delta_mean.
fate (str, optional) – Which fate to plot. If None, uses the first fate in posthoc_df.
figsize (tuple, optional)
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure
- scCS.plot.plot_pairwise_delta_grid(delta_results: Dict[Tuple[str, str], dict], figsize_per_panel: Tuple[float, float] = (4, 4), save_path: str | None = None) matplotlib.pyplot.Figure[source]¶
Grid of ΔCS heatmaps for all condition pairs.
Each panel shows the ΔnCS heatmap for one condition pair, using the same layout as plot_delta_cs_heatmap().
- Parameters:
delta_results (dict) – Output of MultiScorer.compute_pairwise_deltas(). Mapping of (cond_a, cond_b) -> delta_result dict.
figsize_per_panel (tuple) – Size of each subplot.
save_path (str, optional)
- Returns:
fig
- Return type:
matplotlib Figure