This vignette reproduces figure panels from from Maxwell et al, 2024 Figure 2/S2 on CD8+ T cell scRNA and TCR sequencing using T cells sorted from wildtype (sgScramble) or ARID1A deficient (sgArid1a) B16F10 tumors.
Load packages.
#load packages with package manager package called pacman
if (!require("pacman")) install.packages("pacman")
pacman::p_load(here,
Seurat, #Primary package for scRNA analysis
scDataviz, #UMAP density plot
cowplot, #arranging density plots on same plane
ggplot2, #plotting
dplyr, #data wrangling
ggpubfigs, #colorblind friendly color palettes
scRepertoire, #scTCR analysis
SingleCellExperiment, #Make sce objects
scater, #single cell toolkit
Nebulosa, #Marker gene expression density
stringr,#Reformatting strings
forcats, #factors
WebGestaltR) #GSEA
knitr::opts_chunk$set(echo = TRUE) #default setting is that code chunks output are visible
set.seed(123) # Setting seed for reproducibility
Import data and generate UMAP using Seurat DimPlot function with color blind friendly palette from the ggpubfigs package.
#import data
dat.integrated <- readRDS("scRNA_CD8_B16F10.rds")
#Seurat Dimplot function for UMAP
DimPlot(dat.integrated, reduction = "umap", cols = friendly_pal("nickel_five"), label = TRUE, label.box = TRUE) +
ggtitle("CD8+ T cell clusters") + theme(plot.title = element_text(hjust = 0.5))
Generating marker gene heatmap of top 10 marker genes from FindMarkers Seurat function for each cluster. The heatmap will look blurry when viewed in Rstudio, but has much higher resolution when viewed in a PDF viewer such as Adobe or Drawboard PDF.
marker_genes <- read.delim("scRNA_marker_genes.txt", header = F)
marker_genes <- marker_genes[, 1]
# Generating the heatmap
heatmap_plot <- DoHeatmap(object = dat.integrated, features = marker_genes, group.colors = friendly_pal("nickel_five")) +
scale_fill_viridis_c(limits = c(-0.5, 1.5), oob = scales::squish) +
scale_y_discrete(position = "right")
# Save the heatmap with specified dimensions
ggsave("Marker_genes_heatmap.pdf", plot = heatmap_plot, width = 10, height = 14, device = "pdf")
#View heatmap in PDF viewer
To visualize cluster marker gene expression, we use Neubulosa package for gene weighted density visualization. This visualization is more sensitive to low expression than Seurat’s FeaturePlot function and the plots are beuatiful. Below are Nebulosa density plots for C5 proliferation cluster genes Mki67 and Top2a.
p5 <- plot_density(dat.integrated, c("Mki67", "Top2a"))
print(p5)
Visualize CD8+ T cell states from sgScramble to sgArid1a tumors using scDataViz package.
#subset Seurat object by treatment for density plot
sgScr.int=subset(x=dat.integrated,subset=Treatment=="sgScramble")
sgArid1a.int=subset(x=dat.integrated,subset=Treatment=="sgArid1a")
#save sce object for sgScr
sgScr_sce <- as.SingleCellExperiment(sgScr.int)
#colData function from Scater single cell package
metadata(sgScr_sce) <- data.frame(colData(sgScr_sce))
#save sce object for sgArid1a
sgArid1a_sce <- as.SingleCellExperiment(sgArid1a.int)
#colData function from Scater single cell package
metadata(sgArid1a_sce) <- data.frame(colData(sgArid1a_sce))
#save plot for sgScr
#contourPlot() function from scDataviz package
sgScramble <- contourPlot(sgScr_sce, contour=NA, reducedDim = 'UMAP',dimColnames = c('UMAP_1','UMAP_2'), title = "sgScramble") +
scale_fill_viridis_c(option="magma") +
theme_classic() #creates cell density plot split by treatment
#save plot for sgArid1a
#contourPlot() function from scDataviz package
sgArid1a <- contourPlot(sgArid1a_sce, contour=NA, reducedDim = 'UMAP',dimColnames = c('UMAP_1','UMAP_2'), title = "sgArid1a") +
scale_fill_viridis_c(option="magma") +
theme_classic() #creates cell density plot split by treatment
#Run plot_grid() function from cowplot package
#Plot density UMAPs on same plane
plot_grid(sgScramble,sgArid1a)
Visualize cluster populations among all CD8+ T cells within each group. Data wrangling with dplyr and plotting with ggplot2.
#Extract cluster, genotype, and cell number from Seurat object
clusts=table(dat.integrated@active.ident,dat.integrated@meta.data$Treatment)
clusts=as.data.frame(clusts)
#Reshape dataframe and create proportion column using dplyr package
clusts <- clusts %>%
rename(Cluster = Var1, Genotype = Var2) %>%
group_by(Genotype) %>%
mutate(prop = Freq/sum(Freq))
#Make Genotype a factor and set desired order for plotting
clusts$Genotype <- as.factor(clusts$Genotype)
clusts$Genotype <- factor(clusts$Genotype, levels = c("sgScramble", "sgArid1a"))
#color blind friendly palette
mypalette <- friendly_pal("nickel_five")
#barplot
ggplot(clusts,aes(x=Genotype,y=prop,fill=Cluster))+
geom_bar(stat="identity", color="black")+
theme_classic()+ scale_fill_manual(values=mypalette) +
ggtitle(substitute(paste(bold("Cluster Density")))) +
theme(plot.title = element_text(size = 18, hjust = 0.5),
axis.text.x = element_text(size = 14),
axis.title = element_blank(),
axis.title.y = element_text(size = 14)) +
labs(y = "Proportion of UMAP")
Visualize expression of a previously defined CD8+ T cell specific anti-PD1 response signature Kumar et al in T cells from both sgScramble and sgArid1a tumors.
#Read in gene signatures from Maxwell et al
gene_signatures <- read.delim("Maxwell_et_al_Gene_signatures.txt", header = TRUE)
#Select gene signature from Kumar et al
anti_PD1_response <- gene_signatures %>%
select("CD8_anti_PD1_response_sig")
#Convert from dataframe to vector
anti_PD1_response <- as.vector(anti_PD1_response)
#AddModuleScore function from Seurat to add a custom gene signature to object
dat.integrated <- AddModuleScore(object = dat.integrated, features = anti_PD1_response, ctrl = 5, name = "Anti_PD1_Response", seed = 12)
#Visualize expression of custom gene signature
FeaturePlot(dat.integrated,features = "Anti_PD1_Response1",label=FALSE,split.by = "Treatment",order=TRUE, pt.size = .75) & theme(legend.position="right",text=element_text(size=10)) & scale_color_viridis_c(option="magma", limits=c(0.5, 1.1),oob=scales::squish)
Perform differential gene expression (DGE) followed by GSEA comparing sgScramble to sgArid1a for all five clusters. DGE is performed using Seurat FindMarkers function and GSEA is performed using WebGestaltR package.
#Add a "cluster_treatment" vector to object metadata (e.g., Naive_sgArid1a or Naive_sgScramble)
dat.integrated@meta.data$cluster_treatment <- paste(as.vector(dat.integrated$cell.type), as.vector(dat.integrated$Treatment), sep = "_")
table(dat.integrated$cluster_treatment)
##
## Effector_sgArid1a Effector_sgScramble Exhaustion_sgArid1a
## 8276 3669 3568
## Exhaustion_sgScramble Innate_sgArid1a Innate_sgScramble
## 1052 2632 679
## Naive_sgArid1a Naive_sgScramble Proliferating_sgArid1a
## 7220 8943 1740
## Proliferating_sgScramble
## 386
#Make cluster_treatment object ident
Idents(dat.integrated) <- dat.integrated$cluster_treatment
table(Idents(dat.integrated))
##
## Naive_sgScramble Effector_sgScramble Exhaustion_sgScramble
## 8943 3669 1052
## Innate_sgScramble Proliferating_sgScramble Naive_sgArid1a
## 679 386 7220
## Effector_sgArid1a Innate_sgArid1a Exhaustion_sgArid1a
## 8276 2632 3568
## Proliferating_sgArid1a
## 1740
##########
#part1: DE analysis with Seurat FindMarkers function
# outputs: .csv files for DE analysis
#set seed for reproducible analysis
set.seed(12345)
#cluster names vector
name <- as.vector(unique(dat.integrated$cell.type))
#cluster_genotype vectors
sgScramble <- paste0(name, "_sgScramble")
sgArid1a <- paste0(name, "_sgArid1a")
#DGE analysis
for (i in 1:length(name)){
outname <- paste0("response_", name[i], ".csv")
temp <- FindMarkers(dat.integrated, ident.1 = sgArid1a[i], ident.2 = sgScramble[i], logfc.threshold = 0, min.pct = 0.05)
write.csv(temp, outname, quote=F)
}
##########
#part2: generate GSEA input file - ranked gene list with scores
# outputs: /GSEA/*.rnk files for GSEA
##########
#gene rank
#DGE .csv files for each cluster
csv <- list.files(pattern="*.csv")
#Generate rank list for GSEA
for(i in 1:length(csv)){
# Extract the base file name without the extension and add the new extension
base_name <- gsub(pattern="\\.csv$", replacement="", x=csv[i])
rank <- paste0("./GSEA/", base_name, ".rnk") # Construct the output path correctly
# Read the CSV file
deg <- read.csv(csv[i], header=TRUE)
# Calculate the rank score
rank.score <- -log10(deg$p_val_adj)*sign(deg$avg_log2FC)
# Handle infinite and NA values
rank.score[is.na(rank.score)] <- 0
rank.score[rank.score == Inf] <- max(rank.score[which(rank.score < Inf)])+50
rank.score[rank.score == -Inf] <- min(rank.score[which(rank.score > -Inf)])-50
# Check for NA and infinite values before proceeding
if(!any(is.na(rank.score)) && !any(is.infinite(rank.score))){
deg <- cbind(deg$X, rank.score)
write.table(deg, rank, quote=FALSE, row.names = FALSE, col.names = FALSE, sep="\t")
}
}
fnms <- list.files(pattern="*.csv")
for(i in 1:length(fnms)){
# Extract the base file name without the extension and add the new extension
base_name <- gsub(pattern="\\.csv$", replacement="", x=fnms[i])
onms <- paste0("./GSEA/", base_name, ".rnk") # Construct the output path correctly
# Read the CSV file
deg <- read.csv(fnms[i], header=TRUE)
# Calculate the rank score
rank.score <- -log10(deg$p_val_adj)*sign(deg$avg_log2FC)
# Handle infinite and NA values
rank.score[is.na(rank.score)] <- 0
rank.score[rank.score == Inf] <- max(rank.score[which(rank.score < Inf)])+50
rank.score[rank.score == -Inf] <- min(rank.score[which(rank.score > -Inf)])-50
# Check for NA and infinite values before proceeding
if(!any(is.na(rank.score)) && !any(is.infinite(rank.score))){
deg <- cbind(deg$X, rank.score)
write.table(deg, onms, quote=FALSE, row.names = FALSE, col.names = FALSE, sep="\t")
}
}
#########
# part3: perform GSEA with WebGestaltR
#########
outdir <- "./GSEA/hallmark/"
runEnrich <- function(rankGene, outfnm, outdir) {
fdr <- 1
enrichTestGSEA <- WebGestaltR(enrichMethod = "GSEA",
organism="mmusculus",
#enrichDatabaseFile="./GSEA/hallmark_mouse.gmt",
enrichDatabaseFile="./GSEA/hallmark_mouse.gmt", #change gmt file
enrichDatabaseType="genesymbol",
interestGene = rankGene,
interestGeneType = "genesymbol",
referenceSet="genome",
minNum=3,maxNum=2000,
perNum=10000,
fdrMethod="BH", sigMethod="top",
topThr = 51, reportNum = 51,
isOutput=T,
outputDirectory=outdir,
projectName=outfnm,
saveRawGseaResult=T,
nThreads=20)
}
csv <- list.files("./GSEA/", pattern="*.rnk")
for (i in 1:length(csv)){
tmn <- paste0("./GSEA/", csv[i])
rankGene <- read.delim(tmn, header=F)
outfnm <- strsplit(tmn, "response_|.rnk")[[1]][2]
runEnrich(rankGene, outfnm, outdir)
}
## Loading the functional categories...
## Loading the ID list...
## Summarizing the uploaded ID list by GO Slim data...
## Performing the enrichment analysis...
## 10000 permutations of score complete...
## Begin affinity propagation...
## End affinity propagation...
## Begin weighted set cover...
## End weighted set cover...
## Generate the final report...
## Results can be found in the ./GSEA/hallmark//Project_Effector!
## Loading the functional categories...
## Loading the ID list...
## Summarizing the uploaded ID list by GO Slim data...
## Performing the enrichment analysis...
## 10000 permutations of score complete...
## Begin affinity propagation...
## End affinity propagation...
## Begin weighted set cover...
## End weighted set cover...
## Generate the final report...
## Results can be found in the ./GSEA/hallmark//Project_Exhaustion!
## Loading the functional categories...
## Loading the ID list...
## Summarizing the uploaded ID list by GO Slim data...
## Performing the enrichment analysis...
## 10000 permutations of score complete...
## Begin affinity propagation...
## End affinity propagation...
## Begin weighted set cover...
## End weighted set cover...
## Generate the final report...
## Results can be found in the ./GSEA/hallmark//Project_Innate!
## Loading the functional categories...
## Loading the ID list...
## Summarizing the uploaded ID list by GO Slim data...
## Performing the enrichment analysis...
## 10000 permutations of score complete...
## Begin affinity propagation...
## End affinity propagation...
## Begin weighted set cover...
## End weighted set cover...
## Generate the final report...
## Results can be found in the ./GSEA/hallmark//Project_Naive!
## Loading the functional categories...
## Loading the ID list...
## Summarizing the uploaded ID list by GO Slim data...
## Performing the enrichment analysis...
## 10000 permutations of score complete...
## Begin affinity propagation...
## End affinity propagation...
## Begin weighted set cover...
## End weighted set cover...
## Generate the final report...
## Results can be found in the ./GSEA/hallmark//Project_Proliferating!
#end.
The CD8+ T cell immunotherapy response signature indicated the highest expression is in C2 effector like CD8+ T cells and this is increased in sgArid1a tumor group. To investigate what gene signatures are enriched in sgArid1a C2 T cells vs sgScrmable C2 T cells, we pulled data from GSEA results for C2 Effector like cluster and plot enriched gene sets with ggplot2.
rawGseaResult <- readRDS("./GSEA/hallmark/Project_Effector/Project_Effector_GSEA/rawGseaResult.rds")
Gene_set <- names(rawGseaResult$Items_in_Set)
#replace underscores with spaces
Gene_set <- gsub("_", " ", Gene_set)
#Capitalize only first letter of each word, stringr package
Gene_set <- str_to_title(Gene_set)
#delete hallmark text, too reduant for later plotting
Gene_set <- gsub("Hallmark ", "", Gene_set)
NES <- rawGseaResult$Enrichment_Results$NES
FDR <- rawGseaResult$Enrichment_Results$fdr
#make gsea_df for plotting
C2_gsea_df <- data.frame(Gene_set, NES, FDR)
#Take top and bottom 4 gene sets, dplyr package
C2_top4 <- C2_gsea_df %>%
arrange(NES) %>%
slice_head(n=4)
C2_bottom4 <- C2_gsea_df %>%
arrange(NES) %>%
slice_tail(n=4)
#join the top enrichments for sgArid1a and sgScr C2 T cells
C2_top_df <- rbind(C2_top4, C2_bottom4)
#GSEA vertical bars (log10pvalue scale, y=gene set, x=NES) #ggplot2 and forcats packages
ggplot(C2_top_df, aes(NES, fct_reorder(Gene_set, NES), fill=FDR)) + geom_col() +
scale_fill_gradientn(colors=c("#8b0000","#FEFEBE","#9FE2BF","slateblue"))+theme_classic()+theme(panel.border = element_rect(color="black",fill=NA,size=1.5))+ggtitle("GSEA")+labs(fill="FDR")+geom_vline(xintercept = c(0),size=1) +
theme(axis.title.y = element_blank(),
axis.title.x = element_text(size = 14),
plot.title = element_text(size = 18, face = "bold")) +
labs(title = "C2 Effector-like \nGSEA",
x = "NES \n(sgArid1a/sgScramble)")
Since IFN responses are prominently enriched in C2 effector like T cells, we created an interferon stimulated gene (ISG) metagene from leading edge genes in IFN Alpha/Gamma response signatures enriched in any of the five clusters from sgArid1a tumors to visualize this ISG signature in CD8+ T cells.
#Select CD8+ T cell metagene signature
CD8_ISG_score <- gene_signatures %>%
select("CD8_ISG_Metagene")
#Convert from dataframe to vector
CD8_ISG_score <- as.vector(CD8_ISG_score)
#AddModuleScore function from Seurat to add a custom gene signature to object
dat.integrated <- AddModuleScore(object = dat.integrated, features = CD8_ISG_score, ctrl = 5, name = "ISG_Metagene", seed = 12)
#Visualize expression of custom gene signature
FeaturePlot(dat.integrated,features = "ISG_Metagene1",label=FALSE,split.by = "Treatment",order=TRUE, pt.size = .75) & theme(legend.position="right",text=element_text(size=10)) & scale_color_viridis_c(option="magma", limits=c(0, 1), oob=scales::squish)
To further understand the T cell response in sgArid1a tumors, we investigated the clonal expansion of T cells via 10X VDJ kit for TCR-sequencing. This was primarily via the scRepertoire package.
#Read in VDJ filtered annotation files from 10X's CellRanger
sgArid1a_1=read.csv("./TCR_files/sgArid1a_1_filtered_contig_annotations.csv")
sgArid1a_2=read.csv("./TCR_files/sgArid1a_2_filtered_contig_annotations.csv")
sgScr_1=read.csv("./TCR_files/sgScr_1_filtered_contig_annotations.csv")
sgScr_2=read.csv("./TCR_files/sgScr_2_filtered_contig_annotations.csv")
#Make list of TCR samples
contig_list=list(sgArid1a_1,sgArid1a_2,sgScr_1,sgScr_2)
#scRepertoire command to make object
combinedTCR=combineTCR(contig_list,samples=c("sgArid1a","sgArid1a","sgScr","sgScr"),ID=c("1","2","1","2"))
#Integrate TCR data with Seurat object
dat.integrated = combineExpression(combinedTCR,dat.integrated, cloneCall="gene", proportion = FALSE, cloneSize = c(Single=1,Small=5,Medium=20,Large=100,Hyperexpanded=500))
#Make new metadata feature for CloneType TCR expansion categories in Seurat object
slot(dat.integrated,"meta.data")$cloneType=factor(slot(dat.integrated,"meta.data")$cloneType, levels=c("Hyperexpanded (100 < X <= 500)","Large (20 < X <= 100)","Medium (5 < X <= 20)","Small (1 < X <= 5)","Single (0 < X <= 1)", "No TCR mapped"))
# Define custom color palette
custom_colors <- c("Hyperexpanded (100 < X <= 500)" = "#FF0000",
"Large (20 < X <= 100)" = "#FF7F00",
"Medium (5 < X <= 20)" = "#80A440",
"Small (1 < X <= 5)" = "#4A9BFF",
"Single (0 < X <= 1)" = "#AAEEFF",
"No TCR mapped" = "grey50" )
#Make sure any NA value is populated with "No TCR mapped"
dat.integrated@meta.data$cloneType[is.na(dat.integrated@meta.data$cloneType)] <- "No TCR mapped"
#DimPlot for CloneType
DimPlot(dat.integrated, group.by = "cloneType", split.by = "Treatment", pt.size = 0.2,
cols = custom_colors, order = c("Hyperexpanded (100 < X <= 500)",
"Large (20 < X <= 100)",
"Medium (5 < X <= 20)",
"Small (1 < X <= 5)",
"Single (0 < X <= 1)",
"No TCR mapped"))
Visualizing the classes of clonotype expansion in each tumor genotype. Note: The TCR clonotype barchart groups are defined by a proportion of total TCR in their respective groups which are equal to the integer values seen on the TCR UMAP above.
sgArid1a_combine <- rbind(sgArid1a_1, sgArid1a_2)
sgScr_combine <- rbind(sgScr_1, sgScr_2)
#sgArid1a_comb=rbind(sgArid1a_1,sgArid1a_2)
contig_list=list(sgScr_combine, sgArid1a_combine)
#scRepetoire
combinedTCR=combineTCR(contig_list,samples=c("sgScr", "sgArid1a"))
mypalette2 <- rev(c("#FF0000", "#FF7F00", "#80A440", "#4A9BFF", "#AAEEFF"))
#scRepertoire function
clonalHomeostasis(combinedTCR, cloneSize = c(Single = 1e-04, Small = 0.0003, Medium = 0.0012, Large = 0.006, Hyperexpanded= 0.3),cloneCall = "gene",chain="both", )+scale_fill_manual(values=mypalette2) +theme(axis.title.x = element_blank())
Visualizing expansion of individual TCRs in each tumor genotype and whether they are expanded in both genotypes (dual expanded) or unique between genotypes. Colors for this figure were edited in illustrator. Interestingly, the top TCR in sgArid1a tumors is shared in sgScramble tumors, but at low frequency in sgScramble tumor group. This suggests increased antigen presentation of a common antigen such as a B16F10 tumor antigen (most likely), but could conceivably be reactive to other types of antigens such as an auto-antigen.
#clonotype scatter plot
clonalScatter(combinedTCR,cloneCall="gene",y.axis="sgArid1a",x.axis="sgScr",dot.size="total",graph="proportion", palette = "Berlin") #exportTable=TRUE exports data to table
For reproducibility, my session info is listed below outlining the version of R and package versions that I’ve using for this vignette.
print(sessionInfo())
## R version 4.3.1 (2023-06-16)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 22.04.3 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.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: America/Los_Angeles
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats4 stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] WebGestaltR_0.4.6 forcats_1.0.0
## [3] stringr_1.5.1 Nebulosa_1.12.1
## [5] patchwork_1.2.0 scater_1.31.2
## [7] scuttle_1.10.3 scRepertoire_2.0.0
## [9] ggpubfigs_0.0.1 dplyr_1.1.4
## [11] ggplot2_3.5.0 cowplot_1.1.3
## [13] scDataviz_1.12.0 SingleCellExperiment_1.22.0
## [15] SummarizedExperiment_1.30.2 Biobase_2.60.0
## [17] GenomicRanges_1.52.1 GenomeInfoDb_1.36.4
## [19] IRanges_2.34.1 MatrixGenerics_1.12.3
## [21] matrixStats_1.2.0 S4Vectors_0.38.2
## [23] BiocGenerics_0.46.0 Seurat_5.0.1
## [25] SeuratObject_5.0.1 sp_2.1-3
## [27] here_1.0.1 pacman_0.5.1
##
## loaded via a namespace (and not attached):
## [1] spatstat.sparse_3.0-3 bitops_1.0-7
## [3] doParallel_1.0.17 httr_1.4.7
## [5] RColorBrewer_1.1-3 doRNG_1.8.6
## [7] tools_4.3.1 sctransform_0.4.1
## [9] utf8_1.2.4 R6_2.5.1
## [11] lazyeval_0.2.2 uwot_0.1.16
## [13] withr_3.0.0 gridExtra_2.3
## [15] progressr_0.14.0 textshaping_0.3.7
## [17] quantreg_5.97 cli_3.6.2
## [19] Cairo_1.6-2 spatstat.explore_3.2-6
## [21] fastDummies_1.7.3 iNEXT_3.0.1
## [23] isoband_0.2.7 labeling_0.4.3
## [25] sass_0.4.8 mvtnorm_1.2-4
## [27] spatstat.data_3.0-4 readr_2.1.5
## [29] ggridges_0.5.6 pbapply_1.7-2
## [31] askpass_1.2.0 systemfonts_1.0.5
## [33] svglite_2.1.3 stringdist_0.9.12
## [35] parallelly_1.36.0 limma_3.56.2
## [37] flowCore_2.14.2 VGAM_1.1-10
## [39] rstudioapi_0.15.0 generics_0.1.3
## [41] vroom_1.6.5 ica_1.0-3
## [43] spatstat.random_3.2-2 Matrix_1.6-5
## [45] RProtoBufLib_2.14.1 ggbeeswarm_0.7.2
## [47] fansi_1.0.6 abind_1.4-5
## [49] lifecycle_1.0.4 whisker_0.4.1
## [51] yaml_2.3.8 Rtsne_0.17
## [53] grid_4.3.1 promises_1.2.1
## [55] crayon_1.5.2 miniUI_0.1.1.1
## [57] lattice_0.22-5 beachmat_2.16.0
## [59] pillar_1.9.0 knitr_1.45
## [61] rjson_0.2.21 future.apply_1.11.1
## [63] codetools_0.2-19 leiden_0.4.3.1
## [65] glue_1.7.0 data.table_1.15.0
## [67] vctrs_0.6.5 png_0.1-8
## [69] spam_2.10-0 gtable_0.3.4
## [71] cachem_1.0.8 ks_1.14.2
## [73] xfun_0.42 S4Arrays_1.2.1
## [75] mime_0.12 tidygraph_1.3.0
## [77] pracma_2.4.4 survival_3.5-7
## [79] iterators_1.0.14 cytolib_2.14.1
## [81] ellipsis_0.3.2 fitdistrplus_1.1-11
## [83] ROCR_1.0-11 nlme_3.1-164
## [85] bit64_4.0.5 RcppAnnoy_0.0.22
## [87] evd_2.3-6.1 rprojroot_2.0.4
## [89] bslib_0.6.1 irlba_2.3.5.1
## [91] vipor_0.4.7 KernSmooth_2.23-22
## [93] colorspace_2.1-0 ggrastr_1.0.2
## [95] tidyselect_1.2.0 bit_4.0.5
## [97] curl_5.2.0 compiler_4.3.1
## [99] BiocNeighbors_1.18.0 SparseM_1.81
## [101] ggdendro_0.1.23 DelayedArray_0.26.7
## [103] plotly_4.10.4 scales_1.3.0
## [105] lmtest_0.9-40 apcluster_1.4.11
## [107] digest_0.6.34 goftest_1.2-3
## [109] presto_1.0.0 spatstat.utils_3.0-4
## [111] rmarkdown_2.25 XVector_0.40.0
## [113] htmltools_0.5.7 pkgconfig_2.0.3
## [115] umap_0.2.10.0 sparseMatrixStats_1.12.2
## [117] highr_0.10 fastmap_1.1.1
## [119] rlang_1.1.3 htmlwidgets_1.6.4
## [121] shiny_1.8.0 DelayedMatrixStats_1.22.6
## [123] farver_2.1.1 jquerylib_0.1.4
## [125] zoo_1.8-12 jsonlite_1.8.8
## [127] BiocParallel_1.34.2 mclust_6.1
## [129] BiocSingular_1.16.0 RCurl_1.98-1.14
## [131] magrittr_2.0.3 GenomeInfoDbData_1.2.10
## [133] dotCall64_1.1-1 munsell_0.5.0
## [135] Rcpp_1.0.12 evmix_2.12
## [137] viridis_0.6.5 reticulate_1.35.0
## [139] truncdist_1.0-2 stringi_1.8.3
## [141] ggalluvial_0.12.5 ggraph_2.1.0
## [143] zlibbioc_1.46.0 MASS_7.3-60.0.1
## [145] plyr_1.8.9 parallel_4.3.1
## [147] listenv_0.9.1 ggrepel_0.9.5
## [149] deldir_2.0-2 graphlayouts_1.1.0
## [151] splines_4.3.1 hash_2.2.6.3
## [153] tensor_1.5 hms_1.1.3
## [155] igraph_1.6.0 spatstat.geom_3.2-8
## [157] cubature_2.1.0 rngtools_1.5.2
## [159] RcppHNSW_0.6.0 reshape2_1.4.4
## [161] ScaledMatrix_1.8.1 evaluate_0.23
## [163] tzdb_0.4.0 foreach_1.5.2
## [165] tweenr_2.0.2 httpuv_1.6.14
## [167] MatrixModels_0.5-3 RANN_2.6.1
## [169] tidyr_1.3.1 openssl_2.1.1
## [171] purrr_1.0.2 polyclip_1.10-6
## [173] future_1.33.1 scattermore_1.2
## [175] ggforce_0.4.1 rsvd_1.0.5
## [177] xtable_1.8-4 RSpectra_0.16-1
## [179] later_1.3.2 ragg_1.2.7
## [181] viridisLite_0.4.2 gsl_2.1-8
## [183] tibble_3.2.1 beeswarm_0.4.0
## [185] cluster_2.1.6 corrplot_0.92
## [187] globals_0.16.2