OSCR

Focal white matter lesions drive grey matter inflammation and synapse loss.

Code ↔ Paper

10 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 10 matches
  1. [1] § Methods › DBiT-seq bioinformatics analysis ↔ DBiTseq_analysis/ST_Analysis_IO_20250929_final.Rmd, lines 702–789 · score 0.76 · get.knn, dilated, edgelist, node, radius, distances
  2. [2] § Methods › DBiT-seq bioinformatics analysis ↔ DBiTseq_analysis/ST_Analysis_Lesion_20250929.Rmd, lines 702–789 · score 0.76 · get.knn, dilated, edgelist, node, radius, distances
  3. [3] § Methods › Bulk RNA-seq deconvolution and bioinformatics analysis ↔ Bulk_deconvolution/Bulk_RNor2Mm_deconv_2025_EA_1.Rmd, lines 203–224 · score 0.73 · SampleID, SingleCellExperiment, SubClass, medulla, metadata, Bulk
  4. [4] § Distinct transcriptional changes within the circuit › Focal white matter lesions evoke transcriptional changes in the IO ↔ DBiTseq_analysis/ST_Analysis_IO_20250929_final.Rmd, lines 3314–3341 · score 0.70 · Ajap1, Calm1, Cdh11, Cox2, Cox3, Gria1
  5. [5] § Methods › DBiT-seq bioinformatics analysis ↔ DBiTseq_analysis/ST_Analysis_Lesion_20250929.Rmd, lines 1033–1060 · score 0.70 · FindClusters, FindNeighbors, elbow, vst, log, variable
  6. [6] § Methods › DBiT-seq bioinformatics analysis ↔ DBiTseq_analysis/ST_analysis_Healthy.rmd, lines 1046–1073 · score 0.69 · FindClusters, FindNeighbors, elbow, vst, log, variable
  7. [7] § Distinct transcriptional changes within the circuit › Focal white matter lesions evoke transcriptional changes in the IO ↔ DBiTseq_analysis/ST_Analysis_IO_20250929_final.Rmd, lines 2691–2741 · score 0.69 · retrograde endocannabinoid, oxidative phosphorylation, Parkinson, Alzheimer, disease, enrichment
  8. [8] § Methods › DBiT-seq bioinformatics analysis ↔ DBiTseq_analysis/ST_Analysis_IO_20250929_final.Rmd, lines 3342–3365 · score 0.68 · AddModuleScore, Csf1r, nbin, Maf, Spi1, Aif1
  9. [9] § Methods › DBiT-seq bioinformatics analysis ↔ Bulk_deconvolution/Bulk_RNor2Mm_deconv_2025_EA_1.Rmd, lines 146–183 · score 0.57 · FindClusters, FindNeighbors, Neighbour, UMAP, resolution, clustering
  10. [10] § Methods › DBiT-seq bioinformatics analysis ↔ DBiTseq_analysis/ST_Analysis_Lesion_20250929.Rmd, lines 1033–1060 · score 0.54 · FindClusters, FindNeighbors, PCs, Neighbour, resolution, clustering

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 · 5,962 lines · 195 KB · no license · 4 matches

  1. ---
  2. title: "ST_Analysis_SeuratOnly_IO"
  3. authors: "Bastien Herve, Joseph Wong"
  4. output: html_document
  5. date: "2025-09-29"
  6. ---
  7. ```{r}
  8. reticulate::use_condaenv("r-reticulate", required = TRUE)
  9. ```
  10. ```{r}
  11. library(Seurat)
  12. library(Signac)
  13. library(hdf5r)
  14. library(biovizBase)
  15. library(GenomicRanges)
  16. library(stringr)
  17. library(ggplot2)
  18. library(sf)
  19. library(scales)
  20. library(grid)
  21. library(gridExtra)
  22. library(patchwork)
  23. library(plyr)
  24. library(dplyr)
  25. library(Rmagic)
  26. library(clustree)
  27. library(pheatmap)
  28. library(png)
  29. library(imager)
  30. library(RColorBrewer)
  31. library(future)
  32. library(pbapply)
  33. library(cluster)
  34. library(corrplot)
  35. library(reticulate)
  36. library(presto)
  37. library(circlize)
  38. library(ggcorrplot)
  39. library(scatterpie)
  40. library(glmGamPoi)
  41. library(muscat)
  42. library(DESeq2)
  43. library(purrr)
  44. library(Matrix.utils)
  45. library(magrittr)
  46. library(scales)
  47. library(EnhancedVolcano)
  48. library(UpSetR)
  49. library(ReactomePA)
  50. library(enrichplot)
  51. library(biomaRt)
  52. library(org.Mm.eg.db)
  53. library(enrichR)
  54. library(FNN)
  55. library(igraph)
  56. # additional
  57. # library(MASS)
  58. # library(data.table)
  59. ```
  60. ```{r}
  61. sessionInfo()
  62. ```
  63. ```{r}
  64. # set up parameters
  65. seed <- 424242
  66. options(repr.plot.width=16, repr.plot.height=12)
  67. options(future.globals.maxSize = 110000 * 1024^2)
  68. options(repr.matrix.max.rows=100, repr.matrix.max.cols=100)
  69. pixel_size_plot = 2.5
  70. empty_lanes_cutoff_mean <- 500
  71. nb_pixels_dbit = 10000
  72. names_Ctrl <- c("Ctrlrep1", "Ctrlrep2", "Ctrlrep3", "Ctrlrep4")
  73. names_D7 <- c("D7rep1", "D7rep2", "D7rep3", "D7rep4")
  74. names_D14 <- c("D14rep1", "D14rep2", "D14rep3", "D14rep4")
  75. names_D28 <- c("D28rep1", "D28rep2", "D28rep3")
  76. sample_names <- c("P35102_1001","P35102_1002","P35102_1003","P35102_1004","P35102_1005","P35102_1006","P35102_1007","P35102_1008","P35102_1009","P35102_1010","P35102_1011","P35102_1012","P35102_1013","P35102_1014","P35102_1015")
  77. names(sample_names) <- c(names_Ctrl,names_D7,names_D14,names_D28)
  78. ```
  79. ```{r}
  80. orig.ident_colors <- c("#536553", "#657B65", "#8FA38F", "#BCC8BC",
  81. "#B88100", "#F5AB00", "#FFD470", "#FFE7AD",
  82. "#E92A0C", "#F5563D", "#F88877", "#FDDDD8",
  83. "#97615E", "#C8A9A7", "#E0CECD")
  84. names(orig.ident_colors) <- c("Ctrlrep1", "Ctrlrep2", "Ctrlrep3", "Ctrlrep4",
  85. "D7rep1", "D7rep2", "D7rep3", "D7rep4",
  86. "D14rep1", "D14rep2", "D14rep3", "D14rep4",
  87. "D28rep1", "D28rep2", "D28rep3")
  88. show_col(orig.ident_colors)
  89. orig.ident_colors_contrast <- c("#97615E", "#E92A0C", "#F5AB00", "#6E876E",
  90. "#97615E", "#E92A0C", "#F5AB00", "#6E876E",
  91. "#97615E", "#E92A0C", "#F5AB00", "#6E876E",
  92. "#97615E", "#E92A0C", "#F5AB00")
  93. names(orig.ident_colors_contrast) <- c("Ctrlrep1", "Ctrlrep2", "Ctrlrep3", "Ctrlrep4",
  94. "D7rep1", "D7rep2", "D7rep3", "D7rep4",
  95. "D14rep1", "D14rep2", "D14rep3", "D14rep4",
  96. "D28rep1", "D28rep2", "D28rep3")
  97. show_col(orig.ident_colors_contrast)
  98. orig.ident_merge_colors <- c("#6E876E", "#F5AB00", "#E92A0C", "#97615E")
  99. names(orig.ident_merge_colors) <- c("Ctrl", "D7", "D14", "D28")
  100. show_col(orig.ident_merge_colors)
  101. model_colors <- c("#6E876E", "#E92A0C")
  102. names(model_colors) <- c("Ctrl", "Lesion")
  103. show_col(model_colors)
  104. duo_colors <- c("#E92A0C", "#2A75CB")
  105. show_col(duo_colors)
  106. repair_colors <- duo_colors
  107. names(repair_colors) <- c("repaired", "non repaired")
  108. wheeler_colors <- c("#3772FF", "#160F29", "#A9FFCB", "#FDCA40", "#A77E58", "#DE6449", "#C03221", "#791E94", "#EFC3E6", "#0CCA4A", "#D78521", "#000080", "#C3C9E9", "#FFFF00")
  109. names(wheeler_colors) <- c("Astro", "DC", "Endo", "Epen", "Epith", "MicroMacro", "MonoMacro", "Neurons", "Neutro", "OL", "Peri", "SMC", "Stromal", "Tcells")
  110. show_col(wheeler_colors)
  111. zeisel_colors <- c("#3772FF", "#FDCA40", "#A77E58", "#DE6449", "#C03221", "#791E94", "#0CCA4A", "#D78521", "#000080")
  112. names(zeisel_colors) <- c("Astrocyte", "Ependymal", "Blood", "Immune", "Bergmann-glia", "Neurons", "Oligos", "Ttr", "Vascular")
  113. show_col(zeisel_colors)
  114. ```
  115. ```{r}
  116. PrctCellExpringGene <- function(object, genes, group.by = "all"){
  117. if(group.by == "all"){
  118. prct = unlist(lapply(genes,calc_helper, object=object))
  119. result = data.frame(Markers = genes, Cell_proportion = prct)
  120. return(result)
  121. }
  122. else{
  123. list = SplitObject(object, group.by)
  124. factors = names(list)
  125. results = lapply(list, PrctCellExpringGene, genes=genes)
  126. for(i in 1:length(factors)){
  127. results[[i]]$Feature = factors[i]
  128. }
  129. combined = do.call("rbind", results)
  130. return(combined)
  131. }
  132. }
  133. calc_helper <- function(object,genes){
  134. counts = object[['RNA']]@counts
  135. ncells = ncol(counts)
  136. if(genes %in% row.names(counts)){
  137. sum(counts[genes,]>0)/ncells
  138. }else{return(NA)}
  139. }
  140. NbCellExpringGene <- function(object, genes, group.by = "all"){
  141. if(group.by == "all"){
  142. nb = unlist(lapply(genes,calc_helper_nb, object=object))
  143. result = data.frame(Markers = genes, Cell_nb = nb)
  144. return(result)
  145. }
  146. else{
  147. list = SplitObject(object, group.by)
  148. factors = names(list)
  149. results = lapply(list, NbCellExpringGene, genes=genes)
  150. for(i in 1:length(factors)){
  151. results[[i]]$Feature = factors[i]
  152. }
  153. combined = do.call("rbind", results)
  154. return(combined)
  155. }
  156. }
  157. calc_helper_nb <- function(object,genes){
  158. counts = object[['RNA']]@counts
  159. if(genes %in% row.names(counts)){
  160. length(counts[genes,][counts[genes,] > 0])
  161. }else{return(NA)}
  162. }
  163. DoMultiBarHeatmap <- function (object, features = NULL, cells = NULL, group.by = "ident", additional.group.by = NULL, additional.group.sort.by = NULL, cols.use = NULL, group.bar = TRUE, disp.min = -2.5, disp.max = NULL, layer = "scale.data", assay = NULL, label = TRUE, size = 5.5, hjust = 0, angle = 45, raster = TRUE, draw.lines = TRUE, lines.width = NULL, group.bar.height = 0.02, combine = TRUE){
  164. cells <- cells %||% colnames(x = object)
  165. if (is.numeric(x = cells)) {
  166. cells <- colnames(x = object)[cells]
  167. }
  168. assay <- assay %||% DefaultAssay(object = object)
  169. DefaultAssay(object = object) <- assay
  170. features <- features %||% VariableFeatures(object = object)
  171. ## Why reverse???
  172. features <- rev(x = unique(x = features))
  173. disp.max <- disp.max %||% ifelse(test = layer == "scale.data", yes = 2.5, no = 6)
  174. possible.features <- rownames(x = LayerData(object = object, assay = assay, layer = layer))
  175. if (any(!features %in% possible.features)) {
  176. bad.features <- features[!features %in% possible.features]
  177. features <- features[features %in% possible.features]
  178. if (length(x = features) == 0) {
  179. stop("No requested features found in the ", layer,
  180. " slot for the ", assay, " assay.")
  181. }
  182. warning("The following features were omitted as they were not found in the ", layer, " slot for the ", assay, " assay: ", paste(bad.features, collapse = ", "))
  183. }
  184. if (!is.null(additional.group.sort.by)) {
  185. if (any(!additional.group.sort.by %in% additional.group.by)) {
  186. bad.sorts <- additional.group.sort.by[!additional.group.sort.by %in% additional.group.by]
  187. additional.group.sort.by <- additional.group.sort.by[additional.group.sort.by %in% additional.group.by]
  188. if (length(x = bad.sorts) > 0) {
  189. warning("The following additional sorts were omitted as they were not a subset of additional.group.by : ",
  190. paste(bad.sorts, collapse = ", "))
  191. }
  192. }
  193. }
  194. data <- as.data.frame(x = as.matrix(x = t(x = LayerData(object = object, assay = assay, layer = layer)[features, cells, drop = FALSE])))
  195. object <- suppressMessages(expr = StashIdent(object = object, save.name = "ident"))
  196. group.by <- group.by %||% "ident"
  197. groups.use <- object[[c(group.by, additional.group.by[!additional.group.by %in% group.by])]][cells, , drop = FALSE]
  198. plots <- list()
  199. for (i in group.by) {
  200. data.group <- data
  201. if (!is.null(additional.group.by)) {
  202. additional.group.use <- additional.group.by[additional.group.by!=i]
  203. if (!is.null(additional.group.sort.by)){
  204. additional.sort.use = additional.group.sort.by[additional.group.sort.by != i]
  205. } else {
  206. additional.sort.use = NULL
  207. }
  208. } else {
  209. additional.group.use = NULL
  210. additional.sort.use = NULL
  211. }
  212. group.use <- groups.use[, c(i, additional.group.use), drop = FALSE]
  213. for(colname in colnames(group.use)){
  214. if (!is.factor(x = group.use[[colname]])) {
  215. group.use[[colname]] <- factor(x = group.use[[colname]])
  216. }
  217. }
  218. if (draw.lines) {
  219. lines.width <- lines.width %||% ceiling(x = nrow(x = data.group) * 0.0025)
  220. placeholder.cells <- sapply(X = 1:(length(x = levels(x = group.use[[i]])) * lines.width), FUN = function(x) {
  221. return(Seurat:::RandomName(length = 20))
  222. })
  223. placeholder.groups <- data.frame(rep(x = levels(x = group.use[[i]]), times = lines.width))
  224. group.levels <- list()
  225. group.levels[[i]] = levels(x = group.use[[i]])
  226. for (j in additional.group.use) {
  227. group.levels[[j]] <- levels(x = group.use[[j]])
  228. placeholder.groups[[j]] = NA
  229. }
  230. colnames(placeholder.groups) <- colnames(group.use)
  231. rownames(placeholder.groups) <- placeholder.cells
  232. group.use <- sapply(group.use, as.vector)
  233. rownames(x = group.use) <- cells
  234. group.use <- rbind(group.use, placeholder.groups)
  235. for (j in names(group.levels)) {
  236. group.use[[j]] <- factor(x = group.use[[j]], levels = group.levels[[j]])
  237. }
  238. na.data.group <- matrix(data = NA, nrow = length(x = placeholder.cells), ncol = ncol(x = data.group), dimnames = list(placeholder.cells, colnames(x = data.group)))
  239. data.group <- rbind(data.group, na.data.group)
  240. }
  241. order_expr <- paste0('order(', paste(c(i, additional.sort.use), collapse=','), ')')
  242. group.use = with(group.use, group.use[eval(parse(text=order_expr)), , drop=F])
  243. plot <- Seurat:::SingleRasterMap(data = data.group, raster = raster, disp.min = disp.min, disp.max = disp.max, feature.order = features, cell.order = rownames(x = group.use), group.by = group.use[[i]])
  244. if (group.bar) {
  245. pbuild <- ggplot_build(plot = plot)
  246. group.use2 <- group.use
  247. cols <- list()
  248. na.group <- Seurat:::RandomName(length = 20)
  249. for (colname in rev(x = colnames(group.use2))) {
  250. if (colname == i) {
  251. colid = paste0('Identity (', colname, ')')
  252. } else {
  253. colid = colname
  254. }
  255. # Default
  256. cols[[colname]] <- c(scales::hue_pal()(length(x = levels(x = group.use[[colname]]))))
  257. #Overwrite if better value is provided
  258. if (!is.null(cols.use[[colname]])) {
  259. req_length = length(x = levels(group.use))
  260. if (length(cols.use[[colname]]) < req_length){
  261. warning("Cannot use provided colors for ", colname, " since there aren't enough colors.")
  262. } else {
  263. if (!is.null(names(cols.use[[colname]]))) {
  264. if (all(levels(group.use[[colname]]) %in% names(cols.use[[colname]]))) {
  265. cols[[colname]] <- as.vector(cols.use[[colname]][levels(group.use[[colname]])])
  266. } else {
  267. warning("Cannot use provided colors for ", colname, " since all levels (", paste(levels(group.use[[colname]]), collapse=","), ") are not represented.")
  268. }
  269. } else {
  270. cols[[colname]] <- as.vector(cols.use[[colname]])[c(1:length(x = levels(x = group.use[[colname]])))]
  271. }
  272. }
  273. }
  274. # Add white if there's lines
  275. if (draw.lines) {
  276. levels(x = group.use2[[colname]]) <- c(levels(x = group.use2[[colname]]), na.group)
  277. group.use2[placeholder.cells, colname] <- na.group
  278. cols[[colname]] <- c(cols[[colname]], "#FFFFFF")
  279. }
  280. names(x = cols[[colname]]) <- levels(x = group.use2[[colname]])
  281. y.range <- diff(x = pbuild$layout$panel_params[[1]]$y.range)
  282. y.pos <- max(pbuild$layout$panel_params[[1]]$y.range) + y.range * 0.015
  283. y.max <- y.pos + group.bar.height * y.range
  284. pbuild$layout$panel_params[[1]]$y.range <- c(pbuild$layout$panel_params[[1]]$y.range[1], y.max)
  285. plot <- suppressMessages(plot +
  286. annotation_raster(raster = t(x = cols[[colname]][group.use2[[colname]]]), xmin = -Inf, xmax = Inf, ymin = y.pos, ymax = y.max) +
  287. annotation_custom(grob = grid::textGrob(label = colid, hjust = 0, gp = gpar(cex = 0.75)), ymin = mean(c(y.pos, y.max)), ymax = mean(c(y.pos, y.max)), xmin = Inf, xmax = Inf) +
  288. coord_cartesian(ylim = c(0, y.max), clip = "off")
  289. )
  290. if ((colname == i) && label) {
  291. x.max <- max(pbuild$layout$panel_params[[1]]$x.range)
  292. x.divs <- pbuild$layout$panel_params[[1]]$x.major %||% pbuild$layout$panel_params[[1]]$x$break_positions()
  293. group.use$x <- x.divs
  294. label.x.pos <- tapply(X = group.use$x, INDEX = group.use[[colname]], FUN = median) * x.max
  295. label.x.pos <- data.frame(group = names(x = label.x.pos), label.x.pos)
  296. plot <- plot + geom_text(stat = "identity", data = label.x.pos, aes_string(label = "group", x = "label.x.pos"), y = y.max + y.max * 0.03 * 0.5, angle = angle, hjust = hjust, size = size)
  297. plot <- suppressMessages(plot + coord_cartesian(ylim = c(0, y.max + y.max * 0.002 * max(nchar(x = levels(x = group.use[[colname]]))) * size), clip = "off"))
  298. }
  299. }
  300. }
  301. plot <- plot + theme(line = element_blank())
  302. plots[[i]] <- plot
  303. }
  304. if (combine) {
  305. plots <- CombinePlots(plots = plots)
  306. }
  307. return(plots)
  308. }
  309. plot_count_on_tissue <- function(object=NULL, img_data=NULL, gene=NULL, assay=NULL, slot=NULL, image=NULL, readPNG_dim=NULL, transp=NULL, limit_min=NULL, limit_max=NULL, pixel_size=NULL, palette_col=NULL){
  310. DefaultAssay(object) <- assay
  311. img_data[,"value"] <- GetAssayData(object = object, slot = slot)[gene,img_data[,"cell_names"]]
  312. img_data_pixel <- as.data.frame(img_data) %>%
  313. st_as_sf(coords = c("x1", "y1")) %>%
  314. group_by(x,y,var,value) %>%
  315. dplyr::summarise(do_union = F) %>%
  316. st_cast("POLYGON") %>%
  317. st_cast("MULTIPOLYGON") %>%
  318. mutate(var = as.factor(var))
  319. ggplot(img_data_pixel) +
  320. annotation_custom(image) +
  321. geom_sf(aes(fill = value),shape=15, size = pixel_size, alpha = transp) +
  322. scale_fill_gradientn(colours = palette_col, limits = c(limit_min,limit_max), oob=squish) +
  323. scale_x_continuous(expand = c(0, 0), limits = c(0, readPNG_dim[2])) +
  324. scale_y_continuous(expand = c(0, 0), limits = c(0, readPNG_dim[1])) +
  325. theme_void()
  326. }
  327. scale01 <- function(x){(x-min(x))/(max(x)-min(x))}
  328. plot_diff_count_on_tissue <- function(object=NULL, gene=NULL, assay=NULL, slot=NULL, image=NULL, rescale=NULL, transp=NULL, limit=NULL, pixel_size=NULL, palette_col=NULL){
  329. if(length(gene) > 1 & length(assay) > 1){
  330. print("please only compare 2 assays or 2 genes not both")
  331. } else{
  332. if (length(gene) > 1){
  333. DefaultAssay(object) <- assay
  334. df <- data.frame(
  335. x = object$x,
  336. y = object$y,
  337. value1 = GetAssayData(object = object, slot = slot)[gene[1],],
  338. value2 = GetAssayData(object = object, slot = slot)[gene[2],]
  339. )
  340. gene_title <- paste0(gene[1],"/",gene[2])
  341. assay_title <- assay
  342. }else if (length(assay) > 1){
  343. df <- data.frame(
  344. x = object$x,
  345. y = object$y
  346. )
  347. DefaultAssay(object) <- assay[1]
  348. df$value1 = GetAssayData(object = object, slot = slot)[gene,]
  349. DefaultAssay(object) <- assay[2]
  350. df$value2 = GetAssayData(object = object, slot = slot)[gene,]
  351. gene_title <- gene
  352. assay_title <- paste0(assay[1],"/",assay[2])
  353. }
  354. df$value1 <- scale01(df$value1)
  355. df$value2 <- scale01(df$value2)
  356. df$value <- df$value1-df$value2
  357. df$value1 <- NULL
  358. df$value2 <- NULL
  359. if(!is.null(rescale)){
  360. df$x=rescale(df$x, to=c(rescale[1],rescale[2]))
  361. df$y=rescale(df$y, to=c(rescale[3],rescale[4]))
  362. }
  363. ggplot(df, aes(x, y)) +
  364. annotation_custom(image) +
  365. geom_point(aes(colour = value),shape=15, size = pixel_size, alpha = transp) +
  366. scale_colour_gradientn(colours = palette_col, limits = c(-limit,limit), oob=squish) +
  367. scale_x_continuous(expand=c(-0.005,0), lim=c(0,101)) +
  368. scale_y_continuous(expand=c(-0.006,0), lim=c(0,101)) +
  369. theme(axis.line=element_blank(),axis.text.x=element_blank(),
  370. axis.text.y=element_blank(),axis.ticks=element_blank(),
  371. axis.title.x=element_blank(),axis.title.y=element_blank(),
  372. panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
  373. panel.grid.minor=element_blank(),plot.background=element_blank()) +
  374. ggtitle(paste0(gene_title,"_",assay_title))
  375. }
  376. }
  377. ExportGroupBW <- function(
  378. object,
  379. assay = NULL,
  380. group.by = NULL,
  381. idents = NULL,
  382. normMethod = "RC",
  383. tileSize = 100,
  384. minCells = 5,
  385. cutoff = NULL,
  386. chromosome = NULL,
  387. outdir = NULL,
  388. verbose=TRUE
  389. ) {
  390. # Check if temporary directory exist
  391. if (!dir.exists(outdir)){
  392. dir.create(outdir)
  393. }
  394. if (!requireNamespace("rtracklayer", quietly = TRUE)) {
  395. message("Please install rtracklayer. http://www.bioconductor.org/packages/rtracklayer/")
  396. return(NULL)
  397. }
  398. assay <- SetIfNull(x = assay, y = DefaultAssay(object = object))
  399. DefaultAssay(object = object) <- assay
  400. group.by <- SetIfNull(x = group.by, y = 'ident')
  401. Idents(object = object) <- group.by
  402. idents <- SetIfNull(x = idents, y = levels(x = object))
  403. GroupsNames <- names(x = table(object[[group.by]])[table(object[[group.by]]) > minCells])
  404. GroupsNames <- GroupsNames[GroupsNames %in% idents]
  405. # Check if output files already exist
  406. lapply(X = GroupsNames, FUN = function(x) {
  407. fn <- paste0(outdir, .Platform$file.sep, x, ".bed")
  408. if (file.exists(fn)) {
  409. message(sprintf("The group \"%s\" is already present in the destination folder and will be overwritten !",x))
  410. file.remove(fn)
  411. }
  412. })
  413. # Splitting fragments file for each idents in group.by
  414. SplitFragments(
  415. object = object,
  416. assay = assay,
  417. group.by = group.by,
  418. idents = idents,
  419. outdir = outdir,
  420. file.suffix = "",
  421. append = TRUE,
  422. buffer_length = 256L,
  423. verbose = verbose
  424. )
  425. # Column to normalized by
  426. if(!is.null(x = normMethod)) {
  427. if (tolower(x = normMethod) %in% c('rc', 'ncells', 'none')){
  428. normBy <- normMethod
  429. } else{
  430. normBy <- object[[normMethod, drop = FALSE]]
  431. }
  432. }
  433. # Get chromosome information
  434. if(!is.null(x = chromosome)){
  435. seqlevels(object) <- chromosome
  436. }
  437. availableChr <- names(x = seqlengths(object))
  438. chromLengths <- seqlengths(object)
  439. chromSizes <- GRanges(
  440. seqnames = availableChr,
  441. ranges = IRanges(
  442. start = rep(1, length(x = availableChr)),
  443. end = as.numeric(x = chromLengths)
  444. )
  445. )
  446. if (verbose) {
  447. message("Creating tiles")
  448. }
  449. # Create tiles for each chromosome, from GenomicRanges
  450. tiles <- unlist(
  451. x = slidingWindows(x = chromSizes, width = tileSize, step = tileSize)
  452. )
  453. if (verbose) {
  454. message("Creating bigwig files at ", outdir)
  455. }
  456. # Run the creation of bigwig for each cellgroups
  457. if (nbrOfWorkers() > 1) {
  458. mylapply <- future_lapply
  459. } else {
  460. mylapply <- ifelse(test = verbose, yes = pblapply, no = lapply)
  461. }
  462. covFiles <- mylapply(
  463. GroupsNames,
  464. FUN = CreateBWGroup,
  465. availableChr,
  466. chromLengths,
  467. tiles,
  468. normBy,
  469. tileSize,
  470. normMethod,
  471. cutoff,
  472. outdir
  473. )
  474. return(covFiles)
  475. }
  476. CreateBWGroup <- function(
  477. groupNamei,
  478. availableChr,
  479. chromLengths,
  480. tiles,
  481. normBy,
  482. tileSize,
  483. normMethod,
  484. cutoff,
  485. outdir
  486. ) {
  487. if (!requireNamespace("rtracklayer", quietly = TRUE)) {
  488. message("Please install rtracklayer. http://www.bioconductor.org/packages/rtracklayer/")
  489. return(NULL)
  490. }
  491. normMethod <- tolower(x = normMethod)
  492. # Read the fragments file associated to the group
  493. fragi <- rtracklayer::import(
  494. paste0(outdir, .Platform$file.sep, groupNamei, ".bed"), format = "bed"
  495. )
  496. cellGroupi <- unique(x = fragi$name)
  497. # Open the writing bigwig file
  498. covFile <- file.path(
  499. outdir,
  500. paste0(groupNamei, "-TileSize-",tileSize,"-normMethod-",normMethod,".bw")
  501. )
  502. covList <- lapply(X = seq_along(availableChr), FUN = function(k) {
  503. fragik <- fragi[seqnames(fragi) == availableChr[k],]
  504. tilesk <- tiles[BiocGenerics::which(S4Vectors::match(seqnames(tiles), availableChr[k], nomatch = 0) > 0)]
  505. if (length(x = fragik) == 0) {
  506. tilesk$reads <- 0
  507. # If fragments
  508. } else {
  509. # N Tiles
  510. nTiles <- chromLengths[availableChr[k]] / tileSize
  511. # Add one tile if there is extra bases
  512. if (nTiles%%1 != 0) {
  513. nTiles <- trunc(x = nTiles) + 1
  514. }
  515. # Create Sparse Matrix
  516. matchID <- S4Vectors::match(mcols(fragik)$name, cellGroupi)
  517. # For each tiles of this chromosome, create start tile and end tile row,
  518. # set the associated counts matching with the fragments
  519. mat <- sparseMatrix(
  520. i = c(trunc(x = start(x = fragik) / tileSize),
  521. trunc(x = end(x = fragik) / tileSize)) + 1,
  522. j = as.vector(x = c(matchID, matchID)),
  523. x = rep(1, 2*length(x = fragik)),
  524. dims = c(nTiles, length(x = cellGroupi))
  525. )
  526. # Max count for a cells in a tile is set to cutoff
  527. if (!is.null(x = cutoff)){
  528. mat@x[mat@x > cutoff] <- cutoff
  529. }
  530. # Sums the cells
  531. mat <- rowSums(x = mat)
  532. tilesk$reads <- mat
  533. # Normalization
  534. if (!is.null(x = normMethod)) {
  535. if (normMethod == "rc") {
  536. tilesk$reads <- tilesk$reads * 10^4 / length(fragi$name)
  537. } else if (normMethod == "ncells") {
  538. tilesk$reads <- tilesk$reads / length(cellGroupi)
  539. } else if (normMethod == "none") {
  540. } else {
  541. if (!is.null(x = normBy)){
  542. tilesk$reads <- tilesk$reads * 10^4 / sum(normBy[cellGroupi, 1])
  543. }
  544. }
  545. }
  546. }
  547. tilesk <- coverage(tilesk, weight = tilesk$reads)[[availableChr[k]]]
  548. tilesk
  549. })
  550. names(covList) <- availableChr
  551. covList <- as(object = covList, Class = "RleList")
  552. rtracklayer::export.bw(object = covList, con = covFile)
  553. return(covFile)
  554. }
  555. SetIfNull <- function(x, y) {
  556. if (is.null(x = x)) {
  557. return(y)
  558. } else {
  559. return(x)
  560. }
  561. }
  562. repair_lanes <- function(seurat_obj, assay = "RNA", idents=NULL, to_fix_x, to_fix_y) {
  563. if(!is.null(idents)){
  564. seurat_tmp <- subset(seurat_obj, subset=orig.ident==idents)
  565. }else{
  566. seurat_tmp <- colnames(seurat_obj)
  567. }
  568. mat <- seurat_tmp[["RNA"]]$counts
  569. coord <- [email hidden][, c("x","y")]
  570. lengths_x <- sum(lengths(lapply(to_fix_x, function(x){sort(unique(coord[coord$x == x, ]$y))})))
  571. lengths_y <- sum(lengths(lapply(to_fix_y, function(y){sort(unique(coord[coord$y == y, ]$x))})))
  572. pb = txtProgressBar(min = 0, max = sum(lengths_x, lengths_y), style = 3)
  573. pb_counter=0
  574. for(to_fix in to_fix_x){
  575. all_y_list <- sort(unique(coord[coord$x == to_fix, ]$y))
  576. for (i in all_y_list) {
  577. pb_counter=pb_counter+1
  578. setTxtProgressBar(pb,pb_counter)
  579. if (i==1){
  580. idx_to_average <- c(which(coord$x == to_fix + 1 & coord$y == i))
  581. }else if(i==sqrt(nb_pixels_dbit)){
  582. idx_to_average <- c(which(coord$x == to_fix - 1 & coord$y == i))
  583. }else{
  584. idx_to_average <- c(which(coord$x == to_fix - 1 & coord$y == i), which(coord$x == to_fix + 1 & coord$y == i))
  585. }
  586. idx_to_fix <- which(coord$x == to_fix & coord$y == i)
  587. if (length(idx_to_average) > 0) {
  588. mat[, idx_to_fix] <- round(rowMeans(mat[, idx_to_average, drop = FALSE]))
  589. }
  590. }
  591. }
  592. for(to_fix in to_fix_y){
  593. all_x_list <- sort(unique(coord[coord$y == to_fix, ]$x))
  594. for (i in all_x_list) {
  595. pb_counter=pb_counter+1
  596. setTxtProgressBar(pb,pb_counter)
  597. if (i==1){
  598. idx_to_average <- c(which(coord$y == to_fix + 1 & coord$x == i))
  599. }else if(i==sqrt(nb_pixels_dbit)){
  600. idx_to_average <- c(which(coord$y == to_fix - 1 & coord$x == i))
  601. }else{
  602. idx_to_average <- c(which(coord$y == to_fix - 1 & coord$x == i), which(coord$y == to_fix + 1 & coord$x == i))
  603. }
  604. idx_to_fix <- which(coord$y == to_fix & coord$x == i)
  605. if (length(idx_to_average) > 0) {
  606. mat[, idx_to_fix] <- round(rowMeans(mat[, idx_to_average, drop = FALSE]))
  607. }
  608. }
  609. }
  610. close(pb)
  611. return(mat)
  612. }
  613. save_pheatmap_pdf <- function(x, filename, width=7, height=7) {
  614. stopifnot(!missing(x))
  615. stopifnot(!missing(filename))
  616. pdf(filename, width=width, height=height)
  617. grid::grid.newpage()
  618. grid::grid.draw(x$gtable)
  619. dev.off()
  620. }
  621. order_heatmap_genes <- function(x){
  622. if(ncol(x) == 1 | nrow(x) == 1) { return(rownames(x))
  623. } else {
  624. xs <- split(x, apply(x, 1, function(i) colnames(x)[which.max(i)]))
  625. if(ncol(x) == length(orig.ident_merge_colors)-1) {
  626. for(tp in names(xs)){
  627. xs[[tp]] <- xs[[tp]][order(xs[[tp]][,tp], decreasing=TRUE),]
  628. }
  629. }
  630. sapply(names(xs), function(i){
  631. order_heatmap_genes(xs[[i]][, colnames(x) != i, drop = FALSE ])
  632. }, simplify = FALSE)
  633. }
  634. }
  635. dilate <- function(mat, radius = 1) {
  636. padded <- matrix(0, nrow = nrow(mat) + 2 * radius, ncol = ncol(mat) + 2 * radius)
  637. padded[(radius + 1):(nrow(padded) - radius), (radius + 1):(ncol(padded) - radius)] <- mat
  638. result <- matrix(0, nrow = nrow(mat), ncol = ncol(mat))
  639. for (i in 1:nrow(mat)) {
  640. for (j in 1:ncol(mat)) {
  641. neighborhood <- padded[i:(i + 2*radius), j:(j + 2*radius)]
  642. if (sum(neighborhood) > 0) {
  643. result[i, j] <- 1
  644. }
  645. }
  646. }
  647. return(result)
  648. }
  649. cluster_compartment <- function(coords, k, dilation_radius, percentile_thresh, extra_clust_ratio, grid_size){
  650. knn_res <- get.knn(coords, k = k)
  651. edges <- do.call(rbind, lapply(1:nrow(coords), function(i) {
  652. cbind(i, knn_res$nn.index[i, ])
  653. }))
  654. g <- graph_from_edgelist(edges, directed = FALSE)
  655. clusters <- components(g)
  656. main_cluster_id <- which.max(clusters$csize)
  657. potential_extra_cluster <- which(clusters$csize>max(clusters$csize)*extra_clust_ratio)
  658. potential_extra_cluster <- unique(c(potential_extra_cluster,main_cluster_id))
  659. main_cluster_nodes <- which(clusters$membership %in% c(potential_extra_cluster))
  660. main_coords <- coords[main_cluster_nodes, ]
  661. avg_dists <- rowMeans(knn_res$nn.dist)
  662. threshold <- quantile(avg_dists, percentile_thresh)
  663. core_indices <- which(avg_dists <= threshold)
  664. core_coords <- main_coords[core_indices, ]
  665. avg_dists <- rowMeans(knn_res$nn.dist[main_cluster_nodes,])
  666. threshold <- quantile(avg_dists, percentile_thresh)
  667. keep_indices <- which(avg_dists <= threshold)
  668. filtered_coords <- main_coords[keep_indices, ]
  669. grid <- matrix(0, nrow = grid_size, ncol = grid_size)
  670. for (i in 1:nrow(filtered_coords)) {
  671. x <- filtered_coords[i, "x"]
  672. y <- filtered_coords[i, "y"]
  673. if (x >= 1 && x <= grid_size && y >= 1 && y <= grid_size) {
  674. grid[y, x] <- 1
  675. }
  676. }
  677. grid_filled <- dilate(grid, radius = dilation_radius)
  678. my_mat <- t(grid_filled)
  679. d1 <- expand.grid(x = 1:grid_size, y = 1:grid_size)
  680. out <- transform(d1, value = my_mat[as.matrix(d1)])
  681. return(out[out$value==1,])
  682. }
  683. barplot_with_error_and_dots <- function(data, x, y, error = c("se", "sd"), title) {
  684. error <- match.arg(error)
  685. x <- enquo(x)
  686. y <- enquo(y)
  687. summary_data <- data %>%
  688. group_by(!!x) %>%
  689. summarise(
  690. mean = mean(!!y, na.rm = TRUE),
  691. sd = sd(!!y, na.rm = TRUE),
  692. se = sd / sqrt(n()),
  693. .groups = 'drop'
  694. ) %>%
  695. mutate(error_value = ifelse(error == "sd", sd, se))
  696. # Base plot
  697. p <- ggplot(data, aes(x = !!x, y = !!y, fill = !!x)) +
  698. geom_bar(data = summary_data,
  699. aes(y = mean, fill = !!x),
  700. stat = "identity",
  701. width = 0.6,
  702. color = "black") +
  703. scale_fill_manual(values = orig.ident_merge_colors) +
  704. geom_errorbar(data = summary_data,
  705. aes(y = mean,
  706. ymin = mean - error_value,
  707. ymax = mean + error_value),
  708. width = 0.2) +
  709. geom_jitter(color = "black",
  710. width = 0.15, height = 0,
  711. size = 2, alpha = 0.8) +
  712. theme_minimal() +
  713. labs(y = title, x = "") +
  714. theme(legend.position = "none")
  715. return(p)
  716. }
  717. ```
  718. ```{r}
  719. options(repr.plot.width=5, repr.plot.height=5)
  720. color_palette_30 <- c(
  721. "#ffff00",
  722. "#8b4513",
  723. "#483d8b",
  724. "#008000",
  725. "#008b8b",
  726. "#4682b4",
  727. "#000080",
  728. "#daa520",
  729. "#7f007f",
  730. "#8fbc8f",
  731. "#b03060",
  732. "#ff4500",
  733. "#00ff00",
  734. "#deb887",
  735. "#556b2f",
  736. "#9400d3",
  737. "#00ff7f",
  738. "#dc143c",
  739. "#00ffff",
  740. "#0000ff",
  741. "#adff2f",
  742. "#1e90ff",
  743. "#fa8072",
  744. "#90ee90",
  745. "#add8e6",
  746. "#ff1493",
  747. "#7b68ee",
  748. "#ee82ee",
  749. "#ffb6c1")
  750. seurat_clusters_color <- list()
  751. n_clusters <- 22
  752. seurat_clusters_color <- color_palette_30[1:n_clusters]
  753. names(seurat_clusters_color) <- seq(1:n_clusters)-1
  754. show_col(seurat_clusters_color)
  755. ```
  756. ```{r}
  757. seurat_obj <- readRDS("/rds/project/rds-qqstKNzWvy8/Omar_Spatial/P35102_seurat_obj_clustering_DIET_20250819.rds")
  758. ```
  759. ```{r}
  760. DefaultAssay(seurat_obj) <- "RNA"
  761. seurat_obj <- JoinLayers(seurat_obj)
  762. seurat_obj <- NormalizeData(seurat_obj, normalization.method = "LogNormalize", scale.factor = 10000)
  763. DefaultAssay(seurat_obj) <- "RNA_repaired"
  764. seurat_obj <- NormalizeData(seurat_obj, normalization.method = "LogNormalize", scale.factor = 10000)
  765. ```
  766. ```{r}
  767. for (sample_name in names(orig.ident_colors)){
  768. annot_plot <- [email hidden][seurat_obj$orig.ident==sample_name,]
  769. options(repr.plot.width=5.3, repr.plot.height=4.6)
  770. df_tmp <- data.frame(
  771. x = annot_plot$x,
  772. y = annot_plot$y,
  773. value = annot_plot$seurat_clusters
  774. )
  775. print(ggplot(df_tmp, aes(x, y)) +
  776. geom_point(aes(colour = value),shape=15, size = 1)+
  777. scale_colour_manual(values=seurat_clusters_color) +
  778. scale_x_continuous(expand=c(-0.005,0), lim=c(0,101)) +
  779. scale_y_continuous(expand=c(-0.006,0), lim=c(0,101)) +
  780. theme_void() +
  781. ggtitle(sample_name))
  782. }
  783. ```
  784. ```{r}
  785. seurat_obj$InfOlive <- "NA"
  786. for (sample_name in names(orig.ident_colors)){
  787. message(sample_name)
  788. annot_plot_sample <- [email hidden][seurat_obj$orig.ident==sample_name,]
  789. annot_plot_cluster <- annot_plot_sample[annot_plot_sample$seurat_clusters==5,]
  790. #dilation of 5 for the core+pheriphery
  791. mat_peri_compartment <- cluster_compartment(annot_plot_cluster[,c("x","y")],k=5,dilation_radius=5,percentile_thresh=0.5,extra_clust_ratio=0.5,grid_size=sqrt(nb_pixels_dbit))
  792. #dilation of 2 for the core
  793. mat_core_compartment <- cluster_compartment(annot_plot_cluster[,c("x","y")],k=5,dilation_radius=2,percentile_thresh=0.5,extra_clust_ratio=0.5,grid_size=sqrt(nb_pixels_dbit))
  794. # Record periphery first
  795. for(line in 1:nrow(mat_peri_compartment)){
  796. annot_plot_sample[annot_plot_sample$x==mat_peri_compartment[line,"x"] & annot_plot_sample$y==mat_peri_compartment[line,"y"], "InfOlive"] <- "periphery"
  797. }
  798. # Record core second
  799. for(line in 1:nrow(mat_core_compartment)){
  800. annot_plot_sample[annot_plot_sample$x==mat_core_compartment[line,"x"] & annot_plot_sample$y==mat_core_compartment[line,"y"], "InfOlive"] <- "core"
  801. }
  802. [email hidden][rownames(annot_plot_sample),"InfOlive"] <- annot_plot_sample[,"InfOlive", drop=FALSE]
  803. }
  804. ```
  805. ```{r}
  806. for (sample_name in names(orig.ident_colors)){
  807. annot_plot <- [email hidden][seurat_obj$orig.ident==sample_name,]
  808. options(repr.plot.width=5.3, repr.plot.height=4.6)
  809. df_tmp <- data.frame(
  810. x = annot_plot$x,
  811. y = annot_plot$y,
  812. value = annot_plot$InfOlive
  813. )
  814. print(ggplot(df_tmp, aes(x, y)) +
  815. geom_point(aes(colour = value),shape=15, size = 1)+
  816. scale_x_continuous(expand=c(-0.005,0), lim=c(0,101)) +
  817. scale_y_continuous(expand=c(-0.006,0), lim=c(0,101)) +
  818. theme_void() +
  819. ggtitle(sample_name))
  820. }
  821. ```
  822. # Process the inferior olive
  823. ```{r}
  824. # read the rds
  825. seurat_obj_IO <- readRDS("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/P35102_seurat_obj_IO_DIET.rds")
  826. orig.ident_colors <- orig.ident_colors[!names(orig.ident_colors) %like% "D28"]
  827. orig.ident_merge_colors <- orig.ident_merge_colors[names(orig.ident_merge_colors) != "D28"]
  828. seurat_obj_IO <- subset(seurat_obj_IO, subset=orig.ident_merge!="D28")
  829. seurat_obj_IO$orig.ident <- factor(x = seurat_obj_IO$orig.ident, levels = names(orig.ident_colors))
  830. seurat_obj_IO$orig.ident_merge <- factor(x = seurat_obj_IO$orig.ident_merge, levels = names(orig.ident_merge_colors))
  831. ```
  832. ```{r}
  833. DefaultAssay(seurat_obj_IO) <- "RNA"
  834. seurat_obj_IO <- NormalizeData(seurat_obj_IO, normalization.method = "LogNormalize", scale.factor = 10000)
  835. DefaultAssay(seurat_obj_IO) <- "RNA_repaired"
  836. seurat_obj_IO <- NormalizeData(seurat_obj_IO, normalization.method = "LogNormalize", scale.factor = 10000)
  837. seurat_obj_IO <- FindVariableFeatures(seurat_obj_IO, selection.method = "vst", nfeatures = 1000)
  838. ```
  839. ```{r}
  840. options(repr.plot.width=10, repr.plot.height=7)
  841. VariableFeaturePlot(object = seurat_obj_IO, selection.method = "vst", log = TRUE)
  842. ```
  843. ```{r}
  844. seurat_obj_IO <- ScaleData(seurat_obj_IO, features = rownames(seurat_obj_IO))
  845. ```
  846. ```{r}
  847. seurat_obj_IO <- RunPCA(seurat_obj_IO)
  848. ```
  849. ```{r}
  850. options(repr.plot.width=10, repr.plot.height=7)
  851. ElbowPlot(seurat_obj_IO, reduction = "pca", ndims = 50)
  852. ```
  853. ```{r}
  854. nb_pcs = 20
  855. seurat_obj_IO <- FindNeighbors(seurat_obj_IO, reduction = "pca", dims = 1:nb_pcs, prune.SNN = 0)
  856. ```
  857. ```{r}
  858. cluster_res = 1
  859. DefaultAssay(seurat_obj_IO) <- "RNA_repaired"
  860. seurat_obj_IO <- FindClusters(seurat_obj_IO, resolution = cluster_res)
  861. ```
  862. ```{r}
  863. table(seurat_obj_IO$seurat_clusters)
  864. ```
  865. ```{r}
  866. seurat_clusters_IO_color <- list()
  867. n_clusters <- 9
  868. seurat_clusters_IO_color <- color_palette_30[1:n_clusters]
  869. names(seurat_clusters_IO_color) <- seq(1:n_clusters)-1
  870. seurat_obj_IO <- RunUMAP(seurat_obj_IO, reduction = "pca", dims = 1:nb_pcs)
  871. options(repr.plot.width=25, repr.plot.height=8)
  872. DimPlot(seurat_obj_IO, group.by="orig.ident", split.by="orig.ident_merge", cols=orig.ident_colors, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  873. ```
  874. ```{r}
  875. options(repr.plot.width=11, repr.plot.height=9)
  876. for(timepoint in names(orig.ident_merge_colors)){
  877. highlight_cells <- rownames([email hidden][[email hidden]$orig.ident_merge==timepoint,])
  878. print(DimPlot(seurat_obj_IO, cells.highlight = highlight_cells, pt.size=0.5, cols.highlight = orig.ident_merge_colors[timepoint], raster=FALSE))
  879. }
  880. ```
  881. ```{r}
  882. options(repr.plot.width=11, repr.plot.height=9)
  883. DimPlot(seurat_obj_IO, group.by="seurat_clusters", cols=seurat_clusters_IO_color, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE)
  884. ```
  885. ```{r}
  886. options(repr.plot.width=25, repr.plot.height=8)
  887. DimPlot(seurat_obj_IO, group.by="seurat_clusters", split.by="orig.ident_merge", cols=seurat_clusters_IO_color, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  888. ```
  889. ```{r}
  890. DefaultAssay(seurat_obj_IO) <- "RNA_repaired"
  891. options(repr.plot.width=25, repr.plot.height=60)
  892. FeaturePlot(seurat_obj_IO, feature=c("Calb1"), pt.size=0.5, label=FALSE, raster=FALSE)
  893. ```
  894. ```{r}
  895. options(repr.plot.width=25, repr.plot.height=60)
  896. p <- FeaturePlot(seurat_obj_IO, feature = "Calb1", pt.size = 1, label = FALSE, raster = FALSE, order = TRUE) +
  897. NoAxes()
  898. # Change the color using a viridis palette
  899. p1 <- p + viridis::scale_color_viridis(option = "magma", direction = -1)
  900. print(p1)
  901. ggsave("IO_calb1Ex_umap_20250915.svg", p1)
  902. ```
  903. ```{r}
  904. DefaultAssay(seurat_obj_IO) <- "RNA_repaired"
  905. options(repr.plot.width=25, repr.plot.height=60)
  906. FeaturePlot(seurat_obj_IO, feature=c("Calb1", "Aif1"), split.by="orig.ident_merge", ncol=4, pt.size=0.1, label=FALSE, raster=FALSE)
  907. ```
  908. ```{r}
  909. options(repr.plot.width=15, repr.plot.height=15)
  910. set.seed(115)
  911. mat = as.matrix(table(seurat_obj_IO$orig.ident_merge, seurat_obj_IO$seurat_clusters))
  912. for (row in 1:nrow(mat)) mat[row,] <- as.integer(mat[row,]/(sum(mat[row,])/min(rowSums(mat))))
  913. circos.clear()
  914. par(cex = 0.8)
  915. chordDiagram(mat, annotationTrack = c("grid", "axis"), preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(mat))))/3), big.gap = 20, small.gap = 2, order = c(colnames(mat), names(orig.ident_merge_colors)), grid.col=c(rev(seurat_clusters_IO_color), rev(orig.ident_merge_colors)))
  916. circos.track(track.index = 1, panel.fun = function(x, y) {circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, facing = "clockwise", niceFacing = TRUE, adj = c(-0.3, 0.5))}, bg.border = NA)
  917. ```
  918. ```{r}
  919. pdf("Chord_Plot_IO_20250910.pdf", width=8, height=8)
  920. options(repr.plot.width=15, repr.plot.height=15)
  921. set.seed(115)
  922. mat = as.matrix(table(seurat_obj_IO$orig.ident_merge, seurat_obj_IO$seurat_clusters))
  923. for (row in 1:nrow(mat)) mat[row,] <- as.integer(mat[row,]/(sum(mat[row,])/min(rowSums(mat))))
  924. circos.clear()
  925. par(cex = 0.8)
  926. chordDiagram(mat, annotationTrack = c("grid", "axis"), preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(mat))))/3), big.gap = 20, small.gap = 2, order = c(colnames(mat), names(orig.ident_merge_colors)), grid.col=c(rev(seurat_clusters_IO_color), rev(orig.ident_merge_colors)))
  927. circos.track(track.index = 1, panel.fun = function(x, y) {circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, facing = "clockwise", niceFacing = TRUE, adj = c(-0.3, 0.5))}, bg.border = NA)
  928. dev.off()
  929. ```
  930. ```{r}
  931. t <- table(Cluster=seurat_obj_IO$seurat_clusters, Batch=[email hidden][["orig.ident_merge"]])
  932. t <- t[,rev(names(orig.ident_merge_colors))]
  933. options(repr.plot.width=10, repr.plot.height=10)
  934. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+500, 20, f = ceiling)), col = rev(orig.ident_merge_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  935. ```
  936. ```{r}
  937. t <- table(Cluster=seurat_obj_IO$seurat_clusters, Batch=[email hidden][["orig.ident"]])
  938. t <- t[,rev(names(orig.ident_colors))]
  939. options(repr.plot.width=10, repr.plot.height=10)
  940. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+1000, 20, f = ceiling)), col = rev(orig.ident_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  941. ```
  942. ```{r}
  943. DefaultAssay(seurat_obj_IO) <- "RNA"
  944. Idents(object = seurat_obj_IO) <- "seurat_clusters"
  945. ```
  946. ```{r}
  947. seurat_obj_IO.markers.seurat_clusters <- FindAllMarkers(seurat_obj_IO, slot = "data", min.pct = 0.1, logfc.threshold = 0.5, only.pos = TRUE)
  948. ```
  949. ```{r}
  950. seurat_obj_IO.markers.seurat_clusters_pval <- seurat_obj_IO.markers.seurat_clusters[seurat_obj_IO.markers.seurat_clusters$p_val_adj < 0.05,]
  951. seurat_obj_IO.markers.seurat_clusters_best <- seurat_obj_IO.markers.seurat_clusters_pval %>%
  952. filter(avg_log2FC > 0.5) %>%
  953. filter(pct.1 > 0.3) %>%
  954. arrange(cluster, desc(avg_log2FC)) %>%
  955. group_by(cluster)
  956. markers_heatmap <- seurat_obj_IO.markers.seurat_clusters_best %>% top_n(n = 10, wt = avg_log2FC)
  957. topDiffCluster <- seurat_obj_IO.markers.seurat_clusters_best %>% top_n(n = 50, wt = avg_log2FC)
  958. sample_df <- as.data.frame(lapply(split(topDiffCluster, topDiffCluster$cluster), function(x) c(x$gene,rep("None", 50-length(x$gene)))))
  959. colnames(sample_df) <- levels(topDiffCluster$cluster)
  960. sample_df
  961. ```
  962. ```{r}
  963. # export the cluster marker for all pixels
  964. write.csv(sample_df, "IO_allPixel_clusterMarkers_20250915.csv", row.names = TRUE)
  965. ```
  966. ```{r}
  967. options(repr.plot.width=30, repr.plot.height=20)
  968. DoMultiBarHeatmap(
  969. subset(seurat_obj_IO, downsample = 200),
  970. features = unique(markers_heatmap$gene),
  971. cells = NULL,
  972. group.by = "seurat_clusters",
  973. additional.group.by = c("orig.ident_merge"),
  974. additional.group.sort.by = c("orig.ident_merge"),
  975. cols.use = list(seurat_clusters=seurat_clusters_IO_color, orig.ident_merge=orig.ident_merge_colors),
  976. group.bar = TRUE,
  977. disp.min = -2.5,
  978. disp.max = NULL,
  979. layer = "scale.data",
  980. assay = "RNA_repaired",
  981. label = TRUE,
  982. size = 5.5,
  983. hjust = 0,
  984. angle = 45,
  985. raster = TRUE,
  986. draw.lines = TRUE,
  987. lines.width = NULL,
  988. group.bar.height = 0.02,
  989. combine = TRUE
  990. ) + theme(text = element_text(size = 8))
  991. ```
  992. ```{r}
  993. for (sample_name in names(orig.ident_colors)){
  994. annot_plot <- [email hidden][seurat_obj_IO$orig.ident==sample_name,]
  995. options(repr.plot.width=5.3, repr.plot.height=4.6)
  996. df_tmp <- data.frame(
  997. x = annot_plot$x,
  998. y = annot_plot$y,
  999. value = annot_plot$seurat_clusters
  1000. )
  1001. print(ggplot(df_tmp, aes(x, y)) +
  1002. geom_point(aes(colour = value),shape=15, size = 1)+
  1003. scale_color_manual(values=seurat_clusters_IO_color) +
  1004. scale_x_continuous(expand=c(-0.005,0), lim=c(0,101)) +
  1005. scale_y_continuous(expand=c(-0.006,0), lim=c(0,101)) +
  1006. theme_void() +
  1007. ggtitle(sample_name))
  1008. }
  1009. ```
  1010. ```{r}
  1011. # load the given .rds file instead of using subset
  1012. # seurat_obj_IO_calb1 <- subset(seurat_obj_IO, subset = Calb1 > 0, slot = "counts")
  1013. ```
  1014. # 7. Calbindin neurons in the IO
  1015. ```{r}
  1016. # load the given .rds file instead of running
  1017. seurat_obj_IO_calb1 <- readRDS("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/seurat_obj_IO_calb1_DIET.rds")
  1018. ```
  1019. ```{r}
  1020. options(repr.plot.width=11, repr.plot.height=9)
  1021. DimPlot(seurat_obj_IO, cells.highlight = colnames(seurat_obj_IO_calb1), pt.size=0.5,cols.highlight = c("red", "grey50"), raster=FALSE)
  1022. ```
  1023. ```{r}
  1024. percent_micro <- (as.vector(table(seurat_obj_IO_calb1$orig.ident))[1:12]*100)/as.vector(table(seurat_obj_IO$orig.ident))[1:12]
  1025. mat <- tibble(
  1026. group = c("Ctrl","Ctrl","Ctrl","Ctrl","D7","D7","D7","D7","D14","D14","D14","D14"),
  1027. measurement = percent_micro
  1028. )
  1029. mat$group <- factor(mat$group, levels = c("Ctrl", "D7", "D14"))
  1030. options(repr.plot.width=4, repr.plot.height=6)
  1031. barplot_with_error_and_dots(mat, x = group, y = measurement, error = "se", title="Calb1+ pixels (% of IO)")
  1032. ```
  1033. ```{r}
  1034. DefaultAssay(seurat_obj_IO_calb1) <- "RNA"
  1035. seurat_obj_IO_calb1 <- NormalizeData(seurat_obj_IO_calb1, normalization.method = "LogNormalize", scale.factor = 10000)
  1036. DefaultAssay(seurat_obj_IO_calb1) <- "RNA_repaired"
  1037. seurat_obj_IO_calb1 <- NormalizeData(seurat_obj_IO_calb1, normalization.method = "LogNormalize", scale.factor = 10000)
  1038. seurat_obj_IO_calb1 <- FindVariableFeatures(seurat_obj_IO_calb1, selection.method = "vst", nfeatures = 1000)
  1039. options(repr.plot.width=10, repr.plot.height=7)
  1040. VariableFeaturePlot(object = seurat_obj_IO_calb1, selection.method = "vst", log = TRUE)
  1041. ```
  1042. ```{r}
  1043. seurat_obj_IO_calb1 <- ScaleData(seurat_obj_IO_calb1, features = rownames(seurat_obj_IO_calb1))
  1044. ```
  1045. ```{r}
  1046. seurat_obj_IO_calb1 <- RunPCA(seurat_obj_IO_calb1)
  1047. ```
  1048. ```{r}
  1049. options(repr.plot.width=10, repr.plot.height=7)
  1050. ElbowPlot(seurat_obj_IO_calb1, reduction = "pca", ndims = 50)
  1051. ```
  1052. ```{r}
  1053. nb_pcs = 20
  1054. seurat_obj_IO_calb1 <- FindNeighbors(seurat_obj_IO_calb1, reduction = "pca", dims = 1:nb_pcs, prune.SNN = 0)
  1055. #
  1056. cluster_res = 0.8
  1057. seurat_obj_IO_calb1 <- FindClusters(seurat_obj_IO_calb1, resolution = cluster_res)
  1058. ```
  1059. ```{r}
  1060. table(seurat_obj_IO_calb1$seurat_clusters)
  1061. ```
  1062. ```{r}
  1063. seurat_clusters_IO_calb1_color <- list()
  1064. n_clusters <- 5
  1065. seurat_clusters_IO_calb1_color <- color_palette_30[1:n_clusters]
  1066. names(seurat_clusters_IO_calb1_color) <- seq(1:n_clusters)-1
  1067. seurat_obj_IO_calb1 <- RunUMAP(seurat_obj_IO_calb1, reduction = "pca", dims = 1:nb_pcs)
  1068. ```
  1069. ```{r}
  1070. options(repr.plot.width=25, repr.plot.height=8)
  1071. DimPlot(seurat_obj_IO_calb1, group.by="orig.ident", split.by="orig.ident_merge", cols=orig.ident_colors, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  1072. ```
  1073. ```{r}
  1074. options(repr.plot.width=11, repr.plot.height=9)
  1075. for(timepoint in names(orig.ident_merge_colors)){
  1076. highlight_cells <- rownames([email hidden][[email hidden]$orig.ident_merge==timepoint,])
  1077. print(DimPlot(seurat_obj_IO_calb1, cells.highlight = highlight_cells, pt.size=0.5, cols.highlight = orig.ident_merge_colors[timepoint], raster=FALSE))
  1078. }
  1079. ```
  1080. ```{r}
  1081. options(repr.plot.width=11, repr.plot.height=9)
  1082. DimPlot(seurat_obj_IO_calb1, group.by="seurat_clusters", cols=seurat_clusters_IO_calb1_color, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE) + NoAxes()
  1083. ```
  1084. ```{r}
  1085. # export the umap in .svg file
  1086. svg(file="IO_calb1_neuron_20250910.svg", width=4, height=4)
  1087. DimPlot(seurat_obj_IO_calb1, group.by="seurat_clusters", cols=seurat_clusters_IO_calb1_color, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE)+ NoAxes()
  1088. dev.off()
  1089. ```
  1090. ```{r}
  1091. options(repr.plot.width=11, repr.plot.height=9)
  1092. DimPlot(seurat_obj_IO_calb1, group.by="orig.ident_merge", cols=orig.ident_merge_colors, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE)
  1093. ```
  1094. ```{r}
  1095. # export the umap in .svg file
  1096. svg(file="IO_calb1_neuron_days_20250903.svg", width=11, height=9)
  1097. DimPlot(seurat_obj_IO_calb1, group.by="orig.ident_merge", cols=orig.ident_merge_colors, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE)
  1098. dev.off()
  1099. ```
  1100. ```{r}
  1101. options(repr.plot.width=25, repr.plot.height=8)
  1102. DimPlot(seurat_obj_IO_calb1, group.by="seurat_clusters", split.by="orig.ident_merge", cols=seurat_clusters_IO_calb1_color, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  1103. ```
  1104. ```{r}
  1105. # Extract metadata
  1106. df <- [email hidden] %>%
  1107. dplyr::select(seurat_clusters, orig.ident_merge)
  1108. # Count cells per cluster and per day
  1109. df_summary <- df %>%
  1110. group_by(orig.ident_merge, seurat_clusters) %>%
  1111. summarise(n = n(), .groups = "drop") %>%
  1112. group_by(orig.ident_merge) %>%
  1113. mutate(freq = n / sum(n)) # normalize to fractions
  1114. # Plot stacked barplot
  1115. ggplot(df_summary, aes(x = orig.ident_merge, y = freq, fill = seurat_clusters)) +
  1116. geom_bar(stat = "identity", position = "fill") +
  1117. ylab("Fraction of Cells") +
  1118. xlab("Day") +
  1119. scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  1120. theme_classic() +
  1121. theme(axis.text.x = element_text(angle = 45, hjust = 1))
  1122. ggplot(df_summary, aes(x = orig.ident_merge, y = freq, fill = seurat_clusters)) +
  1123. geom_bar(stat = "identity", position = "fill") +
  1124. geom_text(aes(label = scales::percent(freq, accuracy = 1)),
  1125. position = position_stack(vjust = 0.5), size = 3) +
  1126. ylab("Fraction of Cells") +
  1127. xlab("Day") +
  1128. scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  1129. theme_classic() +
  1130. theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  1131. scale_fill_manual(values = seurat_clusters_IO_calb1_color)
  1132. ```
  1133. ```{r}
  1134. # export the bar plot
  1135. barPlot <- ggplot(df_summary, aes(x = orig.ident_merge, y = freq, fill = seurat_clusters)) +
  1136. geom_bar(stat = "identity", position = "fill") +
  1137. geom_text(aes(label = scales::percent(freq, accuracy = 1)),
  1138. position = position_stack(vjust = 0.5), size = 3) +
  1139. ylab("Fraction of Cells") +
  1140. xlab("Day") +
  1141. scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  1142. theme_classic() +
  1143. theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  1144. scale_fill_manual(values = seurat_clusters_IO_calb1_color)
  1145. ggsave(filename = "IO_calb1Neuron_Cluster_barplot_20250903.svg", plot = barPlot, width = 10, height = 8, units = "in")
  1146. ```
  1147. ```{r}
  1148. options(repr.plot.width=15, repr.plot.height=15)
  1149. set.seed(115)
  1150. mat = as.matrix(table(seurat_obj_IO_calb1$orig.ident_merge, seurat_obj_IO_calb1$seurat_clusters))
  1151. for (row in 1:nrow(mat)) mat[row,] <- as.integer(mat[row,]/(sum(mat[row,])/min(rowSums(mat))))
  1152. circos.clear()
  1153. par(cex = 0.8)
  1154. chordDiagram(mat, annotationTrack = c("grid", "axis"), preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(mat))))/3), big.gap = 20, small.gap = 2, order = c(colnames(mat), names(orig.ident_merge_colors)), grid.col=c(rev(seurat_clusters_IO_calb1_color), rev(orig.ident_merge_colors)))
  1155. circos.track(track.index = 1, panel.fun = function(x, y) {circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, facing = "clockwise", niceFacing = TRUE, adj = c(-0.3, 0.5))}, bg.border = NA)
  1156. ```
  1157. ```{r}
  1158. pdf("Chord_plot_IO_NeuronClus.pdf", width=8, height=8)
  1159. options(repr.plot.width=15, repr.plot.height=15)
  1160. set.seed(115)
  1161. mat = as.matrix(table(seurat_obj_IO_calb1$orig.ident_merge, seurat_obj_IO_calb1$seurat_clusters))
  1162. for (row in 1:nrow(mat)) mat[row,] <- as.integer(mat[row,]/(sum(mat[row,])/min(rowSums(mat))))
  1163. circos.clear()
  1164. par(cex = 0.8)
  1165. chordDiagram(mat, annotationTrack = c("grid", "axis"), preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(mat))))/3), big.gap = 20, small.gap = 2, order = c(colnames(mat), names(orig.ident_merge_colors)), grid.col=c(rev(seurat_clusters_IO_calb1_color), rev(orig.ident_merge_colors)))
  1166. circos.track(track.index = 1, panel.fun = function(x, y) {circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, facing = "clockwise", niceFacing = TRUE, adj = c(-0.3, 0.5))}, bg.border = NA)
  1167. dev.off()
  1168. ```
  1169. ```{r}
  1170. df_table <- as.data.frame(table(seurat_obj_IO_calb1$orig.ident, seurat_obj_IO_calb1$seurat_clusters))
  1171. colnames(df_table) <- c("group", "cluster", "count")
  1172. t <- table(seurat_obj_IO_calb1$orig.ident, seurat_obj_IO_calb1$seurat_clusters)
  1173. t_prop <- t/as.vector(table(seurat_obj_IO$orig.ident))*100
  1174. rownames(t_prop) <- c("Ctrl","Ctrl","Ctrl","Ctrl","D7","D7","D7","D7","D14","D14","D14","D14")
  1175. df_table <- as.data.frame(t_prop)
  1176. colnames(df_table) <- c("group", "cluster", "count")
  1177. df_summary <- df_table %>%
  1178. group_by(group, cluster) %>%
  1179. summarise(
  1180. mean = mean(count),
  1181. se = sd(count) / sqrt(n()),
  1182. .groups = "drop"
  1183. )
  1184. options(repr.plot.width=10, repr.plot.height=10)
  1185. ggplot(df_summary, aes(x = cluster, y = mean, fill = group)) +
  1186. # Bars
  1187. geom_bar(stat = "identity", position = position_dodge(width = 0.9), color = "black") +
  1188. # Error bars
  1189. geom_errorbar(aes(ymin = mean - se, ymax = mean + se),
  1190. position = position_dodge(width = 0.9),
  1191. width = 0.2) +
  1192. # Manual fill colors
  1193. scale_fill_manual(values = orig.ident_merge_colors) +
  1194. # Points dodged and jittered
  1195. geom_point(
  1196. data = df_table,
  1197. aes(x = cluster, y = count, fill = group), # <- fill included so dodge works
  1198. position = position_jitterdodge(jitter.width = 0.4, dodge.width = 0.9),
  1199. size = 2, shape = 21, stroke = 0.5,
  1200. color = "black", # border
  1201. show.legend = FALSE
  1202. ) +
  1203. theme_minimal() +
  1204. labs(x = "", y = "% of pixels in the IO") +
  1205. ggtitle("Number of calbindin neurons pixels divided by each IO for each sample") +
  1206. theme(panel.grid.major.x = element_blank(),
  1207. panel.grid.minor.x = element_blank())
  1208. ```
  1209. ```{r}
  1210. t <- table(Cluster=seurat_obj_IO_calb1$seurat_clusters, Batch=[email hidden][["orig.ident_merge"]])
  1211. t <- t[,rev(names(orig.ident_merge_colors))]
  1212. options(repr.plot.width=10, repr.plot.height=10)
  1213. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+100, 20, f = ceiling)), col = rev(orig.ident_merge_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  1214. ```
  1215. ```{r}
  1216. t <- table(Cluster=seurat_obj_IO_calb1$seurat_clusters, Batch=[email hidden][["orig.ident"]])
  1217. t <- t[,rev(names(orig.ident_colors))]
  1218. options(repr.plot.width=10, repr.plot.height=10)
  1219. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+150, 20, f = ceiling)), col = rev(orig.ident_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  1220. ```
  1221. ```{r}
  1222. DefaultAssay(seurat_obj_IO_calb1) <- "RNA"
  1223. Idents(object = seurat_obj_IO_calb1) <- "seurat_clusters"
  1224. seurat_obj_IO_calb1.markers.seurat_clusters <- FindAllMarkers(seurat_obj_IO_calb1, slot = "data", min.pct = 0.1, logfc.threshold = 0, only.pos = TRUE)
  1225. ```
  1226. ```{r}
  1227. write.csv( seurat_obj_IO_calb1.markers.seurat_clusters, "IO_calb1_neuron_clusterMarkers_20250916.csv")
  1228. ```
  1229. ```{r}
  1230. seurat_obj_IO_calb1.markers.seurat_clusters_pval <- seurat_obj_IO_calb1.markers.seurat_clusters[seurat_obj_IO_calb1.markers.seurat_clusters$p_val_adj < 0.05,]
  1231. seurat_obj_IO_calb1.markers.seurat_clusters_best <- seurat_obj_IO_calb1.markers.seurat_clusters_pval %>%
  1232. filter(avg_log2FC > 0.5) %>%
  1233. filter(pct.1 > 0.3) %>%
  1234. arrange(cluster, desc(avg_log2FC)) %>%
  1235. group_by(cluster)
  1236. markers_heatmap <- seurat_obj_IO_calb1.markers.seurat_clusters_best %>% top_n(n = 10, wt = avg_log2FC)
  1237. topDiffCluster <- seurat_obj_IO_calb1.markers.seurat_clusters_best %>% top_n(n = 200, wt = avg_log2FC)
  1238. sample_df <- as.data.frame(lapply(split(topDiffCluster, topDiffCluster$cluster), function(x) c(x$gene,rep("None", 200-length(x$gene)))))
  1239. colnames(sample_df) <- levels(topDiffCluster$cluster)
  1240. sample_df
  1241. ```
  1242. ```{r}
  1243. options(repr.plot.width=30, repr.plot.height=20)
  1244. DoMultiBarHeatmap(
  1245. subset(seurat_obj_IO_calb1, downsample = 200),
  1246. features = unique(markers_heatmap$gene),
  1247. cells = NULL,
  1248. group.by = "seurat_clusters",
  1249. additional.group.by = c("orig.ident_merge"),
  1250. additional.group.sort.by = c("orig.ident_merge"),
  1251. cols.use = list(seurat_clusters=seurat_clusters_IO_calb1_color, orig.ident_merge=orig.ident_merge_colors),
  1252. group.bar = TRUE,
  1253. disp.min = -2.5,
  1254. disp.max = NULL,
  1255. layer = "scale.data",
  1256. assay = "RNA_repaired",
  1257. label = TRUE,
  1258. size = 5.5,
  1259. hjust = 0,
  1260. angle = 45,
  1261. raster = TRUE,
  1262. draw.lines = TRUE,
  1263. lines.width = NULL,
  1264. group.bar.height = 0.02,
  1265. combine = TRUE
  1266. ) + theme(text = element_text(size = 8))
  1267. ```
  1268. ```{r}
  1269. for (sample_name in names(orig.ident_colors)){
  1270. annot_plot <- [email hidden][seurat_obj_IO_calb1$orig.ident==sample_name,]
  1271. annot_plot_plus <- [email hidden][(seurat_obj_IO$orig.ident==sample_name & seurat_obj_IO$InfOlive=="core"),]
  1272. annot_plot_plus <- annot_plot_plus[!(rownames(annot_plot_plus) %in% rownames(annot_plot)),]
  1273. annot_plot_plus$seurat_clusters <- 99
  1274. annot_plot <- annot_plot[,c("x","y","seurat_clusters")]
  1275. annot_plot_plus <- annot_plot_plus[,c("x","y","seurat_clusters")]
  1276. annot_plot$seurat_clusters <- as.character(annot_plot$seurat_clusters)
  1277. annot_plot_plus$seurat_clusters <- as.character(annot_plot_plus$seurat_clusters)
  1278. annot_plot <- rbind(annot_plot_plus,annot_plot)
  1279. annot_plot$seurat_clusters <- factor(x = annot_plot$seurat_clusters, levels = c(names(seurat_clusters_IO_calb1_color),99))
  1280. options(repr.plot.width=5.3, repr.plot.height=4.6)
  1281. df_tmp <- data.frame(
  1282. x = annot_plot$x,
  1283. y = annot_plot$y,
  1284. value = annot_plot$seurat_clusters
  1285. )
  1286. tmp_colors <- c(seurat_clusters_IO_calb1_color,"lightgrey")
  1287. names(tmp_colors) <- c(names(seurat_clusters_IO_calb1_color),99)
  1288. print(ggplot(df_tmp, aes(x, y)) +
  1289. geom_point(aes(colour = value),shape=15, size = 1)+
  1290. scale_color_manual(values=tmp_colors) +
  1291. scale_x_continuous(expand=c(-0.005,0), lim=c(0,101)) +
  1292. scale_y_continuous(expand=c(-0.006,0), lim=c(0,101)) +
  1293. theme_void() +
  1294. ggtitle(sample_name))
  1295. }
  1296. ```
  1297. ## Run GO on the neuron cluster markers
  1298. ```{r}
  1299. # extract gene lists from sample_df
  1300. Clus0_markers <- sample_df[,1]
  1301. Clus1_markers <- sample_df[,2]
  1302. Clus2_markers <- sample_df[,3]
  1303. Clus3_markers <- sample_df[,4]
  1304. Clus4_markers <- sample_df[,5]
  1305. # dbs set up
  1306. dbs <- c("GO_Molecular_Function_2023","GO_Cellular_Component_2023","GO_Biological_Process_2023","KEGG_2019_Mouse") # ,"HDSigDB_Mouse_2021","Tabula_Muris","WikiPathways_2024_Mouse")
  1307. #
  1308. enrichedR.list <- list()
  1309. enrichedR.list[["Clus0_markers"]] <- enrichr(Clus0_markers, dbs)
  1310. enrichedR.list[["Clus1_markers"]] <- enrichr(Clus1_markers, dbs)
  1311. enrichedR.list[["Clus2_markers"]] <- enrichr(Clus2_markers, dbs)
  1312. enrichedR.list[["Clus3_markers"]] <- enrichr(Clus3_markers, dbs)
  1313. enrichedR.list[["Clus4_markers"]] <- enrichr(Clus4_markers, dbs)
  1314. ```
  1315. ```{r}
  1316. library(openxlsx)
  1317. # Create an empty list to store the data frames for export
  1318. export_list <- list()
  1319. # Loop through your enrichedR.list and extract a specific database for each cluster
  1320. for (cluster_name in names(enrichedR.list)) {
  1321. # For example, extract the "GO_Biological_Process_2023" results
  1322. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$GO_Biological_Process_2023
  1323. }
  1324. # Export the prepared list to a single Excel file
  1325. write.xlsx(export_list, file = "enrichment_IO_calb1_neuron_GO_KEGG.xlsx")
  1326. ```
  1327. ```{r}
  1328. pdf("enrichment_plot_IO_NeuronClus_200gene_20250915.pdf", width=12, height=8)
  1329. for (dge in names(enrichedR.list)) {
  1330. for (go_db in dbs) {
  1331. enr_df <- enrichedR.list[[dge]][[go_db]]
  1332. if (is.null(enr_df) || nrow(enr_df) == 0) {
  1333. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  1334. next
  1335. }
  1336. p <- plotEnrich(
  1337. enr_df,
  1338. showTerms = 50,
  1339. numChar = 100,
  1340. y = "Count",
  1341. orderBy = "FDR",
  1342. title = paste0(dge," in ", go_db),
  1343. xlab = ""
  1344. )
  1345. print(
  1346. p + theme(
  1347. axis.text.x = element_text(size = 6),
  1348. axis.text.y = element_text(size = 8),
  1349. axis.title = element_text(size = 6),
  1350. plot.title = element_text(size = 10),
  1351. plot.margin = margin(10, 10, 10, 10)
  1352. )
  1353. )
  1354. }
  1355. }
  1356. dev.off()
  1357. ```
  1358. ## DGE on IO neurons Calb1+
  1359. ```{r}
  1360. condition <- "IO"
  1361. HVGs.list <- list()
  1362. res.list <- list()
  1363. HVGs.list[[condition]] <- list()
  1364. res.list[[condition]] <- list()
  1365. ```
  1366. ```{r}
  1367. DefaultAssay(seurat_obj_IO_calb1) <- 'RNA'
  1368. table(seurat_obj_IO_calb1$orig.ident_merge)
  1369. ```
  1370. ```{r}
  1371. seurat_obj_sce_calb1 <- as.SingleCellExperiment(seurat_obj_IO_calb1, assay="RNA")
  1372. seurat_obj_sce_calb1 <- prepSCE(seurat_obj_sce_calb1, kid = "InfOlive", gid = "orig.ident_merge", sid = "orig.ident", drop = FALSE)
  1373. kids <- purrr::set_names(levels(seurat_obj_sce_calb1$cluster_id))
  1374. # Total number of clusters
  1375. nk <- length(kids)
  1376. # Named vector of sample names
  1377. sids <- purrr::set_names(levels(seurat_obj_sce_calb1$sample_id))
  1378. # Total number of samples
  1379. ns <- length(sids)
  1380. kids
  1381. sids
  1382. ```
  1383. ```{r}
  1384. ## Determine the number of cells per sample
  1385. table(seurat_obj_sce_calb1$sample_id)
  1386. ## Turn named vector into a numeric vector of number of cells per sample
  1387. n_cells <- as.numeric(table(seurat_obj_sce_calb1$sample_id))
  1388. ## Determine how to reoder the samples (rows) of the metadata to match the order of sample names in sids vector
  1389. m <- match(sids, seurat_obj_sce_calb1$sample_id)
  1390. ## Create the sample level metadata by combining the reordered metadata with the number of cells corresponding to each sample.
  1391. ei <- data.frame(colData(seurat_obj_sce_calb1)[m, ], n_cells, row.names = NULL) %>% dplyr::select(-"cluster_id")
  1392. ei
  1393. ```
  1394. ```{r}
  1395. # Aggregate the counts per sample_id and cluster_id
  1396. # Subset metadata to only include the cluster and sample IDs to aggregate across
  1397. groups <- colData(seurat_obj_sce_calb1)[, c("cluster_id", "sample_id")]
  1398. # Aggregate across cluster-sample groups
  1399. pb <- aggregate.Matrix(t(counts(seurat_obj_sce_calb1)), groupings = groups, fun = "sum")
  1400. splitf <- sapply(stringr::str_split(rownames(pb), pattern = "_", n = 2), `[`, 1)
  1401. pb <- split.data.frame(pb, factor(splitf)) %>% lapply(function(u) magrittr::set_colnames(t(u), stringr::str_extract(rownames(u), "(?<=_)[:alnum:]+")))
  1402. class(pb)
  1403. # Explore the different components of list
  1404. str(pb)
  1405. ```
  1406. ```{r}
  1407. options(width = 100)
  1408. table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$group_id)
  1409. ```
  1410. ```{r}
  1411. options(width = 100)
  1412. table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$seurat_clusters)
  1413. ```
  1414. ```{r}
  1415. # prep. data.frame for plotting
  1416. get_sample_ids <- function(x){pb[[x]] %>% colnames()}
  1417. de_samples <- purrr::map(1:length(kids), get_sample_ids) %>% unlist()
  1418. samples_list <- purrr::map(1:length(kids), get_sample_ids)
  1419. get_cluster_ids <- function(x){rep(names(pb)[x],each = length(samples_list[[x]]))}
  1420. de_cluster_ids <- purrr::map(1:length(kids), get_cluster_ids) %>% unlist()
  1421. gg_df <- data.frame(cluster_id = de_cluster_ids, sample_id = de_samples)
  1422. gg_df <- left_join(gg_df, ei[, c("sample_id", "group_id")])
  1423. metadata <- gg_df %>% dplyr::select(cluster_id, sample_id, group_id)
  1424. levels(metadata$cluster_id) <- unique(metadata$cluster_id)
  1425. # Generate vector of cluster IDs
  1426. clusters <- levels(metadata$cluster_id)
  1427. clusters
  1428. cluster_choice <- "core"
  1429. table_sample_low <- table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$sample_id)[cluster_choice,][table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$sample_id)[cluster_choice,] <= 5]
  1430. table_sample_low
  1431. sample_keep <- names(orig.ident_colors)[!names(orig.ident_colors) %in% names(table_sample_low)]
  1432. table_group_low <-table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$group_id)[cluster_choice,][table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$group_id)[cluster_choice,] <= 30]
  1433. table_group_low
  1434. group_keep <- names(orig.ident_merge_colors)[!names(orig.ident_merge_colors) %in% names(table_group_low)]
  1435. cluster_metadata <- metadata[which(metadata$cluster_id == cluster_choice), ]
  1436. # Assign the rownames of the metadata to be the sample IDs
  1437. rownames(cluster_metadata) <- cluster_metadata$sample_id
  1438. #Remove sample and timepoint with low counts (sample<=5, timepoint<=30)
  1439. cluster_metadata <- cluster_metadata[(cluster_metadata$sample_id %in% sample_keep & cluster_metadata$group_id %in% group_keep),]
  1440. new_group_levels <- levels(cluster_metadata$group_id)[levels(cluster_metadata$group_id) %in% group_keep]
  1441. cluster_metadata$group_id <- droplevels(cluster_metadata$group_id)
  1442. levels(cluster_metadata$group_id) <- new_group_levels
  1443. # Subset the counts to only this cluster
  1444. counts <- pb[[cluster_choice]]
  1445. cluster_counts <- data.frame(counts[, which(colnames(counts) %in% rownames(cluster_metadata))])
  1446. # Check that all of the row names of the metadata are the same and in the same order as the column names of the counts in order to use as input to DESeq2
  1447. all(rownames(cluster_metadata) == colnames(cluster_counts))
  1448. ```
  1449. ```{r}
  1450. dds <- DESeqDataSetFromMatrix(cluster_counts, colData = cluster_metadata, design = ~ group_id)
  1451. ```
  1452. ```{r}
  1453. # Transform counts for data visualization
  1454. rld <- rlog(dds, blind=TRUE)
  1455. ```
  1456. ```{r}
  1457. # Plot PCA
  1458. options(repr.plot.width=8, repr.plot.height=5)
  1459. DESeq2::plotPCA(rld, intgroup = "group_id")
  1460. ```
  1461. ```{r}
  1462. # Extract the rlog matrix from the object and compute pairwise correlation values
  1463. rld_mat <- assay(rld)
  1464. rld_cor <- cor(rld_mat)
  1465. ```
  1466. ```{r}
  1467. # Plot heatmap
  1468. options(repr.plot.width=10, repr.plot.height=8)
  1469. pheatmap(rld_cor, annotation = cluster_metadata[, "group_id", drop=F], annotation_colors = list(group_id=orig.ident_merge_colors))
  1470. ```
  1471. ```{r}
  1472. dds <- DESeq(dds)
  1473. ```
  1474. ```{r}
  1475. libsize = data.frame(x=sizeFactors(dds), y=colSums(assay(dds)))
  1476. options(repr.plot.width=7, repr.plot.height=7)
  1477. ggplot(data=libsize, aes(x=x, y=y)) + geom_point() + geom_smooth(method="lm") + xlab("Estimated size factor") + ylab("Library size")
  1478. ```
  1479. ```{r}
  1480. data.frame(colData(dds))
  1481. ```
  1482. ```{r}
  1483. # Plot dispersion estimates
  1484. options(repr.plot.width=12, repr.plot.height=12)
  1485. plotDispEsts(dds)
  1486. ```
  1487. ```{r}
  1488. HVGs.list[[condition]][["upregulated"]] <- list()
  1489. HVGs.list[[condition]][["downregulated"]] <- list()
  1490. ```
  1491. ## 9.1 Contrasts
  1492. ```{r}
  1493. condition1 = "D7"
  1494. condition2 = "Ctrl"
  1495. contrast <- c("group_id", condition1, condition2)
  1496. # resultsNames(dds)
  1497. res <- results(dds, contrast = contrast, alpha = 0.05)
  1498. summary(res)
  1499. options(repr.plot.width=10, repr.plot.height=7)
  1500. hist(res$pvalue, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of p-values", xlab="p-value")
  1501. ```
  1502. ```{r}
  1503. options(repr.plot.width=10, repr.plot.height=7)
  1504. hist(res$padj, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of adj p-values", xlab="adj p-value")
  1505. ```
  1506. ```{r}
  1507. options(repr.plot.width=10, repr.plot.height=7)
  1508. qs <- c(0, quantile(res$baseMean[res$baseMean > 0], 0:7/7))
  1509. # cut the genes into the bins
  1510. bins <- cut(res$baseMean, qs)
  1511. # rename the levels of the bins using the middle point
  1512. levels(bins) <- paste0("~",round(.5*qs[-1] + .5*qs[-length(qs)]))
  1513. # calculate the ratio of $p$ values less than .01 for each bin
  1514. ratios <- tapply(res$pvalue, bins, function(p) mean(p < .01, na.rm=TRUE))
  1515. # plot these ratios
  1516. barplot(ratios, xlab="mean normalized count", ylab="ratio of small p values")
  1517. ```
  1518. ```{r}
  1519. options(repr.plot.width=15, repr.plot.height=15)
  1520. #padj<0.001
  1521. p1<-EnhancedVolcano(res,
  1522. lab = rownames(res),
  1523. x = 'log2FoldChange',
  1524. y = 'padj',
  1525. title = paste0(condition1,' vs ',condition2,' in FC > 1'),
  1526. pCutoff = 0.01,
  1527. FCcutoff = 1,
  1528. pointSize = 3.0,
  1529. labSize = 6.0,
  1530. col=c('black', 'grey', 'grey', 'blue'),
  1531. colAlpha = 1
  1532. )
  1533. print(p1)
  1534. p1_1<-EnhancedVolcano(res,
  1535. lab = rownames(res),
  1536. x = 'log2FoldChange',
  1537. y = 'padj',
  1538. title = paste0(condition1,' vs ',condition2,' in FC > 0.75'),
  1539. pCutoff = 0.01,
  1540. FCcutoff = 0.75,
  1541. pointSize = 3.0,
  1542. labSize = 6.0,
  1543. col=c('black', 'grey', 'grey', 'blue'),
  1544. colAlpha = 1
  1545. )
  1546. print(p1_1)
  1547. ```
  1548. ```{r}
  1549. res.list[[condition]][[paste0(condition1,"_",condition2)]] <- res
  1550. ```
  1551. ```{r}
  1552. write.csv(res, paste0("DGE_",condition,"_neuron_",condition1,"_",condition2,"_20250915.csv"), row.names=TRUE)
  1553. ```
  1554. ```{r}
  1555. res <- res[complete.cases(res$padj),]
  1556. res_filtered <- res[(res$padj < 0.05 & res$baseMean > 1),]
  1557. HVGs.list[[condition]][["upregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange>=0,])
  1558. HVGs.list[[condition]][["downregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange<0,])
  1559. ```
  1560. ## D14 vs Ctrl
  1561. ```{r}
  1562. condition1 = "D14"
  1563. condition2 = "Ctrl"
  1564. ```
  1565. ```{r}
  1566. contrast <- c("group_id", condition1, condition2)
  1567. # resultsNames(dds)
  1568. res <- results(dds, contrast = contrast, alpha = 0.05)
  1569. ```
  1570. ```{r}
  1571. summary(res)
  1572. ```
  1573. ```{r}
  1574. options(repr.plot.width=10, repr.plot.height=7)
  1575. hist(res$pvalue, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of p-values", xlab="p-value")
  1576. ```
  1577. ```{r}
  1578. options(repr.plot.width=10, repr.plot.height=7)
  1579. hist(res$padj, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of adj p-values", xlab="adj p-value")
  1580. ```
  1581. ```{r}
  1582. options(repr.plot.width=10, repr.plot.height=7)
  1583. qs <- c(0, quantile(res$baseMean[res$baseMean > 0], 0:7/7))
  1584. # cut the genes into the bins
  1585. bins <- cut(res$baseMean, qs)
  1586. # rename the levels of the bins using the middle point
  1587. levels(bins) <- paste0("~",round(.5*qs[-1] + .5*qs[-length(qs)]))
  1588. # calculate the ratio of $p$ values less than .01 for each bin
  1589. ratios <- tapply(res$pvalue, bins, function(p) mean(p < .01, na.rm=TRUE))
  1590. # plot these ratios
  1591. barplot(ratios, xlab="mean normalized count", ylab="ratio of small p values")
  1592. ```
  1593. ```{r}
  1594. options(repr.plot.width=15, repr.plot.height=15)
  1595. #padj<0.001
  1596. p2 <- EnhancedVolcano(res,
  1597. lab = rownames(res),
  1598. x = 'log2FoldChange',
  1599. y = 'padj',
  1600. title = paste0(condition1,' vs ',condition2,' in FC > 1'),
  1601. pCutoff = 0.01,
  1602. FCcutoff = 1,
  1603. pointSize = 3.0,
  1604. labSize = 6.0,
  1605. col=c('black', 'grey', 'grey', 'blue'),
  1606. colAlpha = 1)
  1607. print(p2)
  1608. p2_1 <- EnhancedVolcano(res,
  1609. lab = rownames(res),
  1610. x = 'log2FoldChange',
  1611. y = 'padj',
  1612. title = paste0(condition1,' vs ',condition2,' in FC > 0.75'),
  1613. pCutoff = 0.01,
  1614. FCcutoff = 0.75,
  1615. pointSize = 3.0,
  1616. labSize = 6.0,
  1617. col=c('black', 'grey', 'grey', 'blue'),
  1618. colAlpha = 1)
  1619. print(p2_1)
  1620. ```
  1621. ```{r}
  1622. res.list[[condition]][[paste0(condition1,"_",condition2)]] <- res
  1623. ```
  1624. ```{r}
  1625. write.csv(res, paste0("DGE_",condition,"_neuron_",condition1,"_",condition2,"_20250915.csv"), row.names=TRUE)
  1626. ```
  1627. ```{r}
  1628. res <- res[complete.cases(res$padj),]
  1629. res_filtered <- res[(res$padj < 0.05 & res$baseMean > 1),]
  1630. HVGs.list[[condition]][["upregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange>=0,])
  1631. HVGs.list[[condition]][["downregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange<0,])
  1632. ```
  1633. ## D14 vs D7
  1634. ```{r}
  1635. condition1 = "D14"
  1636. condition2 = "D7"
  1637. ```
  1638. ```{r}
  1639. contrast <- c("group_id", condition1, condition2)
  1640. # resultsNames(dds)
  1641. res <- results(dds, contrast = contrast, alpha = 0.05)
  1642. ```
  1643. ```{r}
  1644. summary(res)
  1645. ```
  1646. ```{r}
  1647. options(repr.plot.width=10, repr.plot.height=7)
  1648. hist(res$pvalue, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of p-values", xlab="p-value")
  1649. ```
  1650. ```{r}
  1651. options(repr.plot.width=10, repr.plot.height=7)
  1652. hist(res$padj, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of adj p-values", xlab="adj p-value")
  1653. ```
  1654. ```{r}
  1655. options(repr.plot.width=10, repr.plot.height=7)
  1656. qs <- c(0, quantile(res$baseMean[res$baseMean > 0], 0:7/7))
  1657. # cut the genes into the bins
  1658. bins <- cut(res$baseMean, qs)
  1659. # rename the levels of the bins using the middle point
  1660. levels(bins) <- paste0("~",round(.5*qs[-1] + .5*qs[-length(qs)]))
  1661. # calculate the ratio of $p$ values less than .01 for each bin
  1662. ratios <- tapply(res$pvalue, bins, function(p) mean(p < .01, na.rm=TRUE))
  1663. # plot these ratios
  1664. barplot(ratios, xlab="mean normalized count", ylab="ratio of small p values")
  1665. ```
  1666. ```{r}
  1667. options(repr.plot.width=15, repr.plot.height=15)
  1668. #padj<0.001
  1669. p3 <- EnhancedVolcano(res,
  1670. lab = rownames(res),
  1671. x = 'log2FoldChange',
  1672. y = 'padj',
  1673. title = paste0(condition1,' vs ',condition2,' in FC > 1'),
  1674. pCutoff = 0.01,
  1675. FCcutoff = 1,
  1676. pointSize = 3.0,
  1677. labSize = 6.0,
  1678. col=c('black', 'grey', 'grey', 'blue'),
  1679. colAlpha = 1)
  1680. print(p3)
  1681. p3_1 <- EnhancedVolcano(res,
  1682. lab = rownames(res),
  1683. x = 'log2FoldChange',
  1684. y = 'padj',
  1685. title = paste0(condition1,' vs ',condition2,' in FC > 0.75'),
  1686. pCutoff = 0.01,
  1687. FCcutoff = 0.75,
  1688. pointSize = 3.0,
  1689. labSize = 6.0,
  1690. col=c('black', 'grey', 'grey', 'blue'),
  1691. colAlpha = 1,
  1692. )
  1693. print(p3_1)
  1694. p3_2 <- EnhancedVolcano(res,
  1695. lab = rownames(res),
  1696. x = 'log2FoldChange',
  1697. y = 'padj',
  1698. title = paste0(condition1,' vs ',condition2,' in FC > 0.5'),
  1699. pCutoff = 0.05,
  1700. FCcutoff = 0.5,
  1701. pointSize = 3.0,
  1702. labSize = 6.0,
  1703. col=c('black', 'grey', 'grey', 'blue'),
  1704. colAlpha = 1,
  1705. )
  1706. print(p3_2)
  1707. ```
  1708. ```{r}
  1709. res.list[[condition]][[paste0(condition1,"_",condition2)]] <- res
  1710. ```
  1711. ```{r}
  1712. write.csv(res, paste0("DGE_",condition,"_neuron_",condition1,"_",condition2,"_20250915.csv"), row.names=TRUE)
  1713. ```
  1714. ```{r}
  1715. res <- res[complete.cases(res$padj),]
  1716. res_filtered <- res[(res$padj < 0.05 & res$baseMean > 1),]
  1717. HVGs.list[[condition]][["upregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange>=0,])
  1718. HVGs.list[[condition]][["downregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange<0,])
  1719. ```
  1720. ```{r}
  1721. # export the svg file
  1722. svglite::svglite(file = "volcano_plot_neuron_D7vsCtrl_FC_1.svg", width = 15, height = 15)
  1723. print(p1)
  1724. dev.off()
  1725. svglite::svglite(file = "volcano_plot_neuron_D7vsCtrl_FC_075.svg", width = 15, height = 15)
  1726. print(p1_1)
  1727. dev.off()
  1728. svglite::svglite(file = "volcano_plot_neuron_D14vsCtrl_FC_1.svg", width = 15, height = 15)
  1729. print(p2)
  1730. dev.off()
  1731. svglite::svglite(file = "volcano_plot_neuron_D14vsCtrl_FC_075.svg", width = 15, height = 15)
  1732. print(p2_1)
  1733. dev.off()
  1734. svglite::svglite(file = "volcano_plot_neuron_D14vsD7_FC_1.svg", width = 15, height = 15)
  1735. print(p3)
  1736. dev.off()
  1737. svglite::svglite(file = "volcano_plot_neuron_D14vsD7_FC_075.svg", width = 15, height = 15)
  1738. print(p3_1)
  1739. dev.off()
  1740. ```
  1741. ## GO on the res
  1742. ```{r}
  1743. # load the different DEG list
  1744. res_D7_Ctrl <- read.csv(paste0("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/", "DGE_IO_neuron_","D7","_","Ctrl","_20250915.csv"), row.names = 1)
  1745. res_D14_Ctrl <- read.csv(paste0("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/", "DGE_IO_neuron_","D14","_","Ctrl","_20250915.csv"), row.names = 1)
  1746. res_D14_D7 <- read.csv(paste0("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/", "DGE_IO_neuron_","D14","_","D7","_20250915.csv"), row.names = 1)
  1747. # clean up the na
  1748. res_D7_Ctrl <- res_D7_Ctrl[!is.na(res_D7_Ctrl$padj),]
  1749. res_D14_Ctrl <- res_D14_Ctrl[!is.na(res_D14_Ctrl$padj),]
  1750. res_D14_D7 <- res_D14_D7[!is.na(res_D14_D7$padj),]
  1751. # Filter the res for giving different lists
  1752. res_D7_Ctrl_FC1_up <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange > 1),])
  1753. res_D7_Ctrl_FC1_down <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange < -1),])
  1754. res_D7_Ctrl_FC075_up <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange > 0.75),])
  1755. res_D7_Ctrl_FC075_down <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange < -0.75),])
  1756. res_D7_Ctrl_FC05_up <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange > 0.5),])
  1757. res_D7_Ctrl_FC05_down <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange < -0.5),])
  1758. res_D14_Ctrl_FC1_up <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange > 1),])
  1759. res_D14_Ctrl_FC1_down <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange < -1),])
  1760. res_D14_Ctrl_FC075_up <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange > 0.75),])
  1761. res_D14_Ctrl_FC075_down <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange < -0.75),])
  1762. res_D14_Ctrl_FC05_up <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange > 0.5),])
  1763. res_D14_Ctrl_FC05_down <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange < -0.5),])
  1764. res_D14_D7_FC1_up <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange > 1),])
  1765. res_D14_D7_FC1_down <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange < -1),])
  1766. res_D14_D7_FC075_up <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange > 0.75),])
  1767. res_D14_D7_FC075_down <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange < -0.75),])
  1768. res_D14_D7_FC05_up <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange > 0.5),])
  1769. res_D14_D7_FC05_down <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange < -0.5),])
  1770. ```
  1771. ```{r}
  1772. # Load the libraries
  1773. library(dplyr)
  1774. library(writexl)
  1775. library(tibble)
  1776. # Filter and rank the D7 vs Ctrl results, then add a column for the index
  1777. res_D7_Ctrl_ranked <- res_D7_Ctrl %>%
  1778. filter(abs(log2FoldChange) > 0.5) %>%
  1779. arrange(padj) %>%
  1780. rownames_to_column("GeneName")
  1781. # Filter and rank the D14 vs Ctrl results
  1782. res_D14_Ctrl_ranked <- res_D14_Ctrl %>%
  1783. filter(abs(log2FoldChange) > 0.5) %>%
  1784. arrange(padj) %>%
  1785. rownames_to_column("GeneName")
  1786. # Filter and rank the D14 vs D7 results
  1787. res_D14_D7_ranked <- res_D14_D7 %>%
  1788. filter(abs(log2FoldChange) > 0.5) %>%
  1789. arrange(padj) %>%
  1790. rownames_to_column("GeneName")
  1791. # Create a named list of the filtered data frames
  1792. filtered_results_list <- list(
  1793. D7_vs_Ctrl = res_D7_Ctrl_ranked,
  1794. D14_vs_Ctrl = res_D14_Ctrl_ranked,
  1795. D14_vs_D7 = res_D14_D7_ranked
  1796. )
  1797. # Export the list to a single Excel file with three sheets
  1798. write_xlsx(filtered_results_list, "DGE_IO_neuron_ConditionComparison.xlsx")
  1799. ```
  1800. ```{r}
  1801. dbs <- c("GO_Molecular_Function_2023","GO_Cellular_Component_2023","GO_Biological_Process_2023","KEGG_2019_Mouse") # ,"HDSigDB_Mouse_2021","Tabula_Muris","WikiPathways_2024_Mouse")
  1802. ```
  1803. ```{r}
  1804. enrichedR.list <- list()
  1805. enrichedR.list[["IO_D7_Ctrl_FC1_up"]] <- enrichr(res_D7_Ctrl_FC1_up, dbs)
  1806. enrichedR.list[["IO_D7_Ctrl_FC1_down"]] <- enrichr(res_D7_Ctrl_FC1_down, dbs)
  1807. enrichedR.list[["IO_D7_Ctrl_FC075_up"]] <- enrichr(res_D7_Ctrl_FC075_up, dbs)
  1808. enrichedR.list[["IO_D7_Ctrl_FC075_down"]] <- enrichr(res_D7_Ctrl_FC075_down, dbs)
  1809. enrichedR.list[["IO_D7_Ctrl_FC05_up"]] <- enrichr(res_D7_Ctrl_FC05_up, dbs)
  1810. enrichedR.list[["IO_D7_Ctrl_FC05_down"]] <- enrichr(res_D7_Ctrl_FC05_down, dbs)
  1811. enrichedR.list[["IO_D14_Ctrl_FC1_up"]] <- enrichr(res_D14_Ctrl_FC1_up, dbs)
  1812. enrichedR.list[["IO_D14_Ctrl_FC1_down"]] <- enrichr(res_D14_Ctrl_FC1_down, dbs)
  1813. enrichedR.list[["IO_D14_Ctrl_FC075_up"]] <- enrichr(res_D14_Ctrl_FC075_up, dbs)
  1814. enrichedR.list[["IO_D14_Ctrl_FC075_down"]] <- enrichr(res_D14_Ctrl_FC075_down, dbs)
  1815. enrichedR.list[["IO_D14_Ctrl_FC05_up"]] <- enrichr(res_D14_Ctrl_FC05_up, dbs)
  1816. enrichedR.list[["IO_D14_Ctrl_FC05_down"]] <- enrichr(res_D14_Ctrl_FC05_down, dbs)
  1817. enrichedR.list[["IO_D14_D7_FC1_up"]] <- enrichr(res_D14_D7_FC1_up, dbs)
  1818. enrichedR.list[["IO_D14_D7_FC1_down"]] <- enrichr(res_D14_D7_FC1_down, dbs)
  1819. enrichedR.list[["IO_D14_D7_FC075_up"]] <- enrichr(res_D14_D7_FC075_up, dbs)
  1820. enrichedR.list[["IO_D14_D7_FC075_down"]] <- enrichr(res_D14_D7_FC075_down, dbs)
  1821. enrichedR.list[["IO_D14_D7_FC05_up"]] <- enrichr(res_D14_D7_FC05_up, dbs)
  1822. enrichedR.list[["IO_D14_D7_FC05_down"]] <- enrichr(res_D14_D7_FC05_down, dbs)
  1823. ```
  1824. ```{r}
  1825. # Create an empty list to store the data frames for export
  1826. export_list <- list()
  1827. # Loop through your enrichedR.list and extract a specific database for each cluster
  1828. for (cluster_name in names(enrichedR.list)) {
  1829. # For example, extract the "GO_Biological_Process_2023" results
  1830. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$GO_Biological_Process_2023
  1831. }
  1832. # Export the prepared list to a single Excel file
  1833. write.xlsx(export_list, file = "enrichment_IO_calb1_neuron_DayComparison_GO_KEGG.xlsx")
  1834. ```
  1835. ```{r}
  1836. pdf("enrichment_plot_IO_Neuron_DayComp.pdf", width=12, height=8)
  1837. for (dge in names(enrichedR.list)) {
  1838. for (go_db in dbs) {
  1839. enr_df <- enrichedR.list[[dge]][[go_db]]
  1840. if (is.null(enr_df) || nrow(enr_df) == 0) {
  1841. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  1842. next
  1843. }
  1844. p <- plotEnrich(
  1845. enr_df,
  1846. showTerms = 50,
  1847. numChar = 100,
  1848. y = "Count",
  1849. orderBy = "FDR",
  1850. title = paste0(dge," in ", go_db),
  1851. xlab = ""
  1852. )
  1853. print(
  1854. p + theme(
  1855. axis.text.x = element_text(size = 6),
  1856. axis.text.y = element_text(size = 8),
  1857. axis.title = element_text(size = 6),
  1858. plot.title = element_text(size = 10),
  1859. plot.margin = margin(10, 10, 10, 10)
  1860. )
  1861. )
  1862. }
  1863. }
  1864. dev.off()
  1865. ```
  1866. ```{r}
  1867. pdf("enrichment_plot_IO_Neuron_DayComp_filtered.pdf", width=8, height=4)
  1868. # Define your list of keywords
  1869. keywords <- c("Glycolytic Process", "Pyruvate Metabolic Process", "Carbohydrate Catabolic Process", "Synaptic Vesicle Recycling", "metabo")
  1870. for (dge in names(enrichedR.list)) {
  1871. for (go_db in dbs) {
  1872. enr_df <- enrichedR.list[[dge]][[go_db]]
  1873. if (is.null(enr_df) || nrow(enr_df) == 0) {
  1874. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  1875. next
  1876. }
  1877. # Filter for keywords and FDR < 0.1
  1878. filtered_df <- enr_df[
  1879. grepl(paste(keywords, collapse = "|"), enr_df$Term, ignore.case = TRUE) & enr_df$Adjusted.P.value < 0.1,
  1880. ]
  1881. # Check if there are any results after filtering
  1882. if (nrow(filtered_df) == 0) {
  1883. message("Skipping ", dge, " in ", go_db, " (no terms found after filtering)")
  1884. next
  1885. }
  1886. # Use the filtered data for plotting
  1887. p <- plotEnrich(
  1888. filtered_df,
  1889. showTerms = 50,
  1890. numChar = 100,
  1891. y = "Count",
  1892. orderBy = "FDR",
  1893. title = paste0(dge, " in ", go_db, " (Filtered)"),
  1894. xlab = ""
  1895. )
  1896. print(
  1897. p + theme(
  1898. axis.text.x = element_text(size = 6),
  1899. axis.text.y = element_text(size = 8),
  1900. axis.title = element_text(size = 6),
  1901. plot.title = element_text(size = 10),
  1902. plot.margin = margin(10, 10, 10, 10)
  1903. )
  1904. )
  1905. }
  1906. }
  1907. dev.off()
  1908. ```
  1909. ----------------------------------------
  1910. ## Combining day 7 and day 14 to compare against control (IO neuron)
  1911. ```{r}
  1912. condition <- "IO"
  1913. HVGs.list <- list()
  1914. res.list <- list()
  1915. HVGs.list[[condition]] <- list()
  1916. res.list[[condition]] <- list()
  1917. ```
  1918. ```{r}
  1919. DefaultAssay(seurat_obj_IO_calb1) <- 'RNA'
  1920. table(seurat_obj_IO_calb1$orig.ident_merge)
  1921. ```
  1922. ```{r}
  1923. # Create a copy of the Seurat object to work with
  1924. seurat_obj_IO_calb1_copy <- seurat_obj_IO_calb1
  1925. # Access the orig.ident_merge metadata column and convert it to a character vector.
  1926. # This allows for the assignment of new values that are not already present in the factor levels.
  1927. seurat_obj_IO_calb1_copy$lesion_status <- as.character(seurat_obj_IO_calb1_copy$orig.ident_merge)
  1928. # Now, update the D7 and D14 values to "lesion"
  1929. seurat_obj_IO_calb1_copy$lesion_status[seurat_obj_IO_calb1_copy$lesion_status %in% c("D7", "D14")] <- "lesion"
  1930. # Finally, convert the new column back to a factor and set the levels.
  1931. # This step is crucial for downstream analysis to define your groups.
  1932. seurat_obj_IO_calb1_copy$lesion_status <- factor(seurat_obj_IO_calb1_copy$lesion_status, levels = c("Ctrl", "lesion"))
  1933. # Verify the changes
  1934. table(seurat_obj_IO_calb1_copy$lesion_status)
  1935. seurat_obj_sce_calb1 <- as.SingleCellExperiment(seurat_obj_IO_calb1_copy, assay="RNA")
  1936. seurat_obj_sce_calb1 <- prepSCE(seurat_obj_sce_calb1, kid = "InfOlive", gid = "lesion_status", sid = "orig.ident", drop = FALSE)
  1937. kids <- purrr::set_names(levels(seurat_obj_sce_calb1$cluster_id))
  1938. # Total number of clusters
  1939. nk <- length(kids)
  1940. # Named vector of sample names
  1941. sids <- purrr::set_names(levels(seurat_obj_sce_calb1$sample_id))
  1942. # Total number of samples
  1943. ns <- length(sids)
  1944. kids
  1945. sids
  1946. ```
  1947. ```{r}
  1948. ## Determine the number of cells per sample
  1949. table(seurat_obj_sce_calb1$sample_id)
  1950. ## Turn named vector into a numeric vector of number of cells per sample
  1951. n_cells <- as.numeric(table(seurat_obj_sce_calb1$sample_id))
  1952. ## Determine how to reoder the samples (rows) of the metadata to match the order of sample names in sids vector
  1953. m <- match(sids, seurat_obj_sce_calb1$sample_id)
  1954. ## Create the sample level metadata by combining the reordered metadata with the number of cells corresponding to each sample.
  1955. ei <- data.frame(colData(seurat_obj_sce_calb1)[m, ], n_cells, row.names = NULL) %>% dplyr::select(-"cluster_id")
  1956. ei
  1957. ```
  1958. ```{r}
  1959. # Aggregate the counts per sample_id and cluster_id
  1960. # Subset metadata to only include the cluster and sample IDs to aggregate across
  1961. groups <- colData(seurat_obj_sce_calb1)[, c("cluster_id", "sample_id")]
  1962. # Aggregate across cluster-sample groups
  1963. pb <- aggregate.Matrix(t(counts(seurat_obj_sce_calb1)), groupings = groups, fun = "sum")
  1964. splitf <- sapply(stringr::str_split(rownames(pb), pattern = "_", n = 2), `[`, 1)
  1965. pb <- split.data.frame(pb, factor(splitf)) %>% lapply(function(u) magrittr::set_colnames(t(u), stringr::str_extract(rownames(u), "(?<=_)[:alnum:]+")))
  1966. class(pb)
  1967. # Explore the different components of list
  1968. str(pb)
  1969. ```
  1970. ```{r}
  1971. options(width = 100)
  1972. table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$group_id)
  1973. ```
  1974. ```{r}
  1975. options(width = 100)
  1976. table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$seurat_clusters)
  1977. ```
  1978. ```{r}
  1979. # prep. data.frame for plotting
  1980. get_sample_ids <- function(x){pb[[x]] %>% colnames()}
  1981. de_samples <- purrr::map(1:length(kids), get_sample_ids) %>% unlist()
  1982. samples_list <- purrr::map(1:length(kids), get_sample_ids)
  1983. get_cluster_ids <- function(x){rep(names(pb)[x],each = length(samples_list[[x]]))}
  1984. de_cluster_ids <- purrr::map(1:length(kids), get_cluster_ids) %>% unlist()
  1985. gg_df <- data.frame(cluster_id = de_cluster_ids, sample_id = de_samples)
  1986. gg_df <- left_join(gg_df, ei[, c("sample_id", "group_id")])
  1987. metadata <- gg_df %>% dplyr::select(cluster_id, sample_id, group_id)
  1988. levels(metadata$cluster_id) <- unique(metadata$cluster_id)
  1989. # Generate vector of cluster IDs
  1990. clusters <- levels(metadata$cluster_id)
  1991. clusters
  1992. cluster_choice <- "core"
  1993. table_sample_low <- table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$sample_id)[cluster_choice,][table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$sample_id)[cluster_choice,] <= 5]
  1994. table_sample_low
  1995. sample_keep <- names(orig.ident_colors)[!names(orig.ident_colors) %in% names(table_sample_low)]
  1996. table_group_low <-table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$group_id)[cluster_choice,][table(seurat_obj_sce_calb1$cluster_id, seurat_obj_sce_calb1$group_id)[cluster_choice,] <= 30]
  1997. table_group_low
  1998. group_keep <- names(orig.ident_merge_colors)[!names(orig.ident_merge_colors) %in% names(table_group_low)]
  1999. group_keep <- c("Ctrl", "lesion")
  2000. cluster_metadata <- metadata[which(metadata$cluster_id == cluster_choice), ]
  2001. # Assign the rownames of the metadata to be the sample IDs
  2002. rownames(cluster_metadata) <- cluster_metadata$sample_id
  2003. #Remove sample and timepoint with low counts (sample<=5, timepoint<=30)
  2004. cluster_metadata <- cluster_metadata[(cluster_metadata$sample_id %in% sample_keep & cluster_metadata$group_id %in% group_keep),]
  2005. new_group_levels <- levels(cluster_metadata$group_id)[levels(cluster_metadata$group_id) %in% group_keep]
  2006. cluster_metadata$group_id <- droplevels(cluster_metadata$group_id)
  2007. levels(cluster_metadata$group_id) <- new_group_levels
  2008. # Subset the counts to only this cluster
  2009. counts <- pb[[cluster_choice]]
  2010. cluster_counts <- data.frame(counts[, which(colnames(counts) %in% rownames(cluster_metadata))])
  2011. # Check that all of the row names of the metadata are the same and in the same order as the column names of the counts in order to use as input to DESeq2
  2012. all(rownames(cluster_metadata) == colnames(cluster_counts))
  2013. ```
  2014. ```{r}
  2015. dds <- DESeqDataSetFromMatrix(cluster_counts, colData = cluster_metadata, design = ~ group_id)
  2016. ```
  2017. ```{r}
  2018. # Transform counts for data visualization
  2019. rld <- rlog(dds, blind=TRUE)
  2020. ```
  2021. ```{r}
  2022. # Plot PCA
  2023. options(repr.plot.width=8, repr.plot.height=5)
  2024. DESeq2::plotPCA(rld, intgroup = "group_id")
  2025. ```
  2026. ```{r}
  2027. # Extract the rlog matrix from the object and compute pairwise correlation values
  2028. rld_mat <- assay(rld)
  2029. rld_cor <- cor(rld_mat)
  2030. ```
  2031. ```{r}
  2032. # Plot heatmap
  2033. options(repr.plot.width=10, repr.plot.height=8)
  2034. # pheatmap(rld_cor, annotation = cluster_metadata[, "group_id", drop=F], annotation_colors = list(group_id=orig.ident_merge_colors))
  2035. ```
  2036. ```{r}
  2037. dds <- DESeq(dds)
  2038. ```
  2039. ```{r}
  2040. libsize = data.frame(x=sizeFactors(dds), y=colSums(assay(dds)))
  2041. options(repr.plot.width=7, repr.plot.height=7)
  2042. ggplot(data=libsize, aes(x=x, y=y)) + geom_point() + geom_smooth(method="lm") + xlab("Estimated size factor") + ylab("Library size")
  2043. ```
  2044. ```{r}
  2045. data.frame(colData(dds))
  2046. ```
  2047. ```{r}
  2048. # Plot dispersion estimates
  2049. options(repr.plot.width=12, repr.plot.height=12)
  2050. plotDispEsts(dds)
  2051. ```
  2052. ```{r}
  2053. HVGs.list[[condition]][["upregulated"]] <- list()
  2054. HVGs.list[[condition]][["downregulated"]] <- list()
  2055. ```
  2056. ```{r}
  2057. condition1 = "lesion"
  2058. condition2 = "Ctrl"
  2059. contrast <- c("group_id", condition1, condition2)
  2060. # resultsNames(dds)
  2061. res <- results(dds, contrast = contrast, alpha = 0.05)
  2062. summary(res)
  2063. options(repr.plot.width=10, repr.plot.height=7)
  2064. hist(res$pvalue, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of p-values", xlab="p-value")
  2065. ```
  2066. ```{r}
  2067. options(repr.plot.width=10, repr.plot.height=7)
  2068. hist(res$padj, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of adj p-values", xlab="adj p-value")
  2069. ```
  2070. ```{r}
  2071. options(repr.plot.width=10, repr.plot.height=7)
  2072. qs <- c(0, quantile(res$baseMean[res$baseMean > 0], 0:7/7))
  2073. # cut the genes into the bins
  2074. bins <- cut(res$baseMean, qs)
  2075. # rename the levels of the bins using the middle point
  2076. levels(bins) <- paste0("~",round(.5*qs[-1] + .5*qs[-length(qs)]))
  2077. # calculate the ratio of $p$ values less than .01 for each bin
  2078. ratios <- tapply(res$pvalue, bins, function(p) mean(p < .01, na.rm=TRUE))
  2079. # plot these ratios
  2080. barplot(ratios, xlab="mean normalized count", ylab="ratio of small p values")
  2081. ```
  2082. ```{r}
  2083. options(repr.plot.width=15, repr.plot.height=15)
  2084. #padj<0.001
  2085. genes_to_highlight = c("Gapdh", "Cyc1", "ND6", "Spp1")
  2086. p1_2<-EnhancedVolcano(res,
  2087. lab = rownames(res),
  2088. x = 'log2FoldChange',
  2089. y = 'padj',
  2090. title = paste0(condition1,' vs ',condition2,' in FC > 0.5'),
  2091. pCutoff = 0.05,
  2092. FCcutoff = 0.5,
  2093. pointSize = 3.0,
  2094. labSize = 6.0,
  2095. col=c('black', 'grey', 'grey', 'blue'),
  2096. colAlpha = 1,
  2097. selectLab = genes_to_highlight,
  2098. drawConnectors = TRUE
  2099. )
  2100. print(p1_2)
  2101. ```
  2102. ```{r}
  2103. res.list[[condition]][[paste0(condition1,"_",condition2)]] <- res
  2104. ```
  2105. ```{r}
  2106. write.csv(res, paste0("DGE_",condition,"_neuron_",condition1,"_",condition2,"_20250915.csv"), row.names=TRUE)
  2107. ```
  2108. ```{r}
  2109. res <- res[complete.cases(res$padj),]
  2110. res_filtered <- res[(res$padj < 0.05 & res$baseMean > 1),]
  2111. HVGs.list[[condition]][["upregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange>=0,])
  2112. HVGs.list[[condition]][["downregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange<0,])
  2113. ```
  2114. ```{r}
  2115. # export the svg file
  2116. svglite::svglite(file = "volcano_plot_neuron_LesionvsCtrl_FC_05.svg", width = 8, height = 8)
  2117. print(p1_2)
  2118. dev.off()
  2119. ```
  2120. ### GO on the res
  2121. ```{r}
  2122. # load the different DEG list
  2123. res_lesion_Ctrl <- read.csv(paste0("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/", "DGE_IO_neuron_lesion_Ctrl_20250915.csv"), row.names = 1)
  2124. # clean up the na
  2125. res_lesion_Ctrl <- res_lesion_Ctrl[!is.na(res_lesion_Ctrl$padj),]
  2126. # Filter the res for giving different lists
  2127. res_lesion_Ctrl_FC05_up <- rownames(res_lesion_Ctrl[(res_lesion_Ctrl$padj < 0.05) & (res_lesion_Ctrl$log2FoldChange > 0.5),])
  2128. res_lesion_Ctrl_FC05_down <- rownames(res_lesion_Ctrl[(res_lesion_Ctrl$padj < 0.05) & (res_lesion_Ctrl$log2FoldChange < -0.5),])
  2129. ```
  2130. ```{r}
  2131. # 1. Filter the data based on your criteria
  2132. filtered_data <- res_lesion_Ctrl[(res_lesion_Ctrl$padj < 0.05) & (res_lesion_Ctrl$log2FoldChange > 0.5),]
  2133. # 2. Rank the filtered data by 'padj' in ascending order
  2134. ranked_data <- filtered_data[order(filtered_data$padj),]
  2135. write.csv(ranked_data, "DGE_IO_neuron_lesion_ctrl_FC05_ranked.csv")
  2136. # 1. Filter the data based on your criteria
  2137. filtered_data <- res_lesion_Ctrl[(res_lesion_Ctrl$padj < 0.05) & (res_lesion_Ctrl$log2FoldChange < -0.5),]
  2138. # 2. Rank the filtered data by 'padj' in ascending order
  2139. ranked_data <- filtered_data[order(filtered_data$padj),]
  2140. write.csv(ranked_data, "DGE_IO_neuron_lesion_ctrl_FC05_ranked_down.csv")
  2141. ```
  2142. ```{r}
  2143. dbs <- c("GO_Molecular_Function_2023","GO_Cellular_Component_2023","GO_Biological_Process_2023","KEGG_2019_Mouse")
  2144. ```
  2145. ```{r}
  2146. enrichedR.list <- list()
  2147. enrichedR.list[["IO_Lesion_Ctrl_FC05_up"]] <- enrichr(res_lesion_Ctrl_FC05_up, dbs)
  2148. enrichedR.list[["IO_Lesion_Ctrl_FC05_down"]] <- enrichr(res_lesion_Ctrl_FC05_down, dbs)
  2149. ```
  2150. ```{r}
  2151. # Create an empty list to store the data frames for export
  2152. export_list <- list()
  2153. # Loop through your enrichedR.list and extract a specific database for each cluster
  2154. for (cluster_name in names(enrichedR.list)) {
  2155. # For example, extract the "KEGG" results
  2156. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$KEGG_2019_Mouse
  2157. }
  2158. # Export the prepared list to a single Excel file
  2159. openxlsx::write.xlsx(export_list, file = "enrichment_IO_calb1_neuron_LesionVsCtrl_KEGG_20250924.xlsx")
  2160. ```
  2161. ```{r}
  2162. pdf("enrichment_plot_IO_Neuron_MergedLesionComp.pdf", width=12, height=8)
  2163. for (dge in names(enrichedR.list)) {
  2164. for (go_db in dbs) {
  2165. enr_df <- enrichedR.list[[dge]][[go_db]]
  2166. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2167. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2168. next
  2169. }
  2170. p <- plotEnrich(
  2171. enr_df,
  2172. showTerms = 50,
  2173. numChar = 100,
  2174. y = "Count",
  2175. orderBy = "FDR",
  2176. title = paste0(dge," in ", go_db),
  2177. xlab = ""
  2178. )
  2179. print(
  2180. p + theme(
  2181. axis.text.x = element_text(size = 6),
  2182. axis.text.y = element_text(size = 8),
  2183. axis.title = element_text(size = 6),
  2184. plot.title = element_text(size = 10),
  2185. plot.margin = margin(10, 10, 10, 10)
  2186. )
  2187. )
  2188. }
  2189. }
  2190. dev.off()
  2191. ```
  2192. ```{r}
  2193. pdf("enrichment_plot_IO_Neuron_MergedLesionComp_filtered.pdf", width=8, height=4)
  2194. # Define your list of keywords
  2195. keywords <- c("Oxidative phosphorylation", "Parkinson disease", "Retrograde endocannabinoid signaling", "Alzheimer disease")
  2196. for (dge in names(enrichedR.list)) {
  2197. for (go_db in dbs) {
  2198. enr_df <- enrichedR.list[[dge]][[go_db]]
  2199. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2200. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2201. next
  2202. }
  2203. # Filter for keywords and FDR < 0.1
  2204. filtered_df <- enr_df[
  2205. grepl(paste(keywords, collapse = "|"), enr_df$Term, ignore.case = TRUE) & enr_df$Adjusted.P.value < 0.1,
  2206. ]
  2207. # Check if there are any results after filtering
  2208. if (nrow(filtered_df) == 0) {
  2209. message("Skipping ", dge, " in ", go_db, " (no terms found after filtering)")
  2210. next
  2211. }
  2212. # Use the filtered data for plotting
  2213. p <- plotEnrich(
  2214. filtered_df,
  2215. showTerms = 50,
  2216. numChar = 100,
  2217. y = "Count",
  2218. orderBy = "FDR",
  2219. title = paste0(dge, " in ", go_db, " (Filtered)"),
  2220. xlab = ""
  2221. )
  2222. print(
  2223. p + theme(
  2224. axis.text.x = element_text(size = 6),
  2225. axis.text.y = element_text(size = 8),
  2226. axis.title = element_text(size = 6),
  2227. plot.title = element_text(size = 10),
  2228. plot.margin = margin(10, 10, 10, 10)
  2229. )
  2230. )
  2231. }
  2232. }
  2233. dev.off()
  2234. ```
  2235. ## Comparison on Clusters
  2236. ```{r}
  2237. library(Matrix)
  2238. library(dplyr)
  2239. # Grab metadata
  2240. meta <- colData(seurat_obj_sce_calb1)[, c("sample_id", "seurat_clusters")]
  2241. # counts = genes × cells
  2242. cts <- counts(seurat_obj_sce_calb1)
  2243. # build group labels: sample_cluster
  2244. groups <- paste(meta$sample_id, meta$seurat_clusters, sep = "_")
  2245. # aggregate counts across all cells belonging to each (sample, cluster) pair
  2246. pb <- aggregate.Matrix(t(cts), groupings = groups, fun = "sum")
  2247. pb <- t(pb) # back to genes × pseudobulks
  2248. dim(pb)
  2249. head(colnames(pb))
  2250. ```
  2251. ```{r}
  2252. # split sample_id and cluster from colnames
  2253. colinfo <- do.call(rbind, strsplit(colnames(pb), "_"))
  2254. coldata <- data.frame(
  2255. sample_id = colinfo[,1],
  2256. cluster = colinfo[,2],
  2257. row.names = colnames(pb)
  2258. )
  2259. head(coldata)
  2260. ```
  2261. ```{r}
  2262. dds <- DESeqDataSetFromMatrix(
  2263. countData = as.matrix(pb),
  2264. colData = coldata,
  2265. design = ~ sample_id + cluster
  2266. )
  2267. # filter low counts
  2268. dds <- dds[rowSums(counts(dds)) > 10, ]
  2269. # run DESeq2
  2270. dds <- DESeq(dds)
  2271. ```
  2272. ```{r}
  2273. # results: cluster0 (day7) vs cluster1 (ctrl)
  2274. res <- results(dds, contrast = c("cluster", "0", "1"))
  2275. res <- res[order(res$padj), ]
  2276. head(res)
  2277. ```
  2278. ```{r}
  2279. deg <- as.data.frame(res)
  2280. write.csv(deg, "DEG_neuron_cluster0_day7_vs_cluster1_day0_pseudobulk.csv")
  2281. ```
  2282. ```{r}
  2283. # Volcano plot
  2284. library(EnhancedVolcano)
  2285. p1 <- EnhancedVolcano(
  2286. deg,
  2287. lab = rownames(deg),
  2288. x = 'log2FoldChange',
  2289. y = 'pvalue',
  2290. title = "Cluster 0 (Day7) vs Cluster 1 (Day0)",
  2291. pCutoff = 0.01,
  2292. FCcutoff = 1,
  2293. pointSize = 3.0,
  2294. labSize = 6.0,
  2295. col=c('black', 'grey', 'grey', 'blue'),
  2296. colAlpha = 1
  2297. )
  2298. print(p1)
  2299. ```
  2300. ```{r}
  2301. # load & filter
  2302. res_0_vs_1 <- read.csv("DEG_neuron_cluster0_day7_vs_cluster1_day0_pseudobulk.csv", row.names = 1)
  2303. res_0_vs_1 <- res_0_vs_1[!is.na(res_0_vs_1$padj),]
  2304. # FC > 0.5 (up and down)
  2305. res_0_vs_1_FC05_up <- rownames(res_0_vs_1[(res_0_vs_1$padj < 0.05) & (res_0_vs_1$log2FoldChange > 0.5),])
  2306. res_0_vs_1_FC05_down <- rownames(res_0_vs_1[(res_0_vs_1$padj < 0.05) & (res_0_vs_1$log2FoldChange < -0.5),])
  2307. ```
  2308. ```{r}
  2309. # Assuming res_lesion_Ctrl is your data frame
  2310. # 1. Filter the data based on your criteria
  2311. filtered_data <- res_0_vs_1[(res_0_vs_1$padj < 0.05) & (res_0_vs_1$log2FoldChange > 0.5),]
  2312. # 2. Rank the filtered data by 'padj' in ascending order
  2313. ranked_data <- filtered_data[order(filtered_data$padj),]
  2314. # 3. Export the ranked data to a CSV file
  2315. write.csv(ranked_data, "DGE_IO_neuron_Clus0vsClus1_FC05_ranked_up.csv")
  2316. # 1. Filter the data based on your criteria
  2317. filtered_data <- res_0_vs_1[(res_0_vs_1$padj < 0.05) & (res_0_vs_1$log2FoldChange < -0.5),]
  2318. # 2. Rank the filtered data by 'padj' in ascending order
  2319. ranked_data <- filtered_data[order(filtered_data$padj),]
  2320. # 3. Export the ranked data to a CSV file
  2321. write.csv(ranked_data, "DGE_IO_neuron_Clus0vsClus1_FC05_ranked_down.csv")
  2322. ```
  2323. ```{r}
  2324. dbs <- c("GO_Molecular_Function_2023",
  2325. "GO_Cellular_Component_2023",
  2326. "GO_Biological_Process_2023",
  2327. "KEGG_2019_Mouse")
  2328. enrichedR.list <- list()
  2329. enrichedR.list[["Cluster0_vs_1_FC05_up"]] <- enrichr(res_0_vs_1_FC05_up, dbs)
  2330. enrichedR.list[["Cluster0_vs_1_FC05_down"]] <- enrichr(res_0_vs_1_FC05_down, dbs)
  2331. ```
  2332. ```{r}
  2333. # Create an empty list to store the data frames for export
  2334. export_list <- list()
  2335. # Loop through your enrichedR.list and extract a specific database for each cluster
  2336. for (cluster_name in names(enrichedR.list)) {
  2337. # For example, extract the "GO_Biological_Process_2023" results
  2338. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$GO_Biological_Process_2023
  2339. }
  2340. # Export the prepared list to a single Excel file
  2341. write.xlsx(export_list, file = "enrichment_IO_calb1_neuron_Cluster0vs1_DESeq_20250915.xlsx")
  2342. ```
  2343. ```{r}
  2344. pdf("enrichment_plot_IO_neuron_clus0_day7_vs_clus1_day0_filter.pdf", width=12, height=8)
  2345. for (dge in names(enrichedR.list)) {
  2346. for (go_db in dbs) {
  2347. enr_df <- enrichedR.list[[dge]][[go_db]]
  2348. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2349. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2350. next
  2351. }
  2352. p <- plotEnrich(
  2353. enr_df,
  2354. showTerms = 50,
  2355. numChar = 100,
  2356. y = "Count",
  2357. orderBy = "FDR",
  2358. title = paste0(dge," in ", go_db),
  2359. xlab = ""
  2360. )
  2361. print(
  2362. p + theme(
  2363. axis.text.x = element_text(size = 6),
  2364. axis.text.y = element_text(size = 8),
  2365. axis.title = element_text(size = 6),
  2366. plot.title = element_text(size = 10),
  2367. plot.margin = margin(10, 10, 10, 10)
  2368. )
  2369. )
  2370. }
  2371. }
  2372. dev.off()
  2373. ```
  2374. ```{r}
  2375. pdf("enrichment_plot_IO_neuron_clus0_day7_vs_clus1_day0.pdf", width=12, height=8)
  2376. for (dge in names(enrichedR.list)) {
  2377. for (go_db in dbs) {
  2378. enr_df <- enrichedR.list[[dge]][[go_db]]
  2379. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2380. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2381. next
  2382. }
  2383. p <- plotEnrich(
  2384. enr_df,
  2385. showTerms = 50,
  2386. numChar = 100,
  2387. y = "Count",
  2388. orderBy = "FDR",
  2389. title = paste0(dge," in ", go_db),
  2390. xlab = ""
  2391. )
  2392. print(
  2393. p + theme(
  2394. axis.text.x = element_text(size = 6),
  2395. axis.text.y = element_text(size = 8),
  2396. axis.title = element_text(size = 6),
  2397. plot.title = element_text(size = 10),
  2398. plot.margin = margin(10, 10, 10, 10)
  2399. )
  2400. )
  2401. }
  2402. }
  2403. dev.off()
  2404. ```
  2405. ```{r}
  2406. pdf("enrichment_plot_IO_neuron_clus0_day7_vs_clus1_day0_filter_20250905.pdf", width=6, height=4)
  2407. # Define your list of keywords
  2408. keywords <- c("matergic synapse", "Thermogenesis", "TCA", "oxidative phosphor")
  2409. # keywords <- c("Gluta")
  2410. for (dge in names(enrichedR.list)) {
  2411. for (go_db in dbs) {
  2412. enr_df <- enrichedR.list[[dge]][[go_db]]
  2413. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2414. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2415. next
  2416. }
  2417. # Filter for keywords and FDR < 0.1
  2418. filtered_df <- enr_df[
  2419. grepl(paste(keywords, collapse = "|"), enr_df$Term, ignore.case = TRUE) & enr_df$Adjusted.P.value < 0.1,
  2420. ]
  2421. # Check if there are any results after filtering
  2422. if (nrow(filtered_df) == 0) {
  2423. message("Skipping ", dge, " in ", go_db, " (no terms found after filtering)")
  2424. next
  2425. }
  2426. # Use the filtered data for plotting
  2427. p <- plotEnrich(
  2428. filtered_df,
  2429. showTerms = 4,
  2430. numChar = 100,
  2431. y = "Count",
  2432. orderBy = "FDR",
  2433. title = paste0(dge, " in ", go_db, " (Filtered)"),
  2434. xlab = ""
  2435. )
  2436. print(
  2437. p + theme(
  2438. axis.text.x = element_text(size = 6),
  2439. axis.text.y = element_text(size = 8),
  2440. axis.title = element_text(size = 6),
  2441. plot.title = element_text(size = 10),
  2442. plot.margin = margin(10, 10, 10, 10)
  2443. )
  2444. )
  2445. }
  2446. }
  2447. dev.off()
  2448. ```
  2449. ### Day 14 vs Ctrl
  2450. ```{r}
  2451. # results: cluster2 (day14) vs cluster1 (ctrl)
  2452. res <- results(dds, contrast = c("cluster", "2", "1"))
  2453. res <- res[order(res$padj), ]
  2454. head(res)
  2455. ```
  2456. ```{r}
  2457. deg <- as.data.frame(res)
  2458. write.csv(deg, "DEG_neuron_cluster2_day14_vs_cluster1_day0_pseudobulk.csv")
  2459. ```
  2460. ```{r}
  2461. # Volcano plot
  2462. library(EnhancedVolcano)
  2463. p2 <- EnhancedVolcano(
  2464. deg,
  2465. lab = rownames(deg),
  2466. x = 'log2FoldChange',
  2467. y = 'pvalue',
  2468. title = "Cluster 2 (Day14) vs Cluster 1 (Day0)",
  2469. pCutoff = 0.01,
  2470. FCcutoff = 1,
  2471. pointSize = 3.0,
  2472. labSize = 6.0,
  2473. col=c('black', 'grey', 'grey', 'blue'),
  2474. colAlpha = 1
  2475. )
  2476. print(p2)
  2477. ```
  2478. ```{r}
  2479. # load & filter
  2480. res_2_vs_1 <- read.csv("DEG_neuron_cluster2_day14_vs_cluster1_day0_pseudobulk.csv", row.names = 1)
  2481. res_2_vs_1 <- res_2_vs_1[!is.na(res_2_vs_1$padj),]
  2482. # extract up/down
  2483. # FC > 0.5 (up and down)
  2484. res_2_vs_1_FC05_up <- rownames(res_2_vs_1[(res_2_vs_1$padj < 0.05) & (res_2_vs_1$log2FoldChange > 0.5),])
  2485. res_2_vs_1_FC05_down <- rownames(res_2_vs_1[(res_2_vs_1$padj < 0.05) & (res_2_vs_1$log2FoldChange < -0.5),])
  2486. ```
  2487. ```{r}
  2488. dbs <- c("GO_Molecular_Function_2023",
  2489. "GO_Cellular_Component_2023",
  2490. "GO_Biological_Process_2023",
  2491. "KEGG_2019_Mouse")
  2492. enrichedR.list <- list()
  2493. enrichedR.list[["Cluster2_vs_1_FC05_up"]] <- enrichr(res_2_vs_1_FC05_up, dbs)
  2494. enrichedR.list[["Cluster2_vs_1_FC05_down"]] <- enrichr(res_2_vs_1_FC05_down, dbs)
  2495. ```
  2496. ```{r}
  2497. # Create an empty list to store the data frames for export
  2498. export_list <- list()
  2499. # Loop through your enrichedR.list and extract a specific database for each cluster
  2500. for (cluster_name in names(enrichedR.list)) {
  2501. # For example, extract the "GO_Biological_Process_2023" results
  2502. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$GO_Biological_Process_2023
  2503. }
  2504. # Export the prepared list to a single Excel file
  2505. write.xlsx(export_list, file = "enrichment_IO_calb1_neuron_Cluster2vs1_DESeq_20250915.xlsx")
  2506. ```
  2507. ```{r}
  2508. pdf("enrichment_plot_IO_neuron_clus2_day14_vs_clus1_day0.pdf", width=12, height=8)
  2509. for (dge in names(enrichedR.list)) {
  2510. for (go_db in dbs) {
  2511. enr_df <- enrichedR.list[[dge]][[go_db]]
  2512. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2513. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2514. next
  2515. }
  2516. p <- plotEnrich(
  2517. enr_df,
  2518. showTerms = 50,
  2519. numChar = 100,
  2520. y = "Count",
  2521. orderBy = "FDR",
  2522. title = paste0(dge," in ", go_db),
  2523. xlab = ""
  2524. )
  2525. print(
  2526. p + theme(
  2527. axis.text.x = element_text(size = 6),
  2528. axis.text.y = element_text(size = 8),
  2529. axis.title = element_text(size = 6),
  2530. plot.title = element_text(size = 10),
  2531. plot.margin = margin(10, 10, 10, 10)
  2532. )
  2533. )
  2534. }
  2535. }
  2536. dev.off()
  2537. ```
  2538. ### D14 vs D7
  2539. ```{r}
  2540. # results: cluster 2 (day 14) cluster0 (day7)
  2541. res <- results(dds, contrast = c("cluster", "2", "0"))
  2542. res <- res[order(res$padj), ]
  2543. head(res)
  2544. ```
  2545. ```{r}
  2546. deg <- as.data.frame(res)
  2547. write.csv(deg, "DEG_neuron_cluster2_day14_vs_cluster0_day7_pseudobulk.csv")
  2548. ```
  2549. ```{r}
  2550. # Volcano plot
  2551. library(EnhancedVolcano)
  2552. p3 <- EnhancedVolcano(
  2553. deg,
  2554. lab = rownames(deg),
  2555. x = 'log2FoldChange',
  2556. y = 'pvalue',
  2557. title = "Cluster 2 (Day14) vs Cluster 0 (Day7)",
  2558. pCutoff = 0.01,
  2559. FCcutoff = 1,
  2560. pointSize = 3.0,
  2561. labSize = 6.0,
  2562. col=c('black', 'grey', 'grey', 'blue'),
  2563. colAlpha = 1
  2564. )
  2565. print(p3)
  2566. ```
  2567. ```{r}
  2568. # load & filter
  2569. res_2_vs_0 <- read.csv("DEG_neuron_cluster2_day14_vs_cluster0_day7_pseudobulk.csv", row.names = 1)
  2570. res_2_vs_0 <- res_2_vs_0[!is.na(res_2_vs_0$padj),]
  2571. # FC > 0.5 (up and down)
  2572. res_2_vs_0_FC05_up <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange > 0.5),])
  2573. res_2_vs_0_FC05_down <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange < -0.5),])
  2574. ```
  2575. ```{r}
  2576. # Assuming res_lesion_Ctrl is your data frame
  2577. # 1. Filter the data based on your criteria
  2578. filtered_data <- res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange > 0.5),]
  2579. # 2. Rank the filtered data by 'padj' in ascending order
  2580. ranked_data <- filtered_data[order(filtered_data$padj),]
  2581. # 3. Export the ranked data to a CSV file
  2582. write.csv(ranked_data, "DGE_IO_neuron_Clus2vsClus0_FC05_ranked_up.csv")
  2583. # 1. Filter the data based on your criteria
  2584. filtered_data <- res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange < -0.5),]
  2585. # 2. Rank the filtered data by 'padj' in ascending order
  2586. ranked_data <- filtered_data[order(filtered_data$padj),]
  2587. # 3. Export the ranked data to a CSV file
  2588. write.csv(ranked_data, "DGE_IO_neuron_Clus2vsClus0_FC05_ranked_down.csv")
  2589. ```
  2590. ```{r}
  2591. dbs <- c("GO_Molecular_Function_2023",
  2592. "GO_Cellular_Component_2023",
  2593. "GO_Biological_Process_2023",
  2594. "KEGG_2019_Mouse")
  2595. enrichedR.list <- list()
  2596. enrichedR.list[["Cluster2_vs_0_FC05_up"]] <- enrichr(res_2_vs_0_FC05_up, dbs)
  2597. enrichedR.list[["Cluster2_vs_0_FC05_down"]] <- enrichr(res_2_vs_0_FC05_down, dbs)
  2598. ```
  2599. ```{r}
  2600. # Create an empty list to store the data frames for export
  2601. export_list <- list()
  2602. # Loop through your enrichedR.list and extract a specific database for each cluster
  2603. for (cluster_name in names(enrichedR.list)) {
  2604. # For example, extract the "GO_Biological_Process_2023" results
  2605. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$KEGG_2019_Mouse
  2606. }
  2607. # Export the prepared list to a single Excel file
  2608. openxlsx::write.xlsx(export_list, file = "enrichment_IO_calb1_neuron_Cluster2vs0_DESeq2_KEGG_20250915.xlsx")
  2609. ```
  2610. ```{r}
  2611. pdf("enrichment_plot_IO_neuron_clus2_day14_vs_clus0_day7.pdf", width=12, height=8)
  2612. for (dge in names(enrichedR.list)) {
  2613. for (go_db in dbs) {
  2614. enr_df <- enrichedR.list[[dge]][[go_db]]
  2615. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2616. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2617. next
  2618. }
  2619. p <- plotEnrich(
  2620. enr_df,
  2621. showTerms = 50,
  2622. numChar = 100,
  2623. y = "Count",
  2624. orderBy = "FDR",
  2625. title = paste0(dge," in ", go_db),
  2626. xlab = ""
  2627. )
  2628. print(
  2629. p + theme(
  2630. axis.text.x = element_text(size = 6),
  2631. axis.text.y = element_text(size = 8),
  2632. axis.title = element_text(size = 6),
  2633. plot.title = element_text(size = 10),
  2634. plot.margin = margin(10, 10, 10, 10)
  2635. )
  2636. )
  2637. }
  2638. }
  2639. dev.off()
  2640. ```
  2641. ```{r}
  2642. pdf("enrichment_plot_IO_neuron_clus2_day14_vs_clus0_day7_filter.pdf", width=6, height=4)
  2643. # Define your list of keywords
  2644. keywords <- c("potentiation", "calcium signaling pathway", "depression", "synapse")
  2645. # keywords <- c("Gluta")
  2646. for (dge in names(enrichedR.list)) {
  2647. for (go_db in dbs) {
  2648. enr_df <- enrichedR.list[[dge]][[go_db]]
  2649. if (is.null(enr_df) || nrow(enr_df) == 0) {
  2650. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  2651. next
  2652. }
  2653. # Filter for keywords and FDR < 0.1
  2654. filtered_df <- enr_df[
  2655. grepl(paste(keywords, collapse = "|"), enr_df$Term, ignore.case = TRUE) & enr_df$Adjusted.P.value < 0.1,
  2656. ]
  2657. # Check if there are any results after filtering
  2658. if (nrow(filtered_df) == 0) {
  2659. message("Skipping ", dge, " in ", go_db, " (no terms found after filtering)")
  2660. next
  2661. }
  2662. # Use the filtered data for plotting
  2663. p <- plotEnrich(
  2664. filtered_df,
  2665. showTerms = 4,
  2666. numChar = 100,
  2667. y = "Count",
  2668. orderBy = "FDR",
  2669. title = paste0(dge, " in ", go_db, " (Filtered)"),
  2670. xlab = ""
  2671. )
  2672. print(
  2673. p + theme(
  2674. axis.text.x = element_text(size = 6),
  2675. axis.text.y = element_text(size = 8),
  2676. axis.title = element_text(size = 6),
  2677. plot.title = element_text(size = 10),
  2678. plot.margin = margin(10, 10, 10, 10)
  2679. )
  2680. )
  2681. }
  2682. }
  2683. dev.off()
  2684. ```
  2685. ```{r}
  2686. NeuronClusterMarker <- c("COX1", "COX2", "COX3", "ATP6", "ND4", "ND5", "Caln1", "Calm1", "Camk2a", "Kcnab1", "Kcnc1", "Kcnip4", "Kcna1", "Kcnd3", "Cacna1c", "Cdh11", "Gria1", "Grin1", "Grin2a","Ajap1", "Wnt5a" )
  2687. p <- DotPlot(
  2688. seurat_obj_IO_calb1,
  2689. features = NeuronClusterMarker,
  2690. group.by = "seurat_clusters",
  2691. assay = "RNA_repaired"
  2692. ) +
  2693. scale_color_gradient2(
  2694. low = "blue",
  2695. mid = "lightyellow",
  2696. high = "red",
  2697. midpoint = 0,
  2698. limits = c(-1,1),
  2699. oob = scales::squish
  2700. ) +
  2701. ggtitle("IO Calb1 Neuron Cluster Markers") +
  2702. theme(
  2703. axis.text.x = element_text(angle = 45, hjust = 1, size = 10),
  2704. axis.text.y = element_text(size = 10),
  2705. text = element_text(size = 12)
  2706. )
  2707. print(p)
  2708. ggsave("Dotplot_IO_Calb1_neuron_Cluster_markers.svg" , plot = p, width = 7, height = 4, units="in")
  2709. ```
  2710. --------------------------------------------
  2711. # Microglia in the IO
  2712. *** obsolete codes due to loading .rds
  2713. ```{r}
  2714. micro_Balazs_markers = c("Aif1", "Maf", "Spi1", "Csf1r")
  2715. seurat_obj_IO_calb1 <- AddModuleScore(
  2716. seurat_obj_IO_calb1,
  2717. features=list(micro_Balazs_markers),
  2718. nbin = 24,
  2719. ctrl = 100,
  2720. assay = "RNA_repaired",
  2721. slot = "data",
  2722. name = "AMS",
  2723. )
  2724. colnames([email hidden]) <- c(colnames([email hidden])[1:(length(colnames([email hidden]))-1)], "micro_Balazs_markers")
  2725. options(repr.plot.width=6, repr.plot.height=5)
  2726. FeaturePlot(seurat_obj_IO_calb1, reduction = "umap", features = "micro_Balazs_markers", order=TRUE, pt.size=1, raster=FALSE, min.cutoff=0)
  2727. seurat_obj_IO_calb1_micro <- subset(seurat_obj_IO_calb1, subset= micro_Balazs_markers > 0.05)
  2728. ```
  2729. ```{r}
  2730. # load the .rds file shared on 23rd Aug 2025
  2731. seurat_obj_IO_calb1_micro <- readRDS("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/seurat_obj_IO_calb1_micro_DIET.rds")
  2732. ```
  2733. ```{r}
  2734. options(repr.plot.width=11, repr.plot.height=9)
  2735. DimPlot(seurat_obj_IO_calb1, cells.highlight = colnames(seurat_obj_IO_calb1_micro), pt.size=0.5,cols.highlight = c("red", "grey50"), raster=FALSE)
  2736. ```
  2737. ```{r}
  2738. percent_micro <- (as.vector(table(seurat_obj_IO_calb1_micro$orig.ident))[1:12]*100)/as.vector(table(seurat_obj_IO$orig.ident))[1:12]
  2739. mat <- tibble(
  2740. group = c("Ctrl","Ctrl","Ctrl","Ctrl","D7","D7","D7","D7","D14","D14","D14","D14"),
  2741. measurement = percent_micro
  2742. )
  2743. mat$group <- factor(mat$group, levels = c("Ctrl", "D7", "D14"))
  2744. options(repr.plot.width=4, repr.plot.height=6)
  2745. barplot_with_error_and_dots(mat, x = group, y = measurement, error = "se", title="MG > 10% pixels (% of IO)")
  2746. ```
  2747. ```{r}
  2748. DefaultAssay(seurat_obj_IO_calb1_micro) <- "RNA"
  2749. seurat_obj_IO_calb1_micro <- NormalizeData(seurat_obj_IO_calb1_micro, normalization.method = "LogNormalize", scale.factor = 10000)
  2750. DefaultAssay(seurat_obj_IO_calb1_micro) <- "RNA_repaired"
  2751. seurat_obj_IO_calb1_micro <- NormalizeData(seurat_obj_IO_calb1_micro, normalization.method = "LogNormalize", scale.factor = 10000)
  2752. seurat_obj_IO_calb1_micro <- FindVariableFeatures(seurat_obj_IO_calb1_micro, selection.method = "vst", nfeatures = 1000)
  2753. options(repr.plot.width=10, repr.plot.height=7)
  2754. VariableFeaturePlot(object = seurat_obj_IO_calb1_micro, selection.method = "vst", log = TRUE)
  2755. ```
  2756. ```{r}
  2757. seurat_obj_IO_calb1_micro <- ScaleData(seurat_obj_IO_calb1_micro, features = rownames(seurat_obj_IO_calb1_micro))
  2758. ```
  2759. ```{r}
  2760. seurat_obj_IO_calb1_micro <- RunPCA(seurat_obj_IO_calb1_micro)
  2761. ```
  2762. ```{r}
  2763. options(repr.plot.width=10, repr.plot.height=7)
  2764. ElbowPlot(seurat_obj_IO_calb1_micro, reduction = "pca", ndims = 50)
  2765. ```
  2766. ```{r}
  2767. nb_pcs = 15
  2768. seurat_obj_IO_calb1_micro <- FindNeighbors(seurat_obj_IO_calb1_micro, reduction = "pca", dims = 1:nb_pcs, prune.SNN = 0)
  2769. cluster_res = 0.7
  2770. seurat_obj_IO_calb1_micro <- FindClusters(seurat_obj_IO_calb1_micro, resolution = cluster_res)
  2771. ```
  2772. ```{r}
  2773. table(seurat_obj_IO_calb1_micro$seurat_clusters)
  2774. ```
  2775. ```{r}
  2776. seurat_clusters_IO_calb1_micro_color <- list()
  2777. n_clusters <- 5
  2778. seurat_clusters_IO_calb1_micro_color <- color_palette_30[1:n_clusters]
  2779. names(seurat_clusters_IO_calb1_micro_color) <- seq(1:n_clusters)-1
  2780. seurat_obj_IO_calb1_micro <- RunUMAP(seurat_obj_IO_calb1_micro, reduction = "pca", dims = 1:nb_pcs)
  2781. ```
  2782. ```{r}
  2783. options(repr.plot.width=25, repr.plot.height=8)
  2784. DimPlot(seurat_obj_IO_calb1_micro, group.by="orig.ident", split.by="orig.ident_merge", cols=orig.ident_colors, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  2785. ```
  2786. ```{r}
  2787. options(repr.plot.width=11, repr.plot.height=9)
  2788. for(timepoint in names(orig.ident_merge_colors)){
  2789. highlight_cells <- rownames([email hidden][[email hidden]$orig.ident_merge==timepoint,])
  2790. print(DimPlot(seurat_obj_IO_calb1_micro, cells.highlight = highlight_cells, pt.size=0.5, cols.highlight = orig.ident_merge_colors[timepoint], raster=FALSE))
  2791. }
  2792. ```
  2793. ```{r}
  2794. options(repr.plot.width=11, repr.plot.height=9)
  2795. DimPlot(seurat_obj_IO_calb1_micro, group.by="seurat_clusters", cols=seurat_clusters_IO_calb1_micro_color, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE)
  2796. ```
  2797. ```{r}
  2798. options(repr.plot.width=11, repr.plot.height=9)
  2799. p <- DimPlot(seurat_obj_IO_calb1_micro, group.by="seurat_clusters", cols=seurat_clusters_IO_calb1_micro_color, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE) +NoAxes()
  2800. print(p)
  2801. ggsave("IO_calb1_microglia_Clusters_UMAP.svg", height = 3, width = 4, units = "in")
  2802. ```
  2803. ```{r}
  2804. options(repr.plot.width=25, repr.plot.height=8)
  2805. DimPlot(seurat_obj_IO_calb1_micro, group.by="seurat_clusters", split.by="orig.ident_merge", cols=seurat_clusters_IO_calb1_micro_color, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  2806. ```
  2807. ```{r}
  2808. options(repr.plot.width=15, repr.plot.height=15)
  2809. set.seed(115)
  2810. mat = as.matrix(table(seurat_obj_IO_calb1_micro$orig.ident_merge, seurat_obj_IO_calb1_micro$seurat_clusters))
  2811. for (row in 1:nrow(mat)) mat[row,] <- as.integer(mat[row,]/(sum(mat[row,])/min(rowSums(mat))))
  2812. circos.clear()
  2813. par(cex = 0.8)
  2814. chordDiagram(mat, annotationTrack = c("grid", "axis"), preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(mat))))/3), big.gap = 20, small.gap = 2, order = c(colnames(mat), names(orig.ident_merge_colors)), grid.col=c(rev(seurat_clusters_IO_calb1_micro_color), rev(orig.ident_merge_colors)))
  2815. circos.track(track.index = 1, panel.fun = function(x, y) {circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, facing = "clockwise", niceFacing = TRUE, adj = c(-0.3, 0.5))}, bg.border = NA)
  2816. ```
  2817. ```{r}
  2818. pdf("Chord_plot_IO_MgClus_20250906.pdf", width=8, height=8)
  2819. options(repr.plot.width=15, repr.plot.height=15)
  2820. set.seed(115)
  2821. mat = as.matrix(table(seurat_obj_IO_calb1_micro$orig.ident_merge, seurat_obj_IO_calb1_micro$seurat_clusters))
  2822. for (row in 1:nrow(mat)) mat[row,] <- as.integer(mat[row,]/(sum(mat[row,])/min(rowSums(mat))))
  2823. circos.clear()
  2824. par(cex = 0.8)
  2825. chordDiagram(mat, annotationTrack = c("grid", "axis"), preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(mat))))/3), big.gap = 20, small.gap = 2, order = c(colnames(mat), names(orig.ident_merge_colors)), grid.col=c(rev(seurat_clusters_IO_calb1_micro_color), rev(orig.ident_merge_colors)))
  2826. circos.track(track.index = 1, panel.fun = function(x, y) {circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, facing = "clockwise", niceFacing = TRUE, adj = c(-0.3, 0.5))}, bg.border = NA)
  2827. dev.off()
  2828. ```
  2829. ```{r}
  2830. t <- table(seurat_obj_IO_calb1_micro$orig.ident, seurat_obj_IO_calb1_micro$seurat_clusters)
  2831. t_prop <- t/as.vector(table(seurat_obj_IO$orig.ident))*100
  2832. rownames(t_prop) <- c("Ctrl","Ctrl","Ctrl","Ctrl","D7","D7","D7","D7","D14","D14","D14","D14")
  2833. df_table <- as.data.frame(t_prop)
  2834. colnames(df_table) <- c("group", "cluster", "count")
  2835. df_summary <- df_table %>%
  2836. group_by(group, cluster) %>%
  2837. summarise(
  2838. mean = mean(count),
  2839. se = sd(count) / sqrt(n()),
  2840. .groups = "drop"
  2841. )
  2842. ```
  2843. ```{r}
  2844. options(repr.plot.width=10, repr.plot.height=10)
  2845. ggplot(df_summary, aes(x = cluster, y = mean, fill = group)) +
  2846. # Bars
  2847. geom_bar(stat = "identity", position = position_dodge(width = 0.9), color = "black") +
  2848. # Error bars
  2849. geom_errorbar(aes(ymin = mean - se, ymax = mean + se),
  2850. position = position_dodge(width = 0.9),
  2851. width = 0.2) +
  2852. # Manual fill colors
  2853. scale_fill_manual(values = orig.ident_merge_colors) +
  2854. # Points dodged and jittered
  2855. geom_point(
  2856. data = df_table,
  2857. aes(x = cluster, y = count, fill = group), # <- fill included so dodge works
  2858. position = position_jitterdodge(jitter.width = 0.4, dodge.width = 0.9),
  2859. size = 2, shape = 21, stroke = 0.5,
  2860. color = "black", # border
  2861. show.legend = FALSE
  2862. ) +
  2863. theme_minimal() +
  2864. labs(x = "", y = "% of pixels in the IO") +
  2865. ggtitle("Number of microglia pixels associated calbindin neurons divided by each IO for each sample") +
  2866. theme(panel.grid.major.x = element_blank(),
  2867. panel.grid.minor.x = element_blank())
  2868. ```
  2869. ```{r}
  2870. t <- table(Cluster=seurat_obj_IO_calb1_micro$seurat_clusters, Batch=[email hidden][["orig.ident_merge"]])
  2871. t <- t[,rev(names(orig.ident_merge_colors))]
  2872. options(repr.plot.width=10, repr.plot.height=10)
  2873. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+100, 20, f = ceiling)), col = rev(orig.ident_merge_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  2874. ```
  2875. ```{r}
  2876. t <- table(Cluster=seurat_obj_IO_calb1_micro$seurat_clusters, Batch=[email hidden][["orig.ident"]])
  2877. t <- t[,rev(names(orig.ident_colors))]
  2878. options(repr.plot.width=10, repr.plot.height=10)
  2879. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+200, 20, f = ceiling)), col = rev(orig.ident_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  2880. ```
  2881. ```{r}
  2882. DefaultAssay(seurat_obj_IO_calb1_micro) <- "RNA"
  2883. Idents(object = seurat_obj_IO_calb1_micro) <- "seurat_clusters"
  2884. seurat_obj_IO_calb1_micro.markers.seurat_clusters <- FindAllMarkers(seurat_obj_IO_calb1_micro, slot = "data", min.pct = 0.1, logfc.threshold = 0, only.pos = TRUE)
  2885. ```
  2886. ```{r}
  2887. write.csv(seurat_obj_IO_calb1_micro.markers.seurat_clusters, "IO_calb1_microglia_clusterMarkers_20250916.csv")
  2888. ```
  2889. ```{r}
  2890. seurat_obj_IO_calb1_micro.markers.seurat_clusters_pval <- seurat_obj_IO_calb1_micro.markers.seurat_clusters[seurat_obj_IO_calb1_micro.markers.seurat_clusters$p_val_adj < 0.05,]
  2891. seurat_obj_IO_calb1_micro.markers.seurat_clusters_best <- seurat_obj_IO_calb1_micro.markers.seurat_clusters_pval %>%
  2892. filter(avg_log2FC > 0.5) %>%
  2893. filter(pct.1 > 0.3) %>%
  2894. arrange(cluster, desc(avg_log2FC)) %>%
  2895. group_by(cluster)
  2896. markers_heatmap <- seurat_obj_IO_calb1_micro.markers.seurat_clusters_best %>% top_n(n = 10, wt = avg_log2FC)
  2897. topDiffCluster <- seurat_obj_IO_calb1_micro.markers.seurat_clusters_best %>% top_n(n = 200, wt = avg_log2FC)
  2898. sample_df <- as.data.frame(lapply(split(topDiffCluster, topDiffCluster$cluster), function(x) c(x$gene,rep("None", 200-length(x$gene)))))
  2899. colnames(sample_df) <- levels(topDiffCluster$cluster)
  2900. sample_df
  2901. ```
  2902. ```{r}
  2903. # keep all significant markers without top_n
  2904. seurat_obj_IO_calb1_micro.markers.seurat_clusters_pval <-
  2905. seurat_obj_IO_calb1_micro.markers.seurat_clusters %>%
  2906. filter(p_val_adj < 0.05)
  2907. seurat_obj_IO_calb1_micro.markers.seurat_clusters_best <-
  2908. seurat_obj_IO_calb1_micro.markers.seurat_clusters_pval %>%
  2909. filter(avg_log2FC > 0.5, pct.1 > 0.3) %>%
  2910. arrange(cluster, desc(avg_log2FC)) %>%
  2911. group_by(cluster)
  2912. # keep full list per cluster
  2913. topDiffCluster <- seurat_obj_IO_calb1_micro.markers.seurat_clusters_best
  2914. # split into clusters
  2915. gene_lists <- split(topDiffCluster$gene, topDiffCluster$cluster)
  2916. # find max list length
  2917. max_len <- max(lengths(gene_lists))
  2918. # pad shorter clusters with NA
  2919. sample_df <- as.data.frame(
  2920. lapply(gene_lists, function(x) c(x, rep(NA, max_len - length(x))))
  2921. )
  2922. # set cluster names as column names
  2923. colnames(sample_df) <- names(gene_lists)
  2924. # write to CSV
  2925. write.csv(sample_df, "~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/Bastien20250827/ClusterMarker_IO_Calb1_MG_20250906.csv", row.names = FALSE)
  2926. ```
  2927. ```{r}
  2928. options(repr.plot.width=30, repr.plot.height=20)
  2929. DoMultiBarHeatmap(
  2930. subset(seurat_obj_IO_calb1_micro, downsample = 200),
  2931. features = unique(markers_heatmap$gene),
  2932. cells = NULL,
  2933. group.by = "seurat_clusters",
  2934. additional.group.by = c("orig.ident_merge"),
  2935. additional.group.sort.by = c("orig.ident_merge"),
  2936. cols.use = list(seurat_clusters=seurat_clusters_IO_calb1_micro_color, orig.ident_merge=orig.ident_merge_colors),
  2937. group.bar = TRUE,
  2938. disp.min = -2.5,
  2939. disp.max = NULL,
  2940. layer = "scale.data",
  2941. assay = "RNA_repaired",
  2942. label = TRUE,
  2943. size = 5.5,
  2944. hjust = 0,
  2945. angle = 45,
  2946. raster = TRUE,
  2947. draw.lines = TRUE,
  2948. lines.width = NULL,
  2949. group.bar.height = 0.02,
  2950. combine = TRUE
  2951. ) + theme(text = element_text(size = 8))
  2952. ```
  2953. ```{r}
  2954. pdf("TissueMapping_IO_microglia_cluster_20250906.pdf", width = 5.3, height = 4.6)
  2955. for (sample_name in names(orig.ident_colors)){
  2956. annot_plot <- [email hidden][seurat_obj_IO_calb1_micro$orig.ident==sample_name,]
  2957. annot_plot_plus <- [email hidden][(seurat_obj_IO$orig.ident==sample_name & seurat_obj_IO$InfOlive=="core"),]
  2958. annot_plot_plus <- annot_plot_plus[!(rownames(annot_plot_plus) %in% rownames(annot_plot)),]
  2959. annot_plot_plus$seurat_clusters <- 99
  2960. annot_plot <- annot_plot[,c("x","y","seurat_clusters")]
  2961. annot_plot_plus <- annot_plot_plus[,c("x","y","seurat_clusters")]
  2962. annot_plot$seurat_clusters <- as.character(annot_plot$seurat_clusters)
  2963. annot_plot_plus$seurat_clusters <- as.character(annot_plot_plus$seurat_clusters)
  2964. annot_plot <- rbind(annot_plot_plus,annot_plot)
  2965. annot_plot$seurat_clusters <- factor(x = annot_plot$seurat_clusters, levels = c(names(seurat_clusters_IO_calb1_micro_color),99))
  2966. options(repr.plot.width=5.3, repr.plot.height=4.6)
  2967. df_tmp <- data.frame(
  2968. x = annot_plot$x,
  2969. y = annot_plot$y,
  2970. value = annot_plot$seurat_clusters
  2971. )
  2972. tmp_colors <- c(seurat_clusters_IO_calb1_micro_color,"lightgrey")
  2973. names(tmp_colors) <- c(names(seurat_clusters_IO_calb1_micro_color),99)
  2974. print(ggplot(df_tmp, aes(x, y)) +
  2975. geom_point(aes(colour = value),shape=15, size = 1)+
  2976. scale_color_manual(values=tmp_colors) +
  2977. scale_x_continuous(expand=c(-0.005,0), lim=c(0,101)) +
  2978. scale_y_continuous(expand=c(-0.006,0), lim=c(0,101)) +
  2979. theme_void() +
  2980. ggtitle(sample_name))
  2981. }
  2982. dev.off()
  2983. ```
  2984. ```{r}
  2985. # saveRDS(seurat_obj_IO_calb1_micro, "seurat_obj_IO_calb1_micro.rds")
  2986. ```
  2987. ```{r}
  2988. # load the 5 csv files
  2989. MC1_Volcano_df <- read.csv("goncaloGeneLists/MC1_filtered_genes.csv")
  2990. MC3_Volcano_df <- read.csv("goncaloGeneLists/MC3_filtered_genes.csv")
  2991. MC1_NonDE_df <- read.csv("goncaloGeneLists/MC1_Non_DE.csv")
  2992. MC2_NonDE_df <- read.csv("goncaloGeneLists/MC2_Non_DE.csv")
  2993. MC3_NonDE_df <- read.csv("goncaloGeneLists/MC3_Non_DE.csv")
  2994. ```
  2995. ```{r}
  2996. # Filter to make them all into lists
  2997. FDRCutOff <- 0.1
  2998. MC1_Volcano_df_fil <- MC1_Volcano_df[MC1_Volcano_df$FDR.x < FDRCutOff , ]
  2999. MC1_Volcano_list <- MC1_Volcano_df_fil$gene
  3000. MC3_Volcano_df_fil <- MC3_Volcano_df[MC3_Volcano_df$FDR.x < FDRCutOff , ]
  3001. MC3_Volcano_list <- MC3_Volcano_df_fil$gene
  3002. MC1_NonDE_df_fil <- MC1_NonDE_df[MC1_NonDE_df$FDR < FDRCutOff , ]
  3003. MC1_NonDE_df_list <- MC1_NonDE_df_fil$name
  3004. MC2_NonDE_df_fil <- MC2_NonDE_df[MC2_NonDE_df$FDR < FDRCutOff , ]
  3005. MC2_NonDE_df_list <- MC2_NonDE_df_fil$name
  3006. MC3_NonDE_df_fil <- MC3_NonDE_df[MC3_NonDE_df$FDR < FDRCutOff , ]
  3007. MC3_NonDE_df_list <- MC3_NonDE_df_fil$name
  3008. ```
  3009. ```{r}
  3010. # Perform gene scoring and plot the violin plots for different clusters
  3011. seurat_obj_IO_calb1_micro <- AddModuleScore(
  3012. object = seurat_obj_IO_calb1_micro,
  3013. features = list(MC1_Volcano_list, MC3_Volcano_list),
  3014. name = c("MC1_Score", "MC3_Score")
  3015. )
  3016. # violin plots
  3017. pMC1 <- VlnPlot(seurat_obj_IO_calb1_micro, features = c("MC1_Score1"), group.by = "seurat_clusters") +
  3018. ggtitle("IO microglia MC1 Gene Module Score")
  3019. print(pMC1)
  3020. pMC3 <- VlnPlot(seurat_obj_IO_calb1_micro, features = c("MC3_Score2"), group.by = "seurat_clusters") +
  3021. ggtitle("IO microglia MC3 Gene Module Score")+
  3022. scale_y_continuous(limits = c(-0.1, 0.7), breaks = c(0, 0.2, 0.4, 0.6))
  3023. print(pMC3)
  3024. FeaturePlot(seurat_obj_IO_calb1_micro, features = c("MC1_Score1", "MC3_Score2"))
  3025. # export the violin plots
  3026. ggsave("IO_calb1microglia_MC1score_20250909.svg", plot = pMC1)
  3027. ggsave("IO_calb1microglia_MC3score_20250909.svg", plot = pMC3)
  3028. ```
  3029. # DAM score
  3030. ```{r}
  3031. # load the 5 csv files
  3032. DAM_geneList_df <- read.csv("DAM_geneList.csv")
  3033. KS_DAM_geneList_df <- read.csv("Keren-Shaul DAM list.csv")
  3034. ```
  3035. ```{r}
  3036. # Filter to make them all into lists
  3037. DAM_geneList <- DAM_geneList_df$DAM_geneList
  3038. KS_DAM_geneList_DAM <- KS_DAM_geneList_df$Keren_shaul_DAM_up
  3039. KS_DAM_geneList_HM <- KS_DAM_geneList_df$Keren_shaul_DAM_down
  3040. KS_DAM_geneList_HM <- KS_DAM_geneList_HM[KS_DAM_geneList_HM!=""]
  3041. ```
  3042. ```{r}
  3043. # Perform gene scoring and plot the violin plots for different clusters
  3044. seurat_obj_IO_calb1_micro <- AddModuleScore(
  3045. object = seurat_obj_IO_calb1_micro,
  3046. features = list(DAM_geneList, KS_DAM_geneList_DAM, KS_DAM_geneList_HM),
  3047. name = c("DAM_geneList", "KS_DAM_geneList_DAM", "KS_DAM_geneList_HM")
  3048. )
  3049. # violin plots
  3050. VlnPlot(seurat_obj_IO_calb1_micro, features = c("DAM_geneList1"), group.by = "seurat_clusters") +
  3051. ggtitle("DAM_geneList VolcanoPlot Gene Module Score")
  3052. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_DAM2"), group.by = "seurat_clusters") +
  3053. ggtitle("KS_DAM_geneList_DAM VolcanoPlot Gene Module Score")
  3054. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_HM3"), group.by = "seurat_clusters") +
  3055. ggtitle("KS_DAM_geneList_DAM VolcanoPlot Gene Module Score")
  3056. VlnPlot(seurat_obj_IO_calb1_micro, features = c("DAM_geneList1"), group.by = "orig.ident_merge") +
  3057. ggtitle("DAM_geneList VolcanoPlot Gene Module Score")
  3058. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_DAM2"), group.by = "orig.ident_merge") +
  3059. ggtitle("KS_DAM_geneList_DAM VolcanoPlot Gene Module Score")
  3060. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_HM3"), group.by = "orig.ident_merge") +
  3061. ggtitle("KS_DAM_geneList_DAM VolcanoPlot Gene Module Score")
  3062. FeaturePlot(seurat_obj_IO_calb1_micro, features = c("MC1_Score1", "MC3_Score2"))
  3063. ```
  3064. ```{r}
  3065. pdf("DAM_IO_microglia_calb1.pdf", width=12, height=8)
  3066. # violin plots
  3067. VlnPlot(seurat_obj_IO_calb1_micro, features = c("DAM_geneList1"), group.by = "seurat_clusters") +
  3068. ggtitle("DAM geneList (from 3dpl) Violin Plot Gene Module Score")
  3069. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_DAM2"), group.by = "seurat_clusters") +
  3070. ggtitle("KS DAM Violin Plot Gene Module Score")
  3071. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_HM3"), group.by = "seurat_clusters") +
  3072. ggtitle("KS homeostasis Violin Plot Gene Module Score")
  3073. VlnPlot(seurat_obj_IO_calb1_micro, features = c("DAM_geneList1"), group.by = "orig.ident_merge") +
  3074. ggtitle("DAM geneList (from 3dpl) Violin Plot Gene Module Score")
  3075. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_DAM2"), group.by = "orig.ident_merge") +
  3076. ggtitle("KS DAM Violin Plot Gene Module Score")
  3077. VlnPlot(seurat_obj_IO_calb1_micro, features = c("KS_DAM_geneList_HM3"), group.by = "orig.ident_merge") +
  3078. ggtitle("KS homeostasis Violin Plot Gene Module Score")
  3079. dev.off()
  3080. ```
  3081. ## NeuroProtective score
  3082. ```{r}
  3083. # load the .csv files
  3084. Pro_GeneList_df <- read.csv("NeuProtectiveGeneList.csv")
  3085. ```
  3086. ```{r}
  3087. # get the different list
  3088. Protective_Thora_list <- Pro_GeneList_df$Thora_List
  3089. Protective_Full_list <- Pro_GeneList_df$Full_List
  3090. Protective_BV_list <- Pro_GeneList_df$BV_List
  3091. Protective_Thora_list <- Protective_Thora_list[Protective_Thora_list!=""]
  3092. Protective_Thora_list<- paste0(
  3093. toupper(substr(Protective_Thora_list, 1, 1)),
  3094. tolower(substr(Protective_Thora_list, 2, nchar(Protective_Thora_list)))
  3095. )
  3096. Protective_BV_list <- Protective_BV_list[Protective_BV_list!=""]
  3097. Protective_BV_list<- paste0(
  3098. toupper(substr(Protective_BV_list, 1, 1)),
  3099. tolower(substr(Protective_BV_list, 2, nchar(Protective_BV_list)))
  3100. )
  3101. Protective_Full_list <- Protective_Full_list[Protective_Full_list!=""]
  3102. Protective_Full_list<- paste0(
  3103. toupper(substr(Protective_Full_list, 1, 1)),
  3104. tolower(substr(Protective_Full_list, 2, nchar(Protective_Full_list)))
  3105. )
  3106. Trimmed_List <- c("Bdnf", "Igf1", "Fgf13")
  3107. # Trimmed_List_cl3 <-
  3108. ```
  3109. ```{r}
  3110. # Perform gene scoring and plot the violin plots for different clusters
  3111. seurat_obj_IO_calb1_micro <- AddModuleScore(
  3112. object = seurat_obj_IO_calb1_micro,
  3113. features = list(Trimmed_List),
  3114. name = c( "Trimmed_List")
  3115. )
  3116. # violin plots
  3117. VlnPlot(seurat_obj_IO_calb1_micro, features = c("Trimmed_List1"), group.by = "seurat_clusters") +
  3118. ggtitle("Bdnf and Igf1 Violin Plot Gene Module Score")
  3119. VlnPlot(seurat_obj_IO_calb1_micro, features = c("Trimmed_List1"), group.by = "orig.ident_merge") +
  3120. ggtitle("Bdnf, Igf1, Fgf13 Violin Plot Gene Module Score")
  3121. ```
  3122. -----------------------
  3123. ```{r}
  3124. # Extract metadata
  3125. df <- [email hidden] %>%
  3126. dplyr::select(seurat_clusters, orig.ident_merge)
  3127. # Count cells per cluster and per day
  3128. df_summary <- df %>%
  3129. group_by(orig.ident_merge, seurat_clusters) %>%
  3130. summarise(n = n(), .groups = "drop") %>%
  3131. group_by(orig.ident_merge) %>%
  3132. mutate(freq = n / sum(n)) # normalize to fractions
  3133. # Plot stacked barplot
  3134. ggplot(df_summary, aes(x = orig.ident_merge, y = freq, fill = seurat_clusters)) +
  3135. geom_bar(stat = "identity", position = "fill") +
  3136. ylab("Fraction of Cells") +
  3137. xlab("Day") +
  3138. scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  3139. theme_classic() +
  3140. theme(axis.text.x = element_text(angle = 45, hjust = 1))
  3141. ggplot(df_summary, aes(x = orig.ident_merge, y = freq, fill = seurat_clusters)) +
  3142. geom_bar(stat = "identity", position = "fill") +
  3143. geom_text(aes(label = scales::percent(freq, accuracy = 1)),
  3144. position = position_stack(vjust = 0.5), size = 3) +
  3145. ylab("Fraction of Cells") +
  3146. xlab("Day") +
  3147. scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  3148. theme_classic() +
  3149. theme(axis.text.x = element_text(angle = 45, hjust = 1))
  3150. ggplot(df_summary, aes(x = orig.ident_merge, y = freq, fill = seurat_clusters)) +
  3151. geom_bar(stat = "identity", position = "fill") +
  3152. geom_text(aes(label = scales::percent(freq, accuracy = 1)),
  3153. position = position_stack(vjust = 0.5), size = 3) +
  3154. ylab("Fraction of Cells") +
  3155. xlab("Day") +
  3156. scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  3157. theme_classic() +
  3158. theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  3159. scale_fill_manual(values = seurat_clusters_IO_calb1_color)
  3160. ```
  3161. ```{r}
  3162. # export the bar plot
  3163. barPlot <- ggplot(df_summary, aes(x = orig.ident_merge, y = freq, fill = seurat_clusters)) +
  3164. geom_bar(stat = "identity", position = "fill") +
  3165. geom_text(aes(label = scales::percent(freq, accuracy = 1)),
  3166. position = position_stack(vjust = 0.5), size = 3) +
  3167. ylab("Fraction of Cells") +
  3168. xlab("Day") +
  3169. scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  3170. theme_classic() +
  3171. theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  3172. scale_fill_manual(values = seurat_clusters_IO_calb1_color)
  3173. ggsave(filename = "IO_calb1Microglia_Cluster_barplot_20250907.svg", plot = barPlot, width = 10, height = 8, units = "in")
  3174. ```
  3175. ## Use the Marker genes for GO
  3176. ```{r}
  3177. subset_list_len <- 200
  3178. # extract gene lists from sample_df
  3179. Clus0_markers <- sample_df[1:subset_list_len,1]
  3180. Clus1_markers <- sample_df[1:subset_list_len,2]
  3181. Clus2_markers <- sample_df[1:subset_list_len,3]
  3182. Clus3_markers <- sample_df[1:subset_list_len,4]
  3183. Clus4_markers <- sample_df[1:subset_list_len,5]
  3184. # dbs set up
  3185. dbs <- c("GO_Molecular_Function_2023","GO_Cellular_Component_2023","GO_Biological_Process_2023","KEGG_2019_Mouse")
  3186. #
  3187. enrichedR.list <- list()
  3188. enrichedR.list[["Clus0_markers"]] <- enrichr(Clus0_markers, dbs)
  3189. enrichedR.list[["Clus1_markers"]] <- enrichr(Clus1_markers, dbs)
  3190. enrichedR.list[["Clus2_markers"]] <- enrichr(Clus2_markers, dbs)
  3191. enrichedR.list[["Clus3_markers"]] <- enrichr(Clus3_markers, dbs)
  3192. enrichedR.list[["Clus4_markers"]] <- enrichr(Clus4_markers, dbs)
  3193. ```
  3194. ```{r}
  3195. # Create an empty list to store the data frames for export
  3196. export_list <- list()
  3197. # Loop through your enrichedR.list and extract a specific database for each cluster
  3198. for (cluster_name in names(enrichedR.list)) {
  3199. # For example, extract the "GO_Biological_Process_2023" results
  3200. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$GO_Biological_Process_2023
  3201. }
  3202. # Export the prepared list to a single Excel file
  3203. openxlsx::write.xlsx(export_list, file = "enrichment_IO_calb1_microglia_ClusterMarker_GO_KEGG_20250915.xlsx")
  3204. ```
  3205. ```{r}
  3206. pdf("enrichment_plot_IO_Calb1MgClus_filSample_20250915.pdf", width=12, height=8)
  3207. for (dge in names(enrichedR.list)) {
  3208. for (go_db in dbs) {
  3209. enr_df <- enrichedR.list[[dge]][[go_db]]
  3210. if (is.null(enr_df) || nrow(enr_df) == 0) {
  3211. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  3212. next
  3213. }
  3214. p <- plotEnrich(
  3215. enr_df,
  3216. showTerms = 60,
  3217. numChar = 100,
  3218. y = "Count",
  3219. orderBy = "FDR",
  3220. title = paste0(dge," in ", go_db),
  3221. xlab = ""
  3222. )
  3223. print(
  3224. p + theme(
  3225. axis.text.x = element_text(size = 6),
  3226. axis.text.y = element_text(size = 8),
  3227. axis.title = element_text(size = 6),
  3228. plot.title = element_text(size = 10),
  3229. plot.margin = margin(10, 10, 10, 10)
  3230. )
  3231. )
  3232. }
  3233. }
  3234. dev.off()
  3235. ```
  3236. ```{r}
  3237. pdf("enrichment_plot_IO_Calb1MgClus_filterGO_20250915.pdf", width=8, height=3)
  3238. # Define your list of keywords
  3239. # for D14 clus 0
  3240. clus0_keywords <- c("Positive Regulation Of Receptor", "0030198",
  3241. "Cellular Response To Growth Factor Stimulus", "Positive Regulation Of Cell Migration")
  3242. # for D7
  3243. clus2_keywords <- c("Positive Regulation of Calcium Ion Transmembrane Transporter Activity", "Neuron Projection Morphogenesis", "Neurotransmitter Secretion", "Positive Regulation Of Cation Channel Activity")
  3244. keywords <- c(clus0_keywords, clus2_keywords)
  3245. for (dge in names(enrichedR.list)) {
  3246. for (go_db in dbs) {
  3247. enr_df <- enrichedR.list[[dge]][[go_db]]
  3248. if (is.null(enr_df) || nrow(enr_df) == 0) {
  3249. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  3250. next
  3251. }
  3252. # Filter for keywords and FDR < 0.1
  3253. filtered_df <- enr_df[
  3254. grepl(paste(keywords, collapse = "|"), enr_df$Term, ignore.case = TRUE) & enr_df$Adjusted.P.value < 0.1,
  3255. ]
  3256. # Check if there are any results after filtering
  3257. if (nrow(filtered_df) == 0) {
  3258. message("Skipping ", dge, " in ", go_db, " (no terms found after filtering)")
  3259. next
  3260. }
  3261. # Use the filtered data for plotting
  3262. p <- plotEnrich(
  3263. filtered_df,
  3264. showTerms = 4,
  3265. numChar = 100,
  3266. y = "Count",
  3267. orderBy = "FDR",
  3268. title = paste0(dge, " in ", go_db, " (Filtered)"),
  3269. xlab = ""
  3270. )
  3271. print(
  3272. p + theme(
  3273. axis.text.x = element_text(size = 6),
  3274. axis.text.y = element_text(size = 8),
  3275. axis.title = element_text(size = 6),
  3276. plot.title = element_text(size = 10),
  3277. plot.margin = margin(10, 10, 10, 10)
  3278. )
  3279. )
  3280. }
  3281. }
  3282. dev.off()
  3283. ```
  3284. ```{r}
  3285. pdf("enrichment_dotplot_IO_Calb1MgClus_filterGO_20250916.pdf", width=8, height=3)
  3286. clus0_keywords <- c("Positive Regulation Of Receptor", "0030198",
  3287. "Cellular Response To Growth Factor Stimulus", "Positive Regulation Of Cell Migration")
  3288. # for D7
  3289. clus2_keywords <- c("Positive Regulation of Calcium Ion Transmembrane Transporter Activity", "Neuron Projection Morphogenesis", "Neurotransmitter Secretion", "Positive Regulation Of Cation Channel Activity")
  3290. keywords <- c(clus0_keywords, clus2_keywords)
  3291. for (dge in names(enrichedR.list)) {
  3292. for (go_db in dbs) {
  3293. enr_df <- enrichedR.list[[dge]][[go_db]]
  3294. if (is.null(enr_df) || nrow(enr_df) == 0) {
  3295. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  3296. next
  3297. }
  3298. # ---- Prepare data ----
  3299. # Adjusted P value column in enrichR is usually "Adjusted.P.value"
  3300. if (!("Adjusted.P.value" %in% colnames(enr_df))) {
  3301. stop("No Adjusted.P.value column found in enrichment results for ", dge, " / ", go_db)
  3302. }
  3303. # Significance (FDR)
  3304. enr_df$FDR <- as.numeric(enr_df$Adjusted.P.value)
  3305. # Overlap is in "k/n" format -> extract numerator and denominator
  3306. tmp <- do.call(rbind, strsplit(enr_df$Overlap, "/"))
  3307. enr_df$Count <- as.numeric(tmp[,1])
  3308. enr_df$GeneRatio <- as.numeric(tmp[,1]) / as.numeric(tmp[,2])
  3309. # Keep top 50 terms by FDR
  3310. enr_df <- enr_df[order(enr_df$FDR), ][1:min(50, nrow(enr_df)), ]
  3311. # Filter for keywords and FDR < 0.1
  3312. filtered_df <- enr_df[
  3313. grepl(paste(keywords, collapse = "|"), enr_df$Term, ignore.case = TRUE) & enr_df$Adjusted.P.value < 0.1,
  3314. ]
  3315. # Check if there are any results after filtering
  3316. if (nrow(filtered_df) == 0) {
  3317. message("Skipping ", dge, " in ", go_db, " (no terms found after filtering)")
  3318. next
  3319. }
  3320. enr_df <- filtered_df
  3321. # ---- Dotplot ----
  3322. p <- ggplot(enr_df, aes(
  3323. x = GeneRatio,
  3324. y = reorder(Term, -FDR), # most significant (lowest FDR) at top
  3325. size = Count,
  3326. color = -log10(FDR)
  3327. )) +
  3328. geom_point() +
  3329. scale_color_gradient(low = "blue", high = "red") +
  3330. scale_size_continuous(range = c(2, 5)) +
  3331. labs(
  3332. title = paste0(dge," in ", go_db),
  3333. x = "Gene ratio",
  3334. y = "GO term",
  3335. color = "-log10(FDR)",
  3336. size = "Gene count"
  3337. ) +
  3338. theme_bw() +
  3339. theme(
  3340. axis.text.x = element_text(size = 6),
  3341. axis.text.y = element_text(size = 8),
  3342. axis.title = element_text(size = 6),
  3343. plot.title = element_text(size = 10),
  3344. plot.margin = margin(10, 10, 10, 10)
  3345. )
  3346. print(p)
  3347. }
  3348. }
  3349. dev.off()
  3350. ```
  3351. ```{r}
  3352. library(GOplot)
  3353. pdf("enrichment_GOBubbleplot_IO_Calb1MgClus_filterGO_20250916.pdf", width=12, height=8)
  3354. for (dge in names(enrichedR.list)) {
  3355. for (go_db in dbs) {
  3356. enr_df <- enrichedR.list[[dge]][[go_db]]
  3357. if (is.null(enr_df) || nrow(enr_df) == 0) {
  3358. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  3359. next
  3360. }
  3361. # Prepare enrichment data
  3362. tmp <- do.call(rbind, strsplit(enr_df$Overlap, "/"))
  3363. Count <- as.numeric(tmp[,1])
  3364. ID <- grepl(" ", enr_df$Term, value = 1 )
  3365. GO_data <- data.frame(
  3366. category = go_db,
  3367. ID = paste0("GO:", seq_len(nrow(enr_df))), # fake GO IDs
  3368. term = enr_df$Term,
  3369. genes = enr_df$Genes, # enrichR column listing genes
  3370. adj_pval = enr_df$Adjusted.P.value,
  3371. zscore = NA,
  3372. Count = Count
  3373. )
  3374. # Split the genes into a vector, trim spaces
  3375. all_genes <- unique(trimws(unlist(strsplit(enr_df$Genes, ";"))))
  3376. # Dummy DEG table with matching names
  3377. DEG_data <- data.frame(ID = all_genes, logFC = 1)
  3378. # Merge for GOplot
  3379. circ <- circle_dat(GO_data, DEG_data)
  3380. # Plot GO bubble
  3381. p <- GOBubble(circ, display = "single", title = paste0(dge, " in ", go_db))
  3382. print(p)
  3383. }
  3384. }
  3385. dev.off()
  3386. ```
  3387. # 9. DGE
  3388. ```{r}
  3389. condition <- "IO"
  3390. HVGs.list <- list()
  3391. res.list <- list()
  3392. HVGs.list[[condition]] <- list()
  3393. res.list[[condition]] <- list()
  3394. ```
  3395. ```{r}
  3396. DefaultAssay(seurat_obj_IO_calb1_micro) <- 'RNA'
  3397. table(seurat_obj_IO_calb1_micro$orig.ident_merge)
  3398. ```
  3399. ```{r}
  3400. seurat_obj_sce_calb1_micro <- as.SingleCellExperiment(seurat_obj_IO_calb1_micro, assay="RNA")
  3401. seurat_obj_sce_calb1_micro <- prepSCE(seurat_obj_sce_calb1_micro, kid = "InfOlive", gid = "orig.ident_merge", sid = "orig.ident", drop = FALSE)
  3402. kids <- purrr::set_names(levels(seurat_obj_sce_calb1_micro$cluster_id))
  3403. # Total number of clusters
  3404. nk <- length(kids)
  3405. # Named vector of sample names
  3406. sids <- purrr::set_names(levels(seurat_obj_sce_calb1_micro$sample_id))
  3407. # Total number of samples
  3408. ns <- length(sids)
  3409. kids
  3410. sids
  3411. ```
  3412. ```{r}
  3413. ## Determine the number of cells per sample
  3414. table(seurat_obj_sce_calb1_micro$sample_id)
  3415. ## Turn named vector into a numeric vector of number of cells per sample
  3416. n_cells <- as.numeric(table(seurat_obj_sce_calb1_micro$sample_id))
  3417. ## Determine how to reoder the samples (rows) of the metadata to match the order of sample names in sids vector
  3418. m <- match(sids, seurat_obj_sce_calb1_micro$sample_id)
  3419. ## Create the sample level metadata by combining the reordered metadata with the number of cells corresponding to each sample.
  3420. ei <- data.frame(colData(seurat_obj_sce_calb1_micro)[m, ], n_cells, row.names = NULL) %>% dplyr::select(-"cluster_id")
  3421. ei
  3422. ```
  3423. ```{r}
  3424. # Aggregate the counts per sample_id and cluster_id
  3425. # Subset metadata to only include the cluster and sample IDs to aggregate across
  3426. groups <- colData(seurat_obj_sce_calb1_micro)[, c("cluster_id", "sample_id")]
  3427. # Aggregate across cluster-sample groups
  3428. pb <- aggregate.Matrix(t(counts(seurat_obj_sce_calb1_micro)), groupings = groups, fun = "sum")
  3429. splitf <- sapply(stringr::str_split(rownames(pb), pattern = "_", n = 2), `[`, 1)
  3430. pb <- split.data.frame(pb, factor(splitf)) %>% lapply(function(u) magrittr::set_colnames(t(u), stringr::str_extract(rownames(u), "(?<=_)[:alnum:]+")))
  3431. class(pb)
  3432. # Explore the different components of list
  3433. str(pb)
  3434. ```
  3435. ```{r}
  3436. options(width = 100)
  3437. table(seurat_obj_sce_calb1_micro$cluster_id, seurat_obj_sce_calb1_micro$group_id)
  3438. ```
  3439. ```{r}
  3440. options(width = 100)
  3441. table(seurat_obj_sce_calb1_micro$cluster_id, seurat_obj_sce_calb1_micro$seurat_clusters)
  3442. ```
  3443. ```{r}
  3444. # prep. data.frame for plotting
  3445. get_sample_ids <- function(x){pb[[x]] %>% colnames()}
  3446. de_samples <- purrr::map(1:length(kids), get_sample_ids) %>% unlist()
  3447. samples_list <- purrr::map(1:length(kids), get_sample_ids)
  3448. get_cluster_ids <- function(x){rep(names(pb)[x],each = length(samples_list[[x]]))}
  3449. de_cluster_ids <- purrr::map(1:length(kids), get_cluster_ids) %>% unlist()
  3450. gg_df <- data.frame(cluster_id = de_cluster_ids, sample_id = de_samples)
  3451. gg_df <- left_join(gg_df, ei[, c("sample_id", "group_id")])
  3452. metadata <- gg_df %>% dplyr::select(cluster_id, sample_id, group_id)
  3453. levels(metadata$cluster_id) <- unique(metadata$cluster_id)
  3454. # Generate vector of cluster IDs
  3455. clusters <- levels(metadata$cluster_id)
  3456. clusters
  3457. cluster_choice <- "core"
  3458. table_sample_low <- table(seurat_obj_sce_calb1_micro$cluster_id, seurat_obj_sce_calb1_micro$sample_id)[cluster_choice,][table(seurat_obj_sce_calb1_micro$cluster_id, seurat_obj_sce_calb1_micro$sample_id)[cluster_choice,] <= 5]
  3459. table_sample_low
  3460. sample_keep <- names(orig.ident_colors)[!names(orig.ident_colors) %in% names(table_sample_low)]
  3461. table_group_low <-table(seurat_obj_sce_calb1_micro$cluster_id, seurat_obj_sce_calb1_micro$group_id)[cluster_choice,][table(seurat_obj_sce_calb1_micro$cluster_id, seurat_obj_sce_calb1_micro$group_id)[cluster_choice,] <= 30]
  3462. table_group_low
  3463. group_keep <- names(orig.ident_merge_colors)[!names(orig.ident_merge_colors) %in% names(table_group_low)]
  3464. cluster_metadata <- metadata[which(metadata$cluster_id == cluster_choice), ]
  3465. # Assign the rownames of the metadata to be the sample IDs
  3466. rownames(cluster_metadata) <- cluster_metadata$sample_id
  3467. #Remove sample and timepoint with low counts (sample<=5, timepoint<=30)
  3468. cluster_metadata <- cluster_metadata[(cluster_metadata$sample_id %in% sample_keep & cluster_metadata$group_id %in% group_keep),]
  3469. new_group_levels <- levels(cluster_metadata$group_id)[levels(cluster_metadata$group_id) %in% group_keep]
  3470. cluster_metadata$group_id <- droplevels(cluster_metadata$group_id)
  3471. levels(cluster_metadata$group_id) <- new_group_levels
  3472. # Subset the counts to only this cluster
  3473. counts <- pb[[cluster_choice]]
  3474. cluster_counts <- data.frame(counts[, which(colnames(counts) %in% rownames(cluster_metadata))])
  3475. # Check that all of the row names of the metadata are the same and in the same order as the column names of the counts in order to use as input to DESeq2
  3476. all(rownames(cluster_metadata) == colnames(cluster_counts))
  3477. ```
  3478. ```{r}
  3479. dds <- DESeqDataSetFromMatrix(cluster_counts, colData = cluster_metadata, design = ~ group_id)
  3480. ```
  3481. ```{r}
  3482. # Transform counts for data visualization
  3483. rld <- rlog(dds, blind=TRUE)
  3484. ```
  3485. ```{r}
  3486. # Plot PCA
  3487. options(repr.plot.width=8, repr.plot.height=5)
  3488. DESeq2::plotPCA(rld, intgroup = "group_id")
  3489. ```
  3490. ```{r}
  3491. # Extract the rlog matrix from the object and compute pairwise correlation values
  3492. rld_mat <- assay(rld)
  3493. rld_cor <- cor(rld_mat)
  3494. ```
  3495. ```{r}
  3496. # Plot heatmap
  3497. options(repr.plot.width=10, repr.plot.height=8)
  3498. pheatmap(rld_cor, annotation = cluster_metadata[, "group_id", drop=F], annotation_colors = list(group_id=orig.ident_merge_colors))
  3499. ```
  3500. ```{r}
  3501. dds <- DESeq(dds)
  3502. ```
  3503. ```{r}
  3504. libsize = data.frame(x=sizeFactors(dds), y=colSums(assay(dds)))
  3505. options(repr.plot.width=7, repr.plot.height=7)
  3506. ggplot(data=libsize, aes(x=x, y=y)) + geom_point() + geom_smooth(method="lm") + xlab("Estimated size factor") + ylab("Library size")
  3507. ```
  3508. ```{r}
  3509. data.frame(colData(dds))
  3510. ```
  3511. ```{r}
  3512. # Plot dispersion estimates
  3513. options(repr.plot.width=12, repr.plot.height=12)
  3514. plotDispEsts(dds)
  3515. ```
  3516. ```{r}
  3517. HVGs.list[[condition]][["upregulated"]] <- list()
  3518. HVGs.list[[condition]][["downregulated"]] <- list()
  3519. ```
  3520. ## 9.1 Contrasts
  3521. ```{r}
  3522. condition1 = "D7"
  3523. condition2 = "Ctrl"
  3524. contrast <- c("group_id", condition1, condition2)
  3525. # resultsNames(dds)
  3526. res <- results(dds, contrast = contrast, alpha = 0.05)
  3527. summary(res)
  3528. options(repr.plot.width=10, repr.plot.height=7)
  3529. hist(res$pvalue, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of p-values", xlab="p-value")
  3530. ```
  3531. ```{r}
  3532. options(repr.plot.width=10, repr.plot.height=7)
  3533. hist(res$padj, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of adj p-values", xlab="adj p-value")
  3534. ```
  3535. ```{r}
  3536. options(repr.plot.width=10, repr.plot.height=7)
  3537. qs <- c(0, quantile(res$baseMean[res$baseMean > 0], 0:7/7))
  3538. # cut the genes into the bins
  3539. bins <- cut(res$baseMean, qs)
  3540. # rename the levels of the bins using the middle point
  3541. levels(bins) <- paste0("~",round(.5*qs[-1] + .5*qs[-length(qs)]))
  3542. # calculate the ratio of $p$ values less than .01 for each bin
  3543. ratios <- tapply(res$pvalue, bins, function(p) mean(p < .01, na.rm=TRUE))
  3544. # plot these ratios
  3545. barplot(ratios, xlab="mean normalized count", ylab="ratio of small p values")
  3546. ```
  3547. ```{r}
  3548. options(repr.plot.width=15, repr.plot.height=15)
  3549. #padj<0.001
  3550. p1<-EnhancedVolcano(res,
  3551. lab = rownames(res),
  3552. x = 'log2FoldChange',
  3553. y = 'padj',
  3554. title = paste0(condition1,' vs ',condition2,' in FC > 1'),
  3555. pCutoff = 0.01,
  3556. FCcutoff = 1,
  3557. pointSize = 3.0,
  3558. labSize = 6.0,
  3559. col=c('black', 'grey', 'grey', 'blue'),
  3560. colAlpha = 1
  3561. )
  3562. print(p1)
  3563. p1_1<-EnhancedVolcano(res,
  3564. lab = rownames(res),
  3565. x = 'log2FoldChange',
  3566. y = 'padj',
  3567. title = paste0(condition1,' vs ',condition2,' in FC > 0.75'),
  3568. pCutoff = 0.01,
  3569. FCcutoff = 0.75,
  3570. pointSize = 3.0,
  3571. labSize = 6.0,
  3572. col=c('black', 'grey', 'grey', 'blue'),
  3573. colAlpha = 1
  3574. )
  3575. print(p1_1)
  3576. ```
  3577. ```{r}
  3578. res.list[[condition]][[paste0(condition1,"_",condition2)]] <- res
  3579. ```
  3580. ```{r}
  3581. write.csv(res, paste0("DGE_",condition,"_calb1_mg_",condition1,"_",condition2,"_20250915.csv"), row.names=TRUE)
  3582. ```
  3583. ```{r}
  3584. res <- res[complete.cases(res$padj),]
  3585. res_filtered <- res[(res$padj < 0.05 & res$baseMean > 1),]
  3586. HVGs.list[[condition]][["upregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange>=0,])
  3587. HVGs.list[[condition]][["downregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange<0,])
  3588. ```
  3589. ## D14 vs Ctrl
  3590. ```{r}
  3591. condition1 = "D14"
  3592. condition2 = "Ctrl"
  3593. ```
  3594. ```{r}
  3595. contrast <- c("group_id", condition1, condition2)
  3596. # resultsNames(dds)
  3597. res <- results(dds, contrast = contrast, alpha = 0.05)
  3598. ```
  3599. ```{r}
  3600. summary(res)
  3601. ```
  3602. ```{r}
  3603. options(repr.plot.width=10, repr.plot.height=7)
  3604. hist(res$pvalue, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of p-values", xlab="p-value")
  3605. ```
  3606. ```{r}
  3607. options(repr.plot.width=10, repr.plot.height=7)
  3608. hist(res$padj, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of adj p-values", xlab="adj p-value")
  3609. ```
  3610. ```{r}
  3611. options(repr.plot.width=10, repr.plot.height=7)
  3612. qs <- c(0, quantile(res$baseMean[res$baseMean > 0], 0:7/7))
  3613. # cut the genes into the bins
  3614. bins <- cut(res$baseMean, qs)
  3615. # rename the levels of the bins using the middle point
  3616. levels(bins) <- paste0("~",round(.5*qs[-1] + .5*qs[-length(qs)]))
  3617. # calculate the ratio of $p$ values less than .01 for each bin
  3618. ratios <- tapply(res$pvalue, bins, function(p) mean(p < .01, na.rm=TRUE))
  3619. # plot these ratios
  3620. barplot(ratios, xlab="mean normalized count", ylab="ratio of small p values")
  3621. ```
  3622. ```{r}
  3623. options(repr.plot.width=15, repr.plot.height=15)
  3624. #padj<0.001
  3625. p2 <- EnhancedVolcano(res,
  3626. lab = rownames(res),
  3627. x = 'log2FoldChange',
  3628. y = 'padj',
  3629. title = paste0(condition1,' vs ',condition2,' in FC > 1'),
  3630. pCutoff = 0.01,
  3631. FCcutoff = 1,
  3632. pointSize = 3.0,
  3633. labSize = 6.0,
  3634. col=c('black', 'grey', 'grey', 'blue'),
  3635. colAlpha = 1)
  3636. print(p2)
  3637. p2_1 <- EnhancedVolcano(res,
  3638. lab = rownames(res),
  3639. x = 'log2FoldChange',
  3640. y = 'padj',
  3641. title = paste0(condition1,' vs ',condition2,' in FC > 0.75'),
  3642. pCutoff = 0.01,
  3643. FCcutoff = 0.75,
  3644. pointSize = 3.0,
  3645. labSize = 6.0,
  3646. col=c('black', 'grey', 'grey', 'blue'),
  3647. colAlpha = 1)
  3648. print(p2_1)
  3649. ```
  3650. ```{r}
  3651. res.list[[condition]][[paste0(condition1,"_",condition2)]] <- res
  3652. ```
  3653. ```{r}
  3654. write.csv(res, paste0("DGE_",condition,"_calb1_mg_",condition1,"_",condition2,"_20250915.csv"), row.names=TRUE)
  3655. ```
  3656. ```{r}
  3657. res <- res[complete.cases(res$padj),]
  3658. res_filtered <- res[(res$padj < 0.05 & res$baseMean > 1),]
  3659. HVGs.list[[condition]][["upregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange>=0,])
  3660. HVGs.list[[condition]][["downregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange<0,])
  3661. ```
  3662. ## D14 vs D7
  3663. ```{r}
  3664. condition1 = "D14"
  3665. condition2 = "D7"
  3666. ```
  3667. ```{r}
  3668. contrast <- c("group_id", condition1, condition2)
  3669. # resultsNames(dds)
  3670. res <- results(dds, contrast = contrast, alpha = 0.05)
  3671. ```
  3672. ```{r}
  3673. summary(res)
  3674. ```
  3675. ```{r}
  3676. options(repr.plot.width=10, repr.plot.height=7)
  3677. hist(res$pvalue, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of p-values", xlab="p-value")
  3678. ```
  3679. ```{r}
  3680. options(repr.plot.width=10, repr.plot.height=7)
  3681. hist(res$padj, breaks=0:20/20, col="grey50", border="white", xlim=c(0,1), main="Histogram of adj p-values", xlab="adj p-value")
  3682. ```
  3683. ```{r}
  3684. options(repr.plot.width=10, repr.plot.height=7)
  3685. qs <- c(0, quantile(res$baseMean[res$baseMean > 0], 0:7/7))
  3686. # cut the genes into the bins
  3687. bins <- cut(res$baseMean, qs)
  3688. # rename the levels of the bins using the middle point
  3689. levels(bins) <- paste0("~",round(.5*qs[-1] + .5*qs[-length(qs)]))
  3690. # calculate the ratio of $p$ values less than .01 for each bin
  3691. ratios <- tapply(res$pvalue, bins, function(p) mean(p < .01, na.rm=TRUE))
  3692. # plot these ratios
  3693. barplot(ratios, xlab="mean normalized count", ylab="ratio of small p values")
  3694. ```
  3695. ```{r}
  3696. options(repr.plot.width=15, repr.plot.height=15)
  3697. #padj<0.001
  3698. p3 <- EnhancedVolcano(res,
  3699. lab = rownames(res),
  3700. x = 'log2FoldChange',
  3701. y = 'padj',
  3702. title = paste0(condition1,' vs ',condition2,' in FC > 1'),
  3703. pCutoff = 0.01,
  3704. FCcutoff = 1,
  3705. pointSize = 3.0,
  3706. labSize = 6.0,
  3707. col=c('black', 'grey', 'grey', 'blue'),
  3708. colAlpha = 1)
  3709. print(p3)
  3710. p3_1 <- EnhancedVolcano(res,
  3711. lab = rownames(res),
  3712. x = 'log2FoldChange',
  3713. y = 'padj',
  3714. title = paste0(condition1,' vs ',condition2,' in FC > 0.5'),
  3715. pCutoff = 0.01,
  3716. FCcutoff = 0.5,
  3717. pointSize = 3.0,
  3718. labSize = 6.0,
  3719. col=c('black', 'grey', 'grey', 'blue'),
  3720. colAlpha = 1)
  3721. print(p3_1)
  3722. # Define the genes you want to highlight
  3723. genes_to_highlight <- c("Hexa", "Hexb", "Apoe", "Clu", "B2m", "Megf10", "Dock1")
  3724. p3_1 <- EnhancedVolcano(
  3725. res,
  3726. lab = rownames(res),
  3727. x = 'log2FoldChange',
  3728. y = 'padj',
  3729. title = paste0(condition1,' vs ',condition2,' in FC > 0.5'),
  3730. pCutoff = 0.05,
  3731. FCcutoff = 0.5,
  3732. pointSize = 3.0,
  3733. labSize = 6.0,
  3734. col = c('black', 'grey', 'grey', 'blue'),
  3735. colAlpha = 1,
  3736. # Force-highlight these genes
  3737. selectLab = genes_to_highlight,
  3738. drawConnectors = TRUE
  3739. )
  3740. print(p3_1)
  3741. ```
  3742. ```{r}
  3743. res.list[[condition]][[paste0(condition1,"_",condition2)]] <- res
  3744. ```
  3745. ```{r}
  3746. write.csv(res, paste0("DGE_",condition,"_calb1_mg_",condition1,"_",condition2,"_20250915.csv"), row.names=TRUE)
  3747. ```
  3748. ```{r}
  3749. res <- res[complete.cases(res$padj),]
  3750. res_filtered <- res[(res$padj < 0.05 & res$baseMean > 1),]
  3751. HVGs.list[[condition]][["upregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange>=0,])
  3752. HVGs.list[[condition]][["downregulated"]][[paste0(condition1,"_",condition2)]] <- rownames(res_filtered[res_filtered$log2FoldChange<0,])
  3753. ```
  3754. ```{r}
  3755. # export the svg file
  3756. svglite::svglite(file = "volcano_plot_D7vsCtrl_FC_1.svg", width = 15, height = 15)
  3757. print(p1)
  3758. dev.off()
  3759. svglite::svglite(file = "volcano_plot_D7vsCtrl_FC_075.svg", width = 15, height = 15)
  3760. print(p1_1)
  3761. dev.off()
  3762. svglite::svglite(file = "volcano_plot_D14vsCtrl_FC_1.svg", width = 15, height = 15)
  3763. print(p2)
  3764. dev.off()
  3765. svglite::svglite(file = "volcano_plot_D14vsCtrl_FC_075.svg", width = 15, height = 15)
  3766. print(p2_1)
  3767. dev.off()
  3768. svglite::svglite(file = "volcano_plot_D14vsD7_FC_1.svg", width = 15, height = 15)
  3769. print(p3)
  3770. dev.off()
  3771. svglite::svglite(file = "volcano_plot_D14vsD7_FC_05_small.svg", width = 7, height = 7)
  3772. print(p3_1)
  3773. dev.off()
  3774. ```
  3775. ## GO on the res
  3776. ```{r}
  3777. # load the different DEG list
  3778. res_D7_Ctrl <- read.csv(paste0("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/", "DGE_IO_calb1_mg_","D7","_","Ctrl","_20250915.csv"), row.names = 1)
  3779. res_D14_Ctrl <- read.csv(paste0("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/", "DGE_IO_calb1_mg_","D14","_","Ctrl","_20250915.csv"), row.names = 1)
  3780. res_D14_D7 <- read.csv(paste0("~/rds/rds-rds-karadottir-qqstKNzWvy8/Omar_Spatial/", "DGE_IO_calb1_mg_","D14","_","D7","_20250915.csv"), row.names = 1)
  3781. # clean up the na
  3782. res_D7_Ctrl <- res_D7_Ctrl[!is.na(res_D7_Ctrl$padj),]
  3783. res_D14_Ctrl <- res_D14_Ctrl[!is.na(res_D14_Ctrl$padj),]
  3784. res_D14_D7 <- res_D14_D7[!is.na(res_D14_D7$padj),]
  3785. # Filter the res for giving different lists
  3786. res_D7_Ctrl_FC05_up <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange > 0.5),])
  3787. res_D7_Ctrl_FC05_down <- rownames(res_D7_Ctrl[(res_D7_Ctrl$padj < 0.05) & (res_D7_Ctrl$log2FoldChange < -0.5),])
  3788. res_D14_Ctrl_FC05_up <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange > 0.5),])
  3789. res_D14_Ctrl_FC05_down <- rownames(res_D14_Ctrl[(res_D14_Ctrl$padj < 0.05) & (res_D14_Ctrl$log2FoldChange < -0.5),])
  3790. res_D14_D7_FC05_up <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange > 0.5),])
  3791. res_D14_D7_FC05_down <- rownames(res_D14_D7[(res_D14_D7$padj < 0.05) & (res_D14_D7$log2FoldChange < -0.5),])
  3792. ```
  3793. ```{r}
  3794. dbs <- c("GO_Molecular_Function_2023","GO_Cellular_Component_2023","GO_Biological_Process_2023","KEGG_2019_Mouse")
  3795. ```
  3796. ```{r}
  3797. enrichedR.list <- list()
  3798. enrichedR.list[["IO_D7_Ctrl_FC05_up"]] <- enrichr(res_D7_Ctrl_FC05_up, dbs)
  3799. enrichedR.list[["IO_D7_Ctrl_FC05_down"]] <- enrichr(res_D7_Ctrl_FC05_down, dbs)
  3800. enrichedR.list[["IO_D14_Ctrl_FC05_up"]] <- enrichr(res_D14_Ctrl_FC05_up, dbs)
  3801. enrichedR.list[["IO_D14_Ctrl_FC05_down"]] <- enrichr(res_D14_Ctrl_FC05_down, dbs)
  3802. enrichedR.list[["IO_D14_D7_FC05_up"]] <- enrichr(res_D14_D7_FC05_up, dbs)
  3803. enrichedR.list[["IO_D14_D7_FC05_down"]] <- enrichr(res_D14_D7_FC05_down, dbs)
  3804. ```
  3805. ```{r}
  3806. # Create an empty list to store the data frames for export
  3807. export_list <- list()
  3808. # Loop through your enrichedR.list and extract a specific database for each cluster
  3809. for (cluster_name in names(enrichedR.list)) {
  3810. # For example, extract the "GO_Biological_Process_2023" results
  3811. export_list[[cluster_name]] <- enrichedR.list[[cluster_name]]$GO_Biological_Process_2023
  3812. }
  3813. openxlsx::write.xlsx(export_list, file = "enrichment_IO_calb1_microglia_DayComparison_GO_KEGG_20250915.xlsx")
  3814. ```
  3815. ```{r}
  3816. pdf("enrichment_plot_IO_calb1_mg_DayComparison_20250915.pdf", width=12, height=8)
  3817. for (dge in names(enrichedR.list)) {
  3818. for (go_db in dbs) {
  3819. enr_df <- enrichedR.list[[dge]][[go_db]]
  3820. if (is.null(enr_df) || nrow(enr_df) == 0) {
  3821. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  3822. next
  3823. }
  3824. p <- plotEnrich(
  3825. enr_df,
  3826. showTerms = 50,
  3827. numChar = 100,
  3828. y = "Count",
  3829. orderBy = "FDR",
  3830. title = paste0(dge," in ", go_db),
  3831. xlab = ""
  3832. )
  3833. print(
  3834. p + theme(
  3835. axis.text.x = element_text(size = 6),
  3836. axis.text.y = element_text(size = 8),
  3837. axis.title = element_text(size = 6),
  3838. plot.title = element_text(size = 10),
  3839. plot.margin = margin(10, 10, 10, 10)
  3840. )
  3841. )
  3842. }
  3843. }
  3844. dev.off()
  3845. ```
  3846. ```{r}
  3847. pdf("enrichment_plot_IO_calb1_mg_DayComparison_filtered_20250915.pdf", width=8, height=3)
  3848. # Define your list of keywords
  3849. keywords <- c("Positive Regulation Of Endocytosis", "Positive Regulation Of Peptidase Activity", "Phagocytosis, Engulfment", "Protein Processing", "Positive Regulation Of Receptor−Mediated Endocytosis")
  3850. for (dge in names(enrichedR.list)) {
  3851. for (go_db in dbs) {
  3852. enr_df <- enrichedR.list[[dge]][[go_db]]
  3853. if (is.null(enr_df) || nrow(enr_df) == 0) {
  3854. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  3855. next
  3856. }
  3857. # Filter for keywords and FDR < 0.1
  3858. filtered_df <- enr_df[
  3859. grepl(paste(keywords, collapse = "|"), enr_df$Term, ignore.case = TRUE) & enr_df$Adjusted.P.value < 0.1,
  3860. ]
  3861. # Check if there are any results after filtering
  3862. if (nrow(filtered_df) == 0) {
  3863. message("Skipping ", dge, " in ", go_db, " (no terms found after filtering)")
  3864. next
  3865. }
  3866. # Use the filtered data for plotting
  3867. p <- plotEnrich(
  3868. filtered_df,
  3869. showTerms = 20,
  3870. numChar = 100,
  3871. y = "Count",
  3872. orderBy = "FDR",
  3873. title = paste0(dge, " in ", go_db, " (Filtered)"),
  3874. xlab = ""
  3875. )
  3876. print(
  3877. p + theme(
  3878. axis.text.x = element_text(size = 6),
  3879. axis.text.y = element_text(size = 8),
  3880. axis.title = element_text(size = 6),
  3881. plot.title = element_text(size = 10),
  3882. plot.margin = margin(10, 10, 10, 10)
  3883. )
  3884. )
  3885. }
  3886. }
  3887. dev.off()
  3888. ```
  3889. # Comparison on Clusters
  3890. ```{r}
  3891. library(Matrix)
  3892. library(dplyr)
  3893. # Grab metadata
  3894. meta <- colData(seurat_obj_sce_calb1_micro)[, c("sample_id", "seurat_clusters")]
  3895. # counts = genes × cells
  3896. cts <- counts(seurat_obj_sce_calb1_micro)
  3897. # build group labels: sample_cluster
  3898. groups <- paste(meta$sample_id, meta$seurat_clusters, sep = "_")
  3899. # aggregate counts across all cells belonging to each (sample, cluster) pair
  3900. pb <- aggregate.Matrix(t(cts), groupings = groups, fun = "sum")
  3901. pb <- t(pb) # back to genes × pseudobulks
  3902. dim(pb)
  3903. head(colnames(pb))
  3904. ```
  3905. ```{r}
  3906. # split sample_id and cluster from colnames
  3907. colinfo <- do.call(rbind, strsplit(colnames(pb), "_"))
  3908. coldata <- data.frame(
  3909. sample_id = colinfo[,1],
  3910. cluster = colinfo[,2],
  3911. row.names = colnames(pb)
  3912. )
  3913. head(coldata)
  3914. ```
  3915. ```{r}
  3916. dds <- DESeqDataSetFromMatrix(
  3917. countData = as.matrix(pb),
  3918. colData = coldata,
  3919. design = ~ sample_id + cluster
  3920. )
  3921. # filter low counts
  3922. dds <- dds[rowSums(counts(dds)) > 10, ]
  3923. # run DESeq2
  3924. dds <- DESeq(dds)
  3925. # results: cluster3 vs cluster0
  3926. res <- results(dds, contrast = c("cluster", "3", "0"))
  3927. res <- res[order(res$padj), ]
  3928. head(res)
  3929. ```
  3930. ```{r}
  3931. deg <- as.data.frame(res)
  3932. write.csv(deg, "DEG_calb1_mg_cluster3_vs_cluster0_pseudobulk_20250916.csv")
  3933. ```
  3934. ```{r}
  3935. # Volcano plot
  3936. library(EnhancedVolcano)
  3937. p1 <- EnhancedVolcano(
  3938. deg,
  3939. lab = rownames(deg),
  3940. x = 'log2FoldChange',
  3941. y = 'pvalue',
  3942. title = "Cluster 3 vs Cluster 0",
  3943. pCutoff = 0.01,
  3944. FCcutoff = 1,
  3945. pointSize = 3.0,
  3946. labSize = 6.0,
  3947. col=c('black', 'grey', 'grey', 'blue'),
  3948. colAlpha = 1
  3949. )
  3950. print(p1)
  3951. ```
  3952. ```{r}
  3953. # load & filter
  3954. res_3_vs_0 <- read.csv("DEG_calb1_mg_cluster3_vs_cluster0_pseudobulk_20250916.csv", row.names = 1)
  3955. res_3_vs_0 <- res_3_vs_0[!is.na(res_3_vs_0$padj),]
  3956. # extract up/down
  3957. res_3_vs_0_FC1_up <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange > 1),])
  3958. res_3_vs_0_FC1_down <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange < -1),])
  3959. # FC > 0.75 (up and down)
  3960. res_3_vs_0_FC075_up <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange > 0.75),])
  3961. res_3_vs_0_FC075_down <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange < -0.75),])
  3962. ```
  3963. ```{r}
  3964. dbs <- c("GO_Molecular_Function_2023",
  3965. "GO_Cellular_Component_2023",
  3966. "GO_Biological_Process_2023",
  3967. "KEGG_2019_Mouse")
  3968. enrichedR.list <- list()
  3969. enrichedR.list[["Cluster3_vs_0_FC1_up"]] <- enrichr(res_3_vs_0_FC1_up, dbs)
  3970. enrichedR.list[["Cluster3_vs_0_FC1_down"]] <- enrichr(res_3_vs_0_FC1_down, dbs)
  3971. enrichedR.list[["Cluster3_vs_0_FC075_up"]] <- enrichr(res_3_vs_0_FC075_up, dbs)
  3972. enrichedR.list[["Cluster3_vs_0_FC075_down"]] <- enrichr(res_3_vs_0_FC075_down, dbs)
  3973. ```
  3974. ```{r}
  3975. pdf("enrichment_plot_calb1_mg_cluster3_vs_0_20250916.pdf", width=12, height=8)
  3976. for (dge in names(enrichedR.list)) {
  3977. for (go_db in dbs) {
  3978. enr_df <- enrichedR.list[[dge]][[go_db]]
  3979. if (is.null(enr_df) || nrow(enr_df) == 0) {
  3980. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  3981. next
  3982. }
  3983. p <- plotEnrich(
  3984. enr_df,
  3985. showTerms = 50,
  3986. numChar = 100,
  3987. y = "Count",
  3988. orderBy = "FDR",
  3989. title = paste0(dge," in ", go_db),
  3990. xlab = ""
  3991. )
  3992. print(
  3993. p + theme(
  3994. axis.text.x = element_text(size = 6),
  3995. axis.text.y = element_text(size = 8),
  3996. axis.title = element_text(size = 6),
  3997. plot.title = element_text(size = 10),
  3998. plot.margin = margin(10, 10, 10, 10)
  3999. )
  4000. )
  4001. }
  4002. }
  4003. dev.off()
  4004. ```
  4005. ```{r}
  4006. pdf("enrichment_dotplot_calb1_mg_cluster3_vs_0_20250916.pdf", width=12, height=8)
  4007. for (dge in names(enrichedR.list)) {
  4008. for (go_db in dbs) {
  4009. enr_df <- enrichedR.list[[dge]][[go_db]]
  4010. if (is.null(enr_df) || nrow(enr_df) == 0) {
  4011. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  4012. next
  4013. }
  4014. # ---- Prepare data ----
  4015. # Adjusted P value column in enrichR is usually "Adjusted.P.value"
  4016. if (!("Adjusted.P.value" %in% colnames(enr_df))) {
  4017. stop("No Adjusted.P.value column found in enrichment results for ", dge, " / ", go_db)
  4018. }
  4019. # Significance (FDR)
  4020. enr_df$FDR <- as.numeric(enr_df$Adjusted.P.value)
  4021. # Overlap is in "k/n" format -> extract numerator and denominator
  4022. tmp <- do.call(rbind, strsplit(enr_df$Overlap, "/"))
  4023. enr_df$Count <- as.numeric(tmp[,1])
  4024. enr_df$GeneRatio <- as.numeric(tmp[,1]) / as.numeric(tmp[,2])
  4025. # Keep top 50 terms by FDR
  4026. enr_df <- enr_df[order(enr_df$FDR), ][1:min(50, nrow(enr_df)), ]
  4027. # ---- Dotplot ----
  4028. p <- ggplot(enr_df, aes(
  4029. x = GeneRatio,
  4030. y = reorder(Term, -FDR), # most significant (lowest FDR) at top
  4031. size = Count,
  4032. color = -log10(FDR)
  4033. )) +
  4034. geom_point() +
  4035. scale_color_gradient(low = "blue", high = "red") +
  4036. labs(
  4037. title = paste0(dge," in ", go_db),
  4038. x = "Gene ratio",
  4039. y = "GO term",
  4040. color = "-log10(FDR)",
  4041. size = "Gene count"
  4042. ) +
  4043. theme_bw() +
  4044. theme(
  4045. axis.text.x = element_text(size = 6),
  4046. axis.text.y = element_text(size = 8),
  4047. axis.title = element_text(size = 6),
  4048. plot.title = element_text(size = 10),
  4049. plot.margin = margin(10, 10, 10, 10)
  4050. )
  4051. print(p)
  4052. }
  4053. }
  4054. dev.off()
  4055. ```
  4056. ## Cluster 2 compared to cluster 0
  4057. ```{r}
  4058. # results: cluster2 vs cluster0
  4059. res <- results(dds, contrast = c("cluster", "2", "0"))
  4060. res <- res[order(res$padj), ]
  4061. head(res)
  4062. ```
  4063. ```{r}
  4064. deg <- as.data.frame(res)
  4065. write.csv(deg, "DEG_calb1_mg_cluster2_vs_cluster0_pseudobulk.csv")
  4066. ```
  4067. ```{r}
  4068. # Volcano plot
  4069. library(EnhancedVolcano)
  4070. p1 <- EnhancedVolcano(
  4071. deg,
  4072. lab = rownames(deg),
  4073. x = 'log2FoldChange',
  4074. y = 'pvalue',
  4075. title = "Cluster 2 vs Cluster 0",
  4076. pCutoff = 0.05,
  4077. FCcutoff = 1,
  4078. pointSize = 3.0,
  4079. labSize = 6.0,
  4080. col=c('black', 'grey', 'grey', 'blue'),
  4081. colAlpha = 1
  4082. )
  4083. print(p1)
  4084. ```
  4085. ```{r}
  4086. # load & filter
  4087. res_2_vs_0 <- read.csv("DEG_calb1_mg_cluster2_vs_cluster0_pseudobulk.csv", row.names = 1)
  4088. res_2_vs_0 <- res_2_vs_0[!is.na(res_2_vs_0$padj),]
  4089. # extract up/down
  4090. res_2_vs_0_FC1_up <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange > 1),])
  4091. res_2_vs_0_FC1_down <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange < -1),])
  4092. # FC > 0.75 (up and down)
  4093. res_2_vs_0_FC075_up <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange > 0.75),])
  4094. res_2_vs_0_FC075_down <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange < -0.75),])
  4095. # FC > 0.75 (up and down)
  4096. res_2_vs_0_FC05_up <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange > 0.5),])
  4097. res_2_vs_0_FC05_down <- rownames(res_2_vs_0[(res_2_vs_0$padj < 0.05) & (res_2_vs_0$log2FoldChange < -0.5),])
  4098. ```
  4099. ```{r}
  4100. dbs <- c("GO_Molecular_Function_2023",
  4101. "GO_Cellular_Component_2023",
  4102. "GO_Biological_Process_2023",
  4103. "KEGG_2019_Mouse")
  4104. enrichedR.list <- list()
  4105. enrichedR.list[["Cluster2_vs_0_FC1_up"]] <- enrichr(res_2_vs_0_FC1_up, dbs)
  4106. enrichedR.list[["Cluster2_vs_0_FC1_down"]] <- enrichr(res_2_vs_0_FC1_down, dbs)
  4107. enrichedR.list[["Cluster2_vs_0_FC075_up"]] <- enrichr(res_2_vs_0_FC075_up, dbs)
  4108. enrichedR.list[["Cluster2_vs_0_FC075_down"]] <- enrichr(res_2_vs_0_FC075_down, dbs)
  4109. enrichedR.list[["Cluster2_vs_0_FC05_up"]] <- enrichr(res_2_vs_0_FC05_up, dbs)
  4110. enrichedR.list[["Cluster2_vs_0_FC05_down"]] <- enrichr(res_2_vs_0_FC05_down, dbs)
  4111. ```
  4112. ```{r}
  4113. pdf("enrichment_plot_mg_cluster2_vs_0.pdf", width=12, height=8)
  4114. for (dge in names(enrichedR.list)) {
  4115. for (go_db in dbs) {
  4116. enr_df <- enrichedR.list[[dge]][[go_db]]
  4117. if (is.null(enr_df) || nrow(enr_df) == 0) {
  4118. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  4119. next
  4120. }
  4121. p <- plotEnrich(
  4122. enr_df,
  4123. showTerms = 50,
  4124. numChar = 100,
  4125. y = "Count",
  4126. orderBy = "FDR",
  4127. title = paste0(dge," in ", go_db),
  4128. xlab = ""
  4129. )
  4130. print(
  4131. p + theme(
  4132. axis.text.x = element_text(size = 6),
  4133. axis.text.y = element_text(size = 8),
  4134. axis.title = element_text(size = 6),
  4135. plot.title = element_text(size = 10),
  4136. plot.margin = margin(10, 10, 10, 10)
  4137. )
  4138. )
  4139. }
  4140. }
  4141. dev.off()
  4142. ```
  4143. ## Cluster 1 compared to cluster 0
  4144. ```{r}
  4145. # results: cluster1 vs cluster0
  4146. res <- results(dds, contrast = c("cluster", "1", "0"))
  4147. res <- res[order(res$padj), ]
  4148. head(res)
  4149. ```
  4150. ```{r}
  4151. deg <- as.data.frame(res)
  4152. write.csv(deg, "DEG_mg_cluster1_vs_cluster0_pseudobulk.csv")
  4153. ```
  4154. ```{r}
  4155. # Volcano plot
  4156. library(EnhancedVolcano)
  4157. p1 <- EnhancedVolcano(
  4158. deg,
  4159. lab = rownames(deg),
  4160. x = 'log2FoldChange',
  4161. y = 'pvalue',
  4162. title = "Cluster 1 vs Cluster 0",
  4163. pCutoff = 0.01,
  4164. FCcutoff = 1,
  4165. pointSize = 3.0,
  4166. labSize = 6.0,
  4167. col=c('black', 'grey', 'grey', 'blue'),
  4168. colAlpha = 1
  4169. )
  4170. print(p1)
  4171. ```
  4172. ```{r}
  4173. # load & filter
  4174. res_1_vs_0 <- read.csv("DEG_mg_cluster1_vs_cluster0_pseudobulk.csv", row.names = 1)
  4175. res_1_vs_0 <- res_1_vs_0[!is.na(res_1_vs_0$padj),]
  4176. # extract up/down
  4177. res_1_vs_0_FC1_up <- rownames(res_1_vs_0[(res_1_vs_0$padj < 0.05) & (res_1_vs_0$log2FoldChange > 1),])
  4178. res_1_vs_0_FC1_down <- rownames(res_1_vs_0[(res_1_vs_0$padj < 0.05) & (res_1_vs_0$log2FoldChange < -1),])
  4179. # FC > 0.75 (up and down)
  4180. res_1_vs_0_FC075_up <- rownames(res_1_vs_0[(res_1_vs_0$padj < 0.05) & (res_1_vs_0$log2FoldChange > 0.75),])
  4181. res_1_vs_0_FC075_down <- rownames(res_1_vs_0[(res_1_vs_0$padj < 0.05) & (res_1_vs_0$log2FoldChange < -0.75),])
  4182. ```
  4183. ```{r}
  4184. dbs <- c("GO_Molecular_Function_2023",
  4185. "GO_Cellular_Component_2023",
  4186. "GO_Biological_Process_2023",
  4187. "KEGG_2019_Mouse")
  4188. enrichedR.list <- list()
  4189. enrichedR.list[["Cluster1_vs_0_FC1_up"]] <- enrichr(res_1_vs_0_FC1_up, dbs)
  4190. enrichedR.list[["Cluster1_vs_0_FC1_down"]] <- enrichr(res_1_vs_0_FC1_down, dbs)
  4191. enrichedR.list[["Cluster1_vs_0_FC075_up"]] <- enrichr(res_1_vs_0_FC075_up, dbs)
  4192. enrichedR.list[["Cluster1_vs_0_FC075_down"]] <- enrichr(res_1_vs_0_FC075_down, dbs)
  4193. ```
  4194. ```{r}
  4195. pdf("enrichment_plot_mg_cluster1_vs_0.pdf", width=12, height=8)
  4196. for (dge in names(enrichedR.list)) {
  4197. for (go_db in dbs) {
  4198. enr_df <- enrichedR.list[[dge]][[go_db]]
  4199. if (is.null(enr_df) || nrow(enr_df) == 0) {
  4200. message("Skipping ", dge, " in ", go_db, " (no enrichment results)")
  4201. next
  4202. }
  4203. p <- plotEnrich(
  4204. enr_df,
  4205. showTerms = 50,
  4206. numChar = 100,
  4207. y = "Count",
  4208. orderBy = "FDR",
  4209. title = paste0(dge," in ", go_db),
  4210. xlab = ""
  4211. )
  4212. print(
  4213. p + theme(
  4214. axis.text.x = element_text(size = 6),
  4215. axis.text.y = element_text(size = 8),
  4216. axis.title = element_text(size = 6),
  4217. plot.title = element_text(size = 10),
  4218. plot.margin = margin(10, 10, 10, 10)
  4219. )
  4220. )
  4221. }
  4222. }
  4223. dev.off()
  4224. ```
  4225. ```{r}
  4226. # Save DEGs
  4227. deg <- as.data.frame(res)
  4228. write.csv(deg, "DEG_mg_cluster3_vs_cluster0.csv")
  4229. # Volcano plot
  4230. library(EnhancedVolcano)
  4231. p1 <- EnhancedVolcano(
  4232. deg,
  4233. lab = rownames(deg),
  4234. x = 'log2FoldChange',
  4235. y = 'pvalue',
  4236. title = "Cluster 3 vs Cluster 0",
  4237. pCutoff = 0.01,
  4238. FCcutoff = 1,
  4239. pointSize = 3.0,
  4240. labSize = 6.0,
  4241. col=c('black', 'grey', 'grey', 'blue'),
  4242. colAlpha = 1
  4243. )
  4244. print(p1)
  4245. ```
  4246. ```{r}
  4247. # Use the gene list for the GO
  4248. # load the 3 vs 0 DE results
  4249. res_3_vs_0 <- read.csv("DEG_mg_cluster3_vs_cluster0.csv", row.names = 1)
  4250. # clean up NA
  4251. res_3_vs_0 <- res_3_vs_0[!is.na(res_3_vs_0$padj),]
  4252. # FC > 1 (up and down)
  4253. res_3_vs_0_FC1_up <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange > 1),])
  4254. res_3_vs_0_FC1_down <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange < -1),])
  4255. # FC > 0.75 (up and down)
  4256. res_3_vs_0_FC075_up <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange > 0.75),])
  4257. res_3_vs_0_FC075_down <- rownames(res_3_vs_0[(res_3_vs_0$padj < 0.05) & (res_3_vs_0$log2FoldChange < -0.75),])
  4258. ```
  4259. ---------------------------------------------------------------
  4260. # plotting
  4261. ## plotting all microglia pixels
  4262. ```{r}
  4263. micro_Balazs_markers = c("Aif1", "Maf", "Spi1", "Csf1r")
  4264. seurat_obj_IO <- AddModuleScore(
  4265. seurat_obj_IO,
  4266. features=list(micro_Balazs_markers),
  4267. nbin = 24,
  4268. ctrl = 100,
  4269. assay = "RNA_repaired",
  4270. slot = "data",
  4271. name = "AMS",
  4272. )
  4273. colnames([email hidden]) <- c(colnames([email hidden])[1:(length(colnames([email hidden]))-1)], "micro_Balazs_markers")
  4274. options(repr.plot.width=6, repr.plot.height=5)
  4275. FeaturePlot(seurat_obj_IO, reduction = "umap", features = "micro_Balazs_markers", order=TRUE, pt.size=1, raster=FALSE, min.cutoff=0)
  4276. seurat_obj_IO_micro <- subset(seurat_obj_IO, subset= micro_Balazs_markers > -0.03)
  4277. ```
  4278. ```{r}
  4279. DefaultAssay(seurat_obj_IO_micro) <- "RNA"
  4280. seurat_obj_IO_micro <- NormalizeData(seurat_obj_IO_micro, normalization.method = "LogNormalize", scale.factor = 10000)
  4281. DefaultAssay(seurat_obj_IO_micro) <- "RNA_repaired"
  4282. seurat_obj_IO_micro <- NormalizeData(seurat_obj_IO_micro, normalization.method = "LogNormalize", scale.factor = 10000)
  4283. seurat_obj_IO_micro <- FindVariableFeatures(seurat_obj_IO_micro, selection.method = "vst", nfeatures = 1000)
  4284. seurat_obj_IO_micro <- ScaleData(seurat_obj_IO_micro, features = rownames(seurat_obj_IO_micro))
  4285. seurat_obj_IO_micro <- RunPCA(seurat_obj_IO_micro)
  4286. options(repr.plot.width=10, repr.plot.height=7)
  4287. ElbowPlot(seurat_obj_IO_micro, reduction = "pca", ndims = 50)
  4288. ```
  4289. ```{r}
  4290. nb_pcs = 20
  4291. seurat_obj_IO_micro <- FindNeighbors(seurat_obj_IO_micro, reduction = "pca", dims = 1:nb_pcs, prune.SNN = 0)
  4292. cluster_res = 0.8
  4293. seurat_obj_IO_micro <- FindClusters(seurat_obj_IO_micro, resolution = cluster_res)
  4294. table(seurat_obj_IO_micro$seurat_clusters)
  4295. ```
  4296. ```{r}
  4297. seurat_obj_IO_calb1_color <- list()
  4298. n_clusters <- 6
  4299. seurat_obj_IO_calb1_color <- color_palette_30[1:n_clusters]
  4300. names(seurat_obj_IO_calb1_color) <- seq(1:n_clusters)-1
  4301. seurat_obj_IO_micro <- RunUMAP(seurat_obj_IO_micro, reduction = "pca", dims = 1:nb_pcs)
  4302. ```
  4303. ```{r}
  4304. options(repr.plot.width=25, repr.plot.height=8)
  4305. DimPlot(seurat_obj_IO_micro, group.by="orig.ident", split.by="orig.ident_merge", cols=orig.ident_colors, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  4306. options(repr.plot.width=11, repr.plot.height=9)
  4307. for(timepoint in names(orig.ident_merge_colors)){
  4308. highlight_cells <- rownames([email hidden][[email hidden]$orig.ident_merge==timepoint,])
  4309. print(DimPlot(seurat_obj_IO_micro, cells.highlight = highlight_cells, pt.size=0.5, cols.highlight = orig.ident_merge_colors[timepoint], raster=FALSE))
  4310. }
  4311. ```
  4312. ```{r}
  4313. options(repr.plot.width=11, repr.plot.height=9)
  4314. DimPlot(seurat_obj_IO_micro, group.by="seurat_clusters", cols=seurat_obj_IO_calb1_color, shuffle=TRUE, seed=seed, pt.size=1, label=FALSE, raster=FALSE)
  4315. ```
  4316. ```{r}
  4317. options(repr.plot.width=25, repr.plot.height=8)
  4318. DimPlot(seurat_obj_IO_calb1, group.by="seurat_clusters", split.by="orig.ident_merge", cols=seurat_obj_IO_calb1_color, shuffle=TRUE, seed=seed, ncol=4, pt.size=1, label=FALSE, raster=FALSE)
  4319. ```
  4320. ```{r}
  4321. options(repr.plot.width=15, repr.plot.height=15)
  4322. set.seed(115)
  4323. mat = as.matrix(table(seurat_obj_IO_micro$orig.ident_merge, seurat_obj_IO_micro$seurat_clusters))
  4324. for (row in 1:nrow(mat)) mat[row,] <- as.integer(mat[row,]/(sum(mat[row,])/min(rowSums(mat))))
  4325. circos.clear()
  4326. par(cex = 0.8)
  4327. chordDiagram(mat, annotationTrack = c("grid", "axis"), preAllocateTracks = list(track.height = max(strwidth(unlist(dimnames(mat))))/3), big.gap = 20, small.gap = 2, order = c(colnames(mat), names(orig.ident_merge_colors)), grid.col=c(rev(seurat_obj_IO_calb1_color), rev(orig.ident_merge_colors)))
  4328. circos.track(track.index = 1, panel.fun = function(x, y) {circos.text(CELL_META$xcenter, CELL_META$ylim[1], CELL_META$sector.index, facing = "clockwise", niceFacing = TRUE, adj = c(-0.3, 0.5))}, bg.border = NA)
  4329. ```
  4330. ```{r}
  4331. df_table <- as.data.frame(table(seurat_obj_IO_micro$orig.ident, seurat_obj_IO_micro$seurat_clusters))
  4332. colnames(df_table) <- c("group", "cluster", "count")
  4333. t <- table(seurat_obj_IO_micro$orig.ident, seurat_obj_IO_micro$seurat_clusters)
  4334. t_prop <- t/as.vector(table(seurat_obj_IO$orig.ident))*100
  4335. rownames(t_prop) <- c("Ctrl","Ctrl","Ctrl","Ctrl","D7","D7","D7","D7","D14","D14","D14","D14")
  4336. df_table <- as.data.frame(t_prop)
  4337. colnames(df_table) <- c("group", "cluster", "count")
  4338. df_summary <- df_table %>%
  4339. group_by(group, cluster) %>%
  4340. summarise(
  4341. mean = mean(count),
  4342. se = sd(count) / sqrt(n()),
  4343. .groups = "drop"
  4344. )
  4345. ggplot(df_summary, aes(x = cluster, y = mean, fill = group)) +
  4346. # Bars
  4347. geom_bar(stat = "identity", position = position_dodge(width = 0.9), color = "black") +
  4348. # Error bars
  4349. geom_errorbar(aes(ymin = mean - se, ymax = mean + se),
  4350. position = position_dodge(width = 0.9),
  4351. width = 0.2) +
  4352. # Manual fill colors
  4353. scale_fill_manual(values = orig.ident_merge_colors) +
  4354. # Points dodged and jittered
  4355. geom_point(
  4356. data = df_table,
  4357. aes(x = cluster, y = count, fill = group), # <- fill included so dodge works
  4358. position = position_jitterdodge(jitter.width = 0.4, dodge.width = 0.9),
  4359. size = 2, shape = 21, stroke = 0.5,
  4360. color = "black", # border
  4361. show.legend = FALSE
  4362. ) +
  4363. theme_minimal() +
  4364. labs(x = "", y = "% of pixels in the IO") +
  4365. ggtitle("Number of calbindin neurons pixels divided by each IO for each sample") +
  4366. theme(panel.grid.major.x = element_blank(),
  4367. panel.grid.minor.x = element_blank())
  4368. t <- table(Cluster=seurat_obj_IO_micro$seurat_clusters, Batch=[email hidden][["orig.ident_merge"]])
  4369. t <- t[,rev(names(orig.ident_merge_colors))]
  4370. options(repr.plot.width=10, repr.plot.height=10)
  4371. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+100, 20, f = ceiling)), col = rev(orig.ident_merge_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  4372. t <- table(Cluster=seurat_obj_IO_micro$seurat_clusters, Batch=[email hidden][["orig.ident"]])
  4373. t <- t[,rev(names(orig.ident_colors))]
  4374. options(repr.plot.width=10, repr.plot.height=10)
  4375. barplot(t(t), xlab = "Cluster", ylab="Number of cells", legend = TRUE, ylim = c(0, round_any(as.integer(max(rowSums(t)))+150, 20, f = ceiling)), col = rev(orig.ident_colors), args.legend = list(bty = "n", x = "top", ncol = 3))
  4376. ```
  4377. ```{r}
  4378. DefaultAssay(seurat_obj_IO_micro) <- "RNA"
  4379. Idents(object = seurat_obj_IO_micro) <- "seurat_clusters"
  4380. seurat_obj_IO_micro.markers.seurat_clusters <- FindAllMarkers(seurat_obj_IO_micro, slot = "data", min.pct = 0.1, logfc.threshold = 0, only.pos = TRUE)
  4381. ```
  4382. ```{r}
  4383. write.csv(seurat_obj_IO_micro.markers.seurat_clusters,"IO_microglia_clustermarkers_20250916.csv",row.names = FALSE)
  4384. ```
  4385. ```{r}
  4386. seurat_obj_IO_micro.markers.seurat_clusters_pval <- seurat_obj_IO_micro.markers.seurat_clusters[seurat_obj_IO_micro.markers.seurat_clusters$p_val_adj < 0.05,]
  4387. seurat_obj_IO_micro.markers.seurat_clusters_best <- seurat_obj_IO_micro.markers.seurat_clusters_pval %>%
  4388. filter(avg_log2FC > 0.5) %>%
  4389. filter(pct.1 > 0.3) %>%
  4390. arrange(cluster, desc(avg_log2FC)) %>%
  4391. group_by(cluster)
  4392. markers_heatmap <- seurat_obj_IO_micro.markers.seurat_clusters_best %>% top_n(n = 10, wt = avg_log2FC)
  4393. topDiffCluster <- seurat_obj_IO_micro.markers.seurat_clusters_best %>% top_n(n = 50, wt = avg_log2FC)
  4394. sample_df <- as.data.frame(lapply(split(topDiffCluster, topDiffCluster$cluster), function(x) c(x$gene,rep("None", 50-length(x$gene)))))
  4395. colnames(sample_df) <- levels(topDiffCluster$cluster)
  4396. sample_df
  4397. ```
  4398. ```{r}
  4399. options(repr.plot.width=30, repr.plot.height=20)
  4400. DoMultiBarHeatmap(
  4401. subset(seurat_obj_IO_micro, downsample = 200),
  4402. features = unique(markers_heatmap$gene),
  4403. cells = NULL,
  4404. group.by = "seurat_clusters",
  4405. additional.group.by = c("orig.ident_merge"),
  4406. additional.group.sort.by = c("orig.ident_merge"),
  4407. cols.use = list(seurat_clusters=seurat_obj_IO_calb1_color, orig.ident_merge=orig.ident_merge_colors),
  4408. group.bar = TRUE,
  4409. disp.min = -2.5,
  4410. disp.max = NULL,
  4411. layer = "scale.data",
  4412. assay = "RNA_repaired",
  4413. label = TRUE,
  4414. size = 5.5,
  4415. hjust = 0,
  4416. angle = 45,
  4417. raster = TRUE,
  4418. draw.lines = TRUE,
  4419. lines.width = NULL,
  4420. group.bar.height = 0.02,
  4421. combine = TRUE
  4422. ) + theme(text = element_text(size = 8))
  4423. ```
  4424. ---------------------------------------------------------
  4425. ```{r}
  4426. # load the 5 csv files
  4427. MC1_Volcano_df <- read.csv("goncaloGeneLists/MC1_filtered_genes.csv")
  4428. MC3_Volcano_df <- read.csv("goncaloGeneLists/MC3_filtered_genes.csv")
  4429. MC1_NonDE_df <- read.csv("goncaloGeneLists/MC1_Non_DE.csv")
  4430. MC2_NonDE_df <- read.csv("goncaloGeneLists/MC2_Non_DE.csv")
  4431. MC3_NonDE_df <- read.csv("goncaloGeneLists/MC3_Non_DE.csv")
  4432. ```
  4433. ```{r}
  4434. # Filter to make them all into lists
  4435. FDRCutOff <- 0.1
  4436. MC1_Volcano_df_fil <- MC1_Volcano_df[MC1_Volcano_df$FDR.x < FDRCutOff , ]
  4437. MC1_Volcano_list <- MC1_Volcano_df_fil$gene
  4438. MC3_Volcano_df_fil <- MC3_Volcano_df[MC3_Volcano_df$FDR.x < FDRCutOff , ]
  4439. MC3_Volcano_list <- MC3_Volcano_df_fil$gene
  4440. MC1_NonDE_df_fil <- MC1_NonDE_df[MC1_NonDE_df$FDR < FDRCutOff , ]
  4441. MC1_NonDE_df_list <- MC1_NonDE_df_fil$name
  4442. MC2_NonDE_df_fil <- MC2_NonDE_df[MC2_NonDE_df$FDR < FDRCutOff , ]
  4443. MC2_NonDE_df_list <- MC2_NonDE_df_fil$name
  4444. MC3_NonDE_df_fil <- MC3_NonDE_df[MC3_NonDE_df$FDR < FDRCutOff , ]
  4445. MC3_NonDE_df_list <- MC3_NonDE_df_fil$name
  4446. ```
  4447. ### load the Keren Shaul DAM file
  4448. ```{r}
  4449. Keren_df <- read.csv("Keren-Shaul DAM list.csv")
  4450. Keren_up_list <- Keren_df$Keren_shaul_DAM_up
  4451. Keren_down_list <- Keren_df$Keren_shaul_DAM_down
  4452. Keren_down_list <- Keren_down_list[Keren_down_list!=""]
  4453. # create the neuroprotective list
  4454. NeuPro_list <- c("Igf1", "Bdnf", "Fgf13")
  4455. # Igf1
  4456. Igf1_list <- c("Igf1")
  4457. # create the additional neuroprotective list
  4458. NeuPro_Clus0_list <- c("Igf2", "Igfbp7", "Igf2r1", "Igf1r")
  4459. NeuPro_Clus2_list <- c("Bdnf", "Igf1", "Fbxw7", "Fgf13")
  4460. NeuPro_Clus02_list <- c(NeuPro_Clus0_list, NeuPro_Clus2_list)
  4461. ```
  4462. ```{r}
  4463. # calculate the gene score for the Keren up and down list
  4464. seurat_obj_IO_micro <- AddModuleScore(
  4465. object = seurat_obj_IO_micro,
  4466. features = list(Keren_up_list, Keren_down_list, NeuPro_list, MC1_Volcano_list, MC3_Volcano_list, NeuPro_Clus0_list, NeuPro_Clus2_list, NeuPro_Clus02_list),
  4467. name = c("KerenDAM", "KerenHomeo", "NeuPro", "MC1Score", "MC3Score", "NeuPro0Clus", "NeuPro2Clus", "NeuPro02Clus")
  4468. )
  4469. # Get normalized expression of Igf1 for all cells
  4470. seurat_obj_IO_micro$Igf1Ex4 <- FetchData(
  4471. seurat_obj_IO_micro,
  4472. vars = "Igf1"
  4473. )[,1]
  4474. ```
  4475. ```{r}
  4476. pdf("TissueMapping_IO_microglia_Loc_20250910.pdf", width = 5.3, height = 4.6)
  4477. # Make sure KerenDAM1 values exist in the full object
  4478. # Initialize with NA for all cells
  4479. seurat_obj_IO$Microglia <- NA
  4480. # Fill in values for microglia subset
  4481. seurat_obj_IO$Microglia[colnames(seurat_obj_IO_micro)] <- 1
  4482. # Now plot from the full seurat_obj_IO
  4483. for (sample_name in names(orig.ident_colors)) {
  4484. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4485. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4486. df_tmp <- data.frame(
  4487. x = annot_plot$x,
  4488. y = annot_plot$y,
  4489. value = annot_plot$Microglia
  4490. )
  4491. p <- ggplot(df_tmp, aes(x, y)) +
  4492. # Non-microglia (NA) cells plotted in lightgrey first
  4493. geom_point(data = subset(df_tmp, is.na(value)),
  4494. colour = "lightgrey", shape = 15, size = 1) +
  4495. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4496. geom_point(data = subset(df_tmp, !is.na(value)),
  4497. aes(colour = value), shape = 15, size = 1) +
  4498. scale_colour_gradientn(
  4499. colours = c("blue", "blue", "lightyellow", "red", "red"),
  4500. values = c(0, 0.25, 0.5, 0.75, 1),
  4501. limits = c(-0.1, 0.2),
  4502. na.value = "lightgrey",
  4503. oob = scales::squish
  4504. ) +
  4505. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4506. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4507. theme_void() +
  4508. ggtitle(sample_name)
  4509. print(p)
  4510. }
  4511. dev.off()
  4512. ```
  4513. ```{r}
  4514. pdf("TissueMapping_IO_microglia_Loc_type2_20250910.pdf", width = 5.3, height = 4.6)
  4515. # Make sure KerenDAM1 values exist in the full object
  4516. # Initialize with NA for all cells
  4517. seurat_obj_IO$Microglia <- NA
  4518. # Fill in values for microglia subset
  4519. seurat_obj_IO$Microglia[colnames(seurat_obj_IO_mg_trial)] <- 1
  4520. # Now plot from the full seurat_obj_IO
  4521. for (sample_name in names(orig.ident_colors)) {
  4522. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4523. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4524. df_tmp <- data.frame(
  4525. x = annot_plot$x,
  4526. y = annot_plot$y,
  4527. value = annot_plot$Microglia
  4528. )
  4529. p <- ggplot(df_tmp, aes(x, y)) +
  4530. # Non-microglia (NA) cells plotted in lightgrey first
  4531. geom_point(data = subset(df_tmp, is.na(value)),
  4532. colour = "lightgrey", shape = 15, size = 1) +
  4533. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4534. geom_point(data = subset(df_tmp, !is.na(value)),
  4535. aes(colour = value), shape = 15, size = 1) +
  4536. scale_colour_gradientn(
  4537. colours = c("blue", "blue", "lightyellow", "red", "red"),
  4538. values = c(0, 0.25, 0.5, 0.75, 1),
  4539. limits = c(-0.1, 0.2),
  4540. na.value = "lightgrey",
  4541. oob = scales::squish
  4542. ) +
  4543. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4544. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4545. theme_void() +
  4546. ggtitle(sample_name)
  4547. print(p)
  4548. }
  4549. dev.off()
  4550. ```
  4551. ```{r}
  4552. pdf("TissueMapping_IO_microglia_KerenDAM_20250910.pdf", width = 5.3, height = 4.6)
  4553. # Initialize with NA for all cells
  4554. seurat_obj_IO$KerenDAM1 <- NA
  4555. # Fill in values for microglia subset
  4556. seurat_obj_IO$KerenDAM1[colnames(seurat_obj_IO_micro)] <- seurat_obj_IO_micro$KerenDAM1
  4557. # Now plot from the full seurat_obj_IO
  4558. for (sample_name in names(orig.ident_colors)) {
  4559. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4560. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4561. df_tmp <- data.frame(
  4562. x = annot_plot$x,
  4563. y = annot_plot$y,
  4564. value = annot_plot$KerenDAM1
  4565. )
  4566. p <- ggplot(df_tmp, aes(x, y)) +
  4567. # Non-microglia (NA) cells plotted in lightgrey first
  4568. geom_point(data = subset(df_tmp, is.na(value)),
  4569. colour = "lightgrey", shape = 15, size = 1) +
  4570. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4571. geom_point(data = subset(df_tmp, !is.na(value)),
  4572. aes(colour = value), shape = 15, size = 1) +
  4573. scale_colour_gradientn(
  4574. colours = c("blue", "blue", "lightyellow", "red", "red"),
  4575. values = c(0, 0.25, 0.5, 0.75, 1),
  4576. limits = c(-0.1, 0.25),
  4577. na.value = "lightgrey",
  4578. oob = scales::squish
  4579. ) +
  4580. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4581. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4582. theme_void() +
  4583. ggtitle(sample_name)
  4584. print(p)
  4585. }
  4586. dev.off()
  4587. ```
  4588. ```{r}
  4589. # pdf("TissueMapping_IO_microglia_KerenHomeo_20250910.pdf", width = 5.3, height = 4.6)
  4590. # Initialize with NA for all cells
  4591. seurat_obj_IO$KerenHomeo2 <- NA
  4592. # Fill in values for microglia subset
  4593. seurat_obj_IO$KerenHomeo2[colnames(seurat_obj_IO_micro)] <- seurat_obj_IO_micro$KerenHomeo2
  4594. # Now plot from the full seurat_obj_IO
  4595. for (sample_name in names(orig.ident_colors)) {
  4596. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4597. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4598. df_tmp <- data.frame(
  4599. x = annot_plot$x,
  4600. y = annot_plot$y,
  4601. value = annot_plot$KerenHomeo2
  4602. )
  4603. p <- ggplot(df_tmp, aes(x, y)) +
  4604. # Non-microglia (NA) cells plotted in lightgrey first
  4605. geom_point(data = subset(df_tmp, is.na(value)),
  4606. colour = "lightgrey", shape = 15, size = 1) +
  4607. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4608. geom_point(data = subset(df_tmp, !is.na(value)),
  4609. aes(colour = value), shape = 15, size = 1) +
  4610. scale_colour_gradientn(
  4611. colours = c("darkgreen", "yellow", "red"),
  4612. values = c(0,0.5, 1),
  4613. limits = c(-0.2, 0.3),
  4614. na.value = "lightgrey",
  4615. oob = scales::squish
  4616. ) +
  4617. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4618. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4619. theme_void() +
  4620. ggtitle(sample_name)
  4621. print(p)
  4622. }
  4623. # dev.off()
  4624. ```
  4625. ```{r}
  4626. pdf("TissueMapping_IO_microglia_NeuProtective_20250910.pdf", width = 5.3, height = 4.6)
  4627. # Initialize with NA for all cells
  4628. seurat_obj_IO$NeuPro3 <- NA
  4629. # Fill in values for microglia subset
  4630. seurat_obj_IO$NeuPro3[colnames(seurat_obj_IO_micro)] <- seurat_obj_IO_micro$NeuPro3
  4631. # Now plot from the full seurat_obj_IO
  4632. for (sample_name in names(orig.ident_colors)) {
  4633. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4634. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4635. df_tmp <- data.frame(
  4636. x = annot_plot$x,
  4637. y = annot_plot$y,
  4638. value = annot_plot$NeuPro3
  4639. )
  4640. p <- ggplot(df_tmp, aes(x, y)) +
  4641. # Non-microglia (NA) cells plotted in lightgrey first
  4642. geom_point(data = subset(df_tmp, is.na(value)),
  4643. colour = "lightgrey", shape = 15, size = 1) +
  4644. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4645. geom_point(data = subset(df_tmp, !is.na(value)),
  4646. aes(colour = value), shape = 15, size = 1) +
  4647. scale_colour_gradientn(
  4648. colours = c("blue", "lightyellow", "red"),
  4649. values = c(0, 0.5, 1),
  4650. limits = c(-0.5, 0.5),
  4651. na.value = "lightgrey",
  4652. oob = scales::squish
  4653. ) +
  4654. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4655. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4656. theme_void() +
  4657. ggtitle(sample_name)
  4658. print(p)
  4659. }
  4660. dev.off()
  4661. ```
  4662. ```{r}
  4663. pdf("TissueMapping_IO_microglia_MC1_20250910.pdf", width = 5.3, height = 4.6)
  4664. # Initialize with NA for all cells
  4665. seurat_obj_IO$MC1Score4 <- NA
  4666. # Fill in values for microglia subset
  4667. seurat_obj_IO$MC1Score4[colnames(seurat_obj_IO_micro)] <- seurat_obj_IO_micro$MC1Score4
  4668. # Now plot from the full seurat_obj_IO
  4669. for (sample_name in names(orig.ident_colors)) {
  4670. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4671. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4672. df_tmp <- data.frame(
  4673. x = annot_plot$x,
  4674. y = annot_plot$y,
  4675. value = annot_plot$MC1Score4
  4676. )
  4677. p <- ggplot(df_tmp, aes(x, y)) +
  4678. # Non-microglia (NA) cells plotted in lightgrey first
  4679. geom_point(data = subset(df_tmp, is.na(value)),
  4680. colour = "lightgrey", shape = 15, size = 1) +
  4681. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4682. geom_point(data = subset(df_tmp, !is.na(value)),
  4683. aes(colour = value), shape = 15, size = 1) +
  4684. scale_colour_gradientn(
  4685. colours = c("blue", "yellow", "red"),
  4686. values = c(0, 0.5, 1),
  4687. limits = c(0, 0.8),
  4688. na.value = "lightgrey",
  4689. oob = scales::squish
  4690. ) +
  4691. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4692. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4693. theme_void() +
  4694. ggtitle(sample_name)
  4695. print(p)
  4696. }
  4697. dev.off()
  4698. ```
  4699. ```{r}
  4700. pdf("TissueMapping_IO_microglia_MC3_20250910.pdf", width = 5.3, height = 4.6)
  4701. # Initialize with NA for all cells
  4702. seurat_obj_IO$MC3Score5 <- NA
  4703. # Fill in values for microglia subset
  4704. seurat_obj_IO$MC3Score5[colnames(seurat_obj_IO_micro)] <- seurat_obj_IO_micro$MC3Score5
  4705. # Now plot from the full seurat_obj_IO
  4706. for (sample_name in names(orig.ident_colors)) {
  4707. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4708. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4709. df_tmp <- data.frame(
  4710. x = annot_plot$x,
  4711. y = annot_plot$y,
  4712. value = annot_plot$MC3Score5
  4713. )
  4714. p <- ggplot(df_tmp, aes(x, y)) +
  4715. # Non-microglia (NA) cells plotted in lightgrey first
  4716. geom_point(data = subset(df_tmp, is.na(value)),
  4717. colour = "lightgrey", shape = 15, size = 1) +
  4718. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4719. geom_point(data = subset(df_tmp, !is.na(value)),
  4720. aes(colour = value), shape = 15, size = 1) +
  4721. scale_colour_gradientn(
  4722. colours = c("blue", "yellow", "red"),
  4723. values = c(0, 0.5, 1),
  4724. limits = c(-0.05, 0.3),
  4725. na.value = "lightgrey",
  4726. oob = scales::squish
  4727. ) +
  4728. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4729. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4730. theme_void() +
  4731. ggtitle(sample_name)
  4732. print(p)
  4733. }
  4734. dev.off()
  4735. ```
  4736. ```{r}
  4737. pdf("TissueMapping_IO_microglia_Igf1Exp_20250910.pdf", width = 5.3, height = 4.6)
  4738. # Initialize with NA for all cells
  4739. seurat_obj_IO$Igf1Ex4 <- NA
  4740. # Fill in values for microglia subset
  4741. seurat_obj_IO$Igf1Ex4[colnames(seurat_obj_IO_micro)] <- seurat_obj_IO_micro$Igf1Ex4
  4742. # Now plot from the full seurat_obj_IO
  4743. for (sample_name in names(orig.ident_colors)) {
  4744. annot_plot <- [email hidden][seurat_obj_IO$orig.ident == sample_name, ]
  4745. options(repr.plot.width=5.3, repr.plot.height=4.6)
  4746. df_tmp <- data.frame(
  4747. x = annot_plot$x,
  4748. y = annot_plot$y,
  4749. value = annot_plot$Igf1Ex4
  4750. )
  4751. p <- ggplot(df_tmp, aes(x, y)) +
  4752. # Non-microglia (NA) cells plotted in lightgrey first
  4753. geom_point(data = subset(df_tmp, is.na(value)),
  4754. colour = "lightgrey", shape = 15, size = 1) +
  4755. # Microglia (with KerenDAM1 scores) plotted on top with gradient
  4756. geom_point(data = subset(df_tmp, !is.na(value)),
  4757. aes(colour = value), shape = 15, size = 1) +
  4758. scale_colour_gradientn(
  4759. colours = c("lightyellow","red", "purple", "purple"),
  4760. values = c(0, 0.5, 0.95, 1),
  4761. # limits = c(0, 2),
  4762. na.value = "lightgrey",
  4763. oob = scales::squish
  4764. ) +
  4765. scale_x_continuous(expand = c(-0.005, 0), lim = c(0, 101)) +
  4766. scale_y_continuous(expand = c(-0.006, 0), lim = c(0, 101)) +
  4767. theme_void() +
  4768. ggtitle(sample_name)
  4769. print(p)
  4770. }
  4771. # dev.off()
  4772. ```
  4773. ## cluster 0, popular in D14
  4774. ```{r}
  4775. pdf("TissueMapping_IO_microglia_NeuProtectiveClus0_20250910.pdf", width = 5.3, height = 4.6)
  4776. # Initialize with NA for all cells
  4777. seurat_obj_IO$NeuPro0Clus6 <- NA
  4778. # Fill in values for microglia subset
  4779. seurat_obj_IO$NeuPro0Clu

ST_Analysis_IO_20250929_final.Rmd at commit 75f7289, no license · at the source

Overview

Authors: Omar de Faria Jr1, Stavros Vagionitis1, Andrea Lopez-Lopez1,2, Michael Perry1,3, Joseph Jo Yin Wong1, Leslie Rodríguez-Kirby4, Bastien Hervé4, Balazs Viktor Varga1, Eneritz Agirre4, Sabrina Ghosh1, Sebastian Timmler1, Mert Yucel1, Andrew T. Setley5, Kimberley Anne Evans1, Tanja Mist Birgisdóttir6, Sindri Gíslason6, Yan Ting Ng1, Courtney Kremler1, Helene O. B. Gautier1, Yasmine Kamen1
and 10 other authorsHelena Pivonkova1, Katrin Volbracht1, Felix Hildebrand1, Christian A. Cepeda1, Javier Rueda-Carrasco7, Soyon Hong7, George Malliaras5, Sabine Dietmann8, Gonçalo Castelo-Branco4, Ragnhildur Thóra Káradóttir1,6
  1. Cambridge Centre for Myelin Repair, Cambridge Stem Cell Institute & Department of Veterinary Medicine, University of Cambridge,Cambridge, UK
  2. Research Center for Molecular Medicine and Chronic Diseases (CIMUS), University of Santiago de Compostela, CIBERNED, IDIS,Santiago de Compostela, Spain
  3. UCL Great Ormond Street Institute of Child Health, University College London,London, UK
  4. Laboratory of Molecular Neurobiology, Department of Medical Biochemistry and Biophysics, Karolinska Institutet,Stockholm, Sweden
  5. Electrical Engineering Division, University of Cambridge Department of Engineering,Cambridge, UK
  6. Department of Physiology, BioMedical Center, Faculty of Medicine, University of Iceland,Reykjavik, Iceland
  7. UK Dementia Research Institute, University College London,London, UK
  8. Institute for Informatics, Washington University School of Medicine,St Louis, MO USA
Journal: Nature, volume 654, issue 8120, pages 1033-1043
Dates: received 16 August 2024; accepted 13 March 2026; published online 22 April 2026; in print 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41586-026-10414-w · PMID 42020752 · PMCID PMC13293868 · OpenAlex W7155174467
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), mouse (organism), rat (organism), other condition (population), Alzheimer's / dementia (population), multiple sclerosis (population), cellular / molecular (subfield)
Methods: Connectivity, Spectral & time-frequency, Statistics, Smoothing, state filtering, decompositions, Preprocessing, Evoked potentials, Machine learning, fMRI & imaging, Single-unit activity, calcium imaging
Keywords: Multiple sclerosis, Alzheimer's disease, Neuroimmunology
MeSH: Gray Matter*, Inflammation*, Neuroinflammatory Diseases*, Synapses*, White Matter*, Animals, Female, Male, Mice, Microglia, Myelin Sheath, Neurodegenerative Diseases, Rats, Regeneration (* major topic)
Topic: Neuroinflammation and Neurodegeneration Mechanisms (Neurology, Neuroscience), according to OpenAlex
Funding: Multiple Sclerosis Society (207, 132); Wellcome Trust (218481/Z/19/Z, 320224/Z/24/Z)
Citations: cited by 2 papers (Europe PMC); 79 references in the paper

Abstract

Focal white matter lesions occur in most neurodegenerative disorders1–3. Despite occurring early in disease, white matter lesions are considered to be independent of, or secondary to, grey matter neuroinflammation, synapse loss and altered neuronal activity4–7. Notably, their functional effect on neuronal circuits remains understudied. To address this, we generated a focal white matter lesion in the rat brain within a clinically relevant, anatomically well-defined circuit, in which these lesions occur in many neurodegenerative disorders8–10. Here we show that focal white matter lesions evoke transient neuronal activity changes and microgliosis, with subsequent synapse loss and increased microglial engulfment in the grey matter, which is reversed if myelin regeneration completes. Grey matter microgliosis is often considered to be detrimental; however, we show that it is an integral part of regeneration and is conserved across three distinct mouse circuits and lesioning methods. Preventing these transient changes in the grey matter blocks myelin regeneration in the white matter. Conversely, inducing myelin regeneration failure leads to chronic grey matter neuroinflammation. This recapitulates the low-grade inflammation considered to be a dominant mechanism underlying neurodegeneration7,11,12. Our findings reveal a form of regenerative plasticity coupling white matter integrity to grey matter function, which may underlie multiple neurodegenerative conditions, and highlight the potential of targeting myelin regeneration to prevent chronic neuroinflammation.

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

Repository

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

Castelo-Branco-lab/Karadottir_DBiT_2025

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 75f72895e43d0bdfc73de65e3b25d1fe026e7404, 29 September 2025
Languages: R (5)
Size: 7 files, 5 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, 5 notebooks
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: tidyverse (5 files), Seurat (4 files), circlize (3 files), DESeq2 (3 files), ggplot2 (3 files), igraph (3 files), patchwork (3 files), pheatmap (3 files), reticulate (3 files), ComplexHeatmap (2 files), cowplot (2 files), data.table (1 file), Harmony (1 file), SingleCellExperiment (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
6 files

Code availability

The codes used for RNA-seq deconvolution and DBit-seq analysis are available at GitHub (https://github.com/Castelo-Branco-lab/Karadottir_DBiT_2025).

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

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

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

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

Data

Datasets cited

Data availability

All sequencing data have been deposited in NCBI’s Gene Expression Omnibus and are accessible through GEO series accession number GSE274050 (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE274050) (bulk RNA data) and series accession number GSE311781 (https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE311781) (DBiT-seq). The R. norvegicus reference genome used to align bulk RNA-seq and DBiT-seq reads (mRatBN7.2, RefSeq annotation, NCBI: GCF_015227675.2 (https://www.ncbi.nlm.nih.gov/datasets/genome/GCF_015227675.2)) is available online. The scRNA-seq dataset used to deconvolute the bulk RNA-seq experiment is available online (https://cells.ucsc.edu/?ds=mouse-nervous-system). Source data are provided with this paper.

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

Recorded: type, language, journal, volume, issue, pages, dates, 30 authors, 3 keywords, 14 MeSH terms, 2 funders, 77 references.

Cite

This paper

de Faria, O., Vagionitis, S., Lopez-Lopez, A., Perry, M., Wong, J. J. Y., Rodríguez-Kirby, L., Hervé, B., Varga, B. V., Agirre, E., Ghosh, S., Timmler, S., Yucel, M., Setley, A. T., Evans, K. A., Birgisdóttir, T. M., Gíslason, S., Ng, Y. T., Kremler, C., Gautier, H. O. B., . . . Káradóttir, R. T. (2026). Focal white matter lesions drive grey matter inflammation and synapse loss. Nature, 654(8120), 1033-1043. https://doi.org/10.1038/s41586-026-10414-w

BibTeX

@article{defaria2026focal,
author = {de Faria, Omar and Vagionitis, Stavros and Lopez-Lopez, Andrea and Perry, Michael and Wong, Joseph Jo Yin and Rodríguez-Kirby, Leslie and Hervé, Bastien and Varga, Balazs Viktor and Agirre, Eneritz and Ghosh, Sabrina and Timmler, Sebastian and Yucel, Mert and Setley, Andrew T. and Evans, Kimberley Anne and Birgisdóttir, Tanja Mist and Gíslason, Sindri and Ng, Yan Ting and Kremler, Courtney and Gautier, Helene O. B. and Kamen, Yasmine and Pivonkova, Helena and Volbracht, Katrin and Hildebrand, Felix and Cepeda, Christian A. and Rueda-Carrasco, Javier and Hong, Soyon and Malliaras, George and Dietmann, Sabine and Castelo-Branco, Gonçalo and Káradóttir, Ragnhildur Thóra},
title = {{Focal white matter lesions drive grey matter inflammation and synapse loss}},
journal = {Nature},
year = {2026},
month = apr,
volume = {654},
number = {8120},
pages = {1033--1043},
publisher = {Nature Portfolio},
issn = {0028-0836},
doi = {10.1038/s41586-026-10414-w},
url = {https://doi.org/10.1038/s41586-026-10414-w},
pmid = {42020752},
pmcid = {PMC13293868}
}

RIS

TY - JOUR
AU - de Faria, Omar
AU - Vagionitis, Stavros
AU - Lopez-Lopez, Andrea
AU - Perry, Michael
AU - Wong, Joseph Jo Yin
AU - Rodríguez-Kirby, Leslie
AU - Hervé, Bastien
AU - Varga, Balazs Viktor
AU - Agirre, Eneritz
AU - Ghosh, Sabrina
AU - Timmler, Sebastian
AU - Yucel, Mert
AU - Setley, Andrew T.
AU - Evans, Kimberley Anne
AU - Birgisdóttir, Tanja Mist
AU - Gíslason, Sindri
AU - Ng, Yan Ting
AU - Kremler, Courtney
AU - Gautier, Helene O. B.
AU - Kamen, Yasmine
AU - Pivonkova, Helena
AU - Volbracht, Katrin
AU - Hildebrand, Felix
AU - Cepeda, Christian A.
AU - Rueda-Carrasco, Javier
AU - Hong, Soyon
AU - Malliaras, George
AU - Dietmann, Sabine
AU - Castelo-Branco, Gonçalo
AU - Káradóttir, Ragnhildur Thóra
TI - Focal white matter lesions drive grey matter inflammation and synapse loss
T2 - Nature
J2 - Nature
PY - 2026
DA - 2026/04/22
VL - 654
IS - 8120
SP - 1033
EP - 1043
SN - 0028-0836
PB - Nature Portfolio
DO - 10.1038/s41586-026-10414-w
UR - https://doi.org/10.1038/s41586-026-10414-w
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41586-026-10414-w",
"type": "article-journal",
"title": "Focal white matter lesions drive grey matter inflammation and synapse loss",
"container-title": "Nature",
"author": [
{
"family": "de Faria",
"given": "Omar"
},
{
"family": "Vagionitis",
"given": "Stavros"
},
{
"family": "Lopez-Lopez",
"given": "Andrea"
},
{
"family": "Perry",
"given": "Michael"
},
{
"family": "Wong",
"given": "Joseph Jo Yin"
},
{
"family": "Rodríguez-Kirby",
"given": "Leslie"
},
{
"family": "Hervé",
"given": "Bastien"
},
{
"family": "Varga",
"given": "Balazs Viktor"
},
{
"family": "Agirre",
"given": "Eneritz"
},
{
"family": "Ghosh",
"given": "Sabrina"
},
{
"family": "Timmler",
"given": "Sebastian"
},
{
"family": "Yucel",
"given": "Mert"
},
{
"family": "Setley",
"given": "Andrew T."
},
{
"family": "Evans",
"given": "Kimberley Anne"
},
{
"family": "Birgisdóttir",
"given": "Tanja Mist"
},
{
"family": "Gíslason",
"given": "Sindri"
},
{
"family": "Ng",
"given": "Yan Ting"
},
{
"family": "Kremler",
"given": "Courtney"
},
{
"family": "Gautier",
"given": "Helene O. B."
},
{
"family": "Kamen",
"given": "Yasmine"
},
{
"family": "Pivonkova",
"given": "Helena"
},
{
"family": "Volbracht",
"given": "Katrin"
},
{
"family": "Hildebrand",
"given": "Felix"
},
{
"family": "Cepeda",
"given": "Christian A."
},
{
"family": "Rueda-Carrasco",
"given": "Javier"
},
{
"family": "Hong",
"given": "Soyon"
},
{
"family": "Malliaras",
"given": "George"
},
{
"family": "Dietmann",
"given": "Sabine"
},
{
"family": "Castelo-Branco",
"given": "Gonçalo"
},
{
"family": "Káradóttir",
"given": "Ragnhildur Thóra"
}
],
"container-title-short": "Nature",
"volume": "654",
"issue": "8120",
"page": "1033-1043",
"DOI": "10.1038/s41586-026-10414-w",
"PMID": "42020752",
"PMCID": "PMC13293868",
"ISSN": "0028-0836",
"publisher": "Nature Portfolio",
"URL": "https://doi.org/10.1038/s41586-026-10414-w",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
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/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: Harmony, SingleCellExperiment, reticulate, 11 other tools, Alzheimer's / dementia, cellular / molecular, 1 reference
[2] doi:10.1016/j.celrep.2026.117500 [code]
Spatio-molecular gene expression reflects dorsal anterior cingulate cortex structure and function in the human brain.
Journal: Cell reports
In common: Harmony, SingleCellExperiment, reticulate, 9 other tools, cellular / molecular, 3 references
[3] doi:10.1038/s41586-026-10214-2 [code]
Multidimensional profiling of heterogeneity in supratentorial ependymomas.
Journal: Nature
In common: Harmony, SingleCellExperiment, reticulate, 11 other tools, other condition, mouse
[4] doi:10.1002/imt2.70163 [code]
Spatial multi-omics unveils sphingolipid metabolic reprogramming within the retinal pathological niche.
Journal: iMeta
In common: Harmony, SingleCellExperiment, igraph, 10 other tools, mouse, cellular / molecular, 1 reference
[5] 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: Harmony, SingleCellExperiment, igraph, 10 other tools, other condition, cellular / molecular, 1 reference
[6] doi:10.1016/j.xcrm.2026.102651 [code]
Integrative CSF profiling identifies disease-specific immune responses in leptomeningeal disease.
Journal: Cell reports. Medicine
In common: Harmony, SingleCellExperiment, reticulate, 10 other tools, other condition, cellular / molecular
[7] doi:10.1038/s41593-026-02384-z [code]
cGAS-mediated type I IFN signaling contributes to disease progression in drug-refractory epilepsy.
Journal: Nature neuroscience
In common: SingleCellExperiment, igraph, circlize, 8 other tools, mouse, cellular / molecular, 3 references
[8] doi:10.1016/j.isci.2026.115573 [code]
Female cortical cellular mosaicism underlies shared MeCP2 and PCB impacted gene pathways.
Journal: iScience
In common: SingleCellExperiment, igraph, circlize, 9 other tools, mouse, cellular / molecular, 1 reference
[9] doi:10.1038/s41586-026-10629-x [code]
Whole-genome duplication shaped cell-type evolution in the vertebrate brain.
Journal: Nature
In common: Harmony, reticulate, igraph, 8 other tools, mouse, cellular / molecular, 2 references
[10] doi:10.1038/s41514-026-00397-3 [code]
Nasal administration of Protollin enhances monocyte phagocytosis and decreases CD8&lt;sup&gt;+&lt;/sup&gt; T cell cytotoxicity in subjects with early Alzheimer's disease: a Phase 1 clinical trial.
Journal: npj aging
In common: Harmony, reticulate, circlize, 8 other tools, Alzheimer's / dementia, 2 references

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.