library(knitr) opts_chunk$set( fig.pos = "!h", out.extra = "", warning = F, fig.align = "center" )
libs <- c("here", "tidyr", "dplyr", "Seurat", "scater", "slingshot", "cowplot", "condiments", "ggplot2", "readr", "tradeSeq", "pheatmap", "fgsea", "msigdbr", "scales") suppressMessages( suppressWarnings(sapply(libs, require, character.only = TRUE)) ) rm(libs) theme_set(theme_classic() + theme(rect = element_blank(), plot.background = element_blank(), strip.background = element_rect(fill = "transparent") ))
fibrosis <- condimentsPaper::import_fibrosis()
data("fibrosis", package = "condimentsPaper")
Reduced dimension coordinates are obtained from the original publication.
df <- bind_cols(reducedDim(fibrosis, "UMAP") %>% as.data.frame(), colData(fibrosis)[, 1:14] %>% as.data.frame()) ggplot(df, aes(x = UMAP_1, y = UMAP_2, col = Status)) + geom_point(size = .5) + scale_color_brewer(palette = "Accent") + labs(col = "Disease") + theme(legend.position = c(.15, .4), legend.background = element_blank()) + guides(col = guide_legend(override.aes = list(size = 3))) ggplot(df, aes(x = UMAP_1, y = UMAP_2, col = celltype)) + geom_point(size = .5) + scale_color_brewer(palette = "Dark2") + labs(col = "Cell Type") + theme(legend.position = c(.2, .4), legend.background = element_blank()) + guides(col = guide_legend(override.aes = list(size = 3)))
scores <- condiments::imbalance_score( Object = df %>% select(UMAP_1, UMAP_2) %>% as.matrix(), conditions = df$Status, k = 20, smooth = 30) df$scores <- scores$scaled_scores ggplot(df, aes(x = UMAP_1, y = UMAP_2, col = scores)) + geom_point(size = .7) + scale_color_viridis_c(option = "C", breaks = c(0, 2, 4, 6)) + labs(col = "Scores") + theme(legend.position = c(.15, .4), legend.background = element_blank())
To estimate the trajectory, we use slingshot [@Street2018a].
fibrosis <- slingshot(fibrosis, reducedDim = 'UMAP', clusterLabels = colData(fibrosis)$celltype, start.clus = 'AT1', approx_points = 100)
set.seed(821) topologyTest(SlingshotDataSet(fibrosis), fibrosis$Status) fibrosis_SCGB3A2 <- slingshot(fibrosis[, fibrosis$celltype != "SCGB3A2+"], reducedDim = 'UMAP', clusterLabels = colData(fibrosis[, fibrosis$celltype != "SCGB3A2+"])$celltype, start.clus = 'AT1', approx_points = 100) set.seed(821) topologyTest(SlingshotDataSet(fibrosis_SCGB3A2), fibrosis_SCGB3A2$Status) rm(fibrosis_SCGB3A2)
sdss <- slingshot_conditions(SlingshotDataSet(fibrosis), fibrosis$Status) curves <- bind_rows(lapply(sdss, slingCurves, as.df = TRUE), .id = "Status") p4a <- ggplot(df, aes(x = UMAP_1, y = UMAP_2, col = Status)) + geom_point(size = .7, alpha = .2) + scale_color_brewer(palette = "Accent") + labs(col = "Disaes") + geom_path(data = curves %>% arrange(Status, Lineage, Order), aes(group = interaction(Lineage, Status)), size = 1.5) + annotate("text", x = -10, y = 6, label = "Lineage1", size = 5) + annotate("text", x = -7, y = -2.7, label = "Lineage2", size = 5) + theme(legend.position = c(.15, .35), legend.background = element_blank()) + NULL p4a
df <- bind_cols( as.data.frame(reducedDim(fibrosis, "UMAP")), slingPseudotime(fibrosis) %>% as.data.frame() %>% dplyr::rename_with(paste0, "_pst", .cols = everything()), slingCurveWeights(fibrosis) %>% as.data.frame(), ) %>% mutate(Lineage1_pst = if_else(is.na(Lineage1_pst), 0, Lineage1_pst), Lineage2_pst = if_else(is.na(Lineage2_pst), 0, Lineage2_pst), pst = if_else(Lineage1 > Lineage2, Lineage1_pst, Lineage2_pst), pst = max(pst) - pst) curves <- slingCurves(fibrosis, as.df = TRUE) ggplot(df, aes(x = UMAP_1, y = UMAP_2)) + geom_point(size = .7, aes(col = pst)) + scale_color_viridis_c() + labs(col = "Pseudotime") + geom_path(data = curves %>% arrange(Order), aes(group = Lineage), col = "black", size = 1.5) + annotate("text", x = -10, y = 6, label = "Lineage1", size = 5) + annotate("text", x = -7, y = -2.7, label = "Lineage2", size = 5) + theme(legend.position = c(.15, .35), legend.background = element_blank())
progressionTest(fibrosis, conditions = fibrosis$Status, lineages = TRUE)
df <- slingPseudotime(fibrosis) %>% as.data.frame() df$Status <- fibrosis$Status df <- df %>% pivot_longer(-Status, names_to = "Lineage", values_to = "pst") %>% filter(!is.na(pst)) ggplot(df, aes(x = pst)) + geom_density(alpha = .8, aes(fill = Status), col = "transparent") + geom_density(aes(col = Status), fill = "transparent", size = 1.5) + labs(x = "Pseudotime", fill = "Status") + facet_wrap(~Lineage, scales = "free_x") + guides(col = "none", fill = guide_legend( override.aes = list(size = 1.5, col = c("#7FC97F", "#BEAED4")) )) + scale_fill_brewer(palette = "Accent") + scale_color_brewer(palette = "Accent") + theme(legend.position = c(.8, .8), legend.direction = "horizontal")
fateSelectionTest(fibrosis, conditions = fibrosis$Status)
df <- slingCurveWeights(SlingshotDataSet(fibrosis), as.probs = TRUE) %>% as.data.frame() df$Status <- fibrosis$Status df <- df %>% pivot_longer(-Status, names_to = "Lineage", values_to = "ws") ggplot(df, aes(x = ws)) + geom_density(alpha = .8, aes(fill = Status), col = "transparent") + geom_density(aes(col = Status), fill = "transparent", size = 1.5) + labs(x = "Weights", fill = "Status") + facet_wrap(~Lineage, scales = "free_x") + guides(fill = "none", col = "none") + scale_fill_brewer(palette = "Accent") + scale_color_brewer(palette = "Accent")
We use tradeSeq [@VandenBerge2020].
library(tradeSeq) set.seed(3) BPPARAM <- BiocParallel::bpparam() BPPARAM$workers <- 3 icMat <- evaluateK(counts = fibrosis, sds = SlingshotDataSet(fibrosis), conditions = factor(fibrosis$Status), nGenes = 300, parallel = TRUE, BPPARAM = BPPARAM, k = 3:7)
Next, we fit the NB-GAMs using 6 knots, based on the pseudotime and cell-level weights estimated by Slingshot. We use the conditions
argument to fit separate smoothers for each condition.
library(tradeSeq) set.seed(3) fibrosis <- fitGAM(counts = fibrosis, conditions = factor(fibrosis$Status), nknots = 6)
condRes <- conditionTest(fibrosis, l2fc = log2(2), lineages = TRUE) condRes$padj <- p.adjust(condRes$pvalue_lineage1, "fdr") mean(condRes$padj <= 0.05, na.rm = TRUE) sum(condRes$padj <= 0.05, na.rm = TRUE) conditionGenes <- rownames(condRes)[condRes$padj <= 0.05] conditionGenes <- conditionGenes[!is.na(conditionGenes)]
patRes <- patternTest(fibrosis, l2fc = log2(2)) patRes$padj <- p.adjust(patRes$pvalue, "fdr") mean(patRes$padj <= 0.05, na.rm = TRUE) sum(patRes$padj <= 0.05, na.rm = TRUE) patternGenes <- rownames(patRes)[patRes$padj <= 0.05] patternGenes <- patternGenes[!is.na(patternGenes)]
library(RColorBrewer) scales <- c("#FCAE91", "#DE2D26", "#BDD7E7", "#3182BD") # plot genes oo <- order(patRes$waldStat, decreasing = TRUE) genes <- c("SCGB3A2", "SFTPC", "ABCA3", "AGER") # most significant gene ps <- lapply(genes, function(gene){ plotSmoothers(fibrosis, assays(fibrosis)$counts, gene = gene, curvesCol = scales, border = FALSE, sample = .2) + scale_x_reverse(breaks = 0:4/.4, labels = 4:0/.4) + labs(title = gene, col = "Lineage and Condition") + scale_color_manual(values = scales) + theme(plot.title = element_text(hjust = .5), rect = element_blank()) } ) legend_gene <- get_legend( ps[[1]] + theme(legend.position = "bottom") + guides(col = guide_legend(title.position = "top")) ) ps <- lapply(ps, function(p) {p + guides(col = "none")}) p6 <- plot_grid( plot_grid(plotlist = ps, ncol = 2, scale = .95, labels = c('a)', 'b)', 'c)', 'd)')), plot_grid(NULL, legend_gene, NULL, rel_widths = c(1, 1, 1), ncol = 3), nrow = 2, rel_heights = c(4, .5) ) p6
Below we show heatmaps of the genes DE between lineages The DE genes in the heatmaps are ordered according to a hierarchical clustering on the first lineage.
### based on mean smoother yhatSmooth <- predictSmooth(fibrosis, gene = patternGenes, nPoints = 50, tidy = TRUE) %>% mutate(yhat = log1p(yhat)) %>% group_by(gene) %>% mutate(yhat = scales::rescale(yhat)) %>% filter(condition == "ILD") %>% select(-condition) %>% ungroup() heatSmooth_Lineage1 <- pheatmap( yhatSmooth %>% filter(lineage == 1) %>% select(-lineage) %>% arrange(-time) %>% pivot_wider(names_from = time, values_from = yhat) %>% select(-gene) %>% `rownames<-`(patternGenes), cluster_cols = FALSE, show_rownames = FALSE, show_colnames = FALSE, main = "Lineage 1", legend = FALSE, silent = TRUE ) heatSmooth_Lineage2 <- pheatmap( (yhatSmooth %>% filter(lineage == 2) %>% select(-lineage) %>% arrange(-time) %>% pivot_wider(names_from = time, values_from = yhat) %>% select(-gene))[heatSmooth_Lineage1$tree_row$order, ], cluster_cols = FALSE, cluster_rows = FALSE, show_rownames = FALSE, show_colnames = FALSE, main = "Lineage 2", legend = FALSE, silent = TRUE ) p7 <- plot_grid(heatSmooth_Lineage1[[4]], heatSmooth_Lineage2[[4]], ncol = 2) p7
This is done using the fgsea package [@Korotkevich2016].
geneSets <- msigdbr(species = "Homo sapiens", category = "C5", subcategory = "BP") %>% mutate(gene_symbol = toupper(gene_symbol)) %>% filter(gene_symbol %in% names(fibrosis)) m_list <- geneSets %>% split(x = .$gene_symbol, f = .$gs_name) statsPat <- patRes$waldStat names(statsPat) <- rownames(patRes) eaRes <- fgsea(pathways = m_list, stats = statsPat, nperm = 5e4, minSize = 10) eaRes <- eaRes %>% arrange(pval) knitr::kable(head(eaRes[, 1:3], n = 20))
sessionInfo()
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.