OSCR

IgLON5 autoimmune antibodies activate Tau via neuronal hyperactivity.

Code ↔ Paper

1 match 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 1 match
  1. [1] § MATERIALS AND METHODS › RNA sequencing ↔ 250327_publication.Rmd, lines 416–550 · score 0.72 · fold change, DESeq2, shrinkage, IHW, apeglm, threshold

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,350 lines · 48 KB · LGPL-3.0 · 1 match

  1. ---
  2. title: "DESeq2 RNA-seq Analysis"
  3. author: " Pia Grundschoettel"
  4. date: "17.04.2025"
  5. output:
  6. html_document:
  7. toc: true
  8. toc_float: true
  9. ---
  10. # 1. R requirements
  11. ## 1.1 Install and load packages
  12. ### Install CRAN
  13. ```{r}
  14. # CRAN packages
  15. list.of.packages <- c("apeglm",
  16. "factoextra",
  17. "ggbeeswarm",
  18. "ggplot2",
  19. "ggrepel",
  20. "gplots",
  21. "hexbin",
  22. "Hmisc",
  23. "openxlsx",
  24. "patchwork",
  25. "plotly",
  26. "reshape2",
  27. "scales",
  28. "tidyr",
  29. # "VennDiagram",
  30. "UpSetR",
  31. "rstatix",
  32. "ggExtra",
  33. "multcomp"
  34. # "RANN",
  35. # "igraph",
  36. # "leidenbase"
  37. )
  38. new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
  39. if(length(new.packages)>0) install.packages(new.packages)
  40. ```
  41. ### Install BioConductor
  42. ```{r}
  43. # BioconductoR packages
  44. list.of.bioc.packages <- c("biomaRt",
  45. "clusterProfiler",
  46. "ComplexHeatmap",
  47. "DESeq2",
  48. "DOSE",
  49. "genefilter",
  50. "ggpubr",
  51. "GSEABase",
  52. "GSVA",
  53. "IHW",
  54. "limma",
  55. "org.Hs.eg.db",
  56. "pheatmap",
  57. "RColorBrewer",
  58. "rhdf5",
  59. # "sva",
  60. "tximport"
  61. # "vsn",
  62. # "Seurat",
  63. # "SeuratDisk"
  64. )
  65. new.packages.bioc <- list.of.bioc.packages[!(list.of.bioc.packages %in% installed.packages()[,"Package"])]
  66. if(length(new.packages.bioc)>0) if (!requireNamespace("BiocManager")) install.packages("BiocManager")
  67. BiocManager::install(new.packages.bioc, update = FALSE)
  68. ```
  69. ### Load Packages
  70. ```{r load packages, results='hide',message=FALSE,warning=FALSE}
  71. lapply(c(list.of.packages,list.of.bioc.packages), require, character.only = TRUE)
  72. ```
  73. ```{r}
  74. rm(list.of.packages,list.of.bioc.packages, new.packages, new.packages.bioc)
  75. ```
  76. ## 1.2 Functions used
  77. ### TX import
  78. ```{r}
  79. ### TX import
  80. tx_import <- function(file,
  81. aligner = c("STAR", "Kallisto")) {
  82. if(aligner == "STAR") {
  83. tx <- read.delim(file = file,
  84. header = F ,
  85. stringsAsFactors = F,
  86. col.names = c("GENEID", "SYMBOL", "GENETYPE"))
  87. } else if(aligner == "Kallisto") {
  88. tx <- read.delim(file = file,
  89. header = F ,
  90. stringsAsFactors = F,
  91. col.names = c("GENEID", "TXNAME", "SYMBOL", "GENETYPE"))
  92. } else {print("Unknown aligner - plase choose STAR or Kallisto")}
  93. return(tx)
  94. }
  95. ```
  96. ### Generate norm_anno
  97. ```{r}
  98. generate_norm_anno <- function(dds_object = dds,
  99. annotation_file = tx_annotation){
  100. norm_anno <- as.data.frame(counts(dds_object, normalized=T))
  101. norm_anno$GENEID <- row.names(norm_anno)
  102. # add gene annotation
  103. gene_annotation <- annotation_file[!duplicated(annotation_file$GENEID), c("GENEID", "SYMBOL", "GENETYPE")]
  104. # merge expression table and annotation
  105. norm_anno <- dplyr::left_join(norm_anno, gene_annotation, by = "GENEID")
  106. rownames(norm_anno) <- norm_anno$GENEID
  107. return(norm_anno)
  108. }
  109. ```
  110. ### Boxplot of normalized expression per sample
  111. ```{r}
  112. boxplot_norm <- function(norm_anno = norm_anno,
  113. col.by = "condition",
  114. col.use = col_condition){
  115. # create a sample table just taking the sample ID and condition for boxplot visualization
  116. box_sample_table <- sample_table[ ,c("ID", col.by)]
  117. # annotation
  118. box_norm_table <- norm_anno[ ,colnames(norm_anno) %in% box_sample_table$ID]
  119. box_norm_table$GENEID <- rownames(box_norm_table)
  120. # restructuring the table for ggplot2 analysis w/ melt function
  121. box_norm_table <- melt(box_norm_table, id.vars = c("GENEID"))
  122. colnames(box_norm_table) <- c("GENEID","sample","expression")
  123. box_norm_table <- merge(box_norm_table, box_sample_table, by.x="sample", by.y="ID")
  124. p <- ggplot(box_norm_table, aes(x = sample , y = expression+1))+
  125. geom_boxplot(aes_string(fill = col.by))+
  126. scale_y_log10(labels = scales::label_number(big.mark = ","))+
  127. # scale_y_continuous() +
  128. scale_fill_manual(values = col.use)+
  129. theme_bw() +
  130. theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))+
  131. xlab("Samples") + ylab("Normalized expression") +
  132. ggtitle("Normalized gene expression per sample")
  133. plot(p)
  134. }
  135. ```
  136. ### Generate norm_anno
  137. ```{r}
  138. generate_vst_anno <- function(dds_object = dds_vst,
  139. annotation_file = tx_annotation){
  140. # get gene annotation
  141. gene_annotation <- annotation_file[!duplicated(annotation_file$GENEID), c("GENEID", "SYMBOL", "GENETYPE")]
  142. # vst anno log
  143. vst_anno_log <- as.data.frame(assay(dds_object))
  144. vst_anno_log$GENEID <- row.names(vst_anno_log)
  145. vst_anno_log <- dplyr::left_join(vst_anno_log, gene_annotation, by = "GENEID")
  146. rownames(vst_anno_log) <- vst_anno_log$GENEID
  147. # vst anno (unlog)
  148. vst_anno <- as.data.frame(assay(dds_object))
  149. vst_anno <- 2^vst_anno
  150. vst_anno$GENEID <- row.names(vst_anno)
  151. vst_anno <- dplyr::left_join(vst_anno, gene_annotation, by = "GENEID")
  152. rownames(vst_anno) <- vst_anno$GENEID
  153. vst_anno <- list("log" = vst_anno_log,
  154. "unlog" = vst_anno)
  155. return(vst_anno)
  156. }
  157. ```
  158. ### Heatmap
  159. ```{r}
  160. plotHeatmap <- function(input = norm_anno,
  161. geneset = "all",
  162. title = "",
  163. keyType = "Ensembl",
  164. gene_type = "all",
  165. cutree_cols = 1,
  166. show_rownames = FALSE,
  167. cluster_cols = FALSE,
  168. sample_annotation = sample_table,
  169. plot_mean = FALSE,
  170. method = "complete",
  171. distance = "euclidean")
  172. {
  173. if (geneset[1] != "all") {
  174. if (keyType == "Ensembl") {
  175. input <- input[input$GENEID %in% geneset, ]
  176. }
  177. else if (keyType == "Symbol") {
  178. input <- input[input$SYMBOL %in% geneset, ]
  179. }
  180. else {
  181. print("Wrong keyType. Choose Ensembl or Symbol!")
  182. }
  183. }
  184. if (gene_type != "all") {
  185. input <- input[input$GENETYPE %in% gene_type, ]
  186. }
  187. rownames(input) <- paste(input$GENEID, ":", input$SYMBOL, sep = "")
  188. if(plot_mean == FALSE ){
  189. input <- input[ , colnames(input) %in% sample_annotation$ID]
  190. input_scale <- t(scale(t(input)))
  191. input_scale <- input_scale[, order(sample_annotation[[plot_order]], decreasing = FALSE)]
  192. column_annotation <- plot_annotation
  193. } else {
  194. input <- input[ , colnames(input) %in% plot_annotation_mean$condition]
  195. input_scale <- t(scale(t(input)))
  196. column_annotation <- plot_annotation_mean
  197. }
  198. breaks <- scaleColors(data = input_scale, maxvalue = 2)[["breaks"]]
  199. pheatmap(input_scale, main = as.character(title),
  200. show_rownames = show_rownames,
  201. show_colnames = TRUE,
  202. cluster_cols = cluster_cols,
  203. clustering_method = method,
  204. clustering_distance_rows = distance,
  205. clustering_distance_cols = distance,
  206. fontsize = 7,
  207. cutree_cols = cutree_cols,
  208. border_color = "NA",
  209. annotation_col = column_annotation,
  210. annotation_colors = ann_colors,
  211. breaks = breaks,
  212. color = scaleColors(data = input_scale, maxvalue = 2)[["color"]])
  213. }
  214. ```
  215. ### Heatmap colors
  216. ```{r}
  217. scaleColors <- function(data = input_scale, # data to use
  218. maxvalue = NULL # value at which the color is fully red / blue
  219. ){
  220. if(is.null(maxvalue)){
  221. maxvalue <- floor(min(abs(min(data)), max(data)))
  222. }
  223. if(max(data) > abs(min(data))){
  224. if(ceiling(max(data)) == maxvalue){
  225. myBreaks <- c(floor(-max(data)), seq(-maxvalue+0.2, maxvalue-0.2, 0.2), ceiling(max(data)))
  226. } else{
  227. myBreaks <- c(floor(-max(data)), seq(-maxvalue, maxvalue, 0.2), ceiling(max(data)))
  228. }
  229. paletteLength <- length(myBreaks)
  230. myColor <- colorRampPalette(c("blue", "white", "red"))(paletteLength)
  231. } else {
  232. if(-floor(min(data)) == maxvalue){
  233. myBreaks <- c(floor(min(data)), seq(-maxvalue+0.2, maxvalue-0.2, 0.2), ceiling(min(data)))
  234. } else{
  235. myBreaks <- c(floor(min(data)), seq(-maxvalue, maxvalue, 0.2), ceiling(abs(min(data))))
  236. }
  237. paletteLength <- length(myBreaks)
  238. myColor <- colorRampPalette(c("blue", "white", "red"))(paletteLength)
  239. }
  240. ret <- list(breaks = myBreaks, color = myColor)
  241. return(ret)
  242. }
  243. ```
  244. ### PCA function
  245. ```{r}
  246. plotPCA <- function(pca_input = dds_vst,
  247. pca_sample_table = sample_table,
  248. ntop=500,
  249. xPC=1,
  250. yPC=2,
  251. color,
  252. anno_colour,
  253. add_density = T,
  254. add_silhouette = T,
  255. split_by = "NULL",
  256. shape="NULL",
  257. point_size=3,
  258. title="PCA",
  259. label = NULL,
  260. label_subset = NULL){
  261. if(is.character(pca_input)){
  262. vst_matrix <- as.matrix(removedbatch_dds_vst)
  263. }else if(!is.data.frame(pca_input)){
  264. vst_matrix <- as.matrix(assay(pca_input))
  265. }else{
  266. vst_matrix <- pca_input
  267. }
  268. if(length(ntop)>1){
  269. pca <- prcomp(t(vst_matrix[dimnames(vst_matrix)[[1]] %in% ntop,]))
  270. }else if (ntop == "all"){
  271. pca <- prcomp(t(vst_matrix))
  272. }else{
  273. # select the ntop genes by variance
  274. select <- order(rowVars(vst_matrix), decreasing=TRUE)[c(1:ntop)]
  275. pca <- prcomp(t(vst_matrix[select,]))
  276. }
  277. #calculate explained variance per PC
  278. explVar <- pca$sdev^2/sum(pca$sdev^2)
  279. # transform variance to percent
  280. percentVar <- round(100 * explVar[c(xPC,yPC)], digits=1)
  281. # Define data for plotting
  282. pcaData <- data.frame(xPC=pca$x[,xPC],
  283. yPC=pca$x[,yPC],
  284. color = pca_sample_table[[color]],
  285. name= as.character(pca_sample_table$ID),
  286. stringsAsFactors = F)
  287. #plot PCA
  288. if(is.factor(pcaData$color) || is.character(pcaData$color)|| is.integer(pcaData$color)){
  289. if(shape == "NULL"){
  290. pca_plot <- ggplot(pcaData, aes(x = xPC, y = yPC, colour=color)) +
  291. geom_point(size =point_size)
  292. }else{
  293. pcaData$shape = pca_sample_table[[shape]]
  294. pca_plot <- ggplot(pcaData, aes(x = xPC, y = yPC, color = color, shape=shape)) +
  295. geom_point(size =point_size) +
  296. scale_shape_discrete(name=shape)
  297. }
  298. if(add_silhouette){
  299. pca_plot <- pca_plot + stat_ellipse(geom = "polygon", aes(fill = color), alpha = 0.05)
  300. }
  301. if(anno_colour[1] == "NULL"){
  302. pca_plot <- pca_plot + scale_color_discrete(name=color)
  303. }else{
  304. pca_plot <- pca_plot + scale_color_manual(values=anno_colour, name=color, aesthetics = c("colour", "fill"))
  305. }
  306. }else if(is.numeric(pcaData$color)){
  307. if(shape == "NULL"){
  308. pca_plot <- ggplot(pcaData, aes(x = xPC, y = yPC, colour=color)) +
  309. geom_point(size =point_size) +
  310. scale_color_gradientn(colours = bluered(100),name=color) +
  311. scale_fill_gradientn(colours = bluered(100),name=color)
  312. }else{
  313. pcaData$shape = pca_sample_table[[shape]]
  314. pca_plot <- ggplot(pcaData, aes(x = xPC, y = yPC, colour=color, shape=shape)) +
  315. geom_point(size =point_size) +
  316. scale_color_gradientn(colours = bluered(100),name=color) +
  317. scale_fill_gradientn(colours = bluered(100),name=color) +
  318. scale_shape_discrete(name=shape)
  319. }
  320. }
  321. # adds a label to the plot. To label only specific points, put them in the arument label_subset
  322. if (!is.null(label) == TRUE){
  323. pcaData$label <- pca_sample_table[[label]]
  324. if(!is.null(label_subset) == TRUE){
  325. pcaData_labeled <- pcaData[pcaData$label %in% label_subset,]
  326. } else {
  327. pcaData_labeled <- pcaData
  328. }
  329. pca_plot <- pca_plot +
  330. geom_text_repel(data = pcaData_labeled, aes(label = label), nudge_x = 2, nudge_y = 2, colour = "black")
  331. }
  332. pca_plot <- pca_plot+
  333. xlab(paste0("PC ",xPC, ": ", percentVar[1], "% variance")) +
  334. ylab(paste0("PC ",yPC,": ", percentVar[2], "% variance")) +
  335. coord_fixed()+
  336. theme_bw()+
  337. theme(aspect.ratio = 1,
  338. legend.position = "bottom")+
  339. ggtitle(title)
  340. if(add_density){
  341. ggMarginal(pca_plot, groupFill = T, type = "density")
  342. } else if (split_by != "NULL"){
  343. pca_plot + facet_wrap(~pca_sample_table[[split_by]])
  344. } else {
  345. pca_plot
  346. }
  347. }
  348. ```
  349. ### Wrapper Function to perform DESeq2 differential testing
  350. ```{r}
  351. DEAnalysis <- function(input = dds,
  352. condition,
  353. comparison_table = comparison_table,
  354. alpha = 0.05,
  355. lfcThreshold = 0,
  356. sigFC = 2,
  357. multiple_testing = "IHW",
  358. pAdjustMethod = "BH",
  359. independentFiltering= TRUE,
  360. shrinkage = TRUE,
  361. shrinkType = "normal"){
  362. setClass(Class = "DESeq2_analysis_object",
  363. slots = c(results="data.frame", DE_genes="list", Number_DE_genes="list"))
  364. # create results_list
  365. results_list <- list()
  366. # print parameters
  367. results_list$parameters <-list(multiple_testing = multiple_testing,
  368. p_value_threshold = alpha,
  369. log2_FC_threshold = lfcThreshold,
  370. sigFC = sigFC,
  371. shrinkage = shrinkage,
  372. shrinkage_type = shrinkType)
  373. # Run results() function on comparisons defined in comparison table
  374. for (x in 1:nrow(comparison_table)){
  375. # create DE_object
  376. DE_object <- new(Class = "DESeq2_analysis_object")
  377. # IHW
  378. if (multiple_testing=="IHW") {
  379. res_deseq_lfc <- results(input,
  380. contrast = c(condition,
  381. paste(comparison_table$comparison[x]),
  382. paste(comparison_table$control[x])),
  383. lfcThreshold = lfcThreshold,
  384. alpha = alpha,
  385. filterFun = ihw,
  386. pAdjustMethod = pAdjustMethod,
  387. altHypothesis = "greaterAbs")
  388. # Independent Filtering
  389. }else {
  390. res_deseq_lfc <- results(input,
  391. contrast = c(condition,
  392. paste(comparison_table$comparison[x]),
  393. paste(comparison_table$control[x])),
  394. lfcThreshold = lfcThreshold,
  395. alpha = alpha,
  396. independentFiltering = independentFiltering,
  397. altHypothesis = "greaterAbs",
  398. pAdjustMethod= pAdjustMethod)
  399. }
  400. if(shrinkage == TRUE){
  401. if(shrinkType %in% c("normal", "ashr")){
  402. res_deseq_lfc <- lfcShrink(input,
  403. contrast = c(condition,
  404. paste(comparison_table$comparison[x]),
  405. paste(comparison_table$control[x])),
  406. res=res_deseq_lfc,
  407. type = shrinkType)
  408. }else if(shrinkType == "apeglm"){
  409. res_deseq_lfc <- lfcShrink(input,
  410. coef = paste0(condition, "_",
  411. comparison_table$comparison[x], "_vs_",
  412. comparison_table$control[x]),
  413. res=res_deseq_lfc,
  414. type = shrinkType,
  415. returnList = F)
  416. }
  417. }
  418. res_deseq_lfc <- as.data.frame(res_deseq_lfc)
  419. # indicate significant DE genes
  420. res_deseq_lfc$regulation <- ifelse(!is.na(res_deseq_lfc$padj)&
  421. res_deseq_lfc$padj <= alpha&
  422. res_deseq_lfc$log2FoldChange > log(sigFC,2),
  423. "up",
  424. ifelse(!is.na(res_deseq_lfc$padj)&
  425. res_deseq_lfc$padj <= alpha&
  426. res_deseq_lfc$log2FoldChange < -log(sigFC,2),
  427. "down",
  428. "n.s."))
  429. # add gene annotation to results table
  430. res_deseq_lfc$GENEID <- row.names(res_deseq_lfc)
  431. res_deseq_lfc <- merge(res_deseq_lfc,
  432. norm_anno[,c("GENEID",
  433. "SYMBOL",
  434. "GENETYPE")],
  435. by = "GENEID")
  436. row.names(res_deseq_lfc) <- res_deseq_lfc$GENEID
  437. res_deseq_lfc$comparison<-paste(comparison_table$comparison[x]," vs ",comparison_table$control[x],
  438. sep="")
  439. # re-order results table
  440. if (multiple_testing=="IHW") {
  441. res_deseq_lfc<-res_deseq_lfc[,c("GENEID",
  442. "SYMBOL",
  443. "GENETYPE",
  444. "comparison",
  445. "regulation",
  446. "baseMean",
  447. "log2FoldChange",
  448. "lfcSE",
  449. "pvalue",
  450. "padj"
  451. )]
  452. }else{
  453. res_deseq_lfc<-res_deseq_lfc[,c("GENEID",
  454. "SYMBOL",
  455. "GENETYPE",
  456. "comparison",
  457. "regulation",
  458. "baseMean",
  459. "log2FoldChange",
  460. "lfcSE",
  461. "pvalue",
  462. "padj")]
  463. }
  464. # print result table
  465. DE_object@results <- res_deseq_lfc
  466. # print DE genes in separate tables
  467. DE_object@DE_genes <- list(up_regulated_Genes = res_deseq_lfc[res_deseq_lfc$regulation =="up",],
  468. down_regulated_Genes= res_deseq_lfc[res_deseq_lfc$regulation =="down",])
  469. # print the numbers of DE genes
  470. DE_object@Number_DE_genes <- list(up_regulated_Genes = nrow(DE_object@DE_genes$up_regulated_Genes),
  471. down_regulated_Genes= nrow(DE_object@DE_genes$down_regulated_Genes))
  472. # write DE_object into results_list
  473. results_list[[paste(comparison_table$comparison[x], "vs", comparison_table$control[x], sep="_")]] <- DE_object
  474. }
  475. return(results_list)
  476. }
  477. ```
  478. ### Venn Diagram
  479. ```{r}
  480. plotVenn <- function(comparisons,
  481. regulation=NULL){
  482. venn <- NULL
  483. for(i in 1:length(comparisons)){
  484. res <- DEresults[names(DEresults) %in% comparisons]
  485. comp <- as.data.frame(res[[i]]@results)
  486. if(is.null(regulation)){
  487. DE <- ifelse(comp$regulation %in% c("up","down"), 1, 0)
  488. venn <- cbind(venn, DE)
  489. colnames(venn)[i]<- paste(names(res)[[i]], "up&down", sep=": ")
  490. } else {
  491. DE <- ifelse(comp$regulation == regulation, 1, 0)
  492. venn <- cbind(venn, DE)
  493. colnames(venn)[i]<- paste(names(res)[[i]], regulation, sep=": ")
  494. }
  495. }
  496. vennDiagram(venn,cex = 1, counts.col = "blue")
  497. }
  498. ```
  499. ### GSEA function
  500. ```{r}
  501. #' wrapper function for GSEA on different DE calls
  502. #' @author Charlotte Kröger, Lisa Holsten, Kilian Dahm
  503. #' @param comparisons name of DE analysis comparisons (class: character)
  504. #' @param DE_results list object containing DE analysis results (class: list)
  505. #' @param universe vector of all genes included in the analysis
  506. #' @param GeneSets databases to be used, one of : 'GO', 'KEGG' or 'HALLMARK'
  507. #' @param ontology ontology of the GO database to be used, one of: 'BP', 'MF', 'CC'
  508. #' @param pCorrection p-value adjustment method such as 'BH' (less strict) or 'bonferroni'
  509. #' @param pvalueCutoff set the unadj. or adj. p-value cutoff (depending on correction method)
  510. #' @param qvalueCutoff set the q-value (adj. p-value) cutoff
  511. #'
  512. enrichGSEA <- function(comparisons,
  513. DE_results = DEresults,
  514. universe = universe,
  515. GeneSets = c("GO","KEGG", "HALLMARK", "REACTOME"),
  516. pCorrection = "bonferroni",
  517. pvalueCutoff = 0.05,
  518. qvalueCutoff = 0.05){
  519. ## Results lists
  520. GOresults.list <- list()
  521. KEGGresults.list <- list()
  522. HALLMARKresults.list <- list()
  523. REACTOMEresults.list <- list()
  524. ## Enrichment
  525. for(i in comparisons){
  526. print(paste0("Performing enrichment for ", i))
  527. ## DEGs
  528. genes <- DE_results[[i]]@results
  529. DE_up <- genes[genes$regulation=="up",]$SYMBOL
  530. DE_down <- genes[genes$regulation=="down",]$SYMBOL
  531. # Compare the Clusters regarding their GO enrichment
  532. if("GO" %in% GeneSets){
  533. print("Performing GO enrichment")
  534. resGOup <- as.data.frame(enricher(gene = DE_up,
  535. universe = universe,
  536. TERM2GENE= GO_terms,
  537. pAdjustMethod = pCorrection,
  538. pvalueCutoff = pvalueCutoff,
  539. qvalueCutoff = qvalueCutoff))
  540. if(nrow(resGOup)>0){
  541. resGOup$comparison <- paste0(as.character(i), "_up")
  542. resGOup$regulation <- "up"
  543. GOresults.list[[paste(i, "_up")]] <- resGOup
  544. }
  545. resGOdown <- as.data.frame(enricher(gene = DE_down,
  546. universe = universe,
  547. TERM2GENE= GO_terms,
  548. pAdjustMethod = pCorrection,
  549. pvalueCutoff = pvalueCutoff,
  550. qvalueCutoff = qvalueCutoff))
  551. if(nrow(resGOdown)>0){
  552. resGOdown$comparison <- paste0(as.character(i), "_down")
  553. resGOdown$regulation <- "down"
  554. GOresults.list[[paste(i, "_down")]] <- resGOdown
  555. }
  556. }
  557. # Compare the Clusters regarding their HALLMARK enrichment
  558. if("HALLMARK" %in% GeneSets){
  559. print("Performing HALLMARK enrichment")
  560. resHMup <- as.data.frame(enricher(gene = DE_up,
  561. universe = universe,
  562. TERM2GENE = HALLMARK_terms,
  563. pAdjustMethod = pCorrection,
  564. pvalueCutoff = pvalueCutoff,
  565. qvalueCutoff = qvalueCutoff))
  566. if(nrow(resHMup)>0){
  567. resHMup$comparison <- paste0(as.character(i), "_up")
  568. resHMup$regulation <- "up"
  569. HALLMARKresults.list[[paste(i, "_up")]] <- resHMup
  570. }
  571. resHMdown <- as.data.frame(enricher(gene = DE_down,
  572. universe = universe,
  573. TERM2GENE = HALLMARK_terms,
  574. pAdjustMethod = pCorrection,
  575. pvalueCutoff = pvalueCutoff,
  576. qvalueCutoff = qvalueCutoff))
  577. if(nrow(resHMdown)>0){
  578. resHMdown$comparison <- paste0(as.character(i), "_down")
  579. resHMdown$regulation <- "down"
  580. HALLMARKresults.list[[paste(i, "_down")]] <- resHMdown
  581. }
  582. }
  583. # Compare the Clusters regarding their KEGG enrichment
  584. if("KEGG" %in% GeneSets){
  585. print("Performing KEGG enrichment")
  586. resKEGGup <- as.data.frame(enricher(gene = DE_up,
  587. universe = universe,
  588. TERM2GENE = KEGG_terms,
  589. pAdjustMethod = pCorrection,
  590. pvalueCutoff = pvalueCutoff,
  591. qvalueCutoff = qvalueCutoff))
  592. if(nrow(resKEGGup)>0){
  593. resKEGGup$comparison <- paste0(as.character(i), "_up")
  594. resKEGGup$regulation <- "up"
  595. KEGGresults.list[[paste(i, "_up")]] <- resKEGGup
  596. }
  597. resKEGGdown <- as.data.frame(enricher(gene = DE_down,
  598. universe = universe,
  599. TERM2GENE = KEGG_terms,
  600. pAdjustMethod = pCorrection,
  601. pvalueCutoff = pvalueCutoff,
  602. qvalueCutoff = qvalueCutoff))
  603. if(nrow(resKEGGdown)>0){
  604. resKEGGdown$comparison <- paste0(as.character(i), "_down")
  605. resKEGGdown$regulation <- "down"
  606. KEGGresults.list[[paste(i, "_down")]] <- resKEGGdown
  607. }
  608. }
  609. # Compare the Clusters regarding their REACTOME enrichment
  610. if("REACTOME" %in% GeneSets){
  611. print("Performing REACTOME enrichment")
  612. resREACTOMEup <- as.data.frame(enricher(gene = DE_up,
  613. universe = universe,
  614. TERM2GENE = REACTOME_terms,
  615. pAdjustMethod = pCorrection,
  616. pvalueCutoff = pvalueCutoff,
  617. qvalueCutoff = qvalueCutoff))
  618. if(nrow(resREACTOMEup)>0){
  619. resREACTOMEup$comparison <- paste0(as.character(i), "_up")
  620. resREACTOMEup$regulation <- "up"
  621. REACTOMEresults.list[[paste(i, "_up")]] <- resREACTOMEup
  622. }
  623. resREACTOMEdown <- as.data.frame(enricher(gene = DE_down,
  624. universe = universe,
  625. TERM2GENE = REACTOME_terms,
  626. pAdjustMethod = pCorrection,
  627. pvalueCutoff = pvalueCutoff,
  628. qvalueCutoff = qvalueCutoff))
  629. if(nrow(resREACTOMEdown)>0){
  630. resREACTOMEdown$comparison <- paste0(as.character(i), "_down")
  631. resREACTOMEdown$regulation <- "down"
  632. REACTOMEresults.list[[paste(i, "_down")]] <- resREACTOMEdown
  633. }
  634. }
  635. }
  636. GOresults <- do.call("rbind", GOresults.list)
  637. HALLMARKresults <- do.call("rbind", HALLMARKresults.list)
  638. KEGGresults <- do.call("rbind", KEGGresults.list)
  639. REACTOMEresults <- do.call("rbind", REACTOMEresults.list)
  640. results.list <- list("GO" = GOresults,
  641. "HALLMARK" = HALLMARKresults,
  642. "KEGG" = KEGGresults,
  643. "REACTOME" = REACTOMEresults)
  644. return(results.list)
  645. }
  646. ```
  647. ### GSEA dotplot
  648. ```{r}
  649. #' wrapper function for combined dotplot representation of all comparisons used in the enrichGSEA function
  650. #' @author Charlotte Kröger, Lisa Holsten, Kilian Dahm
  651. #' @param enrich.df data frame of enrichGSEA function
  652. #' @param show number of terms to be shown per comparison
  653. #' @param orderBy parameter for ordering terms on the y-axis
  654. #' @param colorBy parameter for coloring the dots
  655. #' @param scaleBy parameter for scaling the dots
  656. #'
  657. dotplotGSEA <- function(enrich.df,
  658. show =10,
  659. orderBy = c("padj", "count", "GeneRatio"),
  660. colorBy = c("padj", "regulation"),
  661. scaleBy = c("count", "GeneRatio")
  662. ){
  663. if(nrow(enrich.df)<1){ print("No enrichment found.")
  664. } else{
  665. # ordering
  666. enrich.df$gene.ratio <- sapply(strsplit(enrich.df$GeneRatio, split = "/"), function(x) as.numeric(x[1]) / as.numeric(x[2]))
  667. if(orderBy=="padj"){
  668. enrich.df %>% group_by(comparison) %>% arrange(desc(Count), .by_group = TRUE) -> x
  669. x %>% group_by(comparison) %>% arrange(desc(Count), .by_group = TRUE) %>% dplyr::top_n(n = -show, wt = p.adjust) %>% dplyr::pull(Description) -> terms
  670. x <- x[x$Description %in% terms,]
  671. x$Description <- ifelse(nchar(x$Description)>80, paste(substr(x$Description, 1, 80),"[...]",sep=""), x$Description)
  672. x$Description <- factor(x$Description, levels = rev(unique(x$Description)))
  673. } else if (orderBy=="count"){
  674. enrich.df %>% group_by(comparison) %>% arrange(p.adjust, .by_group = TRUE) -> x
  675. x %>% group_by(comparison) %>% arrange(p.adjust, .by_group = TRUE) %>% dplyr::top_n(n = show, wt = Count) %>% dplyr::pull(Description) -> terms
  676. x <- x[x$Description %in% terms,]
  677. x$Description <- ifelse(nchar(x$Description) > 80, paste(substr(x$Description, 1, 80),"[...]",sep=""), x$Description)
  678. x$Description <- factor(x$Description, levels = rev(unique(x$Description)))
  679. } else if (orderBy=="GeneRatio"){
  680. enrich.df %>% group_by(comparison) %>% arrange(p.adjust, .by_group = TRUE) -> x
  681. x %>% group_by(comparison) %>% arrange(p.adjust, .by_group = TRUE) %>% dplyr::top_n(n = show, wt = gene.ratio) %>% dplyr::pull(Description) -> terms
  682. x <- x[x$Description %in% terms,]
  683. x$Description <- ifelse(nchar(x$Description) > 80, paste(substr(x$Description, 1, 80),"[...]",sep=""), x$Description)
  684. x$Description <- factor(x$Description, levels = rev(unique(x$Description)))
  685. }else {
  686. "Please select orderBy='padj', orderBy='count'or orderBy='GeneRatio'."
  687. }
  688. ## coloring
  689. if(colorBy=="regulation" & scaleBy == "count"){
  690. p <- ggplot(data = x ,aes(x=comparison, y=Description, size=Count , fill=regulation)) +
  691. geom_point(pch=21) +
  692. scale_fill_manual(values = c(up = "firebrick4", down = "dodgerblue3")) +
  693. xlab("") +
  694. ylab("") +
  695. scale_radius() +
  696. theme_linedraw()+
  697. theme(axis.text.y = element_text(color = "black"),
  698. axis.text.x = element_text(angle=90, vjust=0.5,hjust=1, color = "black"),
  699. text = element_text(size = 12),
  700. panel.grid.major = element_line(colour = "grey70"))
  701. plot(p)
  702. } else if (colorBy=="regulation" & scaleBy == "GeneRatio"){
  703. p <- ggplot(data = x ,aes(x=comparison, y=Description, size=gene.ratio , fill=regulation)) +
  704. geom_point(pch=21) +
  705. scale_fill_manual(values = c(up = "firebrick4", down = "dodgerblue3")) +
  706. xlab("") +
  707. ylab("") +
  708. scale_radius() +
  709. theme_linedraw()+
  710. theme(axis.text.y = element_text(color = "black"),
  711. axis.text.x = element_text(angle=90, vjust=0.5,hjust=1, color = "black"),
  712. text = element_text(size = 12),
  713. panel.grid.major = element_line(colour = "grey70"))
  714. plot(p)
  715. } else if (colorBy=="padj" & scaleBy=="count"){
  716. p <- ggplot(data = x, aes(x=comparison, y=Description, size=Count, color=p.adjust)) +
  717. geom_point(pch=21) +
  718. scale_colour_gradientn(colours = c('red', 'orange', 'darkblue', 'darkblue'),
  719. limits = c(0, 1),
  720. values = c(0, 0.05, 0.2, 0.5, 1),
  721. breaks = c(0.05, 0.2, 1),
  722. labels = format(c(0.05, 0.2, 1))) +
  723. xlab("") +
  724. ylab("") +
  725. scale_radius() +
  726. theme_linedraw()+
  727. theme(axis.text.y = element_text(color = "black"),
  728. axis.text.x = element_text(angle=90, vjust=0.5, hjust=1, color = "black"),
  729. text = element_text(size = 12),
  730. panel.grid.major = element_line(colour = "grey70"))
  731. plot(p)
  732. } else if (colorBy=="padj" & scaleBy=="GeneRatio"){
  733. p <- ggplot(data = x, aes(x=comparison, y=Description, size=gene.ratio, color=p.adjust)) +
  734. geom_point(pch=21) +
  735. scale_colour_gradientn(colours = c('red', 'orange', 'darkblue', 'darkblue'),
  736. limits = c(0, 1),
  737. values = c(0, 0.05, 0.2, 0.5, 1),
  738. breaks = c(0.05, 0.2, 1),
  739. labels = format(c(0.05, 0.2, 1))) +
  740. xlab("") +
  741. ylab("") +
  742. scale_radius() +
  743. theme_linedraw()+
  744. theme(axis.text.y = element_text(color = "black"),
  745. axis.text.x = element_text(angle=90, vjust=0.5,hjust=1, color = "black"),
  746. text = element_text(size = 12),
  747. panel.grid.major = element_line(colour = "grey70"))
  748. plot(p)
  749. }else {
  750. "Please select colorBy='regulation' or colorBy='padj' and scaleBy='count' or scaleBy='GeneRatio'."
  751. }
  752. }
  753. }
  754. ```
  755. ### Volcano Plot
  756. ```{r}
  757. plotVolcano <- function(DEresults_obj = DEresults,
  758. comparison,
  759. labelnum=20,
  760. y.max = NULL,
  761. signature = NULL){
  762. # specify labeling
  763. upDE <- as.data.frame(DEresults_obj[[comparison]]@results[DEresults_obj[[comparison]]@results$regulation =="up",])
  764. if(!is.null(signature))
  765. upDE <- upDE %>% dplyr::filter(.,SYMBOL %in% signature)
  766. FClabel_up <- upDE[order(abs(upDE$log2FoldChange), decreasing = TRUE),]
  767. if(nrow(FClabel_up)>labelnum){
  768. FClabel_up <- as.character(FClabel_up[c(1:labelnum),"GENEID"])
  769. } else {
  770. FClabel_up <- as.character(FClabel_up$GENEID)}
  771. plabel_up <- upDE[order(upDE$padj, decreasing = FALSE),]
  772. if(nrow(plabel_up)>labelnum){
  773. plabel_up <- as.character(plabel_up[c(1:labelnum),"GENEID"])
  774. } else {
  775. plabel_up <- as.character(plabel_up$GENEID)}
  776. downDE <- as.data.frame(DEresults_obj[[comparison]]@results[DEresults_obj[[comparison]]@results$regulation =="down",])
  777. if(!is.null(signature))
  778. downDE <- downDE %>% dplyr::filter(SYMBOL %in% signature)
  779. FClabel_down <- downDE[order(abs(downDE$log2FoldChange), decreasing = TRUE),]
  780. if(nrow(FClabel_down)>labelnum){
  781. FClabel_down <- as.character(FClabel_down[c(1:labelnum),"GENEID"])
  782. } else {
  783. FClabel_down <- as.character(FClabel_down$GENEID)}
  784. plabel_down <- downDE[order(downDE$padj, decreasing = FALSE),]
  785. if(nrow(plabel_down)>labelnum){
  786. plabel_down <- as.character(plabel_down[c(1:labelnum),"GENEID"])
  787. } else {
  788. plabel_down <- as.character(plabel_down$GENEID)}
  789. label<- unique(c(FClabel_up, plabel_up, FClabel_down, plabel_down))
  790. data <- DEresults_obj[[comparison]]@results
  791. data$label<- ifelse(data$GENEID %in% label == "TRUE",as.character(data$SYMBOL), "")
  792. data <- data[,colnames(data) %in% c("label", "log2FoldChange", "padj", "regulation")]
  793. data$color <- apply(data, 1, function(x){
  794. if(x["label"] != "") "black"
  795. else x["regulation"]
  796. }) %>% unlist()
  797. limits <- ceiling(max(DEresults_obj[[comparison]]@results$log2FoldChange))
  798. # Volcano Plot
  799. volcano <- ggplot(data=na.omit(data), aes(x=log2FoldChange, y=-log10(padj), fill=regulation, color = color)) +
  800. geom_point(shape = 21, alpha=0.75, size=1.75) +
  801. scale_color_manual(values = c(c("down" = "dodgerblue3","n.s." = "grey","up" = "firebrick", "black" = "black"))) +
  802. scale_fill_manual(values=c("down" = "dodgerblue3", "n.s." = "grey", "up" = "firebrick"))+
  803. xlab("log2(FoldChange)") +
  804. ylab("-log10(padj)") +
  805. geom_vline(xintercept = c(-log(DEresults_obj$parameters$sigFC,2),log(DEresults_obj$parameters$sigFC,2)), colour="darkgrey", linetype = "dashed")+
  806. geom_hline(yintercept=-log(0.05,10),colour="darkgrey", linetype = "dashed")+
  807. geom_text_repel(data=na.omit(data[!data$label =="",]),aes(label=label), size=3)+
  808. scale_x_continuous(limits = c(-(limits), limits), breaks = seq(-(limits), limits, by=1))+
  809. guides(color="none") +
  810. ggtitle(paste("Volcano Plot of: ",comparison,sep="")) +
  811. theme_bw() +
  812. theme(panel.grid.minor = element_blank())
  813. if(!is.null(y.max))
  814. volcano <- volcano +
  815. scale_y_continuous(limits = c(0, y.max), breaks = seq(0, y.max, by=1))
  816. else
  817. volcano <- volcano +
  818. scale_y_continuous()
  819. volcano
  820. }
  821. ```
  822. # 2. Project information
  823. ```{r}
  824. organism = "mouse"
  825. ```
  826. # 3. Data Import
  827. ## 3.1 Load gene annotation
  828. ```{r gene annotation import}
  829. tx_annotation <- tx_import(file = "/data/references/mouse/mm10/ID2SYMBOL_gencode_vM25.txt",
  830. aligner = "STAR")
  831. ```
  832. ## 3.2 Load gene set annotation
  833. ```{r}
  834. GO_terms <- read.gmt("/data/analysis/m5.go.bp.v2024.1.Mm.symbols.gmt")
  835. ```
  836. ## 3.3 Load sample table
  837. ```{r sample table import}
  838. # Import your sample table
  839. sample_table <- read.xlsx("/data/analysis/sample_table_final.xlsx")
  840. rownames(sample_table) <- sample_table$ID
  841. sample_table
  842. ```
  843. ### Format sample table
  844. ```{r colour definitions}
  845. unique(sample_table$condition)
  846. ## Add columns with factors for comparisons in model
  847. sample_table$condition <- factor(sample_table$condition,
  848. levels = c("crtx_PBS","crtx_IgG","crtx_LON5","hippo_PBS","hippo_IgG","hippo_LON5"))
  849. sample_table$tissue <- factor(sample_table$tissue,
  850. levels = c("crtx", "hippo"))
  851. sample_table$treat<- factor(sample_table$treat,
  852. levels = c("PBS", "IgG", "LON5"))
  853. sample_table$donor <- factor(sample_table$donor,
  854. levels= c("14", "32", "33", "38", "74", "10", "11", "15", "37", "75", "8", "9", "16", "17"))
  855. # define factor for order of samples in plotting
  856. plot_order <- c("condition")
  857. ```
  858. ### Colour scheme customization
  859. ```{r}
  860. col_condition <- c("#C2E0EB", "#83C5BE","#006D77", "#FFDDD2","#E29578", "#CA582B")
  861. names(col_condition) <- c("crtx_PBS","crtx_IgG","crtx_LON5","hippo_PBS","hippo_IgG","hippo_LON5")
  862. col_tissue <- c("#006D77", "#CA582B")
  863. names(col_tissue) <- c("crtx", "hippo")
  864. col_treatment <- c("#fefae0", "#dda15e","#bc6c25" )
  865. names(col_treatment) <- c("PBS", "IgG", "LON5")
  866. col_donor <- c("#155289", "#95AAD3", "#B9DBF4", "#B8E2DE", "#94C47D", "#F0CF7F", "#F6BF93","#EDAEAE", "#E07F80", "#780000", "#C195C4", "#9B5C97", "#C43E96", "grey")
  867. names(col_donor) <- c("14", "32", "33", "38", "74", "10", "11", "15", "37", "75", "8", "9", "16", "17")
  868. # combine color code into list
  869. ann_colors <- list(condition= col_condition,
  870. tissue = col_tissue,
  871. treat = col_treatment,
  872. donor = col_donor
  873. )
  874. ```
  875. ```{r}
  876. alignstat <-sample_table[ , c("ID", "uniquely_mapped","total_reads")]
  877. alignstat <-gather(alignstat, "total_reads", "uniquely_mapped", key = "type", value = "reads")
  878. ggplot(alignstat, aes(x = reorder(ID,-reads), y = reads, fill = type)) +
  879. geom_bar(stat = "identity", position = "dodge", colour = "black") +
  880. scale_y_continuous(labels = scales::label_number(big.mark = ",")) +
  881. scale_fill_manual(name = "", values = c("white", "grey")) +
  882. ylab("Number of reads") +
  883. xlab("Sample IDs") +
  884. geom_hline(yintercept=5 * 10^6, linetype="dashed", color = "red") +
  885. ggtitle("Total reads and uniquely mapped reads") +
  886. theme(axis.text.x = element_text(angle = 90, size = 9, hjust = 1, vjust = .5),
  887. strip.background = element_rect(fill = "white"),
  888. panel.background = element_rect(fill = "white", colour = "black"),
  889. legend.position = "bottom")
  890. rm(alignstat)
  891. ```
  892. ### QC
  893. ```{r qc sample exclusion}
  894. # define read cutoff
  895. samples_to_keep <- sample_table[sample_table$uniquely_mapped > 5000000,]$ID
  896. length(samples_to_keep)
  897. nrow(sample_table) - length(samples_to_keep)
  898. sample_table <- sample_table[which(sample_table$ID %in% samples_to_keep),]
  899. rownames(sample_table) <- sample_table$ID
  900. ```
  901. # 4. Import of count files
  902. ```{r}
  903. star.count <- read.table(file = "/data/analysis/count_matrix.tsv",
  904. row.names = 1,
  905. header = T,
  906. stringsAsFactors = F,
  907. check.names = F)
  908. star.count <- star.count[, colnames(star.count) %in% sample_table$ID]
  909. ```
  910. # 5. Building the DESeqDataSet
  911. ```{r}
  912. identical(as.character(rownames(sample_table)), as.character(colnames(star.count)))
  913. # Reorder the rows of the sample_table matrix if necessary (based on Occam's razor [least number of moves for reordering])
  914. sample_table <- sample_table[match(colnames(star.count), rownames(sample_table)),]
  915. dds_txi <- DESeqDataSetFromMatrix(countData = star.count,
  916. colData = sample_table,
  917. design = ~condition)
  918. rm(star.count)
  919. ```
  920. ## 5.1 Pre-filtering
  921. ```{r pre-filtering}
  922. genes_to_keep <- rowSums(counts(dds_txi) >= 10) >= min(table(sample_table$condition)) #number of donors and number of different input amounts
  923. table(genes_to_keep)
  924. dds <- dds_txi[genes_to_keep,]
  925. ```
  926. **Number of genes after filtering is:** `r sum(genes_to_keep) `
  927. ## 5.2 DESeq calculations
  928. ```{r DESeq calculation}
  929. dds <- DESeq(dds)
  930. ```
  931. ## 5.3 Normalized counts
  932. ```{r gene annotation}
  933. norm_anno <- generate_norm_anno(dds_object = dds)
  934. ```
  935. Boxplot of normalized samples
  936. ```{r, fig.height=5, fig.width=8}
  937. boxplot_norm(norm_anno = norm_anno,
  938. col.by = "condition",
  939. col.use = col_condition)
  940. ```
  941. ## 5.4 Variance stabilizing transformation
  942. ```{r varStab}
  943. if (nrow(colData(dds)) < 30) {
  944. dds_vst <- rlog(dds, blind = TRUE)
  945. } else dds_vst <- vst(dds, blind = TRUE)
  946. ```
  947. ```{r vst matrix}
  948. vst <- generate_vst_anno(dds_object = dds_vst)
  949. vst_anno_log <- vst$log
  950. vst_anno <- vst$unlog
  951. ncol(vst_anno_log)
  952. nrow(sample_table)
  953. vst_anno_log[1:3,c(1:2, (ncol(vst_anno_log)-5):ncol(vst_anno_log))]
  954. vst_anno[1:3,c(1:2, (ncol(vst_anno)-5):ncol(vst_anno))]
  955. ```
  956. # 6. Exploratory Data Analysis
  957. ```{r}
  958. # choose columns from the sample table for the heatmap annotation
  959. plot_annotation <- sample_table[ , c("condition",
  960. "donor",
  961. "treat",
  962. "tissue"),
  963. drop = F]
  964. rownames(plot_annotation) <- sample_table$ID
  965. ```
  966. ## 6.2 Principle Component Analysis
  967. ### Supplementary Figure S3 i
  968. ```{r, fig.width=6, fig.height=5}
  969. plotPCA(ntop = "all",
  970. xPC = 1,
  971. yPC = 2,
  972. color = "condition",
  973. anno_colour = col_condition,
  974. shape = "input",
  975. point_size = 3,
  976. add_density = F,
  977. add_silhouette = F,
  978. label = NULL,
  979. title ="Condition")
  980. ```
  981. # 7. Differential Expression Analysis
  982. ```{r}
  983. comparison_table <- data.frame(control = c("crtx_PBS" ,"crtx_PBS" ,"crtx_IgG" , "hippo_PBS", "hippo_PBS", "hippo_IgG"),
  984. comparison = c("crtx_IgG" , "crtx_LON5", "crtx_LON5","hippo_IgG", "hippo_LON5", "hippo_LON5" ))
  985. ```
  986. ```{r}
  987. dds_dea <- dds
  988. DEresults_list <- list()
  989. for (i in unique(comparison_table$control)) {
  990. print(i)
  991. dds_dea$condition <- relevel(dds_dea$condition, i)
  992. dds_dea <- nbinomWaldTest(object = dds_dea)
  993. comparison_table_subset <- comparison_table[comparison_table$control == i, ]
  994. DEresults <- DEAnalysis(input = dds_dea,
  995. comparison_table = comparison_table_subset,
  996. condition = "condition",
  997. alpha = 0.05 ,
  998. lfcThreshold = 0,
  999. sigFC = 2,
  1000. multiple_testing = "IHW",
  1001. pAdjustMethod = "BH",
  1002. shrinkage = TRUE,
  1003. shrinkType = "apeglm")
  1004. DEresults_list <- c(DEresults_list, DEresults)
  1005. }
  1006. DEresults <- DEresults_list[unique(names(DEresults_list))]
  1007. ```
  1008. ### Summary of DE genes
  1009. #### Figure 3 j
  1010. ```{r, fig.height=3, fig.width=6}
  1011. DEcounts <- NULL
  1012. for(i in 1:nrow(comparison_table)){
  1013. tmp <- unlist(DEresults[[1+i]]@Number_DE_genes)
  1014. DEcounts <- rbind(DEcounts, tmp)
  1015. }
  1016. rownames(DEcounts) <- names(DEresults)[-1]
  1017. DEcounts
  1018. DEcounts_melt <- reshape2::melt(DEcounts)
  1019. # ggplot(DEcounts_melt, aes(x = Var1, fill = Var2)) +
  1020. # geom_col(aes(y = value), position = "dodge", color = "black") +
  1021. # geom_text(aes(label = value, y = value), position = position_dodge(.9), hjust=1) +
  1022. # theme_bw()+
  1023. # theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = .5)) +
  1024. # scale_fill_manual(values = c("up_regulated_Genes" = "firebrick", "down_regulated_Genes" = "cornflowerblue")) +
  1025. # guides(fill = guide_legend(title = "Mode of regulation")) +
  1026. # xlab("Comparison") + ylab("Number of DEGs") + coord_flip()
  1027. ggplot(DEcounts_melt[DEcounts_melt$Var1 %in% c("hippo_IgG_vs_hippo_PBS", "hippo_LON5_vs_hippo_PBS", "hippo_LON5_vs_hippo_IgG"),], aes(x = Var1, fill = Var2)) +
  1028. geom_col(aes(y = value), position = "dodge", color = "black") +
  1029. geom_text(aes(label = value, y = value), position = position_dodge(.9), hjust=1) +
  1030. theme_bw()+
  1031. theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = .5)) +
  1032. scale_fill_manual(values = c("up_regulated_Genes" = "firebrick", "down_regulated_Genes" = "cornflowerblue")) +
  1033. guides(fill = guide_legend(title = "Mode of regulation")) +
  1034. xlab("Comparison") + ylab("Number of DEGs") + coord_flip()
  1035. ```
  1036. ### Upset Plot
  1037. #### Supplementary Figure S3 k
  1038. ```{r}
  1039. list_up <- list()
  1040. list_down <- list()
  1041. for(i in 1:nrow(comparison_table)){
  1042. comp <- paste0(comparison_table[i,2], "_vs_", comparison_table[i,1])
  1043. list_up[[paste0(comp, "_up")]] <- DEresults[[comp]]@DE_genes[["up_regulated_Genes"]][["SYMBOL"]]
  1044. list_down[[paste0(comp, "_down")]] <- DEresults[[comp]]@DE_genes[["down_regulated_Genes"]][["SYMBOL"]]
  1045. }
  1046. upset(fromList(list_up), nsets = 10,nintersects = 100, keep.order = F, sets.bar.color = "firebrick")
  1047. upset(fromList(list_down), nsets = 10,nintersects = 100, keep.order = F, sets.bar.color = "dodgerblue")
  1048. ```
  1049. ## 7.2 General DE Gene analysis
  1050. ### Venn diagrams
  1051. #### Supplementary Figure S3 j
  1052. ```{r, fig.height=6, fig.width=6}
  1053. # plotVenn(comparisons = c("hippo_LON5_vs_hippo_IgG","hippo_LON5_vs_hippo_PBS", "crtx_LON5_vs_crtx_IgG", "crtx_LON5_vs_crtx_PBS"),
  1054. # regulation ="up")
  1055. plotVenn(comparisons = c("hippo_LON5_vs_hippo_IgG", "crtx_LON5_vs_crtx_IgG"),
  1056. regulation ="up")
  1057. plotVenn(comparisons = c("hippo_LON5_vs_hippo_PBS", "crtx_LON5_vs_crtx_PBS"),
  1058. regulation ="up")
  1059. ```
  1060. ### Gene Set Enrichment of DE genes
  1061. ```{r}
  1062. # define universe
  1063. universe <- unique(as.character(norm_anno$SYMBOL))
  1064. ```
  1065. ```{r, warnings=FALSE, message=FALSE}
  1066. GSEA_results <- enrichGSEA(comparisons = "hippo_LON5_vs_hippo_IgG",
  1067. DE_results = DEresults,
  1068. universe = universe,
  1069. GeneSets = c("GO"),#, "HALLMARK", "REACTOME"
  1070. pCorrection = "bonferroni",
  1071. pvalueCutoff = 0.05,
  1072. qvalueCutoff = 0.05)
  1073. ```
  1074. ```{r}
  1075. GSEA_results$GO$comparison <-
  1076. factor(GSEA_results$GO$comparison,
  1077. levels = c(unique(GSEA_results$GO$comparison)))
  1078. ```
  1079. Figure 3 l
  1080. ```{r, fig.height=6, fig.width=15}
  1081. dotplotGSEA(enrich.df = GSEA_results$GO, show = 20, orderBy = "padj", colorBy = "regulation", scaleBy = "count")
  1082. ```
  1083. ### Heatmaps of DE genes
  1084. #### Figure 3 i
  1085. ```{r}
  1086. sample_anno <- sample_table[sample_table$tissue == "hippo",]
  1087. input <- norm_anno[,c(sample_anno$ID,"GENEID", "SYMBOL", "GENETYPE" )]
  1088. gene_anno <- tx_annotation
  1089. geneset <- DEresults[["hippo_LON5_vs_hippo_IgG"]]@results[DEresults[["hippo_LON5_vs_hippo_IgG"]]@results$regulation %in% c("up","down"),"GENEID"]
  1090. input <- input[input$GENEID %in% geneset,]
  1091. input <- input[,colnames(input) %in% sample_anno$ID]
  1092. input_scale <- t(scale(t(input)))
  1093. input_scale<-as.data.frame(input_scale)
  1094. input_scale$GENEID <- rownames(input_scale)
  1095. gene_anno <- gene_anno[match(rownames(input_scale), gene_anno$GENEID),]
  1096. input_scale <- merge(input_scale,
  1097. gene_anno,
  1098. by = "GENEID")
  1099. rownames(input_scale) <- input_scale$SYMBOL
  1100. title=paste("Heatmap of significant DE genes in: ","hippo_LON5_vs_hippo_IgG",sep="")
  1101. print(plotHeatmap(input=input_scale,
  1102. sample_annotation= sample_anno,
  1103. geneset = geneset,
  1104. title = title,
  1105. keyType = "Ensembl",
  1106. show_rownames = F,
  1107. cluster_cols = F,
  1108. gene_type="all",
  1109. plot_mean = F))
  1110. ```
  1111. ### Volcano Plots
  1112. #### Figure 3 k
  1113. ```{r}
  1114. # Plot Volcano Plot
  1115. print(plotVolcano(DEresults_obj = DEresults, comparison = "hippo_LON5_vs_hippo_IgG", labelnum = 20))
  1116. ```
  1117. ```{r}
  1118. sessionInfo()
  1119. ```

250327_publication.Rmd at commit 39b95ee, under LGPL-3.0 · at the source

Overview

Authors: Bilge Askin1,2, Cagla Kilic1, César Cordero Gómez1,3, Sophie Lan-Linh Duong1,3,4, Alvaro Domingues-Baquero1, Alexander Goihl5, Karsten Nalbach6,7,8, Joana Petushi1, Pia Grundschöttel9,10,11, Jessica Wagner6,7,12, Valentine Thomas1, Janne Lamberty1, Emily Withers1, Hanna Huber11, Sabrina Huebschmann1, Ekaterina Semenova1, Paul Turko13, Andrew G. Newman14, Lisa Diez1, Marc Beyer9,11
and 11 other authorsElena De Domenico9,11, Peter Körtvelyessy3,15, Dirk Reinhold5, Anja Schneider11, Jonas J. Neher6,7,12, Thomas Ulas9,10,11, Stefan F. Lichtenthaler6,7,8, Benjamin R. Rost1, Dietmar Schmitz1,2,14,16, Harald Prüss1,2,3, Susanne Wegmann1,2
16 affiliations
  1. German Center for Neurodegenerative Diseases (DZNE), Berlin, Germany
  2. Einstein Center for Neurosciences (ECN), Charité – Universitätsmedizin Berlin, Berlin, Germany
  3. Department of Neurology and Experimental Neurology, Charité – Universitätsmedizin Berlin, Berlin, Germany
  4. Berlin Institute of Health (BIH) at Charité – Universitätsmedizin Berlin, Berlin, Germany
  5. Institute of Molecular and Clinical Immunology, Otto-von-Guericke-University, Magdeburg, Germany
  6. German Center for Neurodegenerative Diseases (DZNE), Munich, Germany
  7. Munich Cluster for Systems Neurology (SyNergy), Munich, Germany
  8. Neuroproteomics, School of Medicine and Health, Klinikum Rechts der Isar, Technical University of Munich, Munich, Germany
  9. Platform for Single Cell Genomics and Epigenomics (PRECISE) at the German Center for Neurodegenerative Diseases and the University of Bonn, Bonn, Germany
  10. Genomics and Immunoregulation, Life and Medical Sciences (LIMES) Institute, University of Bonn, Bonn, Germany
  11. German Center for Neurodegenerative Diseases (DZNE), Bonn, Germany
  12. Metabolic Biochemistry, Biomedical Center Munich (BMC), Faculty of Medicine, Ludwig Maximilian University, Munich, Germany
  13. Institute of Integrative Neuroanatomy, Charité, Berlin, Germany
  14. Institute of Cell Biology and Neurobiology, Charité – Universitätsmedizin Berlin, Berlin, Germany
  15. German Center for Neurodegenerative Diseases (DZNE), Magdeburg, Germany
  16. Neuroscience Research Center (NWFZ), Charité-Universitätsmedizin, Berlin, Germany
Journal: Science advances, volume 12, issue 20, article eaec2042
Dates: received 10 September 2025; accepted 8 April 2026; published online 13 May 2026; in print May 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1126/sciadv.aec2042 · PMID 42127169 · PMCID PMC13170660 · OpenAlex W7160985357
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: human (organism), mouse (organism), other condition (population), cellular / molecular (subfield)
Methods: Statistics, Evoked potentials, fMRI & imaging, Single-unit activity, calcium imaging
MeSH: Autoantibodies*, Cell Adhesion Molecules, Neuronal*, Neurons*, tau Proteins*, Animals, Autoimmune Diseases, Hippocampus, Humans, Mice, Phosphorylation (* major topic)
Journal subjects: Neuroscience, Diseases and Disorders
Topic: Autoimmune Neurological Disorders and Treatments (Neurology, Medicine), according to OpenAlex
Citations: cited by 1 paper (Europe PMC); 116 references in the paper

Abstract

Anti-IgLON5 disease is an autoimmune disease, in which autoantibodies (AABs) against the neuronal cell surface protein IgLON5 lead to profound brain dysfunction and Tau pathology. How α-IgLON5 AABs cause neuronal Tau protein pathology and neurodegeneration remains unclear. We find that patient-derived α-IgLON5 AABs cluster IgLON5 proteins with other cell surface proteins, leading to neuronal hyperactivity that triggers pathological Tau missorting and phosphorylation, typically observed early in Tau-related neurodegenerative diseases. In wild-type mice, α-IgLON5 AABs induce hippocampal Tau phosphorylation and neuroinflammatory responses. Our findings establish a causal link between the α-IgLON5 AABs and Tau pathology in anti-IgLON5 disease patients and highlight the role of neuronal hyperactivity as a disease-overarching driver of Tau pathology and provide a potential target for therapeutic intervention.

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 1 match between paragraphs and lines of code.

gitlab.dzne.de/ag-ulas/iglon5-autoimmune-antibody-influence-on-neurons

License: LGPL-3.0
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: 39b95ee856d3cbf4189243e201bc7cf6be8bf980, 7 April 2026
Languages: R (1)
Size: 5 files, 1 script
Software Heritage: not archived
Found in: “Data and code”
Holds: README, license file, CITATION.cff, 1 notebook
Not found: environment file, tests, continuous integration, documentation
Tools: reshape2 (1 file), tidyverse (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
3 files

Zenodo 19454006

License: CC-BY-4.0
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: “Data and code”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: reshape2 (1 file), tidyverse (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers (HTTP 200)
  • 28 September 2026: the link answers (HTTP 200)
3 files

gitlab.dzne.de/grundschoettelp/iglon5-autoimmune-antibody-influence-on-neurons

License: LGPL-3.0
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: 39b95ee856d3cbf4189243e201bc7cf6be8bf980, 7 April 2026
Languages: R (1)
Size: 5 files, 1 script
Software Heritage: not archived
Found in: “Data, code, and materials availability:”
Holds: README, license file, CITATION.cff, 1 notebook
Not found: environment file, tests, continuous integration, documentation
Tools: reshape2 (1 file), tidyverse (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
3 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:

  • 3 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 3 scripts, each with its path and the digest of its content;
  • 1 match between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

Datasets cited

Data, code, and materials availability

All data and code needed to evaluate and reproduce the results in the paper are present in the paper and/or the Supplementary Materials or are available as follows: The plasmid for enhanced green fluorescent protein (eGFP)–TauP301L/S320F expression can be provided by S.W.’s pending scientific review and a completed material transfer agreement with the DZNE. Requests for the plasmid for eGFP-TauP301L/S320F should be submitted to: . RNA-seq data generated in this study are available in the GEO at www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE298951, under the accession number GSE298951, with the token: mduriemyzlsvdej. Lists of DEGs can be found in data S1. Code for RNA-seq analysis is available at https://gitlab.dzne.de/grundschoettelp/iglon5-autoimmune-antibody-influence-on-neurons. The proteomics data have been deposited to the ProteomeXchange Consortium via the PRIDE partner repository with the dataset identifier PXD066225 (token i5YAGUXZ5Yv4, username: , password: rbRRDufu6h6K). Lists of differentially enriched proteins can be found in data S3.

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, 28 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 31 authors, 10 MeSH terms, 6 funders, 115 references.

Cite

This paper

Askin, B., Kilic, C., Cordero Gómez, C., Duong, S. L.-L., Domingues-Baquero, A., Goihl, A., Nalbach, K., Petushi, J., Grundschöttel, P., Wagner, J., Thomas, V., Lamberty, J., Withers, E., Huber, H., Huebschmann, S., Semenova, E., Turko, P., Newman, A. G., Diez, L., . . . Wegmann, S. (2026). IgLON5 autoimmune antibodies activate Tau via neuronal hyperactivity. Science advances, 12(20), eaec2042. https://doi.org/10.1126/sciadv.aec2042

BibTeX

@article{askin2026iglon5,
author = {Askin, Bilge and Kilic, Cagla and Cordero Gómez, César and Duong, Sophie Lan-Linh and Domingues-Baquero, Alvaro and Goihl, Alexander and Nalbach, Karsten and Petushi, Joana and Grundschöttel, Pia and Wagner, Jessica and Thomas, Valentine and Lamberty, Janne and Withers, Emily and Huber, Hanna and Huebschmann, Sabrina and Semenova, Ekaterina and Turko, Paul and Newman, Andrew G. and Diez, Lisa and Beyer, Marc and De Domenico, Elena and Körtvelyessy, Peter and Reinhold, Dirk and Schneider, Anja and Neher, Jonas J. and Ulas, Thomas and Lichtenthaler, Stefan F. and Rost, Benjamin R. and Schmitz, Dietmar and Prüss, Harald and Wegmann, Susanne},
title = {{IgLON5 autoimmune antibodies activate Tau via neuronal hyperactivity}},
journal = {Science advances},
year = {2026},
month = may,
volume = {12},
number = {20},
pages = {eaec2042},
publisher = {American Association for the Advancement of Science},
issn = {2375-2548},
doi = {10.1126/sciadv.aec2042},
url = {https://doi.org/10.1126/sciadv.aec2042},
pmid = {42127169},
pmcid = {PMC13170660}
}

RIS

TY - JOUR
AU - Askin, Bilge
AU - Kilic, Cagla
AU - Cordero Gómez, César
AU - Duong, Sophie Lan-Linh
AU - Domingues-Baquero, Alvaro
AU - Goihl, Alexander
AU - Nalbach, Karsten
AU - Petushi, Joana
AU - Grundschöttel, Pia
AU - Wagner, Jessica
AU - Thomas, Valentine
AU - Lamberty, Janne
AU - Withers, Emily
AU - Huber, Hanna
AU - Huebschmann, Sabrina
AU - Semenova, Ekaterina
AU - Turko, Paul
AU - Newman, Andrew G.
AU - Diez, Lisa
AU - Beyer, Marc
AU - De Domenico, Elena
AU - Körtvelyessy, Peter
AU - Reinhold, Dirk
AU - Schneider, Anja
AU - Neher, Jonas J.
AU - Ulas, Thomas
AU - Lichtenthaler, Stefan F.
AU - Rost, Benjamin R.
AU - Schmitz, Dietmar
AU - Prüss, Harald
AU - Wegmann, Susanne
TI - IgLON5 autoimmune antibodies activate Tau via neuronal hyperactivity
T2 - Science advances
J2 - Sci Adv
PY - 2026
DA - 2026/05/13
VL - 12
IS - 20
SP - eaec2042
SN - 2375-2548
PB - American Association for the Advancement of Science
DO - 10.1126/sciadv.aec2042
UR - https://doi.org/10.1126/sciadv.aec2042
LA - en
ER -

CSL-JSON

{
"id": "10.1126/sciadv.aec2042",
"type": "article-journal",
"title": "IgLON5 autoimmune antibodies activate Tau via neuronal hyperactivity",
"container-title": "Science advances",
"author": [
{
"family": "Askin",
"given": "Bilge"
},
{
"family": "Kilic",
"given": "Cagla"
},
{
"family": "Cordero Gómez",
"given": "César"
},
{
"family": "Duong",
"given": "Sophie Lan-Linh"
},
{
"family": "Domingues-Baquero",
"given": "Alvaro"
},
{
"family": "Goihl",
"given": "Alexander"
},
{
"family": "Nalbach",
"given": "Karsten"
},
{
"family": "Petushi",
"given": "Joana"
},
{
"family": "Grundschöttel",
"given": "Pia"
},
{
"family": "Wagner",
"given": "Jessica"
},
{
"family": "Thomas",
"given": "Valentine"
},
{
"family": "Lamberty",
"given": "Janne"
},
{
"family": "Withers",
"given": "Emily"
},
{
"family": "Huber",
"given": "Hanna"
},
{
"family": "Huebschmann",
"given": "Sabrina"
},
{
"family": "Semenova",
"given": "Ekaterina"
},
{
"family": "Turko",
"given": "Paul"
},
{
"family": "Newman",
"given": "Andrew G."
},
{
"family": "Diez",
"given": "Lisa"
},
{
"family": "Beyer",
"given": "Marc"
},
{
"family": "De Domenico",
"given": "Elena"
},
{
"family": "Körtvelyessy",
"given": "Peter"
},
{
"family": "Reinhold",
"given": "Dirk"
},
{
"family": "Schneider",
"given": "Anja"
},
{
"family": "Neher",
"given": "Jonas J."
},
{
"family": "Ulas",
"given": "Thomas"
},
{
"family": "Lichtenthaler",
"given": "Stefan F."
},
{
"family": "Rost",
"given": "Benjamin R."
},
{
"family": "Schmitz",
"given": "Dietmar"
},
{
"family": "Prüss",
"given": "Harald"
},
{
"family": "Wegmann",
"given": "Susanne"
}
],
"container-title-short": "Sci Adv",
"volume": "12",
"issue": "20",
"page": "eaec2042",
"DOI": "10.1126/sciadv.aec2042",
"PMID": "42127169",
"PMCID": "PMC13170660",
"ISSN": "2375-2548",
"publisher": "American Association for the Advancement of Science",
"URL": "https://doi.org/10.1126/sciadv.aec2042",
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
13
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1038/s41593-026-02367-0 [code]
A reproducible three-dimensional model of human brain tissue to investigate physiological and disease-associated microglia phenotypes.
Journal: Nature neuroscience
In common: reshape2, tidyverse, cellular / molecular, 5 references, 3 authors
[2] doi:10.1093/brain/awag015
Brainstem pathology in anti-IgLON5 disease: new insights into early events and tau progression.
Journal: Brain : a journal of neurology
In common: other condition, cellular / molecular, 11 references
[3] doi:10.1038/s41467-026-74961-6 [code]
Spatial multi-omics identifies early synaptic pruning and context-specific dopaminergic vulnerability in synucleinopathies.
Journal: Nature communications
In common: tidyverse, cellular / molecular, 2 authors
[4] doi:10.3389/fnsyn.2026.1832103 [code]
Automated ROI detection allows rapid quantification of synaptic activity across tens of thousands of synapses in cell culture.
Journal: Frontiers in synaptic neuroscience
In common: tidyverse, cellular / molecular, 3 references, author Paul Turko
[5] doi:10.1186/s13073-026-01702-1
Tandem repeat polymorphisms are associated with brain structure: results of two large population-based studies.
Journal: Genome medicine
In common: 2 authors
[6] doi:
AMPAR immunization induces progressive autoimmune encephalitis with autoreactive B cells in the brain
Journal: bioRxiv : the preprint server for biology
In common: other condition, mouse, cellular / molecular, 5 references
[7] 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: reshape2, tidyverse, other condition, 4 references
[8] doi:10.1016/j.celrep.2026.117505 [code]
Impaired spatial coding and neuronal hyperactivity in the medial entorhinal cortex of aged APP knock-in mice.
Journal: Cell reports
In common: reshape2, tidyverse, mouse, 3 references
[9] doi:10.1038/s41467-026-74968-z [code]
Activity-dependent ribosome profiling reveals the landscape of canonical and non-canonical translation in brain tissue.
Journal: Nature communications
In common: tidyverse, mouse, cellular / molecular, 5 references
[10] doi:10.1038/s41467-026-71831-z [code]
Dysfunction of the episodic memory network in the Alzheimer's disease cascade.
Journal: Nature communications
In common: 1 reference, author Anja Schneider

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.