Run-down for snRNA-seq clustering analysis for ROSMAP data

This code includes The .RDS file for the pre-processed seurat object can be found at: https://www.synapse.org/#!Synapse:syn26477245. You need to put this file under "Output" directory for the tutorial code to run. Other outputs from clustering results will be stored under "clustering_results". You may choose to change this for the desired output folder otherwise. Please note that, while this tutorial uses gene variance calculation routine from Seurat (based on variance stabilizing transformation), we also provide dispersion calculations in Scran. The user may choose to do either scran or seurat routine by turning use.scran/use.seurat = TRUE/FALSE per section.

##  Load necessary packages and functions into R
rm(list = ls())
library(Seurat)
## Warning: package 'Seurat' was built under R version 3.6.3
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 3.6.3
library(ggrepel)
## Warning: package 'ggrepel' was built under R version 3.6.3
library(scran)
## Loading required package: SingleCellExperiment
## Loading required package: SummarizedExperiment
## Loading required package: GenomicRanges
## Loading required package: stats4
## Loading required package: BiocGenerics
## Loading required package: parallel
## 
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:parallel':
## 
##     clusterApply, clusterApplyLB, clusterCall, clusterEvalQ,
##     clusterExport, clusterMap, parApply, parCapply, parLapply,
##     parLapplyLB, parRapply, parSapply, parSapplyLB
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, append, as.data.frame, basename, cbind, colnames,
##     dirname, do.call, duplicated, eval, evalq, Filter, Find, get, grep,
##     grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget,
##     order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank,
##     rbind, Reduce, rownames, sapply, setdiff, sort, table, tapply,
##     union, unique, unsplit, which, which.max, which.min
## Loading required package: S4Vectors
## 
## Attaching package: 'S4Vectors'
## The following object is masked from 'package:base':
## 
##     expand.grid
## Loading required package: IRanges
## 
## Attaching package: 'IRanges'
## The following object is masked from 'package:grDevices':
## 
##     windows
## Loading required package: GenomeInfoDb
## Warning: package 'GenomeInfoDb' was built under R version 3.6.3
## Loading required package: Biobase
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## Loading required package: DelayedArray
## Warning: package 'DelayedArray' was built under R version 3.6.3
## Loading required package: matrixStats
## Warning: package 'matrixStats' was built under R version 3.6.3
## 
## Attaching package: 'matrixStats'
## The following objects are masked from 'package:Biobase':
## 
##     anyMissing, rowMedians
## Loading required package: BiocParallel
## Warning: package 'BiocParallel' was built under R version 3.6.2
## 
## Attaching package: 'DelayedArray'
## The following objects are masked from 'package:matrixStats':
## 
##     colMaxs, colMins, colRanges, rowMaxs, rowMins, rowRanges
## The following objects are masked from 'package:base':
## 
##     aperm, apply, rowsum
## 
## Attaching package: 'SummarizedExperiment'
## The following object is masked from 'package:Seurat':
## 
##     Assays
print(getwd())
## [1] "C:/Users/songw01/Documents/Papers/AD_scRNAseq_Review/example_codes/AD_scRNAseq_companion"
out.dir <- "clustering_results";dir.create(out.dir)
## Warning in dir.create(out.dir): 'clustering_results' already exists
source("./scripts/R_functions/enrichment_functions.v2.R")
## Loading required package: doParallel
## Warning: package 'doParallel' was built under R version 3.6.3
## Loading required package: foreach
## Warning: package 'foreach' was built under R version 3.6.3
## Loading required package: iterators
## Warning: package 'iterators' was built under R version 3.6.3
source("./scripts/R_functions/clustering_functions.v1.R")
## 
## Attaching package: 'reshape'
## The following objects are masked from 'package:S4Vectors':
## 
##     expand, rename

data loading

Now, since the data files is huge, load it from cloud

seu = readRDS("Output/SeuratObject.RDS") 
#urlstr <- "https://www.dropbox.com/s/w0mzab5i3dwxwlp/SeuratObject.RDS?raw=1"
#seu = readRDS(url(urlstr))
print(seu)
## An object of class Seurat 
## 35350 features across 70634 samples within 2 assays 
## Active assay: SCT (17575 features, 3000 variable features)
##  1 other assay present: RNA
##  3 dimensional reductions calculated: pca, umap, tsne

Get Feature selection

use modelGeneVar function from scran

Here, we will demonstrate how to select genes with significant dispersions by using modelGeneVar() from scran workflow, or FindVariableFeatures() from Seurat

use.scran = FALSE # use scran workflow
use.seurat = TRUE # use seurat workflow

if (use.scran)
{
    gene.var = modelGeneVar(x = GetAssayData(seu),block = factor(seu@meta.data$individualID))
    gene.var =gene.var[order(gene.var$bio,decreasing = TRUE),]
    
    # get significant genes
    gene.sig.var = subset(gene.var,FDR < 0.05) # significant dispersion genes with FDR < 0.05

    # populate variable genes in seurat
    seu[["SCT"]]@var.features = rownames(gene.sig.var)

    library(ggplot2)
    library(ggrepel)
    pobj = ggplot() + geom_point(data = as.data.frame(gene.var[,1:6]),aes(x = tech,y = bio,colour = FDR < 0.05),alpha = 0.2) + 
      scale_colour_manual(values = c("TRUE" = "red","FALSE" = "gray")) + 
      geom_text_repel(data = subset(data.frame(gene.var[1:20,1:6],gene = rownames(gene.var)[1:20]),FDR < 0.05),aes(x = tech,y = bio,label = gene),size = 5) + # name top 20 genes for viz. 
      labs(x = "Technical",y = "Biological") + 
      guides(colour = guide_legend(title = "Biological Var.\nFDR < 0.05")) + 
      theme_bw() + 
      theme(axis.title = element_text(size = 20),axis.text = element_text(size = 17),
        legend.position = "bottom",legend.title = element_text(size = 20),
        legend.text = element_text(size = 17),legend.direction = "horizontal")

    png(file = paste0(out.dir,"/scran_variance.png"),res = 300,width = 1800,height = 2100)
    print(pobj)
    dev.off()
    
    pobj
}

if (use.seurat)
{
    # Seurat's VST routine: note that nfeatures = 3000 is set. While Seurat recommends 2000, 3000 may be more liberal to include more variability in the data set. 
    seu = FindVariableFeatures(
      object= seu,
      selection.method = "vst",
      nfeatures = 3000,
      verbose = TRUE
    )
    # plot variable features with and without labels
    top10 <- head(VariableFeatures(seu), 10)
    plot1 <- VariableFeaturePlot(seu) + theme(legend.position = "bottom",legend.direction = "vertical")
    plot2 <- LabelPoints(plot = plot1, points = top10, repel = TRUE) + theme(legend.position = "bottom",legend.direction = "vertical")
    png(file = paste0(out.dir,"/Seurat_variable_features.png"),res = 300,width = 3200,height = 2500)
    plot1 + plot2
    dev.off()
    
    plot1 + plot2
}
## Warning: Using `as.character()` on a quosure is deprecated as of rlang 0.3.0.
## Please use `as_label()` or `as_name()` instead.
## This warning is displayed once per session.
## When using repel, set xnudge and ynudge to 0 for optimal results
## Warning: Transformation introduced infinite values in continuous x-axis
## Warning: Transformation introduced infinite values in continuous x-axis

print(length(seu[["SCT"]]@var.features))
## [1] 3000

PCA data

Now, let's perform PCA. This portion includes two pipelines for PC selection: getDenoisedPCs from scran, and observing explained variance curve for Seurat.

use.scran = FALSE # use scran workflow
use.seurat = TRUE # use seurat workflow

### scran workflow to nominate PCs
if (use.scran)
{
    ## get SCT normalized data from Seurat: But, this matrix can be any log-normalized data for scRNA-seq
    mat = GetAssayData(seu);
    mat = mat[match(rownames(gene.sig.var),rownames(mat)),]

    # in case you would want to denoise PCs
    pcs.denoised <- getDenoisedPCs(mat, technical=gene.sig.var) 
    
    # replace PCA components in Seurat object
    seu$pca@cell.embeddings = pcs.denoised$components[colnames(seu),]
    
    # run UMAP on updated PCs
    seu <- RunUMAP(seu, dims = 1:ncol(pcs.denoised$components), seed.use = 4867)
}


### seurat workflow to nominate PCs 
if (use.seurat)
{
    # Run PCA in seurat workflow
    seu <- ScaleData(seu, features = rownames(seu))
    seu = RunPCA(seu, features = VariableFeatures(object = seu))

    # Get the total variance:
    total_variance <- sum(matrixStats::rowVars(Seurat::GetAssayData(seu, assay = "SCT", slot = "scale.data")))
    eigValues =  (seu$pca@stdev)^2

    pca.pdata = data.frame(PC = 1:length(seu$pca@stdev),
    eigValues = (seu$pca@stdev)^2,  ## EigenValues
    varExplained = eigValues / total_variance * 100,
    totalExplained = cumsum(eigValues / total_variance * 100))

    pobj = ggplot(data = pca.pdata,aes(x = PC,y = varExplained)) + geom_point() + geom_line() + 
    geom_vline(xintercept = c(5,7,20),colour = c("red","blue","green")) + 
    theme_bw() + 
    labs(x = "PCs",y = "%. Variance Explained") + 
    theme(axis.title = element_text(size = 20),axis.text = element_text(size = 17))

    png(file = paste0(out.dir,"/variance_explained.png"),res = 300,width = 2400,height = 2100)
    print(pobj)
    dev.off()
    
    pobj
    
    n.pcs = 20 # use 20 PCs after inspecting the plot
    seu <- RunUMAP(seu, dims = 1:n.pcs, seed.use = 4867)

}
## Centering and scaling data matrix
## PC_ 1 
## Positive:  RBFOX1, CSMD1, KCNIP4, RALYL, LRRTM4, TENM2, SNTG1, IQCJ-SCHIP1, DPP10, GPM6A 
##     ASIC2, CNTNAP2, LINGO2, CDH18, DGKB, ROBO2, UNC5D, HS6ST3, KCTD16, ST6GALNAC5 
##     CDH12, DSCAM, PCDH7, CNTN4, RGS6, FAM19A2, SYN3, NRGN, GRIN1, ENC1 
## Negative:  PLP1, QKI, MBP, ST18, CTNNA3, RNF220, PIP4K2A, SLC44A1, CLDN11, TMEM144 
##     PHLPP1, PDE4B, NCKAP5, TMTC2, DOCK10, DOCK5, CNP, FRMD4B, TF, PTGDS 
##     ZBTB20, C10orf90, ERBB2IP, GPM6B, EDIL3, CREB5, ENPP2, TMEM165, ELMO1, MAN2A1 
## PC_ 2 
## Positive:  IL1RAPL1, SLC24A2, PLP1, PEX5L, ST18, TTLL7, CTNNA3, MBP, CLDN11, CNTNAP2 
##     SLC44A1, APLP1, FRMD5, RNF220, DPYD, PRUNE2, PLCL1, SH3GL3, MAP7, ELMO1 
##     TMEM144, SHTN1, EDIL3, IQCJ-SCHIP1, MOBP, QDPR, ENPP2, TMEFF2, PDE1C, KIRREL3 
## Negative:  SLC1A2, ATP1A2, HIF3A, ADGRV1, CST3, PITPNC1, PARD3, SLC1A3, NKAIN3, GJA1 
##     AQP4, GPC5, RANBP3L, COL5A3, APOE, PTPRZ1, FGFR3, RFX4, NHSL1, TPD52L1 
##     SLC14A1, RYR3, PLPP3, MSI2, BMPR1B, ZNF98, DTNA, HPSE2, CABLES1, PREX2 
## PC_ 3 
## Positive:  NXPH1, LHFPL3, PCDH15, LUZP2, VCAN, GRIK1, MEGF11, SMOC1, KAZN, TNR 
##     GAD1, SGCZ, MYO16, ALK, SOX6, TMEM132C, ADARB2, SEMA5A, ZNF385D, KCNIP1 
##     LRRC4C, COL9A1, FERMT1, XKR4, KIF26B, GPNMB, DAB1, STK32A, XYLT1, ERBB4 
## Negative:  ADGRV1, GJA1, AQP4, RANBP3L, SLC14A1, BMPR1B, COL5A3, CLU, FGFR3, GPC5 
##     ETNPPL, TPD52L1, PRDM16, SLC39A12, ACSBG1, LRRC16A, APOE, PAPLN, GFAP, SLC7A11 
##     GLIS3, RYR3, SLCO1C1, ZNF98, ZNRF3, MLC1, SLC1A3, STON2, EMX2, SDC4 
## PC_ 4 
## Positive:  NTM, GPM6A, LRP1B, CTNNA2, PPP2R2B, RORA, NCAM2, NPAS3, NEBL, LRRTM4 
##     CACNB2, CSMD1, LRRC4C, ERBB4, CNTNAP2, TENM2, SPARCL1, SORBS1, SLC1A2, RBFOX1 
##     IL1RAPL1, DPP10, PCDH7, SGCD, SNTG1, GPC5, GRIA4, GPM6B, HS6ST3, SOX5 
## Negative:  DOCK8, APBB1IP, TBXAS1, FYB, CD74, INPP5D, SYK, C3, SLCO2B1, C10orf11 
##     ADAM28, ST6GAL1, CSF1R, RHBDF2, ARHGAP15, PTPRC, FLI1, ARHGAP24, LY86, BLNK 
##     PALD1, SRGAP2, LYN, P2RY12, IKZF1, RBM47, CSF3R, RUNX1, CSF2RA, LPCAT2 
## PC_ 5 
## Positive:  VCAN, CA10, TNR, DSCAM, KCNIP4, PDZD2, MEGF11, SMOC1, GPNMB, LHFPL3 
##     XYLT1, FERMT1, STK32A, PTPRZ1, COL9A1, SEMA5A, ZFPM2, BRINP3, COL20A1, FAM19A1 
##     KIF13A, DGKG, PDGFRA, MMP16, PDZRN4, CSPG4, SEZ6L, EPN2, CRISPLD2, GPR17 
## Negative:  GAD2, ZNF385D, GAD1, GRIP1, BTBD11, ANK1, ERBB4, GRIP2, RBMS3, PTPRM 
##     KCNC2, TAC1, SLC35F4, LHX6, SLC6A1, NHS, KCNAB1, PTCHD4, ZNF536, VWC2 
##     TENM3, IGF1, CNTNAP3B, MYO16, MAFB, PVALB, RGS5, SNRPN, TRPC4, ARL4C
## Warning: The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
## To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
## This message will be shown once per session
## 14:50:02 UMAP embedding parameters a = 0.9922 b = 1.112
## 14:50:02 Read 70634 rows and found 20 numeric columns
## 14:50:02 Using Annoy for neighbor search, n_neighbors = 30
## 14:50:02 Building Annoy index with metric = cosine, n_trees = 50
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## 14:50:16 Writing NN index file to temp file C:\Users\songw01\AppData\Local\Temp\RtmpUnIohD\file427ce465396
## 14:50:16 Searching Annoy index using 1 thread, search_k = 3000
## 14:50:43 Annoy recall = 100%
## 14:50:43 Commencing smooth kNN distance calibration using 1 thread
## 14:50:49 Initializing from normalized Laplacian + noise
## 14:51:24 Commencing optimization for 200 epochs, with 3091350 positive edges
## 14:52:53 Optimization finished

UMAP Embedding

# jointly visualize with other complex features
xy = Embeddings(seu,"umap")
pdata = cbind.data.frame(seu@meta.data,as.data.frame(xy[match(colnames(seu),rownames(xy)),]))
pdata$pathology.group = gsub("late","Late AD",gsub("early","Early AD",gsub("no","Healthy",gsub("-pathology$","",as.character(pdata$pathology)))))

# get cluster label coordinate
xy.o = do.call('rbind',lapply(split(1:nrow(xy),factor(seu@meta.data$seurat_clusters)),function(x,y) apply(rbind(y[x,]),2,function(q) median(q)),y = xy));colnames(xy.o) = c("x","y")
hobj = hclust(dist(xy.o),"complete")
cls.tick = hobj$label[hobj$order]

# first create comprehensive uMAP plot
colmap = c("Healthy" = "darkolivegreen1","Early AD" = "yellow","Late AD" = "coral")

pobj = ggplot() + 
  geom_point(data = pdata,aes(x = UMAP_1,y = UMAP_2,fill = pathology.group,colour = broad.cell.type),shape = 21,alpha = 0.4,size = 3,stroke = 1.5) + 
  geom_text(data = data.frame(cls.id = rownames(xy.o),as.data.frame(xy.o)),aes(x = x,y = y,label = cls.id),size = 7) + 
  scale_fill_manual(values = colmap) +
  guides(fill = guide_legend(title = "Diagnosis",ncol = 3),colour = guide_legend(title = "Cell Type",ncol = 3)) + 
  theme_bw() + 
  theme(axis.ticks = element_blank(),axis.title = element_blank(),axis.text = element_blank(),
        panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        legend.title = element_text(size = 20),legend.text = element_text(size = 18),
        legend.position = "bottom",legend.direction = "horizontal")

png(file = paste0(out.dir,"/umap.png"),res = 300,width = 3500,height = 2800)
print(pobj)
dev.off()
## png 
##   2
pobj

Marker plotting on UMAP

# get marker expression plots
genes = c("Ex" = "NRGN","In" = "GAD1","Ast" = "AQP4","Ast" = "GFAP",
          "Mic" = "TYROBP","Mic" = "CX3CR1","Oli" = "PLP1","OPC" = "VCAN","End" = "FLT1")
dobj = DotPlot(seu, features = genes) + RotatedAxis() + scale_y_discrete(limits = cls.tick) + 
  labs(x = "Cell type marker",y = "Cluster") + 
  theme(axis.text.y = element_text(size = 16),axis.text.x = element_text(size = 14),
        legend.position = "bottom",legend.direction = "vertical")

png(file = paste0(out.dir,"/Celltype_Markers.Dotplot.png"),res = 300,width = 1700,height = 2700)
print(dobj)
dev.off()
## png 
##   2
dobj

Composition analysis

## create proportion plot
# assign features 
mods = split(colnames(seu),Idents(seu));
vec = seu@meta.data$pathology.group;names(vec) = colnames(seu);
vec[vec == "early-pathology"] = "Early AD"
vec[vec == "late-pathology"] = "Late AD"
vec[vec == "no-pathology"] = "Healthy"


colmap = c("Healthy" = "darkolivegreen1","Early AD" = "yellow","Late AD" = "coral")

# check enrichments 
fet.res = perform.AllPairs.FET(geneSets1 = mods,geneSets2 = split(names(vec),factor(vec)),background = colnames(seu),adjust.FET.pvalue = T,or = 1,alternative = "greater",
                               do.multicore = F,n.cores = NULL)
fet.res = fet.res[order(fet.res$FET_pvalue),]
fet.res$corrected.FET.pvalue = p.adjust(fet.res$FET_pvalue,"BH")

require(reshape2)
## Loading required package: reshape2
## Warning: package 'reshape2' was built under R version 3.6.3
## 
## Attaching package: 'reshape2'
## The following objects are masked from 'package:reshape':
## 
##     colsplit, melt, recast
pmat = acast(data = fet.res,formula = set1_Name ~ set2_Name,value.var = "corrected.FET.pvalue")

# get coordinates for marks
m = overlap_modules_wt_categ(mods,vec);
m = m[,match(rev(names(colmap)),colnames(m))]
dot.coord = t(apply(m,1,function(x) cumsum(x) - 0.5*x))

# make data for dot marks
dot.data = subset(fet.res,corrected.FET.pvalue < 0.05 & enrichment.foldchange > 1.2)
ij = cbind(match(as.character(dot.data$set1_Name),rownames(dot.coord)),match(as.character(dot.data$set2_Name),colnames(dot.coord)))
dot.data$y = apply(ij,1,function(x,m) m[x[1],x[2]],m = dot.coord)

# generate plot
probj = get_proportion_plot(modules = mods,vec = vec,cols = colmap) 
probj = probj + scale_fill_manual(values = colmap,limits = names(colmap)) + 
  geom_point(data = dot.data,aes(x = set1_Name,y = y,size = enrichment.foldchange),colour = "red",alpha = 0.5) + 
  guides(size = guide_legend(ncol = 1,title = "EFC"),fill = guide_legend(title = "Pathology",ncol = 1)) + 
  scale_x_discrete(limits = cls.tick) + scale_y_continuous(limits = c(0,1)) + 
  coord_flip() + 
  theme(axis.text = element_text(size = 19),
        legend.text = element_text(size = 18),legend.title = element_text(size = 20))
## Scale for 'fill' is already present. Adding another scale for 'fill', which
## will replace the existing scale.
png(file = paste0(out.dir,"/Pathology_Proportion.png"),res = 300,width = 1340,height = 2800)
print(probj)
dev.off()
## png 
##   2
probj

Session info

sessionInfo()
## R version 3.6.1 (2019-07-05)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19041)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United States.1252 
## [2] LC_CTYPE=English_United States.1252   
## [3] LC_MONETARY=English_United States.1252
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.1252    
## 
## attached base packages:
## [1] parallel  stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] reshape2_1.4.4              reshape_0.8.8              
##  [3] doParallel_1.0.16           iterators_1.0.13           
##  [5] foreach_1.5.1               scran_1.16.0               
##  [7] SingleCellExperiment_1.10.1 SummarizedExperiment_1.18.1
##  [9] DelayedArray_0.12.3         BiocParallel_1.20.1        
## [11] matrixStats_0.57.0          Biobase_2.46.0             
## [13] GenomicRanges_1.40.0        GenomeInfoDb_1.22.1        
## [15] IRanges_2.22.1              S4Vectors_0.26.0           
## [17] BiocGenerics_0.34.0         ggrepel_0.9.1              
## [19] ggplot2_3.3.2               Seurat_3.2.2               
## 
## loaded via a namespace (and not attached):
##   [1] plyr_1.8.6               igraph_1.2.6             lazyeval_0.2.2          
##   [4] splines_3.6.1            listenv_0.8.0            scater_1.16.0           
##   [7] digest_0.6.27            htmltools_0.5.0          viridis_0.5.1           
##  [10] magrittr_1.5             tensor_1.5               cluster_2.1.0           
##  [13] ROCR_1.0-11              limma_3.42.2             globals_0.13.1          
##  [16] colorspace_1.4-1         rappdirs_0.3.1           xfun_0.18               
##  [19] dplyr_1.0.2              crayon_1.3.4             RCurl_1.98-1.2          
##  [22] jsonlite_1.7.1           spatstat_1.64-1          spatstat.data_1.4-3     
##  [25] survival_3.2-7           zoo_1.8-8                glue_1.4.2              
##  [28] polyclip_1.10-0          gtable_0.3.0             zlibbioc_1.32.0         
##  [31] XVector_0.28.0           leiden_0.3.3             BiocSingular_1.4.0      
##  [34] future.apply_1.6.0       abind_1.4-5              scales_1.1.1            
##  [37] edgeR_3.28.1             miniUI_0.1.1.1           Rcpp_1.0.5              
##  [40] viridisLite_0.3.0        xtable_1.8-4             reticulate_1.17         
##  [43] dqrng_0.2.1              rsvd_1.0.3               htmlwidgets_1.5.2       
##  [46] httr_1.4.2               RColorBrewer_1.1-2       ellipsis_0.3.1          
##  [49] ica_1.0-2                pkgconfig_2.0.3          farver_2.0.3            
##  [52] uwot_0.1.8               deldir_0.1-29            locfit_1.5-9.4          
##  [55] tidyselect_1.1.0         labeling_0.4.2           rlang_0.4.8             
##  [58] later_1.1.0.1            munsell_0.5.0            tools_3.6.1             
##  [61] generics_0.0.2           ggridges_0.5.2           evaluate_0.14           
##  [64] stringr_1.4.0            fastmap_1.0.1            yaml_2.2.1              
##  [67] goftest_1.2-2            knitr_1.30               fitdistrplus_1.1-1      
##  [70] purrr_0.3.4              RANN_2.6.1               pbapply_1.4-3           
##  [73] future_1.19.1            nlme_3.1-149             mime_0.9                
##  [76] compiler_3.6.1           beeswarm_0.2.3           plotly_4.9.2.1          
##  [79] png_0.1-7                spatstat.utils_1.17-0    tibble_3.0.4            
##  [82] statmod_1.4.35           stringi_1.5.3            RSpectra_0.16-0         
##  [85] lattice_0.20-41          Matrix_1.2-18            vctrs_0.3.4             
##  [88] pillar_1.4.6             lifecycle_0.2.0          lmtest_0.9-38           
##  [91] RcppAnnoy_0.0.16         BiocNeighbors_1.4.2      data.table_1.13.2       
##  [94] cowplot_1.1.0            bitops_1.0-6             irlba_2.3.3             
##  [97] httpuv_1.5.4             patchwork_1.0.1          R6_2.4.1                
## [100] promises_1.1.1           KernSmooth_2.23-17       gridExtra_2.3           
## [103] vipor_0.4.5              codetools_0.2-16         MASS_7.3-53             
## [106] withr_2.3.0              sctransform_0.3.1        GenomeInfoDbData_1.2.1  
## [109] mgcv_1.8-33              grid_3.6.1               rpart_4.1-15            
## [112] tidyr_1.1.2              rmarkdown_2.5            DelayedMatrixStats_1.8.0
## [115] Rtsne_0.15               shiny_1.5.0              ggbeeswarm_0.6.0