scCompoundDE decomposes pseudo-bulk differential expression (DE) signals into two orthogonal components:
Standard pseudo-bulk tools (DESeq2, edgeR, limma-voom) cannot distinguish between these two sources. Every published pseudo-bulk DE result potentially conflates them.

Donor A (disease): 80% exhausted T cells (high PDCD1, TOX)
Donor B (healthy): 80% naive T cells (high IL7R, CCR7)
Standard pseudo-bulk DE reports:
→ PDCD1 UP p = 1e-8 ← but is this transcriptional or compositional?
→ IL7R DOWN p = 1e-6 ← same question
scCompoundDE answers:
→ PDCD1 TC_ratio = 0.12 → compositional artefact ⚠
→ IL7R TC_ratio = 0.09 → compositional artefact ⚠
→ IFNG TC_ratio = 0.91 → transcriptional signal ✓
For each gene, compoundDE() returns a TC_ratio in [0, 1]:
| TC_ratio | Classification | Meaning |
|---|---|---|
| ≥ 0.8 | Transcriptional | Real cell-intrinsic biology |
| ≤ 0.2 | Compositional | Subtype proportion artefact |
| 0.2–0.8 | Mixed | Both mechanisms contribute |
# From Bioconductor
BiocManager::install("scCompoundDE")
# Development version from GitHub
BiocManager::install("SubhadipJana1409/scCompoundDE")
library(scCompoundDE)
result <- compoundDE(
sce,
broad_type = "T_cell", # broad population to decompose
subtype_col = "cell_subtype",# fine-grained subtype labels
broad_col = "cell_type", # broad label column
donor = "donor",
condition = "condition",
min_cells = 10L,
min_subtypes = 2L
)
result
# CDEResult
# Broad type : T_cell
# Subtypes : Exhausted, Naive, Memory
# Genes tested : 8,342
# Significant : 1,204 (adj.P.Val < 0.05)
# ── Decomposition ──────────────────
# Transcriptional: 831 genes (TC_ratio >= 0.8)
# Compositional : 203 genes (TC_ratio <= 0.2)
# Mixed : 170 genes
# Get only transcriptionally-driven genes
real_genes <- filterGenesBySource(result, source = "transcriptional")
# Visualise
plotDecomposition(result) # T_score vs C_score scatter
plotTCRatio(result) # TC_ratio histogram
plotProportion(result) # subtype proportions per condition
We validated scCompoundDE on the widely used Kang et al. (2018) IFN-β PBMC dataset:
The algorithm correctly identified 9 out of 10 canonical interferon-stimulated genes (e.g., ISG15, IFIT1, MX1) and successfully classified them as transcriptionally driven. This confirms the method reliably isolates true, cell-intrinsic biological responses from confounding factors.
Out of 5,975 significant genes (FDR < 0.05), 547 genes were flagged as purely compositional artefacts (TC_ratio ≤ 0.2). These are genes that standard pseudo-bulk tools would mistakenly report as cell-intrinsic DEGs, but are actually just the result of subtype proportion shifts (e.g., an influx of a specific cell type) across conditions. Examples of these artefacts include ACTB, FTH1, GAPDH, and S100A8.
Each gene's transcriptional (T) vs compositional (C) z-scores. Blue = transcriptional, red = compositional, orange = mixed.

Histogram of TC_ratio values across all significant genes. Vertical lines mark the classification thresholds (0.2 and 0.8).

Mean subtype proportions per condition. Shifts here drive the compositional component of the DE signal.

min_cells).T_g = Σ_k π̄_k · logFC_gk (proportion-weighted transcript shift)C_g = Σ_k Δπ_k · μ_gk (expression-weighted proportion shift)TC_ratio_g = |T_z| / (|T_z| + |C_z|).| Function | Description |
|---|---|
compoundDE() |
Full decomposition pipeline → CDEResult
|
filterGenesBySource() |
Extract gene lists by classification |
plotDecomposition() |
Scatter: T_score vs C_score per gene |
plotProportion() |
Stacked bar: subtype proportions per condition |
plotTCRatio() |
Histogram of TC_ratio with threshold lines |
deTable(result) # DataFrame with all stats + TC_ratio + source
subtypeProportions(result) # matrix: samples × subtypes
subtypeDE(result) # list of per-subtype DE DataFrames
tcRatio(result) # named numeric: TC_ratio per gene
Jana S (2026). scCompoundDE: Compositional and Transcriptional Decomposition of Pseudo-Bulk Differential Expression for Single-Cell RNA-seq. R package version 0.99.0. https://github.com/SubhadipJana1409/scCompoundDE
MIT © Subhadip Jana