OSCR

Enhancing Maturation of Human Neuromuscular Organoids via Electrical Stimulation.

Code ↔ Paper

18 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 18 matches · 1 of them tie a paragraph to a whole file, not to given lines: a weak match, whose lines are not tinted
  1. [1] § Experimental Section › Functional Characterization of NMOs › NMO Contraction Analysis › Signal Extraction ↔ src/utils/time_series_extraction.py, lines 136–212 · score 0.82 · minimum border length, rotated image, sub region, cropped, angle, axis
  2. [2] § Experimental Section › Functional Characterization of NMOs › NMO Contraction Analysis › Signal Analysis ↔ src/utils/pre_processing.py, the whole file · a weak match · score 0.78 · polynomial interpolation, de trending, pre processing, noise, smoothing, conversion
  3. [3] § Experimental Section › Immunofluorescence Analysis of NMOs › Image Analysis ↔ Image-analysis/Col4A1 or Col5A3 area analysis.ipynb, lines 180–305 · score 0.73 · Col4A1, Col5A3, NMO region, muscle regions, segmented, ilastik
  4. [4] § Experimental Section › Bulk RNA Sequencing › Alignment and Quantification ↔ Transcriptomics-analysis/EPS_NMOs_analysis_v2.Rmd, lines 17–64 · score 0.71 · featureCounts, Homo sapiens, FR, v2, matrix, GRCh38
  5. [5] § Experimental Section › Immunofluorescence Analysis of NMOs › Image Analysis ↔ Image-analysis/PAX7-Ki67 analysis.ipynb, lines 172–315 · score 0.71 · PAX7 masks, muscle region mask, DAPI mask, Ki67, Ilastik, quantified
  6. [6] § Experimental Section › Functional Characterization of NMOs › NMO Contraction Analysis › Signal Analysis ↔ src/2_time_series_analysis.ipynb, lines 120–185 · score 0.70 · de trending, pre processing, polynomial interpolation, smoothing, pixels, contractile
  7. [7] § Results › Transcriptional Analysis Reveals Chronic Electrical Pulse Stimulation‐Induced Maturation of NMOs ↔ Transcriptomics-analysis/EPS_NMOs_analysis_v2.Rmd, lines 932–1012 · score 0.69 · cellular processes, gene expression, muscle contraction, dendrite, myelination, myogenesis
  8. [8] § Experimental Section › Bulk RNA Sequencing › Gene Set Enrichment Analysis ↔ Transcriptomics-analysis/EPS_NMOs_analysis_v2.Rmd, lines 461–484 · score 0.68 · GO Biological Process, EnrichR, Hallmark, pathways, enrichment, genes
  9. [9] § Experimental Section › Immunofluorescence Analysis of NMOs › Image Analysis ↔ Image-analysis/PAX7-Ki67 analysis.ipynb, lines 172–315 · score 0.67 · Ki67 masks, DAPI mask, region mask, segmented, ilastik, quantified
  10. [10] § Experimental Section › Analysis of NMO Size ↔ src/3_border_and_area_computation.ipynb, lines 29–72 · score 0.66 · segmented image, Cellpose, centroid, diameter, border, models
  11. [11] § Results › Dual Role of Chronic Electrical Pulse Stimulation in Skeletal Muscle Maturation ↔ Image-analysis/Col4A1 or Col5A3 area analysis.ipynb, lines 180–305 · score 0.65 · Col4A1, Col5A3, neural region, NMO region, muscle
  12. [12] § Experimental Section › Immunofluorescence Analysis of NMOs › Image Analysis ↔ Image-analysis/MYOD analysis.ipynb, lines 99–129 · score 0.64 · MyoD1, muscle region mask, DAPI mask, Ilastik, signal, filtered
  13. [13] § Results › Transcriptional Analysis Reveals Chronic Electrical Pulse Stimulation‐Induced Maturation of NMOs ↔ Transcriptomics-analysis/EPS_NMOs_analysis_v2.Rmd, lines 932–1012 · score 0.62 · muscle contraction, fold change, chronic EPS, myogenesis, axon, enriched
  14. [14] § Experimental Section › Functional Characterization of NMOs › NMO Contraction Analysis › Signal Extraction ↔ src/utils/time_series_extraction.py, lines 136–212 · score 0.61 · minimum border length, border points, signal, frame, mask, threshold
  15. [15] § Experimental Section › Immunofluorescence Analysis of NMOs › Image Analysis ↔ Image-analysis/BTX & Innervation analysis.ipynb, lines 163–182 · score 0.59 · TUBB3 mask, TUBB3 images, innervation, overlaying, ilastik, NMJ
  16. [16] § Experimental Section › Immunofluorescence Analysis of NMOs › Image Analysis ↔ Image-analysis/SOX1-Ki67 analysis.ipynb, lines 111–126 · score 0.57 · neural region mask, DAPI mask, SOX1, Ki67, ilastik, filtered
  17. [17] § Experimental Section › Immunofluorescence Analysis of NMOs › Image Analysis ↔ Image-analysis/ChAT area analysis.ipynb, lines 140–280 · score 0.55 · ChAT, NMO region, segmented, ilastik, DAPI, quantified
  18. [18] § Experimental Section › Bulk RNA Sequencing › Alignment and Quantification ↔ Transcriptomics-analysis/rna_seq_pipeline_v2.sh, lines 18–33 · score 0.53 · samtools, strandness, HISAT2, genome, v2, rna

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,532 lines · 71 KB · MIT · 4 matches

  1. ---
  2. title: "Analysis Report of EPS effect on NMO transcriptome using bulk RNA-seq"
  3. output:
  4. html_document:
  5. theme: journal
  6. toc: true
  7. toc_float:
  8. collapsed: false
  9. smooth_scroll: false
  10. date: "2025-10-16"
  11. ---
  12. ```{r setup, include=FALSE}
  13. knitr::opts_chunk$set(echo = FALSE,warning = F,message = F)
  14. ```
  15. # Data preprocessing
  16. Qualtiy assessment of the sequenced reads was performed using *FastQC*. The data passed all important quality checks. Accordingly, reads were aligned to the homo sapiens genome assembly GRCh38 using *HISAT2* and aligned reads were then quantified using *featureCounts*. The count matrix was subsequently annotated for downstream analysis and differential gene expression was performed using *DESeq2* and gene set enrichment analysis using *EnrichR*.
  17. ```{r include = F}
  18. # load the required libraries
  19. library(tidyverse)
  20. library(DESeq2)
  21. library(DT)
  22. library(patchwork)
  23. # define important functions
  24. extract_genes <- function(x,pattern) x %>% filter(Term %in% grep(x=x$Term, pattern= pattern,value = T,ignore.case=T)) %>% dplyr::select(Genes) %>% unlist %>% unname %>% str_split(';') %>% unlist %>% unique
  25. expression_colors <- function(a,b) scale_fill_gradientn(colors = c("#2166ac", "#67a9cf", "#fbe7a2", "#f4a582", "#b2182b"),
  26. values = scales::rescale(seq(-a,a,by = b), from = c(-a,a)),
  27. limits = c(-a,a),oob = scales::squish)
  28. # read in the data
  29. rf.summ <- read.delim("/fast/AG_Gouti/BulkRNAseq/output/Anthie_NMOs/A5014/all_samples_featurecounts_RF.txt.summary")
  30. #rf <- rowMeans(rf.summ[,-1])
  31. ## plot of assigned and unassigned counts
  32. rf.summ %>% pivot_longer(names_to = 'sample',values_to= 'read_count', cols = 2:12) %>%
  33. mutate(sample_id = str_extract(sample, "RNA_\\d+")) %>%
  34. ggplot(aes(y= Status, x= read_count))+theme_bw()+geom_col()+facet_wrap(~sample_id)
  35. ## plot of % of assigned and unassigned counts
  36. ism <- cbind(Status = rf.summ[,1], apply(rf.summ[,-1],2,function(x) 100*x/sum(x)) %>% as.data.frame)
  37. ism %>% pivot_longer(names_to = 'sample',values_to= '% of total reads', cols = 2:12) %>%
  38. mutate(sample_id = str_extract(sample, "RNA_\\d+")) %>%
  39. ggplot(aes(y= Status, x= `% of total reads`))+theme_bw()+geom_col()+facet_wrap(~sample_id)
  40. # read the FR featureCounts output
  41. cts <- read.delim('/fast/AG_Gouti/BulkRNAseq/output/Anthie_NMOs/A5014/all_samples_featurecounts_RF.txt',header = T,skip = 1,sep = "\t" )
  42. # remove unnecessary columns
  43. cts <- cts[,-2:-6]
  44. # move gene IDs to become rownames
  45. cts <- cts %>% column_to_rownames('Geneid') %>% as.matrix
  46. # adjust colnames to run IDs
  47. colnames(cts) <- str_extract(colnames(cts), "RNA_\\d+")
  48. # define sample meta data
  49. coldata <- data.frame(sample = paste0('RNA_',c(paste0('0',1:9),10,11)),
  50. plate_no = c('P1648',rep('P1571',5),rep('P1575',5)),
  51. timepoint = c('d30',rep(c('d40','d40','d60','d60','d60'), times = 2)),
  52. line = 'TTNGFP',
  53. group = c('Control',rep(c('Control','EPS1a','Control','EPS1b','EPS2'),times = 2)))
  54. coldata <- coldata %>% column_to_rownames('sample')
  55. ```
  56. ```{r include=FALSE}
  57. # We choose to use RF because of the sequencing chemistry that was used
  58. # rearrange columns of count matrix to match rows of meta data
  59. cts <- cts[,rownames(coldata)]
  60. ncol(cts);nrow(coldata)
  61. identical(rownames(coldata),colnames(cts))
  62. # exclude genes with zero expression in all samples
  63. cts_filtered <- cts[rowSums(cts) > 0,]
  64. dim(cts);dim(cts_filtered)
  65. ```
  66. ```{r include=FALSE}
  67. # Converting eensembl IDs to gene symbols
  68. library(biomaRt)
  69. # Connect to the Ensembl BioMart database for human
  70. mart <- useMart("ensembl", dataset = "hsapiens_gene_ensembl")
  71. # Convert from ensembl IDs to gene symbols
  72. # Retrieve mappings along with an indicator of canonical transcripts
  73. mapping <- getBM(attributes = c("hgnc_symbol", "ensembl_gene_id", "transcript_is_canonical"),
  74. filters = "ensembl_gene_id",
  75. values = rownames(cts_filtered),
  76. mart = mart)
  77. # Filter for canonical isoforms only
  78. canonical_mapping <- mapping %>% filter(transcript_is_canonical == 1)
  79. length(rownames(cts_filtered)); nrow(mapping);nrow(canonical_mapping)
  80. unique(mapping$ensembl_gene_id) %>% length
  81. # search for duplicated Ensembl IDs and resolve them
  82. canonical_mapping[duplicated(canonical_mapping$ensembl_gene_id),]
  83. # search for duplicated symbols and resolve them
  84. canonical_mapping[duplicated(canonical_mapping$hgnc_symbol),]
  85. kar = canonical_mapping$hgnc_symbol[duplicated(canonical_mapping$hgnc_symbol)]
  86. kar = kar[kar != ""]
  87. cat(kar,sep = '\n') # list them
  88. # remove rows 4234, 12582, 27361, 39893
  89. #canonical_mapping <- canonical_mapping[-c(23619, 31588),]
  90. # search for Ensembl IDs without a matched gene symbol
  91. # Those IDs represent novel genes that have yet no symbols
  92. canonical_mapping %>% filter(hgnc_symbol == "") %>% nrow()
  93. # an easier way of mapping ensembl IDs to hgnc symbols
  94. features_metadata <- data.frame(ensembl_gene_id = rownames(cts_filtered)) %>%
  95. left_join(mapping[,-3], by = 'ensembl_gene_id') %>% distinct()
  96. dim(features_metadata)
  97. identical(features_metadata %>% arrange(ensembl_gene_id) %>% dplyr::select(hgnc_symbol,ensembl_gene_id),
  98. canonical_mapping[,-3] %>% arrange(ensembl_gene_id))
  99. # Since both canonical_mapping & features_metadata are identical, we can use them interchangeably
  100. features_metadata[duplicated(features_metadata$ensembl_gene_id),]
  101. features_metadata[duplicated(features_metadata$hgnc_symbol),]
  102. all(features_metadata[duplicated(features_metadata$hgnc_symbol),2] != '')
  103. # idx <- which(features_metadata[duplicated(features_metadata$hgnc_symbol),2] != '')
  104. # ism = features_metadata[duplicated(features_metadata$hgnc_symbol),]
  105. # ism[idx,] %>% View()
  106. ```
  107. # Sample metadata
  108. The following table shows information about the samples included in this dataset. The organoid line, timepoint, plate number and treatment group are specified.
  109. ```{r}
  110. coldata$replicate <- ifelse(coldata$plate_no == 'P1575', 'Rep2','Rep1')
  111. coldata$group_desc <- case_match(coldata$group, "Control" ~ "Control", "EPS1a" ~ "Early-stage EPS", "EPS1b" ~ "Chronic EPS, stable","EPS2" ~ "Chronic EPS, increasing")
  112. coldata %>% datatable(options = list(pageLength = 11))
  113. ```
  114. # Clustering samples
  115. ## Gene expression heatmap
  116. The following heatmap shows the expression values (after undergoing variance stabilizing transformation) of the 2000 most highly variable genes in the dataset. Both samples (columns) and genes (rows) are clustered using hierarchical clustering.
  117. ```{r include = F}
  118. library(pheatmap)
  119. head(coldata)
  120. # create DESeqDataSet
  121. dds <- DESeqDataSetFromMatrix(countData = cts_filtered,
  122. colData = coldata,
  123. design = ~ group + timepoint)
  124. dds <- DESeq(dds)
  125. resultsNames(dds)
  126. vsd <- vst(dds, blind=FALSE)
  127. rld <- rlog(dds, blind=FALSE)
  128. ntd <- normTransform(dds)
  129. # select 2000 most highly expressed genes
  130. #select <- order(rowMeans(counts(dds,normalized=TRUE)), decreasing=TRUE)[1:2000]
  131. # select 2000 most highly variable genes
  132. select <- rowSds(counts(dds,normalized= TRUE)) %>% sort(decreasing = T) %>% head(2000) %>% names()
  133. df <- as.data.frame(colData(dds)[,c("group","timepoint","plate_no")])
  134. pheatmap(assay(ntd)[select,], cluster_rows=FALSE, show_rownames=FALSE,
  135. cluster_cols=TRUE, annotation_col=df)
  136. ```
  137. ```{r}
  138. pheatmap(assay(vsd)[select,], cluster_rows=TRUE, show_rownames=FALSE,
  139. cluster_cols=TRUE, annotation_col=df)
  140. ```
  141. ```{r include = F}
  142. pheatmap(assay(rld)[select,], cluster_rows=FALSE, show_rownames=FALSE,
  143. cluster_cols=TRUE, annotation_col=df)
  144. ```
  145. ## Heatmap of sample-to-sample distances
  146. The following is a heatmap of the sample-to-sample distance matrix where the smaller the distance, the closer the two samples are to each other in terms of their transcriptomic profile. The clustering shows the same pattern as in the expression heatmap above.
  147. ```{r fig.dim=c(700/96,400/96),fig.dpi=300}
  148. sampleDists <- dist(t(assay(vsd)))
  149. library("RColorBrewer")
  150. sampleDistMatrix <- as.matrix(sampleDists)
  151. # rownames(sampleDistMatrix) <- colnames(sampleDistMatrix) <- paste(vsd$timepoint,vsd$plate_no,vsd$group,sep="-")
  152. rownames(sampleDistMatrix) <- paste(vsd$timepoint,vsd$group_desc,vsd$replicate, sep = '_')
  153. colnames(sampleDistMatrix) <- NULL
  154. # colors <- colorRampPalette( rev(brewer.pal(9, "Blues")) )(255)
  155. # pheatmap(sampleDistMatrix,
  156. # clustering_distance_rows=sampleDists,
  157. # clustering_distance_cols=sampleDists,
  158. # col=colors,
  159. # breaks = seq(20,60,length.out = 256))
  160. colors <- colorRampPalette(c("#b2182b", "#f4a582","#fbe7a2"))(255)
  161. #colors <- colorRampPalette(c("#b2182b","#fbe7a2"))(255)
  162. #colors <- viridis::viridis(255) %>% rev
  163. plt <- pheatmap(sampleDistMatrix,
  164. clustering_distance_rows=sampleDists,
  165. clustering_distance_cols=sampleDists,
  166. col=colors,
  167. breaks = seq(20,60,length.out = 256))
  168. plt
  169. # ism = as.vector(sampleDistMatrix)
  170. # min(ism[ism!=0])
  171. # mat_log <- log10(sampleDistMatrix + 1)
  172. #
  173. # # Define log-spaced breaks (using the log-transformed min and max)
  174. # log_breaks <- seq(min(mat_log), max(mat_log), length.out = 256)
  175. #
  176. # # Now map these back to the original (non-log) scale to set the `breaks` param
  177. # orig_breaks <- 10^log_breaks
  178. ```
  179. ## Principal component analysis
  180. ```{r include = F}
  181. plotPCA(vsd, intgroup=c("timepoint", "plate_no","group"))+theme_bw()
  182. ```
  183. The following PCA plot shows the different samples annotated by timepoint and plate number. The first PC nicely captures the variation along the timepoints from d30 through d40 to d60. This shows that the timepoint is the single most important determinant of the transcriptomic status.
  184. ```{r fig.dim=c(6.25,4.2)}
  185. pcaData <- plotPCA(vsd, intgroup=c("timepoint", "plate_no","group"), returnData=TRUE)
  186. percentVar <- round(100 * attr(pcaData, "percentVar"))
  187. ggplot(pcaData, aes(PC1, PC2, color= timepoint, shape= plate_no)) +
  188. geom_point(size=3) + theme_bw()+
  189. xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  190. ylab(paste0("PC2: ",percentVar[2],"% variance")) #+
  191. #coord_fixed()
  192. ```
  193. The following PCA plot shows the different samples annotated by group and plate number.
  194. ```{r fig.dim=c(6.25,4.2)}
  195. pcaData <- plotPCA(vsd, intgroup=c("timepoint", "plate_no","group"), returnData=TRUE)
  196. ggplot(pcaData, aes(PC1, PC2, color= group.1, shape= plate_no)) +
  197. geom_point(size=3) + theme_bw()+
  198. scale_color_manual(values = c('darkolivegreen4', 'gold','tomato','dodgerblue'))+
  199. xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  200. ylab(paste0("PC2: ",percentVar[2],"% variance")) #+
  201. #coord_fixed()
  202. ```
  203. The following PCA plot shows the different samples annotated by timepoint, group and plate number.
  204. ```{r fig.dim=c(7.8,4.2)}
  205. pcaData <- plotPCA(vsd, intgroup=c("timepoint", "plate_no","group_desc"), returnData=TRUE)
  206. pcaData$group_desc <- factor(pcaData$group_desc, levels = c('Control','Early-stage EPS','Chronic EPS, stable','Chronic EPS, increasing'))
  207. #pcaData$plate_no <- factor(pcaData$plate_no, levels = c('P1648','P1571','P1575'))
  208. plt <- ggplot(pcaData, aes(PC1, PC2, color= group_desc, shape= plate_no, label = timepoint)) +
  209. geom_point(size=3) + theme_bw()+
  210. ggrepel::geom_text_repel(size =5)+
  211. scale_color_manual(values = c('darkolivegreen4', 'gold','tomato','dodgerblue'))+
  212. labs(color = 'Group')+
  213. xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  214. ylab(paste0("PC2: ",percentVar[2],"% variance")) +
  215. theme(axis.text = element_text(size = 12, color = 'black'),
  216. axis.title = element_text(size = 14),
  217. legend.text = element_text(size = 12),
  218. legend.title = element_text(size = 14))
  219. #coord_fixed()
  220. plt
  221. ```
  222. # Differential gene expression
  223. Differential gene expression analysis was performed using DESeq2 where gene expression was modeled as a function of the group (EPS vs Control) and the plate number (P1575 vs P1571) to take into account the variability between the two replicates. A 3rd replicate is recommended to improve the statistical robustness of this analysis.
  224. ## D40 comparisons (EPS1a vs Control)
  225. ```{r include = F}
  226. my.coldata <- coldata %>% filter(timepoint == 'd40')
  227. my.counts <- cts_filtered[,rownames(my.coldata)]
  228. # define the test variable and its reference level
  229. my.coldata$group <- factor(my.coldata$group, levels = c('Control','EPS1a'))
  230. my.coldata$plate_no <- factor(my.coldata$plate_no, levels = c('P1571','P1575'))
  231. table(rownames(my.coldata),my.coldata$group)
  232. table(rownames(my.coldata),my.coldata$plate_no)
  233. # create DESeqDataSet
  234. dds <- DESeqDataSetFromMatrix(countData = my.counts,
  235. colData = my.coldata,
  236. design = ~ group + plate_no)
  237. # pre-filter low-count genes
  238. smallestGroupSize <- 2
  239. keep <- rowSums(counts(dds) >= 10) >= smallestGroupSize
  240. dds <- dds[keep,]
  241. # run DGE analysis
  242. dds <- DESeq(dds)
  243. resultsNames(dds)
  244. res1a <- results(dds,name = "group_EPS1a_vs_Control") %>% as.data.frame
  245. #res <- results(dds,name = "plate_no_P1575_vs_P1571") %>% as.data.frame
  246. #res
  247. # apply Log fold change shrinkage for visualization and ranking
  248. #resLFC <- lfcShrink(dds, coef= "group_EPS1a_vs_Control", type="apeglm") %>% as.data.frame
  249. #resLFC <- lfcShrink(dds, coef= "plate_no_P1575_vs_P1571", type="apeglm") %>% as.data.frame
  250. #resLFC
  251. # inspect results with and without LFC shrinkage
  252. res1a %>% filter(padj < 0.05) %>% nrow
  253. res1a %>% filter(padj < 0.05 & log2FoldChange > 0) %>% nrow
  254. res1a %>% filter(padj < 0.05 & log2FoldChange < 0) %>% nrow
  255. # resLFC %>% filter(padj < 0.05) %>% nrow
  256. # resLFC %>% filter(padj < 0.05 & log2FoldChange > 0) %>% nrow
  257. # resLFC %>% filter(padj < 0.05 & log2FoldChange < 0) %>% nrow
  258. #View(res)
  259. ```
  260. The following table shows the 1000 most significant DEGs arranged by P-value.
  261. ```{r}
  262. res1a <- res1a %>% rownames_to_column('ensembl_gene_id')
  263. res1a <- left_join(res1a,canonical_mapping[,c('ensembl_gene_id','hgnc_symbol')], by = 'ensembl_gene_id')
  264. res1a <- res1a[,colnames(res1a)[c(1,8,2:7)]]
  265. res1a %>% arrange(pvalue) %>% head(1000) %>% datatable(options = list(pageLength= 10))
  266. ```
  267. ```{r}
  268. dn <- res1a %>% filter(padj < 0.05 & log2FoldChange < 0) %>% mutate(hgnc_symbol = ifelse(hgnc_symbol == "","Novel_Gene",hgnc_symbol)) %>% mutate(id_symbol = paste(ensembl_gene_id,hgnc_symbol,sep ='_')) %>% dplyr::select(id_symbol) %>% unlist %>% unname
  269. up <- res1a %>% filter(padj < 0.05 & log2FoldChange > 0) %>% mutate(hgnc_symbol = ifelse(hgnc_symbol == "","Novel_Gene",hgnc_symbol)) %>% mutate(id_symbol = paste(ensembl_gene_id,hgnc_symbol,sep ='_')) %>% dplyr::select(id_symbol) %>% unlist %>% unname
  270. ```
  271. - 4 genes were significantly upregulated at an FDR-adjusted P-value less than 0.05, namely: `r up`
  272. - 4 genes were downregulated at the adjusted P-value threshold, namely: `r dn`
  273. ## D60 comparisons
  274. ```{r include=FALSE}
  275. my.coldata <- coldata %>% filter(timepoint == 'd60')
  276. my.counts <- cts_filtered[,rownames(my.coldata)]
  277. # define the test variable and its reference level
  278. my.coldata$group <- factor(my.coldata$group, levels = c('Control','EPS1b','EPS2'))
  279. my.coldata$plate_no <- factor(my.coldata$plate_no, levels = c('P1571','P1575'))
  280. table(rownames(my.coldata),my.coldata$group)
  281. table(rownames(my.coldata),my.coldata$plate_no)
  282. # create DESeqDataSet
  283. dds <- DESeqDataSetFromMatrix(countData = my.counts,
  284. colData = my.coldata,
  285. design = ~ group + plate_no)
  286. # pre-filter low-count genes
  287. smallestGroupSize <- 2
  288. keep <- rowSums(counts(dds) >= 10) >= smallestGroupSize
  289. dds <- dds[keep,]
  290. # run DGE analysis
  291. dds <- DESeq(dds)
  292. resultsNames(dds)
  293. ```
  294. ### EPS1b vs Control
  295. ```{r include = F}
  296. res1b <- results(dds,name = "group_EPS1b_vs_Control") %>% as.data.frame()
  297. #res2 <- results(dds,name = "group_EPS2_vs_Control") %>% as.data.frame()
  298. #res
  299. # apply Log fold change shrinkage for visualization and ranking
  300. #resLFC <- lfcShrink(dds, coef= "group_EPS1b_vs_Control", type="apeglm") %>% as.data.frame()
  301. #resLFC <- lfcShrink(dds, coef= "group_EPS2_vs_Control", type="apeglm") %>% as.data.frame()
  302. #resLFC
  303. # inspect results with and without LFC shrinkage
  304. res1b %>% filter(padj < 0.05) %>% nrow
  305. res1b %>% filter(padj < 0.05 & log2FoldChange > 0) %>% nrow
  306. res1b %>% filter(padj < 0.05 & log2FoldChange < 0) %>% nrow
  307. # resLFC %>% filter(padj < 0.05) %>% nrow
  308. # resLFC %>% filter(padj < 0.05 & log2FoldChange > 0) %>% nrow
  309. # resLFC %>% filter(padj < 0.05 & log2FoldChange < 0) %>% nrow
  310. #View(res)
  311. #sig.genes <- res %>% filter(padj < 0.05 & log2FoldChange > 0) %>% rownames
  312. ```
  313. The following table shows the 1000 most significant DEGs arranged by P-value.
  314. ```{r}
  315. res1b <- res1b %>% rownames_to_column('ensembl_gene_id')
  316. res1b <- left_join(res1b,canonical_mapping[,c('ensembl_gene_id','hgnc_symbol')], by = 'ensembl_gene_id')
  317. res1b <- res1b[,colnames(res1b)[c(1,8,2:7)]]
  318. res1b %>% arrange(pvalue) %>% head(1000) %>% datatable(options = list(pageLength= 10))
  319. ```
  320. - 46 genes were significantly upregulated and no genes significantly downregulated at an FDR-adjust P-value less than 0.05. The upregulated genes are listed in the following table.
  321. ```{r}
  322. #gene_symbols %>% datatable(options = list(pageLength = 10))
  323. res1b %>% filter(padj < 0.05 & log2FoldChange > 0) %>% datatable(options = list(pageLength = 10))
  324. ```
  325. ### EPS2 vs Control
  326. ```{r include=FALSE}
  327. res2 <- results(dds,name = "group_EPS2_vs_Control") %>% as.data.frame()
  328. # apply Log fold change shrinkage for visualization and ranking
  329. #resLFC <- lfcShrink(dds, coef= "group_EPS2_vs_Control", type="apeglm") %>% as.data.frame()
  330. # inspect results with and without LFC shrinkage
  331. res2 %>% filter(padj < 0.05) %>% nrow
  332. res2 %>% filter(padj < 0.05 & log2FoldChange > 0) %>% nrow
  333. res2 %>% filter(padj < 0.05 & log2FoldChange < 0) %>% nrow
  334. # resLFC %>% filter(padj < 0.05) %>% nrow
  335. # resLFC %>% filter(padj < 0.05 & log2FoldChange > 0) %>% nrow
  336. # resLFC %>% filter(padj < 0.05 & log2FoldChange < 0) %>% nrow
  337. up <- res2 %>% filter(padj < 0.05 & log2FoldChange > 0) %>% rownames
  338. dn <- res2 %>% filter(padj < 0.05 & log2FoldChange < 0) %>% rownames
  339. ```
  340. The following table shows the 1000 most significant DEGs arranged by P-value.
  341. ```{r}
  342. res2 <- res2 %>% rownames_to_column('ensembl_gene_id')
  343. res2 <- left_join(res2,canonical_mapping[,c('ensembl_gene_id','hgnc_symbol')], by = 'ensembl_gene_id')
  344. res2 <- res2[,colnames(res2)[c(1,8,2:7)]]
  345. res2 %>% arrange(pvalue) %>% head(1000) %>% datatable(options = list(pageLength= 10))
  346. ```
  347. - A total of 52 genes were differentially expressed at an FDR-adjusted P-value less than 0.05; 48 of which were significantly upregulated and 4 were significantly downregulated. Those are listed in the following table.
  348. ```{r}
  349. #gene_symbols2 %>% datatable(options = list(pageLength = 10))
  350. res2 %>% filter(padj < 0.05) %>% datatable(options = list(pageLength = 10))
  351. ```
  352. # Functional enrichment analysis
  353. ## EnrichR
  354. ```{r include=FALSE}
  355. # Functional enrichment
  356. library(enrichR)
  357. websiteLive <- getOption("enrichR.live")
  358. if (websiteLive) {
  359. listEnrichrSites()
  360. setEnrichrSite("Enrichr") # Human genes
  361. }
  362. # if (websiteLive) {
  363. # dbs <- listEnrichrDbs()
  364. # head(dbs)
  365. # }
  366. dbs <- c('MSigDB_Hallmark_2020','GO_Biological_Process_2023','GO_Cellular_Component_2023','GO_Molecular_Function_2023',
  367. 'WikiPathways_2024_Human','Reactome_Pathways_2024','KEGG_2021_Human','Elsevier_Pathway_Collection',
  368. 'OMIM_Disease','OMIM_Expanded','Jensen_DISEASES','DisGeNET')
  369. ```
  370. Gene set or functional enrichment analysis was performed using the statistical tests available in *EnrichR*. Gene sets of 12 different databases were tested, namely:
  371. ```{r}
  372. cat(dbs,sep = '\n')
  373. ```
  374. Only significant DEGs with an FDR-adjusted P-value less than 0.05 were tested for enrichment.
  375. ### D60 comparisons
  376. #### EPS1b vs Control
  377. ```{r include = F}
  378. g = res1b %>% filter(padj < 0.05 & log2FoldChange > 0) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  379. if (websiteLive) {
  380. #enriched <- enrichr(gene_symbols$hgnc_symbol, dbs)
  381. enriched <- enrichr(g, dbs)
  382. }
  383. enriched.df <- list_rbind(enriched[sapply(enriched, nrow) != 0], names_to = 'database')
  384. ```
  385. The following table shows the 1000 most significantly enriched gene sets arranged by P-value. These represent functions that are upregulated in EPS1b vs control.
  386. ```{r}
  387. enriched.df %>% arrange(P.value) %>% head(1000) %>%
  388. datatable(options = list(pageLength= 10))
  389. ```
  390. #### EPS2 vs Control
  391. ```{r include = F}
  392. # up.symbols <- gene_symbols2 %>% filter(ensembl_gene_id %in% up)%>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  393. g = res2 %>% filter(padj < 0.05 & log2FoldChange > 0) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  394. if (websiteLive) {
  395. #enriched <- enrichr(up.symbols, dbs)
  396. enriched <- enrichr(g, dbs)
  397. }
  398. enriched.df <- list_rbind(enriched[sapply(enriched, nrow) != 0], names_to = 'database')
  399. ```
  400. The following table shows the 1000 most significantly enriched gene sets arranged by P-value. These represent functions that are upregulated in EPS2 vs control.
  401. ```{r}
  402. enriched.df %>% arrange(P.value) %>% head(1000) %>%
  403. datatable(options = list(pageLength= 10))
  404. ```
  405. ## FGSEA
  406. In contract to *EnrichR*, *FGSEA* performs functional enrichment using a ranked genome-wide gene list where genes are ranked from the most significantly upregulated to the most significantly downregulated or vice versa based on log2 fold change or some measure of statistical significance. This approach does not require the use of thresholds/cutoffs for defining statistically significant genes prior to the enrichment analysis.
  407. ```{r include = FALSE}
  408. library(fgsea)
  409. # load gene sets
  410. h <- rjson::fromJSON(file = '/fast/AG_Gouti/snRNAseq/MSigDB_GeneSets/h.all.v2025.1.Hs.json.txt')
  411. go.bp <- rjson::fromJSON(file = '/fast/AG_Gouti/snRNAseq/MSigDB_GeneSets/c5.go.bp.v2025.1.Hs.json.txt')
  412. h.gs <- lapply(h, function(x) x$geneSymbols)
  413. go.bp.gs <- lapply(go.bp, function(x) x$geneSymbols)
  414. gs <- c(h.gs,go.bp.gs)
  415. ```
  416. ### D40 comparisons (EPS1a vs Control)
  417. ```{r include=FALSE}
  418. dim(res1a); dim(res1a[complete.cases(res1a),])
  419. df <- res1a[complete.cases(res1a),] %>% filter(hgnc_symbol != '')
  420. sum(duplicated(df$hgnc_symbol))
  421. df$hgnc_symbol[duplicated(df$hgnc_symbol)]
  422. #df %>% filter(hgnc_symbol %in% df$hgnc_symbol[duplicated(df$hgnc_symbol)]) %>% View()
  423. # df <- res1a[complete.cases(res1a),] %>% rownames_to_column("ensembl_gene_id") %>% left_join(mapping[,c("ensembl_gene_id","hgnc_symbol")], by = 'ensembl_gene_id') %>% filter(hgnc_symbol != '')
  424. # -log10(min(df$pvalue[df$pvalue > 0]) + 1e-10)
  425. # df <- df %>% mutate(metric = sign(log2FoldChange) * -log10(pvalue + 1e-10)) %>%
  426. # arrange(metric) %>% dplyr::select(hgnc_symbol,metric)
  427. # ranks <- df$metric; names(ranks) <- df$hgnc_symbol
  428. # Apply a function to select the ID with more transcripts
  429. ls <- split(x = df, f = df$hgnc_symbol)
  430. df <- lapply(ls, function(x){
  431. data.frame(stat = x$stat[which.max(x$baseMean)])
  432. }) %>% list_rbind(names_to = 'hgnc_symbol') %>% arrange(stat)
  433. ranks <- df$stat; names(ranks) <- df$hgnc_symbol
  434. fgseaRes <- fgsea(pathways = gs,
  435. stats = ranks,
  436. eps = 0.0,
  437. nPermSimple = 50000,
  438. minSize = 15,
  439. maxSize = 500)
  440. ```
  441. The following table displays the gene sets significantly enriched at an FDR-adjusted P-value < 0.05 and arranged by P-value.
  442. ```{r}
  443. fgseaRes %>% filter(padj < 0.05) %>% arrange(pval) %>% datatable(options = list(pageLength= 10))
  444. ```
  445. ### D60 comparisons
  446. #### EPS1b vs Control
  447. ```{r include=FALSE}
  448. dim(res1b); dim(res1b[complete.cases(res1b),])
  449. df <- res1b[complete.cases(res1b),] %>% filter(hgnc_symbol != '')
  450. sum(duplicated(df$hgnc_symbol))
  451. df$hgnc_symbol[duplicated(df$hgnc_symbol)]
  452. # -log10(min(df$pvalue[df$pvalue > 0]) + 1e-10)
  453. # df <- df %>% mutate(metric = sign(log2FoldChange) * -log10(pvalue + 1e-10)) %>%
  454. # arrange(metric) %>% dplyr::select(hgnc_symbol,metric)
  455. # ranks <- df$metric; names(ranks) <- df$hgnc_symbol
  456. # Apply a function to select the ID with more transcripts
  457. ls <- split(x = df, f = df$hgnc_symbol)
  458. df <- lapply(ls, function(x){
  459. data.frame(stat = x$stat[which.max(x$baseMean)])
  460. }) %>% list_rbind(names_to = 'hgnc_symbol') %>% arrange(stat)
  461. ranks <- df$stat; names(ranks) <- df$hgnc_symbol
  462. fgseaRes <- fgsea(pathways = gs,
  463. stats = ranks,
  464. eps = 0.0,
  465. nPermSimple = 50000,
  466. minSize = 15,
  467. maxSize = 500)
  468. ```
  469. The following table displays the gene sets significantly enriched at an FDR-adjusted P-value < 0.05 and arranged by P-value.
  470. ```{r}
  471. fgseaRes %>% filter(padj < 0.05) %>% arrange(pval) %>% datatable(options = list(pageLength= 10))
  472. ```
  473. #### EPS2 vs Control
  474. ```{r include=FALSE}
  475. dim(res2); dim(res2[complete.cases(res2),])
  476. df <- res2[complete.cases(res2),] %>% filter(hgnc_symbol != '')
  477. sum(duplicated(df$hgnc_symbol))
  478. df$hgnc_symbol[duplicated(df$hgnc_symbol)]
  479. # -log10(min(df$pvalue[df$pvalue > 0]) + 1e-10)
  480. # df <- df %>% mutate(metric = sign(log2FoldChange) * -log10(pvalue + 1e-10)) %>%
  481. # arrange(metric) %>% dplyr::select(hgnc_symbol,metric)
  482. # ranks <- df$metric; names(ranks) <- df$hgnc_symbol
  483. # Apply a function to select the ID with more transcripts
  484. ls <- split(x = df, f = df$hgnc_symbol)
  485. df <- lapply(ls, function(x){
  486. data.frame(stat = x$stat[which.max(x$baseMean)])
  487. }) %>% list_rbind(names_to = 'hgnc_symbol') %>% arrange(stat)
  488. ranks <- df$stat; names(ranks) <- df$hgnc_symbol
  489. fgseaRes <- fgsea(pathways = gs,
  490. stats = ranks,
  491. eps = 0.0,
  492. nPermSimple = 50000,
  493. minSize = 15,
  494. maxSize = 500)
  495. ```
  496. The following table displays the gene sets significantly enriched at an FDR-adjusted P-value < 0.05 and arranged by P-value.
  497. ```{r}
  498. fgseaRes %>% filter(padj < 0.05) %>% arrange(pval) %>% datatable(options = list(pageLength= 10))
  499. ```
  500. # Visualization of signifcant genes
  501. ## D60 comparisons
  502. ### Bar graphs
  503. DEGs with an adjusted P-value < 0.05 are visualized in a descending order of statistical significance.
  504. ```{r include = F}
  505. # create DESeqDataSet
  506. dds <- DESeqDataSetFromMatrix(countData = cts_filtered,
  507. colData = coldata,
  508. design = ~ group + timepoint)
  509. #dds <- DESeq(dds)
  510. #resultsNames(dds)
  511. # Visualize genes of interest
  512. ntd <- normTransform(dds)
  513. norm.cts <- assay(ntd)
  514. # library(vsn)
  515. # meanSdPlot(assay(ntd))
  516. #head(assay(ntd),3)
  517. #head(my.counts,3)
  518. p = 0.05 ; fc = 1
  519. # define significant DEGs
  520. up1b = res1b %>% filter(padj < p & log2FoldChange > log2(fc)) %>% arrange(pvalue) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  521. dn1b = res1b %>% filter(padj < p & log2FoldChange < -log2(fc)) %>% arrange(pvalue) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  522. up2 = res2 %>% filter(padj < p & log2FoldChange > log2(fc)) %>% arrange(pvalue) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  523. dn2 = res2 %>% filter(padj < p & log2FoldChange < -log2(fc)) %>% arrange(pvalue) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  524. ```
  525. #### Genes significantly upregulated by EPS1b
  526. ```{r fig.dim= c(1000/96,700/96), fig.dpi= 300}
  527. g = up1b
  528. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  529. #df <- cbind(coldata,norm.cts[rownames(norm.cts) %in% g,] %>% t)
  530. df <- cbind(coldata,norm.cts[g,] %>% t)
  531. df <- df %>% filter(timepoint == 'd60' & group != 'EPS2') %>%
  532. tidyr::pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 7:(6+length(g))) %>%
  533. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  534. # ism <- res1b %>% filter(padj < 0.05) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  535. # identical(unique(df$hgnc_symbol), ism)
  536. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  537. df %>% ggplot(aes(x = group, y = exp, fill= plate_no))+geom_col(width = 0.45, position = position_dodge())+theme_bw()+facet_wrap(~hgnc_symbol)+
  538. labs(x = '', y = 'Normalized expression')
  539. ```
  540. #### Genes significantly upregulated by EPS2
  541. ```{r fig.dim= c(1000/96,700/96), fig.dpi= 300}
  542. g = up2
  543. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  544. df <- cbind(coldata,norm.cts[g,] %>% t)
  545. df <- df %>% filter(timepoint == 'd60' & group != 'EPS1b') %>%
  546. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 7:(6+length(g))) %>%
  547. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  548. # ism <- res2 %>% filter(padj < 0.05 & log2FoldChange > 0) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  549. # identical(unique(df$hgnc_symbol), ism)
  550. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  551. df %>% ggplot(aes(x = group, y = exp, fill= plate_no))+geom_col(width = 0.45, position = position_dodge())+theme_bw()+facet_wrap(~hgnc_symbol)+
  552. labs(x = '', y = 'Normalized expression')
  553. ```
  554. #### Genes significantly upregulated by both EPS1b & EPS2
  555. ```{r fig.dim=c(1100/96,700/96), fig.dpi=300}
  556. g = intersect(up1b,up2)
  557. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  558. a <- res1b %>% filter(ensembl_gene_id %in% g) %>% dplyr::select(hgnc_symbol,stat)
  559. b <- res2 %>% filter(ensembl_gene_id %in% g) %>% dplyr::select(hgnc_symbol,stat)
  560. g2 <- inner_join(a,b, by = "hgnc_symbol") %>% mutate(mean.stat = (stat.x + stat.y)/2) %>% arrange(desc(mean.stat)) %>%
  561. dplyr::select(hgnc_symbol) %>% unlist %>% unname
  562. df <- cbind(coldata,norm.cts[g,] %>% t)
  563. # head(df)
  564. # df %>% rownames_to_column("sample") %>%
  565. # pivot_longer(names_to = "gene",values_to = "exp",cols = 7:48) %>%
  566. # ggplot(aes(x = sample, y = exp, fill= group))+geom_col(width = 0.6)+theme_bw()+facet_wrap(~gene)
  567. # df %>% rownames_to_column("sample") %>%
  568. # pivot_longer(names_to = "gene",values_to = "exp",cols = 6:9) %>%
  569. # ggplot(aes(x = group, y = exp,color = plate_no, group = plate_no))+geom_point(size = 1.5)+geom_line()+theme_bw()+facet_wrap(~gene)
  570. df <- df %>% filter(timepoint == 'd60') %>%
  571. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 7:(6+length(g))) %>%
  572. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  573. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = g2)
  574. df %>% ggplot(aes(x = group, y = exp, fill= plate_no))+geom_col(width = 0.45, position = position_dodge())+theme_bw()+facet_wrap(~hgnc_symbol)+
  575. labs(x = '', y = 'Normalized expression')#+
  576. #theme(axis.text.x = element_text(angle = 30, vjust = 0.7))
  577. ```
  578. #### Genes significantly downregulated by EPS2
  579. ```{r fig.dim=c(700/96, 240/96), fig.dpi=300}
  580. g = dn2
  581. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  582. df <- cbind(coldata,norm.cts[g,] %>% t)
  583. df <- df %>% filter(timepoint == 'd60' & group != 'EPS1b') %>%
  584. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 7:(6+length(g))) %>%
  585. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  586. # ism <- res2 %>% filter(padj < 0.05 & log2FoldChange < 0) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  587. # identical(unique(df$hgnc_symbol), ism)
  588. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  589. df %>% ggplot(aes(x = group, y = exp, fill= plate_no))+geom_col(width = 0.45, position = position_dodge())+theme_bw()+facet_wrap(~hgnc_symbol)+
  590. labs(x = '', y = 'Normalized expression')+
  591. theme(axis.text.x = element_text(angle = 0, vjust = 0.7))
  592. ```
  593. ### Time course plots
  594. #### Genes significantly upregulated by EPS1b
  595. ```{r fig.dim= c(1200/96,750/96), fig.dpi= 300}
  596. g = up1b
  597. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  598. #df <- cbind(coldata,norm.cts[rownames(norm.cts) %in% g,] %>% t)
  599. df <- cbind(coldata,norm.cts[g,] %>% t)
  600. df <- df %>% rownames_to_column('sample') %>%
  601. filter(group != 'EPS2') %>%
  602. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g))) %>%
  603. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  604. # ism <- res1b %>% filter(padj < 0.05) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  605. # identical(unique(df$hgnc_symbol), ism)
  606. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  607. #df$group <- factor(df$group, levels = c('Control','EPS1a','EPS1b','EPS2'))
  608. #df$group2 <- case_match(df$group, c('EPS1a','EPS1b') ~ 'EPS', .default = df$group)
  609. df$group2 <- ifelse(df$group == 'Control','Control','EPS stable')
  610. #df$group3 <- paste(df$group2,df$plate_no, sep = '_')
  611. df %>% ggplot(aes(x = timepoint, y = exp, color = group2, shape = plate_no))+
  612. #geom_col(width = 0.5,position = position_dodge())+
  613. geom_point()+
  614. geom_line(data = df %>% filter(plate_no != 'P1575' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  615. geom_line(data = df %>% filter(plate_no != 'P1571' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  616. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_03','RNA_05')), aes(x = timepoint, y = exp, group = 1), color = 'tomato')+
  617. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_08','RNA_10')), aes(x = timepoint, y = exp, group = 1), color = 'tomato')+
  618. theme_bw()+facet_wrap(~hgnc_symbol,scales = 'free_y')+
  619. #scale_color_manual(values = c('darkolivegreen4', 'tomato','dodgerblue','violet'))+
  620. scale_color_manual(values = c('darkolivegreen4', 'tomato'))+
  621. labs(x = '', y = 'Normalized expression')
  622. ```
  623. #### Genes significantly upregulated by EPS2
  624. ```{r fig.dim= c(1300/96,750/96), fig.dpi= 300}
  625. g = up2
  626. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  627. #df <- cbind(coldata,norm.cts[rownames(norm.cts) %in% g,] %>% t)
  628. df <- cbind(coldata,norm.cts[g,] %>% t)
  629. df <- df %>% rownames_to_column('sample') %>%
  630. filter(group != 'EPS1b') %>%
  631. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g))) %>%
  632. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  633. # ism <- res1b %>% filter(padj < 0.05) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  634. # identical(unique(df$hgnc_symbol), ism)
  635. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  636. #df$group <- factor(df$group, levels = c('Control','EPS1a','EPS1b','EPS2'))
  637. df$group2 <- ifelse(df$group == 'Control','Control','EPS stable/increasing')
  638. #df$group3 <- paste(df$group2,df$plate_no, sep = '_')
  639. df %>% ggplot(aes(x = timepoint, y = exp, color = group2, shape = plate_no))+
  640. #geom_col(width = 0.5,position = position_dodge())+
  641. geom_point()+
  642. geom_line(data = df %>% filter(plate_no != 'P1575' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  643. geom_line(data = df %>% filter(plate_no != 'P1571' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  644. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_03','RNA_06')) , aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  645. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_08','RNA_11')), aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  646. theme_bw()+facet_wrap(~hgnc_symbol,scales = 'free_y')+
  647. #scale_color_manual(values = c('darkolivegreen4', 'tomato','dodgerblue','violet'))+
  648. scale_color_manual(values = c('darkolivegreen4', 'dodgerblue'))+
  649. labs(x = '', y = 'Normalized expression')
  650. ```
  651. #### Genes significantly upregulated by both EPS1b & EPS2
  652. ```{r fig.dim=c(1150/96,700/96), fig.dpi=300}
  653. g = intersect(up1b,up2)
  654. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  655. a <- res1b %>% filter(ensembl_gene_id %in% g) %>% dplyr::select(hgnc_symbol,stat)
  656. b <- res2 %>% filter(ensembl_gene_id %in% g) %>% dplyr::select(hgnc_symbol,stat)
  657. g2 <- inner_join(a,b, by = "hgnc_symbol") %>% mutate(mean.stat = (stat.x + stat.y)/2) %>% arrange(desc(mean.stat)) %>%
  658. dplyr::select(hgnc_symbol) %>% unlist %>% unname
  659. df <- cbind(coldata,norm.cts[g,] %>% t)
  660. df <- df %>% rownames_to_column('sample') %>%
  661. #filter(group != 'EPS1b') %>%
  662. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g))) %>%
  663. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  664. # ism <- res1b %>% filter(padj < 0.05) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  665. # identical(unique(df$hgnc_symbol), ism)
  666. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = g2)
  667. df$group <- factor(df$group, levels = c('Control','EPS1a','EPS1b','EPS2'))
  668. #df$group2 <- case_match(df$group, c('EPS1a','EPS1b') ~ 'EPS', .default = df$group)
  669. #df$group2 <- ifelse(df$group == 'Control','Control','EPS stable,increasing')
  670. #df$group3 <- paste(df$group2,df$plate_no, sep = '_')
  671. df %>% ggplot(aes(x = timepoint, y = exp, color = group, shape = plate_no))+
  672. #geom_col(width = 0.5,position = position_dodge())+
  673. geom_point()+
  674. geom_line(data = df %>% filter(plate_no != 'P1575' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  675. geom_line(data = df %>% filter(plate_no != 'P1571' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  676. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_03','RNA_05')), aes(x = timepoint, y = exp, group = 1), color = 'tomato')+
  677. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_08','RNA_10')), aes(x = timepoint, y = exp, group = 1), color = 'tomato')+
  678. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_03','RNA_06')), aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  679. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_08','RNA_11')), aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  680. theme_bw()+facet_wrap(~hgnc_symbol,scales = 'free_y')+
  681. scale_color_manual(values = c('darkolivegreen4', 'gold','tomato','dodgerblue'))+
  682. #scale_color_manual(values = c('darkolivegreen3', 'dodgerblue'))+
  683. labs(x = '', y = 'Normalized expression')
  684. ```
  685. #### Genes significantly downregulated by EPS2
  686. ```{r fig.dim=c(800/96, 240/96), fig.dpi=300}
  687. g = dn2
  688. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  689. #df <- cbind(coldata,norm.cts[rownames(norm.cts) %in% g,] %>% t)
  690. df <- cbind(coldata,norm.cts[g,] %>% t)
  691. df <- df %>% rownames_to_column('sample') %>%
  692. filter(group != 'EPS1b') %>%
  693. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g))) %>%
  694. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  695. # ism <- res1b %>% filter(padj < 0.05) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  696. # identical(unique(df$hgnc_symbol), ism)
  697. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  698. #df$group <- factor(df$group, levels = c('Control','EPS1a','EPS1b','EPS2'))
  699. df$group2 <- ifelse(df$group == 'Control','Control','EPS stable,increasing')
  700. #df$group3 <- paste(df$group2,df$plate_no, sep = '_')
  701. df %>% ggplot(aes(x = timepoint, y = exp, color = group2, shape = plate_no))+
  702. #geom_col(width = 0.5,position = position_dodge())+
  703. geom_point()+
  704. geom_line(data = df %>% filter(plate_no != 'P1575' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  705. geom_line(data = df %>% filter(plate_no != 'P1571' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  706. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_03','RNA_06')) , aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  707. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_08','RNA_11')), aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  708. theme_bw()+facet_wrap(~hgnc_symbol,scales = 'free_y')+
  709. #scale_color_manual(values = c('darkolivegreen4', 'tomato','dodgerblue','violet'))+
  710. scale_color_manual(values = c('darkolivegreen4', 'dodgerblue'))+
  711. labs(x = '', y = 'Normalized expression')
  712. ```
  713. ### Heatmaps & Dot plots
  714. DEGs with an adjusted P-value < 0.05 are mapped to the relevant biological functions and cellular processes they regulate.
  715. #### EPS1b vs Control {.tabset .tabset-pills}
  716. ```{r include =FALSE}
  717. #my.title = 'EPS1b vs Control comparison'
  718. my.title = 'Chronic EPS, stable vs Control comparison'
  719. g1 <- res1b %>% filter(padj < 0.05 & log2FoldChange > 0) %>% arrange(pvalue) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  720. g2 <- res1b %>% filter(padj < 0.05 & log2FoldChange > 0) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  721. # perform enrichment analysis for significant genes
  722. enriched <- enrichr(g2, dbs)
  723. enriched.df <- list_rbind(enriched[sapply(enriched, nrow) != 0], names_to = 'database')
  724. # Biological functions in Neurons & Muscles
  725. gene.functions = list(`Neuronal functions` = extract_genes(enriched.df,'neuron'),
  726. `Axon functions` = extract_genes(enriched.df,'axon'),
  727. `Dendrite functions` = extract_genes(enriched.df,'dendrite'),
  728. `Myelination`= extract_genes(enriched.df,'myelin'),
  729. `Synaptic functions` = extract_genes(enriched.df,'synaps|synaptic transmission'),
  730. `Myogenesis/Myotube formation`= extract_genes(enriched.df,'myogenesis|myotube|myoblast fusion'),
  731. `Muscle contraction`= extract_genes(enriched.df,'muscle contract|muscular contract'),
  732. `Angiogenesis`= extract_genes(enriched.df,'angiogenesis|vascular endothelial growth|blood vessel remodeling|blood vessel morphogenesis|blood vessel sprouting'),
  733. `Endothelial cell functions`= extract_genes(enriched.df,'\\b(endothelial cell|endothelial cells)\\b'),
  734. `Apoptosis/Cell death` = extract_genes(enriched.df,'apopto|cell death'),
  735. `Mitochondrial functions` = extract_genes(enriched.df,'mitochondr|atp synthesis|oxidative phosphory'),
  736. `Oxidative stress` = extract_genes(enriched.df,'oxidative stress')
  737. )
  738. # create gene-function data frame
  739. gene.functions.df <- lapply(gene.functions, function(x) data.frame(gene = x)) %>% list_rbind(names_to = 'annotation')
  740. my.genes <- unique(gene.functions.df$gene)
  741. orf.genes <- grep(x = my.genes,pattern = 'orf',ignore.case = T,value = T)
  742. my.genes[my.genes %in% orf.genes] <- str_to_title(orf.genes)
  743. gene.functions.df$gene[gene.functions.df$gene %in% orf.genes] <- str_to_title(orf.genes)
  744. # Gene expression heatmaps
  745. g1sub <- canonical_mapping %>% filter(hgnc_symbol %in% unique(gene.functions.df$gene)) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  746. #mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g1)
  747. #df <- cbind(coldata,norm.cts[g1,] %>% t %>% scale)
  748. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g1sub)
  749. df <- cbind(coldata,norm.cts[g1sub,] %>% t %>% scale)
  750. df <- df %>% rownames_to_column('sample') %>% filter(timepoint == 'd60' & group != 'EPS2') %>%
  751. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g1sub))) %>%
  752. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  753. df$group_plate <- paste(df$group,df$plate_no, sep = '_')
  754. df$group_plate <- factor(df$group_plate, levels = c("Control_P1571","Control_P1575","EPS1b_P1571","EPS1b_P1575"))
  755. df$group_replicate <- paste(df$group_desc,df$replicate, sep = ' ')
  756. df$group_replicate <- factor(df$group_replicate, levels = c("Control Rep1","Control Rep2","Chronic EPS, stable Rep1","Chronic EPS, stable Rep2"))
  757. #table(df$group_plate,df$group_replicate)
  758. #df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol) %>% rev)
  759. plt1v <- df %>% ggplot(aes(x= group_replicate, y= hgnc_symbol, fill= exp)) + # instead of x = group_plate
  760. geom_tile() +
  761. theme_bw()+
  762. theme(panel.grid.major = element_blank())+
  763. scale_x_discrete(position='bottom')+
  764. #scale_fill_gradient2(low = 'dodgerblue', mid = 'white', high = 'tomato', midpoint = 0, limits = c(-1.2,1.2))+
  765. expression_colors(1.5,0.75)+
  766. labs(x= '',y= '',fill= 'Scaled expression', title = my.title)+
  767. theme(plot.title = element_text(hjust = 0.5, size = 16),
  768. axis.text.x = element_text(angle = 30,hjust = 1,size = 14),
  769. axis.text.y = element_text(size = 12),
  770. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  771. plt1h <- df %>% ggplot(aes(y= group_replicate, x= hgnc_symbol, fill= exp)) + # instead of y = group_plate
  772. geom_tile() +
  773. theme_bw()+
  774. theme(panel.grid.major = element_blank())+
  775. scale_x_discrete(position='bottom')+
  776. #scale_fill_gradient2(low = 'dodgerblue', mid = 'white', high = 'tomato', midpoint = 0, limits = c(-1.2,1.2))+
  777. expression_colors(1.5,0.75)+
  778. labs(x= '',y= '',fill= 'Scaled expression', title = my.title)+
  779. theme(plot.title = element_text(hjust = 0.5, size = 16),
  780. axis.text.x = element_text(angle = 30, hjust = 1,size = 12),
  781. axis.text.y = element_text(size = 14),
  782. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  783. ```
  784. ```{r include = F}
  785. # Gene-Functions Dot plots
  786. global_size_range <- range(c(-log10(res1b$pvalue), -log10(res2$pvalue)))
  787. dt <- res1b %>% filter(hgnc_symbol %in% g2) %>% dplyr::select(hgnc_symbol,log2FoldChange,pvalue) %>% mutate(metric = -log10(pvalue))
  788. # unique(gene.functions.df$gene)
  789. # unique(dt$hgnc_symbol)
  790. colnames(gene.functions.df)[2] <- 'hgnc_symbol'
  791. dt <- left_join(gene.functions.df, dt, by = 'hgnc_symbol')
  792. #summary(dt$log2FoldChange)
  793. dt$annotation <- factor(dt$annotation, levels = names(gene.functions))
  794. plt2v <- dt %>% ggplot(aes(x = annotation, y = hgnc_symbol, fill = log2FoldChange, size = metric))+geom_point(shape=21)+theme_bw()+expression_colors(1.5,0.75)+theme_bw()+
  795. scale_size_continuous(limits = global_size_range, range = c(1,10))+
  796. labs(x ='',y = '', size = 'statistical significance',title = my.title)+
  797. guides(fill = guide_colourbar(order = 1),size = guide_legend(order = 2))+
  798. theme(plot.title = element_text(hjust = 0.5, size = 16),
  799. axis.text.x = element_text(angle = 30, hjust= 1,size = 14),
  800. axis.text.y = element_text(size = 12),
  801. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  802. dt$annotation <- factor(dt$annotation, levels = names(gene.functions) %>% rev)
  803. plt2h <- dt %>% ggplot(aes(y = annotation, x = hgnc_symbol, fill = log2FoldChange, size = metric))+geom_point(shape=21)+theme_bw()+expression_colors(1.5,0.75)+theme_bw()+
  804. scale_size_continuous(limits = global_size_range, range = c(1,10))+
  805. labs(x ='',y = '', size = 'statistical significance',title = my.title)+
  806. guides(fill = guide_colourbar(order = 1),size = guide_legend(order = 2))+
  807. theme(plot.title = element_text(hjust = 0.5, size = 16),
  808. axis.text.x = element_text(angle = 30, hjust= 1,size = 12),
  809. axis.text.y = element_text(size = 14),
  810. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  811. ```
  812. ##### Vertical heatmap & dot plot
  813. ```{r fig.dim=c(1300/96,940/96), fig.dpi=300}
  814. plt1v + plt2v + plot_layout(widths = c(4,12))
  815. ```
  816. ##### Horizontal heatmap & dot plot
  817. ```{r fig.dim=c(1350/96,700/96), fig.dpi=300}
  818. plt1h / plt2h + plot_layout(heights = c(4,12))
  819. ```
  820. #### {-}
  821. #### EPS2 vs Control {.tabset .tabset-pills}
  822. ```{r include =FALSE}
  823. #my.title = 'EPS2 vs Control comparison'
  824. my.title = 'Chronic EPS, increasing vs Control comparison'
  825. g1 <- res2 %>% filter(padj < 0.05 & log2FoldChange > 0) %>% arrange(pvalue) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  826. g2 <- res2 %>% filter(padj < 0.05 & log2FoldChange > 0) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  827. # perform enrichment analysis for significant genes
  828. enriched <- enrichr(g2, dbs)
  829. enriched.df <- list_rbind(enriched[sapply(enriched, nrow) != 0], names_to = 'database')
  830. # Biological functions in Neurons & Muscles
  831. gene.functions = list(`Neuronal functions` = extract_genes(enriched.df,'neuron'),
  832. `Axon functions` = extract_genes(enriched.df,'axon'),
  833. `Dendrite functions` = extract_genes(enriched.df,'dendrite'),
  834. `Myelination`= extract_genes(enriched.df,'myelin'),
  835. `Synaptic functions` = extract_genes(enriched.df,'synaps|synaptic transmission'),
  836. `Myogenesis/Myotube formation`= extract_genes(enriched.df,'myogenesis|myotube|myoblast fusion'),
  837. `Muscle contraction`= extract_genes(enriched.df,'muscle contract|muscular contract'),
  838. `Angiogenesis`= extract_genes(enriched.df,'angiogenesis|vascular endothelial growth|blood vessel remodeling|blood vessel morphogenesis|blood vessel sprouting'),
  839. `Endothelial cell functions`= extract_genes(enriched.df,'\\b(endothelial cell|endothelial cells)\\b'),
  840. `Apoptosis/Cell death` = extract_genes(enriched.df,'apopto|cell death'),
  841. `Mitochondrial functions` = extract_genes(enriched.df,'mitochondr|atp synthesis|oxidative phosphory'),
  842. `Oxidative stress` = extract_genes(enriched.df,'oxidative stress')
  843. )
  844. # create gene-function data frame
  845. gene.functions.df <- lapply(gene.functions, function(x) data.frame(gene = x)) %>% list_rbind(names_to = 'annotation')
  846. my.genes <- unique(gene.functions.df$gene)
  847. orf.genes <- grep(x = my.genes,pattern = 'orf',ignore.case = T,value = T)
  848. my.genes[my.genes %in% orf.genes] <- str_to_title(orf.genes)
  849. gene.functions.df$gene[gene.functions.df$gene %in% orf.genes] <- str_to_title(orf.genes)
  850. # Gene expression heatmaps
  851. g1sub <- canonical_mapping %>% filter(hgnc_symbol %in% unique(gene.functions.df$gene)) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  852. #mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g1)
  853. #df <- cbind(coldata,norm.cts[g1,] %>% t %>% scale)
  854. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g1sub)
  855. df <- cbind(coldata,norm.cts[g1sub,] %>% t %>% scale)
  856. df <- df %>% rownames_to_column('sample') %>% filter(timepoint == 'd60' & group != 'EPS1b') %>%
  857. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g1sub))) %>%
  858. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  859. df$group_plate <- paste(df$group,df$plate_no, sep = '_')
  860. df$group_plate <- factor(df$group_plate, levels = c("Control_P1571","Control_P1575","EPS2_P1571","EPS2_P1575"))
  861. df$group_replicate <- paste(df$group_desc,df$replicate, sep = ' ')
  862. df$group_replicate <- factor(df$group_replicate, levels = c("Control Rep1","Control Rep2","Chronic EPS, increasing Rep1","Chronic EPS, increasing Rep2"))
  863. #table(df$group_plate,df$group_replicate)
  864. #df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol) %>% rev)
  865. plt1v <- df %>% ggplot(aes(x= group_replicate, y= hgnc_symbol, fill= exp)) + # instead of x= group_plate
  866. geom_tile() +
  867. theme_bw()+
  868. theme(panel.grid.major = element_blank())+
  869. scale_x_discrete(position='bottom')+
  870. #scale_fill_gradient2(low = 'dodgerblue', mid = 'white', high = 'tomato', midpoint = 0, limits = c(-1.2,1.2))+
  871. expression_colors(1.5,0.75)+
  872. labs(x= '',y= '',fill= 'Scaled expression', title = my.title)+
  873. theme(plot.title = element_text(hjust = 0.5, size = 16),
  874. axis.text.x = element_text(angle = 30,hjust = 1,size = 14),
  875. axis.text.y = element_text(size = 12),
  876. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  877. plt1h <- df %>% ggplot(aes(y= group_replicate, x= hgnc_symbol, fill= exp)) + # instead of y= group_plate
  878. geom_tile() +
  879. theme_bw()+
  880. theme(panel.grid.major = element_blank())+
  881. scale_x_discrete(position='bottom')+
  882. #scale_fill_gradient2(low = 'dodgerblue', mid = 'white', high = 'tomato', midpoint = 0, limits = c(-1.2,1.2))+
  883. expression_colors(1.5,0.75)+
  884. labs(x= '',y= '',fill= 'Scaled expression', title = my.title)+
  885. theme(plot.title = element_text(hjust = 0.5, size = 16),
  886. axis.text.x = element_text(angle = 30, hjust = 1,size = 12),
  887. axis.text.y = element_text(size = 14),
  888. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  889. ```
  890. ```{r include = F}
  891. # Gene-Functions Dot plots
  892. global_size_range <- range(c(-log10(res1b$pvalue), -log10(res2$pvalue)))
  893. dt <- res2 %>% filter(hgnc_symbol %in% g2) %>% dplyr::select(hgnc_symbol,log2FoldChange,pvalue) %>% mutate(metric = -log10(pvalue))
  894. # unique(gene.functions.df$gene)
  895. # unique(dt$hgnc_symbol)
  896. colnames(gene.functions.df)[2] <- 'hgnc_symbol'
  897. dt <- left_join(gene.functions.df, dt, by = 'hgnc_symbol')
  898. #summary(dt$log2FoldChange)
  899. dt$annotation <- factor(dt$annotation, levels = names(gene.functions))
  900. plt2v <- dt %>% ggplot(aes(x = annotation, y = hgnc_symbol, fill = log2FoldChange, size = metric))+geom_point(shape=21)+theme_bw()+expression_colors(1.5,0.75)+theme_bw()+
  901. scale_size_continuous(limits = global_size_range, range = c(1,10))+
  902. labs(x ='',y = '', size = 'statistical significance',title = my.title)+
  903. guides(fill = guide_colourbar(order = 1),size = guide_legend(order = 2))+
  904. theme(plot.title = element_text(hjust = 0.5, size = 16),
  905. axis.text.x = element_text(angle = 30, hjust= 1,size = 14),
  906. axis.text.y = element_text(size = 12),
  907. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  908. dt$annotation <- factor(dt$annotation, levels = names(gene.functions) %>% rev)
  909. plt2h <- dt %>% ggplot(aes(y = annotation, x = hgnc_symbol, fill = log2FoldChange, size = metric))+geom_point(shape=21)+theme_bw()+expression_colors(1.5,0.75)+theme_bw()+
  910. scale_size_continuous(limits = global_size_range, range = c(1,10))+
  911. labs(x ='',y = '', size = 'statistical significance',title = my.title)+
  912. guides(fill = guide_colourbar(order = 1),size = guide_legend(order = 2))+
  913. theme(plot.title = element_text(hjust = 0.5, size = 16),
  914. axis.text.x = element_text(angle = 30, hjust= 1,size = 12),
  915. axis.text.y = element_text(size = 14),
  916. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  917. ```
  918. ##### Vertical heatmap & dot plot
  919. ```{r fig.dim=c(1420/96,920/96), fig.dpi=300}
  920. plt1v + plt2v + plot_layout(widths = c(4,11))
  921. ```
  922. ##### Horizontal heatmap & dot plot
  923. ```{r fig.dim=c(1300/96,700/96), fig.dpi=300}
  924. plt1h / plt2h + plot_layout(heights = c(4,11))
  925. ```
  926. #### {-}
  927. # Dynamic genes
  928. Principal component analysis shows that PC1 neatly separates samples based on the developmental time point. Therefore, genes whose expression highly correlates with PC1 are those which significantly change over the developmental timeline. To identify those dynamic genes, a correlation analysis between gene expression and PC1 was performed and genes with the most significant correlations were tested for functional enrichment using *EnrichR*.
  929. ```{r include=FALSE}
  930. norm.cts <- assay(ntd)
  931. identical(rownames(t(norm.cts)), rownames(pcaData))
  932. # Calculate correlation between gene expression and first principal component (PC1)
  933. # cor.res <- cor(pcaData$PC1,t(norm.cts))
  934. # hist(cor.res[1,])
  935. # cor.res[1,] %>% sort() %>% tail(50)
  936. # sum(abs(cor.res[1,]) > 0.9 )
  937. cor.res <- apply(t(norm.cts),2,cor.test, y= pcaData$PC1)
  938. cor.coef <- sapply(cor.res, function(x) unname(x$estimate))
  939. pval <- sapply(cor.res, function(x) x$p.value)
  940. padj <- p.adjust(pval,method = 'fdr')
  941. #data.frame(cor.coef = cor.coef, pval = pval) %>% ggplot(aes(x = cor.coef, y = pval))+geom_point()
  942. sum(padj < 5/100)
  943. g.id <- names(padj[padj < 5/100])
  944. g.sym <- canonical_mapping %>% filter(ensembl_gene_id %in% g.id) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname %>% unique
  945. if (websiteLive) {
  946. enriched <- enrichr(g.sym, dbs)
  947. }
  948. enriched.df <- list_rbind(enriched[sapply(enriched, nrow) != 0], names_to = 'database')
  949. top.g.id <- sort(pval, decreasing = F) %>% head(1000) %>% names()
  950. top.g.sym <- canonical_mapping %>% filter(ensembl_gene_id %in% top.g.id) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname %>% unique
  951. length(top.g.id);length(unique(top.g.sym))
  952. top.g.pval <- pval[names(pval) %in% top.g.id]
  953. top.g.coef <- cor.coef[names(cor.coef) %in% top.g.id]
  954. identical(rownames(as.data.frame(top.g.pval)), rownames(as.data.frame(top.g.coef)))
  955. top.g.df <- inner_join(as.data.frame(top.g.coef) %>% rownames_to_column('ensembl_gene_id') ,
  956. as.data.frame(top.g.pval) %>% rownames_to_column('ensembl_gene_id'), by = 'ensembl_gene_id')
  957. colnames(top.g.df)[c(2,3)] <- c('cor.coef','pval')
  958. top.g.df <- left_join(top.g.df, canonical_mapping %>% dplyr::select(ensembl_gene_id,hgnc_symbol), by = 'ensembl_gene_id')
  959. ```
  960. The top dynamic genes are shown in the following table together with their correlation coefficient with PC1, the P-value for the correlation and the FDR-adjusted P-value. Genes are ranked based on the statistical significance of their correlation. A negative correlation indicates that the gene decreases in expression and a positive correlation indicates that it increases in expression with developmental time.
  961. ```{r}
  962. #colnames(top.g.df)[c(1,4,2,3)]
  963. top.g.df[,c(1,4,2,3)] %>% mutate(padj = p.adjust(pval, method= 'fdr')) %>% arrange(pval) %>%
  964. datatable(options = list(pageLength= 10))
  965. ```
  966. The results of functional enrichment analysis of those genes are shown in the following table. Gene sets are arranged by P-value.
  967. ```{r}
  968. enriched.df %>% arrange(P.value) %>% head(1000) %>%
  969. datatable(options = list(pageLength= 10))
  970. ```
  971. The developmental time profiles of the expression of the top 50 genes are shown here.
  972. ```{r include=FALSE}
  973. top.g.id <- sort(pval, decreasing = F) %>% head(50) %>% names()
  974. top.g.sym <- canonical_mapping %>% filter(ensembl_gene_id %in% top.g.id) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname %>% unique
  975. length(top.g.id);length(unique(top.g.sym))
  976. top.g.pval <- pval[names(pval) %in% top.g.id]
  977. top.g.coef <- cor.coef[names(cor.coef) %in% top.g.id]
  978. identical(rownames(as.data.frame(top.g.pval)), rownames(as.data.frame(top.g.coef)))
  979. top.g.df <- inner_join(as.data.frame(top.g.coef) %>% rownames_to_column('ensembl_gene_id') ,
  980. as.data.frame(top.g.pval) %>% rownames_to_column('ensembl_gene_id'), by = 'ensembl_gene_id')
  981. colnames(top.g.df)[c(2,3)] <- c('cor.coef','pval')
  982. top.g.df <- left_join(top.g.df, canonical_mapping %>% dplyr::select(ensembl_gene_id,hgnc_symbol), by = 'ensembl_gene_id')
  983. sorted.sym <- top.g.df %>% arrange(pval) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  984. ```
  985. ```{r fig.dim= c(1200/96,900/96), fig.dpi= 300}
  986. df <- cbind(coldata,norm.cts[top.g.id,] %>% t)
  987. df <- df %>% pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 7:(6+length(top.g.id))) %>%
  988. left_join(canonical_mapping[,-3], by = 'ensembl_gene_id')
  989. #identical(unique(df$hgnc_symbol), sorted.sym)
  990. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = sorted.sym) # or levels = unique(df$hgnc_symbol)
  991. plt <- df %>% ggplot(aes(x = timepoint, y = exp))+theme_bw()+
  992. geom_jitter(color = 'gray', width = 0.2, height = 0)+
  993. geom_point(aes(x = timepoint, y= mean.exp),size = 1, data = df %>% group_by(hgnc_symbol,timepoint) %>% summarise(n_samples = n(), mean.exp = mean(exp)))+
  994. geom_line(aes(x = timepoint, y= mean.exp, group = 1), data = df %>% group_by(hgnc_symbol,timepoint) %>% summarise(n_samples = n(), mean.exp = mean(exp)))+
  995. facet_wrap(~ hgnc_symbol, scales = 'free')+
  996. labs(x = '', y = 'Normalized expression')
  997. plt
  998. ```
  999. ## Dynamic genes significantly upregulated by EPS1b
  1000. ```{r fig.dim=c(850/96, 500/96), fig.dpi=300}
  1001. g = intersect(up1b,g.id)
  1002. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  1003. df <- cbind(coldata,norm.cts[g,] %>% t)
  1004. df <- df %>% rownames_to_column('sample') %>%
  1005. filter(group != 'EPS2') %>%
  1006. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g))) %>%
  1007. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  1008. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  1009. #df$group <- factor(df$group, levels = c('Control','EPS1a','EPS1b','EPS2'))
  1010. #df$group2 <- case_match(df$group, c('EPS1a','EPS1b') ~ 'EPS', .default = df$group)
  1011. df$group2 <- ifelse(df$group == 'Control','Control','EPS stable')
  1012. #df$group3 <- paste(df$group2,df$plate_no, sep = '_')
  1013. df %>% ggplot(aes(x = timepoint, y = exp, color = group2, shape = plate_no))+
  1014. #geom_col(width = 0.5,position = position_dodge())+
  1015. geom_point()+
  1016. geom_line(data = df %>% filter(plate_no != 'P1575' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  1017. geom_line(data = df %>% filter(plate_no != 'P1571' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  1018. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_03','RNA_05')), aes(x = timepoint, y = exp, group = 1), color = 'tomato')+
  1019. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_08','RNA_10')), aes(x = timepoint, y = exp, group = 1), color = 'tomato')+
  1020. theme_bw()+facet_wrap(~hgnc_symbol,scales = 'free_y')+
  1021. #scale_color_manual(values = c('darkolivegreen4', 'tomato','dodgerblue','violet'))+
  1022. scale_color_manual(values = c('darkolivegreen4', 'tomato'))+
  1023. labs(x = '', y = 'Normalized expression')
  1024. ```
  1025. ### Heatmap & Dot plot
  1026. ```{r include=FALSE}
  1027. my.title = "Chronic EPS, stable vs Control comparison"
  1028. # perform enrichment analysis for significant genes
  1029. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  1030. my.genes <- unique(mapping.df$hgnc_symbol)
  1031. # print numbers of ensembl IDs and corresponding gene symbols
  1032. #length(g);length(my.genes)
  1033. enriched <- enrichr(my.genes, dbs)
  1034. enriched.df <- list_rbind(enriched[sapply(enriched, nrow) != 0], names_to = 'database')
  1035. # Biological functions in Neurons & Muscles
  1036. gene.functions = list(`Neuronal functions` = extract_genes(enriched.df,'neuron'),
  1037. `Axon functions` = extract_genes(enriched.df,'axon'),
  1038. `Dendrite functions` = extract_genes(enriched.df,'dendrite'),
  1039. `Myelination`= extract_genes(enriched.df,'myelin'),
  1040. `Synaptic functions` = extract_genes(enriched.df,'synaps|synaptic transmission'),
  1041. `Myogenesis/Myotube formation`= extract_genes(enriched.df,'myogenesis|myotube|myoblast fusion'),
  1042. `Muscle contraction`= extract_genes(enriched.df,'muscle contract|muscular contract'),
  1043. `Angiogenesis`= extract_genes(enriched.df,'angiogenesis|vascular endothelial growth|blood vessel remodeling|blood vessel morphogenesis|blood vessel sprouting'),
  1044. `Endothelial cell functions`= extract_genes(enriched.df,'\\b(endothelial cell|endothelial cells)\\b'),
  1045. `Apoptosis/Cell death` = extract_genes(enriched.df,'apopto|cell death'),
  1046. `Mitochondrial functions` = extract_genes(enriched.df,'mitochondr|atp synthesis|oxidative phosphory'),
  1047. `Oxidative stress` = extract_genes(enriched.df,'oxidative stress')
  1048. )
  1049. # create gene-function data frame
  1050. gene.functions.df <- lapply(gene.functions, function(x) data.frame(gene = x)) %>% list_rbind(names_to = 'annotation')
  1051. my.genes <- unique(gene.functions.df$gene)
  1052. orf.genes <- grep(x = my.genes,pattern = 'orf',ignore.case = T,value = T)
  1053. my.genes[my.genes %in% orf.genes] <- str_to_title(orf.genes)
  1054. gene.functions.df$gene[gene.functions.df$gene %in% orf.genes] <- str_to_title(orf.genes)
  1055. # Heatmap
  1056. g.sub <- canonical_mapping %>% filter(hgnc_symbol %in% unique(gene.functions.df$gene)) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  1057. df <- cbind(coldata,norm.cts[g.sub,] %>% t %>% scale)
  1058. df <- df %>% rownames_to_column('sample') %>% filter(timepoint == 'd60' & group != 'EPS2') %>%
  1059. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g.sub))) %>%
  1060. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  1061. df$group_plate <- paste(df$group,df$plate_no, sep = '_')
  1062. df$group_plate <- factor(df$group_plate, levels = c("Control_P1571","Control_P1575","EPS1b_P1571","EPS1b_P1575"))
  1063. df$group_replicate <- paste(df$group_desc,df$replicate, sep = ' ')
  1064. df$group_replicate <- factor(df$group_replicate, levels = c("Control Rep1","Control Rep2","Chronic EPS, stable Rep1","Chronic EPS, stable Rep2"))
  1065. #table(df$group_plate,df$group_replicate)
  1066. plt1h <- df %>% ggplot(aes(y= group_replicate, x= hgnc_symbol, fill= exp)) + # instead of y = group_plate
  1067. geom_tile() +
  1068. theme_bw()+
  1069. theme(panel.grid.major = element_blank())+
  1070. scale_x_discrete(position='bottom')+
  1071. #scale_fill_gradient2(low = 'dodgerblue', mid = 'white', high = 'tomato', midpoint = 0, limits = c(-1.2,1.2))+
  1072. expression_colors(1.5,0.75)+
  1073. labs(x= '',y= '',fill= 'Scaled expression', title = my.title)+
  1074. theme(plot.title = element_text(hjust = 0.5, size = 16),
  1075. axis.text.x = element_text(angle = 30, hjust = 1,size = 12),
  1076. axis.text.y = element_text(size = 14),
  1077. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  1078. # Gene-Function dot plot
  1079. dt <- res1b %>% filter(hgnc_symbol %in% my.genes) %>% dplyr::select(hgnc_symbol,log2FoldChange,pvalue) %>% mutate(metric = -log10(pvalue))
  1080. # unique(gene.functions.df$gene)
  1081. # unique(dt$hgnc_symbol)
  1082. colnames(gene.functions.df)[2] <- 'hgnc_symbol'
  1083. dt <- left_join(gene.functions.df, dt, by = 'hgnc_symbol')
  1084. summary(dt$log2FoldChange)
  1085. dt$annotation <- factor(dt$annotation, levels = names(gene.functions) %>% rev)
  1086. plt2h <- dt %>% ggplot(aes(y = annotation, x = hgnc_symbol, fill = log2FoldChange, size = metric))+geom_point(shape=21)+theme_bw()+expression_colors(1.5,0.75)+theme_bw()+
  1087. labs(x ='',y = '', size = 'statistical significance',title = my.title)+
  1088. theme(plot.title = element_text(hjust = 0.5, size = 16),
  1089. axis.text.x = element_text(angle = 30, hjust= 1,size = 12),
  1090. axis.text.y = element_text(size = 14),
  1091. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  1092. ```
  1093. ```{r fig.dim=c(800/96,710/96), fig.dpi=300}
  1094. plt1h / plt2h + plot_layout(heights = c(4,12))
  1095. ```
  1096. ## Dynamic genes significantly upregulated by EPS2
  1097. ```{r fig.dim=c(850/96, 550/96), fig.dpi=300}
  1098. g = intersect(up2,g.id)
  1099. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  1100. #df <- cbind(coldata,norm.cts[rownames(norm.cts) %in% g,] %>% t)
  1101. df <- cbind(coldata,norm.cts[g,] %>% t)
  1102. df <- df %>% rownames_to_column('sample') %>%
  1103. filter(group != 'EPS1b') %>%
  1104. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g))) %>%
  1105. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  1106. # ism <- res1b %>% filter(padj < 0.05) %>% arrange(pvalue) %>% dplyr::select(hgnc_symbol) %>% unlist %>% unname
  1107. # identical(unique(df$hgnc_symbol), ism)
  1108. df$hgnc_symbol <- factor(df$hgnc_symbol, levels = unique(df$hgnc_symbol))
  1109. #df$group <- factor(df$group, levels = c('Control','EPS1a','EPS1b','EPS2'))
  1110. df$group2 <- ifelse(df$group == 'Control','Control','EPS stable/increasing')
  1111. #df$group3 <- paste(df$group2,df$plate_no, sep = '_')
  1112. df %>% ggplot(aes(x = timepoint, y = exp, color = group2, shape = plate_no))+
  1113. #geom_col(width = 0.5,position = position_dodge())+
  1114. geom_point()+
  1115. geom_line(data = df %>% filter(plate_no != 'P1575' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  1116. geom_line(data = df %>% filter(plate_no != 'P1571' & group == 'Control'), aes(x = timepoint, y = exp, group = 1), color = 'darkolivegreen4')+
  1117. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_03','RNA_06')) , aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  1118. geom_line(data = df %>% filter(sample %in% c('RNA_01','RNA_08','RNA_11')), aes(x = timepoint, y = exp, group = 1), color = 'dodgerblue')+
  1119. theme_bw()+facet_wrap(~hgnc_symbol,scales = 'free_y')+
  1120. #scale_color_manual(values = c('darkolivegreen4', 'tomato','dodgerblue','violet'))+
  1121. scale_color_manual(values = c('darkolivegreen4', 'dodgerblue'))+
  1122. labs(x = '', y = 'Normalized expression')
  1123. ```
  1124. ### Heatmap & Dot plot
  1125. ```{r include=FALSE}
  1126. my.title = "Chronic EPS, increasing vs Control comparison"
  1127. # perform enrichment analysis for significant genes
  1128. mapping.df <- canonical_mapping %>% filter(ensembl_gene_id %in% g)
  1129. my.genes <- unique(mapping.df$hgnc_symbol)
  1130. # print numbers of ensembl IDs and corresponding gene symbols
  1131. #length(g);length(my.genes)
  1132. enriched <- enrichr(my.genes, dbs)
  1133. enriched.df <- list_rbind(enriched[sapply(enriched, nrow) != 0], names_to = 'database')
  1134. # Biological functions in Neurons & Muscles
  1135. gene.functions = list(`Neuronal functions` = extract_genes(enriched.df,'neuron'),
  1136. `Axon functions` = extract_genes(enriched.df,'axon'),
  1137. `Dendrite functions` = extract_genes(enriched.df,'dendrite'),
  1138. `Myelination`= extract_genes(enriched.df,'myelin'),
  1139. `Synaptic functions` = extract_genes(enriched.df,'synaps|synaptic transmission'),
  1140. `Myogenesis/Myotube formation`= extract_genes(enriched.df,'myogenesis|myotube|myoblast fusion'),
  1141. `Muscle contraction`= extract_genes(enriched.df,'muscle contract|muscular contract'),
  1142. `Angiogenesis`= extract_genes(enriched.df,'angiogenesis|vascular endothelial growth|blood vessel remodeling|blood vessel morphogenesis|blood vessel sprouting'),
  1143. `Endothelial cell functions`= extract_genes(enriched.df,'\\b(endothelial cell|endothelial cells)\\b'),
  1144. `Apoptosis/Cell death` = extract_genes(enriched.df,'apopto|cell death'),
  1145. `Mitochondrial functions` = extract_genes(enriched.df,'mitochondr|atp synthesis|oxidative phosphory'),
  1146. `Oxidative stress` = extract_genes(enriched.df,'oxidative stress')
  1147. )
  1148. # create gene-function data frame
  1149. gene.functions.df <- lapply(gene.functions, function(x) data.frame(gene = x)) %>% list_rbind(names_to = 'annotation')
  1150. my.genes <- unique(gene.functions.df$gene)
  1151. orf.genes <- grep(x = my.genes,pattern = 'orf',ignore.case = T,value = T)
  1152. my.genes[my.genes %in% orf.genes] <- str_to_title(orf.genes)
  1153. gene.functions.df$gene[gene.functions.df$gene %in% orf.genes] <- str_to_title(orf.genes)
  1154. # Heatmap
  1155. g.sub <- canonical_mapping %>% filter(hgnc_symbol %in% unique(gene.functions.df$gene)) %>% dplyr::select(ensembl_gene_id) %>% unlist %>% unname
  1156. df <- cbind(coldata,norm.cts[g.sub,] %>% t %>% scale)
  1157. df <- df %>% rownames_to_column('sample') %>% filter(timepoint == 'd60' & group != 'EPS1b') %>%
  1158. pivot_longer(names_to = "ensembl_gene_id",values_to = "exp",cols = 8:(7+length(g.sub))) %>%
  1159. left_join(mapping.df[,-3], by = 'ensembl_gene_id')
  1160. df$group_plate <- paste(df$group,df$plate_no, sep = '_')
  1161. df$group_plate <- factor(df$group_plate, levels = c("Control_P1571","Control_P1575","EPS2_P1571","EPS2_P1575"))
  1162. df$group_replicate <- paste(df$group_desc,df$replicate, sep = ' ')
  1163. df$group_replicate <- factor(df$group_replicate, levels = c("Control Rep1","Control Rep2","Chronic EPS, increasing Rep1","Chronic EPS, increasing Rep2"))
  1164. #table(df$group_plate,df$group_replicate)
  1165. plt1h <- df %>% ggplot(aes(y= group_replicate, x= hgnc_symbol, fill= exp)) + # instead of y = group_plate
  1166. geom_tile() +
  1167. theme_bw()+
  1168. theme(panel.grid.major = element_blank())+
  1169. scale_x_discrete(position='bottom')+
  1170. #scale_fill_gradient2(low = 'dodgerblue', mid = 'white', high = 'tomato', midpoint = 0, limits = c(-1.2,1.2))+
  1171. expression_colors(1.5,0.75)+
  1172. labs(x= '',y= '',fill= 'Scaled expression', title = my.title)+
  1173. theme(plot.title = element_text(hjust = 0.5, size = 16),
  1174. axis.text.x = element_text(angle = 30, hjust = 1,size = 12),
  1175. axis.text.y = element_text(size = 14),
  1176. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  1177. # Gene-Function dot plot
  1178. dt <- res1b %>% filter(hgnc_symbol %in% my.genes) %>% dplyr::select(hgnc_symbol,log2FoldChange,pvalue) %>% mutate(metric = -log10(pvalue))
  1179. # unique(gene.functions.df$gene)
  1180. # unique(dt$hgnc_symbol)
  1181. colnames(gene.functions.df)[2] <- 'hgnc_symbol'
  1182. dt <- left_join(gene.functions.df, dt, by = 'hgnc_symbol')
  1183. summary(dt$log2FoldChange)
  1184. dt$annotation <- factor(dt$annotation, levels = names(gene.functions) %>% rev)
  1185. plt2h <- dt %>% ggplot(aes(y = annotation, x = hgnc_symbol, fill = log2FoldChange, size = metric))+geom_point(shape=21)+theme_bw()+expression_colors(1.5,0.75)+theme_bw()+
  1186. labs(x ='',y = '', size = 'statistical significance',title = my.title)+
  1187. theme(plot.title = element_text(hjust = 0.5, size = 16),
  1188. axis.text.x = element_text(angle = 30, hjust= 1,size = 12),
  1189. axis.text.y = element_text(size = 14),
  1190. legend.position = 'right',legend.title.position = 'left', legend.title = element_text(angle = 90))
  1191. ```
  1192. ```{r fig.dim=c(800/96,710/96), fig.dpi=300}
  1193. plt1h / plt2h + plot_layout(heights = c(4,12))
  1194. ```
  1195. # R session information
  1196. ```{r}
  1197. utils::sessionInfo()
  1198. ```

EPS_NMOs_analysis_v2.Rmd at commit 8eb2cca, under MIT · at the source

Overview

Authors: Chrysanthi‐Maria Moysidou1, Inês Afonso Martins1, Ismail Amr El‐Shimy1, Iacopo Bicci1, Donatella Cea2, Christina Bukas2, Isra Mekki2, Mara‐Camelia Rusu1, Aylin Nebol1, Ines Lahmann1, Marie Piraud2, Enrico Klotzsch3,4,5, Mina Gouti1,6
  1. Max Delbrück Center for Molecular Medicine (MDC) Berlin Germany
  2. Helmholtz AI, Computational Health Center (CHC) Helmholtz Munich Neuherberg Germany
  3. Berlin Institute of Health Center for Regenerative Therapies (BCRT) Berlin Germany
  4. Berlin Institute of Health Experimental and Clinical Research Center (ECRC) Berlin Germany
  5. Charité Universitätsmedizin Berlin Germany
  6. Department of Pediatric Neurology Charité Universitätsmedizin Berlin Berlin Germany
Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany), volume 13, issue 50, article e22762
Dates: received 13 November 2025; accepted 5 June 2026; published online 22 June 2026; in print September 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1002/advs.202522762 · PMID 42325128 · PMCID PMC13337066 · OpenAlex W7165545725
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: human (organism), developmental (subfield)
Keywords: bioengineering, biophysical cues, electrical stimulation, EPS‐NMOs, neuromuscular organoids, neuromuscular systems, organoid maturation
MeSH: Electric Stimulation*, Muscle, Skeletal*, Neuromuscular Junction*, Organoids*, Pluripotent Stem Cells*, Cell Differentiation, Humans (* major topic)
Topic: Planarian Biology and Electrostimulation (Molecular Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Citations: cited by 1 paper (Europe PMC); 93 references in the paper

Abstract

Organoids derived from human pluripotent stem cells (hPSCs) are emerging as powerful models for studying development and disease. Despite their physiological relevance, the predictive power of organoids remains limited by the immature state of the constituent cells, posing a major challenge for mechanistic studies of adult physiology and late‐onset disorders. Here, we establish a strategy for enhancing the maturation status of human neuromuscular organoids (NMOs) through chronic Electrical Pulse Stimulation (EPS). We demonstrate that low‐frequency EPS, applied during the early stages of NMO development and maintained over several weeks, enhances neuromuscular maturation and functional output. Independent of stimulation waveform dynamics, EPS‐trained NMOs (EPS‐NMOs) display stronger and more frequent spontaneous contractions that persist long after stimulation has ceased. Quantitative imaging and transcriptomic analyses reveal a robust improvement in EPS‐NMO skeletal muscle and neural tissue morphology, coordinated regulation of lineage‐specific biomarkers, and upregulation of gene programs associated with neuromuscular maturation. Mechanobiological measurements further demonstrate increased tissue stiffness and faster relaxation dynamics in EPS‐NMOs, consistent with enhanced excitation‐contraction coupling (ECC) and force generation. Collectively, these findings establish EPS as a powerful, non‐invasive, and on‐demand modality for promoting the morphological and functional maturation of complex organoid systems.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 18 matches between paragraphs and lines of code.

Gouti-Lab/EPS-Project

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 8eb2ccab44fac1b8c61fbd493b55a05d963c75bb, 23 March 2026
Languages: Jupyter (8), R (1), Shell (1)
Size: 15 files, 10 scripts
Software Heritage: not archived
Found in: “Data Availability Statement”
Holds: README, license file, 9 notebooks
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: Matplotlib (8 files), NumPy (8 files), pandas (8 files), scikit-image (8 files), imageio (7 files), h5py (4 files), tifffile (4 files), DESeq2 (1 file), patchwork (1 file), pheatmap (1 file), SAMtools (1 file), SciPy (1 file), Subread (featureCounts) (1 file), tidyverse (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
12 files

HelmholtzAI-Consultants-Munich/NMOs-Contraction

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 58bf0ae2227d6ef5a657d2191f2ed4ae94baf63d, 12 June 2026
Languages: Python (5), Jupyter (3)
Size: 16 files, 8 scripts
Software Heritage: not archived
Found in: “Data Availability Statement”
Holds: README, environment (requirements.txt), 3 notebooks
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (6 files), pandas (5 files), Matplotlib (4 files), scikit-image (3 files), Plotly (2 files), Cellpose (1 file), Pillow (1 file), SciPy (1 file), seaborn (1 file), statsmodels (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
9 files

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:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 18 scripts, each with its path and the digest of its content;
  • 18 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

No dataset and no data link were found in the paper.

Data Availability Statement

The data that support the findings of this study are available from the corresponding authors upon reasonable request. All analyses of sequencing data were executed on a SLURM‐managed HPC cluster (Max Cluster) at MDC‐Berlin using GNU parallel to parallelize QC, alignment, and counting across samples. Software versions and links to reference files (genome build and GTF) are provided in Table S3 and command‐line arguments and analysis scripts are available on GitHub (https://github.com/Gouti‐Lab/EPS‐Project (https://github.com/Gouti-Lab/EPS-Project)). Image analysis was carried out using FiJi, iLastik and python scripts. Code is available on GitHub (https://github.com/Gouti‐Lab/EPS‐Project (https://github.com/Gouti-Lab/EPS-Project)). The code used for size analysis and spontaneous contraction characterization in Python is available at https://github.com/HelmholtzAI‐Consultants‐Munich/NMOs‐Contraction (https://github.com/HelmholtzAI-Consultants-Munich/NMOs-Contraction). The programme for quantification of mechanobiological properties is available at https://github.com/enricoklotzsch/organoid_stress_relax/.

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, 13 authors, 7 keywords, 7 MeSH terms, 6 funders, 89 references.

Cite

This paper

Moysidou, C., Afonso Martins, I., El‐Shimy, I. A., Bicci, I., Cea, D., Bukas, C., Mekki, I., Rusu, M., Nebol, A., Lahmann, I., Piraud, M., Klotzsch, E., & Gouti, M. (2026). Enhancing Maturation of Human Neuromuscular Organoids via Electrical Stimulation. Advanced science (Weinheim, Baden-Wurttemberg, Germany), 13(50), e22762. https://doi.org/10.1002/advs.202522762

BibTeX

@article{moysidou2026enhancing,
author = {Moysidou, Chrysanthi‐Maria and Afonso Martins, Inês and El‐Shimy, Ismail Amr and Bicci, Iacopo and Cea, Donatella and Bukas, Christina and Mekki, Isra and Rusu, Mara‐Camelia and Nebol, Aylin and Lahmann, Ines and Piraud, Marie and Klotzsch, Enrico and Gouti, Mina},
title = {{Enhancing Maturation of Human Neuromuscular Organoids via Electrical Stimulation}},
journal = {Advanced science (Weinheim, Baden-Wurttemberg, Germany)},
year = {2026},
month = jun,
volume = {13},
number = {50},
pages = {e22762},
publisher = {Wiley},
issn = {2198-3844},
doi = {10.1002/advs.202522762},
url = {https://doi.org/10.1002/advs.202522762},
pmid = {42325128},
pmcid = {PMC13337066}
}

RIS

TY - JOUR
AU - Moysidou, Chrysanthi‐Maria
AU - Afonso Martins, Inês
AU - El‐Shimy, Ismail Amr
AU - Bicci, Iacopo
AU - Cea, Donatella
AU - Bukas, Christina
AU - Mekki, Isra
AU - Rusu, Mara‐Camelia
AU - Nebol, Aylin
AU - Lahmann, Ines
AU - Piraud, Marie
AU - Klotzsch, Enrico
AU - Gouti, Mina
TI - Enhancing Maturation of Human Neuromuscular Organoids via Electrical Stimulation
T2 - Advanced science (Weinheim, Baden-Wurttemberg, Germany)
J2 - Adv Sci (Weinh)
PY - 2026
DA - 2026/06/22
VL - 13
IS - 50
SP - e22762
SN - 2198-3844
PB - Wiley
DO - 10.1002/advs.202522762
UR - https://doi.org/10.1002/advs.202522762
LA - en
ER -

CSL-JSON

{
"id": "10.1002/advs.202522762",
"type": "article-journal",
"title": "Enhancing Maturation of Human Neuromuscular Organoids via Electrical Stimulation",
"container-title": "Advanced science (Weinheim, Baden-Wurttemberg, Germany)",
"author": [
{
"family": "Moysidou",
"given": "Chrysanthi‐Maria"
},
{
"family": "Afonso Martins",
"given": "Inês"
},
{
"family": "El‐Shimy",
"given": "Ismail Amr"
},
{
"family": "Bicci",
"given": "Iacopo"
},
{
"family": "Cea",
"given": "Donatella"
},
{
"family": "Bukas",
"given": "Christina"
},
{
"family": "Mekki",
"given": "Isra"
},
{
"family": "Rusu",
"given": "Mara‐Camelia"
},
{
"family": "Nebol",
"given": "Aylin"
},
{
"family": "Lahmann",
"given": "Ines"
},
{
"family": "Piraud",
"given": "Marie"
},
{
"family": "Klotzsch",
"given": "Enrico"
},
{
"family": "Gouti",
"given": "Mina"
}
],
"container-title-short": "Adv Sci (Weinh)",
"volume": "13",
"issue": "50",
"page": "e22762",
"DOI": "10.1002/advs.202522762",
"PMID": "42325128",
"PMCID": "PMC13337066",
"ISSN": "2198-3844",
"publisher": "Wiley",
"URL": "https://doi.org/10.1002/advs.202522762",
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
22
]
]
}
}

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/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: Subread (featureCounts), SAMtools, DESeq2, 12 other tools
[2] doi:10.1016/j.xcrm.2026.102766 [code]
A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.
Journal: Cell reports. Medicine
In common: imageio, tifffile, DESeq2, 12 other tools
[3] doi:10.1371/journal.pcbi.1014571 [code]
SynAPSeg: A novel dataset and image analysis framework for deep learning-based synapse detection and quantification.
Journal: PLoS computational biology
In common: Cellpose, imageio, tifffile, 8 other tools, 2 references
[4] doi:10.1038/s41467-026-71458-0 [code]
Early differential impact of MeCP2 mutations on functional networks in Rett syndrome patient-derived human cortical organoids.
Journal: Nature communications
In common: Cellpose, tifffile, pheatmap, 7 other tools, 2 references
[5] doi:10.1093/bioinformatics/btag592 [code]
Network-based stratification of allele-specific expression reveals patient subgroups in Huntington's disease.
Journal: Bioinformatics (Oxford, England)
In common: Subread (featureCounts), SAMtools, DESeq2, 9 other tools
[6] doi:10.1093/neuonc/noag128 [code]
Spatially-resolved single-cell imaging of melanoma brain metastases identifies localized immune patterns predictive of immune checkpoint blockade response.
Journal: Neuro-oncology
In common: Cellpose, imageio, tifffile, 8 other tools
[7] doi:10.1073/pnas.2609132123 [code]
A human lysosomal storage disorder toolkit for decoding proteome landscapes in cortical-like and dopaminergic-like induced neurons.
Journal: Proceedings of the National Academy of Sciences of the United States of America
In common: Cellpose, tifffile, pheatmap, 9 other tools
[8] doi:10.1038/s41467-026-71803-3 [code]
Charting the transition from in vitro gliogenesis to the in vivo maturation of human glial progenitor cells transplanted into the hypomyelinated mouse brain.
Journal: Nature communications
In common: SAMtools, DESeq2, pheatmap, 9 other tools
[9] doi:10.1186/s11689-026-09713-0 [code]
DRP1 mutations associated with EMPF1 encephalopathy perturb the transcriptional profile and maturation of cortical neurons.
Journal: Journal of neurodevelopmental disorders
In common: tifffile, DESeq2, pheatmap, 9 other tools
[10] doi:10.1038/s42003-026-10063-9 [code]
Conserved Kir channel mechanisms governing intrinsic excitability in human and rodent parvalbumin neurons.
Journal: Communications biology
In common: Cellpose, tifffile, Plotly, 7 other tools, 1 reference

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.

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.