RPBC can be installed from Bioconductor using:
if (!requireNamespace("BiocManager", quietly = TRUE)) {
install.packages("BiocManager")
}
BiocManager::install("RPBC")
After installation, load the package with:
library(RPBC)
Region-Preserving Batch Correction (RPBC) is designed for paired region-resolved single-cell and spatial molecular data in which patient-associated nuisance variation should be reduced while preserving a prespecified population-average regional effect.
RPBC supports three related workflows:
The primary user interface is rpbc(). It accepts either a
SingleCellExperiment or SpatialExperiment object and returns the input
object with the harmonized expression matrix stored as a new assay.
Package version: 0.99.1
The package includes haley_gbm_example, a representative subset of a
published glioblastoma imaging mass cytometry (IMC) dataset. The example retains
all seven patients included in the RPBC real-world application and preserves the
paired Core/Edge design, with 30 cells sampled from each patient-region combination.
The object contains 420 cells and 10 representative biological markers.
Raw IMC intensities are stored in the "counts" assay.
data("haley_gbm_example", package = "RPBC")
haley_gbm_example
#> class: SpatialExperiment
#> dim: 10 420
#> metadata(0):
#> assays(1): counts
#> rownames(10): CD45 CD3 ... Ki67 Vimentin
#> rowData names(0):
#> colnames(420): ROI_1A1_cell_337 ROI_1A1_cell_460 ... ROI_7A3_cell_12293
#> ROI_7A3_cell_12381
#> colData names(8): cell_id ROI ... mgmt_status sample_id
#> reducedDimNames(0):
#> mainExpName: NULL
#> altExpNames(0):
#> spatialCoords names(0) :
#> imgData names(0):
dim(haley_gbm_example)
#> [1] 10 420
SummarizedExperiment::assayNames(haley_gbm_example)
#> [1] "counts"
The paired patient-region structure can be inspected directly from the cell-level metadata.
table(
haley_gbm_example$patient_id,
haley_gbm_example$region_type
)
#>
#> Core Edge
#> 1 30 30
#> 2 30 30
#> 3 30 30
#> 4 30 30
#> 5 30 30
#> 6 30 30
#> 7 30 30
Each of the seven patients contributes cells from both Core and Edge, satisfying the paired regional structure required by RPBC.
The example data are derived from:
Haley MJ, et al. (2024). Hypoxia coordinates the spatial landscape of myeloid cells within glioblastoma to affect survival. Science Advances, 10(20), eadj3301. doi:10.1126/sciadv.adj3301.
Haley M, Couper K. (2024). Imaging mass cytometry data from IDH wildtype glioblastomas. Dryad. doi:10.5061/dryad.2z34tmprw.
RPBC separates assay selection from transformation through the
assay_name and transform arguments.
The available transformations are:
"none": use the selected assay exactly as supplied;"asinh": apply asinh(x / cofactor);"log1p": apply log(x + 1) to non-negative values.For the bundled IMC example, the "counts" assay contains raw intensities,
so the analyses below use:
transform = "asinh"
cofactor = 5
If an assay has already been appropriately normalized and transformed,
such as a sequencing "logcounts" assay, it can instead be supplied with
transform = "none".
The "log1p" option performs only the transformation log(x + 1); it is
not a replacement for sequencing-data normalization.
Ordinary RPBC is the base workflow for a paired region-resolved design. RPBC harmonizes patient and patient-by-region nuisance components while retaining the population-average Core/Edge regional effect.
example_ordinary <- rpbc(
object = haley_gbm_example,
patient = "patient_id",
region = "region_type",
assay_name = "counts",
transform = "asinh",
cofactor = 5,
adaptive = FALSE,
output_assay = "rpbc"
)
SummarizedExperiment::assayNames(example_ordinary)
#> [1] "counts" "rpbc"
The original "counts" assay remains available, while the harmonized
values are stored in the new "rpbc" assay.
dim(
SummarizedExperiment::assay(
example_ordinary,
"rpbc"
)
)
#> [1] 10 420
Adaptive RPBC uses the same paired biological target but incorporates group-size-dependent stabilization into the patient-region scale adjustment.
example_adaptive <- rpbc(
object = haley_gbm_example,
patient = "patient_id",
region = "region_type",
assay_name = "counts",
transform = "asinh",
cofactor = 5,
adaptive = TRUE,
output_assay = "rpbc_adaptive"
)
SummarizedExperiment::assayNames(example_adaptive)
#> [1] "counts" "rpbc_adaptive"
The bundled example is deliberately balanced at 30 cells per patient-region combination. It therefore demonstrates the Adaptive RPBC interface and output structure rather than the effect of unequal patient-region sample sizes.
The Adaptive RPBC defaults are:
delta_adaptive_k = 1
delta_bounds = c(0.5, 2)
and can be modified through rpbc() when appropriate.
Covariate-adjusted RPBC is used when patient-level variables should be
retained as part of the preserved mean structure. Covariates supplied
through covariates must be constant within patient.
The Haley example contains patient age and sex, so both are included below.
example_covariate <- rpbc(
object = haley_gbm_example,
patient = "patient_id",
region = "region_type",
assay_name = "counts",
transform = "asinh",
cofactor = 5,
covariates = c("age", "sex"),
adaptive = FALSE,
output_assay = "rpbc_covariate"
)
SummarizedExperiment::assayNames(example_covariate)
#> [1] "counts" "rpbc_covariate"
The harmonized expression matrix is stored in "rpbc_covariate".
dim(
SummarizedExperiment::assay(
example_covariate,
"rpbc_covariate"
)
)
#> [1] 10 420
Adaptive RPBC and covariate-adjusted RPBC are currently implemented as separate extensions and therefore should not be requested simultaneously.
The harmonized matrix can be accessed using the standard
SummarizedExperiment assay interface. For example:
rpbc_matrix <- SummarizedExperiment::assay(
example_ordinary,
"rpbc"
)
rpbc_matrix[1:5, 1:5]
#> ROI_1A1_cell_337 ROI_1A1_cell_460 ROI_1A1_cell_514 ROI_1A1_cell_3185
#> CD45 4.332762e-07 6.476164e-07 2.945675e-07 4.883923e-07
#> CD3 1.924978e-06 1.187254e-06 1.770623e-06 1.436945e-06
#> Cd8a 1.289758e-06 1.564613e-06 2.083473e-06 4.455594e-07
#> CD68 -4.757505e-09 1.286778e-07 -2.303632e-08 -1.162583e-07
#> CD163 -3.429965e-07 3.253885e-07 7.140947e-07 -1.045584e-07
#> ROI_1A1_cell_3214
#> CD45 6.384304e-07
#> CD3 9.352934e-07
#> Cd8a 2.159198e-06
#> CD68 6.386567e-07
#> CD163 -2.871333e-08
The matrix retains the same marker-by-cell dimensions and dimnames as the selected input assay, allowing the harmonized values to be used in downstream single-cell or spatial analyses.
RPBC does not prescribe a particular downstream workflow. Dimensionality reduction, clustering, visualization, differential analyses, or other biological analyses can therefore be performed using methods appropriate for the study after harmonization.
The three workflows address related but distinct analysis settings.
Ordinary RPBC is appropriate when the primary objective is to reduce patient and patient-by-region nuisance variation while preserving the population-average regional effect and no additional patient-level covariates need to be protected.
Adaptive RPBC is appropriate when group-size-dependent stabilization of patient-region scale adjustment is desired, particularly in designs with unequal patient-region sample sizes.
Covariate-adjusted RPBC is appropriate when known patient-level covariates, such as age or sex, should remain part of the protected mean structure during harmonization.
Only one of the Adaptive or covariate-adjusted extensions should currently be used in a single RPBC call.
By default, rpbc() returns the modified Bioconductor object. Users who
require internal fitted quantities or convergence information can set:
return_fit = TRUE
The result is then a list containing the harmonized object in object and
the fitted RPBC quantities in fit.
For example:
example_fit <- rpbc(
object = haley_gbm_example,
patient = "patient_id",
region = "region_type",
assay_name = "counts",
transform = "asinh",
cofactor = 5,
adaptive = FALSE,
output_assay = "rpbc_fit_example",
return_fit = TRUE
)
names(example_fit)
#> [1] "object" "fit"
all(example_fit$fit$converged)
#> [1] TRUE
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.5 LTS
#>
#> Matrix products: default
#> BLAS: /home/biocbuild/bbs-3.24-bioc/R/lib/libRblas.so
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_GB LC_COLLATE=C
#> [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: America/New_York
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] RPBC_0.99.1 BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] Matrix_1.7-6 jsonlite_2.0.0
#> [3] rjson_0.2.23 compiler_4.6.1
#> [5] BiocManager_1.30.27 Rcpp_1.1.2
#> [7] SpatialExperiment_1.23.0 SummarizedExperiment_1.43.0
#> [9] Biobase_2.73.2 magick_2.9.1
#> [11] GenomicRanges_1.65.4 jquerylib_0.1.4
#> [13] IRanges_2.47.5 Seqinfo_1.3.2
#> [15] yaml_2.3.12 fastmap_1.2.0
#> [17] lattice_0.23-1 R6_2.6.1
#> [19] XVector_0.53.0 S4Arrays_1.13.2
#> [21] generics_0.1.4 knitr_1.52
#> [23] BiocGenerics_0.59.12 DelayedArray_0.39.8
#> [25] bookdown_0.48 MatrixGenerics_1.25.0
#> [27] bslib_0.12.0 rlang_1.3.0
#> [29] cachem_1.1.0 xfun_0.62
#> [31] sass_0.4.10 otel_0.3.0
#> [33] SparseArray_1.13.4 cli_3.6.6
#> [35] magrittr_2.0.5 digest_0.6.39
#> [37] grid_4.6.1 lifecycle_1.0.5
#> [39] S4Vectors_0.51.10 SingleCellExperiment_1.35.2
#> [41] evaluate_1.0.5 abind_1.4-8
#> [43] stats4_4.6.1 rmarkdown_2.32
#> [45] matrixStats_1.5.0 tools_4.6.1
#> [47] htmltools_0.5.9