Zika virus infections of human stem cell-derived cerebral organoids reveal viral lineage-specific pathogenesis responses.
The 4 matches · 1 of them tie a paragraph to a whole file, not to given lines: a weak match, whose lines are not tinted
- [1] § MATERIALS AND METHODS › Bulk RNA isolation and sequencing ↔ BulkRNA-seq_umi/nf-core_rnaseq/nf-core_rnaseq_umi.sh, the whole file · a weak match · score 0.75 · nf core, plus virus, gencode, hg38, MIT, genomes
- [2] § RESULTS › ZIKV-induced growth defect severity correlates with cytoarchitectural disruption ↔ scRNA-seq/020222_Gehrke.Rmd, lines 450–458 · score 0.60 · intermediate progenitor cells, neuronal progenitor cells, astrocytes, radial, Neurons
- [3] § RESULTS › Bulk RNA-seq reveals differential stress responses among ZIKV lineage infections ↔ scRNA-seq/020222_Gehrke.Rmd, lines 1028–1080 · score 0.59 · Log2 FC, stress response, fold change, Volcano, adj, cutoffs
- [4] § RESULTS › Bulk RNA-seq reveals differential stress responses among ZIKV lineage infections ↔ scRNA-seq/020222_Gehrke.Rmd, lines 1028–1080 · score 0.51 · log2 FC, stress response, overlaps, adj, folded, UG
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
R Markdown · 1,145 lines · 44 KB · MIT · 3 matches
- ---
- title: "scRNA-seq processing"
- author: "Charlie Whittaker and Yann Vanrobaeys"
- date: "2024-07-08"
- output:
- html_document:
- toc: true
- toc_depth: 3
- html_notebook: default
- ---
- ```{r setup, include=FALSE}
- knitr::opts_chunk$set(tidy=FALSE, cache=TRUE,
- dev="png", message=FALSE, error=FALSE, warning=TRUE)
- ```
- ```{r}
- library(Seurat)
- library(dplyr)
- library(ggplot2)
- library(openxlsx)
- library(SingleR)
- library(ggpubr)
- library(readxl)
- library(writexl)
- library(openxlsx)
- library(tidyverse)
- library(reprex)
- library(matrixStats)
- library(XML)
- library(ggrepel)
- library(rtracklayer)
- library(DESeq2)
- library(apeglm)
- library(ComplexHeatmap)
- library(edgeR)
- library(gprofiler2)
- library(cluster)
- library(stringr)
- library(fgsea)
- ```
- # Setup the Seurat Object
- ## Load the CellRanger outputs of individual sample
- ```{r}
- d9433_d7_mock.data <- Read10X(data.dir = "CellRanger_filtered_feature_bc_matrix_dir/d9433_d7_mock/filtered_feature_bc_matrix")
- d9433_d7_pr.data <- Read10X(data.dir = "CellRanger_filtered_feature_bc_matrix_dir/d9434_d7_pr/filtered_feature_bc_matrix")
- d9433_d7_mal.data <- Read10X(data.dir = "CellRanger_filtered_feature_bc_matrix_dir/d9435_d7_mal/filtered_feature_bc_matrix")
- d9433_d7_ug.data <- Read10X(data.dir = "CellRanger_filtered_feature_bc_matrix_dir/d9436_d7_ug/filtered_feature_bc_matrix")
- ```
- ## Initialize the Seurat object with the raw (non-normalized data).
- ```{r}
- d9433_d7_mock <- CreateSeuratObject(counts = d9433_d7_mock.data, project = "d9433_d7_mock", min.cells = 3, min.features = 200)
- d9434_d7_pr <- CreateSeuratObject(counts = d9433_d7_pr.data, project = "d9433_d7_pr", min.cells = 3, min.features = 200)
- d9435_d7_mal <- CreateSeuratObject(counts = d9433_d7_mal.data, project = "d9433_d7_mal", min.cells = 3, min.features = 200)
- d9436_d7_ug <- CreateSeuratObject(counts = d9433_d7_ug.data, project = "d9433_d7_ug", min.cells = 3, min.features = 200)
- d9433_d7_mock[["Condition"]] <- "Mock"
- d9434_d7_pr[["Condition"]] <- "Puerto Rico"
- d9435_d7_mal[["Condition"]] <- "Malaysia"
- d9436_d7_ug[["Condition"]] <- "Uganda"
- ```
- ## Merging data - All samples
- ```{r}
- seurat.merge <- merge(
- x = d9433_d7_mock,
- y = list(d9434_d7_pr, d9435_d7_mal, d9436_d7_ug),
- add.cell.ids = c("Mock", "PR", "MAL", "UG"),
- project = "020222Gehrke"
- )
- ```
- # Standard pre-processing worflow
- ## Process data
- ```{r}
- seurat.merge <- NormalizeData(seurat.merge, normalization.method = "LogNormalize", scale.factor = 10000)
- seurat.merge <- FindVariableFeatures(seurat.merge, selection.method = "vst", nfeatures = 2000)
- seurat.merge <- ScaleData(seurat.merge)
- seurat.merge <- RunPCA(seurat.merge, features = VariableFeatures(object = seurat.merge))
- ElbowPlot(seurat.merge, ndims = 50)
- seurat.merge <- RunUMAP(seurat.merge, reduction="pca",dims=1:30)
- seurat.merge <- FindNeighbors(seurat.merge, dims = 1:30, verbose = FALSE)
- seurat.merge <- FindClusters(seurat.merge, verbose = FALSE)
- ```
- ## Dim plot to explore the unintegrated data
- ```{r}
- Idents(seurat.merge) <- 'RNA_snn_res.0.8'
- seurat.merge$Condition <- factor(seurat.merge$Condition, levels = c("Mock", "Puerto Rico", "Malaysia", "Uganda"))
- DimPlot(seurat.merge,reduction="umap",split.by="Condition",label=TRUE,repel=FALSE) + NoLegend()
- ```
- ## QCs
- ```{r}
- seurat.merge[["percent.mt"]] <- PercentageFeatureSet(seurat.merge, pattern = "^MT-")
- seurat.merge$log10GenesPerUMI <- log10(seurat.merge$nFeature_RNA) / log10(seurat.merge$nCount_RNA)
- l2.n_feature <- log2([email hidden]$nFeature_RNA)
- l2.n_count <- log2([email hidden]$nCount_RNA)
- seurat.merge <- AddMetaData(seurat.merge, l2.n_feature, "l2.n_feature")
- seurat.merge <- AddMetaData(seurat.merge, l2.n_count, "l2.n_count")
- p <- table([email hidden]$RNA_snn_res.0.8,[email hidden]$Condition)
- p
- Idents(seurat.merge) <- 'RNA_snn_res.0.8'
- VlnPlot(seurat.merge, features=c("percent.mt"), split.by = "Condition", ncol=1, pt.size=0)+ NoLegend()
- VlnPlot(seurat.merge, features=c("l2.n_feature"), split.by = "Condition", ncol=1, pt.size=0)+ NoLegend()
- VlnPlot(seurat.merge, features=c("l2.n_count"), split.by = "Condition", ncol=1, pt.size=0)+ NoLegend()
- [email hidden] %>%
- ggplot(aes(color=orig.ident, x=nCount_RNA, fill= orig.ident)) +
- geom_density(alpha = 0.2) +
- scale_x_log10() +
- theme_classic() +
- ylab("Cell density") +
- geom_vline(xintercept = 500) +
- ggtitle("nCount")
- [email hidden] %>%
- ggplot(aes(color=orig.ident, x=nFeature_RNA, fill= orig.ident)) +
- geom_density(alpha = 0.2) +
- scale_x_log10() +
- theme_classic() +
- ylab("Cell density") +
- geom_vline(xintercept = 200) +
- ggtitle("nFeature")
- [email hidden] %>%
- ggplot(aes(x=nCount_RNA, y=nFeature_RNA, color=percent.mt)) +
- geom_point() +
- scale_color_gradient(low = "gray90", high = "black") +
- stat_smooth(method=lm) +
- scale_x_log10() +
- scale_y_log10() +
- theme_classic() +
- geom_vline(xintercept = 500) +
- geom_hline(yintercept = 250) +
- facet_wrap(~orig.ident)
- [email hidden] %>%
- ggplot(aes(x=log10GenesPerUMI, color = orig.ident, fill=orig.ident)) +
- geom_density(alpha = 0.2) +
- theme_classic() +
- geom_vline(xintercept = 0.8)
- ```
- ## Gene per UMI filtering of the merged object
- ```{r}
- seurat.merge.filt <- subset(seurat.merge, percent.mt <= 25 & log10GenesPerUMI > 0.75)
- VlnPlot(seurat.merge.filt, group.by = "orig.ident",features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)
- [email hidden] %>%
- ggplot(aes(x=log10GenesPerUMI, color = orig.ident, fill=orig.ident)) +
- geom_density(alpha = 0.2) +
- theme_classic() +
- geom_vline(xintercept = 0.8)
- Idents(seurat.merge.filt) <- 'RNA_snn_res.0.8'
- DimPlot(seurat.merge.filt,reduction="umap",split.by="Condition",label=TRUE,repel=FALSE) + NoLegend()
- ```
- ## Gene level filtering of the merged object
- ```{r}
- seurat.merge.filt2 <- seurat.merge.filt
- # Output a logical vector for every gene on whether the more than zero counts per cell
- # Extract counts
- counts <- GetAssayData(object = seurat.merge.filt2, slot = "counts")
- # Output a logical vector for every gene on whether the more than zero counts per cell
- nonzero <- counts > 0
- # Sums all TRUE values and returns TRUE if more than 10 TRUE values per gene
- keep_genes <- Matrix::rowSums(nonzero) >= 10
- # Only keeping those genes expressed in more than 10 cells
- filtered_counts <- counts[keep_genes, ]
- # Reassign to filtered Seurat object
- seurat.merge.filt2 <- CreateSeuratObject(filtered_counts, meta.data = [email hidden])
- ```
- ## Reprocess of the filtered merged object
- ```{r}
- seurat.merge.filt2 <- NormalizeData(seurat.merge.filt2, normalization.method = "LogNormalize", scale.factor = 10000)
- seurat.merge.filt2 <- FindVariableFeatures(seurat.merge.filt2, selection.method = "vst", nfeatures = 2000)
- seurat.merge.filt2 <- ScaleData(seurat.merge.filt2)
- seurat.merge.filt2 <- RunPCA(seurat.merge.filt2, features = VariableFeatures(object = seurat.merge.filt2))
- ElbowPlot(seurat.merge.filt2, ndims = 50)
- seurat.merge.filt2 <- RunUMAP(seurat.merge.filt2, reduction="pca",dims=1:30)
- seurat.merge.filt2 <- FindNeighbors(seurat.merge.filt2, dims = 1:30, verbose = FALSE)
- seurat.merge.filt2 <- FindClusters(seurat.merge.filt2, verbose = FALSE)
- Idents(seurat.merge.filt2) <- 'RNA_snn_res.0.8'
- DimPlot(seurat.merge.filt2,reduction="umap",split.by="Condition",label=TRUE,repel=FALSE) + NoLegend()
- ```
- # SCT normalization, MT regression and integration
- ```{r}
- split_seurat <- SplitObject(seurat.merge.filt2, split.by = "orig.ident")
- for (i in 1:length(split_seurat)) {
- split_seurat[[i]] <- NormalizeData(split_seurat[[i]], verbose = TRUE)
- split_seurat[[i]] <- SCTransform(split_seurat[[i]], vars.to.regress = c("percent.mt"))
- }
- # Select the most variable features to use for integration
- integ_features <- SelectIntegrationFeatures(object.list = split_seurat,
- nfeatures = 3000)
- # Prepare the SCT list object for integration
- split_seurat <- PrepSCTIntegration(object.list = split_seurat,
- anchor.features = integ_features)
- # Find best buddies - can take a while to run
- integ_anchors <- FindIntegrationAnchors(object.list = split_seurat,
- normalization.method = "SCT",
- anchor.features = integ_features)
- # Integrate across conditions
- seurat.integrated <- IntegrateData(anchorset = integ_anchors,
- normalization.method = "SCT")
- ```
- ## PCA view of integrated data
- ```{r}
- # Run PCA
- seurat.integrated <- RunPCA(object = seurat.integrated)
- # Plot PCA
- PCAPlot(seurat.integrated,split.by = "Condition")
- # Elbow Plot
- ElbowPlot(seurat.integrated, ndims = 50)
- ```
- # UMAP of integrated data
- ```{r}
- seurat.integrated <- RunUMAP(seurat.integrated, dims = 1:30, reduction = "pca")
- DimPlot(seurat.integrated, split.by = "Condition")
- ```
- ## Integrated Clustering
- ```{r}
- # Determine the K-nearest neighbor graph
- seurat.integrated <- FindNeighbors(object = seurat.integrated, dims = 1:30)
- # Determine the clusters for various resolutions
- seurat.integrated <- FindClusters(object = seurat.integrated, resolution = c(0.4, 0.8, 1.2))
- ```
- ## Dimplots of different resolutions
- ```{r fig.width=11, fig.height=4}
- Idents(seurat.integrated) <- 'integrated_snn_res.0.4'
- DimPlot(seurat.integrated, split.by = "Condition",label=TRUE,repel=FALSE) + NoLegend() + ggtitle("0.4 res")
- Idents(seurat.integrated) <- 'integrated_snn_res.0.8'
- DimPlot(seurat.integrated, split.by = "Condition",label=TRUE,repel=FALSE) + NoLegend() + ggtitle("0.8 res")
- Idents(seurat.integrated) <- 'integrated_snn_res.1.2'
- DimPlot(seurat.integrated, split.by = "Condition",label=TRUE,repel=FALSE) + NoLegend() + ggtitle("1.4 res")
- ```
- ## Proportion tables of integrated data
- ```{r}
- p <- table([email hidden]$integrated_snn_res.0.4,[email hidden]$orig.ident)
- p
- (round(prop.table(p,2),3)*100)
- ```
- # Investigate quality control features of the integrated clusters
- ```{r fig.width=5, fig.height=4}
- Idents(seurat.integrated,) <- 'integrated_snn_res.0.4'
- vln_plot_mt <- VlnPlot(seurat.integrated, features=c("percent.mt"), ncol=1, pt.size=0)+ NoLegend()
- vln_plot_feature <- VlnPlot(seurat.integrated, features=c("l2.n_feature"), ncol=1, pt.size=0)+ NoLegend()
- vln_plot_count <- VlnPlot(seurat.integrated, features=c("l2.n_count"), ncol=1, pt.size=0)+ NoLegend()
- UMAP_plot <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- ggarrange(UMAP_plot, vln_plot_mt, vln_plot_feature, vln_plot_count, ncol = 2, nrow = 2)
- ```
- # Cell type assignment of clusters
- ## Identiify cell type biomarkers
- ```{r}
- DefaultAssay(seurat.integrated)<-"RNA"
- Idents(object = seurat.integrated) <- 'integrated_snn_res.0.4'
- seurat.integrated.clusterMarkers <- FindAllMarkers(seurat.integrated, only.pos=TRUE, min.pct=0.25)
- write.xlsx(seurat.integrated.clusterMarkers, file="seurat.integrated.clusterMarkers.xlsx", rowNames=TRUE, overwrite = TRUE)
- ```
- ## Biomarkers gene expression pattern
- ### Biomarker TTR
- ```{r fig.width=11, fig.height=4}
- vln_plot_TTR <- VlnPlot(seurat.integrated, features = "TTR", pt.size=0) + NoLegend()
- UMAP_plot <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_TTR <- FeaturePlot(seurat.integrated, features = c("TTR"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_TTR, UMAP_plot, feature_plot_TTR, ncol = 3, nrow = 1)
- ```
- ### Biomarker PCP4
- ```{r fig.width=11, fig.height=4}
- vln_plot_PCP4 <- VlnPlot(seurat.integrated, features = "PCP4", pt.size=0) + NoLegend()
- UMAP_plot_PCP4 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_PCP4 <- FeaturePlot(seurat.integrated, features = c("PCP4"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_PCP4, UMAP_plot_PCP4, feature_plot_PCP4, ncol = 3, nrow = 1)
- ```
- ### Biomarker STMN2
- ```{r fig.width=11, fig.height=4}
- vln_plot_STMN2 <- VlnPlot(seurat.integrated, features = "STMN2", pt.size=0) + NoLegend()
- UMAP_plot_STMN2 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_STMN2 <- FeaturePlot(seurat.integrated, features = c("STMN2"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_EOMES, UMAP_plot_EOMES, feature_plot_EOMES, ncol = 3, nrow = 1)
- ```
- ### Biomarker MAP2
- ```{r fig.width=11, fig.height=4}
- vln_plot_MAP2 <- VlnPlot(seurat.integrated, features = "MAP2", pt.size=0) + NoLegend()
- UMAP_plot <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_MAP2 <- FeaturePlot(seurat.integrated, features = c("MAP2"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_MAP2, UMAP_plot, feature_plot_MAP2, ncol = 3, nrow = 1)
- ```
- ### Biomarker TOP2A
- ```{r fig.width=11, fig.height=4}
- vln_plot_TOP2A <- VlnPlot(seurat.integrated, features = "TOP2A", pt.size=0) + NoLegend()
- UMAP_plot <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_TOP2A <- FeaturePlot(seurat.integrated, features = c("TOP2A"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_TOP2A, UMAP_plot, feature_plot_TOP2A, ncol = 3, nrow = 1)
- ```
- ### Biomarker CCNB2
- ```{r fig.width=11, fig.height=4}
- vln_plot_CCNB2 <- VlnPlot(seurat.integrated, features = "CCNB2", pt.size=0) + NoLegend()
- UMAP_plot_CCNB2 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_CCNB2 <- FeaturePlot(seurat.integrated, features = c("CCNB2"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_TBR2, UMAP_plot_TBR2, feature_plot_TBR2, ncol = 3, nrow = 1)
- ```
- ### Biomarker NEFL
- ```{r fig.width=11, fig.height=4}
- vln_plot_NEFL <- VlnPlot(seurat.integrated, features = "NEFL", pt.size=0) + NoLegend()
- UMAP_plot_NEFL <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_NEFL <- FeaturePlot(seurat.integrated, features = c("NEFL"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_NEFL, UMAP_plot_NEFL, feature_plot_NEFL, ncol = 3, nrow = 1)
- ```
- ### Biomarker MEIS2
- ```{r fig.width=11, fig.height=4}
- vln_plot_MEIS2 <- VlnPlot(seurat.integrated, features = "MEIS2", pt.size=0) + NoLegend()
- UMAP_plot_MEIS2 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_MEIS2 <- FeaturePlot(seurat.integrated, features = c("MEIS2"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_MEIS2, UMAP_plot_MEIS2, feature_plot_MEIS2, ncol = 3, nrow = 1)
- ```
- ### Biomarker SOX2
- ```{r fig.width=11, fig.height=4}
- vln_plot_SOX2 <- VlnPlot(seurat.integrated, features = "SOX2", pt.size=0) + NoLegend()
- UMAP_plot_SOX2 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_SOX2 <- FeaturePlot(seurat.integrated, features = c("SOX2"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_SOX2, UMAP_plot_SOX2, feature_plot_SOX2, ncol = 3, nrow = 1)
- ```
- ### Biomarker PTN
- ```{r fig.width=11, fig.height=4}
- vln_plot_PTN <- VlnPlot(seurat.integrated, features = "PTN", pt.size=0) + NoLegend()
- UMAP_plot_PTN <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_PTN <- FeaturePlot(seurat.integrated, features = c("PTN"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_PTN, UMAP_plot_PTN, feature_plot_PTN, ncol = 3, nrow = 1)
- ```
- ### Biomarker S100A10
- ```{r fig.width=11, fig.height=4}
- vln_plot_S100A10 <- VlnPlot(seurat.integrated, features = "S100A10", pt.size=0) + NoLegend()
- UMAP_plot_S100A10 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_S100A10 <- FeaturePlot(seurat.integrated, features = c("S100A10"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_S100A10, UMAP_plot_S100A10, feature_plot_S100A10, ncol = 3, nrow = 1)
- ```
- ### Biomarker COL1A1
- ```{r fig.width=11, fig.height=4}
- vln_plot_COL1A1 <- VlnPlot(seurat.integrated, features = "COL1A1", pt.size=0) + NoLegend()
- UMAP_plot_COL1A1 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_COL1A1 <- FeaturePlot(seurat.integrated, features = c("COL1A1"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_COL1A1, UMAP_plot_COL1A1, feature_plot_COL1A1, ncol = 3, nrow = 1)
- ```
- ### Biomarker COL1A2
- ```{r fig.width=11, fig.height=4}
- vln_plot_COL1A2 <- VlnPlot(seurat.integrated, features = "COL1A2", pt.size=0) + NoLegend()
- UMAP_plot_COL1A2 <- DimPlot(seurat.integrated, label=TRUE,repel=FALSE) + NoLegend()
- feature_plot_COL1A2 <- FeaturePlot(seurat.integrated, features = c("COL1A2"), min.cutoff = "q10", max.cutoff = "q90")
- ggarrange(vln_plot_COL1A2, UMAP_plot_COL1A2, feature_plot_COL1A2, ncol = 3, nrow = 1)
- ```
- ## Rename cluster names
- ```{r fig.width=4.5, fig.height=4.5}
- Idents(object = seurat.integrated) <- 'integrated_snn_res.0.4'
- new.cluster.ids <- c("Neuronal progenitor cells", "Neuronal progenitor cells", "Intermediate progenitor cells", "Neurons", "Cell debris", "Neuronal progenitor cells", "Midbrain-Hindbrain", "Radial glial cells", "Ventral progenitors", "Ventral progenitors", "Choroid plexus", "Astrocytes", "Neuronal progenitor cells")
- names(new.cluster.ids) <- levels(seurat.integrated)
- seurat.integrated <- RenameIdents(seurat.integrated, new.cluster.ids)
- DimPlot(seurat.integrated, reduction = "umap", label = TRUE, pt.size = 0.5, label.size = 5, repel = TRUE) + NoLegend()
- ```
- ## Bubble plot with biomarkers
- ```{r fig.width=7, fig.height=6}
- markers.to.plot <- c("SOX2", "TOP2A", "MAP2", "NEFL", "TLE4", "EPB41L4A-AS1", "TTR", "S100A10")
- DotPlot(seurat.integrated, features = markers.to.plot, cols = c("black", "brown", "yellow", "green"), dot.scale = 8, split.by = "Condition") +
- RotatedAxis()
- ```
- # Viral expression
- ## Between samples and conditions
- ```{r}
- seurat.integrated$Condition <- factor(seurat.integrated$Condition, levels = c("Mock", "Malaysia", "Puerto Rico", "Uganda"))
- # Create individual violin plots
- vln_plot_1 <- VlnPlot(seurat.integrated, features = "vir-ZVMAL", group.by = "Condition", pt.size=0.3, y.max=8) + NoLegend()
- vln_plot_2 <- VlnPlot(seurat.integrated, features = "vir-ZVPR", group.by = "Condition", pt.size=0.3, y.max=8) + NoLegend()
- vln_plot_3 <- VlnPlot(seurat.integrated, features = "vir-ZVUG", group.by = "Condition", pt.size=0.3, y.max=8) + NoLegend()
- # Arrange the plots together
- ggarrange(vln_plot_1, vln_plot_2, vln_plot_3, ncol = 3, nrow = 1)
- ```
- ## Per celltype
- ```{r fig.width=6, fig.height=12}
- # Subset the Seurat object to exclude the "Cell debris" cluster
- seurat_no_debris <- subset(seurat.integrated, idents = "Cell debris", invert = TRUE)
- # Create individual violin plots
- vln_plot_1 <- VlnPlot(seurat_no_debris, features = "vir-ZVMAL", split.by = "Condition", pt.size=0, y.max=8)
- vln_plot_2 <- VlnPlot(seurat_no_debris, features = "vir-ZVPR", split.by = "Condition", pt.size=0, y.max=8)
- vln_plot_3 <- VlnPlot(seurat_no_debris, features = "vir-ZVUG", split.by = "Condition", pt.size=0, y.max=8)
- # Arrange the plots together
- ggarrange(vln_plot_2, vln_plot_1, vln_plot_3, ncol = 1, nrow = 3)
- ```
- ## QC per celltype per infection
- ```{r fig.width=10, fig.height=15}
- # Create individual violin plots
- vln_plot_mt <- VlnPlot(seurat_no_debris, features=c("percent.mt"), split.by = "Condition", ncol=1, pt.size=0)
- vln_plot_feature <- VlnPlot(seurat_no_debris, features=c("l2.n_feature"), split.by = "Condition", ncol=1, pt.size=0)
- vln_plot_count <- VlnPlot(seurat_no_debris, features=c("l2.n_count"), split.by = "Condition", ncol=1, pt.size=0)
- # Arrange the plots together
- combined_QCplot <- ggarrange(
- vln_plot_mt + theme(plot.margin = margin(5.5, 5.5, 5.5, 60, "pt")),
- vln_plot_feature + theme(plot.margin = margin(5.5, 5.5, 5.5, 60, "pt")),
- vln_plot_count + theme(plot.margin = margin(5.5, 5.5, 5.5, 60, "pt")),
- ncol = 1, nrow = 3
- )
- ggsave("combined_QCplot.pdf", plot = combined_QCplot, width = 10, height = 15)
- ```
- ## Number of cells per celltype per condition
- ```{r}
- # Create the table
- cell_counts <- table(Idents(seurat_no_debris), seurat_no_debris$Condition)
- # Convert the table to a data frame for exporting
- cell_counts_df <- as.data.frame.matrix(cell_counts)
- # Export to Excel
- write.xlsx(cell_counts_df, file = "cell_counts_clusters_conditions.xlsx", rowNames = TRUE)
- ```
- ## Number of infected and non infected cells
- ```{r}
- DefaultAssay(seurat_no_debris)<-"RNA"
- # Specify the genes of interest
- genes_of_interest <- c("vir-ZVPR", "vir-ZVMAL", "vir-ZVUG")
- # Extract expression data for the genes of interest
- expression_data <- FetchData(seurat_no_debris, vars = genes_of_interest)
- # Identify cells expressing each gene
- expressing_cells <- expression_data > 0
- # Identify cells that do not express any of the genes
- non_expressing_cells <- rowSums(expressing_cells) == 0
- # Get cell types from the active ident
- cell_types <- [email hidden]
- # Get conditions from the metadata
- conditions <- seurat_no_debris$Condition
- # Create a dataframe with cell types, conditions, and expression status
- expression_per_celltype_condition <- data.frame(cell_type = cell_types,
- condition = conditions,
- expressing_cells,
- none_expressed = non_expressing_cells)
- # Count the number of cells expressing each gene and not expressing any gene per cell type and condition
- counts_per_celltype_condition <- aggregate(. ~ cell_type + condition,
- data = expression_per_celltype_condition,
- FUN = sum)
- # View the results
- print(counts_per_celltype_condition)
- # Specify the output file name
- output_file <- "CellType_Condition_ViralExpression.xlsx"
- # Export the result to an Excel file
- write.xlsx(counts_per_celltype_condition, file = output_file, rowNames = FALSE)
- ```
- # Bubble plot interferon genes
- ```{r fig.width=7, fig.height=6}
- interferons.to.plot.bulk <- c("IFIT2", "ISG15", "IFIT3", "STAT1", "IFIT5", "IFIT1", "IFI27", "HLA-B", "IFI6", "EIF2AK2")
- # Create the DotPlot
- DotPlot(seurat.integrated, features = interferons.to.plot.bulk,
- cols = c("black", "brown", "yellow", "green"),
- dot.scale = 8, split.by = "Condition", scale.by = "size") +
- RotatedAxis()
- interferonDotPlot <- DotPlot(seurat.integrated, features = interferons.to.plot.bulk,
- cols = c("black", "brown", "yellow", "green"),
- dot.scale = 8, split.by = "Condition", scale.by = "size") +
- RotatedAxis()
- # Save the plot as a PDF
- ggsave(filename = "interferonDotPlot.pdf", plot = interferonDotPlot, device = "pdf", width = 10, height = 12)
- ```
- # Differentially Expressed Genes per cluster virus vs mock
- ```{r}
- seurat.integrated$Condition <- factor(seurat.integrated$Condition, levels = c("Mock", "Malaysia", "Puerto Rico", "Uganda"))
- seurat.integrated$ClusterNames <- [email hidden]
- seurat.integrated$cluster.condition <- paste(seurat.integrated$ClusterNames, seurat.integrated$Condition, sep = "_")
- Idents(seurat.integrated) <- "cluster.condition"
- table(seurat.integrated$cluster.condition)
- # Create a data frame from the table output
- df <- as.data.frame(table(seurat.integrated$cluster.condition))
- # Split the cluster.condition into separate columns for cluster and condition
- df <- tidyr::separate(df, Var1, into = c("Cluster", "Condition"), sep = "_")
- # Create the bar plot
- ggplot(df, aes(x = Cluster, y = Freq, fill = Condition)) +
- geom_bar(stat = "identity", position = "dodge") +
- labs(title = "Number of cells per cluster per condition",
- x = "Cluster",
- y = "Count",
- fill = "Condition") +
- theme_minimal()+
- theme(axis.text.x = element_text(angle = 45, hjust = 1))
- ```
- ```{r}
- # Initialize a list to store the results
- de_results_PR <- list()
- de_results_Mal <- list()
- de_results_Ug <- list()
- de_results_MalPR <- list()
- de_results_UgPR <- list()
- de_results_MalUg <- list()
- # Define the clusters and conditions
- clusters <- levels(seurat.integrated$ClusterNames)
- PRconditions <- c("Puerto Rico", "Mock")
- Malconditions <- c("Malaysia", "Mock")
- Ugconditions <- c("Uganda", "Mock")
- MalPRconditions <- c("Malaysia", "Puerto Rico")
- UgPRconditions <- c("Uganda", "Puerto Rico")
- MalUgconditions <- c("Malaysia", "Uganda")
- # Loop through each cluster and perform differential expression analysis for PR vs mock
- for (cluster in clusters) {
- ident.1 <- paste(cluster, PRconditions[1], sep = "_")
- ident.2 <- paste(cluster, PRconditions[2], sep = "_")
- if (ident.1 %in% Idents(seurat.integrated) & ident.2 %in% Idents(seurat.integrated)) {
- de_results_PR[[paste("Cluster", cluster)]] <- FindMarkers(seurat.integrated, ident.1 = ident.1, ident.2 = ident.2, verbose = FALSE, logfc.threshold = 0)
- } else {
- message(paste("Cluster", cluster, "does not have both conditions."))
- }
- }
- # Loop through each cluster and perform differential expression analysis for Mal vs mock
- for (cluster in clusters) {
- ident.1 <- paste(cluster, Malconditions[1], sep = "_")
- ident.2 <- paste(cluster, Malconditions[2], sep = "_")
- if (ident.1 %in% Idents(seurat.integrated) & ident.2 %in% Idents(seurat.integrated)) {
- de_results_Mal[[paste("Cluster", cluster)]] <- FindMarkers(seurat.integrated, ident.1 = ident.1, ident.2 = ident.2, verbose = FALSE, logfc.threshold = 0)
- } else {
- message(paste("Cluster", cluster, "does not have both conditions."))
- }
- }
- # Loop through each cluster and perform differential expression analysis for Ug vs mock
- for (cluster in clusters) {
- ident.1 <- paste(cluster, Ugconditions[1], sep = "_")
- ident.2 <- paste(cluster, Ugconditions[2], sep = "_")
- if (ident.1 %in% Idents(seurat.integrated) & ident.2 %in% Idents(seurat.integrated)) {
- de_results_Ug[[paste("Cluster", cluster)]] <- FindMarkers(seurat.integrated, ident.1 = ident.1, ident.2 = ident.2, verbose = FALSE, logfc.threshold = 0)
- } else {
- message(paste("Cluster", cluster, "does not have both conditions."))
- }
- }
- # Loop through each cluster and perform differential expression analysis for Mal vs PR
- for (cluster in clusters) {
- ident.1 <- paste(cluster, MalPRconditions[1], sep = "_")
- ident.2 <- paste(cluster, MalPRconditions[2], sep = "_")
- if (ident.1 %in% Idents(seurat.integrated) & ident.2 %in% Idents(seurat.integrated)) {
- de_results_MalPR[[paste("Cluster", cluster)]] <- FindMarkers(seurat.integrated, ident.1 = ident.1, ident.2 = ident.2, verbose = FALSE, logfc.threshold = 0)
- } else {
- message(paste("Cluster", cluster, "does not have both conditions."))
- }
- }
- # Loop through each cluster and perform differential expression analysis for Ug vs PR
- for (cluster in clusters) {
- ident.1 <- paste(cluster, UgPRconditions[1], sep = "_")
- ident.2 <- paste(cluster, UgPRconditions[2], sep = "_")
- if (ident.1 %in% Idents(seurat.integrated) & ident.2 %in% Idents(seurat.integrated)) {
- de_results_UgPR[[paste("Cluster", cluster)]] <- FindMarkers(seurat.integrated, ident.1 = ident.1, ident.2 = ident.2, verbose = FALSE, logfc.threshold = 0)
- } else {
- message(paste("Cluster", cluster, "does not have both conditions."))
- }
- }
- # Loop through each cluster and perform differential expression analysis for Mal vs Ug
- for (cluster in clusters) {
- ident.1 <- paste(cluster, MalUgconditions[1], sep = "_")
- ident.2 <- paste(cluster, MalUgconditions[2], sep = "_")
- if (ident.1 %in% Idents(seurat.integrated) & ident.2 %in% Idents(seurat.integrated)) {
- de_results_MalUg[[paste("Cluster", cluster)]] <- FindMarkers(seurat.integrated, ident.1 = ident.1, ident.2 = ident.2, verbose = FALSE, logfc.threshold = 0)
- } else {
- message(paste("Cluster", cluster, "does not have both conditions."))
- }
- }
- ```
- # GSEA - Functional Class Sorting
- Preparing rank files
- Extract protein coding genes from assembled data files, adjust the data and write rnk file in gsea directory
- ## Rank files for GSEA
- Ranked gene lists (rnk files) were generated from differential expression results using avg_log2FC values. The process involved iterating through each cluster of differential expression results for the conditions Mal, PR, and Ug, extracting the avg_log2FC values, and renaming the columns to reflect the specific condition and cluster (e.g., Ug_v_mock.Neuronal_progenitor_cells.rnk, PR_v_mock.Neurons.rnk, etc.). These avg_log2FC values were stored in individual data frames for each celltype, which were subsequently merged into a single data frame for each condition.
- For each merged data frame, the gene name and corresponding avg_log2FC values were selected and saved as rnk files, ensuring only complete cases were included. These rnk files were then used for Gene Set Enrichment Analysis (GSEA) utilizing the prerank_4.3.2_v2023.1.sh script to identify enriched gene sets within the collection Gene Ontology Biological Process (c5bp).
- ```{r}
- # Initialize an empty list to store avg_log2FC dataframes
- avg_log2FC_list_Mal <- list()
- avg_log2FC_list_PR <- list()
- avg_log2FC_list_Ug <- list()
- avg_log2FC_list_MalPR <- list()
- avg_log2FC_list_UgPR <- list()
- avg_log2FC_list_MalUg <- list()
- # Loop through the differential expression results and extract avg_log2FC
- for (cluster in names(de_results_Mal)) {
- cluster_name <- sub("Cluster ", "", cluster) # Remove "Cluster " prefix to get the cluster name
- column_name <- paste0("mal_v_mock.", cluster_name) # Create the new column name
- avg_log2FC_df <- data.frame(gene_name = rownames(de_results_Mal[[cluster]]),
- avg_log2FC = de_results_Mal[[cluster]]$avg_log2FC)
- colnames(avg_log2FC_df)[2] <- column_name # Rename the avg_log2FC column to the new name
- avg_log2FC_list_Mal[[cluster_name]] <- avg_log2FC_df # Use the cluster name without "Cluster " prefix
- }
- for (cluster in names(de_results_PR)) {
- cluster_name <- sub("Cluster ", "", cluster) # Remove "Cluster " prefix to get the cluster name
- column_name <- paste0("PR_v_mock.", cluster_name) # Create the new column name
- avg_log2FC_df <- data.frame(gene_name = rownames(de_results_PR[[cluster]]),
- avg_log2FC = de_results_PR[[cluster]]$avg_log2FC)
- colnames(avg_log2FC_df)[2] <- column_name # Rename the avg_log2FC column to the new name
- avg_log2FC_list_PR[[cluster_name]] <- avg_log2FC_df # Use the cluster name without "Cluster " prefix
- }
- for (cluster in names(de_results_Ug)) {
- cluster_name <- sub("Cluster ", "", cluster) # Remove "Cluster " prefix to get the cluster name
- column_name <- paste0("Ug_v_mock.", cluster_name) # Create the new column name
- avg_log2FC_df <- data.frame(gene_name = rownames(de_results_Ug[[cluster]]),
- avg_log2FC = de_results_Ug[[cluster]]$avg_log2FC)
- colnames(avg_log2FC_df)[2] <- column_name # Rename the avg_log2FC column to the new name
- avg_log2FC_list_Ug[[cluster_name]] <- avg_log2FC_df # Use the cluster name without "Cluster " prefix
- }
- for (cluster in names(de_results_MalPR)) {
- cluster_name <- sub("Cluster ", "", cluster) # Remove "Cluster " prefix to get the cluster name
- column_name <- paste0("Mal_v_PR.", cluster_name) # Create the new column name
- avg_log2FC_df <- data.frame(gene_name = rownames(de_results_MalPR[[cluster]]),
- avg_log2FC = de_results_MalPR[[cluster]]$avg_log2FC)
- colnames(avg_log2FC_df)[2] <- column_name # Rename the avg_log2FC column to the new name
- avg_log2FC_list_MalPR[[cluster_name]] <- avg_log2FC_df # Use the cluster name without "Cluster " prefix
- }
- for (cluster in names(de_results_UgPR)) {
- cluster_name <- sub("Cluster ", "", cluster) # Remove "Cluster " prefix to get the cluster name
- column_name <- paste0("Ug_v_PR.", cluster_name) # Create the new column name
- avg_log2FC_df <- data.frame(gene_name = rownames(de_results_UgPR[[cluster]]),
- avg_log2FC = de_results_UgPR[[cluster]]$avg_log2FC)
- colnames(avg_log2FC_df)[2] <- column_name # Rename the avg_log2FC column to the new name
- avg_log2FC_list_UgPR[[cluster_name]] <- avg_log2FC_df # Use the cluster name without "Cluster " prefix
- }
- for (cluster in names(de_results_MalUg)) {
- cluster_name <- sub("Cluster ", "", cluster) # Remove "Cluster " prefix to get the cluster name
- column_name <- paste0("Mal_v_Ug.", cluster_name) # Create the new column name
- avg_log2FC_df <- data.frame(gene_name = rownames(de_results_MalUg[[cluster]]),
- avg_log2FC = de_results_MalUg[[cluster]]$avg_log2FC)
- colnames(avg_log2FC_df)[2] <- column_name # Rename the avg_log2FC column to the new name
- avg_log2FC_list_MalUg[[cluster_name]] <- avg_log2FC_df # Use the cluster name without "Cluster " prefix
- }
- # Merge all dataframes in the list into one dataframe
- merged_df_Mal <- Reduce(function(x, y) merge(x, y, by = "gene_name", all = TRUE), avg_log2FC_list_Mal)
- merged_df_PR <- Reduce(function(x, y) merge(x, y, by = "gene_name", all = TRUE), avg_log2FC_list_PR)
- merged_df_Ug <- Reduce(function(x, y) merge(x, y, by = "gene_name", all = TRUE), avg_log2FC_list_Ug)
- merged_df_MalPR <- Reduce(function(x, y) merge(x, y, by = "gene_name", all = TRUE), avg_log2FC_list_MalPR)
- merged_df_UgPR <- Reduce(function(x, y) merge(x, y, by = "gene_name", all = TRUE), avg_log2FC_list_UgPR)
- merged_df_MalUg <- Reduce(function(x, y) merge(x, y, by = "gene_name", all = TRUE), avg_log2FC_list_MalUg)
- # View the final merged dataframe
- head(merged_df_Mal)
- head(merged_df_PR)
- head(merged_df_Ug)
- names <- colnames(merged_df_Mal)
- for (i in names[-1]){
- d<-merged_df_Mal %>% dplyr::select('gene_name',all_of(i))
- names(d)[1] <- '#Gene'
- d<-d[complete.cases(d), ]
- write.table(d, sep='\t',file=paste0(i,".rnk"),col.names=TRUE, quote=FALSE, row.names=FALSE)
- }
- names <- colnames(merged_df_PR)
- for (i in names[-1]){
- d<-merged_df_PR %>% dplyr::select('gene_name',all_of(i))
- names(d)[1] <- '#Gene'
- d<-d[complete.cases(d), ]
- write.table(d, sep='\t',file=paste0(i,".rnk"),col.names=TRUE, quote=FALSE, row.names=FALSE)
- }
- names <- colnames(merged_df_Ug)
- for (i in names[-1]){
- d<-merged_df_Ug %>% dplyr::select('gene_name',all_of(i))
- names(d)[1] <- '#Gene'
- d<-d[complete.cases(d), ]
- write.table(d, sep='\t',file=paste0(i,".rnk"),col.names=TRUE, quote=FALSE, row.names=FALSE)
- }
- names <- colnames(merged_df_MalPR)
- for (i in names[-1]){
- d<-merged_df_MalPR %>% dplyr::select('gene_name',all_of(i))
- names(d)[1] <- '#Gene'
- d<-d[complete.cases(d), ]
- write.table(d, sep='\t',file=paste0(i,".rnk"),col.names=TRUE, quote=FALSE, row.names=FALSE)
- }
- names <- colnames(merged_df_UgPR)
- for (i in names[-1]){
- d<-merged_df_UgPR %>% dplyr::select('gene_name',all_of(i))
- names(d)[1] <- '#Gene'
- d<-d[complete.cases(d), ]
- write.table(d, sep='\t',file=paste0(i,".rnk"),col.names=TRUE, quote=FALSE, row.names=FALSE)
- }
- names <- colnames(merged_df_MalUg)
- for (i in names[-1]){
- d<-merged_df_MalUg %>% dplyr::select('gene_name',all_of(i))
- names(d)[1] <- '#Gene'
- d<-d[complete.cases(d), ]
- write.table(d, sep='\t',file=paste0(i,".rnk"),col.names=TRUE, quote=FALSE, row.names=FALSE)
- }
- ```
- ## Process luria tsv GSEA results to produce a single output file using submit_prerank_4.3.2_v2023.2_caw.sh bash script
- ## Identify files that need to be imported - the basedir will change according to run
- After running the javaGSEA version 4.3.2 bash script with msigDb version 2023.2 (Subramanian et al. 2005), the resulting data files were processed to create a comprehensive and analyzable dataset. The initial step involved identifying and importing the relevant GSEA result files. These files were located in the specified base directory and its subdirectories, matching a specific naming pattern (e.g., "^gsea_.*\.tsv$").
- ```{r}
- base_dir <- "gsea_celltypes/aug01/"
- # Get a list of directories in the base directory
- sub_dirs <- list.dirs(base_dir, recursive = FALSE)
- # Initialize an empty list to store file paths
- file_list <- list()
- # Loop through each sub-directory
- for (sub_dir in sub_dirs) {
- # Get a list of files in the sub-directory that match the pattern
- files <- list.files(path = sub_dir, pattern = "^gsea_.*\\.tsv$", full.names = TRUE)
- # Add the files to the file list
- file_list <- c(file_list, files)
- }
- ```
- ## Import the GSEA data into a list of lists
- ```{r}
- gsea_results.list <- lapply(file_list, read.delim)
- ```
- ## Extract relevant results names from output filenames and rename results dataframes
- To facilitate the analysis, the filenames were processed to extract meaningful names, indicating the specific comparison and whether the results were positive or negative. These names were used to label the corresponding data frames in the list of GSEA results.
- ```{r}
- # Define a function to process each file path
- process_filepath <- function(filepath) {
- # Remove folder info from the front of the file path
- short_filename <- gsub("gsea_celltypes/aug01//", "", filepath)
- # Replace ".rnk." with "_"
- short_filename <- gsub("\\.rnk\\.", "_", short_filename)
- # Add "_pos" if "pos" is in the remainder or "_neg" if "neg" in the remainder
- if (grepl("pos", short_filename)) {
- short_filename <- paste0(short_filename, "_pos")
- } else if (grepl("neg", short_filename)) {
- short_filename <- paste0(short_filename, "_neg")
- }
- short_filename <- gsub("\\.GseaP.*_pos$", "_pos", short_filename)
- short_filename <- gsub("\\.GseaP.*_neg$", "_neg", short_filename)
- return(short_filename)
- }
- # Apply the function to each file path in file_list
- short_filenames <- lapply(file_list, process_filepath)
- # Rename the list of gsea results
- names(gsea_results.list) <- short_filenames
- ```
- ## Extract relevant columns from the dataframes
- Next, each data frame in the list was refined to include only the relevant columns: "NAME" (gene set name), "SIZE" (number of genes in the set), "NES" (normalized enrichment score), and "FDR.q.val" (false discovery rate q-value).
- ```{r}
- # Define the columns to select
- columns_to_select <- c("NAME", "SIZE", "NES", "FDR.q.val")
- # Loop through the list of dataframes
- gsea_results.list <- lapply(gsea_results.list, function(df) {
- # Select the desired columns using dplyr::select
- df_selected <- dplyr::select(df, all_of(columns_to_select))
- # Return the modified dataframe
- return(df_selected)
- })
- ```
- ## Add a comparison column containing the name of each results list
- Additionally, a new column was added to each data frame to indicate the specific comparison it represents, simplifying downstream analysis.
- ```{r}
- # Loop through the list of dataframes
- for (comparison_name in names(gsea_results.list)) {
- new_name <- gsub("_pos$|_neg$", "", comparison_name)
- # Access the dataframe by its name
- df <- gsea_results.list[[comparison_name]]
- # Add a new column containing the comparison name
- df <- df %>% mutate(Comparison = new_name)
- # Update the dataframe in the list
- gsea_results.list[[comparison_name]] <- df
- }
- ```
- ```{r}
- gsea_results.list <- lapply(gsea_results.list, function(x) {
- x$NES <- as.numeric(x$NES)
- return(x)
- })
- ```
- ## Assemble the data into a single output file and export the results
- The GSEA results were then combined into a single data frame. This combined data frame included an additional column "Collection," derived from the comparison names, which identified the gene set collections (e.g., c2cp, h, c5bp).
- ```{r}
- combined_df <- bind_rows(gsea_results.list, .id = "ComparisonFull")
- #Use mutate and str_extract to create the new 'Collection' column
- combined_df <- combined_df %>%
- mutate(Collection = str_extract(Comparison, "[^_]+$")) %>%
- mutate(Comparison = str_remove(Comparison, "_c2cp|_c5bp|_h"))
- ```
- ## Pivoting dataframe
- To ensure unique entries and appropriate aggregation, the maximum "SIZE" value for each gene set name was determined. The data was then summarized to avoid duplicates, averaging the NES and FDR.q.val values for each gene set and comparison. This summarized data was pivoted to create a wide-format table, where NES and FDR.q.val values for different comparisons were represented as separate columns. The final data frame was enhanced by including the maximum "SIZE" values and sorting by the minimum FDR.q.val across all comparisons.
- ```{r}
- # Get the maximum SIZE value for each NAME
- df_size_max <- combined_df %>%
- group_by(NAME) %>%
- summarize(SIZE = max(SIZE, na.rm = TRUE), .groups = 'drop')
- # Ensure no duplicate entries for the same NAME and Comparison
- df_summary <- df %>%
- group_by(NAME, Comparison, Collection) %>%
- summarize(NES = mean(NES, na.rm = TRUE), FDR.q.val = mean(FDR.q.val, na.rm = TRUE), .groups = 'drop')
- # Pivot the dataframe to get NES and FDR.q.val with correct column names
- pivoted_df <- df_summary %>%
- pivot_wider(names_from = Comparison,
- values_from = c(NES, FDR.q.val),
- names_sep = ".") %>%
- rename_with(~ sub("^(.+?)\\.NES$", "\\1.NES", .), starts_with("NES")) %>%
- rename_with(~ sub("^(.+?)\\.FDR.q.val$", "\\1.FDR.q.val", .), starts_with("FDR.q.val"))
- # Combine the SIZE column with the pivoted dataframe
- final_df <- pivoted_df %>%
- left_join(df_size_max, by = "NAME") %>%
- select(NAME, SIZE, Collection, everything()) # Ensure Collection is included and in the right order
- # Identify FDR.q.val columns
- fdr_columns <- grep("^FDR.q.val", names(final_df), value = TRUE)
- # Create MinFDR column with the minimum value of all FDR.q.val columns
- final_df <- final_df %>%
- rowwise() %>%
- mutate(MinFDR = min(c_across(all_of(fdr_columns)), na.rm = TRUE)) %>%
- ungroup()
- # Sort final_df by MinFDR with smallest values at the top
- final_df <- final_df %>%
- arrange(MinFDR)
- head(final_df)
- write.xlsx(final_df, "GSEA_virus_v_mock_celltypes_c2cp_h_c5bp.xlsx")
- ```
- # Volcano plot
- ```{r fig.width=7, fig.height=7}
- library(EnhancedVolcano)
- # Extract the DEG table for "Cluster Neuronal progenitor cells"
- deg_table <- de_results_Ug[["Cluster Neuronal progenitor cells"]]
- # Define the genes to label
- genes_to_label <- c("CANX", "PDIA4", "HSP90B1", "SELENOS", "HERPUD1", "HSPA5", "SEC61B", "XBP1", "GRINA", "SEC63", "MIF", "CLU")
- # Filter for significant genes in the list to label
- genes_to_label_significant <- intersect(genes_to_label, rownames(deg_table)[deg_table$p_val_adj < 0.05])
- # Define custom colors
- keyvals <- rep('grey', nrow(deg_table))
- names(keyvals) <- rownames(deg_table)
- keyvals[deg_table$avg_log2FC > 0.2 & deg_table$p_val_adj < 0.05] <- 'red'
- keyvals[deg_table$avg_log2FC < -0.2 & deg_table$p_val_adj < 0.05] <- 'blue'
- # Create a volcano plot with custom colors
- EnhancedVolcano(
- deg_table,
- lab = rownames(deg_table),
- x = 'avg_log2FC',
- y = 'p_val_adj',
- xlim = c(-0.75, 0.75),
- selectLab = genes_to_label_significant,
- xlab = bquote(~Log[2]~ 'fold change'),
- ylab = bquote(~-Log[10]~ 'p-value adjusted'),
- title = "Uganda VS Mock Neuronal progenitor cells",
- subtitle = bquote(italic(ER_STRESS_RESPONSE)),
- pCutoff = 0.05,
- FCcutoff = 0.20,
- pointSize = 2.0,
- labSize = 4.0,
- colCustom = keyvals,
- legendPosition = 'right',
- legendLabSize = 10,
- legendIconSize = 3.0,
- drawConnectors = TRUE,
- widthConnectors = 0.5,
- colConnectors = 'black',
- gridlines.major = FALSE,
- gridlines.minor = FALSE,
- border = 'full',
- borderWidth = 1.0,
- borderColour = 'black',
- max.overlaps = Inf
- )+
- theme(legend.position="none")
- ```
- # Heatmap of specific gene sets from GSEA
- ```{r}
- library(ComplexHeatmap)
- library(circlize)
- # Convert tbl_df to data.frame
- df <- as.data.frame(GSEA_LeeGeneSets_forheatmap)
- # Set the first column as row names
- rownames(df) <- df[[1]]
- # Remove the first column from the dataframe
- df <- df[ , -1]
- # Filter rows where MinFDR is under 0.05
- df_filtered <- df[df$MinFDR < 0.05, ]
- df_filtered <- subset(df, select = -c(MinFDR))
- df_filtered[is.na(df_filtered)] <- 0
- # Split dataframe into groups of 3 columns
- column_groups <- split(names(df), ceiling(seq_along(names(df)) / 3))
- # Convert the groups into a list of matrices
- list_of_matrices <- lapply(column_groups, function(cols) {
- mat <- as.matrix(df[, cols])
- rownames(mat) <- rownames(df)
- mat
- })
- # Define a function to create heatmaps
- create_heatmap <- function(mat) {
- Heatmap(mat, name = "NES", cluster_rows = FALSE, cluster_columns = FALSE, show_row_names = TRUE, row_names_side = c("left"), row_names_gp = gpar(fontsize = 4), column_names_gp = gpar(fontsize = 4))
- }
- # Create heatmaps for each group
- heatmaps <- lapply(list_of_matrices, create_heatmap)
- # Combine heatmaps side by side using the + operator
- combined_heatmap <- heatmaps[[1]]
- for (i in 2:length(heatmaps)) {
- combined_heatmap <- combined_heatmap + heatmaps[[i]]
- }
- # Draw the combined heatmap
- draw(combined_heatmap, merge_legends = TRUE)
- # # Save as PDF
- # pdf("combined_heatmap.pdf", width = 10, height = 6) # Adjust width and height as needed
- # draw(combined_heatmap, merge_legends = TRUE)
- # dev.off()
- ```
- <<<<<<< HEAD
- # write session info
- Capturing information about the R session helps document your work
- ```{r}
- sessionInfo()
- writeLines(capture.output(sessionInfo()), "220222Geh_sessionInfo.txt")
- ```
020222_Gehrke.Rmd at commit c6e52b0, under MIT · at the source
Overview
- Massachusetts Institute of Technology, Cambridge, Massachusetts, USA
- Whitehead Institute for Biomedical Research, Cambridge, Massachusetts, USA
- Bioinformatics & Computing Core Facility of the Swanson Biotechnology Center, Koch Institute for Integrative Cancer Research, Massachusetts Institute of Technology, Cambridge, Massachusetts, USA
- Massachusetts General Hospital, Boston, Massachusetts, USA
- Harvard Medical School, Boston, Massachusetts, USA
Abstract
Zika virus (ZIKV) has multiple lineages and strains that cause a range of disease severity, underscoring the need to elucidate differential neuropathogenesis mechanisms. Here, we performed systematic, side-by-side comparisons of African, Asian, and American ZIKV lineage infections using cerebral organoids derived from human embryonic stem cells, a relevant human model experimental system. African lineage ZIKV strains, as well as the ancestral Asian Malaysia strain, persistently infected neural progenitor cells, causing apoptosis and severe disruption of ventricular cytoarchitecture. In contrast, contemporary Asian and American lineage viruses were cleared from ventricles, coinciding with low apoptosis and reduced neuropathology. Single-cell RNA sequencing demonstrated upregulated cell-type-specific antiviral signaling during American lineage infections, coinciding with viral clearance from ventricular progenitor cells. Conversely, pathogenic African lineage infections were associated with apoptosis, reduced STAT2 and IFIT1 protein levels, and enhanced activation of stress pathways. African lineage and ancestral Malaysian strain infections induced mitochondrial oxidative stress. Scavenging the reactive oxygen species improved ventricular cytoarchitecture and progenitor survival, but without reducing viral titers. Together, these findings suggest that lineage- and strain-specific host stress responses, rather than viral burden alone, contribute to ZIKV-induced neurodevelopmental damage. An implication of this study is that host-directed therapeutic strategies, used to improve host tolerance to viral infection, may benefit clinical outcomes.
IMPORTANCE: This study provides a systematic comparison of Zika virus (ZIKV) lineage infections in a relevant human model system to correlate mechanisms of host cellular responses with neuropathogenesis. By analyzing African, Asian, and American ZIKV infections side by side in cerebral organoids derived from human embryonic stem cells, we link persistent infection of neural progenitor cells to elevated cellular stress responses and structural disruption of organoid ventricles. Structural disruption was reduced by adding a hydroxyl radical scavenger, but without lowering viral titer. These data are important in strongly suggesting that host responses to viral infection can be of equal or greater importance than viral burden in determining pathogenesis. This study provides mechanistic insight into how closely related viral lineage infections result in divergent outcomes in the developing brain. The data have added importance for suggesting the potential value of host-directed therapeutics to improve ZIKV tolerance without addressing viral titer.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 4 matches between paragraphs and lines of code.
KochInstitute-Bioinformatics/Gehrke_d7_infection
c6e52b0ceece280e5e84e9dc544ee3d855cb5537, 18 February 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
17 files
- BulkRNA-seq_umi/
220516Geh_processing_d7. , R, 1,062 linesRmd - BulkRNA-seq_umi/
Rcode/ , R, 325 linesanalysis_tools.R - BulkRNA-seq_umi/
Rcode/ , R, 719 linescommon.R - BulkRNA-seq_umi/
Rcode/ , R, 1,009 linesdata_formatting_tools.R - BulkRNA-seq_umi/
Rcode/ , R, 17 linesparseRnks.r - BulkRNA-seq_umi/
Rcode/ , R, 783 linesplots.R - BulkRNA-seq_umi/
Rcode/ , R, 8 linesrun_ssGSEA.r - BulkRNA-seq_umi/
Rcode/ , R, 557 linesssGSEAProjection.Library .R - BulkRNA-seq_umi/
gene_sets/ , Shell, 7 linescp_geneSets.sh - BulkRNA-seq_umi/
gsea/ , Shell, 63 linessubmit_prerank_4.3.2_v20 23.2.sh - BulkRNA-seq_umi/
nf-core_rnaseq/ , Shell, 25 lines, 1 matchnf-core_rnaseq_umi.sh - BulkRNA-seq_umi/
singularity_Rstudio_bulk , Shell, 86 linesRNAseq.sh - scRNA-seq/
020222_Gehrke.Rmd , R, 1,145 lines, 3 matches - scRNA-seq/
gsea_celltypes/ , Shell, 63 linessubmit_prerank_4.3.2_v20 23.2_caw.sh - scRNA-seq/
singularity_Rstudio_scRN , Shell, 79 linesAseq.sh - LICENSE, License, 21 lines
- README.md, Text, 101 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 15 scripts, each with its path and the digest of its content;
- 4 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- geo:GSE297797, at NCBI GEO; found in “DATA AVAILABILITY”
Data availability
The GitHub repository for the code used for bulk and single-cell RNAseq analyses can be found at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 12 authors, 7 keywords, 10 MeSH terms, 2 funders, 83 references.
Cite
This paper
Harding, A. T., Zhang, Y., Chen, J.-J., Antonucci, J. M., Richards, A., Leger, V., Whittaker, C. A., Vanrobaeys, Y. S., Agarwal, D., Lungjangwa, T., Jaenisch, R., & Gehrke, L. (2026). Zika virus infections of human stem cell-derived cerebral organoids reveal viral lineage-specific pathogenesis responses. mBio, 17(7), e00863-26. https://
BibTeX
@article{harding2026zika
author = {Harding, Alfred T. and Zhang, Yichen and Chen, Jane-Jane and Antonucci, Jenna M. and Richards, Alexsia and Leger, Valerie and Whittaker, Charles A. and Vanrobaeys, Yann S. and Agarwal, Divyansh and Lungjangwa, Tenzin and Jaenisch, Rudolf and Gehrke, Lee},
title = {{Zika virus infections of human stem cell-derived cerebral organoids reveal viral lineage-specific pathogenesis responses}},
journal = {mBio},
year = {2026},
month = jun,
volume = {17},
number = {7},
pages = {e00863--26},
publisher = {American Society for Microbiology (ASM)},
issn = {2150-7511},
doi = {10.1128/
url = {https://
pmid = {42294680},
pmcid = {PMC13343971}
}
RIS
TY - JOUR
AU - Harding, Alfred T.
AU - Zhang, Yichen
AU - Chen, Jane-Jane
AU - Antonucci, Jenna M.
AU - Richards, Alexsia
AU - Leger, Valerie
AU - Whittaker, Charles A.
AU - Vanrobaeys, Yann S.
AU - Agarwal, Divyansh
AU - Lungjangwa, Tenzin
AU - Jaenisch, Rudolf
AU - Gehrke, Lee
TI - Zika virus infections of human stem cell-derived cerebral organoids reveal viral lineage-specific pathogenesis responses
T2 - mBio
J2 - mBio
PY - 2026
DA - 2026/
VL - 17
IS - 7
SP - e00863
EP - 26
SN - 2150-7511
PB - American Society for Microbiology (ASM)
DO - 10.1128/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1128/
"type": "article-journal",
"title": "Zika virus infections of human stem cell-derived cerebral organoids reveal viral lineage-specific pathogenesis responses",
"container-title": "mBio",
"author": [
{
"family": "Harding",
"given": "Alfred T."
},
{
"family": "Zhang",
"given": "Yichen"
},
{
"family": "Chen",
"given": "Jane-Jane"
},
{
"family": "Antonucci",
"given": "Jenna M."
},
{
"family": "Richards",
"given": "Alexsia"
},
{
"family": "Leger",
"given": "Valerie"
},
{
"family": "Whittaker",
"given": "Charles A."
},
{
"family": "Vanrobaeys",
"given": "Yann S."
},
{
"family": "Agarwal",
"given": "Divyansh"
},
{
"family": "Lungjangwa",
"given": "Tenzin"
},
{
"family": "Jaenisch",
"given": "Rudolf"
},
{
"family": "Gehrke",
"given": "Lee"
}
],
"container-title-short":
"volume": "17",
"issue": "7",
"page": "e00863-26",
"DOI": "10.1128/
"PMID": "42294680",
"PMCID": "PMC13343971",
"ISSN": "2150-7511",
"publisher": "American Society for Microbiology (ASM)",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
15
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41593-026-02367-0 [code]
- A reproducible three-dimensional model of human brain tissue to investigate physiological and disease-associated microglia phenotypes.Journal: Nature neuroscienceIn common: edgeR, DESeq2, circlize, 5 other tools, 4 references
- [2] doi:10.1038/s41593-026-02300-5 [code]
- Integrated single-cell and spatial transcriptomic profiling in ALS uncovers peripheral-to-central immune infiltration and reprogramming.Journal: Nature neuroscienceIn common: edgeR, DESeq2, circlize, 5 other tools, other condition
- [3] doi:10.1016/j.xcrm.2026.102766 [code]
- A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.Journal: Cell reports. MedicineIn common: edgeR, DESeq2, circlize, 5 other tools, other condition
- [4] doi:10.1016/j.isci.2026.115657 [code]
- Integration of machine learning to develop a disulfidptosis model for predicting glioma prognosis, immunotherapy response, and drug.Journal: iScienceIn common: edgeR, DESeq2, circlize, 5 other tools, other condition
- [5] doi:10.1111/adb.70179 [code]
- Transcriptional Response to Chronic Long-Access Fentanyl Self-Administration in Rat Habenula and Amygdala.Journal: Addiction biologyIn common: Nextflow, edgeR, circlize, 4 other tools, other condition
- [6] doi:10.1038/s42003-026-10957-8 [code]
- Brain defence by the extracellular matrix protein Cochlin.Journal: Communications biologyIn common: edgeR, DESeq2, circlize, 5 other tools
- [7] doi:10.1093/braincomms/fcag239 [code]
- Extracellular matrix remodelling in degenerative cervical myelopathy.Journal: Brain communicationsIn common: edgeR, DESeq2, circlize, 5 other tools
- [8] doi:10.1038/s41586-026-10512-9 [code]
- Astrocyte glucocorticoid receptor signalling restricts neuronal plasticity.Journal: NatureIn common: edgeR, DESeq2, circlize, 5 other tools
- [9] doi:10.1016/j.isci.2026.115573 [code]
- Female cortical cellular mosaicism underlies shared MeCP2 and PCB impacted gene pathways.Journal: iScienceIn common: edgeR, DESeq2, circlize, 5 other tools
- [10] doi:10.1002/imt2.70163 [code]
- Spatial multi-omics unveils sphingolipid metabolic reprogramming within the retinal pathological niche.Journal: iMetaIn common: edgeR, DESeq2, circlize, 5 other tools
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 15 scripts, and 4 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:a7bfaa2453fd0ef8…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
