CytoSPACER is an R implementation of CytoSPACE (Vahid et al., Nature Biotechnology, 2023), designed for high-resolution mapping of single-cell transcriptomes to spatial transcriptomics (ST) data. This vignette provides a quick introduction to get you started with the package.
Let’s create a simple simulated dataset to demonstrate the workflow:
set.seed(42)
# Simulate scRNA-seq data (100 genes x 500 cells)
n_genes <- 100
n_cells <- 500
n_spots <- 50
# Create expression matrix with some structure
sc_data <- matrix(
rpois(n_genes * n_cells, lambda = 5),
nrow = n_genes,
ncol = n_cells
)
rownames(sc_data) <- paste0("Gene", seq_len(n_genes))
colnames(sc_data) <- paste0("Cell", seq_len(n_cells))
# Add cell type-specific expression patterns
cell_types <- rep(c("TypeA", "TypeB", "TypeC", "TypeD", "TypeE"), each = 100)
names(cell_types) <- colnames(sc_data)
# TypeA cells express genes 1-20 highly
sc_data[1:20, cell_types == "TypeA"] <- sc_data[1:20, cell_types == "TypeA"] + 20
# TypeB cells express genes 21-40 highly
sc_data[21:40, cell_types == "TypeB"] <- sc_data[21:40, cell_types == "TypeB"] + 20
# TypeC cells express genes 41-60 highly
sc_data[41:60, cell_types == "TypeC"] <- sc_data[41:60, cell_types == "TypeC"] + 20
# Simulate ST data (100 genes x 50 spots)
st_data <- matrix(
rpois(n_genes * n_spots, lambda = 50),
nrow = n_genes,
ncol = n_spots
)
rownames(st_data) <- paste0("Gene", seq_len(n_genes))
colnames(st_data) <- paste0("Spot", seq_len(n_spots))
# Create spatial coordinates (grid pattern)
coordinates <- data.frame(
row = rep(1:10, each = 5),
col = rep(1:5, times = 10),
row.names = colnames(st_data)
)
# Display data dimensions
cat("scRNA-seq data:", nrow(sc_data), "genes x", ncol(sc_data), "cells\n")
#> scRNA-seq data: 100 genes x 500 cells
cat("ST data:", nrow(st_data), "genes x", ncol(st_data), "spots\n")
#> ST data: 100 genes x 50 spots
cat("Cell types:", paste(unique(cell_types), collapse = ", "), "\n")
#> Cell types: TypeA, TypeB, TypeC, TypeD, TypeENow let’s run the main analysis. We’ll provide pre-computed cell type fractions to skip the Seurat-dependent deconvolution step:
# Create simple cell type fractions (for demonstration)
# In real analysis, these would be estimated from the data
unique_types <- unique(cell_types)
n_types <- length(unique_types)
cell_type_fractions <- matrix(
1/n_types,
nrow = n_spots,
ncol = n_types,
dimnames = list(colnames(st_data), unique_types)
)
cell_type_fractions <- as.data.frame(cell_type_fractions)
# Run CytoSPACER with default parameters
results <- run_cytospace(
sc_data = sc_data,
cell_types = cell_types,
st_data = st_data,
coordinates = coordinates,
cell_type_fractions = cell_type_fractions,
mean_cells_per_spot = 5,
distance_metric = "pearson",
sampling_method = "duplicates",
seed = 42,
verbose = TRUE
)The results object contains several components:
# Check the structure
names(results)
#> [1] "assigned_locations" "expression" "cell_type_by_spot"
#> [4] "fractional_abundances" "parameters" "log"
#> [7] "runtime"
# View assigned locations
head(results$assigned_locations)
#> UniqueCID OriginalCID CellType SpotID row col
#> 1 UCID001 Cell49 TypeA Spot26 6 1
#> 2 UCID002 Cell65 TypeA Spot28 6 3
#> 3 UCID003 Cell25 TypeA Spot26 6 1
#> 4 UCID004 Cell74 TypeA Spot28 6 3
#> 5 UCID005 Cell18 TypeA Spot26 6 1
#> 6 UCID006 Cell100 TypeA Spot28 6 3
# Cell type counts per spot
head(results$cell_type_by_spot)
#> TypeA TypeB TypeC TypeD TypeE Total
#> Spot1 0 1 0 2 1 4
#> Spot10 0 2 0 1 0 3
#> Spot11 1 1 3 0 2 7
#> Spot12 2 0 1 0 0 3
#> Spot13 0 0 0 1 2 3
#> Spot14 6 0 0 0 0 6
# Fractional abundances
head(results$fractional_abundances)
#> TypeA TypeB TypeC TypeD TypeE
#> Spot1 0.0000000 0.2500000 0.0000000 0.5000000 0.2500000
#> Spot10 0.0000000 0.6666667 0.0000000 0.3333333 0.0000000
#> Spot11 0.1428571 0.1428571 0.4285714 0.0000000 0.2857143
#> Spot12 0.6666667 0.0000000 0.3333333 0.0000000 0.0000000
#> Spot13 0.0000000 0.0000000 0.0000000 0.3333333 0.6666667
#> Spot14 1.0000000 0.0000000 0.0000000 0.0000000 0.0000000CytoSPACER provides several visualization functions:
# Total cells assigned
cat("Total cells assigned:", nrow(results$assigned_locations), "\n")
#> Total cells assigned: 249
# Cells per cell type
table(results$assigned_locations$CellType)
#>
#> TypeA TypeB TypeC TypeD TypeE
#> 49 50 50 50 50
# Average cells per spot
cat("Average cells per spot:",
mean(results$cell_type_by_spot$Total), "\n")
#> Average cells per spot: 4.98
# Runtime
cat("Analysis runtime:", round(results$runtime, 2), "seconds\n")
#> Analysis runtime: 0.02 secondssessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04 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] future_1.70.0 Matrix_1.7-5 CytoSPACER_1.0.0 rmarkdown_2.31
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.6 future.apply_1.20.2 jsonlite_2.0.0
#> [4] dplyr_1.2.1 compiler_4.6.1 Rcpp_1.1.1-1.1
#> [7] tidyselect_1.2.1 parallel_4.6.1 jquerylib_0.1.4
#> [10] globals_0.19.1 scales_1.4.0 yaml_2.3.12
#> [13] fastmap_1.2.0 lattice_0.22-9 ggplot2_4.0.3
#> [16] R6_2.6.1 labeling_0.4.3 generics_0.1.4
#> [19] knitr_1.51 tibble_3.3.1 maketools_1.3.2
#> [22] pillar_1.11.1 bslib_0.11.0 RColorBrewer_1.1-3
#> [25] rlang_1.2.0 cachem_1.1.0 xfun_0.59
#> [28] sass_0.4.10 sys_3.4.3 S7_0.2.2
#> [31] otel_0.2.0 cli_3.6.6 withr_3.0.3
#> [34] progressr_1.0.0 magrittr_2.0.5 digest_0.6.39
#> [37] grid_4.6.1 lifecycle_1.0.5 vctrs_0.7.3
#> [40] evaluate_1.0.5 glue_1.8.1 data.table_1.18.4
#> [43] farver_2.1.2 listenv_1.0.0 codetools_0.2-20
#> [46] buildtools_1.0.0 parallelly_1.48.0 pkgconfig_2.0.3
#> [49] tools_4.6.1 htmltools_0.5.9