PopComm

PopComm (Population-Level Cell–Cell Communication Analysis Tools) is a computational framework designed to quantify sample-level ligand–receptor (LR)–mediated cell–cell communication from human large-scale single-cell and single-nucleus RNA-seq datasets. It infers LR interactions between sender/receiver cell types, computes per-sample communication strength, and supports association with phenotypes (e.g., aging, disease) as well as comprehensive visualization.

PopComm is available in R and Python. It uses a human LR database by default, but users can easily swap it for a species-specific database (e.g., mouse) to suit their research needs.

Overview

Overview

PopComm provides three primary modules for population-scale cell–cell communication analysis:

  1. LR Filtering Module:
    • Identifies expressed ligand–receptor pairs (LR pairs) between sender and receiver cell types, using expression thresholds and cross-sample robustness criteria (e.g., correlation or model-based evidence).
    • Can operate on specific cell-type pairs or all combinations in the dataset.
  2. LR Scoring Module:
    • Quantifies sample-level communication intensity using a projection-based scoring approach, enabling downstream comparisons across phenotypes (categorical or continuous).
    • Can operate on specific cell-type pairs or all combinations in the dataset.
  3. Visualization Module:
    • Built-in visualizations to interpret LR interactions at both the LR and sample levels:
      • Circular network diagrams — Summarize cell–cell communication; edges encode interaction count/strength and node size reflects activity.
      • Dot plots — Rank top ligand–receptor pairs per sender–receiver; dot size shows significance and color the correlation/score.
      • Heatmaps — Show sample-wise LR interaction scores, with optional metadata tracks to highlight phenotypes and patterns.
      • PCA projections — Project sample LR scores into 2D to reveal clustering or separation aligned with metadata.
      • Boxplot (group comparison) — Compare LR scores between discrete groups (e.g., High vs Low) and report test statistics.
      • Dotplot (continuous variable) — Scatter LR scores vs a continuous covariate (e.g., IFNscore); add a fit and show R²/p-value.

Installation

R

Install the PopComm R package from CRAN (stable) or GitHub (development version):

# Stable version (CRAN - Windows/macOS/Linux)
install.packages("PopComm")

# Development version (GitHub - Windows/macOS/Linux)
# install.packages("devtools")      # If not already installed
# devtools::install_github("JusticeGO/PopComm")
install.packages("PopComm", repos = c('https://justicego.r-universe.dev', 'https://cloud.r-project.org'))

Python

The Python version of PopComm (available on PyPI) mirrors the R workflow (filter → score → visualize):

# Stable Version (PyPI)
pip install PopComm

Data Requirements

Prepare single-cell or single-nucleus RNA-seq data plus an LR database table. PopComm works in Seurat mode or Matrix mode.

Core inputs

Gene identifiers: Must match the LR database (e.g., HGNC for human, MGI for mouse); keep naming/case consistent.

Seurat mode

Matrix mode

Filtering and statistical criteria (set in the function call)

Metadata for plotting / association

Quick Start (R)

See the CRAN reference manual for full details. Example below uses Perivascular → Endothelial in Matrix mode.

Data preparation

# Load package and example data
library(PopComm)

data(matrix_object)      # example column name: "Endothelial--sample01"
data(lr_db)

1) LR filtering

Filter LR pairs and compute correlations for Perivascular -> Endothelial

filtered_lr <- filter_lr_single(
  rna              = matrix_object,
  sender           = "Perivascular",
  receiver         = "Endothelial",
  lr_database      = lr_db,
  cell_type_col    = 1,      # after splitting colnames by id_sep, cell type is part 1
  sample_col       = 2,      # sample is part 2
  id_sep           = "--",
  min_samples      = 10,
  min_sample_ratio = 0.1,
  cor_method       = "spearman",
  adjust_method    = "BH",
  min_adjust_p     = 0.05,
  min_cor          = 0,
  min_r2           = 0,
  min_fstat        = 0,
  num_cores        = 10,
  verbose          = TRUE
)

if (is.null(filtered_lr) || nrow(filtered_lr) == 0L) {
  stop("No LR pairs passed filters for Perivascular -> Endothelial.")
}

head(filtered_lr)

If you don’t specify a sender and receiver, use filter_lr_all() to analyze all sender–receiver combinations.

Output (filtered_lr)

Rows are ordered by ascending adjust.p and then descending cor.

2) Sample-level scoring

Compute per-sample LR projection scores using the filtered pairs

lr_scores <- score_lr_single(
  rna           = matrix_object,
  sender        = "Perivascular",
  receiver      = "Endothelial",
  filtered_lr   = filtered_lr,
  cell_type_col = 1,
  sample_col    = 2,
  id_sep        = "--",
  num_cores     = 10,
  verbose       = TRUE
)

if (is.null(lr_scores) || nrow(lr_scores) == 0L) {
  stop("No LR scores returned; check filters and inputs.")
}

head(lr_scores)

If you used filter_lr_all() in the previous step, use score_lr_all() here.

Output (lr_scores)

Rows are ordered by the filtered_lr keys and descending score.

3) One-step integrated analysis (optional)

Run filtering + scoring in one call

res_single <- one_step_single(
  rna              = matrix_object,
  sender           = "Perivascular",
  receiver         = "Endothelial",
  lr_database      = lr_db,
  cell_type_col    = 1,
  sample_col       = 2,
  id_sep           = "--",
  min_samples      = 10,
  min_sample_ratio = 0.1,
  cor_method       = "spearman",
  adjust_method    = "BH",
  min_adjust_p     = 0.05,
  num_cores        = 10,
  verbose          = TRUE
)

if (!is.null(res_single)) {
  lapply(res_single, head)  # res1 (LR stats), res2 (sample scores)
}

For all sender–receiver combinations, use one_step_all(). Returns two data frames: res1 (LR statistics) and res2 (per-sample scores). Returns NULL if required cell types/samples are missing or no LR pairs pass thresholds.


Visualization (R)

PopComm includes views such as circular networks, dot plots, heatmaps, PCA, and box/violin or scatter/line for associations.

Prepare metadata: a data.frame with a sample column matching lr_scores$sample, plus variables to analyze.

Data preparation

# Load package and example data
library(PopComm)

data(filtered_lr_eg)
data(lr_scores_eg)
data(metadata_eg)

1) LR filtering views

circle_plot

Plots a circular LR interaction network with curved directed edges. Nodes are arranged in a circle, and edge widths and colors represent interaction strengths.

p_net <- circle_plot(
  filtered_lr            = filtered_lr_eg,
  edge_width             = "count",    # <character> one of c("count", "cor")
  node_colors            = NULL,
  show_self_interactions = TRUE,
  cutoff                 = 0
)

print(p_net)

dot_plot

This function generates a dot plot to visualize LR interaction. Dot sizes are scaled by the correlation coefficient and dot colors represent -log10(adjust.p). The function supports plotting the top interactions per sender-receiver pair or user-specified LR pairs.

p_dot <- dot_plot(
  filtered_lr = filtered_lr_eg,
  top_n       = 5,
  axis        ="LR-SR",    # <character> one of c("LR-SR", "SR-LR")
  type_scale  = "size",    # <character> one of c("size", "radius")
  selected_LR = NULL
)

print(p_dot)

2) Sample-level scoring views

heatmap_sample

This function generates a heatmap to visualize the LR interaction scores across samples. Rows represent LR pairs and columns represent samples. Optionally, sample metadata can be used to annotate the columns. Hierarchical clustering of samples and LRSR features was performed using 1 − Spearman correlation as the distance measure (pairwise.complete.obs) and average linkage, unless otherwise specified.

p_hm <- heatmap_sample(
  lr_scores         = lr_scores_eg,
  metadata          = metadata_eg,
  score             = "normalized",   # <character> one of c("normalized", "raw")
  selected_sender   = "Endothelial",
  selected_receiver = "Perivascular",
  selected_metadata = c("Sex", "Age_group", "IFN_type"),
  treeheight_row    = 50,
  treeheight_col    = 50,
  show_LR           = FALSE,
  show_sample       = FALSE,
  basic_title       = NULL,
  dist_method       = "correlation",   # <character> one of c("correlation", "euclidean")
  clustering_method = "average"   # <character> one of c("average", "complete", "ward.D2", "single", "mcquitty", "median", "centroid")
)

print(p_hm)

pca_sample

This function performs principal component analysis (PCA) on LR interaction scores across samples, and generates a scatter plot of the first two principal components. Optionally, sample metadata can be used to color the points.

pca_res <- pca_sample(
  lr_scores         = lr_scores_eg,
  metadata          = metadata_eg,
  selected_sender   = NULL,
  selected_receiver = NULL,
  color_by          = "IFN_type",
  n_components      = 2
)

print(pca_res$plot)
head(pca_res$df)

3) Differential interaction analysis

boxplot_lr_group_comparison (discrete variable)

This function generates a boxplot comparing LR interaction scores across sample groups with optional significance testing (t-test or Wilcoxon).

p_box <- boxplot_lr_group_comparison(
  lr_scores   = lr_scores_eg,
  metadata    = metadata_eg,
  ligand      = "PSAP",
  receptor    = "LRP1",
  sender      = "Perivascular",
  receiver    = "Fibroblast",
  group_by    = "IFN_type",
  score       = "normalized",    # <character> one of c("normalized", "raw")
  show_counts = TRUE,
  test        = TRUE,
  paired      = FALSE,
  test_method = "wilcox.test"    # <character> one of c("wilcox.test", "t.test")
  stat_label  = "p.signif"       # <character> one of c("p.signif", "p.format", "p.value", "none")
  colors      = c("#5fa9d1", "#154778"),
  title       = NULL
)

print(p_box$plot)
head(p_box$df)

dotplot_lr_continuous_group (continuous variable)

This function creates a dotplot (scatter plot) of LR interaction scores against a continuous variable with optional regression line.

p_scatter <- dotplot_lr_continuous_group(
  lr_scores      = lr_scores_eg,
  metadata       = metadata_eg,
  ligand         = "HLA-A",
  receptor       = "LILRB2",
  sender         = "Lymphoid",
  receiver       = "Myeloid",
  group_by       = "IFNscore",
  score          = "normalized",  # <character> one of c("normalized", "raw")
  point_size     = 3,
  point_color    = "dodgerblue4",
  add_regression = TRUE,
  title          = NULL
)

print(p_scatter$plot)
head(p_scatter$df)

Tips

LR Database: CellTalkDB

PopComm supports using curated LR tables. This package uses the CellTalkDB resource as the default LR database for human (and optionally mouse) LR interactions.

Performance

FAQ

Q1. What advantages does PopComm offer over single-sample communication tools?

Q2. Can I analyze a specific sender–receiver pair only?

Q3. Does PopComm work with non-human data?

Cite PopComm & Database Resources

PopComm: A Population-Scale Single-Cell Atlas of the Human Heart Reveals Cellular Remodeling and Cell–Cell Communication in Aging and Cardiac Disease (Submission in progress)

Database Source: We thanks the CellTalk Database developed by Professor Xiaohui Fan. If you use the default LR database in PopComm, please also cite the orignal paper of CellTalkDB: Shao X., Liao J., Li C., et al. CellTalkDB: A manually curated database of ligand-receptor interactions in human and mouse. Briefings in Bioinformatics (2021).

License

PopComm is released under the MIT License. If you distribute an LR database derived from third-party resources (e.g., CellTalkDB), please respect their terms and acknowledge/cite those resources.