This vignette endeavors to put Bioconductor and scvi-tools together to help understand how different data structures and methods relevant to CITE-seq analysis contribute to interpretation of CITE-seq exeperiments.
The scvi-tools tutorial (for version 0.20.0) analyzes a pair of 10x PBMC CITE-seq experiments (5k and 10k cells). Chapter 12 of the OSCA book analyzes only the 10k dataset.
The following subsections are essentially “code-only”. We exhibit steps necessary to assemble a SingleCellExperiment instance with the subset of the totalVI quantifications produced for the cells from the “10k” dataset.
## class: SingleCellExperiment
## dim: 33538 7472
## metadata(2): Samples se.averaged
## assays(2): counts logcounts
## rownames(33538): ENSG00000243485 ENSG00000237613 ... ENSG00000277475
## ENSG00000268674
## rowData names(3): ID Symbol Type
## colnames(7472): AAACCCAAGATTGTGA-1 AAACCCACATCGGTTA-1 ...
## TTTGTTGTCGAGTGAG-1 TTTGTTGTCGTTCAGA-1
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: Gene Expression
## altExpNames(1): Antibody Capture
## AnnData object with n_obs × n_vars = 10849 × 4000
## obs: 'n_genes', 'percent_mito', 'n_counts', 'batch', '_scvi_labels', '_scvi_batch', 'leiden_totalVI'
## var: 'highly_variable', 'highly_variable_rank', 'means', 'variances', 'variances_norm', 'highly_variable_nbatches'
## uns: '_scvi_manager_uuid', '_scvi_uuid', 'hvg', 'leiden', 'log1p', 'neighbors', 'umap'
## obsm: 'X_totalVI', 'X_umap', 'denoised_protein', 'protein_expression', 'protein_foreground_prob'
## layers: 'counts', 'denoised_rna'
## obsp: 'connectivities', 'distances'
In this section we reduce the cell collections to cells common to the chapter 12 and totalVI datasets.
# select and order
totvi_latent = totvi_latent[comm,]
totvi_umap = totvi_umap[comm,]
totvi_denoised_rna = totvi_denoised_rna[comm,]
totvi_denoised_protein = totvi_denoised_protein[comm,]
totvi_leiden = totvi_leiden[comm]
# organize the totalVI into SCE with altExp
totsce = SingleCellExperiment(SimpleList(logcounts=t(totvi_denoised_rna))) # FALSE name
rowData(totsce) = S4Vectors::DataFrame(fullvi$var)
rownames(totsce) = rownames(fullvi$var)
rowData(totsce)$Symbol = rownames(totsce)
nn = SingleCellExperiment(SimpleList(logcounts=t(totvi_denoised_protein))) # FALSE name
reducedDims(nn) = list(UMAP=totvi_umap)
altExp(totsce) = nn
altExpNames(totsce) = "denoised_protein"
totsce$leiden = totvi_leiden
altExp(totsce)$leiden = totvi_leiden
altExp(totsce)$ch12.clusters = altExp(ch12sce[,comm])$label
# add average ADT abundance to metadata, for adt_profiles
tot.se.averaged <- sumCountsAcrossCells(altExp(totsce), altExp(totsce)$leiden,
exprs_values="logcounts", average=TRUE)
rownames(tot.se.averaged) = gsub("_TotalSeqB", "", rownames(tot.se.averaged))
metadata(totsce)$se.averaged = tot.se.averaged
The TSNE projection of the normalized ADT quantifications and the walktrap cluster assignments are produced for the cells common to the two approaches.
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_text_repel()`).
This heatmap uses precomputed cluster averages that are lodged in the metadata element of the SingleCellExperiment. Colors represent the log2-fold change from the grand average across all clusters.
We enhance the annotation of the list of subclusters retrieved using
getCh12AllSce
and then drill into mRNA-based subclusters of
ADT-based cluster 3 to compare expression levels of three genes.
## adding rname '/tmp/RtmpyK9mLF/ch12_allsce.rda1e821292d1ad'
ch12_allsce = lapply(ch12_allsce, function(x) {
colnames(x)= x$Barcode;
cn = colnames(x);
x = x[,intersect(cn,comm)]; x})
of.interest <- "3"
markers <- c("GZMH", "IL7R", "KLRB1")
plotExpression(ch12_allsce[[of.interest]], x="subcluster",
features=markers, swap_rownames="Symbol", ncol=3)
There is a suggestion of a boolean basis for subcluster identity, depending on low or high expression of the selected genes.
Following the exploration in OSCA chapter 12, cluster 3 is analyzed for a regression association between expression measures of three genes and the ADT-based abundance of CD127.
plotExpression(ch12_allsce[["3"]], x="CD127", show_smooth=TRUE, show_se=FALSE,
features=c("IL7R", "TPT1", "KLRB1", "GZMH"), swap_rownames="Symbol")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
The approach to profiling the ADT abundances used in the totalVI tutorial employs scaling to (0,1).
A quick view of the concordance of the two clustering outcomes is
atot = altExp(totsce)
ach12 = altExp(ch12sce_matched)
tt = table(ch12=ach12$label, VI=atot$leiden)
pheatmap::pheatmap(log(tt+1))
With this we can pick out some clusters with many cells in common:
lit = tt[c("9", "12", "5", "3"), c("0", "1", "2", "8", "6", "5")]
rownames(lit) = sQuote(rownames(lit))
colnames(lit) = sQuote(colnames(lit))
lit
## VI
## ch12 '0' '1' '2' '8' '6' '5'
## '9' 1334 0 0 0 0 0
## '12' 0 993 0 0 15 0
## '5' 0 102 671 8 44 2
## '3' 0 0 5 322 297 67
Let’s examine the distributions of marker mRNAs in the Leiden totalVI clusters corresponding to OSCA cluster “3”:
tsub = totsce[,which(altExp(totsce)$leiden %in% c("5", "6", "8"))]
markers <- c("GZMH", "IL7R", "KLRB1")
altExp(tsub)$leiden = factor(altExp(tsub)$leiden) # squelch unused levels
tsub$leiden = factor(tsub$leiden) # squelch unused levels
plotExpression(tsub, x="leiden",
features=markers, swap_rownames="Symbol", ncol=3)
Note that the y axis label is incorrect – we are plotting the denoised expression values from totalVI.
The display seems roughly consistent with the “boolean basis” observed above with the mRNA-based subclustering.
The same approach is taken as above. We don’t have TPT1 in the 4000 genes retained in the totalVI exercise.
rn = rownames(altExp(tsub))
rn = gsub("_TotalSeqB", "", rn)
rownames(altExp(tsub)) = rn
rowData(altExp(tsub)) = DataFrame(Symbol=rn)
plotExpression(tsub, x="CD127", show_smooth=TRUE, show_se=FALSE,
features=c("IL7R", "KLRB1", "GZMH"), swap_rownames="Symbol")
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
We have shown how rudimentary programming and data organization can be used to make outputs of OSCA and totalVI methods amenable to comparison in the Bioconductor framework.
The scviR package includes a shiny app in the function
explore_subcl
that should be expanded to facilitate
exploration of totalVI subclusters. Much more work remains to be done in
the area of exploring
additional approaches to integrative interpretation of ADT and mRNA abundance patterns, such as intersection and concatenation methods in the feature selection materials in OSCA ch. 12
effects of tuning and architecture details for the totalVI VAE
## R version 4.4.2 (2024-10-31)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.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.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=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: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats4 stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] scater_1.35.0 scuttle_1.17.0
## [3] reshape2_1.4.4 ggplot2_3.5.1
## [5] scviR_1.7.0 SingleCellExperiment_1.29.1
## [7] SummarizedExperiment_1.37.0 Biobase_2.67.0
## [9] GenomicRanges_1.59.1 GenomeInfoDb_1.43.2
## [11] IRanges_2.41.1 S4Vectors_0.45.2
## [13] BiocGenerics_0.53.3 generics_0.1.3
## [15] MatrixGenerics_1.19.0 matrixStats_1.4.1
## [17] shiny_1.9.1 basilisk_1.19.0
## [19] reticulate_1.40.0 BiocStyle_2.35.0
##
## loaded via a namespace (and not attached):
## [1] DBI_1.2.3 gridExtra_2.3 rlang_1.1.4
## [4] magrittr_2.0.3 compiler_4.4.2 RSQLite_2.3.8
## [7] mgcv_1.9-1 dir.expiry_1.15.0 png_0.1-8
## [10] vctrs_0.6.5 stringr_1.5.1 pkgconfig_2.0.3
## [13] crayon_1.5.3 fastmap_1.2.0 dbplyr_2.5.0
## [16] XVector_0.47.0 labeling_0.4.3 utf8_1.2.4
## [19] promises_1.3.2 rmarkdown_2.29 UCSC.utils_1.3.0
## [22] ggbeeswarm_0.7.2 purrr_1.0.2 bit_4.5.0
## [25] xfun_0.49 zlibbioc_1.52.0 cachem_1.1.0
## [28] beachmat_2.23.2 jsonlite_1.8.9 blob_1.2.4
## [31] later_1.4.1 DelayedArray_0.33.2 BiocParallel_1.41.0
## [34] irlba_2.3.5.1 parallel_4.4.2 R6_2.5.1
## [37] stringi_1.8.4 bslib_0.8.0 RColorBrewer_1.1-3
## [40] limma_3.63.2 jquerylib_0.1.4 Rcpp_1.0.13-1
## [43] knitr_1.49 splines_4.4.2 httpuv_1.6.15
## [46] Matrix_1.7-1 tidyselect_1.2.1 abind_1.4-8
## [49] yaml_2.3.10 viridis_0.6.5 codetools_0.2-20
## [52] curl_6.0.1 plyr_1.8.9 lattice_0.22-6
## [55] tibble_3.2.1 withr_3.0.2 basilisk.utils_1.19.0
## [58] evaluate_1.0.1 BiocFileCache_2.15.0 pillar_1.9.0
## [61] BiocManager_1.30.25 filelock_1.0.3 munsell_0.5.1
## [64] scales_1.3.0 xtable_1.8-4 glue_1.8.0
## [67] pheatmap_1.0.12 maketools_1.3.1 tools_4.4.2
## [70] BiocNeighbors_2.1.1 sys_3.4.3 ScaledMatrix_1.15.0
## [73] buildtools_1.0.0 grid_4.4.2 colorspace_2.1-1
## [76] nlme_3.1-166 GenomeInfoDbData_1.2.13 beeswarm_0.4.0
## [79] BiocSingular_1.23.0 vipor_0.4.7 cli_3.6.3
## [82] rsvd_1.0.5 fansi_1.0.6 S4Arrays_1.7.1
## [85] viridisLite_0.4.2 dplyr_1.1.4 gtable_0.3.6
## [88] sass_0.4.9 digest_0.6.37 SparseArray_1.7.2
## [91] ggrepel_0.9.6 farver_2.1.2 memoise_2.0.1
## [94] htmltools_0.5.8.1 lifecycle_1.0.4 httr_1.4.7
## [97] statmod_1.5.0 mime_0.12 bit64_4.5.2