Skip to main content

Cell-Cell Communication Circle Plot

Authors

[Editor] Bizard Team;

[Contributors] ShiXiang Wang.

Modified

2026-11-05

🤖 AI Skill — Download the Bizard unified skill for your AI assistant ⬇️ Download Skill ZIP
🔌 MCP Server — Let AI agents (Claude Code, Cursor, …) query Bizard live: claude mcp add bizard -- npx @openbiox/bizard-mcp — or the free hosted instance (no install, faster from mainland China): claude mcp add --transport http bizard http://biotree.top:38123/bizard-mcp/mcp 📖 MCP Docs
📖 Cite Bizard — if Bizard helps your research, please cite: Li, K., Zheng, H., Huang, K., et al. (2026). Bizard: A Community-Driven Platform for Accelerating and Enhancing Biomedical Data Visualization. iMetaMed, e70038. 🔗 DOI / BibTeX

The Cell-Cell Communication Circle Plot (细胞-细胞通讯网络圈图) is a specialized visualization for depicting intercellular signaling interactions inferred from single-cell RNA sequencing (scRNA-seq) data. Using the CellChat R package, this plot presents a circular network where nodes represent cell populations (cell types or clusters) and directed edges indicate the strength and direction of ligand-receptor communication signals between them.

The arc width of each edge encodes communication probability, and the self-loops on each node represent autocrine signaling. Color coding maps each cell type to a distinct hue, and arrow directionality shows the sender-receiver relationship. This visualization is particularly powerful for discovering cross-talk between immune cells and tumor cells, identifying key signaling hubs in tissue microenvironments, and comparing communication networks across biological conditions.

Example

Cell-Cell Communication Circle Plot DEMO

Setup

  • System Requirements: Cross-platform (Linux/MacOS/Windows)

  • Programming Language: R

  • Dependencies: CellChat, ggplot2, circlize

# Install Bioconductor manager if needed
if (!requireNamespace("BiocManager", quietly = TRUE)) {
  install.packages("BiocManager")
}

# Install CRAN dependencies
if (!requireNamespace("ggplot2", quietly = TRUE)) install.packages("ggplot2")
if (!requireNamespace("circlize", quietly = TRUE)) install.packages("circlize")
if (!requireNamespace("igraph", quietly = TRUE)) install.packages("igraph")

# Install CellChat from GitHub (jinworks/CellChat is the current maintained fork)
if (!requireNamespace("CellChat", quietly = TRUE)) {
  if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes")
  remotes::install_github("jinworks/CellChat")
}

# Load packages
library(CellChat)
library(ggplot2)
library(circlize)
sessioninfo::session_info("attached")
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.6.2 (2026-10-29)
 os       Ubuntu 26.04.1 LTS
 system   x86_64, linux-gnu
 ui       X11
 language (EN)
 collate  C.UTF-8
 ctype    C.UTF-8
 tz       UTC
 date     2026-11-05
 pandoc   3.7.0.2 @ /usr/bin/ (via rmarkdown)
 quarto   1.11.9 @ /usr/local/bin/quarto

─ Packages ───────────────────────────────────────────────────────────────────
 ! package      * version    date (UTC) lib source
 P Biobase      * 2.72.0     2026-04-28 [?] Bioconductor 3.23 (R 4.6.2)
 P BiocGenerics * 0.58.1     2026-05-14 [?] Bioconductor 3.23 (R 4.6.2)
 P CellChat     * 2.2.0.9001 2026-11-03 [?] Github (jinworks/CellChat@75253cd)
 P circlize     * 0.4.18     2026-04-04 [?] RSPM
 P dplyr        * 1.2.1      2026-04-03 [?] RSPM
 P generics     * 0.1.4      2025-05-09 [?] RSPM
 P ggplot2      * 4.0.3.9000 2026-11-03 [?] Github (tidyverse/ggplot2@b638d65)
 P igraph       * 2.3.4      2026-09-30 [?] RSPM

 [1] /home/runner/.cache/R/renv/library/Bizard-5140bdc6/linux-ubuntu-resolute/R-4.6/x86_64-pc-linux-gnu
 [2] /home/runner/work/_temp/Library
 [3] /opt/R/4.6.2/lib/R/library

 * ── Packages attached to the search path.
 P ── Loaded and on-disk path mismatch.

──────────────────────────────────────────────────────────────────────────────

Data Preparation

For this tutorial, we build a simulated CellChat-compatible communication matrix so the example is fully self-contained and runs without requiring an external dataset or model inference. The same visualizations work identically with a real CellChat object produced from your own scRNA-seq data.

# Simulate a communication count/weight matrix
# In real use, these come from cellchat@net$count and cellchat@net$weight

set.seed(42)
cell_types <- c("CD4 T", "CD8 T", "NK", "B cell", "Monocyte",
                "DC", "Fibroblast", "Epithelial", "Endothelial")
n <- length(cell_types)

net_count  <- matrix(sample(0:50, n * n, replace = TRUE), n, n,
                     dimnames = list(cell_types, cell_types))
net_weight <- matrix(runif(n * n, 0, 1), n, n,
                     dimnames = list(cell_types, cell_types))
diag(net_count)  <- 0  # remove self-communication
diag(net_weight) <- 0

# Group size (proportional to number of cells per type, simulated)
group_size <- sample(50:500, n, replace = TRUE)
names(group_size) <- cell_types

cat("Simulated", n, "cell types with", sum(net_count), "total interactions\n")
Simulated 9 cell types with 1875 total interactions
print(net_count)
            CD4 T CD8 T NK B cell Monocyte DC Fibroblast Epithelial Endothelial
CD4 T           0    23 46      4       29 44         48         37          41
CD8 T          36     0  2     19       42 27         25          9           8
NK              0    35  0     33       14  4         49         39          28
B cell         24    24 24      0       21  3          5          4          11
Monocyte        9    36 26     39        0 33          5         32          19
DC             35    45 35      2       35  0          1         48           8
Fibroblast     17    19 36     32        3 34          0         38          42
Epithelial     48    25 30     41       21 23         20          0          34
Endothelial    46    49 44     23       17 22          1         44           0

Build a CellChat Object from Your Own Data (Reference)

The following code is for reference only (eval: false). It shows how to build a CellChat object from a Seurat scRNA-seq object before running the visualizations below.

library(Seurat)
library(CellChat)

# 1. Extract normalised count matrix and metadata from a Seurat object
seurat_obj  <- readRDS("your_seurat_object.rds")
data_input  <- GetAssayData(seurat_obj, assay = "RNA", slot = "data")
meta        <- seurat_obj@meta.data

# 2. Create CellChat object
cellchat <- createCellChat(object = data_input, meta = meta, group.by = "cell_type")

# 3. Set ligand-receptor database
cellchat@DB <- CellChatDB.human  # or CellChatDB.mouse

# 4. Pre-process & infer communication
cellchat <- subsetData(cellchat)
cellchat <- identifyOverExpressedGenes(cellchat)
cellchat <- identifyOverExpressedInteractions(cellchat)
cellchat <- computeCommunProb(cellchat, type = "triMean")
cellchat <- filterCommunication(cellchat, min.cells = 10)
cellchat <- computeCommunProbPathway(cellchat)
cellchat <- aggregateNet(cellchat)
# Now cellchat@net$count and cellchat@net$weight are available for plotting

Visualization

1. Circle Plot of Overall Cell-Cell Communication Network

The overall circle plot summarizes all inferred communication interactions. Each node represents a cell type; node size is proportional to the number of interactions it participates in. Arc width encodes communication strength.

par(mfrow = c(1, 2), xpd = TRUE)

# Panel A: Number of interactions
netVisual_circle(
  net_count,
  vertex.weight = group_size,
  weight.scale  = TRUE,
  label.edge    = FALSE,
  title.name    = "Number of interactions"
)

# Panel B: Interaction strength (weights)
netVisual_circle(
  net_weight,
  vertex.weight = group_size,
  weight.scale  = TRUE,
  label.edge    = FALSE,
  title.name    = "Interaction weights/strength"
)

par(mfrow = c(1, 1))
Figure 1: Overall Cell-Cell Communication Circle Plot

2. Circle Plot for Individual Cell Groups

To highlight the outgoing signals from each cell type separately, we subset the weight matrix row by row and produce one circle per cell type.

n_types <- nrow(net_weight)
n_cols  <- ceiling(sqrt(n_types))
n_rows  <- ceiling(n_types / n_cols)

par(mfrow = c(n_rows, n_cols), xpd = TRUE, mar = c(1, 1, 2, 1))

for (i in seq_len(n_types)) {
  mat_i          <- matrix(0, nrow = n_types, ncol = n_types,
                           dimnames = dimnames(net_weight))
  mat_i[i, ]    <- net_weight[i, ]   # outgoing signals from cell type i

  netVisual_circle(
    mat_i,
    vertex.weight   = group_size,
    weight.scale    = TRUE,
    edge.weight.max = max(net_weight),
    title.name      = rownames(net_weight)[i]
  )
}

par(mfrow = c(1, 1))
Figure 2: Per-Cell-Type Outgoing Communication Circle Plot

3. Chord Diagram

The chord diagram provides an alternative circular view using circlize, clearly showing bidirectional communication volumes between cell type pairs.

# Use circlize for a chord diagram of communication weights
chordDiagram(
  net_weight,
  transparency      = 0.4,
  annotationTrack   = "grid",
  preAllocateTracks = 1
)

circos.trackPlotRegion(
  track.index = 1,
  panel.fun   = function(x, y) {
    circos.text(
      CELL_META$xcenter,
      CELL_META$ylim[1] + 0.1,
      CELL_META$sector.index,
      facing     = "clockwise",
      niceFacing = TRUE,
      adj        = c(0, 0.5),
      cex        = 0.7
    )
  },
  bg.border = NA
)

title("Cell-Cell Communication (Chord Diagram)")
circos.clear()
Figure 3: Cell-Cell Communication Chord Diagram

4. Communication Heatmap

A heatmap view allows rapid identification of dominant sender-receiver pairs and asymmetric communication patterns.

df_heat <- as.data.frame(as.table(net_weight))
colnames(df_heat) <- c("Sender", "Receiver", "Weight")

ggplot(df_heat, aes(x = Receiver, y = Sender, fill = Weight)) +
  geom_tile(color = "white", linewidth = 0.4) +
  scale_fill_gradient(low = "white", high = "#b74147", name = "Weight") +
  theme_minimal(base_size = 11) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid  = element_blank(),
    plot.title  = element_text(size = 13, face = "bold", hjust = 0.5)
  ) +
  labs(
    title = "Cell-Cell Communication Heatmap",
    x = "Receiver", y = "Sender"
  )
Figure 4: Cell-Cell Communication Heatmap

5. CellPhoneDB-Style Ligand-Receptor Dot Plot

The CellPhoneDB output is conventionally shown as a dot heatmap: rows = ligand-receptor pairs, columns = cell-type pairs, point size = permutation P value, colour = scaled mean expression of both partners [6]. This recipe reproduces that layout from a simulated interaction table.

set.seed(2401)
lr_pairs <- c("FGFR1_FGF2", "MET_HGF", "EGFR_EGFR", "VEGFB_FLT1",
              "NOTCH1_DLL1", "WNT5A_FZD5", "CXCL12_CXCR4", "PDGFB_PDGFRB")
cell_pairs <- c("EC1|EC2", "EC1|Fibro", "EC2|SMC", "Fibro|EC1",
                "EC2|EC2", "SMC|EC1", "Fibro|EC2", "EC1|SMC")

lr_df <- expand.grid(pair = lr_pairs, cell_pair = cell_pairs,
                     stringsAsFactors = FALSE)
lr_df$pval  <- runif(nrow(lr_df), 0, 1)
lr_df$mean  <- rnorm(nrow(lr_df), 0.5, 0.4)
lr_df$mean  <- pmax(pmin(lr_df$mean, 1.5), 0)

ggplot(lr_df, aes(cell_pair, pair, size = pval, colour = mean)) +
  geom_point(alpha = 0.85) +
  scale_size_continuous(range = c(0.5, 6), trans = "reverse",
                        name = "Permutation P") +
  scale_colour_gradient(low = "#445EAD", high = "#B2182B",
                        name = "Scaled mean\nexpression") +
  labs(x = "Cell-type pair", y = "Ligand-receptor pair") +
  theme_classic(base_size = 10) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        legend.box = "vertical")
Figure 5: CellPhoneDB-style dot plot: rows = ligand-receptor pairs, columns = cell-type pairs; point size = permutation P, colour = scaled mean expression.
Tip

Practice tips

  • CellPhoneDB permutation P values are one-sided (larger = more random); scale_size_continuous(trans = "reverse") flips the axis so larger points = more significant.
  • The colour scale represents the mean of the two partners’ normalised expression, which is what CellPhoneDB reports as scale_factor.
  • expand.grid() creates all pair combinations; subset to significant interactions (e.g. P < 0.05) before plotting for cleaner figures.

References

References

[1] Jin S, Guerrero-Juarez CF, Zhang L, et al. Inference and analysis of cell-cell communication using CellChat. Nature Communications. 2021;12(1):1088. https://doi.org/10.1038/s41467-021-21246-9

[2] Jin S, et al. CellChat for systematic analysis of cell-cell communication from single-cell transcriptomics. Nature Protocols. 2024. https://doi.org/10.1038/s41596-024-01045-4

[3] CellChat GitHub: https://github.com/jinworks/CellChat