SpaGER: Quick Start Guide

Introduction

SpaGER (Spatial Gene Expression in R) is a high-performance R implementation of the SpaGE algorithm for predicting genome-wide expression profiles in spatial transcriptomics data through integration with scRNA-seq reference datasets.

Why SpaGER?

Spatial transcriptomics technologies provide invaluable spatial context but often measure only a limited panel of genes. SpaGER addresses this limitation by:

  • Leveraging scRNA-seq data to impute unmeasured genes in spatial data
  • Using domain adaptation via Principal Vectors (PVs)
  • Providing C++ acceleration for high performance
  • Supporting seamless Seurat integration

Installation

# From R-Universe (recommended)
install.packages("SpaGER", repos = "https://zaoqu-liu.r-universe.dev")

# From GitHub
remotes::install_github("Zaoqu-Liu/SpaGER")

Basic Usage

Load Package

library(SpaGER)

Generate Simulated Data

For demonstration, we create simulated spatial and scRNA-seq datasets:

set.seed(42)

# Simulate scRNA-seq reference data
n_rna_cells <- 500
n_spatial_cells <- 200
n_shared_genes <- 100
n_rna_only_genes <- 50

# scRNA-seq data: cells x genes
rna_data <- matrix(
  abs(rnorm(n_rna_cells * (n_shared_genes + n_rna_only_genes), mean = 5, sd = 2)),
  nrow = n_rna_cells
)
colnames(rna_data) <- c(
  paste0("SharedGene", 1:n_shared_genes),
  paste0("RNAOnlyGene", 1:n_rna_only_genes)
)
rownames(rna_data) <- paste0("RNACell", 1:n_rna_cells)

# Spatial data: only shared genes
spatial_data <- matrix(
  abs(rnorm(n_spatial_cells * n_shared_genes, mean = 5, sd = 2)),
  nrow = n_spatial_cells
)
colnames(spatial_data) <- paste0("SharedGene", 1:n_shared_genes)
rownames(spatial_data) <- paste0("SpatialSpot", 1:n_spatial_cells)

cat("scRNA-seq data:", nrow(rna_data), "cells x", ncol(rna_data), "genes\n")
#> scRNA-seq data: 500 cells x 150 genes
cat("Spatial data:", nrow(spatial_data), "cells x", ncol(spatial_data), "genes\n")
#> Spatial data: 200 cells x 100 genes

Run SpaGE Prediction

# Predict unmeasured genes
predicted <- SpaGE(
  spatial_data = as.data.frame(spatial_data),
  rna_data = as.data.frame(rna_data),
  n_pv = 30,                # Number of principal vectors
  n_neighbors = 50,         # k for KNN imputation
  verbose = TRUE
)

# Check results
cat("\nPredicted:", ncol(predicted), "genes for", nrow(predicted), "spatial spots\n")
#> 
#> Predicted: 50 genes for 200 spatial spots
head(predicted[, 1:5])
#>              RNAOnlyGene1 RNAOnlyGene2 RNAOnlyGene3 RNAOnlyGene4 RNAOnlyGene5
#> SpatialSpot1     5.052071     4.473041     5.137224     4.748652     4.786710
#> SpatialSpot2     5.204982     5.343771     5.186167     4.870106     5.362815
#> SpatialSpot3     5.500350     5.128955     4.858680     4.870086     4.983224
#> SpatialSpot4     4.914745     5.253821     4.816689     5.028372     4.672101
#> SpatialSpot5     5.061131     5.269184     4.849490     5.045723     4.868479
#> SpatialSpot6     4.912111     5.250018     5.033773     5.171062     5.024322

Predict Specific Genes

# Predict only specific genes of interest
genes_of_interest <- c("RNAOnlyGene1", "RNAOnlyGene10", "RNAOnlyGene25")

predicted_specific <- SpaGE(
  spatial_data = as.data.frame(spatial_data),
  rna_data = as.data.frame(rna_data),
  n_pv = 30,
  genes_to_predict = genes_of_interest,
  verbose = FALSE
)

cat("Predicted genes:", colnames(predicted_specific), "\n")
#> Predicted genes: RNAOnlyGene1 RNAOnlyGene10 RNAOnlyGene25

Cross-Validation

Evaluate prediction accuracy using leave-one-gene-out cross-validation:

# Run CV on a subset of shared genes
cv_genes <- paste0("SharedGene", 1:10)

cv_results <- SpaGE_cv(
  spatial_data = as.data.frame(spatial_data),
  rna_data = as.data.frame(rna_data[, c(paste0("SharedGene", 1:n_shared_genes))]),
  n_pv = 20,
  genes = cv_genes,
  verbose = FALSE
)

# Summary
cat("Cross-validation Results:\n")
#> Cross-validation Results:
cat("Mean Spearman correlation:", round(mean(cv_results$correlation), 3), "\n")
#> Mean Spearman correlation: 0.007
cat("Median Spearman correlation:", round(median(cv_results$correlation), 3), "\n")
#> Median Spearman correlation: 0.022

Visualize CV Results

# Plot correlation distribution
hist(cv_results$correlation, 
     breaks = 20, 
     main = "Leave-One-Out Cross-Validation",
     xlab = "Spearman Correlation",
     col = "#3498db",
     border = "white")
abline(v = mean(cv_results$correlation), col = "red", lwd = 2, lty = 2)
legend("topright", legend = paste("Mean =", round(mean(cv_results$correlation), 3)),
       col = "red", lty = 2, lwd = 2)

Accessing Metadata

SpaGE returns additional metadata as attributes:

# Access metadata from prediction result
cat("Number of PVs requested:", attr(predicted, "n_pv"), "\n")
#> Number of PVs requested: 30
cat("Number of PVs used:", attr(predicted, "n_pv_used"), "\n")
#> Number of PVs used: 21
cat("Number of shared genes:", attr(predicted, "n_shared_genes"), "\n")
#> Number of shared genes: 100
cat("Top PV similarities:", round(head(attr(predicted, "similarities"), 5), 3), "\n")
#> Top PV similarities: 0.893 0.86 0.838 0.823 0.798

Session Information

sessionInfo()
#> R version 4.6.0 (2026-04-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 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.26.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] SpaGER_1.0.0   rmarkdown_2.31
#> 
#> loaded via a namespace (and not attached):
#>   [1] deldir_2.0-4           pbapply_1.7-4          gridExtra_2.3         
#>   [4] rlang_1.2.0            magrittr_2.0.5         RcppAnnoy_0.0.23      
#>   [7] otel_0.2.0             spatstat.geom_3.8-1    matrixStats_1.5.0     
#>  [10] ggridges_0.5.7         compiler_4.6.0         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          promises_1.5.0        
#>  [19] purrr_1.2.2            xfun_0.59              cachem_1.1.0          
#>  [22] jsonlite_2.0.0         goftest_1.2-3          later_1.4.8           
#>  [25] spatstat.utils_3.2-3   irlba_2.3.7            parallel_4.6.0        
#>  [28] cluster_2.1.8.2        R6_2.6.1               ica_1.0-3             
#>  [31] spatstat.data_3.1-9    bslib_0.11.0           stringi_1.8.7         
#>  [34] RColorBrewer_1.1-3     reticulate_1.46.0      spatstat.univar_3.2-0 
#>  [37] parallelly_1.47.0      lmtest_0.9-40          jquerylib_0.1.4       
#>  [40] scattermore_1.2        Rcpp_1.1.1-1.1         knitr_1.51            
#>  [43] tensor_1.5.1           future.apply_1.20.2    zoo_1.8-15            
#>  [46] sctransform_0.4.3      FNN_1.1.4.1            httpuv_1.6.17         
#>  [49] Matrix_1.7-5           splines_4.6.0          igraph_2.3.2          
#>  [52] tidyselect_1.2.1       abind_1.4-8            yaml_2.3.12           
#>  [55] spatstat.random_3.5-0  codetools_0.2-20       miniUI_0.1.2          
#>  [58] spatstat.explore_3.8-1 listenv_1.0.0          lattice_0.22-9        
#>  [61] tibble_3.3.1           plyr_1.8.9             shiny_1.14.0          
#>  [64] S7_0.2.2               ROCR_1.0-12            evaluate_1.0.5        
#>  [67] Rtsne_0.17             future_1.70.0          fastDummies_1.7.6     
#>  [70] survival_3.8-6         polyclip_1.10-7        fitdistrplus_1.2-6    
#>  [73] pillar_1.11.1          Seurat_5.5.0           KernSmooth_2.23-26    
#>  [76] plotly_4.12.0          generics_0.1.4         RcppHNSW_0.7.0        
#>  [79] sp_2.2-1               ggplot2_4.0.3          scales_1.4.0          
#>  [82] globals_0.19.1         xtable_1.8-8           glue_1.8.1            
#>  [85] lazyeval_0.2.3         maketools_1.3.2        tools_4.6.0           
#>  [88] sys_3.4.3              data.table_1.18.4      RSpectra_0.16-2       
#>  [91] RANN_2.6.2             buildtools_1.0.0       dotCall64_1.2         
#>  [94] cowplot_1.2.0          grid_4.6.0             tidyr_1.3.2           
#>  [97] nlme_3.1-169           patchwork_1.3.2        cli_3.6.6             
#> [100] spatstat.sparse_3.2-0  spam_2.11-4            viridisLite_0.4.3     
#> [103] dplyr_1.2.1            uwot_0.2.4             gtable_0.3.6          
#> [106] sass_0.4.10            digest_0.6.39          progressr_0.19.0      
#> [109] ggrepel_0.9.8          htmlwidgets_1.6.4      SeuratObject_5.4.0    
#> [112] farver_2.1.2           htmltools_0.5.9        lifecycle_1.0.5       
#> [115] httr_1.4.8             mime_0.13              MASS_7.3-65