Single-nuclei RNA-seq (snRNA-seq) provides another strategy for performing single-cell transcriptomics where individual nuclei instead of cells are captured and sequenced. The major advantage of snRNA-seq over scRNA-seq is that the former does not require the preservation of cellular integrity during sample preparation, especially dissociation. We only need to extract nuclei in an intact state, meaning that snRNA-seq can be applied to cell types, tissues and samples that are not amenable to dissociation and later processing. The cost of this flexibility is the loss of transcripts that are primarily located in the cytoplasm, potentially limiting the availability of biological signal for genes with little nuclear localization.
The computational analysis of snRNA-seq data is very much like that of scRNA-seq data. We have a matrix of (UMI) counts for genes by cells that requires quality control, normalization and so on. (Technically, the columsn correspond to nuclei but we will use these two terms interchangeably in this chapter.) In fact, the biggest difference in processing occurs in the construction of the count matrix itself, where intronic regions must be included in the annotation for each gene to account for the increased abundance of unspliced transcripts. The rest of the analysis only requires a few minor adjustments to account for the loss of cytoplasmic transcripts. We demonstrate using a dataset from Wu et al. (2019) involving snRNA-seq on healthy and fibrotic mouse kidneys.
## class: SingleCellExperiment ## dim: 18249 8231 ## metadata(0): ## assays(1): counts ## rownames(18249): mt-Cytb mt-Nd6 ... Gm44613 Gm38304 ## rowData names(0): ## colnames(8231): sNuc-10x_AAACCTGAGTCCGGTC sNuc-10x_AAACCTGCACAGACAG ... ## UUO_TTGCCGTCACAAGACG UUO_TTTGTCATCTGCTGTC ## colData names(2): Technology Status ## reducedDimNames(0): ## mainExpName: NULL ## altExpNames(0):
The loss of the cytoplasm means that the stripped nuclei should not contain any mitochondrial transcripts. This means that the mitochondrial proportion becomes an excellent QC metric for the efficacy of the stripping process. Unlike scRNA-seq, there is no need to worry about variations in mitochondrial content due to genuine biology. High-quality nuclei should not contain any mitochondrial transcripts; the presence of any mitochondrial counts in a library indicates that the removal of the cytoplasm was not complete, possibly introducing irrelevant heterogeneity in downstream analyses.
## Mode FALSE TRUE ## logical 2264 5967
We apply a simple filter to remove libraries corresponding to incompletely stripped nuclei. The outlier-based approach described in Section 12.3 can be used here, but some caution is required in low-coverage experiments where a majority of cells have zero mitochondrial counts. In such cases, the MAD may also be zero such that other libraries with very low but non-zero mitochondrial counts are removed. This is typically too conservative as such transcripts may be present due to sporadic ambient contamination rather than incomplete stripping.
## low_lib_size low_n_features high_subsets_Mt_percent ## 0 0 2264 ## discard ## 2264
Instead, we enforce a minimum difference between the threshold and the median in
isOutlier() (Figure 11.1).
We arbitrarily choose +0.5% here, which takes precedence over the outlier-based threshold if the latter is too low.
In this manner, we avoid discarding libraries with a very modest amount of contamination; the same code will automatically fall back to the outlier-based threshold in datasets where the stripping was systematically less effective.
## low_lib_size low_n_features high_subsets_Mt_percent ## 0 0 42 ## discard ## 42
The expected absence of genuine mitochondrial expression can also be exploited to estimate the level of ambient contamination (Multi-sample Chapter 5). We demonstrate on mouse brain snRNA-seq data from 10X Genomics (Zheng et al. 2017), using the raw count matrix prior to any filtering for nuclei-containing barcodes.
library(DropletTestFiles) raw.path <- getTestFile("tenx-2.0.1-nuclei_900/1.0.0/raw.tar.gz") out.path <- file.path(tempdir(), "nuclei") untar(raw.path, exdir=out.path) library(DropletUtils) fname <- file.path(out.path, "raw_gene_bc_matrices/mm10") sce.brain <- read10xCounts(fname, col.names=TRUE) sce.brain
## class: SingleCellExperiment ## dim: 27998 737280 ## metadata(1): Samples ## assays(1): counts ## rownames(27998): ENSMUSG00000051951 ENSMUSG00000089699 ... ## ENSMUSG00000096730 ENSMUSG00000095742 ## rowData names(2): ID Symbol ## colnames(737280): AAACCTGAGAAACCAT-1 AAACCTGAGAAACCGC-1 ... ## TTTGTCATCTTTAGTC-1 TTTGTCATCTTTCCTC-1 ## colData names(2): Sample Barcode ## reducedDimNames(0): ## mainExpName: NULL ## altExpNames(0):
We call non-empty droplets using
emptyDrops() as previously described (Section 7.2).
## Mode FALSE TRUE NA's ## logical 2306 1730 733244
If our libraries are of high quality, we can assume that any mitochondrial “expression” is due to contamination from the ambient solution.
We then use the
controlAmbience() function to estimate the proportion of ambient contamination for each gene, allowing us to mark potentially problematic genes in the DE results (Figure 11.4).
In fact, we can use this information even earlier to remove these genes during dimensionality reduction and clustering.
This is not generally possible for scRNA-seq as any notable contaminating transcripts may originate from a subpopulation that actually expresses that gene and thus cannot be blindly removed.
ambient <- estimateAmbience(counts(sce.brain), round=FALSE, good.turing=FALSE) nuclei <- rowSums(counts(sce.brain)[,which(e.out$FDR <= 0.001)]) is.mito <- grepl("mt-", rowData(sce.brain)$Symbol) contam <- controlAmbience(nuclei, ambient, features=is.mito, mode="proportion") plot(log10(nuclei+1), contam*100, col=ifelse(is.mito, "red", "grey"), pch=16, xlab="Log-nuclei expression", ylab="Contamination (%)")
R version 4.2.2 (2022-10-31) Platform: x86_64-pc-linux-gnu (64-bit) Running under: Ubuntu 20.04.5 LTS Matrix products: default BLAS: /home/biocbuild/bbs-3.16-bioc/R/lib/libRblas.so LAPACK: /home/biocbuild/bbs-3.16-bioc/R/lib/libRlapack.so locale:  LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C  LC_TIME=en_GB LC_COLLATE=C  LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8  LC_PAPER=en_US.UTF-8 LC_NAME=C  LC_ADDRESS=C LC_TELEPHONE=C  LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C attached base packages:  stats4 stats graphics grDevices utils datasets methods  base other attached packages:  DropletUtils_1.18.1 DropletTestFiles_1.8.0  batchelor_1.14.1 bluster_1.8.0  scran_1.26.2 scater_1.26.1  ggplot2_3.4.0 scuttle_1.8.4  scRNAseq_2.12.0 SingleCellExperiment_1.20.0  SummarizedExperiment_1.28.0 Biobase_2.58.0  GenomicRanges_1.50.2 GenomeInfoDb_1.34.8  IRanges_2.32.0 S4Vectors_0.36.1  BiocGenerics_0.44.0 MatrixGenerics_1.10.0  matrixStats_0.63.0 BiocStyle_2.26.0  rebook_1.8.0 loaded via a namespace (and not attached):  AnnotationHub_3.6.0 BiocFileCache_2.6.0  igraph_1.3.5 lazyeval_0.2.2  BiocParallel_1.32.5 digest_0.6.31  ensembldb_2.22.0 htmltools_0.5.4  viridis_0.6.2 fansi_1.0.4  magrittr_2.0.3 memoise_2.0.1  ScaledMatrix_1.6.0 cluster_2.1.4  limma_3.54.1 Biostrings_2.66.0  R.utils_2.12.2 prettyunits_1.1.1  colorspace_2.1-0 blob_1.2.3  rappdirs_0.3.3 ggrepel_0.9.2  xfun_0.36 dplyr_1.1.0  crayon_1.5.2 RCurl_1.98-1.10  jsonlite_1.8.4 graph_1.76.0  glue_1.6.2 gtable_0.3.1  zlibbioc_1.44.0 XVector_0.38.0  DelayedArray_0.24.0 BiocSingular_1.14.0  Rhdf5lib_1.20.0 HDF5Array_1.26.0  scales_1.2.1 edgeR_3.40.2  DBI_1.1.3 Rcpp_1.0.10  viridisLite_0.4.1 xtable_1.8-4  progress_1.2.2 dqrng_0.3.0  bit_4.0.5 rsvd_1.0.5  ResidualMatrix_1.8.0 metapod_1.6.0  httr_1.4.4 dir.expiry_1.6.0  ellipsis_0.3.2 R.methodsS3_1.8.2  pkgconfig_2.0.3 XML_3.99-0.13  farver_2.1.1 CodeDepends_0.6.5  sass_0.4.5 dbplyr_2.3.0  locfit_1.5-9.7 utf8_1.2.3  tidyselect_1.2.0 labeling_0.4.2  rlang_1.0.6 later_1.3.0  AnnotationDbi_1.60.0 munsell_0.5.0  BiocVersion_3.16.0 tools_4.2.2  cachem_1.0.6 cli_3.6.0  generics_0.1.3 RSQLite_2.2.20  ExperimentHub_2.6.0 evaluate_0.20  stringr_1.5.0 fastmap_1.1.0  yaml_2.3.7 knitr_1.42  bit64_4.0.5 purrr_1.0.1  KEGGREST_1.38.0 AnnotationFilter_1.22.0  sparseMatrixStats_1.10.0 mime_0.12  R.oo_1.25.0 xml2_1.3.3  biomaRt_2.54.0 compiler_4.2.2  beeswarm_0.4.0 filelock_1.0.2  curl_5.0.0 png_0.1-8  interactiveDisplayBase_1.36.0 statmod_1.5.0  tibble_3.1.8 bslib_0.4.2  stringi_1.7.12 highr_0.10  GenomicFeatures_1.50.4 lattice_0.20-45  ProtGenerics_1.30.0 Matrix_1.5-3  vctrs_0.5.2 rhdf5filters_1.10.0  pillar_1.8.1 lifecycle_1.0.3  BiocManager_1.30.19 jquerylib_0.1.4  BiocNeighbors_1.16.0 cowplot_1.1.1  bitops_1.0-7 irlba_22.214.171.124  httpuv_1.6.8 rtracklayer_1.58.0  R6_2.5.1 BiocIO_1.8.0  bookdown_0.32 promises_126.96.36.199  gridExtra_2.3 vipor_0.4.5  codetools_0.2-18 assertthat_0.2.1  rhdf5_2.42.0 rjson_0.2.21  withr_2.5.0 GenomicAlignments_1.34.0  Rsamtools_2.14.0 GenomeInfoDbData_1.2.9  parallel_4.2.2 hms_1.1.2  grid_4.2.2 beachmat_2.14.0  rmarkdown_2.20 DelayedMatrixStats_1.20.0  Rtsne_0.16 shiny_1.7.4  ggbeeswarm_0.7.1 restfulr_0.0.15
Bakken, T. E., R. D. Hodge, J. A. Miller, Z. Yao, T. N. Nguyen, B. Aevermann, E. Barkan, et al. 2018. “Single-nucleus and single-cell transcriptomes compared in matched cortical cell types.” PLoS ONE 13 (12): e0209648.
Wu, H., Y. Kirita, E. L. Donnelly, and B. D. Humphreys. 2019. “Advantages of Single-Nucleus over Single-Cell RNA Sequencing of Adult Kidney: Rare Cell Types and Novel Cell States Revealed in Fibrosis.” J. Am. Soc. Nephrol. 30 (1): 23–32.
Zheng, G. X., J. M. Terry, P. Belgrader, P. Ryvkin, Z. W. Bent, R. Wilson, S. B. Ziraldo, et al. 2017. “Massively parallel digital transcriptional profiling of single cells.” Nat Commun 8 (January): 14049.