sceleto.interaction

Cell–cell communication inference — a Python port of CellChat. Infers ligand–receptor–mediated signaling between cell groups in an AnnData, using the curated CellChatDB database.

Database

sceleto.interaction.load_cellcommdb(species: str = 'human') CellCommDB[source]

Load the bundled CellChatDB for a species.

Parameters

species

One of "human", "mouse", "zebrafish".

Returns

CellCommDB

Loaded database with interaction / complex / cofactor / geneinfo tables.

sceleto.interaction.load_ppi(species: str = 'human') DataFrame[source]

Load the bundled protein–protein interaction edge list.

Ships the CellChat PPI network for the (not-yet-ported) expression-smoothing / diffusion step (smoothData / projectData in R). Provided so the data is available; the smoothing step itself is not implemented yet, so the current pipeline does not consume this. Only "human" and "mouse" are available.

Returns

pd.DataFrame

Columns gene_i, gene_j, weight (undirected edges).

sceleto.interaction.list_cellcommdb() list[str][source]

Return the species for which a CellChatDB is bundled.

class sceleto.interaction.CellCommDB(species: str, interaction: DataFrame, complex: DataFrame, cofactor: DataFrame, geneinfo: DataFrame)[source]

Bases: object

A loaded CellChatDB for one species.

Attributes

species

One of "human", "mouse", "zebrafish".

interaction

Ligand–receptor interaction table (indexed by name).

complex

Complex → subunit table (indexed by complex name).

cofactor

Cofactor sets (indexed by cofactor name).

geneinfo

Single-column frame of official gene symbols.

species: str
interaction: DataFrame
complex: DataFrame
cofactor: DataFrame
geneinfo: DataFrame
is_complex(name: str) bool[source]

True if name is a complex (present in the complex table).

resolve_genes(name: str) list[str][source]

Resolve a ligand/receptor token to its constituent gene symbols.

A single gene resolves to [name]; a complex resolves to its non-empty subunits (order preserved). Unknown tokens resolve to [name] (treated as a single gene).

Parameters

name

A gene symbol or a complex name from the ligand/receptor columns of interaction.

resolve_cofactor(name: str) list[str][source]

Resolve a cofactor-set name to its gene symbols ([] if blank).

subset(*, annotation: str | Sequence[str] | None = None, pathway: str | Sequence[str] | None = None) CellCommDB[source]

Return a new CellCommDB with the interaction table filtered.

Parameters

annotation

Keep only interactions with these annotation class(es). See ANNOTATIONS.

pathway

Keep only interactions in these signaling pathway(s).

property pathways: list[str]

Sorted unique signaling pathway names in the interaction table.

signaling_genes() list[str][source]

All gene symbols referenced by any ligand/receptor (complexes expanded).

This is the gene universe to intersect with adata.var_names before inference (CellChat’s subsetData step).

Gene-symbol Normalization

class sceleto.interaction.GeneMapper(symbols: Iterable[str], synonyms: dict[str, list[str]] | None = None, *, case_insensitive: bool = True)[source]

Bases: object

Map query gene symbols onto a reference symbol set, alias-aware.

Parameters

symbols

Canonical reference symbols (the database’s official symbols).

synonyms

Optional {canonical_symbol: [alias, ...]}. Aliases are matched only when they are unambiguous — an alias pointing at more than one canonical symbol is dropped from the alias table (a conservative choice: better to leave it unmatched than to guess wrong).

case_insensitive

Also match on a case-folded key. Enables e.g. human TGFB1 in the DB to catch a query written Tgfb1, which matters when a mouse-cased object is scored against the human DB or vice versa. Direct (case-sensitive) hits always take priority over case-folded ones.

classmethod from_db(db, *, case_insensitive: bool = True) GeneMapper[source]

Build a GeneMapper from a loaded CellCommDB.

Uses db.geneinfo (Symbol + space-separated Synonym).

resolve(symbol: str) str | None[source]

Resolve one query symbol to a canonical symbol, or None.

Resolution order: exact canonical → exact alias → case-folded canonical → case-folded alias.

map(query: Iterable[str]) MappingResult[source]

Map a set of query symbols onto canonical symbols.

Parameters

query

Query gene symbols (e.g. adata.var_names).

Returns

MappingResult

Full breakdown of direct / alias / unmatched resolutions.

rename_frame(adata_var_names: Iterable[str]) dict[str, str][source]

Return a collision-safe rename dict → canonical symbols.

Only entries that actually change are returned, suitable for adata.var.rename(index=...). Direct matches are omitted (no change).

Renames that would collide are dropped so the result never introduces duplicate var_names: an alias is not renamed to a canonical that is already present among the query names, nor to a canonical that two different aliases both target. This prevents silently overwriting a real gene’s expression column (e.g. a panel carrying both TGFB1 and a legacy alias of it).

class sceleto.interaction.MappingResult(mapping: dict[str, str], matched_direct: set[str], matched_alias: dict[str, str], unmatched: set[str])[source]

Bases: object

Outcome of mapping a query gene set onto canonical symbols.

Attributes

mapping

{query_symbol: canonical_symbol} for every query that resolved.

matched_direct

Queries that matched a canonical symbol as-is.

matched_alias

{query_symbol: canonical_symbol} resolved through a synonym.

unmatched

Queries that matched nothing.

mapping: dict[str, str]
matched_direct: set[str]
matched_alias: dict[str, str]
unmatched: set[str]
property n_matched: int
summary() str[source]

Core Inference

The CellComm class drives the whole pipeline; its methods mirror CellChat’s workflow: identify_overexpressedcompute_communicationfilter_communicationcompute_communication_pathwayaggregatesubset_communication / rank_net / contribution.

class sceleto.interaction.CellComm(adata: AnnData, groupby: str, *, db: CellCommDB | None = None, species: str = 'human', layer: str | None = None, map_symbols: bool = True, coordinates: ndarray | None = None, spatial_factors: dict | None = None, verbose: bool = True)[source]

Bases: object

Cell–cell communication analysis over an AnnData.

Parameters

adata

Cells × genes AnnData with normalized, non-negative expression in the chosen layer (log-normalized .X is typical).

groupby

adata.obs column with the cell-group labels. Its categorical order (or sorted uniques) defines the network’s node order.

db

A loaded CellCommDB. If None, loads the species default.

species

Used only when db is None to pick the bundled database.

layer

Layer to read expression from; None uses adata.X.

map_symbols

If True (default), normalize adata.var_names onto database canonical symbols (alias/case-aware) before analysis — this is what makes cross-species and symbol-update mismatches recoverable.

verbose

Print progress.

Notes

The AnnData is not copied; compute_communication writes results into self (and, optionally, adata.uns['cellcomm'] via to_uns()).

property is_computed: bool

Whether compute_communication() has run.

property prob: ndarray

Per-pair communication probability (K×K×nLR).

property pval: ndarray

Per-pair permutation p-values (K×K×nLR).

property weight: ndarray

Aggregated K×K interaction-strength matrix (needs aggregate()).

property count: ndarray

Aggregated K×K interaction-count matrix (needs aggregate()).

property pathways: list[str]

Signaling pathway names (needs compute_communication_pathway()).

identify_overexpressed(*, thresh_p: float = 0.05, thresh_fc: float = 0.0, thresh_pc: float = 0.0, only_pos: bool = True, variable_both: bool = True) CellComm[source]

DE (Wilcoxon, one-vs-rest via scanpy) → significant L–R pairs.

Populates overexpressed_, features_sig_, and LRsig (the exact pair set compute_communication() scores).

Parameters

thresh_p

Adjusted-p cutoff for a gene to count as over-expressed.

thresh_fc

Minimum log-fold-change.

thresh_pc

Minimum detection fraction in the group.

only_pos

Keep only up-regulated genes.

variable_both

If True, keep an interaction only when both ligand and receptor are over-expressed; else either endpoint suffices (mirrors CellChat variable.both).

compute_communication(*, type: str = 'triMean', trim: float = 0.1, population_size: bool = False, nboot: int = 100, seed: int = 1, Kh: float = 0.5, n: float = 1.0, n_jobs: int = 1, distance_use: bool = True, interaction_range: float = 250.0, scale_distance: float = 0.01, k_min: int = 10, contact_dependent: bool = True, contact_range: float | None = None) CellComm[source]

Communication probability + permutation p-value per L–R pair.

Requires identify_overexpressed() first (or a manually set LRsig). Writes self.net = {'prob', 'pval'}: each a K × K × nLR array (sender × receiver × interaction).

Parameters

type, trim

Group-summary statistic (triMean default) and trim fraction.

population_size

Weight probabilities by group cell-fractions (CellChat population.size).

nboot

Number of label permutations for the p-value.

seed

RNG seed for the permutations.

Kh, n

Hill function parameters (dissociation constant, coefficient).

n_jobs

Threads for the permutation bootstrap (the dominant cost). 1 (default) runs serially; higher values parallelize the per-boot group averaging. Results are identical regardless of n_jobs.

distance_use, interaction_range, scale_distance, k_min, contact_dependent, contact_range

Spatial only (when the object was built with coordinates). Constrain communication by spatial proximity: interaction_range (µm diffusion cutoff), scale_distance (distance scaling), contact_range (µm, required if contact_dependent for the Cell-Cell Contact L-R pairs). See compute_region_distance().

compute_communication_pathway(*, thresh: float = 0.05) CellComm[source]

Sum significant per-pair prob within each signaling pathway.

Writes self.netP = {'prob' (K×K×nPathway), 'pathways' (list)}.

filter_communication(*, min_cells: int = 10) CellComm[source]

Zero out communication involving cell groups with too few cells.

Ports CellChat filterCommunication (min-cells branch): any cell group with <= min_cells cells is unreliable, so all communication where it is the sender OR receiver is set to 0. Should be called after compute_communication() and before aggregate() / compute_communication_pathway().

Parameters

min_cells

Cell groups with at most this many cells are excluded.

aggregate(*, thresh: float = 0.05) CellComm[source]

Aggregate to K×K count and weight matrices.

count = number of significant L–R pairs between each group pair; weight = summed communication probability.

subset_communication(*, thresh: float = 0.05, sources: Sequence[str] | None = None, targets: Sequence[str] | None = None, signaling: Sequence[str] | None = None) DataFrame[source]

Tidy long-form significant communication table.

Returns

pd.DataFrame

Columns: source, target, ligand, receptor, interaction_name, pathway_name, prob, pval.

rank_net(*, measure: str = 'weight', thresh: float = 0.05) DataFrame[source]

Rank signaling pathways by total information flow (rankNet).

For each pathway, “information flow” = the summed communication probability (measure="weight") or the number of significant links (measure="count") over all group pairs. Pathways are returned in descending order.

Parameters

measure

"weight" (summed probability, the CellChat “information flow”) or "count" (number of significant group-pair links).

thresh

p-value threshold for significance.

Returns

pd.DataFrame

Columns pathway_name, flow (the ranking value), sorted descending.

contribution(signaling: str, *, thresh: float = 0.05) DataFrame[source]

Per-L–R-pair contribution to one signaling pathway (netAnalysis_contribution).

Within a pathway, each ligand–receptor pair contributes a share of the total communication probability. Returns each pair’s summed probability and its fractional contribution, descending.

Parameters

signaling

Pathway name (see CellComm.netP ["pathways"] or db.pathways).

thresh

p-value threshold for significance.

Returns

pd.DataFrame

Columns interaction_name, ligand, receptor, prob, contribution (fraction of the pathway total), sorted descending.

signaling_role_pathway(*, pattern: str = 'outgoing') DataFrame[source]

Per-pathway × cell-group signaling-role matrix (see signaling_role_pathway()).

compute_net_similarity(*, slot: str = 'netP', type: str = 'functional', k=None, thresh=None) CellComm[source]

Pairwise pathway-network similarity → netP['similarity'][type].

Delegates to compute_net_similarity() (which returns the matrix); the method stores it and returns self so the manifold sub-pipeline chains: cc.compute_net_similarity().net_embedding().

net_embedding(*, type: str = 'functional', n_neighbors=None, min_dist: float = 0.3, metric: str = 'correlation', seed: int = 42, pathway_remove=None, **umap_kwargs) CellComm[source]

2-D UMAP of the pathway similarity → netP['embedding'][type].

Delegates to net_embedding(); stores the embedding and returns self (chainable).

net_clustering(*, type: str = 'functional', k=None, method: str = 'kmeans', k_eigen=None, n_init: int = 10, seed: int = 0) Series[source]

Cluster pathways in the similarity manifold (see net_clustering()).

identify_communication_patterns(pattern: str = 'outgoing', k=None, *, seed: int = 0, max_iter: int = 500, store: bool = True, verbose: bool = True) dict[source]

NMF outgoing/incoming communication patterns (see identify_communication_patterns()).

select_k(pattern: str = 'outgoing', k_range=range(2, 11), *, n_runs: int = 30, seed: int = 10, max_iter: int = 500, verbose: bool = True) DataFrame[source]

NMF rank selection (cophenetic + silhouette; see select_k()).

to_uns(key: str = 'cellcomm') None[source]

Store the result dict into adata.uns[key].

Network Analysis

sceleto.interaction.compute_centrality(mat: ndarray, names: list[str]) DataFrame[source]

Per-node centrality scores for one signaling network.

Parameters

mat

K × K weighted communication matrix (source × target).

names

Node (cell-group) names.

Returns

pd.DataFrame

Index = names; columns = outdeg (Sender), indeg (Receiver), flowbet (Mediator), info (Influencer), plus hub, authority, eigen, pagerank.

sceleto.interaction.signaling_role(centrality: DataFrame) DataFrame[source]

Assign the dominant signaling role per cell group.

For each node, reports the four core scores (Sender/Receiver/Mediator/ Influencer) and the role with the highest score.

sceleto.interaction.signaling_role_pathway(cc, *, pattern: str = 'outgoing') DataFrame[source]

Per-pathway × cell-group signaling-role matrix (netAnalysis_signalingRole_heatmap).

For each pathway network, computes the chosen centrality role per cell group and stacks them into a pathway × cell-group matrix — the data behind the standard CellChat signaling-role heatmap.

Parameters

cc

A CellComm after compute_communication_pathway().

pattern

Which role to score: "outgoing"/"sender" (out-degree), "incoming"/"receiver" (in-degree), "mediator" (betweenness), or "influencer" (information centrality).

Returns

pd.DataFrame

Rows = pathways, columns = cell groups, values = the role score.

sceleto.interaction.network_graph(mat: ndarray, names: list[str]) DiGraph[source]

Public helper: aggregated communication matrix → weighted DiGraph.

Node/edge order matches names; edge attribute weight carries the communication strength. Convenient for custom downstream graph analysis.

Communication Patterns (NMF)

Outgoing/incoming communication-pattern discovery via non-negative matrix factorization (CellChat selectK / identifyCommunicationPatterns). The factorization uses the same Lee multiplicative-update rule as R’s NMF package (scikit-learn NMF(solver='mu')).

sceleto.interaction.select_k(cc: CellChat, pattern: str = 'outgoing', k_range=range(2, 11), *, n_runs: int = 30, seed: int = 10, max_iter: int = 500, verbose: bool = True) pd.DataFrame[source]

Rank selection for NMF communication patterns (CellChat selectK).

For each candidate k this runs NMF n_runs times (varying the seed), forms the consensus clustering of cell groups over the runs, and reports two stability metrics — the same ones CellChat’s selectK reads out of NMF::nmfEstimateRank:

  • cophenetic : cophenetic correlation of the consensus matrix. Drops sharply at the k beyond which the factorization is no longer stable.

  • silhouette : mean silhouette of the consensus clustering.

Pick the k just before cophenetic correlation begins to fall (a common NMF heuristic).

Parameters

cc

CellComm object after CellComm.compute_communication_pathway().

pattern

"outgoing" or "incoming".

k_range

Iterable of candidate ranks (default range(2, 11) → 2..10). Values above min(n_groups, n_pathways) are skipped with a warning.

n_runs

NMF restarts per k (CellChat default 30). Use a smaller value for a quick scan.

seed

Base seed; run r uses seed + r for reproducibility.

max_iter

Maximum NMF iterations.

verbose

Print progress.

Returns

pd.DataFrame

Columns k, cophenetic, silhouette (one row per usable k), sorted by k. Feed the chosen k to identify_communication_patterns().

Raises

ValueError

If cc.netP['prob'] is missing, the matrix is all zeros, or no k in k_range is usable (all exceed the factorizable rank).

sceleto.interaction.identify_communication_patterns(cc: CellComm, pattern: str = 'outgoing', k: int | None = None, *, seed: int = 0, max_iter: int = 500, store: bool = True, verbose: bool = True) dict[source]

NMF communication patterns (CellChat identifyCommunicationPatterns).

Factorizes the cell-group × pathway matrix into k latent patterns. Each pattern links a group of cells (rows of W) to a group of pathways (rows of H), exposing coordinated outgoing (sending) or incoming (receiving) signaling programs.

Parameters

cc

A CellComm object after CellComm.compute_communication_pathway() (so cc.netP['prob'] exists).

pattern

"outgoing" sums over the receiver axis (who sends); "incoming" sums over the sender axis (who receives).

k

Number of patterns (NMF rank). Run select_k() first to choose it. Must satisfy 1 <= k <= min(n_groups, n_pathways).

seed

Random seed passed to NMF for reproducibility.

max_iter

Maximum NMF iterations.

store

If True (default), store the result on cc.patterns[pattern].

verbose

Print progress.

Returns

dict

{"pattern", "k", "data", "W", "H", "cell", "signaling", "cell_pattern"} where

  • W : DataFrame, index = cell groups, columns = Pattern 1..k; each row is row-normalized (a cell group’s pattern memberships sum to 1), matching CellChat scaleMat(W, 'r1').

  • H : DataFrame, index = Pattern 1..k, columns = pathways; each column is column-normalized (a pathway’s pattern memberships sum to 1), matching CellChat scaleMat(H, 'c1').

  • cell / signaling : tidy long-form of W / H (the R res.pattern$cell / res.pattern$signaling tables).

  • cell_pattern : Series mapping each cell group to its dominant pattern (argmax over W).

  • data : the input cell-group × pathway matrix (pre-NMF).

Raises

ValueError

If cc.netP['prob'] is missing, the matrix is all zeros, or k is out of range (k missing, k < 1, or k larger than the number of usable groups/pathways).

sceleto.interaction.plot_communication_patterns(cc: CellChat, pattern: str = 'outgoing', *, result: dict | None = None, figsize: tuple[float, float] = (10, 6), cmap: str = 'Spectral_r', title: str | None = None) plt.Figure[source]

Two-panel heatmap of the communication patterns (CellChat river view).

Left panel: W (cell groups × patterns) — which cells drive each pattern. Right panel: Hᵀ (pathways × patterns) — which pathways define each pattern. Together they read like CellChat’s identifyCommunicationPatterns heatmap pair.

Parameters

cc

CellComm object. Uses cc.patterns[pattern] unless a result dict is passed directly.

pattern

"outgoing" or "incoming".

result

A result dict from identify_communication_patterns(). If None, read cc.patterns[pattern] (raising if it has not been computed).

figsize

Figure size.

cmap

Matplotlib colormap (default "Spectral_r" ≈ CellChat’s reversed Spectral).

title

Overall figure title.

Returns

matplotlib.figure.Figure

Raises

ValueError

If no pattern result is available for pattern.

Pathway Similarity & Clustering (manifold)

Functional/structural similarity between signaling-pathway networks, UMAP embedding, and clustering (CellChat computeNetSimilarity / netEmbedding / netClustering).

sceleto.interaction.compute_net_similarity(cc, *, slot: str = 'netP', type: str = 'functional', k: int | None = None, thresh: float | None = None) DataFrame[source]

Pairwise similarity between per-pathway signaling networks.

Port of CellChat’s computeNetSimilarity (analysis.R). Builds an nPathway × nPathway similarity matrix over the K×K per-pathway networks in cc.netP['prob'], then smooths it with a shared-nearest-neighbor graph.

Parameters

cc

CellComm object with cc.netP['prob'] (K×K×nPathway) and cc.netP['pathways'] set by compute_communication_pathway.

slot

Slot name to read the prob array from (default "netP"); kept for API parity with R. Only "netP" is supported.

type

"functional" (Jaccard overlap of binarized networks) or "structural" (1 D-measure; see _net_d_structure()).

k

kNN neighborhood for SNN smoothing. Defaults to ceil(sqrt(nPathway)) (+1 if nPathway > 25), as in R.

thresh

Optional fraction in [0, 0.25]: interactions below this quantile of the non-zero prob values are zeroed before similarity is computed (R’s thresh).

Returns

pandas.DataFrame

The smoothed nPathway × nPathway similarity matrix, indexed and columned by pathway name. Also stored at cc.netP['similarity'][type].

Notes

Functional similarity is exactly R’s sum(Gi*Gj) / sum(Gi + Gj Gi*Gj) on the binarized (prob > 0) networks — i.e. the Jaccard index of the flattened K×K binary adjacency vectors. It is computed here with scipy.spatial.distance.pdist() (metric="jaccard") and similarity = 1 distance; the full K×K matrix including the diagonal is flattened, matching R (R sums over all K² entries, diagonal included). The diagonal of the result is forced to 1 as in R.

Structural similarity is 1 D where D is the graph D-measure; it is best-effort faithful to R/igraph (see module Notes).

sceleto.interaction.net_embedding(cc, *, type: str = 'functional', n_neighbors: int | None = None, min_dist: float = 0.3, metric: str = 'correlation', seed: int = 42, pathway_remove: list[str] | None = None, **umap_kwargs) DataFrame[source]

UMAP embedding of the pathway similarity matrix (R netEmbedding).

Runs 2-D UMAP on the similarity matrix (each pathway’s similarity row is its feature vector), reproducing CellChat’s runUMAP defaults (metric="correlation", min_dist=0.3, n_neighbors=ceil(sqrt(n))+1, seed=42).

Parameters

cc

CellComm object; requires cc.netP['similarity'][type] from compute_net_similarity().

type

"functional" or "structural".

n_neighbors

UMAP neighborhood size. Defaults to ceil(sqrt(nPathway)) + 1 (R). Must be smaller than the number of pathways.

min_dist

UMAP min_dist (default 0.3, as in R).

metric

UMAP metric (default "correlation", matching R’s runUMAP).

seed

Random seed (R uses 42).

pathway_remove

Pathway names to drop before embedding. If None (default), R’s rule is applied: pathways whose similarity column sums to exactly 1 (i.e. only self-similar, disconnected from every other pathway) are removed.

**umap_kwargs

Extra keyword arguments forwarded to umap.UMAP.

Returns

pandas.DataFrame

nPathway × 2 embedding (columns UMAP1, UMAP2), indexed by pathway name. Also stored at cc.netP['embedding'][type].

Raises

ValueError

If fewer than 3 pathways remain (UMAP requires n_neighbors < n with n_neighbors >= 2, so a meaningful embedding needs n >= 3).

Notes

UMAP requires n_neighbors < n_samples. When the requested/derived n_neighbors is too large for the (possibly reduced) pathway set it is clamped to n 1 with a verbose note, rather than raising.

sceleto.interaction.net_clustering(cc, *, type: str = 'functional', k: int | None = None, method: str = 'kmeans', k_eigen: int | None = None, n_init: int = 10, seed: int = 0) Series[source]

Cluster pathways in the similarity embedding (R netClustering).

Parameters

cc

CellComm object; requires cc.netP['embedding'][type] from net_embedding().

type

"functional" or "structural".

k

Number of clusters. If None and method="kmeans", k is chosen automatically via the Laplacian eigengap of the similarity matrix (R uses a consensus-k-means eigengap; here the eigengap is taken directly on the SNN-smoothed similarity — see Notes).

method

"kmeans" (sklearn.cluster.KMeans) or "spectral" (sklearn.cluster.SpectralClustering, normalized-Laplacian eigenvectors).

k_eigen

Number of eigenvectors for spectral clustering (default = k).

n_init

k-means restarts (R uses nstart=10).

seed

Random seed.

Returns

pandas.Series

Pathway → integer cluster label (1-based, matching R). Also stored at cc.netP['clustering'][type].

Notes

R’s automatic k runs k-means for k = 2..min(N-1, 10), builds a consensus co-clustering matrix and takes its Laplacian eigengap. We simplify to a single eigengap computation on the SNN-smoothed similarity matrix (_eigengap_k()), which uses the same normalized-Laplacian / largest-eigengap rule and gives the same cluster count in the typical case. Pass an explicit k to bypass this.

sceleto.interaction.plot_net_embedding(cc, *, type: str = 'functional', ax=None, figsize: tuple[float, float] = (6, 6), label: bool = True, font_size: int = 8, point_size: float = 60.0, title: str | None = None)[source]

Scatter of the pathway embedding colored by cluster (R netVisual_embedding).

Parameters

cc

CellComm object; requires cc.netP['embedding'][type] (from net_embedding()) and, for coloring, cc.netP['clustering'][type] (from net_clustering()).

type

"functional" or "structural".

ax

Existing matplotlib axes to draw on; a new figure is created if None.

figsize

Figure size when creating a new figure.

label

Annotate each point with its pathway name.

font_size

Font size for the pathway labels.

point_size

Scatter marker size.

title

Optional axes title.

Returns

matplotlib.figure.Figure

The figure containing the embedding scatter.

Multi-dataset Comparison

Compare communication across conditions (e.g. disease vs normal). Build per- condition CellComm objects, then wrap them in MultiCellComm to compare total interactions, rank pathways by differential information flow (with a Wilcoxon test), and compute differential networks.

class sceleto.interaction.MultiCellComm(objects: Sequence, names: Sequence[str] | None = None)[source]

Bases: object

Compare communication across multiple CellComm datasets.

Parameters

objects

The per-condition CellComm objects, each already run through compute_communication (+ aggregate for count/weight comparisons, + compute_communication_pathway for pathway ranking).

names

Dataset names (e.g. ["NL", "LS"]). Defaults to Dataset1..N.

compare_interactions(measure: str = 'count') DataFrame[source]

Total interactions (count) or strength (weight) per dataset.

Requires CellComm.aggregate() on each object.

Returns

pd.DataFrame

Columns dataset, value.

diff_interaction(measure: str = 'count', *, comparison: tuple[int, int] = (0, 1), remove_isolate: bool = False, top: float = 1.0) DataFrame[source]

Differential K×K matrix net[ds2] - net[ds1] (netVisual_diffInteraction).

Positive entries = increased in the second dataset.

Parameters

measure

"count" or "weight".

comparison

(i, j) dataset indices; the result is ds_j - ds_i.

remove_isolate

Drop groups that are all-zero in the differential.

top

Keep only the top fraction by magnitude (1.0 keeps all).

Returns

pd.DataFrame

K×K differential matrix (rows=source, cols=target).

rank_net(*, measure: str = 'weight', comparison: tuple[int, int] = (0, 1), do_stat: bool = False, paired_test: bool = True, thresh: float = 0.05, stacked: bool = False) DataFrame[source]

Rank pathways by information flow across datasets (rankNet comparison).

For each dataset, information flow of a pathway = summed communication probability over all group pairs; for measure="weight" this is transformed as -1/log(x) (CellChat’s “information flow”). Pathways absent in a dataset contribute 0.

Parameters

measure

"weight" (summed prob → info flow) or "count" (binarized — number of communicating group pairs per pathway).

comparison

(i, j) dataset indices to compare.

do_stat

If True (2 datasets only), a Wilcoxon test per pathway comparing the per-group-pair prob vectors of the two conditions.

paired_test

Paired signed-rank (default) vs unpaired rank-sum. Valid because datasets share the same K cell groups.

thresh

p-value threshold (only used when ranking the net slot; the default pathway-level netP has no p-values).

stacked

Add a per-pathway contribution.relative = fraction across datasets.

Returns

pd.DataFrame

One row per (pathway, dataset): name, contribution, contribution.scaled, group (dataset), contribution.relative.1, and pvalues (if do_stat).

Spatial Constraints

For spatially-resolved data, build the CellComm object with coordinates and spatial_factors={'ratio':…, 'tol':…}, then pass interaction_range / contact_range to compute_communication. The communication probability is constrained by spatial proximity between cell groups.

sceleto.interaction.compute_region_distance(coordinates: ndarray, groups, *, interaction_range: float = 250.0, ratio: float = 1.0, tol: float = 5.0, k_min: int = 10, contact_dependent: bool = True, contact_range: float | None = None, do_symmetric: bool = True) SpatialResult[source]

Cluster×cluster spatial distance + contact adjacency (computeRegionDistance).

Parameters

coordinates

n_cells × 2 array of spot/cell centroid coordinates (pixels or µm).

groups

Per-cell group labels (array/Series/Categorical); defines the K groups.

interaction_range

Max diffusion distance (µm). Group pairs whose nearest-neighbor distance exceeds this (beyond tol) are marked non-interacting (d = NaN).

ratio

Pixel→µm conversion (multiplies raw coordinate distances).

tol

Tolerance (µm) added when comparing distances against the ranges (typically half the spot/cell size).

k_min

Minimum number of neighbor spots within range for an edge to count.

contact_dependent

If True build adj_contact using contact_range; else it is all ones (no contact restriction).

contact_range

Contact distance (µm) for juxtacrine signaling (required when contact_dependent).

do_symmetric

Symmetrize the adjacency/distance (an edge needs both directions).

Returns

SpatialResult

sceleto.interaction.spatial_probability_factor(d_spatial: ndarray, *, scale_distance: float = 0.01) ndarray[source]

Convert the cluster distance matrix into the P.spatial factor.

Reproduces CellChat’s distance.use=TRUE branch: P.spatial = 1/(d_spatial*scale_distance), non-interacting pairs → 0, and the diagonal set to the max (self-signaling gets the strongest weight).

Parameters

d_spatial

K × K distance matrix from compute_region_distance().

scale_distance

Scale so the minimum scaled distance is in [1, 2] (CellChat guidance).

Returns

np.ndarray

K × K non-negative spatial probability factor.

Visualization

sceleto.interaction.plot_network_circle(mat: ndarray, names: Sequence[str], *, ax: Axes | None = None, figsize: tuple[float, float] = (7, 7), edge_scale: float = 8.0, node_scale: float = 800.0, cmap: str | None = None, title: str | None = None) Figure[source]

Circular interaction diagram (netVisual_circle).

Nodes are cell groups placed on a circle; a directed edge i→j is drawn with width proportional to mat[i, j] and colored by the sender.

Parameters

mat

K × K weight/count matrix (source × target).

names

Cell-group names.

edge_scale, node_scale

Visual scaling for edge widths and node sizes.

sceleto.interaction.plot_heatmap(mat: ndarray, names: Sequence[str], *, ax: Axes | None = None, figsize: tuple[float, float] = (6, 5), cmap: str = 'Reds', title: str | None = None) Figure[source]

Sender × receiver heatmap of interaction strength (netVisual_heatmap).

sceleto.interaction.plot_bubble(comm: DataFrame, *, figsize: tuple[float, float] | None = None, cmap: str = 'Reds', title: str | None = None) Figure[source]

Bubble plot of L–R communication (netVisual_bubble).

Parameters

comm

Long-form table from CellComm.subset_communication() (columns source, target, interaction_name, prob, pval).

sceleto.interaction.plot_chord(mat: ndarray, names: Sequence[str], *, ax: Axes | None = None, figsize: tuple[float, float] = (7, 7), gap: float = 0.02, title: str | None = None) Figure[source]

Chord diagram of group→group communication (netVisual_chord_cell).

A lightweight matplotlib implementation: each cell group gets an arc on the unit circle sized by its total interaction; ribbons connect senders to receivers with width proportional to the communication weight.

sceleto.interaction.plot_rank_net(ranking: DataFrame, *, ax: Axes | None = None, figsize: tuple[float, float] | None = None, color: str = '#4C72B0', title: str | None = None) Figure[source]

Horizontal bar plot of pathway information flow (rankNet).

Parameters

ranking

Output of CellComm.rank_net() — columns pathway_name and flow, already sorted descending.

sceleto.interaction.plot_signaling_role_heatmap(role_matrix: DataFrame, *, figsize: tuple[float, float] | None = None, cmap: str = 'OrRd', title: str | None = None) Figure[source]

Pathway × cell-group signaling-role heatmap (netAnalysis_signalingRole_heatmap).

Parameters

role_matrix

Output of sceleto.interaction.signaling_role_pathway() — rows = pathways, columns = cell groups.

sceleto.interaction.plot_contribution(contrib: DataFrame, *, ax: Axes | None = None, figsize: tuple[float, float] | None = None, color: str = '#55A868', title: str | None = None) Figure[source]

Bar plot of each L–R pair’s contribution to a pathway (netAnalysis_contribution).

Parameters

contrib

Output of CellComm.contribution() — columns interaction_name and contribution.

sceleto.interaction.plot_signaling_role_scatter(cc, signaling: Sequence[str] | None = None, *, thresh: float | None = None, ax: Axes | None = None, figsize: tuple[float, float] = (6, 6), dot_scale: float = 400.0, label: bool = True, font_size: int = 9, title: str | None = None) Figure[source]

Dominant sender/receiver 2-D scatter (netAnalysis_signalingRole_scatter).

Each cell group is a point at (outgoing strength, incoming strength): x is the total outgoing communication (row sums of the weight matrix, i.e. the group as sender) and y the total incoming communication (column sums, the group as receiver). Dot size is proportional to the total number of inferred links (outgoing + incoming), and dot color encodes the cell group. This is CellChat’s dominant sender/receiver map.

Parameters

cc

A CellComm after compute_communication() and aggregate() (needs cc.net['weight'] and cc.net['count']).

signaling

Restrict to one or more pathway names (sum over just those pathways). If None (default) the aggregated network over all pathways is used.

thresh

p-value threshold for counting significant links in the signaling=... path (dot size). If None (default) it matches the threshold used by compute_communication_pathway(), so dot size and dot position always share the same significance cutoff. Ignored when signaling is None.

ax

Existing axes to draw on; a new figure is created if None.

figsize

Figure size when creating a new figure.

dot_scale

Overall scaling of the dot area (links → point size).

label

Annotate each point with its cell-group name.

font_size

Font size for the point labels.

title

Axes title.

Returns

matplotlib.figure.Figure

sceleto.interaction.plot_signaling_role_network(cc, signaling: str | None = None, *, figsize: tuple[float, float] | None = None, cmap: str = 'BuGn', title: str | None = None) Figure[source]

4-role centrality heatmap strip (netAnalysis_signalingRole_network).

Computes the four core CellChat centrality roles — Sender (out-degree), Receiver (in-degree), Mediator (flow betweenness), Influencer (information) — per cell group for one signaling pathway (or the aggregated network) via compute_centrality(), row-normalizes each role by its maximum (as R does with sweep(mat, 1, max, '/')), and shows the roles × cell-groups importance strip.

Parameters

cc

A CellComm after compute_communication_pathway() (for a named signaling) or after aggregate() (for the aggregated network when signaling=None).

signaling

Pathway name (from cc.netP['pathways']). If None (default) the aggregated cc.net['weight'] network is used.

figsize

Figure size; a sensible size is derived from the number of groups.

cmap

Matplotlib colormap (default "BuGn", matching R).

title

Heatmap title.

Returns

matplotlib.figure.Figure

sceleto.interaction.plot_chord_gene(cc, *, sources: Sequence[str] | None = None, targets: Sequence[str] | None = None, signaling: Sequence[str] | None = None, thresh: float = 0.05, ax: Axes | None = None, figsize: tuple[float, float] = (8, 8), gap: float = 0.015, max_pairs: int = 40, font_size: int = 8, title: str | None = None) Figure[source]

Gene-level ligand→receptor chord diagram (netVisual_chord_gene).

Distinct from the cell-level sceleto.interaction.plot_chord(): sectors around the circle are the ligand and receptor genes involved, and each ribbon is a significant ligand→receptor link, colored by the sending cell group. This reveals which L–R pairs drive the communication between the chosen sources and targets. Built from subset_communication().

Parameters

cc

A CellComm after compute_communication().

sources, targets

Restrict to these sender / receiver cell groups (names). None keeps all.

signaling

Restrict to these signaling pathway names. None keeps all.

thresh

p-value threshold for a link to be shown.

ax

Existing axes; a new figure is created if None.

figsize

Figure size when creating a new figure.

gap

Angular gap between gene sectors, as a fraction of the full circle.

max_pairs

Cap on the number of ligand→receptor links drawn (the strongest by probability are kept) to keep the diagram legible.

font_size

Gene-label font size.

title

Axes title.

Returns

matplotlib.figure.Figure

sceleto.interaction.plot_communication_patterns_river(cc, pattern: str = 'outgoing', *, result: dict | None = None, cutoff: float = 0.5, figsize: tuple[float, float] = (10, 7), font_size: int = 8, title: str | None = None) Figure[source]

Cell-groups ↔ patterns ↔ pathways alluvial diagram (netAnalysis_river).

A three-column linked-bipartite (“river”) diagram: the left column is the cell groups, the middle column the learned communication patterns, and the right column the signaling pathways. Bands connect a cell group to a pattern with width proportional to its W loading, and a pattern to a pathway with width proportional to its H loading; loadings below cutoff (after per-column scaling in identify_communication_patterns()) are dropped.

Parameters

cc

A CellComm. Uses cc.patterns[pattern] unless a result dict is passed directly.

pattern

"outgoing" or "incoming".

result

A result dict from identify_communication_patterns(). If None, read cc.patterns[pattern].

cutoff

Loadings below this are treated as zero (no band drawn), matching R’s cutoff = 0.5.

figsize

Figure size.

font_size

Label font size.

title

Figure title.

Returns

matplotlib.figure.Figure

sceleto.interaction.plot_communication_patterns_dot(cc, pattern: str = 'outgoing', *, result: dict | None = None, axis: str = 'cell', cutoff: float | None = None, figsize: tuple[float, float] | None = None, cmap: str = 'viridis', title: str | None = None) Figure[source]

Communication-pattern loading dot plot (netAnalysis_dot).

A dot plot of the NMF loadings: for axis="cell" the y-axis is cell groups and each column is a pattern with dot size/color ∝ W loading; for axis="signaling" the y-axis is pathways with dot size/color ∝ H loading. Loadings below cutoff are hidden.

Parameters

cc

A CellComm. Uses cc.patterns[pattern] unless a result dict is passed.

pattern

"outgoing" or "incoming".

result

A result dict from identify_communication_patterns(). If None, read cc.patterns[pattern].

axis

"cell" (plot W: cell groups × patterns) or "signaling" (plot H: pathways × patterns).

cutoff

Hide loadings below this. Defaults to 1 / n_patterns (as in R).

figsize

Figure size; derived from the matrix shape if None.

cmap

Colormap for the loading value.

title

Axes title.

Returns

matplotlib.figure.Figure

sceleto.interaction.plot_net_embedding_zoom(cc, *, type: str = 'functional', cluster: int | None = None, ax: Axes | None = None, figsize: tuple[float, float] = (6, 6), label: bool = True, font_size: int = 9, point_size: float = 120.0, title: str | None = None) Figure[source]

Zoomed pathway-similarity embedding scatter (netVisual_embeddingZoomIn).

Same manifold as sceleto.interaction.plot_net_embedding(), but zoomed to one cluster: only the pathways assigned to cluster are shown (with the axes scaled to that subset), so densely packed cluster members become readable. Dot size is proportional to each pathway’s total communication probability.

Parameters

cc

A CellComm with cc.netP['embedding'][type] (from net_embedding()) and cc.netP['clustering'][type] (from net_clustering()).

type

"functional" or "structural".

cluster

Cluster label (1-based, as returned by net_clustering) to zoom into. If None all clusters are shown (equivalent to the full embedding but with the zoom styling).

ax

Existing axes; a new figure is created if None.

figsize

Figure size when creating a new figure.

label

Annotate each point with its pathway name.

font_size

Label font size.

point_size

Base scatter marker size (scaled by communication probability).

title

Axes title.

Returns

matplotlib.figure.Figure

sceleto.interaction.plot_aggregate(cc, signaling: str, *, layout: str = 'circle', thresh: float = 0.05, ax: Axes | None = None, figsize: tuple[float, float] = (7, 7), title: str | None = None, **kwargs) Figure[source]

Draw one signaling pathway’s aggregated network (netVisual_aggregate).

Convenience dispatcher: given a signaling pathway name, pull its K × K inter-group matrix from cc.netP['prob'][:, :, idx] and render it with the existing sceleto.interaction.plot_network_circle() (layout="circle") or sceleto.interaction.plot_chord() (layout="chord").

Parameters

cc

A CellComm after compute_communication_pathway().

signaling

Pathway name (from cc.netP['pathways']).

layout

"circle" or "chord".

thresh

Unused for the pathway-level matrix (already thresholded during compute_communication_pathway); accepted for API parity.

ax

Existing axes; a new figure is created if None.

figsize

Figure size when creating a new figure.

title

Plot title (defaults to "<signaling> signaling pathway network").

**kwargs

Forwarded to the underlying plotting function.

Returns

matplotlib.figure.Figure