The data in this package is published in the publication Bhuva et al., Genome Biology, 2024. Annotations for each dataset are obtained independently of the molecular measurements. The lowest level of measurement is annotated for each dataset. For BGI STOmics, this is each DNA nanoball, and for 10x Xenium and NanoString CosMx, these are the individual transcript detections. The package provides functions to convert these unit measurements into higher level summaries such as cells, regions, square bins, or hex bins for analysis purposes. These summaries are stored in SpatialExperiment objects.
The SubcellularSpatialData package can be downloaded as follows:
To download the data, we first need to get a list of the data
available in the SubcellularSpatialData package and
determine the unique identifiers for each data. The query()
function assists in getting this list.
eh = ExperimentHub()
query(eh, "SubcellularSpatialData")
#> ExperimentHub with 4 records
#> # snapshotDate(): 2026-10-07
#> # $dataprovider: 10x, NanoString, BGI
#> # $species: Mus musculus, Homo sapiens
#> # $rdataclass: data.frame
#> # additional mcols(): taxonomyid, genome, description,
#> # coordinate_1_based, maintainer, rdatadateadded, preparerclass, tags,
#> # rdatapath, sourceurl, sourcetype
#> # retrieve records with, e.g., 'object[["EH8230"]]'
#>
#> title
#> EH8230 | xenium_mm_brain
#> EH8231 | stomics_mm_brain
#> EH8232 | cosmx_hs_nsclc
#> EH8567 | xenium_hs_breast_addonData can then be downloaded using the unique identifier.
As the datasets are large in size, the code above is not executed. Instead, we will explore the package using a subsampled dataset that is available within the package.
# load internal sample data
data(tx_small)
# view data
head(tx_small)
#> sample_id cell gene genetype x y counts region
#> 1 IDC 151494 MLPH Gene 4504.334 3809.989 1 Invasive Tumor
#> 2 IDC 6761 PGR Gene 2496.278 8024.483 1 Invasive Tumor
#> 3 ILC 241408 ESR1 Gene 5941.193 2698.466 1 Invasive Tumor
#> 4 ILC 11168 TPD52 Gene 4108.165 6605.351 1 Invasive Tumor
#> 5 ILC 182726 SERPINB9 Gene 2697.842 7453.444 1 Invasive Tumor
#> 6 IDC 1431 RAMP2 Gene 3084.036 5910.526 1 Invasive Tumor
#> technology transcript_id overlaps_nucleus z_location qv
#> 1 Xenium 2.817885e+14 0 23.82261 29.55229
#> 2 Xenium 2.820548e+14 0 27.02060 40.00000
#> 3 Xenium 2.816253e+14 1 16.49564 30.72199
#> 4 Xenium 2.819431e+14 1 26.57264 40.00000
#> 5 Xenium 2.819904e+14 0 28.33879 27.57970
#> 6 Xenium 2.819088e+14 1 27.42442 35.51832The data is in the form of a transcript table where the following columns are present across all datasets:
Additional columns may be present for different technologies.
We now visualise the data on a spatial plot
library(ggplot2)
tx_small |>
ggplot(aes(x, y, colour = region)) +
geom_point(pch = ".") +
scale_colour_brewer(palette = "Set2", guide = guide_legend(override.aes = list(shape = 15, size = 5))) +
facet_wrap(~sample_id, ncol = 2, scales = "free") +
theme_minimal() +
theme(legend.position = "bottom")The transcript table is highly detailed containing a low-level form
of measurement. Users may be more interestered in working on binned
counts, cellular counts, or region-specific pseudo-bulked samples. These
can be obtained using the helper function tx2spe(). For
cellular counts, the original cell binning provided by the vendor is
used. Transcript aggregation is performed separately per sample
therefore users do not need to separate data per sample.
Please note that BGI only performs nuclear binning of counts therefore cellular counts obtained will represent nuclear counts only. We recommended that for fair evaluations during benchmarking, alternative binning algorithms that are fair are explored, or analysis be performed on square or hex binned counts.
library(SpatialExperiment)
# summarising counts per cell
tx2spe(tx_small, bin = "cell")
#> class: SpatialExperiment
#> dim: 489 92394
#> metadata(0):
#> assays(1): counts
#> rownames(489): MLPH PGR ... NegControlCodeword_0524
#> NegControlProbe_00009
#> rowData names(2): gene genetype
#> colnames(92394): IDC_10 IDC_100005 ... ILC_99993 ILC_99994
#> colData names(8): sample_id cell_id ... region technology
#> reducedDimNames(0):
#> mainExpName: NULL
#> altExpNames(0):
#> spatialCoords names(2) : x y
#> imgData names(0):
# summarising counts per square bin
tx2spe(tx_small, bin = "square", nbins = 30)
#> class: SpatialExperiment
#> dim: 489 1458
#> metadata(0):
#> assays(1): counts
#> rownames(489): MLPH PGR ... BLANK_0406 NegControlCodeword_0524
#> rowData names(2): gene genetype
#> colnames(1458): IDC_4 IDC_5 ... ILC_822 ILC_828
#> colData names(13): sample_id bin_id ... region technology
#> reducedDimNames(0):
#> mainExpName: NULL
#> altExpNames(0):
#> spatialCoords names(2) : x y
#> imgData names(0):
# summarising counts per hex bin
tx2spe(tx_small, bin = "hex", nbins = 30)
#> class: SpatialExperiment
#> dim: 489 1654
#> metadata(0):
#> assays(1): counts
#> rownames(489): MLPH PGR ... BLANK_0406 NegControlCodeword_0524
#> rowData names(2): gene genetype
#> colnames(1654): IDC_6 IDC_7 ... ILC_1077 ILC_1103
#> colData names(15): sample_id bin_id ... region technology
#> reducedDimNames(0):
#> mainExpName: NULL
#> altExpNames(0):
#> spatialCoords names(2) : x y
#> imgData names(0):
# summarising counts per region
tx2spe(tx_small, bin = "region")
#> class: SpatialExperiment
#> dim: 489 14
#> metadata(0):
#> assays(1): counts
#> rownames(489): MLPH PGR ... BLANK_0406 NegControlCodeword_0524
#> rowData names(2): gene genetype
#> colnames(14): IDC_Adipose tissue (fat) IDC_Blood vessels ... ILC_Normal
#> ducts ILC_Stroma
#> colData names(10): sample_id bin_id ... region technology
#> reducedDimNames(0):
#> mainExpName: NULL
#> altExpNames(0):
#> spatialCoords names(2) : x y
#> imgData names(0):When transcript counts are aggregated (using any approach),
aggregation of numeric columns is performed using the
mean(..., na.rm = TRUE) function and aggregation of
character/factor columns is performed such that the most frequent class
becomes the representative class. As such, for a hex bin, the highest
frequency region for the transcripts allocated to the bin becomes the
bin’s region annotation. New coordinates for cells, bins, or regions are
computed using the mean function as well, therefore represent the center
of mass for the object. For hex and square bins, the average coordinate
is computed by default, however, x and y indices for the bin are stored
in the colData under the bin_x and bin_y columns.
When aggregation is perfomed using bins or regions, an additional column, ncells, is computed that indicates how many unique cells are present within the bin/region. Do note that if a cell overlaps multiple bins/regions, it will be counted in each bin/region.
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] stats4 stats graphics grDevices utils datasets methods
#> [8] base
#>
#> other attached packages:
#> [1] SpatialExperiment_1.23.0 SingleCellExperiment_1.35.2
#> [3] SummarizedExperiment_1.43.0 Biobase_2.73.2
#> [5] GenomicRanges_1.65.4 Seqinfo_1.3.2
#> [7] IRanges_2.47.5 S4Vectors_0.51.10
#> [9] MatrixGenerics_1.25.0 matrixStats_1.5.0
#> [11] ggplot2_4.0.3 ExperimentHub_3.3.2
#> [13] AnnotationHub_4.3.2 BiocFileCache_3.3.0
#> [15] dbplyr_2.6.0 BiocGenerics_0.59.12
#> [17] generics_0.1.4 SubcellularSpatialData_1.9.0
#> [19] prettydoc_0.4.1
#>
#> loaded via a namespace (and not attached):
#> [1] tidyselect_1.2.1 dplyr_1.2.1 farver_2.1.2
#> [4] blob_1.3.0 filelock_1.0.3 Biostrings_2.81.9
#> [7] S7_0.2.2 fastmap_1.2.0 digest_0.6.39
#> [10] lifecycle_1.0.5 KEGGREST_1.53.6 RSQLite_3.53.3
#> [13] magrittr_2.0.5 compiler_4.6.1 rlang_1.3.0
#> [16] sass_0.4.10 tools_4.6.1 yaml_2.3.12
#> [19] knitr_1.52 S4Arrays_1.13.2 labeling_0.4.3
#> [22] bit_4.6.0 curl_8.0.0 DelayedArray_0.39.8
#> [25] RColorBrewer_1.1-3 abind_1.4-8 withr_3.0.3
#> [28] purrr_1.2.2 sys_3.4.3 grid_4.6.1
#> [31] scales_1.4.0 cli_3.6.6 rmarkdown_2.32
#> [34] crayon_1.5.3 otel_0.2.0 httr_1.4.9
#> [37] rjson_0.2.23 BiocBaseUtils_1.15.1 DBI_1.3.0
#> [40] cachem_1.1.0 AnnotationDbi_1.75.2 BiocManager_1.30.27
#> [43] XVector_0.53.0 vctrs_0.7.3 Matrix_1.7-6
#> [46] jsonlite_2.0.0 bit64_4.8.6 maketools_1.3.2
#> [49] magick_2.9.1 jquerylib_0.1.4 hexbin_1.28.6
#> [52] glue_1.8.1 gtable_0.3.6 BiocVersion_3.24.0
#> [55] tibble_3.3.1 pillar_1.11.1 rappdirs_0.3.4
#> [58] htmltools_0.5.9 R6_2.6.1 httr2_1.3.0
#> [61] evaluate_1.0.5 lattice_0.23-1 png_0.1-9
#> [64] memoise_2.0.1 BiocStyle_2.41.0 bslib_0.12.0
#> [67] Rcpp_1.1.2 SparseArray_1.13.4 xfun_0.61
#> [70] buildtools_1.0.0 pkgconfig_2.0.3