ConvergeR is an analytical toolkit designed to compute, visualize, and statistically evaluate the convergence of single-cell states, based on the methodology established by Whitfield et al. (2026).
In this vignette, we will demonstrate the package workflow using a full dataset of 3,000 Peripheral Blood Mononuclear Cells (PBMC). We will evaluate cells for their balance between two opposing states: Immune Signaling UP versus Immune Signaling DN from MSigDB.
Let’s load the required packages and the lightweight subset of the PBMC dataset bundled with the package.
library(ConvergeR)
library(Seurat)
#> Loading required package: SeuratObject
#> Loading required package: sp
#> 'SeuratObject' was built under R 4.6.0 but the current version is
#> 4.6.1; it is recomended that you reinstall 'SeuratObject' as the ABI
#> for R may have changed
#> 'SeuratObject' was built with package 'Matrix' 1.7.5 but the current
#> version is 1.7.6; it is recomended that you reinstall 'SeuratObject' as
#> the ABI for 'Matrix' may have changed
#>
#> Attaching package: 'SeuratObject'
#> The following objects are masked from 'package:base':
#>
#> intersect, t
library(ggplot2)
# Load the built-in example dataset
seu_path <- system.file("extdata", "pbmc3k_subset.rds", package = "ConvergeR")
seu <- readRDS(seu_path)
# Normalising
seu <- NormalizeData(seu, verbose = FALSE)
# Inject mock clinical metadata to simulate a multi-patient cohort
set.seed(42)
seu$age <- sample(20:70, ncol(seu), replace = TRUE)
seu$tumor_status <- sample(c("Primary", "Metastatic"), ncol(seu), replace = TRUE)
seu$treatment <- sample(c("Treated", "Untreated"), ncol(seu), replace = TRUE)
seu$SS <- paste0("Patient_", sample(1:5, ncol(seu), replace = TRUE))Instead of manually importing .gmt files, we use the
msigdbr package to directly retrieve the official Hallmark
Immune signatures.
library(msigdbr)
# S'assurer que l'on travaille sur l'assay RNA principal
DefaultAssay(seu) <- "RNA"
# Récupérer deux signatures immunitaires/inflammatoires bien exprimées dans les PBMC
hallmark_sets <- msigdbr(species = "Homo sapiens", category = "H")
#> Downloading gene sets (first use only, may take a few minutes)...
raw_group1 <- hallmark_sets[hallmark_sets$gs_name == "HALLMARK_INTERFERON_ALPHA_RESPONSE", ]$gene_symbol
raw_group2 <- hallmark_sets[hallmark_sets$gs_name == "HALLMARK_INFLAMMATORY_RESPONSE", ]$gene_symbol
# Intersection stricte avec les gènes réellement présents dans pbmc3k_subset
group1_genes <- intersect(raw_group1, rownames(seu))
group2_genes <- intersect(raw_group2, rownames(seu))
# Calcul des scores de modules Seurat
seu <- AddModuleScore(seu, features = list(group1_genes), name = "Score_IFN_")
seu <- AddModuleScore(seu, features = list(group2_genes), name = "Score_Inflam_")
# Renommer proprement les colonnes pour la suite
seu$Score_IFN <- seu$Score_IFN_1
seu$Score_Inflam <- seu$Score_Inflam_1seu <- CalculateConvergedScore(
seurat_obj = seu,
principal_score = "Score_IFN",
other_scores = "Score_Inflam",
principal_name = "Interferon",
other_name = "Inflammatory",
output_colname = "Converged_Immune",
principal_color = "#9b59b6", # Violet pour Interféron
other_color = "#e67e22" # Orange pour Inflammatoire
)ConvergeR automatically reads the color metadata generated in the previous step to produce standardized plots.
Proportion of cells converging to either Immune state across our 10 mock patients.
PlotConvergenceProportion(
seurat_obj = seu,
x_var = "SS",
fill_var = "Converged_Immune_Direction",
title = "Immune Convergence by Patient"
)We evaluate the statistical significance at the patient level (pseudobulk) to prevent pseudoreplication bias caused by single-cell testing.
TestConvergenceScore(
seurat_obj = seu,
score_var = "Converged_Immune",
test_var = "age",
level = "patient",
patient_id_var = "SS"
)
#> Spearman correlation | level: patient (pseudobulk) | N = 5 | testing 'Converged_Immune' by 'age' | p = 0.517How to read this result: The output message displays the statistical test used (e.g., Spearman correlation for continuous variables), the analysis level (patient pseudobulk to avoid single-cell pseudoreplication), the number of observations (\(N\) patients), and the p-value. A p-value below 0.05 indicates a statistically significant association between the convergence score and the tested variable.
TestMultivariateConvergence(
seurat_obj = seu,
score_var = "Converged_Immune",
test_vars = c("age", "tumor_status", "treatment"),
level = "patient",
patient_id_var = "SS"
)
#> ======================================================
#> Multivariate Linear Model | level: patient (pseudobulk) | N = 5
#> Formula: Converged_Immune ~ age + tumor_status + treatment
#> Global Model R-squared: 0.77 | Global p-value: 0.586
#> ------------------------------------------------------
#> Independent Variable Effects:
#> - age : p = 0.563 (Estimate = 0.002)
#> - tumor_statusPrimary : p = 0.599 (Estimate = -0.079)
#> - treatmentUntreated : p = 0.551 (Estimate = 0.078)
#> ======================================================How to read this result: This model fits a multivariable linear regression on pseudobulk data. It details the global model performance (\(R^2\) and global p-value) and breaks down the independent effect (Estimate) and significance (p-value accompanied by conventional significance stars) for each covariate, allowing you to assess the effect of a variable while controlling for potential confounders.
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] msigdbr_26.1.1 ggplot2_4.0.3 Seurat_5.5.1 SeuratObject_5.4.0
#> [5] sp_2.2-3 ConvergeR_0.99.0 BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] deldir_2.0-4 pbapply_1.7-5 gridExtra_2.3.1
#> [4] rlang_1.3.0 magrittr_2.0.5 RcppAnnoy_0.0.23
#> [7] otel_0.2.0 spatstat.geom_3.8-3 matrixStats_1.5.0
#> [10] ggridges_0.5.7 compiler_4.6.1 png_0.1-9
#> [13] vctrs_0.7.3 reshape2_1.4.5 stringr_1.6.0
#> [16] pkgconfig_2.0.3 fastmap_1.2.0 labeling_0.4.3
#> [19] promises_1.5.0 rmarkdown_2.32 purrr_1.2.2
#> [22] xfun_0.61 cachem_1.1.0 jsonlite_2.0.0
#> [25] goftest_1.2-3 later_1.4.8 spatstat.utils_3.2-5
#> [28] irlba_2.3.7 parallel_4.6.1 cluster_2.1.8.3
#> [31] R6_2.6.1 ica_1.0-3 spatstat.data_3.1-9
#> [34] bslib_0.12.0 stringi_1.8.9 RColorBrewer_1.1-3
#> [37] reticulate_1.47.0 spatstat.univar_3.2-0 parallelly_1.48.0
#> [40] lmtest_0.9-40 jquerylib_0.1.4 scattermore_1.2
#> [43] assertthat_0.2.1 Rcpp_1.1.2 knitr_1.52
#> [46] tensor_1.5.1 future.apply_1.20.2 zoo_1.9-0
#> [49] sctransform_0.4.3 httpuv_1.6.17 Matrix_1.7-6
#> [52] splines_4.6.1 igraph_2.3.3 tidyselect_1.2.1
#> [55] abind_1.4-8 yaml_2.3.12 spatstat.random_3.5-2
#> [58] spatstat.explore_3.8-3 codetools_0.2-20 miniUI_0.1.2
#> [61] curl_8.0.0 listenv_1.0.0 plyr_1.8.9
#> [64] lattice_0.23-1 tibble_3.3.1 withr_3.0.3
#> [67] shiny_1.14.0 S7_0.2.2 ROCR_1.0-12
#> [70] evaluate_1.0.5 Rtsne_0.17 future_1.75.0
#> [73] fastDummies_1.7.6 survival_3.8-12 polyclip_1.10-7
#> [76] fitdistrplus_1.2-6 pillar_1.11.1 BiocManager_1.30.27
#> [79] KernSmooth_2.23-27 plotly_4.12.1 generics_0.1.4
#> [82] RcppHNSW_0.7.0 scales_1.4.0 globals_0.19.1
#> [85] xtable_1.8-8 glue_1.8.1 maketools_1.3.2
#> [88] tools_4.6.1 sys_3.4.3 data.table_1.18.6.1
#> [91] RSpectra_0.16-2 RANN_2.6.3 buildtools_1.0.0
#> [94] dotCall64_1.2 cowplot_1.2.0 grid_4.6.1
#> [97] tidyr_1.3.2 nlme_3.1-171 patchwork_1.3.2
#> [100] cli_3.6.6 spatstat.sparse_3.2-0 spam_2.11-4
#> [103] viridisLite_0.4.3 dplyr_1.2.1 uwot_0.2.5
#> [106] gtable_0.3.6 sass_0.4.10 digest_0.6.39
#> [109] progressr_1.0.0 ggrepel_0.9.8 htmlwidgets_1.6.4
#> [112] farver_2.1.2 htmltools_0.5.9 lifecycle_1.0.5
#> [115] httr_1.4.9 mime_0.13 MASS_7.3-66