vignettes/pbmc_multiomic.Rmd
pbmc_multiomic.Rmd
In this vignette, we’ll demonstrate how to jointly analyze a single-cell dataset measuring both DNA accessibility and gene expression in the same cells using Signac and Seurat. In this vignette we’ll be using a publicly available 10x Genomic Multiome dataset for human PBMCs.
You can download the required data by running the following lines in a shell:
wget https://cf.10xgenomics.com/samples/cell-arc/1.0.0/pbmc_granulocyte_sorted_10k/pbmc_granulocyte_sorted_10k_filtered_feature_bc_matrix.h5
wget https://cf.10xgenomics.com/samples/cell-arc/1.0.0/pbmc_granulocyte_sorted_10k/pbmc_granulocyte_sorted_10k_atac_fragments.tsv.gz
wget https://cf.10xgenomics.com/samples/cell-arc/1.0.0/pbmc_granulocyte_sorted_10k/pbmc_granulocyte_sorted_10k_atac_fragments.tsv.gz.tbi
# load the RNA and ATAC data
counts <- Read10X_h5("../vignette_data/multiomic/pbmc_granulocyte_sorted_10k_filtered_feature_bc_matrix.h5")
fragpath <- "../vignette_data/multiomic/pbmc_granulocyte_sorted_10k_atac_fragments.tsv.gz"
# get gene annotations for hg38
annotation <- GetGRangesFromEnsDb(ensdb = EnsDb.Hsapiens.v86)
seqlevels(annotation) <- paste0('chr', seqlevels(annotation))
# create a Seurat object containing the RNA adata
pbmc <- CreateSeuratObject(
counts = counts$`Gene Expression`,
assay = "RNA"
)
# create ATAC assay and add it to the object
pbmc[["ATAC"]] <- CreateChromatinAssay(
counts = counts$Peaks,
sep = c(":", "-"),
fragments = fragpath,
annotation = annotation
)
pbmc
## An object of class Seurat
## 144978 features across 11909 samples within 2 assays
## Active assay: RNA (36601 features, 0 variable features)
## 1 other assay present: ATAC
We can compute per-cell quality control metrics using the DNA accessibility data and remove cells that are outliers for these metrics, as well as cells with low or unusually high counts for either the RNA or ATAC assay.
DefaultAssay(pbmc) <- "ATAC"
pbmc <- NucleosomeSignal(pbmc)
pbmc <- TSSEnrichment(pbmc)
VlnPlot(
object = pbmc,
features = c("nCount_RNA", "nCount_ATAC", "TSS.enrichment", "nucleosome_signal"),
ncol = 4,
pt.size = 0
)
# filter out low quality cells
pbmc <- subset(
x = pbmc,
subset = nCount_ATAC < 100000 &
nCount_RNA < 25000 &
nCount_ATAC > 1000 &
nCount_RNA > 1000 &
nucleosome_signal < 2 &
TSS.enrichment > 1
)
pbmc
## An object of class Seurat
## 144978 features across 11331 samples within 2 assays
## Active assay: ATAC (108377 features, 0 variable features)
## 1 other assay present: RNA
The set of peaks identified using Cellranger often merges distinct
peaks that are close together. This can create a problem for certain
analyses, particularly motif enrichment analysis and peak-to-gene
linkage. To identify a more accurate set of peaks, we can call peaks
using MACS2 with the CallPeaks()
function. Here we call
peaks on all cells together, but we could identify peaks for each group
of cells separately by setting the group.by
parameter, and
this can help identify peaks specific to rare cell populations.
# call peaks using MACS2
peaks <- CallPeaks(pbmc)
# remove peaks on nonstandard chromosomes and in genomic blacklist regions
peaks <- keepStandardChromosomes(peaks, pruning.mode = "coarse")
peaks <- subsetByOverlaps(x = peaks, ranges = blacklist_hg38_unified, invert = TRUE)
# quantify counts in each peak
macs2_counts <- FeatureMatrix(
fragments = Fragments(pbmc),
features = peaks,
cells = colnames(pbmc)
)
# create a new assay using the MACS2 peak set and add it to the Seurat object
pbmc[["peaks"]] <- CreateChromatinAssay(
counts = macs2_counts,
fragments = fragpath,
annotation = annotation
)
## Computing hash
We can normalize the gene expression data using SCTransform, and reduce the dimensionality using PCA.
DefaultAssay(pbmc) <- "RNA"
pbmc <- SCTransform(pbmc)
pbmc <- RunPCA(pbmc)
Here we process the DNA accessibility assay the same way we would process a scATAC-seq dataset, by performing latent semantic indexing (LSI).
DefaultAssay(pbmc) <- "peaks"
pbmc <- FindTopFeatures(pbmc, min.cutoff = 5)
pbmc <- RunTFIDF(pbmc)
pbmc <- RunSVD(pbmc)
To annotate cell types in the dataset we can transfer cell labels from an existing PBMC reference dataset using tools in the Seurat package. See the Seurat reference mapping vignette for more information.
We’ll use an annotated PBMC reference dataset from Hao et al. (2020), available for download here: https://atlas.fredhutch.org/data/nygc/multimodal/pbmc_multimodal.h5seurat
Note that the SeuratDisk package is required to load the reference dataset. Installation instructions for SeuratDisk can be found here.
library(SeuratDisk)
# load PBMC reference
reference <- LoadH5Seurat("../vignette_data/multiomic/pbmc_multimodal.h5seurat", assays = list("SCT" = "counts"), reductions = 'spca')
DefaultAssay(pbmc) <- "SCT"
# transfer cell type labels from reference to query
transfer_anchors <- FindTransferAnchors(
reference = reference,
query = pbmc,
normalization.method = "SCT",
reference.reduction = "spca",
recompute.residuals = FALSE,
dims = 1:50
)
predictions <- TransferData(
anchorset = transfer_anchors,
refdata = reference$celltype.l2,
weight.reduction = pbmc[['pca']],
dims = 1:50
)
pbmc <- AddMetaData(
object = pbmc,
metadata = predictions
)
# set the cell identities to the cell type predictions
Idents(pbmc) <- "predicted.id"
# set a reasonable order for cell types to be displayed when plotting
levels(pbmc) <- c("CD4 Naive", "CD4 TCM", "CD4 CTL", "CD4 TEM", "CD4 Proliferating",
"CD8 Naive", "dnT",
"CD8 TEM", "CD8 TCM", "CD8 Proliferating", "MAIT", "NK", "NK_CD56bright",
"NK Proliferating", "gdT",
"Treg", "B naive", "B intermediate", "B memory", "Plasmablast",
"CD14 Mono", "CD16 Mono",
"cDC1", "cDC2", "pDC", "HSPC", "Eryth", "ASDC", "ILC", "Platelet")
Using the weighted nearest neighbor methods in Seurat v4, we can compute a joint neighbor graph that represent both the gene expression and DNA accessibility measurements.
# build a joint neighbor graph using both assays
pbmc <- FindMultiModalNeighbors(
object = pbmc,
reduction.list = list("pca", "lsi"),
dims.list = list(1:50, 2:40),
modality.weight.name = "RNA.weight",
verbose = TRUE
)
# build a joint UMAP visualization
pbmc <- RunUMAP(
object = pbmc,
nn.name = "weighted.nn",
assay = "RNA",
verbose = TRUE
)
DimPlot(pbmc, label = TRUE, repel = TRUE, reduction = "umap") + NoLegend()
For each gene, we can find the set of peaks that may regulate the gene by by computing the correlation between gene expression and accessibility at nearby peaks, and correcting for bias due to GC content, overall accessibility, and peak size. See the Signac paper for a full description of the method we use to link peaks to genes.
Running this step on the whole genome can be time consuming, so here
we demonstrate peak-gene links for a subset of genes as an example. The
same function can be used to find links for all genes by omitting the
genes.use
parameter:
DefaultAssay(pbmc) <- "peaks"
# first compute the GC content for each peak
pbmc <- RegionStats(pbmc, genome = BSgenome.Hsapiens.UCSC.hg38)
# link peaks to genes
pbmc <- LinkPeaks(
object = pbmc,
peak.assay = "peaks",
expression.assay = "SCT",
genes.use = c("LYZ", "MS4A1")
)
We can visualize these links using the CoveragePlot()
function, or alternatively we could use the
CoverageBrowser()
function in an interactive analysis:
idents.plot <- c("B naive", "B intermediate", "B memory",
"CD14 Mono", "CD16 Mono", "CD8 TEM", "CD8 Naive")
p1 <- CoveragePlot(
object = pbmc,
region = "MS4A1",
features = "MS4A1",
expression.assay = "SCT",
idents = idents.plot,
extend.upstream = 500,
extend.downstream = 10000
)
p2 <- CoveragePlot(
object = pbmc,
region = "LYZ",
features = "LYZ",
expression.assay = "SCT",
idents = idents.plot,
extend.upstream = 8000,
extend.downstream = 5000
)
patchwork::wrap_plots(p1, p2, ncol = 1)
## R version 4.3.1 (2023-06-16)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Sonoma 14.0
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: Asia/Singapore
## tzcode source: internal
##
## attached base packages:
## [1] stats4 stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] SeuratDisk_0.0.0.9020 BSgenome.Hsapiens.UCSC.hg38_1.4.5
## [3] BSgenome_1.68.0 rtracklayer_1.60.1
## [5] Biostrings_2.68.1 XVector_0.40.0
## [7] EnsDb.Hsapiens.v86_2.99.0 ensembldb_2.24.1
## [9] AnnotationFilter_1.24.0 GenomicFeatures_1.52.2
## [11] AnnotationDbi_1.62.2 Biobase_2.60.0
## [13] GenomicRanges_1.52.0 GenomeInfoDb_1.36.3
## [15] IRanges_2.34.1 S4Vectors_0.38.2
## [17] BiocGenerics_0.46.0 SeuratObject_4.1.4
## [19] Seurat_4.4.0 Signac_1.11.0
##
## loaded via a namespace (and not attached):
## [1] fs_1.6.3 ProtGenerics_1.32.0
## [3] matrixStats_1.0.0 spatstat.sparse_3.0-2
## [5] bitops_1.0-7 httr_1.4.7
## [7] RColorBrewer_1.1-3 docopt_0.7.1
## [9] tools_4.3.1 sctransform_0.4.0
## [11] backports_1.4.1 utf8_1.2.3
## [13] R6_2.5.1 lazyeval_0.2.2
## [15] uwot_0.1.16 withr_2.5.1
## [17] sp_2.1-0 prettyunits_1.2.0
## [19] gridExtra_2.3 progressr_0.14.0
## [21] cli_3.6.1 textshaping_0.3.7
## [23] spatstat.explore_3.2-3 slam_0.1-50
## [25] labeling_0.4.3 sass_0.4.7
## [27] spatstat.data_3.0-1 ggridges_0.5.4
## [29] pbapply_1.7-2 pkgdown_2.0.7
## [31] Rsamtools_2.16.0 systemfonts_1.0.5
## [33] foreign_0.8-84 dichromat_2.0-0.1
## [35] parallelly_1.36.0 rstudioapi_0.15.0
## [37] RSQLite_2.3.1 generics_0.1.3
## [39] BiocIO_1.10.0 ica_1.0-3
## [41] spatstat.random_3.1-6 dplyr_1.1.3
## [43] Matrix_1.6-1.1 ggbeeswarm_0.7.2
## [45] fansi_1.0.5 abind_1.4-5
## [47] lifecycle_1.0.3 yaml_2.3.7
## [49] SummarizedExperiment_1.30.2 BiocFileCache_2.8.0
## [51] Rtsne_0.16 grid_4.3.1
## [53] blob_1.2.4 promises_1.2.1
## [55] crayon_1.5.2 miniUI_0.1.1.1
## [57] lattice_0.21-8 cowplot_1.1.1
## [59] KEGGREST_1.40.1 pillar_1.9.0
## [61] knitr_1.44 rjson_0.2.21
## [63] future.apply_1.11.0 codetools_0.2-19
## [65] fastmatch_1.1-4 leiden_0.4.3
## [67] glue_1.6.2 data.table_1.14.8
## [69] remotes_2.4.2.1 vctrs_0.6.3
## [71] png_0.1-8 gtable_0.3.4
## [73] cachem_1.0.8 xfun_0.40
## [75] S4Arrays_1.0.6 mime_0.12
## [77] qlcMatrix_0.9.7 survival_3.5-5
## [79] RcppRoll_0.3.0 ellipsis_0.3.2
## [81] fitdistrplus_1.1-11 ROCR_1.0-11
## [83] nlme_3.1-162 bit64_4.0.5
## [85] progress_1.2.2 filelock_1.0.2
## [87] RcppAnnoy_0.0.21 rprojroot_2.0.3
## [89] bslib_0.5.1 irlba_2.3.5.1
## [91] vipor_0.4.5 KernSmooth_2.23-21
## [93] rpart_4.1.19 colorspace_2.1-0
## [95] DBI_1.1.3 Hmisc_5.1-1
## [97] nnet_7.3-19 ggrastr_1.0.2
## [99] tidyselect_1.2.0 bit_4.0.5
## [101] compiler_4.3.1 curl_5.1.0
## [103] htmlTable_2.4.1 hdf5r_1.3.8
## [105] xml2_1.3.5 desc_1.4.2
## [107] DelayedArray_0.26.7 plotly_4.10.2
## [109] checkmate_2.2.0 scales_1.2.1
## [111] lmtest_0.9-40 rappdirs_0.3.3
## [113] stringr_1.5.0 digest_0.6.33
## [115] goftest_1.2-3 spatstat.utils_3.0-3
## [117] sparsesvd_0.2-2 rmarkdown_2.25
## [119] htmltools_0.5.6.1 pkgconfig_2.0.3
## [121] base64enc_0.1-3 MatrixGenerics_1.12.3
## [123] dbplyr_2.3.4 fastmap_1.1.1
## [125] rlang_1.1.1 htmlwidgets_1.6.2
## [127] shiny_1.7.5 farver_2.1.1
## [129] jquerylib_0.1.4 zoo_1.8-12
## [131] jsonlite_1.8.7 BiocParallel_1.34.2
## [133] VariantAnnotation_1.46.0 RCurl_1.98-1.12
## [135] magrittr_2.0.3 Formula_1.2-5
## [137] GenomeInfoDbData_1.2.10 patchwork_1.1.3
## [139] munsell_0.5.0 Rcpp_1.0.11
## [141] reticulate_1.32.0 stringi_1.7.12
## [143] zlibbioc_1.46.0 MASS_7.3-60
## [145] plyr_1.8.9 parallel_4.3.1
## [147] listenv_0.9.0 ggrepel_0.9.3
## [149] deldir_1.0-9 splines_4.3.1
## [151] tensor_1.5 hms_1.1.3
## [153] igraph_1.5.1 spatstat.geom_3.2-5
## [155] reshape2_1.4.4 biomaRt_2.56.1
## [157] XML_3.99-0.14 evaluate_0.22
## [159] biovizBase_1.48.0 tweenr_2.0.2
## [161] httpuv_1.6.11 RANN_2.6.1
## [163] tidyr_1.3.0 purrr_1.0.2
## [165] polyclip_1.10-6 future_1.33.0
## [167] scattermore_1.2 ggplot2_3.4.4
## [169] ggforce_0.4.1 xtable_1.8-4
## [171] restfulr_0.0.15 later_1.3.1
## [173] viridisLite_0.4.2 ragg_1.2.6
## [175] tibble_3.2.1 memoise_2.0.1
## [177] beeswarm_0.4.0 GenomicAlignments_1.36.0
## [179] cluster_2.1.4 globals_0.16.2