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.0
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 30Each 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:
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.
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:
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".
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-08The 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:
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] TRUEsessionInfo()
#> 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] RPBC_0.99.0 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 XVector_0.53.0
#> [19] R6_2.6.1 S4Arrays_1.13.2
#> [21] generics_0.1.4 knitr_1.52
#> [23] BiocGenerics_0.59.12 DelayedArray_0.39.8
#> [25] MatrixGenerics_1.25.0 maketools_1.3.2
#> [27] bslib_0.12.0 rlang_1.3.0
#> [29] cachem_1.1.0 xfun_0.61
#> [31] sass_0.4.10 sys_3.4.3
#> [33] otel_0.2.0 SparseArray_1.13.4
#> [35] cli_3.6.6 magrittr_2.0.5
#> [37] digest_0.6.39 grid_4.6.1
#> [39] lifecycle_1.0.5 S4Vectors_0.51.10
#> [41] SingleCellExperiment_1.35.2 evaluate_1.0.5
#> [43] buildtools_1.0.0 abind_1.4-8
#> [45] stats4_4.6.1 rmarkdown_2.32
#> [47] matrixStats_1.5.0 tools_4.6.1
#> [49] htmltools_0.5.9