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

plot_star_embedding(, point_size, alpha, arm_color, ...)

Radial star embedding plot — the primary scCS visualization.

plot_nn_entropy_elbow(, color_map, str]] = None, ...)

Elbow plots for choosing the optimal number of nearest neighbors (k_nn).

plot_expression_trends(→ matplotlib.pyplot.Figure)

Plot gene expression trends along a chosen commitment axis.

plot_star_panels(, point_size, alpha, color_map, ...)

Multi-panel star embedding: one panel per coloring scheme.

plot_rose(, show_sectors, color_map, str]] = None, ax, ...)

Polar rose plot of cumulative velocity magnitudes per angular bin.

plot_rose_grid(, title, save_path)

Grid of polar rose plots — one per condition.

plot_pairwise_cs(→ matplotlib.pyplot.Figure)

Heatmap of pairwise commitment scores.

plot_commitment_bar(→ matplotlib.pyplot.Figure)

Bar chart of unCS and nCS for all k populations.

plot_commitment_heatmap(→ matplotlib.pyplot.Figure)

Heatmap of per-cell fate affinity scores (cells × fates).

plot_subset_comparison(, save_path)

Compare commitment scores across multiple subsets.

plot_delta_cs_heatmap(→ matplotlib.pyplot.Figure)

Heatmap of ΔCS = nCS_A − nCS_B with CI annotation.

plot_compare_conditions_bar(→ matplotlib.pyplot.Figure)

Grouped bar chart of nCS per condition.

plot_commitment_vector_radar(, save_path)

Radar / spider chart of commitment vectors per condition.

plot_omnibus_summary(→ matplotlib.pyplot.Figure)

Summary heatmap: fates × conditions showing omnibus significance.

plot_posthoc_heatmap(→ matplotlib.pyplot.Figure)

Condition × condition heatmap of post-hoc p-values for a given fate.

plot_pairwise_delta_grid(, save_path)

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.PROGENITOR_COLOR = '#AAAAAA'[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" — reads sccs_pseudotime then velocity_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}; requires score(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_by modes. 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_by modes. 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() and fit() already called. No prior score() 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()

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 for fate

    (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, so pairwise_nCS is 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, else pairwise_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