OSCR

Single-nucleus brain transcriptomics reveals microglia dysfunction in multiple system atrophy.

Code ↔ Paper

26 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 26 matches
  1. [1] § Methods › Bioinformatic analysis › Integration and annotation ↔ Objects_preparations.Rmd, lines 309–338 · score 0.86 · alignment.strength, basicP2proc, buildGraph, embedGraph, findCommunities, largeVis
  2. [2] § Methods › Bioinformatic analysis › Integration and annotation ↔ Manuscript_figures.Rmd, lines 5665–5677 · score 0.77 · append.auc, append.specificity.metrics, getDifferentialGenes, z.threshold, upregulated
  3. [3] § Results › Minor compositional changes in neuronal subtypes across PD and MSA ↔ Manuscript_figures.Rmd, lines 4324–4350 · score 0.75 · NR2F2, CALB2, DCC, ID2, NKX2, PAX6
  4. [4] § Results › Minor compositional changes in neuronal subtypes across PD and MSA ↔ Manuscript_figures.Rmd, lines 4166–4190 · score 0.75 · NR2F2, CALB2, DCC, ID2, NKX2, PAX6
  5. [5] § Results › Subdued microglial responses in MSA, in contrast to increased numbers of activated microglia in PD ↔ Manuscript_figures.Rmd, lines 5468–5525 · score 0.71 · MIC_steady, MIC_intermediate1, MIC_activated, MIC_intermediate2, steady state, bar
  6. [6] § Results › Subdued microglial responses in MSA, in contrast to increased numbers of activated microglia in PD ↔ Manuscript_figures.Rmd, lines 5192–5249 · score 0.71 · MIC_steady, MIC_intermediate1, MIC_activated, MIC_intermediate2, steady state, bar
  7. [7] § Methods › Bioinformatic analysis › Covariate analysis ↔ Manuscript_figures.Rmd, lines 3907–3941 · score 0.70 · donor_min_cells, form_tensor, vargenes_thresh, var_scale_power, metadata
  8. [8] § Methods › Bioinformatic analysis › Pathway enrichment ↔ Manuscript_figures.Rmd, lines 5992–6031 · score 0.70 · enrichKEGG, soluble fraction, clusterProfiler, CSF, gene
  9. [9] § Methods › Bioinformatic analysis › Pathway enrichment ↔ Manuscript_figures.Rmd, lines 5702–5741 · score 0.70 · enrichKEGG, soluble fraction, clusterProfiler, CSF, gene
  10. [10] § Methods › Bioinformatic analysis › Cluster-free compositional changes ↔ Manuscript_figures.Rmd, lines 886–902 · score 0.68 · estimateCellDensity, Cell densities, subtract, graph
  11. [11] § Results › Reduced phagocytic activity in microglia exposed to cerebrospinal fluid from MSA patients ↔ Manuscript_figures.Rmd, lines 2359–2452 · score 0.66 · KEGG phagosome, lysosome pathways, PPI, orchid, steelblue, tomato
  12. [12] § Results › Reduced phagocytic activity in microglia exposed to cerebrospinal fluid from MSA patients ↔ Manuscript_figures.Rmd, lines 2328–2421 · score 0.66 · KEGG phagosome, lysosome pathways, PPI, orchid, steelblue, tomato
  13. [13] § Results › Reduced phagocytic activity in microglia exposed to cerebrospinal fluid from MSA patients ↔ Manuscript_figures.Rmd, lines 2172–2198 · score 0.66 · CTRL CSF, PD CSF, MSA CSF, pHrodo, phagocytic, coli
  14. [14] § Results › Reduced phagocytic activity in microglia exposed to cerebrospinal fluid from MSA patients ↔ Manuscript_figures.Rmd, lines 2160–2186 · score 0.66 · CTRL CSF, PD CSF, MSA CSF, pHrodo, phagocytic, coli
  15. [15] § Methods › Bioinformatic analysis › Protein-protein interactions ↔ Manuscript_figures.Rmd, lines 2359–2452 · score 0.63 · STRINGdb, soluble fraction, ggraph, interactions, Protein, PD
  16. [16] § Methods › Bioinformatic analysis › Protein-protein interactions ↔ Manuscript_figures.Rmd, lines 2328–2421 · score 0.63 · STRINGdb, soluble fraction, ggraph, interactions, Protein, PD
  17. [17] § Methods › Bioinformatic analysis › Regulon activity ↔ Scenic.ipynb, lines 116–142 · score 0.59 · mask dropouts, pyscenic grn, ctx, grnboost2, motif, Regulons
  18. [18] § Methods › Bioinformatic analysis › Regulon activity ↔ Scenic.ipynb, lines 116–142 · score 0.59 · mask dropouts, pyscenic grn, ctx, grnboost2, motif, Regulons
  19. [19] § Methods › Bioinformatic analysis › Genetic risk factor vulnerability ↔ scDRS_PD.ipynb, lines 45–57 · score 0.58 · load_gs, scDRS, munged, GWAS
  20. [20] § Results › Higher proportion of homeostatic astroglia in PD ↔ Manuscript_figures.Rmd, lines 95–167 · score 0.57 · OL_SGCZ, OL_LINC01608, OL_SLC5A11, homeostatic, reactive, OPCs
  21. [21] § Results › Higher proportion of homeostatic astroglia in PD ↔ Manuscript_figures.Rmd, lines 95–167 · score 0.57 · OL_SGCZ, OL_LINC01608, OL_SLC5A11, homeostatic, reactive, OPCs
  22. [22] § Methods › Bioinformatic analysis › Cosine similarities ↔ Manuscript_figures.Rmd, lines 4224–4295 · score 0.57 · PCA space, DESeq2, rotated, collapsed, matrices, genes
  23. [23] § Methods › Bioinformatic analysis › Cosine similarities ↔ Manuscript_figures.Rmd, lines 4075–4146 · score 0.57 · PCA space, DESeq2, rotated, collapsed, matrices, genes
  24. [24] § Results › Compromised oligodendrocytes in MSA signal to microglia and perivascular macrophages ↔ Objects_preparations.Rmd, lines 69–102 · score 0.56 · OL_SLC5A11, OL LINC01608, cell subtype, homeostatic
  25. [25] § Results › Minor compositional changes in neuronal subtypes across PD and MSA ↔ Manuscript_figures.Rmd, lines 722–736 · score 0.55 · PPP1R1B, SLC17A7, GAD2, GAD1, meis2, st18
  26. [26] § Results › The single-nucleus transcriptomics of the striatum in MSA, PD and control brains ↔ Manuscript_figures.Rmd, lines 5617–5663 · score 0.50 · medium spiny neurons, GABAergic, MSN, astrocyte, microglia

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 · 6,077 lines · 179 KB · GPL-3.0 · 13 matches

  1. ---
  2. title: "Figures_MSA-PD"
  3. author: "Rasmus Rydbirk"
  4. date: "04-12-2024"
  5. output:
  6. html_document:
  7. toc: yes
  8. toc_float: yes
  9. ---
  10. # Setup
  11. ```{r setup, message = F}
  12. library(conos)
  13. library(magrittr)
  14. library(dplyr)
  15. library(cacoa) # github.com/kharchenkolab/cacoa
  16. library(sccore)
  17. library(scHelper) # github.com/rrydbirk/scHelper
  18. library(qs)
  19. library(ggplot2)
  20. library(ggsci)
  21. library(cowplot)
  22. library(ggpubr)
  23. library(STRINGdb)
  24. library(reshape2)
  25. library(ggforce)
  26. library(ggpmisc)
  27. library(RColorBrewer)
  28. library(CRMetrics)
  29. library(ggrepel)
  30. library(circlize)
  31. library(ComplexHeatmap)
  32. library(stringr)
  33. library(rstatix)
  34. library(slingshot)
  35. library(gamm4)
  36. library(scITD)
  37. library(ggraph)
  38. ## Comparisons
  39. comp <- list(c("CTRL","MSA"),
  40. c("CTRL","PD"),
  41. c("MSA","PD"))
  42. comp.long <- list(c("CTRL vs. MSA","CTRL vs. PD"),
  43. c("CTRL vs. MSA","PD vs. MSA"),
  44. c("CTRL vs. PD","PD vs. MSA"))
  45. # Palettes
  46. ## Major celltypes
  47. anno.neurons <- qread("anno_neurons.qs")
  48. anno.neurons.major <- anno.neurons %>%
  49. collapseAnnotation("GABA") %>%
  50. collapseAnnotation("GLU") %>%
  51. renameAnnotation("GABA", "Inh. neurons") %>%
  52. renameAnnotation("GLU", "Exc. neurons") %>%
  53. collapseAnnotation("MSN")
  54. anno <- qread("anno_major.qs")
  55. anno.major <- anno[!names(anno) %in% names(anno.neurons.major) & !anno == "Neurons"] %>%
  56. {factor(c(., anno.neurons.major))}
  57. pal.major <- brewer.pal(n = 10, "Set1") %>%
  58. c("lightblue3") %>%
  59. setNames(levels(anno.major)[c(9,8,3,5,10,6:7,2,1,4)])
  60. ## Condition
  61. pal.major %<>% c(c("yellow", brewer.pal(n = 6, "Accent")[5:6]) %>% setNames(c("CTRL","PD","MSA")))
  62. ## Comparisons
  63. pal.major %<>% c(brewer.pal(n = 10, "Paired")[c(6,8,10)] %>% setNames(c("CTRL vs. MSA","CTRL vs. PD","PD vs. MSA")))
  64. ## Neurons
  65. pal.major %<>% c(setNames(c("navy",
  66. "mediumblue",
  67. "lightslateblue",
  68. "lightskyblue",
  69. "lightblue",
  70. "lightseagreen",
  71. "blue",
  72. "cadetblue1",
  73. "cyan",
  74. "cyan4",
  75. "aquamarine2",
  76. "lightcoral",
  77. "brown1",
  78. "orange",
  79. "darkorange4",
  80. "lightgoldenrod3"),
  81. levels(anno.neurons)))
  82. ## Glia
  83. anno.glia <- c("anno_astro.qs",
  84. "anno_oligo.qs",
  85. "anno_opc.qs") %>%
  86. lapply(qread) %>%
  87. Reduce(c, .) %>%
  88. factor() %>%
  89. renameAnnotation("Homeostatic_astrocytes", "AS_homeostatic") %>%
  90. renameAnnotation("Reactive_astrocytes", "AS_reactive") %>%
  91. renameAnnotation("Homeostatic_LINC01608", "OL_LINC01608") %>%
  92. renameAnnotation("Homeostatic_SLC5A11", "OL_SLC5A11") %>%
  93. renameAnnotation("Reactive_SCGZ", "OL_SGCZ")
  94. pal.major %<>% c(setNames(c("pink",
  95. pal.major["Astrocytes"],
  96. pal.major["Oligodendrocytes"],
  97. "chartreuse",
  98. "darkolivegreen",
  99. "brown4",
  100. "coral"),
  101. levels(anno.glia)))
  102. ## Microglia
  103. anno.micro <- qread("anno_micro_pvm.qs") %>%
  104. renameAnnotation("Steady-state","MIC_steady-state") %>%
  105. renameAnnotation("Intermediate1","MIC_intermediate1") %>%
  106. renameAnnotation("Intermediate2","MIC_intermediate2") %>%
  107. renameAnnotation("Activated","MIC_activated")
  108. pal.major %<>% c(setNames(c(pal.major["Microglia"],
  109. "maroon4",
  110. "magenta",
  111. "pink3",
  112. pal.major["PVMs"]),
  113. levels(anno.micro)))
  114. ## Phago. assay
  115. pal.major %<>% c(setNames(c("purple",
  116. "black",
  117. pal.major[c("CTRL","PD","MSA")]),
  118. c("PBS",
  119. "LPS",
  120. "CTRL CSF",
  121. "PD CSF",
  122. "MSA CSF")))
  123. ## Houston assay
  124. pal.major %<>% c(setNames(c(pal.major["PBS"],
  125. pal.major["CTRL"],
  126. "yellow3",
  127. "orange",
  128. pal.major["PD"],
  129. "cyan4",
  130. "navyblue",
  131. pal.major["MSA"],
  132. "pink3",
  133. "red4"),
  134. c("Microglia medium",
  135. "CTRL CSF, no dil.",
  136. "CTRL CSF, 1:2 dil.",
  137. "CTRL CSF, 1:4 dil.",
  138. "PD CSF, no dil.",
  139. "PD CSF, 1:2 dil.",
  140. "PD CSF, 1:4 dil.",
  141. "MSA CSF, no dil.",
  142. "MSA CSF, 1:2 dil.",
  143. "MSA CSF, 1:4 dil.")))
  144. # Load major Conos object
  145. con <- qread("con_major.qs", nthreads = 10)
  146. tt <- Sys.time()
  147. ```
  148. Define helper functions
  149. ```{r}
  150. getOntWithFamily <- function(cao, comp, name = "GSEA") {
  151. fams <- cao$test.results[[name]]$families
  152. df.all <- list(cao$.__enclos_env__$private$getOntologyPvalueResults(name = name, genes = "up", p.adj = 1, q.value = 1),
  153. cao$.__enclos_env__$private$getOntologyPvalueResults(name = name, genes = "down", p.adj = 1, q.value = 1)) %>%
  154. bind_rows() %>%
  155. mutate(logp = -log10(p.adjust),
  156. comp = comp)
  157. df <- cacoa:::getOntologyFamilyChildren(df.all, fams=fams, type = name, subtype = "BP")
  158. return(list(df.all = df.all,
  159. df = df,
  160. fams = fams))
  161. }
  162. ```
  163. ```{r}
  164. lianaCircos <- function(df,
  165. top.interactions = 30,
  166. text.size = 1,
  167. pal = pal.major,
  168. cell.types = c("Astrocytes",
  169. "Immune",
  170. "Microglia",
  171. "Neurons",
  172. "OPCs",
  173. "Oligodendrocytes",
  174. "PVMs",
  175. "Pericytes/endothelial"),
  176. big.gap = 5,
  177. small.gap = 2,
  178. arrow.width = 3,
  179. link.ramp.rel = T,
  180. link.sort = F,
  181. scale = F,
  182. arrow.head.width = 0.3,
  183. arrow.head.length = 0.3,
  184. link.ramp.col = c("navy", "grey", "firebrick")) {
  185. input_df <- df %>%
  186. slice_max(order_by = score, n = top.interactions) %>%
  187. mutate(target = paste0(target, " ")) %>%
  188. mutate(source_lig = paste0(source, "|", ligand),
  189. target_rec = paste0(target, "|", receptor))
  190. if (link.ramp.rel) {
  191. arr_wd <- rep(arrow.width, nrow(input_df))
  192. } else {
  193. arr_wd <- (((input_df$score - min(input_df$score))/(max(input_df$score) - min(input_df$score))) * (arrow.width)) + 1
  194. }
  195. # Colors and segments
  196. anno.col <- setNames(pal,
  197. cell.types) %>%
  198. c(., "Oligodendrocytes " = unname(.["Oligodendrocytes"]))
  199. cell_cols <- anno.col[unique(c(unique(input_df$source), unique(input_df$target), "Oligodendrocytes "))]
  200. link_cols <- c()
  201. if (!link.ramp.rel) {
  202. for (i in input_df$source_lig) {
  203. link_cols <- c(link_cols, cell_cols[str_extract(i,
  204. "[^|]+")])
  205. }
  206. } else {
  207. input_df %<>%
  208. arrange(score)
  209. df.down <- input_df %>% filter(score <= 0)
  210. link_down <- colorRampPalette(c(link.ramp.col[1], link.ramp.col[2]))(nrow(df.down))
  211. df.up <- input_df %>% filter(score > 0)
  212. link_up <- colorRampPalette(c(link.ramp.col[2], link.ramp.col[3]))(nrow(df.up))
  213. link_cols <- c(link_down, link_up)
  214. }
  215. segments <- unique(c(paste0(input_df$source, "|", input_df$ligand),
  216. paste0(input_df$target, "|", input_df$receptor)))
  217. grp <- str_extract(segments, "[^|]+") %>%
  218. setNames(segments)
  219. # Redo colors
  220. cell_cols2 <- grp
  221. for (i in unique(grp)) {
  222. cell_cols2[cell_cols2 == i] <- cell_cols[i]
  223. }
  224. # Plot
  225. input_df %>%
  226. select(source_lig, target_rec, score) %>%
  227. chordDiagram(directional = 1,
  228. group = grp,
  229. scale = scale,
  230. diffHeight = 0.005,
  231. direction.type = c("arrows"),
  232. link.arr.type = "triangle",
  233. annotationTrack = c(),
  234. preAllocateTracks = list(
  235. list(track.height = 0.05),
  236. list(track.height = 0.25),
  237. list(track.height = 0.05)),
  238. big.gap = big.gap,
  239. transparency = 1,
  240. link.arr.lwd = arr_wd,
  241. link.arr.col = link_cols,
  242. link.arr.length = arrow.head.length,
  243. link.arr.width = arrow.head.width,
  244. small.gap = small.gap
  245. )
  246. circos.track(track.index = 2, panel.fun = function(x, y) {
  247. circos.text(CELL_META$xcenter,
  248. CELL_META$ylim[1],
  249. str_extract(CELL_META$sector.index, "[^|]+$"),
  250. facing = "clockwise",
  251. niceFacing = TRUE,
  252. adj = c(0, 0.55),
  253. cex = 1)
  254. }, bg.border = NA)
  255. # Split segments
  256. for (l in segments) {
  257. highlight.sector(l, track.index = 3, col = cell_cols2[l])
  258. }
  259. # Add ligand/receptor track
  260. ## Ligand
  261. highlight.sector(input_df$source_lig,
  262. track.index = 1,
  263. col = "black",
  264. text = "Ligands",
  265. cex = 1,
  266. text.col = "white",
  267. niceFacing = TRUE)
  268. ## Receptor
  269. highlight.sector(input_df$target_rec,
  270. track.index = 1,
  271. col = "white",
  272. text = "Receptors",
  273. cex = 1,
  274. text.col = "black",
  275. border = "black",
  276. niceFacing = TRUE)
  277. # Legends
  278. minmax <- input_df %>%
  279. pull(score) %>%
  280. {pmax(abs(min(.)), max(.))} %>%
  281. formatC(digits = 1) %>%
  282. as.numeric()
  283. col.range = c(-minmax, 0, minmax)
  284. lgd_links = Legend(at = col.range,
  285. col_fun = colorRamp2(col.range, link.ramp.col),
  286. title_position = "topleft",
  287. title = "Links")
  288. lgd_ct <- Legend(labels = unique(c(input_df$source, input_df$target)),
  289. title = "Cell type",
  290. type = "points",
  291. legend_gp = gpar(col = "transparent"),
  292. background = cell_cols[unique(c(input_df$source, input_df$target))])
  293. lgd_list_vertical = packLegend(lgd_ct, lgd_links)
  294. draw(lgd_list_vertical,
  295. just = c("left", "bottom"),
  296. x = unit(5, "mm"),
  297. y = unit(5, "mm"))
  298. circos.clear()
  299. }
  300. ```
  301. ```{r}
  302. getTscanTrajectory <- function(con, anno) {
  303. requireNamespace("TSCAN", quietly = T)
  304. emb <- con$embedding[names(anno), ]
  305. anno %<>% .[rownames(emb)]
  306. cent.ids <- emb %>%
  307. rownames() %>%
  308. split(anno)
  309. centroids <- cent.ids %>%
  310. lapply(\(cid) emb[cid, ]) %>%
  311. lapply(colMeans) %>%
  312. bind_rows() %>%
  313. t() %>%
  314. `colnames<-`(c("UMAP1","UMAP2"))
  315. mst <- centroids %>%
  316. TSCAN::createClusterMST(clusters = NULL)
  317. line.data <- TSCAN::reportEdges(centroids, mst = mst, clusters = NULL)
  318. return(line.data)
  319. }
  320. ```
  321. ```{r, fig.width=8, fig.height=4}
  322. plotGenePseudoBulk <- function(gene, cm.pseudo, legend = T) {
  323. idx <- cm.pseudo %>%
  324. colnames() %>%
  325. data.frame(id = .) %>%
  326. mutate(condition = strsplit(id, "_|!!") %>% sget(1),
  327. ct = strsplit(id, "!!") %>% sget(2)) %>%
  328. mutate(ord = order(condition, ct))
  329. x <- cm.pseudo %>%
  330. .[match(gene, rownames(.)), match(colnames(na.omit(.)), colnames(.))] %>%
  331. .[idx$ord]
  332. plot.dat <- x %>%
  333. {data.frame(sample = names(.),
  334. value = unname(.))} %>%
  335. mutate(anno = strsplit(sample, "!!") %>%
  336. sget(2),
  337. condition = strsplit(sample, "!!|_") %>%
  338. sget(1)) %>%
  339. mutate(anno = factor(anno))
  340. stat.test <- plot.dat %>%
  341. group_by(anno) %>%
  342. rstatix::wilcox_test(value ~ condition) %>%
  343. filter(p.adj <= 0.05) %>%
  344. rstatix::add_xy_position(x = "anno", step.increase = 0.05)
  345. omnibus.test <- plot.dat %>%
  346. group_by(anno) %>%
  347. rstatix::kruskal_test(value ~ condition) %>%
  348. filter(p <= 0.05) %>%
  349. mutate(p = formatC(p, digits = 2))
  350. p <- plot.dat %>%
  351. ggplot(aes(anno, value)) +
  352. geom_boxplot(aes(fill = condition)) +
  353. theme_bw() +
  354. theme(line = element_blank(),
  355. axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
  356. axis.ticks.x = element_line()) +
  357. labs(x = "", y = "Normalized pseudobulk expression", fill = "", title = paste0(gene, " expression")) +
  358. scale_fill_manual(values = pal.major) +
  359. geom_text(data = omnibus.test, aes(anno, y = pmin(max(plot.dat$value) * 1.05, max(plot.dat$value) + 10), label = p), size = 3) +
  360. stat_pvalue_manual(stat.test, hide.ns = T, label = "p.adj", size = 3)
  361. if (!legend) p <- p + guides(fill = "none")
  362. return(p)
  363. }
  364. ```
  365. # Figure 1
  366. ## Load data
  367. ```{r}
  368. cao_msa <- qread("cao_major_msa.qs", nthreads = 10)
  369. cao_msa$plot.theme <- theme_bw()
  370. cao_pd <- qread("cao_major_pd.qs", nthreads = 10)
  371. cao_pd$plot.theme <- theme_bw()
  372. cao_dis <- qread("cao_major_dis.qs", nthreads = 10)
  373. cao_dis$plot.theme <- theme_bw()
  374. ```
  375. ## Figure 1b
  376. ```{r, fig.width=5.7, fig.height=4}
  377. con$plotGraph(groups = anno.major,
  378. embedding = "UMAP_1_0.001_5",
  379. size = 0.1,
  380. palette = pal.major,
  381. font.size = 3,
  382. raster = T,
  383. show.labels = T,
  384. plot.na = F,
  385. show.legend = T,
  386. legend.title = "Cell type",
  387. alpha = 0.05) +
  388. dotSize(3) +
  389. labs(x="UMAP1", y= "UMAP2") +
  390. theme(line = element_blank()) +
  391. ylim(c(-20, 15)) +
  392. xlim(c(-21, 11)) -> p
  393. p
  394. ```
  395. Export source data
  396. ```{r, eval = F}
  397. p$data %>%
  398. write.table("source_data/F1b.tsv", sep = "\t", dec = ".", row.names = F)
  399. ```
  400. ## Figure 1c
  401. ```{r, fig.height=4, fig.width=5}
  402. cm.merged <- con$getJointCountMatrix()
  403. markers <- c("AQP4","PTPRC","CSF1R","RBFOX3","SLC17A7","GAD1","PPP1R1B","MOG","VCAN","PDGFRB","MRC1")
  404. dotPlot(markers,
  405. cm.merged,
  406. anno.major %>%
  407. factor(., levels = sort(levels(.))[c(1,3,5,2,4,6,7:10)]),
  408. cols = c("white","firebrick"),
  409. gene.order = markers) -> p
  410. p
  411. ```
  412. Export source data
  413. ```{r, eval = F}
  414. p$data %>%
  415. write.table("source_data/F1c.tsv", sep = "\t", dec = ".", row.names = F)
  416. ```
  417. ## Figure 1d
  418. ```{r}
  419. spc <- con$getDatasetPerCell()
  420. cpc <- spc %>%
  421. as.character() %>%
  422. grepl.replace(c("CTRL","MSA","PD")) %>%
  423. `names<-`(names(spc))
  424. con$plotGraph(groups = cpc,
  425. embedding = "UMAP_1_0.001_5",
  426. size = 0.1,
  427. alpha = 0.05,
  428. palette = pal.major,
  429. font.size = 3,
  430. raster = F,
  431. show.labels = T,
  432. plot.na = F,
  433. mark.groups = F,
  434. show.legend = T) +
  435. labs(x="UMAP1", y= "UMAP2", col = "") +
  436. theme(legend.position = "bottom",
  437. line = element_blank()) +
  438. dotSize(3) -> p
  439. p
  440. ```
  441. Export source data
  442. ```{r, eval = F}
  443. p$data %>%
  444. write.table("source_data/F1d.tsv", sep = "\t", dec = ".", row.names = F)
  445. ```
  446. ## Figure 1e
  447. ```{r, fig.height=4, fig.width=3}
  448. cao_msa$plotCellLoadings(show.pvals = F,
  449. alpha = 0)$data %>%
  450. ggplot(aes(ind, values, fill = ind)) +
  451. geom_hline(yintercept = 0, col = "black") +
  452. geom_violin() +
  453. coord_flip() +
  454. theme_bw() +
  455. scale_fill_manual(values = pal.major) +
  456. theme(legend.position = "none",
  457. line = element_blank()) +
  458. scale_y_continuous(breaks = c(-1,0,1),
  459. limits = c(-1,1),
  460. labels = c("-1\nCTRL",0,"1\nMSA")) +
  461. labs(x = "", y = "") -> p
  462. p
  463. ```
  464. Export source data
  465. ```{r, eval = F}
  466. p$data %>%
  467. write.table("source_data/F1e.tsv", sep = "\t", dec = ".", row.names = F)
  468. ```
  469. ## Figure 1f
  470. ```{r, fig.height=4, fig.width=3}
  471. cao_pd$plotCellLoadings(show.pvals = F,
  472. alpha = 0)$data %>%
  473. ggplot(aes(ind, values, fill = ind)) +
  474. geom_hline(yintercept = 0, col = "black") +
  475. geom_violin() +
  476. coord_flip() +
  477. theme_bw() +
  478. scale_fill_manual(values = pal.major) +
  479. theme(legend.position = "none",
  480. line = element_blank()) +
  481. scale_y_continuous(breaks = c(-1,0,1),
  482. limits = c(-1,1.1),
  483. labels = c("-1\nCTRL",0,"1\nPD")) +
  484. geom_vline(xintercept = 7.5, col = "red") +
  485. labs(x = "", y = "") -> p
  486. p
  487. ```
  488. Export source data
  489. ```{r, eval = F}
  490. p$data %>%
  491. write.table("source_data/F1f.tsv", sep = "\t", dec = ".", row.names = F)
  492. ```
  493. ## Figure 1g
  494. ```{r, fig.height=4, fig.width=3}
  495. cao_dis$plotCellLoadings(show.pvals = F,
  496. alpha = 0)$data %>%
  497. ggplot(aes(ind, values, fill = ind)) +
  498. geom_hline(yintercept = 0, col = "black") +
  499. geom_violin() +
  500. coord_flip() +
  501. theme_bw() +
  502. scale_fill_manual(values = pal.major) +
  503. theme(legend.position = "none",
  504. line = element_blank()) +
  505. scale_y_continuous(breaks = c(-1,0,1),
  506. limits = c(-1,1),
  507. labels = c("-1\nPD",0,"1\nMSA")) +
  508. geom_vline(xintercept = 5.5, col = "red") +
  509. labs(x = "", y = "") -> p
  510. p
  511. ```
  512. Export source data
  513. ```{r, eval = F}
  514. p$data %>%
  515. write.table("source_data/F1g.tsv", sep = "\t", dec = ".", row.names = F)
  516. ```
  517. ## Figure 1h
  518. ```{r, fig.width = 6, fig.height = 4}
  519. cao_msa$cell.groups.palette <- pal.major
  520. stat.p <- cao_msa$test.results$expression.shifts$padjust %>%
  521. {data.frame(Type = names(.), padj = unname(.), value = 0.4)} %>%
  522. mutate(padj = formatC(padj, digits = 3))
  523. stat.p$padj[stat.p$padj > 0.05] <- ""
  524. cao_msa$plotExpressionShiftMagnitudes(show.pvalues = "none") +
  525. labs(y = "Normalized expression distance") +
  526. geom_text(data = stat.p, aes(label = padj)) -> p
  527. p
  528. ```
  529. Export source data
  530. ```{r, eval = F}
  531. p$data %>%
  532. write.table("source_data/F1h.tsv", sep = "\t", dec = ".", row.names = F)
  533. ```
  534. ## Figure 1i
  535. ```{r}
  536. cao_pd$cell.groups.palette <- pal.major
  537. stat.p <- cao_pd$test.results$expression.shifts$padjust %>%
  538. {data.frame(Type = names(.), padj = unname(.), value = 0.35)} %>%
  539. mutate(padj = formatC(padj, digits = 3))
  540. stat.p$padj[stat.p$padj > 0.05] <- ""
  541. cao_pd$plotExpressionShiftMagnitudes(show.pvalues = "none") +
  542. labs(y = "Normalized expression distance") +
  543. geom_text(data = stat.p, aes(label = padj)) -> p
  544. p
  545. ```
  546. Export source data
  547. ```{r, eval = F}
  548. p$data %>%
  549. write.table("source_data/F1i.tsv", sep = "\t", dec = ".", row.names = F)
  550. ```
  551. ## Figure 1j
  552. ```{r}
  553. cao_dis$cell.groups.palette <- pal.major
  554. stat.p <- cao_dis$test.results$expression.shifts$padjust %>%
  555. {data.frame(Type = names(.), padj = unname(.), value = 0.3)} %>%
  556. mutate(padj = formatC(padj, digits = 3))
  557. stat.p$padj[stat.p$padj > 0.05] <- ""
  558. cao_dis$plotExpressionShiftMagnitudes(show.pvalues = "none") +
  559. labs(y = "Normalized expression distance") +
  560. geom_text(data = stat.p, aes(label = padj)) -> p
  561. p
  562. ```
  563. Export source data
  564. ```{r, eval = F}
  565. p$data %>%
  566. write.table("source_data/F1j.tsv", sep = "\t", dec = ".", row.names = F)
  567. ```
  568. # Figure 2
  569. ## Load data
  570. ```{r}
  571. cao <- qread("cao_neurons.qs", nthreads = 10)
  572. cao$plot.theme <- theme_bw()
  573. cao_msa <- qread("cao_neurons_msa.qs", nthreads = 10)
  574. cao_msa$plot.theme <- theme_bw()
  575. cao_pd <- qread("cao_neurons_pd.qs", nthreads = 10)
  576. cao_pd$plot.theme <- theme_bw()
  577. cao_dis <- qread("cao_neurons_dis.qs", nthreads = 10)
  578. cao_dis$plot.theme <- theme_bw()
  579. ```
  580. ## Figure 2a
  581. ```{r, fig.height=4, fig.width=4}
  582. cao$plotEmbedding(groups = cao$cell.groups,
  583. size = 0.1,
  584. palette = pal.major,
  585. font.size = 3,
  586. raster = T,
  587. show.labels = T,
  588. plot.na = F,
  589. alpha = 0.1) +
  590. theme(line = element_blank()) +
  591. labs(x="largeVis1", y= "largeVis2") -> p
  592. p
  593. ```
  594. Export source data
  595. ```{r, eval = F}
  596. p$data %>%
  597. write.table("source_data/F2a.tsv", sep = "\t", dec = ".", row.names = F)
  598. ```
  599. ## Figure 2b
  600. ```{r, fig.width=6.7, fig.height=4}
  601. cm.merged <- cao$data.object$getJointCountMatrix()
  602. markers <- c("GAD1","GAD2","PPP1R1B","SLC17A7","CHAT","CALB2","DCC","ID2","MEIS2","ST18","NKX2-1","NR2F2","PAX6","PVALB","RXFP1","SST","VIP","RELN","SATB2","DRD1","DRD2","FOXP2", "LRP8", "VLDLR")
  603. dotPlot(markers,
  604. cm.merged,
  605. anno.neurons,
  606. cols = c("white","firebrick"),
  607. gene.order = markers) -> p
  608. p
  609. ```
  610. Export source data
  611. ```{r, eval = F}
  612. p$data %>%
  613. write.table("source_data/F2b.tsv", sep = "\t", dec = ".", row.names = F)
  614. ```
  615. ## Figure 2c
  616. ```{r, fig.height=4, fig.width=3}
  617. cao_msa$plotCellLoadings(show.pvals = F,
  618. alpha = 0)$data %>%
  619. ggplot(aes(ind, values, fill = ind)) +
  620. geom_hline(yintercept = 0, col = "black") +
  621. geom_violin() +
  622. coord_flip() +
  623. theme_bw() +
  624. scale_fill_manual(values = pal.major) +
  625. theme(legend.position = "none",
  626. line = element_blank()) +
  627. scale_y_continuous(breaks = c(-1,0,1),
  628. limits = c(-1,1),
  629. labels = c("-1\nCTRL",0,"1\nMSA")) +
  630. labs(x = "", y = "") -> p
  631. p
  632. ```
  633. Export source data
  634. ```{r, eval = F}
  635. p$data %>%
  636. write.table("source_data/F2c.tsv", sep = "\t", dec = ".", row.names = F)
  637. ```
  638. ## Figure 2d
  639. ```{r, fig.height=4, fig.width=3}
  640. cao_pd$plotCellLoadings(show.pvals = F,
  641. alpha = 0)$data %>%
  642. ggplot(aes(ind, values, fill = ind)) +
  643. geom_hline(yintercept = 0, col = "black") +
  644. geom_violin() +
  645. coord_flip() +
  646. theme_bw() +
  647. scale_fill_manual(values = pal.major) +
  648. theme(legend.position = "none",
  649. line = element_blank()) +
  650. scale_y_continuous(breaks = c(-1,0,1),
  651. limits = c(-1,1),
  652. labels = c("-1\nCTRL",0,"1\nPD")) +
  653. geom_vline(xintercept = 13.5, col = "red") +
  654. labs(x = "", y = "") -> p
  655. p
  656. ```
  657. Export source data
  658. ```{r, eval = F}
  659. p$data %>%
  660. write.table("source_data/F2d.tsv", sep = "\t", dec = ".", row.names = F)
  661. ```
  662. ## Figure 2e
  663. ```{r, fig.height=4, fig.width=3}
  664. cao_dis$plotCellLoadings(show.pvals = F,
  665. alpha = 0)$data %>%
  666. ggplot(aes(ind, values, fill = ind)) +
  667. geom_hline(yintercept = 0, col = "black") +
  668. geom_violin() +
  669. coord_flip() +
  670. theme_bw() +
  671. scale_fill_manual(values = pal.major) +
  672. theme(legend.position = "none",
  673. line = element_blank()) +
  674. scale_y_continuous(breaks = c(-1,0,1),
  675. limits = c(-1,1),
  676. labels = c("-1\nPD",0,"1\nMSA")) +
  677. labs(x = "", y = "") -> p
  678. p
  679. ```
  680. Export source data
  681. ```{r, eval = F}
  682. p$data %>%
  683. write.table("source_data/F2e.tsv", sep = "\t", dec = ".", row.names = F)
  684. ```
  685. ## Figure 2f
  686. ```{r, fig.width = 8.5, fig.height = 5}
  687. cao_msa$cell.groups.palette <- pal.major
  688. cao_msa$plotExpressionShiftMagnitudes() +
  689. labs(y = "Normalized expression distance") -> p1
  690. cao_pd$cell.groups.palette <- pal.major
  691. cao_pd$plotExpressionShiftMagnitudes() +
  692. labs(y = "Normalized expression distance") -> p2
  693. cao_dis$cell.groups.palette <- pal.major
  694. cao_dis$plotExpressionShiftMagnitudes() +
  695. labs(y = "Normalized expression distance") -> p3
  696. p1
  697. p2
  698. p3
  699. ```
  700. Export source data
  701. ```{r, eval = F}
  702. p1$data %>%
  703. write.table("source_data/F2f1.tsv", sep = "\t", dec = ".", row.names = F)
  704. p2$data %>%
  705. write.table("source_data/F2f2.tsv", sep = "\t", dec = ".", row.names = F)
  706. p3$data %>%
  707. write.table("source_data/F2f3.tsv", sep = "\t", dec = ".", row.names = F)
  708. ```
  709. ## Figure 2g
  710. ```{r, fig.height=4, fig.width=4}
  711. sample.groups <- cao$sample.groups
  712. cao$estimateCellDensity(method = "graph")
  713. cao$estimateDiffCellDensity(type = "subtract")
  714. cao$plotCellDensity(show.cell.groups = F, show.legend = F, color.range = c(0, 0.00035))$CTRL +
  715. geom_circle(aes(x0 = 30.9, y0 = 10, r = 10)) +
  716. geom_circle(aes(x0 = 17.5, y0 = 24, r = 4), col = "cyan3") +
  717. theme(line = element_blank()) -> p
  718. p
  719. ```
  720. Export source data
  721. ```{r, eval = F}
  722. p$data %>%
  723. write.table("source_data/F2g1.tsv", sep = "\t", dec = ".", row.names = F)
  724. ```
  725. ```{r, fig.height=4, fig.width=4}
  726. # MSA
  727. cao$sample.groups <- sample.groups %>%
  728. names() %>%
  729. grepl.replace(c("CTRL","MSA","PD")) %>%
  730. `names<-`(sample.groups %>% names()) %>%
  731. .[. %in% c("CTRL","MSA")]
  732. cao$target.level <- "MSA"
  733. cao$estimateCellDensity(method = "graph", name = "msa.density")
  734. cao$estimateDiffCellDensity(type = "subtract", name = "msa.density")
  735. cao$plotCellDensity(show.cell.groups = F, name = "msa.density", show.legend = F, color.range = c(0, 0.00035))$MSA +
  736. geom_circle(aes(x0 = 30.9, y0 = 10, r = 10)) +
  737. geom_circle(aes(x0 = 17.5, y0 = 24, r = 4), col = "cyan3") +
  738. theme(line = element_blank()) -> p
  739. p
  740. ```
  741. Export source data
  742. ```{r, eval = F}
  743. p$data %>%
  744. write.table("source_data/F2g2.tsv", sep = "\t", dec = ".", row.names = F)
  745. ```
  746. ```{r, fig.height=4, fig.width=5.1}
  747. # PD
  748. cao$sample.groups <- sample.groups %>%
  749. names() %>%
  750. grepl.replace(c("CTRL","MSA","PD")) %>%
  751. `names<-`(sample.groups %>% names()) %>%
  752. .[. %in% c("CTRL","PD")]
  753. cao$target.level <- "PD"
  754. cao$estimateCellDensity(method = "graph", name = "pd.density")
  755. cao$estimateDiffCellDensity(type = "subtract", name = "pd.density")
  756. cao$plotCellDensity(show.cell.groups = F, name = "pd.density", show.legend = T, color.range = c(0, 0.00035))$PD +
  757. geom_circle(aes(x0 = 30.9, y0 = 10, r = 10)) +
  758. geom_circle(aes(x0 = 17.5, y0 = 24, r = 4), col = "cyan3") +
  759. theme(line = element_blank()) -> p
  760. p
  761. ```
  762. Export source data
  763. ```{r, eval = F}
  764. p$data %>%
  765. write.table("source_data/F2g3.tsv", sep = "\t", dec = ".", row.names = F)
  766. ```
  767. # Figure 3
  768. ## Load data
  769. ```{r}
  770. con.glia <- qread("con_oligo_astro_opc.qs", nthreads = 10)
  771. cao_msa <- qread("cao_oligo_astro_opc_msa.qs", nthreads = 10)
  772. cao_msa$plot.theme <- theme_bw()
  773. cao_pd <- qread("cao_oligo_astro_opc_pd.qs", nthreads = 10)
  774. cao_pd$plot.theme <- theme_bw()
  775. cao_dis <- qread("cao_oligo_astro_opc_dis.qs", nthreads = 10)
  776. cao_dis$plot.theme <- theme_bw()
  777. ```
  778. ## Figure 3a
  779. ```{r, fig.width=4, fig.height=4}
  780. con.glia$plotGraph(groups = anno.glia,
  781. plot.na = F,
  782. size = 0.1,
  783. palette = pal.major,
  784. font.size = 3,
  785. raster = T,
  786. show.labels = T, embedding = "largeVis_CPCA_AS01",
  787. alpha = 0.05) +
  788. labs(x = "largeVis1", y = "largeVis2") +
  789. theme(line = element_blank()) -> p
  790. p
  791. ```
  792. Export source data
  793. ```{r, eval = F}
  794. p$data %>%
  795. write.table("source_data/F3a.tsv", sep = "\t", dec = ".", row.names = F)
  796. ```
  797. ## Figure 3b
  798. ```{r, fig.height=4, fig.width=4.5}
  799. cm.merged <- con.glia$getJointCountMatrix()
  800. markers <- c("AQP4","TNC","MOG","LINC01608","SLC5A11","SGCZ","VCAN","OLIG2")
  801. dotPlot(markers,
  802. cm.merged,
  803. anno.glia,
  804. cols = c("white","firebrick"),
  805. gene.order = markers) -> p
  806. p
  807. ```
  808. Export source data
  809. ```{r, eval = F}
  810. p$data %>%
  811. write.table("source_data/F3b.tsv", sep = "\t", dec = ".", row.names = F)
  812. ```
  813. ## Figure 3c
  814. ```{r, fig.height=4, fig.width=3}
  815. cao_msa$plotCellLoadings(show.pvals = F,
  816. alpha = 0)$data %>%
  817. ggplot(aes(ind, values, fill = ind)) +
  818. geom_hline(yintercept = 0, col = "black") +
  819. geom_violin() +
  820. coord_flip() +
  821. theme_bw() +
  822. scale_fill_manual(values = pal.major) +
  823. theme(legend.position = "none",
  824. line = element_blank()) +
  825. scale_y_continuous(breaks = c(-1,0,1),
  826. limits = c(-1.1,1),
  827. labels = c("-1\nCTRL",0,"1\nMSA")) +
  828. geom_vline(xintercept = 6.5, col = "red") +
  829. labs(x = "", y = "") -> p
  830. p
  831. ```
  832. Export source data
  833. ```{r, eval = F}
  834. p$data %>%
  835. write.table("source_data/F3c.tsv", sep = "\t", dec = ".", row.names = F)
  836. ```
  837. ## Figure 3d
  838. ```{r, fig.height=4, fig.width=3}
  839. cao_pd$plotCellLoadings(show.pvals = F,
  840. alpha = 0)$data %>%
  841. ggplot(aes(ind, values, fill = ind)) +
  842. geom_hline(yintercept = 0, col = "black") +
  843. geom_violin() +
  844. coord_flip() +
  845. theme_bw() +
  846. scale_fill_manual(values = pal.major) +
  847. theme(legend.position = "none",
  848. line = element_blank()) +
  849. scale_y_continuous(breaks = c(-1,0,1),
  850. limits = c(-1.15,1),
  851. labels = c("-1\nCTRL",0,"1\nPD")) +
  852. geom_vline(xintercept = 4.5, col = "red") +
  853. labs(x = "", y = "") -> p
  854. p
  855. ```
  856. Export source data
  857. ```{r, eval = F}
  858. p$data %>%
  859. write.table("source_data/F3d.tsv", sep = "\t", dec = ".", row.names = F)
  860. ```
  861. ## Figure 3e
  862. ```{r, fig.height=4, fig.width=3}
  863. cao_dis$plotCellLoadings(show.pvals = F,
  864. alpha = 0)$data %>%
  865. ggplot(aes(ind, values, fill = ind)) +
  866. geom_hline(yintercept = 0, col = "black") +
  867. geom_violin() +
  868. coord_flip() +
  869. theme_bw() +
  870. scale_fill_manual(values = pal.major) +
  871. theme(legend.position = "none",
  872. line = element_blank()) +
  873. scale_y_continuous(breaks = c(-1,0,1),
  874. limits = c(-1.1,1),
  875. labels = c("-1\nPD",0,"1\nMSA")) +
  876. geom_vline(xintercept = 6.5, col = "red") +
  877. labs(x = "", y = "") -> p
  878. p
  879. ```
  880. Export source data
  881. ```{r, eval = F}
  882. p$data %>%
  883. write.table("source_data/F3e.tsv", sep = "\t", dec = ".", row.names = F)
  884. ```
  885. ## Figure 3f
  886. ```{r, fig.width = 7, fig.height = 5}
  887. stat.p <- cao_msa$test.results$expression.shifts$padjust %>%
  888. {data.frame(Type = names(.), padj = unname(.), value = 0.1)} %>%
  889. mutate(padj = formatC(padj, digits = 3))
  890. stat.p$padj[stat.p$padj > 0.05] <- ""
  891. cao_msa$plotExpressionShiftMagnitudes(show.pvalues = "none") +
  892. labs(y = "Normalized expression distance") +
  893. geom_text(data = stat.p, aes(label = padj)) -> p1
  894. stat.p <- cao_pd$test.results$expression.shifts$padjust %>%
  895. {data.frame(Type = names(.), padj = unname(.), value = 0.14)} %>%
  896. mutate(padj = formatC(padj, digits = 3))
  897. stat.p$padj[stat.p$padj > 0.05] <- ""
  898. cao_pd$plotExpressionShiftMagnitudes(show.pvalues = "none") +
  899. labs(y = "Normalized expression distance") +
  900. geom_text(data = stat.p, aes(label = padj)) -> p2
  901. stat.p <- cao_dis$test.results$expression.shifts$padjust %>%
  902. {data.frame(Type = names(.), padj = unname(.), value = 0.13)} %>%
  903. mutate(padj = formatC(padj, digits = 3))
  904. stat.p$padj[stat.p$padj > 0.05] <- ""
  905. cao_dis$plotExpressionShiftMagnitudes(show.pvalues = "none") +
  906. labs(y = "Normalized expression distance") +
  907. geom_text(data = stat.p, aes(label = padj)) -> p3
  908. p1
  909. p2
  910. p3
  911. ```
  912. Export source data
  913. ```{r, eval = F}
  914. p1$data %>%
  915. write.table("source_data/F3f1.tsv", sep = "\t", dec = ".", row.names = F)
  916. p2$data %>%
  917. write.table("source_data/F3f2.tsv", sep = "\t", dec = ".", row.names = F)
  918. p3$data %>%
  919. write.table("source_data/F3f3.tsv", sep = "\t", dec = ".", row.names = F)
  920. ```
  921. Export source data
  922. ```{r, eval = F}
  923. p$data %>%
  924. write.table("source_data/F1j.tsv", sep = "\t", dec = ".", row.names = F)
  925. ```
  926. ```{r, echo=F}
  927. rm(con.glia)
  928. gc()
  929. ```
  930. # Figure 4
  931. ## Figure 4a,b
  932. ```{r, fig.width=14, fig.height=5}
  933. cao_msa <- qread("cao_astro_msa.qs", nthreads = 10)
  934. cao_msa$plot.theme <- theme_bw()
  935. cao_pd <- qread("cao_astro_pd.qs", nthreads = 10)
  936. cao_pd$plot.theme <- theme_bw()
  937. cao_dis <- qread("cao_astro_dis.qs", nthreads = 10)
  938. cao_dis$plot.theme <- theme_bw()
  939. df.all <- Map(getOntWithFamily, list(cao_msa, cao_pd, cao_dis), c("CTRL vs. MSA", "CTRL vs. PD", "PD vs. MSA")) %>%
  940. lget("df.all") %>%
  941. bind_rows() %>%
  942. mutate(Group = paste0("AS_", strsplit(Group, "_") %>% sget(1) %>% tolower()))
  943. # Select relevant pathways
  944. p.ids <- c("GO:0050821", "GO:0050728", "GO:0006986", "GO:0030168", "GO:0030001", "GO:1904707", "GO:0140053", "GO:0006486", "GO:0010717", "GO:0031113", "GO:0032675", "GO:0061041", "GO:0071222", "GO:0045766", "GO:0006487", "GO:0097501", "GO:0042776", "GO:0045047", "GO:0044794", "GO:0035633", "GO:0097242", "GO:0006120", "GO:0042026", "GO:0006979", "GO:0071222", "GO:0017015", "GO:0009611", "GO:1901201", "GO:0042594", "GO:0097501", "GO:0006123", "GO:0006909", "GO:0007179", "GO:0006120", "GO:0097501")
  945. ```
  946. ### Figure 4a
  947. ```{r, fig.width=14, fig.height=3}
  948. ct <- "AS_homeostatic"
  949. df.sel <- df.all %>%
  950. filter(Group == ct)
  951. p1 <- ggplot(df.sel, aes(NES, logp, col = comp, shape = comp)) +
  952. geom_point(data = ~filter(., p.adjust > 0.05), size = 0.1, alpha = 0.5, col = "black") +
  953. geom_point(data = ~filter(., p.adjust <= 0.05), size = 2, alpha = 0.8) +
  954. theme_bw() +
  955. geom_hline(yintercept = -log10(0.05), linetype = "dashed") +
  956. scale_color_manual(values = pal.major) +
  957. theme(line = element_blank()) +
  958. labs(y = "-log10(adj. p)", shape = "Comparison", col = "Comparison") +
  959. dotSize(3)
  960. df <- Map(getOntWithFamily, list(cao_msa, cao_pd, cao_dis), c("CTRL vs. MSA", "CTRL vs. PD", "PD vs. MSA")) %>%
  961. lget("df") %>%
  962. bind_rows() %>%
  963. mutate(Group = paste0("AS_", strsplit(Group, "_") %>% sget(1) %>% tolower())) %>%
  964. filter(Group == ct,
  965. ID %in% p.ids)
  966. p2 <- df %>%
  967. filter(p.adjust <= 0.05, NES > 0) %>%
  968. mutate(Group = factor(Group, levels = sort(unique(Group)))) %>%
  969. select(Description, NES, Group, comp) %>%
  970. as.data.frame() %>%
  971. group_by(comp, Group) %>%
  972. group_split() %>%
  973. lapply(dplyr::slice, seq(5)) %>%
  974. bind_rows() %>%
  975. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  976. ggplot(aes(x, y, label = Description, col = comp)) +
  977. geom_text(hjust = 0) +
  978. theme_void() +
  979. xlim(0, 1) +
  980. labs(title = "Selected terms for up-regulated genes") +
  981. scale_color_manual(values = pal.major) +
  982. guides(col = "none")
  983. p3 <- df %>%
  984. filter(p.adjust <= 0.05, NES < 0) %>%
  985. select(Description, NES, Group, comp) %>%
  986. group_by(comp, Group) %>%
  987. group_split() %>%
  988. lapply(dplyr::slice, seq(5)) %>%
  989. bind_rows() %>%
  990. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  991. ggplot(aes(x, y, label = Description, col = comp)) +
  992. geom_text(hjust = 0) +
  993. theme_void() +
  994. xlim(0, 1) +
  995. labs(title = "Selected terms for down-regulated genes") +
  996. scale_color_manual(values = pal.major) +
  997. guides(col = "none")
  998. plot_grid(plotlist = list(p3, p1, p2), ncol = 3, rel_widths = c(0.9, 1, 0.9))
  999. ```
  1000. Export source data
  1001. ```{r, eval = F}
  1002. p1$data %>%
  1003. write.table("source_data/F4a.tsv", sep = "\t", dec = ".", row.names = F)
  1004. ```
  1005. ### Figure 4b
  1006. ```{r, fig.width=14, fig.height=3}
  1007. ct <- "AS_reactive"
  1008. df.sel <- df.all %>%
  1009. filter(Group == ct)
  1010. p1 <- ggplot(df.sel, aes(NES, logp, col = comp, shape = comp)) +
  1011. geom_point(data = ~filter(., p.adjust > 0.05), size = 0.1, alpha = 0.5, col = "black") +
  1012. geom_point(data = ~filter(., p.adjust <= 0.05), size = 2, alpha = 0.8) +
  1013. theme_bw() +
  1014. geom_hline(yintercept = -log10(0.05), linetype = "dashed") +
  1015. scale_color_manual(values = pal.major) +
  1016. theme(line = element_blank()) +
  1017. labs(y = "-log10(adj. p)", shape = "Comparison", col = "Comparison") +
  1018. dotSize(3)
  1019. df <- Map(getOntWithFamily, list(cao_msa, cao_pd, cao_dis), c("CTRL vs. MSA", "CTRL vs. PD", "PD vs. MSA")) %>%
  1020. lget("df") %>%
  1021. bind_rows() %>%
  1022. mutate(Group = paste0("AS_", strsplit(Group, "_") %>% sget(1) %>% tolower())) %>%
  1023. filter(Group == ct,
  1024. ID %in% p.ids)
  1025. p2 <- df %>%
  1026. filter(p.adjust <= 0.05, NES > 0) %>%
  1027. mutate(Group = factor(Group, levels = sort(unique(Group)))) %>%
  1028. select(Description, NES, Group, comp) %>%
  1029. group_by(comp, Group) %>%
  1030. group_split() %>%
  1031. lapply(dplyr::slice, seq(5)) %>%
  1032. bind_rows() %>%
  1033. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1034. ggplot(aes(x, y, label = Description, col = comp)) +
  1035. geom_text(hjust = 0) +
  1036. theme_void() +
  1037. xlim(0, 1) +
  1038. labs(title = "Selected terms for up-regulated genes") +
  1039. scale_color_manual(values = pal.major) +
  1040. guides(col = "none")
  1041. p3 <- df %>%
  1042. filter(p.adjust <= 0.05, NES < 0) %>%
  1043. select(Description, NES, Group, comp) %>%
  1044. group_by(comp, Group) %>%
  1045. group_split() %>%
  1046. lapply(dplyr::slice, seq(5)) %>%
  1047. bind_rows() %>%
  1048. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1049. ggplot(aes(x, y, label = Description, col = comp)) +
  1050. geom_text(hjust = 0) +
  1051. theme_void() +
  1052. xlim(0, 1) +
  1053. labs(title = "Selected terms for down-regulated genes") +
  1054. scale_color_manual(values = pal.major) +
  1055. guides(col = "none")
  1056. plot_grid(plotlist = list(p3, p1, p2), ncol = 3, rel_widths = c(0.9, 1, 0.9))
  1057. ```
  1058. ```{r, eval = F}
  1059. p1$data %>%
  1060. write.table("source_data/F4b.tsv", sep = "\t", dec = ".", row.names = F)
  1061. ```
  1062. ## Figure 4c
  1063. ```{r, fig.width=14, fig.height=3}
  1064. cao_msa <- qread("cao_oligo_msa.qs", nthreads = 10)
  1065. cao_msa$plot.theme <- theme_bw()
  1066. cao_pd <- qread("cao_oligo_pd.qs", nthreads = 10)
  1067. cao_pd$plot.theme <- theme_bw()
  1068. cao_dis <- qread("cao_oligo_dis.qs", nthreads = 10)
  1069. cao_dis$plot.theme <- theme_bw()
  1070. df.all <- Map(getOntWithFamily, list(cao_msa, cao_pd, cao_dis), c("CTRL vs. MSA", "CTRL vs. PD", "PD vs. MSA")) %>%
  1071. lget("df.all") %>%
  1072. bind_rows() %>%
  1073. mutate(Group = paste0("OL_", strsplit(Group, "_") %>% sget(2) %>% gsub("SCGZ", "SGCZ", .)))
  1074. # Select relevant pathways
  1075. p.ids <- c("GO:0071345", "GO:0045596", "GO:0060271", "GO:0048709", "GO:0006986", "GO:0016032", "GO:0060271", "GO:0042026", "GO:0006986", "GO:0120034", "GO:0071346", "GO:1904262", "GO:0042776", "GO:0061077", "GO:0050821", "GO:0045047", "GO:0042776", "GO:0050821", "GO:0045047", "GO:0007042", "GO:0042776", "GO:0061077", "GO:0045047", "GO:0042776", "GO:0045047", "GO:2000249", "GO:0002474", "GO:0042026", "GO:0002040", "GO:0046330", "GO:0043542", "GO:0030036", "GO:0032981", "GO:0007042")
  1076. ct <- "OL_SLC5A11"
  1077. df.sel <- df.all %>%
  1078. filter(Group == ct)
  1079. p1 <- ggplot(df.sel, aes(NES, logp, col = comp, shape = comp)) +
  1080. geom_point(data = ~filter(., p.adjust > 0.05), size = 0.1, alpha = 0.5, col = "black") +
  1081. geom_point(data = ~filter(., p.adjust <= 0.05), size = 2, alpha = 0.8) +
  1082. theme_bw() +
  1083. geom_hline(yintercept = -log10(0.05), linetype = "dashed") +
  1084. scale_color_manual(values = pal.major) +
  1085. theme(line = element_blank()) +
  1086. labs(y = "-log10(adj. p)", shape = "Comparison", col = "Comparison") +
  1087. dotSize(3)
  1088. df <- Map(getOntWithFamily, list(cao_msa, cao_pd, cao_dis), c("CTRL vs. MSA", "CTRL vs. PD", "PD vs. MSA")) %>%
  1089. lget("df") %>%
  1090. bind_rows() %>%
  1091. mutate(Group = paste0("OL_", strsplit(Group, "_") %>% sget(2) %>% gsub("SCGZ", "SGCZ", .))) %>%
  1092. filter(Group == ct,
  1093. ID %in% p.ids)
  1094. p2 <- df %>%
  1095. filter(p.adjust <= 0.05, NES > 0) %>%
  1096. mutate(Group = factor(Group, levels = sort(unique(Group)))) %>%
  1097. select(Description, NES, Group, comp) %>%
  1098. group_by(comp, Group) %>%
  1099. group_split() %>%
  1100. lapply(dplyr::slice, seq(5)) %>%
  1101. bind_rows() %>%
  1102. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1103. ggplot(aes(x, y, label = Description, col = comp)) +
  1104. geom_text(hjust = 0) +
  1105. theme_void() +
  1106. xlim(0, 1) +
  1107. labs(title = "Selected terms for up-regulated genes") +
  1108. scale_color_manual(values = pal.major) +
  1109. guides(col = "none")
  1110. p3 <- df %>%
  1111. filter(p.adjust <= 0.05, NES < 0) %>%
  1112. select(Description, NES, Group, comp) %>%
  1113. group_by(comp, Group) %>%
  1114. group_split() %>%
  1115. lapply(dplyr::slice, seq(5)) %>%
  1116. bind_rows() %>%
  1117. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1118. ggplot(aes(x, y, label = Description, col = comp)) +
  1119. geom_text(hjust = 0) +
  1120. theme_void() +
  1121. xlim(0, 1) +
  1122. labs(title = "Selected terms for down-regulated genes") +
  1123. scale_color_manual(values = pal.major) +
  1124. guides(col = "none")
  1125. plot_grid(plotlist = list(p3, p1, p2), ncol = 3, rel_widths = c(0.9, 1, 0.9))
  1126. ```
  1127. Export source data
  1128. ```{r, eval = F}
  1129. p1$data %>%
  1130. write.table("source_data/F4c.tsv", sep = "\t", dec = ".", row.names = F)
  1131. ```
  1132. ## Figure 4d,e
  1133. ```{r}
  1134. cm.merged <- con$getJointCountMatrix(raw = T) %>%
  1135. Matrix::t() %>%
  1136. .[, colnames(.) %in% names(anno.glia)]
  1137. # Create sample-wise annotation
  1138. anno.donor <- con$getDatasetPerCell()[colnames(cm.merged)]
  1139. anno.subtype <- anno.glia %>%
  1140. .[!is.na(.)] %>%
  1141. factor()
  1142. idx <- intersect(anno.donor %>% names(), anno.subtype %>% names())
  1143. anno.donor %<>% .[idx]
  1144. anno.subtype %<>% .[idx] %>%
  1145. {`names<-`(as.character(.), names(.))}
  1146. anno.final <- paste0(anno.donor,"!!",anno.subtype) %>%
  1147. `names<-`(anno.donor %>% names())
  1148. # Create pseudo CM
  1149. cm.pseudo <- sccore::collapseCellsByType(cm.merged %>% Matrix::t(),
  1150. groups = anno.final, min.cell.count = 1) %>%
  1151. t() %>%
  1152. apply(2, as, "integer")
  1153. cm.pseudo %<>%
  1154. {. + 1} %>%
  1155. DESeq2::DESeqDataSetFromMatrix(.,
  1156. colnames(.) %>%
  1157. strsplit("_") %>%
  1158. sget(1) %>%
  1159. data.frame() %>%
  1160. `dimnames<-`(list(colnames(cm.pseudo), "group")),
  1161. design = ~ group) %>%
  1162. DESeq2::estimateSizeFactors() %>%
  1163. DESeq2::counts(normalized = T)
  1164. ```
  1165. ### Figure 4d
  1166. ```{r, fig.width=4, fig.height=4}
  1167. # For DE between visits
  1168. genes <- "TLR1"
  1169. idx <- cm.pseudo %>%
  1170. colnames() %>%
  1171. data.frame(id = .) %>%
  1172. mutate(condition = strsplit(id, "_|!!") %>% sget(1),
  1173. ct = strsplit(id, "!!") %>% sget(2)) %>%
  1174. mutate(ord = order(condition, ct))
  1175. x <- cm.pseudo %>%
  1176. .[match(genes, rownames(.)), match(colnames(na.omit(.)), colnames(.))] %>%
  1177. .[idx$ord]
  1178. plot.dat <- x %>%
  1179. {data.frame(sample = names(.),
  1180. value = unname(.))} %>%
  1181. mutate(anno = strsplit(sample, "!!") %>%
  1182. sget(2),
  1183. condition = strsplit(sample, "!!|_") %>%
  1184. sget(1)) %>%
  1185. filter(anno %in% c("OL_LINC01608", "OL_SGCZ", "OL_SLC5A11")) %>%
  1186. mutate(anno = factor(anno))
  1187. stat.test <- plot.dat %>%
  1188. group_by(anno) %>%
  1189. rstatix::dunn_test(value ~ condition) %>%
  1190. rstatix::add_xy_position(x = "anno", step.increase = 0.1, fun = "mean_sd", scales = "free") %>%
  1191. mutate(p.adj = formatC(p.adj, digits = 2))
  1192. plot.dat %>%
  1193. ggplot(aes(anno, value)) +
  1194. geom_boxplot(aes(fill = condition)) +
  1195. theme_bw() +
  1196. theme(line = element_blank(),
  1197. axis.ticks.x = element_line(),
  1198. axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
  1199. labs(x = "", y = "Normalized pseudobulk expression", fill = "", title = "TLR1 expression") +
  1200. scale_fill_manual(values = pal.major) +
  1201. stat_compare_means(aes(fill = condition), method = "kruskal", label = "p.format", label.y = 8.5e2) +
  1202. stat_pvalue_manual(stat.test, label = "p.adj", hide.ns = T) -> p
  1203. p
  1204. ```
  1205. ```{r, eval = F}
  1206. p$data %>%
  1207. write.table("source_data/F4d.tsv", sep = "\t", dec = ".", row.names = F)
  1208. ```
  1209. ### Figure 4e
  1210. ```{r, fig.width=4, fig.height=4}
  1211. # For DE between visits
  1212. genes <- "LRP1"
  1213. idx <- cm.pseudo %>%
  1214. colnames() %>%
  1215. data.frame(id = .) %>%
  1216. mutate(condition = strsplit(id, "_|!!") %>% sget(1),
  1217. ct = strsplit(id, "!!") %>% sget(2)) %>%
  1218. mutate(ord = order(condition, ct))
  1219. x <- cm.pseudo %>%
  1220. .[match(genes, rownames(.)), match(colnames(na.omit(.)), colnames(.))] %>%
  1221. .[idx$ord]
  1222. plot.dat <- x %>%
  1223. {data.frame(sample = names(.),
  1224. value = unname(.))} %>%
  1225. mutate(anno = strsplit(sample, "!!") %>%
  1226. sget(2),
  1227. condition = strsplit(sample, "!!|_") %>%
  1228. sget(1)) %>%
  1229. filter(anno %in% c("OL_LINC01608", "OL_SGCZ", "OL_SLC5A11")) %>%
  1230. mutate(anno = factor(anno))
  1231. stat.test <- plot.dat %>%
  1232. group_by(anno) %>%
  1233. rstatix::wilcox_test(value ~ condition) %>%
  1234. rstatix::add_xy_position(x = "anno", step.increase = 0.05) %>%
  1235. mutate(p.adj = formatC(p.adj, digits = 2))
  1236. plot.dat %>%
  1237. ggplot(aes(anno, value)) +
  1238. geom_boxplot(aes(fill = condition)) +
  1239. theme_bw() +
  1240. theme(line = element_blank(),
  1241. axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
  1242. axis.ticks.x = element_line()) +
  1243. labs(x = "", y = "Normalized pseudobulk expression", fill = "", title = "LRP1 expression") +
  1244. scale_fill_manual(values = pal.major) +
  1245. stat_compare_means(aes(fill = condition), method = "kruskal", label = "p.format", label.y = 175) +
  1246. stat_pvalue_manual(stat.test, label = "p.adj", hide.ns = T) +
  1247. ylim(c(0, 180)) -> p
  1248. p
  1249. ```
  1250. Export source data
  1251. ```{r, eval = F}
  1252. p$data %>%
  1253. write.table("source_data/F4e.tsv", sep = "\t", dec = ".", row.names = F)
  1254. ```
  1255. ## Figure 4f
  1256. For calculation of data, see `Liana.ipynb`.
  1257. ```{r, fig.width=10, fig.height=8}
  1258. dat <- read.delim("liana_res.csv",
  1259. sep = ",",
  1260. header = T) %>%
  1261. mutate(group = strsplit(sample, "_") %>%
  1262. sget(1))
  1263. dat.plot <- dat %>%
  1264. dplyr::rename(ligand = ligand_complex,
  1265. receptor = receptor_complex,
  1266. score = lrscore) %>%
  1267. filter(target == "Oligodendrocytes",
  1268. ligand %in% c("BMP1", "SERPINE2", "PSAP", "APOE", "APP", "SERPING1"),
  1269. receptor %in% c("LRP1", "BMPR1A", "LRP4")) %>%
  1270. group_by(group, ligand, receptor, source, target) %>%
  1271. summarize(score = mean(score)) %>%
  1272. ungroup() %>%
  1273. arrange(group, source, target, ligand, receptor)
  1274. dat.msa <- dat.plot %>%
  1275. filter(group == "MSA",
  1276. score > 0.39) %>%
  1277. mutate(lrst = paste0(ligand, receptor, source, target))
  1278. dat.pd <- dat.plot %>%
  1279. mutate(lrst = paste0(ligand, receptor, source, target)) %>%
  1280. filter(group == "PD",
  1281. lrst %in% dat.msa$lrst)
  1282. dat.rel <- dat.msa %>%
  1283. mutate(score = score - dat.pd$score)
  1284. dat.rel %>%
  1285. lianaCircos()
  1286. ```
  1287. ```{r, eval = F}
  1288. dat.rel %>%
  1289. write.table("source_data/F4f.tsv", sep = "\t", dec = ".", row.names = F)
  1290. ```
  1291. # Figure 5 & SF14
  1292. ## Load data
  1293. ```{r}
  1294. cao <- qread("cao_micro_pvm.qs", nthreads = 10)
  1295. cao$plot.theme <- theme_bw()
  1296. cao_msa <- qread("cao_micro_pvm_msa.qs", nthreads = 10)
  1297. cao_msa$plot.theme <- theme_bw()
  1298. cao_pd <- qread("cao_micro_pvm_pd.qs", nthreads = 10)
  1299. cao_pd$plot.theme <- theme_bw()
  1300. cao_dis <- qread("cao_micro_pvm_dis.qs", nthreads = 10)
  1301. cao_dis$plot.theme <- theme_bw()
  1302. ```
  1303. ```{r}
  1304. sample.groups <- cao$sample.groups
  1305. ```
  1306. ## Figure 5a
  1307. ```{r}
  1308. cao$plotEmbedding(groups = anno.micro,
  1309. size = 0.5,
  1310. palette = pal.major,
  1311. font.size = 3,
  1312. raster = T,
  1313. mark.groups = T,
  1314. plot.na = F,
  1315. alpha = 0.2) +
  1316. labs(x="UMAP1", y= "UMAP2") +
  1317. theme(line = element_blank()) -> p
  1318. p
  1319. ```
  1320. ```{r, eval = F}
  1321. p$data %>%
  1322. write.table("source_data/F5a.tsv", sep = "\t", dec = ".", row.names = F)
  1323. ```
  1324. ## Figure 5b
  1325. ```{r, fig.width=4, fig.height=4}
  1326. cm.merged <- cao$data.object$getJointCountMatrix()
  1327. markers <- c("AIF1","F13A1","MRC1","CD163","CD74")
  1328. dotPlot(markers,
  1329. cm.merged,
  1330. cao$cell.groups,
  1331. cols = c("white","firebrick")) -> p
  1332. p
  1333. ```
  1334. Export source data
  1335. ```{r, eval = F}
  1336. p$data %>%
  1337. write.table("source_data/F5b.tsv", sep = "\t", dec = ".", row.names = F)
  1338. ```
  1339. ## Figure 5c-e & SF14
  1340. ```{r}
  1341. # anno.sort <- anno.micro[names(anno.micro) %in% rownames(cao$data.object$embedding)]
  1342. anno.sort <- anno.micro[rownames(cao$data.object$embedding)]
  1343. anno.sel <- anno.sort[!anno.sort %in% c("MIC_intermediate1", "PVMs")] %>% factor()
  1344. anno.sel2 <- anno.sort[!anno.sort %in% c("MIC_intermediate2", "MIC_activated")] %>% factor()
  1345. ldata1 <- getTscanTrajectory(cao$data.object, anno.sel)
  1346. ldata2 <- getTscanTrajectory(cao$data.object, anno.sel2)
  1347. ldata <- rbind(ldata1, ldata2)
  1348. ```
  1349. ### Figure 5c
  1350. ```{r}
  1351. cao$data.object$embedding %>%
  1352. as.data.frame() %>%
  1353. mutate(., unname(anno.micro[rownames(.)])) %>%
  1354. setNames(c("UMAP1", "UMAP2", "annotation")) %>%
  1355. ggplot() +
  1356. geom_point(aes(UMAP1, UMAP2, col = annotation), size = 0.3) +
  1357. geom_line(data = ldata, mapping=aes(UMAP1, UMAP2, group = edge), linewidth = 1) +
  1358. theme_bw() +
  1359. theme(legend.position = "right",
  1360. line = element_blank()) +
  1361. labs(col = "", x = "UMAP1", y = "UMAP2") +
  1362. scale_colour_manual(values = pal.major) +
  1363. dotSize(3) -> p
  1364. p
  1365. ```
  1366. Export source data
  1367. ```{r, eval = F}
  1368. n <- nrow(p$data)
  1369. cbind(p$data, p@layers$geom_line$data[seq_len(n), ]) %>%
  1370. write.table("source_data/F5c.tsv", sep = "\t", dec = ".", row.names = F)
  1371. ```
  1372. ## Figures 5d,e & SF14
  1373. Prepare data
  1374. ```{r}
  1375. emb <- cao$data.object$embedding %>%
  1376. `colnames<-`(c("UMAP1","UMAP2")) %>%
  1377. .[rownames(.) %in% names(anno.sel2), ]
  1378. sds_obj <- slingshot(emb,
  1379. anno.sel2,
  1380. start.clus = "MIC_steady-state",
  1381. stretch = 0
  1382. )
  1383. sds <- as.SlingshotDataSet(sds_obj)
  1384. pseudotime <- sds_obj@assays@data@listData$pseudotime[, 1]
  1385. ```
  1386. Here, we show the code for running the generalized additive mixed model. It takes a significant amount of time to run, we provide data in `pseudotime_micro_l2.qs`.
  1387. ```{r, eval = F}
  1388. mat <- cao$data.object$getJointCountMatrix() %>%
  1389. .[match(names(sds_obj), rownames(.)), colSums(.) > 2e2] %>%
  1390. .[, !grepl(pattern = "RPL|RPS|MT-", colnames(.))]
  1391. mt <- mat %>%
  1392. as.matrix() %>%
  1393. as.data.frame() %>%
  1394. tibble::rownames_to_column() %>%
  1395. {message("Mutating"); mutate(.,
  1396. pseudotime = pseudotime[rowname],
  1397. condition = cao$data.object$getDatasetPerCell()[rowname] %>%
  1398. as.character() %>%
  1399. strsplit("_") %>%
  1400. sget(1),
  1401. sample = strsplit(rowname, "!!") %>%
  1402. sget(1))} %>%
  1403. .[complete.cases(.), ] %>%
  1404. {message("Melting"); reshape2::melt(., id.vars = c("rowname", "pseudotime", "condition", "sample"))} %$%
  1405. {message("Splitting"); split(., variable)}
  1406. ```
  1407. ```{r, eval = F}
  1408. res <- mt %>%
  1409. sccore::plapply(\(x) {
  1410. fit_full <- gamm4(data = x, formula = value ~ s(pseudotime, by = factor(condition)), random = ~(1 | sample), REML = F)
  1411. fit_reduced <- gamm4(data = x, formula = value ~ s(pseudotime), random = ~(1 | sample), REML = F)
  1412. fit_none <- gamm4(data = x, formula = value ~ 1, random = ~(1 | sample), REML = F)
  1413. ann <- anova(fit_full$mer, fit_reduced$mer, fit_none$mer)
  1414. if (any(ann$`Pr(>Chisq)` <= 0.05, na.rm = T)) {
  1415. residuals <- predict(fit_full$gam, se.fit = T)$fit %>%
  1416. unname()
  1417. r.sq <- c(summary(fit_full$gam)$r.sq, summary(fit_reduced$gam)$r.sq) %>%
  1418. setNames(c("full", "reduced"))
  1419. out <- list(anova = ann,
  1420. residuals = residuals,
  1421. r.sq = r.sq)
  1422. return(out)
  1423. }
  1424. }, n.cores = 40, mc.preschedule = T, mc.cleanup = T, progress = F) %>%
  1425. .[!sapply(., is.null)]
  1426. qsave(res, "pseudotime_micro_l2.qs")
  1427. ```
  1428. ### Figure 5d
  1429. ```{r}
  1430. cao$data.object$embedding %>%
  1431. as.data.frame() %>%
  1432. mutate(., unname(anno.micro[rownames(.)])) %>%
  1433. setNames(c("UMAP1", "UMAP2", "annotation")) %>%
  1434. mutate(., pseudotime = pseudotime[rownames(.)]) %>%
  1435. ggplot() +
  1436. geom_point(aes(UMAP1, UMAP2, col = pseudotime), size = 0.3) +
  1437. geom_line(data = ldata2, aes(UMAP1, UMAP2, group = edge), linewidth = 1) +
  1438. theme_bw() +
  1439. theme(line = element_blank()) +
  1440. scale_color_gradient(low = "navyblue", high = "orange") +
  1441. labs(col = "Pseudotime", x = "UMAP1", y = "UMAP2") -> p
  1442. p
  1443. ```
  1444. Export source data
  1445. ```{r, eval = F}
  1446. n <- nrow(p$data)
  1447. cbind(p$data, p@layers$geom_line$data[seq_len(n), ]) %>%
  1448. write.table("source_data/F5d.tsv", sep = "\t", dec = ".", row.names = F)
  1449. ```
  1450. ### Figure 5e & SF14
  1451. Please note, row order may change per iteration.
  1452. ```{r, fig.height=4, fig.width=4}
  1453. res <- qread("pseudotime_micro_l2.qs")
  1454. rsq.pseudo <- res %>%
  1455. sapply(\(gene) gene$r.sq[1]) %>%
  1456. sort(decreasing = T)
  1457. res.filter <- res[names(rsq.pseudo)[seq(50)] %>% strsplit(".", fixed = T) %>% sget(1)]
  1458. cm.merged <- cao$data.object$getJointCountMatrix() %>%
  1459. .[match(names(pseudotime), rownames(.)), colnames(.) %in% names(res.filter)] %>%
  1460. .[rowSums(.) > 0, ]
  1461. ## Predict smoothend expression
  1462. pseudotime.both <- pseudotime[rownames(cm.merged)]
  1463. weights.both <- sds_obj@assays@data@listData$weights %>% .[match(names(pseudotime.both), rownames(.)), 1] + 1E-7
  1464. scFit <- cm.merged %>%
  1465. Matrix::t() %>%
  1466. tradeSeq::fitGAM(pseudotime = pseudotime.both, cellWeights = weights.both, verbose = T)
  1467. Smooth <- tradeSeq::predictSmooth(scFit, gene = colnames(cm.merged), tidy = F, n=100)
  1468. # Average across replicates and scale
  1469. Smooth <- t(scale(t(Smooth)))
  1470. # Seriate the results
  1471. Smooth <- Smooth[ seriation::get_order(seriation::seriate(Smooth, method="PCA_angle")), ]
  1472. ```
  1473. #### Figure 5e
  1474. ```{r, fig.height=4, fig.width=4}
  1475. # Create heatmap
  1476. col_fun = circlize::colorRamp2(c(-4, 0, 4), c("navy", "white", "firebrick"))
  1477. Heatmap(Smooth,
  1478. col = col_fun,
  1479. cluster_columns=F,
  1480. cluster_rows=F,
  1481. show_column_names = F,
  1482. row_names_gp = grid::gpar(fontsize = 5)) -> p
  1483. p
  1484. ```
  1485. Export source data
  1486. ```{r, eval = F}
  1487. p@matrix %>%
  1488. write.table("source_data/F5e.tsv", sep = "\t", dec = ".", row.names = F)
  1489. ```
  1490. ```{r, echo = F}
  1491. rm(cao)
  1492. gc()
  1493. ```
  1494. #### Supplementary Figure 14
  1495. We provide this figure here since all data are already loaded.
  1496. ```{r, fig.height=40, fig.width=20}
  1497. cpc <- pseudotime %>%
  1498. names() %>%
  1499. strsplit("_") %>%
  1500. sget(1) %>%
  1501. factor()
  1502. res[rownames(Smooth)] %>%
  1503. lget("residuals") %>%
  1504. lapply(as.data.frame) %>%
  1505. lapply(setNames, "residuals") %>%
  1506. lapply(mutate, group = cpc, pseudotime = pseudotime) %>%
  1507. data.table::rbindlist(idcol = "gene") %>%
  1508. ggplot(aes(pseudotime, residuals, col = group)) +
  1509. geom_smooth() +
  1510. theme_bw() +
  1511. facet_wrap(~gene, ncol = 5, scales = "free") -> p
  1512. p
  1513. ```
  1514. Export source data
  1515. ```{r, eval = F}
  1516. p$data %>%
  1517. write.table("source_data/SF14.tsv", sep = "\t", dec = ".", row.names = F)
  1518. ```
  1519. ## Figure 5f
  1520. ```{r, fig.height=4, fig.width=3}
  1521. cao_msa$plotCellLoadings(show.pvals = F,
  1522. alpha = 0)$data %>%
  1523. ggplot(aes(ind, values, fill = ind)) +
  1524. geom_hline(yintercept = 0, col = "black") +
  1525. geom_violin() +
  1526. coord_flip() +
  1527. theme_bw() +
  1528. scale_fill_manual(values = pal.major) +
  1529. theme(legend.position = "none") +
  1530. scale_y_continuous(breaks = c(-1,0,1),
  1531. limits = c(-1,1),
  1532. labels = c("-1\nCTRL",0,"1\nMSA")) +
  1533. geom_vline(xintercept = 4.5, col = "red") +
  1534. labs(x = "", y = "") +
  1535. theme(line = element_blank()) -> p
  1536. p
  1537. ```
  1538. ```{r, eval = F}
  1539. p$data %>%
  1540. write.table("source_data/F5f.tsv", sep = "\t", dec = ".", row.names = F)
  1541. ```
  1542. ## Figure 5g
  1543. ```{r, fig.height=4, fig.width=3}
  1544. cao_pd$plotCellLoadings(show.pvals = F,
  1545. alpha = 0)$data %>%
  1546. ggplot(aes(ind, values, fill = ind)) +
  1547. geom_hline(yintercept = 0, col = "black") +
  1548. geom_violin() +
  1549. coord_flip() +
  1550. theme_bw() +
  1551. scale_fill_manual(values = pal.major) +
  1552. theme(legend.position = "none") +
  1553. scale_y_continuous(breaks = c(-1,0,1),
  1554. limits = c(-1,1.1),
  1555. labels = c("-1\nCTRL",0,"1\nPD")) +
  1556. geom_vline(xintercept = 4.5, col = "red") +
  1557. labs(x = "", y = "") +
  1558. theme(line = element_blank()) -> p
  1559. p
  1560. ```
  1561. Export source data
  1562. ```{r, eval = F}
  1563. p$data %>%
  1564. write.table("source_data/F5g.tsv", sep = "\t", dec = ".", row.names = F)
  1565. ```
  1566. ## Figure 5h
  1567. ```{r, fig.height=4, fig.width=3}
  1568. cao_dis$plotCellLoadings(show.pvals = F,
  1569. alpha = 0)$data %>%
  1570. ggplot(aes(ind, values, fill = ind)) +
  1571. geom_hline(yintercept = 0, col = "black") +
  1572. geom_violin() +
  1573. coord_flip() +
  1574. theme_bw() +
  1575. scale_fill_manual(values = pal.major) +
  1576. theme(legend.position = "none") +
  1577. scale_y_continuous(breaks = c(-1,0,1),
  1578. limits = c(-1.2,1),
  1579. labels = c("-1\nPD",0,"1\nMSA")) +
  1580. geom_vline(xintercept = 3.5, col = "red") +
  1581. labs(x = "", y = "") +
  1582. theme(line = element_blank()) -> p
  1583. p
  1584. ```
  1585. ```{r, eval = F}
  1586. p$data %>%
  1587. write.table("source_data/F5h.tsv", sep = "\t", dec = ".", row.names = F)
  1588. ```
  1589. ```{r, echo = F}
  1590. rm(cao_dis)
  1591. gc()
  1592. ```
  1593. ## Figure 5j
  1594. We provide combined data from the RNAscope experiments as a single file `res.qs`.
  1595. ```{r}
  1596. res <- qread("RNAscope.qs") %>%
  1597. filter(target == "AIF1", Ch1NumSpots > 0) %>%
  1598. arrange(file)
  1599. area <- read.table("RNAscope_areas.tsv", sep = "\t", header = T) %>% # Million pixels
  1600. mutate(file = paste(File.name, Tissue, sep = "")) %>%
  1601. filter(file %in% res$file) %>%
  1602. arrange(file) %>%
  1603. mutate(rel_px = px.2 / 1E6)
  1604. ```
  1605. ```{r, fig.width=4, fig.height=8}
  1606. p1 <- res %>%
  1607. group_by(group, target, file) %>%
  1608. summarize(spots = mean(Ch1NumSpots)) %>%
  1609. ggplot(aes(group, spots, fill = group)) +
  1610. geom_boxplot() +
  1611. geom_jitter(width = 0.2) +
  1612. theme_bw() +
  1613. labs(y = "Mean no. spots per double-positive cell", x = "") +
  1614. stat_compare_means(method = "kruskal.test", label.y = 115) +
  1615. stat_compare_means(comparisons = comp, method = "wilcox.test") +
  1616. theme(line = element_blank()) +
  1617. guides(fill = "none") +
  1618. scale_fill_manual(values = pal.major)
  1619. p2 <- res %>%
  1620. group_by(group, target, file) %>%
  1621. summarize(no_cells = n()) %>%
  1622. as.data.frame() %>%
  1623. arrange(file) %>%
  1624. mutate(rel_cells = no_cells / area$rel_px) %>%
  1625. ggplot(aes(group, rel_cells, fill = group)) +
  1626. geom_boxplot(outliers = F) +
  1627. geom_jitter(width = 0.2) +
  1628. theme_bw() +
  1629. stat_compare_means(method = "kruskal.test", label.y = 17) +
  1630. stat_compare_means(comparisons = comp, method = "wilcox.test") +
  1631. labs(y = "No. double-positive cells\nNormalized to area", x = "") +
  1632. theme(line = element_blank()) +
  1633. guides(fill = "none") +
  1634. scale_fill_manual(values = pal.major)
  1635. plot_grid(plotlist = list(p1, p2), ncol = 1)
  1636. ```
  1637. Export source data
  1638. ```{r, eval = F}
  1639. p1$data %>%
  1640. write.table("source_data/F5j1.tsv", sep = "\t", dec = ".", row.names = F)
  1641. p2$data %>%
  1642. write.table("source_data/F5j2.tsv", sep = "\t", dec = ".", row.names = F)
  1643. ```
  1644. ## Figure 5k
  1645. ```{r, fig.width=12, fig.height=3}
  1646. fams <- cao_msa$test.results[["GSEA"]]$families
  1647. df.all <- list(cao_msa$.__enclos_env__$private$getOntologyPvalueResults(name = "GSEA", genes = "up", p.adj = 1, q.value = 1),
  1648. cao_msa$.__enclos_env__$private$getOntologyPvalueResults(name = "GSEA", genes = "down", p.adj = 1, q.value = 1)) %>%
  1649. bind_rows() %>%
  1650. mutate(logp = -log10(p.adjust))
  1651. # Relevant pathways
  1652. p.ids <- c("GO:0060760", "GO:0002230", "GO:0019915", "GO:1904646", "GO:0042775", "GO:0019646", "GO:0033108", "GO:0035455", "GO:0061077", "GO:0006914", "GO:0042026", "GO:0034340", "GO:0051607", "GO:0060337", "GO:0035455", "GO:0002684", "GO:0036037", "GO:0048514")
  1653. df <- cacoa:::getOntologyFamilyChildren(df.all, fams=fams, type = "GSEA", subtype = "BP") %>%
  1654. mutate(Group = paste0("MIC_", tolower(Group)) %>% gsub("MIC_pvms", "PVMs", .)) %>%
  1655. filter(ID %in% p.ids)
  1656. df.all %<>% mutate(Group = paste0("MIC_", tolower(Group)) %>% gsub("MIC_pvms", "PVMs", .))
  1657. p1 <- ggplot(df.all, aes(NES, logp, col = Group, shape = Group)) +
  1658. geom_point(data = ~filter(., p.adjust > 0.05), size = 0.1, alpha = 0.5, col = "black") +
  1659. geom_point(data = ~filter(., p.adjust <= 0.05), size = 2, alpha = 0.5) +
  1660. theme_bw() +
  1661. geom_hline(yintercept = -log10(0.05), linetype = "dashed") +
  1662. scale_color_manual(values = pal.major) +
  1663. theme(line = element_blank()) +
  1664. labs(y = "-log10(adj. p)") +
  1665. dotSize(3)
  1666. p2 <- df %>%
  1667. filter(p.adjust <= 0.05, NES > 0) %>%
  1668. mutate(Group = factor(Group, levels = sort(unique(Group)))) %>%
  1669. select(Description, NES, Group) %$%
  1670. split(., Group) %>%
  1671. lapply(dplyr::slice, seq(5)) %>%
  1672. bind_rows() %>%
  1673. dplyr::slice(seq(25)) %>%
  1674. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1675. ggplot(aes(x, y, label = Description, col = Group)) +
  1676. geom_text(hjust = 0) +
  1677. theme_void() +
  1678. xlim(0, 1) +
  1679. labs(title = "Selected terms for up-regulated genes") +
  1680. scale_color_manual(values = pal.major) +
  1681. guides(col = "none")
  1682. p3 <- df %>%
  1683. filter(p.adjust <= 0.05, NES < 0) %>%
  1684. select(Description, NES, Group) %>%
  1685. dplyr::slice(seq(20)) %>%
  1686. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1687. ggplot(aes(x, y, label = Description, col = Group)) +
  1688. geom_text(hjust = 0) +
  1689. theme_void() +
  1690. xlim(0, 1) +
  1691. labs(title = "Selected terms for down-regulated genes") +
  1692. scale_color_manual(values = pal.major) +
  1693. guides(col = "none")
  1694. plot_grid(plotlist = list(p3, p1, p2), ncol = 3, rel_widths = c(0.9, 1, 0.9))
  1695. ```
  1696. ```{r, eval = F}
  1697. p1$data %>%
  1698. write.table("source_data/F5k.tsv", sep = "\t", dec = ".", row.names = F)
  1699. ```
  1700. ```{r, echo = F}
  1701. rm(cao_msa)
  1702. gc()
  1703. ```
  1704. ## Figure 5l
  1705. ```{r, fig.width=12, fig.height=3}
  1706. fams <- cao_pd$test.results[["GSEA"]]$families
  1707. df.all <- list(cao_pd$.__enclos_env__$private$getOntologyPvalueResults(name = "GSEA", genes = "up", p.adj = 1, q.value = 1),
  1708. cao_pd$.__enclos_env__$private$getOntologyPvalueResults(name = "GSEA", genes = "down", p.adj = 1, q.value = 1)) %>%
  1709. bind_rows() %>%
  1710. mutate(logp = -log10(p.adjust))
  1711. # Select relevant pathways
  1712. p.ids <- c("GO:0042776", "GO:0034341", "GO:0001916", "GO:0002503", "GO:0019885", "GO:0016042", "GO:0001909", "GO:0051085", "GO:0045824", "GO:0044000", "GO:0019885", "GO:0044242", "GO:0001944", "GO:0034976", "GO:0019646", "GO:0009205", "GO:0019883", "GO:0070972", "GO:0002474")
  1713. df <- cacoa:::getOntologyFamilyChildren(df.all, fams=fams, type = "GSEA", subtype = "BP") %>%
  1714. mutate(Group = paste0("MIC_", tolower(Group)) %>% gsub("MIC_pvms", "PVMs", .)) %>%
  1715. filter(ID %in% p.ids)
  1716. df.all %<>% mutate(Group = paste0("MIC_", tolower(Group)) %>% gsub("MIC_pvms", "PVMs", .))
  1717. p1 <- ggplot(df.all, aes(NES, logp, col = Group, shape = Group)) +
  1718. geom_point(data = ~filter(., p.adjust > 0.05), size = 0.1, alpha = 0.5, col = "black") +
  1719. geom_point(data = ~filter(., p.adjust <= 0.05), size = 2, alpha = 0.5) +
  1720. theme_bw() +
  1721. geom_hline(yintercept = -log10(0.05), linetype = "dashed") +
  1722. scale_color_manual(values = pal.major) +
  1723. theme(line = element_blank()) +
  1724. labs(y = "-log10(adj. p)") +
  1725. dotSize(3)
  1726. p2 <- df %>%
  1727. filter(p.adjust <= 0.05, NES > 0) %>%
  1728. select(Description, NES, Group) %$%
  1729. split(., Group) %>%
  1730. lapply(dplyr::slice, seq(5)) %>%
  1731. bind_rows() %>%
  1732. dplyr::slice(seq(25)) %>%
  1733. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1734. ggplot(aes(x, y, label = Description, col = Group)) +
  1735. geom_text(hjust = 0) +
  1736. theme_void() +
  1737. xlim(0, 1) +
  1738. labs(title = "Selected terms for up-regulated genes") +
  1739. scale_color_manual(values = pal.major) +
  1740. guides(col = "none")
  1741. p3 <- df %>%
  1742. filter(p.adjust <= 0.05, NES < 0) %>%
  1743. select(Description, NES, Group) %$%
  1744. split(., Group) %>%
  1745. lapply(dplyr::slice, seq(5)) %>%
  1746. bind_rows() %>%
  1747. dplyr::slice(seq(25)) %>%
  1748. mutate(., x = 0, y = rev(seq(nrow(.)))) %>%
  1749. ggplot(aes(x, y, label = Description, col = Group)) +
  1750. geom_text(hjust = 0) +
  1751. theme_void() +
  1752. xlim(0, 1) +
  1753. labs(title = "Selected terms for down-regulated genes") +
  1754. scale_color_manual(values = pal.major) +
  1755. guides(col = "none")
  1756. plot_grid(plotlist = list(p3, p1, p2), ncol = 3, rel_widths = c(0.9, 1, 0.9))
  1757. ```
  1758. Export source data
  1759. ```{r, eval = F}
  1760. p1$data %>%
  1761. write.table("source_data/F5l.tsv", sep = "\t", dec = ".", row.names = F)
  1762. ```
  1763. ```{r, echo = F}
  1764. rm(cao_pd)
  1765. gc()
  1766. ```
  1767. # Figure 6
  1768. Figures 6c,e,f where made with GraphPad Prism. Data are available in `Phagocytosis_assay_triplicates_raw_data_HH.tsv` (Copenhagen experiment) or `HOUSTON.tsv` (Houston experiment).
  1769. ## Figure 6b
  1770. ```{r, fig.height=4, fig.width=5}
  1771. dat <- read.delim("Phagocytosis_assay_triplicates_raw_data_HH.tsv",
  1772. header = T, dec = ",") %>%
  1773. tidyr::pivot_longer(names_to = "group", cols = -1, values_to = "value") %>%
  1774. mutate(group = gsub(".1|.2", "", group) %>% factor(labels = c("PBS","LPS","MSA CSF","CTRL CSF","PD CSF"))) %>%
  1775. mutate(group = factor(group, levels = c("PBS","LPS","CTRL CSF","MSA CSF","PD CSF"))) %>%
  1776. group_by(Time, group) %>%
  1777. summarize(mean = mean(value, na.rm = T),
  1778. sd = sd(value, na.rm = T))
  1779. dat %>%
  1780. ggplot(aes(Time, mean, group=group, color=group)) +
  1781. geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), width=.1) +
  1782. geom_point(size = 0.5) +
  1783. theme_bw() +
  1784. labs(x = "Time (hours)", y = "pHrodo-labelled E. coli uptake - intensity ratio [AU]", col = "Stimulation") +
  1785. scale_color_manual(values = pal.major) +
  1786. theme(line = element_blank()) -> p
  1787. p
  1788. ```
  1789. ```{r, eval = F}
  1790. p$data %>%
  1791. write.table("source_data/F6b.tsv", sep = "\t", dec = ".", row.names = F)
  1792. ```
  1793. ## Figure 6d & Supplementary Dataset 15
  1794. ```{r}
  1795. dat.raw <- read.table("Cytokine_summary.tsv", header = TRUE, sep = "\t", dec = ",")
  1796. dat.tmp <- dat.raw %>%
  1797. melt(id.vars = c("Sample","Group","Condition")) %>%
  1798. mutate(variable = variable %>%
  1799. as.character() %>%
  1800. gsub(".", "-", ., fixed = T) %>%
  1801. as.factor()) %>%
  1802. filter(Condition == "CSF",
  1803. !variable %in% c("IL-8", "protein"), # IL-8 was not within detection limits, protein has no influence on IL-10 or -13 according to lm()
  1804. Group != "LPS") %>% # LPS is not relevant for post-CSF measurements
  1805. mutate(Group = Group %>% factor(levels = c("CTRL","MSA","PD")),
  1806. variable = variable %>% factor())
  1807. # IL-10 and -13 are nominally significant
  1808. stat.test <- dat.tmp %>%
  1809. dplyr::select(Group, value, variable) %>%
  1810. group_by(variable) %>%
  1811. rstatix::kruskal_test(value ~ Group) %>%
  1812. arrange(p)
  1813. ```
  1814. ### Figure 6d
  1815. ```{r, fig.width=4, fig.height=4}
  1816. post.test <- dat.tmp %>%
  1817. dplyr::select(Group, value, variable) %>%
  1818. filter(variable %in% c("IL-10", "IL-13")) %>%
  1819. # filter(variable %in% c("IL-10")) %>%
  1820. dplyr::rename(var = variable) %>%
  1821. group_by(var) %>%
  1822. dunn_test(value ~ Group) %>%
  1823. rstatix::add_xy_position(x = "Group") %>%
  1824. dplyr::rename(variable = var) %>%
  1825. mutate(p = format(p, digits = 3))
  1826. dat.tmp %>%
  1827. filter(variable %in% c("IL-10")) %>%
  1828. ggplot(aes(Group, value)) +
  1829. geom_point(aes(fill = Group), size = 3, position = position_jitter(width = 0.3), pch = 21, color = "black") +
  1830. theme_bw() +
  1831. theme(line = element_blank()) +
  1832. stat_pvalue_manual(post.test %>% filter(variable == "IL-10"), tip.length = 0.01, bracket.nudge.y = 3, hide.ns = F, label = "p") +
  1833. scale_fill_manual(values = pal.major) +
  1834. labs(x = "", y = "pg/mL") +
  1835. guides(col = "none", fill = "none") +
  1836. # facet_wrap(~variable, scales = "free") +
  1837. guides(fil = "none") -> p
  1838. p
  1839. ```
  1840. Export source data
  1841. ```{r, eval = F}
  1842. p$data %>%
  1843. write.table("source_data/F6d.tsv", sep = "\t", dec = ".", row.names = F)
  1844. ```
  1845. ### Supplementary Dataset 15
  1846. ```{r, eval = F}
  1847. stat.test %>%
  1848. write.table("SupplementaryDataset15.tsv", sep = "\t", dec = ".", row.names = F)
  1849. post.test %>%
  1850. dplyr::select(-groups) %>%
  1851. write.table("SD15_post.tsv", sep = "\t", dec = ".", row.names = F)
  1852. ```
  1853. ## Figures 6g-i
  1854. ```{r}
  1855. dat.melt <- read.table("Microglia+CSF_samples_aSyn_sCD163.tsv", header = T, sep = "\t", dec = ",") %>%
  1856. melt(id.vars = c("diagnosis", "sex")) %>%
  1857. mutate(diagnosis = factor(diagnosis, levels = c("CTRL","MSA","IPD"), labels = c("CTRL","MSA","PD")))
  1858. ```
  1859. ### Figure 6g
  1860. ```{r, fig.width=4, fig.height=4}
  1861. dat.melt %>%
  1862. filter(variable == "sCD163_ng.mL_CSF") %>%
  1863. ggplot(aes(diagnosis, value)) +
  1864. geom_boxplot(aes(fill = diagnosis)) +
  1865. theme_bw() +
  1866. labs(x = "", y = "sCD163 ng/ml", fill = "Diagnosis") +
  1867. scale_fill_manual(values = pal.major) +
  1868. stat_compare_means(method = "t.test", comparisons = list(c("CTRL","MSA"), c("MSA","PD"), c("CTRL","PD"))) +
  1869. guides(fill = "none") +
  1870. theme(line = element_blank()) -> p
  1871. p
  1872. ```
  1873. Export source data
  1874. ```{r, eval = F}
  1875. p$data %>%
  1876. write.table("source_data/F6g.tsv", sep = "\t", dec = ".", row.names = F)
  1877. ```
  1878. ### Figure 6h
  1879. ```{r, fig.width=4, fig.height=4}
  1880. dat.melt %>%
  1881. filter(variable == "aSyn_pg.mL") %>%
  1882. ggplot(aes(diagnosis, value)) +
  1883. geom_boxplot(aes(fill = diagnosis)) +
  1884. theme_bw() +
  1885. labs(x = "", y = "aSyn pg/ml", fill = "Diagnosis") +
  1886. scale_fill_manual(values = pal.major) +
  1887. stat_compare_means(method = "t.test", comparisons = list(c("CTRL","MSA"), c("MSA","PD"), c("CTRL","PD"))) +
  1888. guides(fill = "none") +
  1889. theme(line = element_blank()) -> p
  1890. p
  1891. ```
  1892. ```{r, eval = F}
  1893. p$data %>%
  1894. write.table("source_data/F6h.tsv", sep = "\t", dec = ".", row.names = F)
  1895. ```
  1896. ### Figure 6i
  1897. ```{r, fig.width=4, fig.height=4}
  1898. dat.melt %>%
  1899. filter(variable %in% c("aSyn_pg.mL","sCD163_ng.mL_CSF")) %>%
  1900. select(-sex) %>%
  1901. mutate(id = rep(seq(63), 2)) %>%
  1902. tidyr::pivot_wider(names_from = variable, values_from = value) %>%
  1903. ggplot(aes(aSyn_pg.mL, sCD163_ng.mL_CSF)) +
  1904. geom_point(aes(fill = diagnosis), pch = 21, color = "black") +
  1905. theme_bw() +
  1906. labs(x = "aSyn pg/ml", y = "sCD163, ng/ml", fill = "") +
  1907. geom_smooth(method = MASS::rlm, se = FALSE, color = "black") +
  1908. stat_poly_eq(aes(label = paste(after_stat(rr.label), after_stat(p.value.label), sep = "*\", \"*")), color = "black") +
  1909. scale_fill_manual(values = pal.major) +
  1910. theme(line = element_blank()) -> p
  1911. p
  1912. ```
  1913. Export source data
  1914. ```{r, eval = F}
  1915. p$data %>%
  1916. write.table("source_data/F6i.tsv", sep = "\t", dec = ".", row.names = F)
  1917. ```
  1918. ## Figure 6j
  1919. Here, we use data from [Rydbirk *et al*.](https://pmc.ncbi.nlm.nih.gov/articles/PMC9164190/) on differentially expressed proteins in the soluble fraction of CSF pools.
  1920. ```{r, fig.width=6, fig.height=4}
  1921. dat <- read.delim("Soluble_fraction.txt")
  1922. msa.dep <- dat %>%
  1923. filter(Disease.group == "MSA") %>%
  1924. pull(Gene.name)
  1925. pd.dep <- dat %>%
  1926. filter(Disease.group == "PD") %>%
  1927. pull(Gene.name)
  1928. overlap <- intersect(msa.dep, pd.dep)
  1929. highlight_proteins <- c("CTSS", "FCGR2A", "LAMP1", "CTSD", "CLTC") # From suppl. table 14, KEGG phagosome or lysosome pathways
  1930. msa.dep %<>% .[!. %in% overlap]
  1931. pd.dep %<>% .[!. %in% overlap]
  1932. overlap %<>% .[!. %in% highlight_proteins]
  1933. string_db <- STRINGdb$new(
  1934. version = "12.0", # or latest available
  1935. species = 9606, # 9606 = Homo sapiens
  1936. score_threshold = 400, # confidence score cutoff
  1937. input_directory = ""
  1938. )
  1939. genes <- c(msa.dep, pd.dep, overlap, highlight_proteins) %>% unique()
  1940. mapped_genes <- string_db$map(
  1941. data.frame(gene = genes),
  1942. "gene",
  1943. removeUnmappedRows = TRUE
  1944. )
  1945. # Get interactions
  1946. interactions <- string_db$get_interactions(mapped_genes$STRING_id)
  1947. # Convert to igraph object
  1948. ppi_graph <- graph_from_data_frame(interactions, directed = FALSE)
  1949. # Create label mapping: STRING ID to gene name
  1950. string_to_gene <- mapped_genes %>%
  1951. select(STRING_id, gene) %>%
  1952. distinct()
  1953. # Add labels to graph nodes
  1954. V(ppi_graph)$label <- string_to_gene$gene[match(V(ppi_graph)$name, string_to_gene$STRING_id)]
  1955. custom_colors <- c(
  1956. "CTSS" = "firebrick",
  1957. "FCGR2A" = "purple2",
  1958. "LAMP1" = "purple2",
  1959. "CTSD" = "navyblue",
  1960. "CLTC" = "navyblue",
  1961. setNames(rep("tomato", length(msa.dep)), msa.dep),
  1962. setNames(rep("steelblue", length(pd.dep)), pd.dep),
  1963. setNames(rep("orchid", length(overlap)), overlap))
  1964. # Apply color mapping to node attributes
  1965. V(ppi_graph)$node_color <- custom_colors[V(ppi_graph)$label]
  1966. # Get node labels for each edge endpoint
  1967. edge_ends <- ends(ppi_graph, es = E(ppi_graph), names = FALSE)
  1968. source_labels <- V(ppi_graph)$label[edge_ends[, 1]]
  1969. target_labels <- V(ppi_graph)$label[edge_ends[, 2]]
  1970. # Assign edge width
  1971. E(ppi_graph)$edge_width <- ifelse(
  1972. source_labels %in% highlight_proteins & target_labels %in% highlight_proteins,
  1973. 0.5, 0.1
  1974. )
  1975. # Compute node sizes based on label
  1976. V(ppi_graph)$node_size <- sapply(V(ppi_graph)$label, \(x) if (x %in% overlap) 3 else if (x %in% highlight_proteins) 5 else 2)
  1977. V(ppi_graph)$label_type <- ifelse(
  1978. V(ppi_graph)$label %in% highlight_proteins,
  1979. "highlight", "other"
  1980. )
  1981. # Plot the network with size and color
  1982. ggraph(ppi_graph, layout = "fr") +
  1983. geom_edge_link(aes(width = I(edge_width)), alpha = 0.4) +
  1984. geom_node_point(aes(color = I(node_color), size = I(node_size)), show.legend = FALSE) +
  1985. geom_node_label(data = function(x) { x[x$label_type == "highlight", ] },
  1986. aes(label = label), size = 3, label.padding = unit(0.15, "lines"), repel = TRUE, show.legend = F) +
  1987. geom_node_text(data = function(x) { x[x$label_type == "other", ] },
  1988. aes(label = label), size = 2, repel = TRUE, show.legend = F) +
  1989. theme_void()
  1990. ```
  1991. Export source data
  1992. ```{r, eval = F}
  1993. ppi_graph %>%
  1994. vertex.attributes() %>%
  1995. as.data.frame() %>%
  1996. write.table("source_data/F6j_nodes.tsv", sep = "\t", dec = ".", row.names = F)
  1997. ppi_graph %>%
  1998. as_edgelist() %>%
  1999. as.data.frame() %>%
  2000. setNames(c("from", "to")) %>%
  2001. cbind(edge.attributes(ppi_graph)) %>%
  2002. write.table("source_data/F6j_edges.tsv", sep = "\t", dec = ".", row.names = F)
  2003. ```
  2004. # Supplementary Figure 1
  2005. ## Load data
  2006. ```{r}
  2007. samples <- anno.major %>%
  2008. names() %>%
  2009. strsplit("!!") %>%
  2010. sget(1) %>%
  2011. unique()
  2012. crm <- qread("crm.qs",
  2013. nthreads = 10)
  2014. crm$theme <- theme_bw()
  2015. ```
  2016. ## 1a-f
  2017. ```{r, fig.width=8, fig.height=12}
  2018. mtp <- crm$selectMetrics(ids = c(1:4,6,19))
  2019. plot.list <- mtp %>%
  2020. lapply(\(met) crm$plotSummaryMetrics(metrics = met, comp.group = "sample", second.comp.group = "group") +
  2021. scale_fill_manual(values = pal.major) +
  2022. labs(x = "") +
  2023. theme(axis.text.x = element_blank(),
  2024. axis.ticks.x = element_blank()))
  2025. plot.list %>%
  2026. plot_grid(plotlist = ., labels = letters[1:6], ncol = 2)
  2027. ```
  2028. Export source data
  2029. ```{r, eval = F}
  2030. for (i in seq(6)) plot.list[[i]]$data %>% write.table(paste0("source_data/SF1", letters[i], ".tsv"), sep = "\t", dec = ".", row.names = F)
  2031. ```
  2032. ## 1g
  2033. ```{r, fig.width=6, fig.height=4}
  2034. crm$plotSummaryMetrics(metrics = crm$selectMetrics(ids = 20), comp.group = "sample", second.comp.group = "group") +
  2035. scale_fill_manual(values = pal.major) +
  2036. labs(x = "") +
  2037. theme(axis.text.x = element_blank(),
  2038. axis.ticks.x = element_blank(),
  2039. legend.position = "right") -> p
  2040. p
  2041. ```
  2042. Export source data
  2043. ```{r, eval = F}
  2044. p$data %>%
  2045. write.table("source_data/SF1g.tsv", sep = "\t", dec = ".", row.names = F)
  2046. ```
  2047. ## 1h
  2048. ```{r, fig.width=6, fig.height=4}
  2049. crm$plotFilteredCells(doublet.method = "doubletdetection", depth.cutoff = 5e2, size = 0.2, alpha = 0.1) +
  2050. dotSize(3) -> p
  2051. p
  2052. ```
  2053. Export source data
  2054. ```{r, eval = F}
  2055. p$data %>%
  2056. write.table("source_data/SF1h.tsv", sep = "\t", dec = ".", row.names = F)
  2057. ```
  2058. ## 1i
  2059. ```{r, fig.width=8, fig.height=4}
  2060. crm$plotFilteredCells(type = "bar", doublet.method = "doubletdetection", depth.cutoff = 5e2)$data %>%
  2061. filter(sample != "MSA_1406") %>%
  2062. mutate(sample = strsplit(sample, "_") %>%
  2063. sget(1)) %$%
  2064. split(., sample) %>%
  2065. lapply(\(x) split(x, x$filter)) %>%
  2066. lapply(lapply, \(df) mutate(df, sample = paste0(sample, seq(nrow(df))))) %>%
  2067. lapply(bind_rows) %>%
  2068. bind_rows() %>%
  2069. mutate(sample = factor(sample, levels = c(paste0("CTRL", seq(10)), paste0("MSA", seq(7)), paste0("PD", seq(12))))) %>%
  2070. ggplot(aes(sample, pct, fill = filter)) +
  2071. geom_bar(stat = "identity") +
  2072. geom_text_repel(aes(label = sprintf("%0.2f", round(pct, digits = 2))),
  2073. position = position_stack(vjust = 0.5),
  2074. direction = "y",
  2075. size = 2.5) +
  2076. crm$theme +
  2077. theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  2078. labs(x = "", y = "Percentage cells filtered") +
  2079. theme(legend.position = "bottom") -> p
  2080. p
  2081. ```
  2082. Export source data
  2083. ```{r, eval = F}
  2084. p$data %>%
  2085. write.table("source_data/SF1i.tsv", sep = "\t", dec = ".", row.names = F)
  2086. ```
  2087. # Supplementary Figure 2
  2088. These figures cannot be reproduced here due to GDPR. Leaving the code for visibility.
  2089. ## Load data
  2090. ```{r, eval = F}
  2091. crm <- qread("crm.qs", nthreads = 10)
  2092. ```
  2093. ## 2a
  2094. ```{r, fig.width=8, fig.height=8, eval = F}
  2095. crm$plotCbCells() +
  2096. theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))
  2097. ```
  2098. ## 2b
  2099. ```{r, fig.width=5, fig.height=4, eval = F}
  2100. crm$plotCbAmbGenes() +
  2101. theme(line = element_blank(),
  2102. axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5),
  2103. axis.ticks.x = element_line()) -> p
  2104. p
  2105. ```
  2106. Export source data
  2107. ```{r, eval = F}
  2108. p$data %>%
  2109. write.table("source_data/SF2b.tsv", sep = "\t", dec = ".", row.names = F)
  2110. ```
  2111. ```{r, echo=FALSE}
  2112. rm(crm)
  2113. gc()
  2114. ```
  2115. ## 2c
  2116. ```{r fig.height=24, fig.width=8}
  2117. c("RBFOX3","MOG","VCAN","AQP4","CSF1R","PDGFRB","PTPRC","MRC1","GAD1","SLC17A7","PPP1R1B") %>%
  2118. sort() %>%
  2119. lapply(function(g) con$plotGraph(embedding = "UMAP", gene=g, title=g, size=0.1, plot.na = F, palette = colorRampPalette(c("grey90","firebrick"))) + theme(line = element_blank())) -> plot.list
  2120. plot.list %>%
  2121. cowplot::plot_grid(plotlist=., ncol=2)
  2122. ```
  2123. Export source data
  2124. ```{r, eval = F}
  2125. for (i in seq(length(plot.list))) plot.list[[i]]$data %>% write.table(paste0("source_data/SF2c", i, ".tsv"), sep = "\t", dec = ".", row.names = F)
  2126. ```
  2127. # Supplementary Figure 3
  2128. ```{r}
  2129. con$embedding <- con$embeddings$UMAP
  2130. sample.groups <- con$samples %>%
  2131. names() %>%
  2132. setNames(grepl.replace(., c("CTRL","MSA","PD")), .)
  2133. cao <- Cacoa$new(data.object = con,
  2134. sample.groups = ifelse(grepl("CTRL", sample.groups), "CTRL", "DISEASE") %>%
  2135. setNames(names(sample.groups)),
  2136. cell.groups = anno.major,
  2137. ref.level = "CTRL",
  2138. target.level = "DISEASE",
  2139. n.cores = 32)
  2140. meta <- read.delim("metadata.tsv", sep = "\t") %>%
  2141. filter(sample %in% names(con$samples)) %>%
  2142. tibble::column_to_rownames("sample") %>%
  2143. dplyr::select(-condition)
  2144. meta %<>%
  2145. mutate(sample = rownames(.))
  2146. spc <- con$getDatasetPerCell()
  2147. mpc <- spc %>%
  2148. data.frame(sample = ., cid = names(.))
  2149. for (cc in colnames(meta)) {
  2150. mpc[[cc]] <- meta[[cc]][match(mpc$sample, meta$sample)]
  2151. }
  2152. mpc$subtype[mpc$subtype == ""] <- NA
  2153. ```
  2154. ```{r, fig.width=5, fig.height=4}
  2155. p <- con$plotGraph(colors = setNames(mpc$age, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, title = "Age", size = 0.3, alpha = 0.3) +
  2156. scale_color_gradient(low = "grey", high = "firebrick") +
  2157. theme(line = element_blank()) +
  2158. labs(col = "Years")
  2159. p
  2160. ```
  2161. Export source data
  2162. ```{r, eval = F}
  2163. p$data %>%
  2164. write.table("source_data/SF3_1.tsv", sep = "\t", dec = ".", row.names = F)
  2165. ```
  2166. ```{r, fig.width=5, fig.height=4}
  2167. p <- con$plotGraph(colors = setNames(mpc$pmi, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, title = "PMI", size = 0.3, alpha = 0.3) +
  2168. scale_color_gradient(low = "grey", high = "firebrick") +
  2169. theme(line = element_blank()) +
  2170. labs(col = "Hours")
  2171. p
  2172. ```
  2173. Export source data
  2174. ```{r, eval = F}
  2175. p$data %>%
  2176. write.table("source_data/SF3_2.tsv", sep = "\t", dec = ".", row.names = F)
  2177. ```
  2178. ```{r, fig.width=5, fig.height=4}
  2179. p <- con$plotGraph(colors = setNames(mpc$disease_duration, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, title = "Disease duration", size = 0.3, alpha = 0.3) +
  2180. scale_color_gradient(low = "grey", high = "firebrick") +
  2181. theme(line = element_blank()) +
  2182. labs(col = "Years")
  2183. p
  2184. ```
  2185. Export source data
  2186. ```{r, eval = F}
  2187. p$data %>%
  2188. write.table("source_data/SF3_3.tsv", sep = "\t", dec = ".", row.names = F)
  2189. ```
  2190. ```{r, fig.width=6.75, fig.height=4}
  2191. p <- con$plotGraph(groups = setNames(mpc$sample, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, shuffle.colors = T, title = "Sample", size = 0.3, alpha = 0.3) +
  2192. theme(line = element_blank()) + dotSize(3)
  2193. p
  2194. ```
  2195. Export source data
  2196. ```{r, eval = F}
  2197. p$data %>%
  2198. write.table("source_data/SF3_4.tsv", sep = "\t", dec = ".", row.names = F)
  2199. ```
  2200. ```{r, fig.width=5.25, fig.height=4}
  2201. p <- con$plotGraph(groups = setNames(mpc$brain_bank, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, shuffle.colors = T, title = "Brain bank", size = 0.3, alpha = 0.3) +
  2202. theme(line = element_blank()) + dotSize(3)
  2203. p
  2204. ```
  2205. Export source data
  2206. ```{r, eval = F}
  2207. p$data %>%
  2208. write.table("source_data/SF3_5.tsv", sep = "\t", dec = ".", row.names = F)
  2209. ```
  2210. ```{r, fig.width=5.15, fig.height=4}
  2211. p <- con$plotGraph(groups = setNames(mpc$sex, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, shuffle.colors = T, title = "Sex", size = 0.3, alpha = 0.3) +
  2212. theme(line = element_blank()) + dotSize(3)
  2213. p
  2214. ```
  2215. Export source data
  2216. ```{r, eval = F}
  2217. p$data %>%
  2218. write.table("source_data/SF3_6.tsv", sep = "\t", dec = ".", row.names = F)
  2219. ```
  2220. ```{r, fig.width=5.4, fig.height=4}
  2221. p <- con$plotGraph(groups = setNames(mpc$subtype, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, shuffle.colors = T, title = "Subtype", size = 0.3, alpha = 0.3) +
  2222. theme(line = element_blank()) + dotSize(3)
  2223. p
  2224. ```
  2225. Export source data
  2226. ```{r, eval = F}
  2227. p$data %>%
  2228. write.table("source_data/SF3_6.tsv", sep = "\t", dec = ".", row.names = F)
  2229. ```
  2230. ```{r, fig.width=5.15, fig.height=4}
  2231. p <- con$plotGraph(groups = setNames(mpc$extract, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, shuffle.colors = T, title = "Extract", size = 0.3, alpha = 0.3) +
  2232. theme(line = element_blank()) + dotSize(3)
  2233. p
  2234. ```
  2235. Export source data
  2236. ```{r, eval = F}
  2237. p$data %>%
  2238. write.table("source_data/SF3_7.tsv", sep = "\t", dec = ".", row.names = F)
  2239. ```
  2240. ```{r, fig.width=5.88, fig.height=4}
  2241. p <- con$plotGraph(groups = setNames(mpc$flowcell, mpc$cid), plot.na = F, embedding = "UMAP_1_0.001_5", mark.groups = F, show.legend = T, shuffle.colors = T, title = "Flowcell", size = 0.3, alpha = 0.3) +
  2242. theme(line = element_blank()) + dotSize(3)
  2243. p
  2244. ```
  2245. Export source data
  2246. ```{r, eval = F}
  2247. p$data %>%
  2248. write.table("source_data/SF3_8.tsv", sep = "\t", dec = ".", row.names = F)
  2249. ```
  2250. # Supplementary Figure 4 & Supplementary Dataset 3
  2251. ## Load metadata
  2252. ```{r}
  2253. meta <- read.delim("metadata.tsv", sep = "\t") %>%
  2254. filter(sample %in% names(con$samples)) %>%
  2255. tibble::column_to_rownames("sample") %>%
  2256. mutate(sample = rownames(.)) %>%
  2257. dplyr::select(-condition)
  2258. ```
  2259. ## 4a
  2260. ```{r}
  2261. con_msa <- con$clone()
  2262. con_msa$embedding <- con$embeddings$UMAP
  2263. con_msa$samples <- con$samples %>% .[!grepl("PD", names(.))]
  2264. sample.groups <- con_msa$samples %>%
  2265. names() %>%
  2266. setNames(grepl.replace(., c("CTRL","MSA")), .)
  2267. cao_msa <- Cacoa$new(data.object = con_msa,
  2268. sample.groups = ifelse(grepl("CTRL", sample.groups), "CTRL", "MSA") %>%
  2269. setNames(names(sample.groups)),
  2270. cell.groups = anno.major,
  2271. ref.level = "CTRL",
  2272. target.level = "MSA",
  2273. n.cores = 32)
  2274. cao_msa$estimateExpressionShiftMagnitudes()
  2275. cao_msa$estimateMetadataSeparation(sample.meta = meta %>% filter(!grepl("PD", sample)) %>% dplyr::select(-brain_bank, -sample),
  2276. space = "expression.shifts")
  2277. ```
  2278. ```{r, fig.width=25, fig.height=8}
  2279. plot.list <- list(
  2280. cao_msa$plotSampleDistances(space = "expression.shifts", show.sample.size = T, method = "UMAP", title = "Condition"),
  2281. cao_msa$plotSampleDistances(space = "expression.shifts", method = "UMAP", show.sample.size = T, sample.colors = meta$age %>% setNames(rownames(meta)), title = "Age"),
  2282. cao_msa$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$disease_duration %>% setNames(rownames(meta)), show.sample.size = T, title = "Disease duration"),
  2283. cao_msa$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$extract %>% setNames(rownames(meta)), show.sample.size = T, title = "Extract batch"),
  2284. cao_msa$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$flowcell %>% setNames(rownames(meta)), show.sample.size = T, title = "Flowcell"),
  2285. cao_msa$plotSampleDistances(space = "expression.shifts", method = "UMAP", show.sample.size = T, sample.colors = meta$pmi %>% setNames(rownames(meta)), title = "PMI"),
  2286. cao_msa$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$sex %>% setNames(rownames(meta)), show.sample.size = T, title = "Sex"),
  2287. cao_msa$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$subtype %>% setNames(rownames(meta)), show.sample.size = T, title = "Subtype"),
  2288. cao_msa$test.results$metadata.separation$padjust %>%
  2289. data.frame(p = .) %>%
  2290. mutate(pp = -log10(p), padj = formatC(p, digits = 3)) %>%
  2291. mutate(padj = sapply(padj, \(x) if (x > 0.05) "" else paste("p.adj = ", x, sep = ""))) %>%
  2292. tibble::rownames_to_column("covariate") %>%
  2293. ggplot(aes(covariate, pp)) +
  2294. geom_bar(stat = "identity", fill = "lightblue4") +
  2295. ylim(0, pmax(2, max(-log10(cao_msa$test.results$metadata.separation$padjust)))) +
  2296. theme_minimal() +
  2297. theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
  2298. labs(x = "", y = "-log10(adj. p)", title = "Association significance") +
  2299. geom_hline(yintercept = -log10(0.05), colour = "red3") +
  2300. geom_text(aes(label = padj, y = pp + 0.1), size = 8)
  2301. )
  2302. cowplot::plot_grid(plotlist = plot.list, ncol = 5) -> p
  2303. p
  2304. ```
  2305. Export source data
  2306. ```{r, eval = F}
  2307. for (i in seq(length(plot.list))) plot.list[[i]]$data %>% write.table(paste0("source_data/SF4a", i, ".tsv"), sep = "\t", dec = ".", row.names = F)
  2308. ```
  2309. ## 4b
  2310. ```{r}
  2311. con_pd <- con$clone()
  2312. con_pd$embedding <- con$embeddings$UMAP
  2313. con_pd$samples <- con$samples %>% .[!grepl("MSA", names(.))]
  2314. sample.groups <- con_pd$samples %>%
  2315. names() %>%
  2316. setNames(grepl.replace(., c("CTRL","PD")), .)
  2317. cao_pd <- Cacoa$new(data.object = con_pd,
  2318. sample.groups = ifelse(grepl("CTRL", sample.groups), "CTRL", "PD") %>%
  2319. setNames(names(sample.groups)),
  2320. cell.groups = anno.major,
  2321. ref.level = "CTRL",
  2322. target.level = "PD",
  2323. n.cores = 32)
  2324. cao_pd$estimateExpressionShiftMagnitudes()
  2325. cao_pd$estimateMetadataSeparation(sample.meta = meta %>% filter(!grepl("MSA", sample)) %>% dplyr::select(-disease_duration, -subtype, -sample),
  2326. space = "expression.shifts")
  2327. ```
  2328. ```{r, fig.width=20, fig.height=8}
  2329. plot.list <- list(
  2330. cao_pd$plotSampleDistances(space = "expression.shifts", show.sample.size = T, method = "UMAP", title = "Condition"),
  2331. cao_pd$plotSampleDistances(space = "expression.shifts", method = "UMAP", show.sample.size = T, sample.colors = meta$age %>% setNames(rownames(meta)), title = "Age"),
  2332. cao_pd$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$brain_bank %>% setNames(rownames(meta)), show.sample.size = T, title = "Brain bank"),
  2333. cao_pd$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$extract %>% setNames(rownames(meta)), show.sample.size = T, title = "Extract batch"),
  2334. cao_pd$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$flowcell %>% setNames(rownames(meta)), show.sample.size = T, title = "Flowcell"),
  2335. cao_pd$plotSampleDistances(space = "expression.shifts", method = "UMAP", show.sample.size = T, sample.colors = meta$pmi %>% setNames(rownames(meta)), title = "PMI"),
  2336. cao_pd$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$sex %>% setNames(rownames(meta)), show.sample.size = T, title = "Sex"),
  2337. cao_pd$test.results$metadata.separation$padjust %>%
  2338. data.frame(p = .) %>%
  2339. mutate(pp = -log10(p), padj = formatC(p, digits = 3)) %>%
  2340. mutate(padj = sapply(padj, \(x) if (x > 0.05) "" else paste("p.adj = ", x, sep = ""))) %>%
  2341. tibble::rownames_to_column("covariate") %>%
  2342. ggplot(aes(covariate, pp)) +
  2343. geom_bar(stat = "identity", fill = "lightblue4") +
  2344. ylim(0, pmax(2, max(-log10(cao_pd$test.results$metadata.separation$padjust)))) +
  2345. theme_minimal() +
  2346. theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
  2347. labs(x = "", y = "-log10(adj. p)", title = "Association significance") +
  2348. geom_hline(yintercept = -log10(0.05), colour = "red3") +
  2349. geom_text(aes(label = padj, y = pp + 0.1), size = 3)
  2350. )
  2351. cowplot::plot_grid(plotlist = plot.list, ncol = 4) -> p
  2352. p
  2353. ```
  2354. Export source data
  2355. ```{r, eval = F}
  2356. for (i in seq(length(plot.list))) plot.list[[i]]$data %>% write.table(paste0("source_data/SF4b", i, ".tsv"), sep = "\t", dec = ".", row.names = F)
  2357. ```
  2358. ## 4c
  2359. ```{r}
  2360. con_dis <- con$clone()
  2361. con_dis$embedding <- con$embeddings$UMAP
  2362. con_dis$samples <- con$samples %>% .[!grepl("CTRL", names(.))]
  2363. sample.groups <- con_dis$samples %>%
  2364. names() %>%
  2365. setNames(grepl.replace(., c("PD","MSA")), .)
  2366. cao_dis <- Cacoa$new(data.object = con_dis,
  2367. sample.groups = ifelse(grepl("PD", sample.groups), "PD", "MSA") %>%
  2368. setNames(names(sample.groups)),
  2369. cell.groups = anno.major,
  2370. ref.level = "PD",
  2371. target.level = "MSA",
  2372. n.cores = 32)
  2373. cao_dis$estimateExpressionShiftMagnitudes()
  2374. cao_dis$estimateMetadataSeparation(sample.meta = meta %>% filter(!grepl("CTRL", sample)) %>% dplyr::select(-sample),
  2375. space = "expression.shifts")
  2376. ```
  2377. ```{r, fig.width=25, fig.height=8}
  2378. plot.list <- list(
  2379. cao_dis$plotSampleDistances(space = "expression.shifts", show.sample.size = T, method = "UMAP", title = "Condition"),
  2380. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", show.sample.size = T, sample.colors = meta$age %>% setNames(rownames(meta)), title = "Age"),
  2381. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$brain_bank %>% setNames(rownames(meta)), show.sample.size = T, title = "Brain bank"),
  2382. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$disease_duration %>% setNames(rownames(meta)), show.sample.size = T, title = "Disease duration"),
  2383. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$extract %>% setNames(rownames(meta)), show.sample.size = T, title = "Extract batch"),
  2384. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$flowcell %>% setNames(rownames(meta)), show.sample.size = T, title = "Flowcell"),
  2385. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", show.sample.size = T, sample.colors = meta$pmi %>% setNames(rownames(meta)), title = "PMI"),
  2386. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$sex %>% setNames(rownames(meta)), show.sample.size = T, title = "Sex"),
  2387. cao_dis$plotSampleDistances(space = "expression.shifts", method = "UMAP", sample.colors = meta$subtype %>% setNames(rownames(meta)), show.sample.size = T, title = "Subtype"),
  2388. cao_dis$test.results$metadata.separation$padjust %>%
  2389. data.frame(p = .) %>%
  2390. mutate(pp = -log10(p), padj = formatC(p, digits = 3)) %>%
  2391. mutate(padj = sapply(padj, \(x) if (x > 0.05) "" else paste("p.adj = ", x, sep = ""))) %>%
  2392. tibble::rownames_to_column("covariate") %>%
  2393. ggplot(aes(covariate, pp)) +
  2394. geom_bar(stat = "identity", fill = "lightblue4") +
  2395. ylim(0, pmax(2, max(-log10(cao_pd$test.results$metadata.separation$padjust)))) +
  2396. theme_minimal() +
  2397. theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
  2398. labs(x = "", y = "-log10(adj. p)", title = "Association significance") +
  2399. geom_hline(yintercept = -log10(0.05), colour = "red3") +
  2400. geom_text(aes(label = padj, y = pp + 0.1), size = 8)
  2401. )
  2402. cowplot::plot_grid(plotlist = plot.list, ncol = 5) -> p
  2403. p
  2404. ```
  2405. Export source data
  2406. ```{r, eval = F}
  2407. for (i in seq(length(plot.list))) plot.list[[i]]$data %>% write.table(paste0("source_data/SF4c", i, ".tsv"), sep = "\t", dec = ".", row.names = F)
  2408. ```
  2409. ## Supplementary Dataset 3
  2410. Not rerun
  2411. ```{r, eval = F}
  2412. list(cao_msa, cao_pd, cao_dis) %>%
  2413. lapply(getElement, "test.results") %>%
  2414. lget("metadata.separation") %>%
  2415. lapply(\(x) x[-1]) %>%
  2416. Map(\(dat, nn) bind_cols(dat) %>% data.frame() %>% `rownames<-`(nn), dat = ., nn = lapply(., lapply, names) %>% sget(1)) %>%
  2417. setNames(c("MSA", "PD", "dis")) %>%
  2418. lapply(tibble::rownames_to_column, var = "covariate") %>%
  2419. bind_rows(.id = "comparison") %>%
  2420. mutate(comparison = scHelper::grepl.replace(comparison, c("MSA", "PD", "dis"), c("CTRL vs MSA", "CTRL vs PD", "PD vs MSA"))) %>%
  2421. write.table("Table SX - Cacoa covariate analysis.tsv", sep = "\t", dec = ".", row.names = F)
  2422. ```
  2423. # Supplementary Figure 5
  2424. To investigate effects from co-variates, we ran scITD on all cell types for each comparison. We don't determine factors here as it takes a significant amount of time, but we keep the code in the first instance.
  2425. We tested different levels of **var_scale_power**, here we're just showing **var_scale_power = 0.5** as we didn't find any effects except for OPCs. Per default, we set **vargenes_method="norm_var_pvals"** and adjusted **vargenes_thresh** to obtain around 1,000 var. genes, but in some instances we took the top most variable genes instead.
  2426. ### Neurons, preparation
  2427. ```{r}
  2428. con.tmp <- qread("cao_neurons.qs", nthreads = 10)$data.object
  2429. anno <- qread("anno_neurons.qs")
  2430. anno %<>%
  2431. collapseAnnotation("GABA") %>%
  2432. collapseAnnotation("GLU") %>%
  2433. renameAnnotation("GABA", "Inh. neurons") %>%
  2434. renameAnnotation("GLU", "Exc. neurons") %>%
  2435. collapseAnnotation("MSN")
  2436. cm.raw.all <- con.tmp$getJointCountMatrix(raw = T) %>%
  2437. Matrix::t() %>%
  2438. .[!grepl("MT-|RPS|RPL", rownames(.)), ]
  2439. meta.all <- con.tmp$getDatasetPerCell() %>%
  2440. data.frame(donors = .) %>%
  2441. mutate(ctypes = anno[rownames(.)] %>% unname()) %>%
  2442. .[complete.cases(.), ]
  2443. metadata.all <- read.delim("metadata.tsv")
  2444. for (cc in colnames(metadata.all)[-1]) {
  2445. meta.all[[cc]] <- metadata.all[[cc]][match(meta.all$donors, metadata.all$sample)]
  2446. }
  2447. # Convert integers to numeric
  2448. meta.all$age %<>% as.numeric()
  2449. meta.all$disease_duration %<>% as.numeric()
  2450. ```
  2451. ### CTRL vs MSA
  2452. ```{r}
  2453. meta <- meta.all %>%
  2454. filter(condition != "PD") %>%
  2455. mutate(donors = factor(donors),
  2456. ctypes = factor(ctypes))
  2457. metadata <- metadata.all %>%
  2458. filter(condition != "PD")
  2459. cm.raw <- cm.raw.all %>%
  2460. .[, colnames(.) %in% rownames(meta)]
  2461. # set up project parameters
  2462. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2463. ncores = 31,
  2464. rand_seed = 10)
  2465. # create project container
  2466. itd_container <- make_new_container(count_data=cm.raw %>% .[, colnames(.) %in% rownames(meta)],
  2467. meta_data=meta,
  2468. params=param_list,
  2469. label_donor_sex = F)
  2470. itd_container %<>% form_tensor(donor_min_cells=1,
  2471. norm_method='trim',
  2472. scale_factor=10000,
  2473. vargenes_method='norm_var_pvals',
  2474. vargenes_thresh=0.7,
  2475. scale_var = TRUE,
  2476. var_scale_power = 0.5)
  2477. print(length(itd_container[["all_vargenes"]]))
  2478. ```
  2479. ```{r, eval = F}
  2480. # get assistance with rank determination
  2481. itd_container %<>% determine_ranks_tucker(max_ranks_test=c(10,15),
  2482. shuffle_level='cells',
  2483. num_iter=10,
  2484. norm_method='trim',
  2485. scale_factor=10000,
  2486. scale_var=TRUE,
  2487. var_scale_power=0.5)
  2488. itd_container$plots$rank_determination_plot
  2489. ```
  2490. ```{r, fig.height=5, fig.width=8}
  2491. itd_container %<>% run_tucker_ica(ranks=c(5,10),
  2492. tucker_type = 'regular',
  2493. rotation_type = 'hybrid')
  2494. # get donor scores-metadata associations
  2495. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  2496. stat_use='pval')
  2497. # plot donor scores
  2498. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  2499. show_donor_ids = TRUE,
  2500. add_meta_associations="pval")
  2501. # show the donor scores heatmap
  2502. p <- itd_container$plots$donor_matrix
  2503. p
  2504. ```
  2505. ### CTRL vs PD
  2506. ```{r}
  2507. meta <- meta.all %>%
  2508. filter(condition != "MSA") %>%
  2509. mutate(donors = factor(donors),
  2510. ctypes = factor(ctypes))
  2511. metadata <- metadata.all %>%
  2512. filter(condition != "MSA")
  2513. cm.raw <- cm.raw.all %>%
  2514. .[, colnames(.) %in% rownames(meta)]
  2515. # set up project parameters
  2516. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2517. ncores = 31,
  2518. rand_seed = 10)
  2519. # create project container
  2520. itd_container <- make_new_container(count_data=cm.raw,
  2521. meta_data=meta,
  2522. params=param_list,
  2523. label_donor_sex = F)
  2524. itd_container %<>% form_tensor(donor_min_cells=1,
  2525. norm_method='trim',
  2526. scale_factor=10000,
  2527. vargenes_method='norm_var',
  2528. vargenes_thresh=500,
  2529. scale_var = TRUE,
  2530. var_scale_power = 0.5)
  2531. print(length(itd_container[["all_vargenes"]]))
  2532. ```
  2533. ```{r}
  2534. itd_container %<>% run_tucker_ica(ranks=c(5,10),
  2535. tucker_type = 'regular',
  2536. rotation_type = 'hybrid')
  2537. # get donor scores-metadata associations
  2538. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2539. stat_use='pval')
  2540. # plot donor scores
  2541. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2542. show_donor_ids = TRUE,
  2543. add_meta_associations='pval')
  2544. # show the donor scores heatmap
  2545. p <- itd_container$plots$donor_matrix
  2546. p
  2547. ```
  2548. ### PD vs MSA
  2549. ```{r}
  2550. meta <- meta.all %>%
  2551. filter(condition != "CTRL") %>%
  2552. mutate(donors = factor(donors),
  2553. ctypes = factor(ctypes))
  2554. metadata <- metadata.all %>%
  2555. filter(condition != "CTRL")
  2556. cm.raw <- cm.raw.all %>%
  2557. .[, colnames(.) %in% rownames(meta)]
  2558. # set up project parameters
  2559. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2560. ncores = 31,
  2561. rand_seed = 10)
  2562. # create project container
  2563. itd_container <- make_new_container(count_data=cm.raw,
  2564. meta_data=meta,
  2565. params=param_list,
  2566. label_donor_sex = F)
  2567. itd_container %<>% form_tensor(donor_min_cells=1,
  2568. norm_method='trim',
  2569. scale_factor=10000,
  2570. vargenes_method='norm_var',
  2571. vargenes_thresh=500,
  2572. scale_var = TRUE,
  2573. var_scale_power = 0.5)
  2574. print(length(itd_container[["all_vargenes"]]))
  2575. ```
  2576. ```{r}
  2577. itd_container %<>% run_tucker_ica(ranks=c(5,10),
  2578. tucker_type = 'regular',
  2579. rotation_type = 'hybrid')
  2580. # get donor scores-metadata associations
  2581. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2582. stat_use='pval')
  2583. # plot donor scores
  2584. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2585. show_donor_ids = TRUE,
  2586. add_meta_associations='pval')
  2587. # show the donor scores heatmap
  2588. p <- itd_container$plots$donor_matrix
  2589. p
  2590. ```
  2591. ### Astrocytes, preparation
  2592. ```{r}
  2593. con.tmp <- qread("con_astrocytes.qs", nthreads = 10)
  2594. anno <- qread("anno_astro.qs")
  2595. cm.raw.all <- con.tmp$getJointCountMatrix(raw = T) %>%
  2596. .[, !grepl("MT-|RPS|RPL", colnames(.))] %>%
  2597. Matrix::t()
  2598. meta.all <- con.tmp$getDatasetPerCell() %>%
  2599. .[names(.) %in% names(anno)] %>%
  2600. data.frame(donors = .) %>%
  2601. mutate(ctypes = anno[rownames(.)] %>% unname()) %>%
  2602. .[complete.cases(.), ]
  2603. metadata.all <- read.delim("metadata.tsv")
  2604. for (cc in colnames(metadata.all)[-1]) {
  2605. meta.all[[cc]] <- metadata.all[[cc]][match(meta.all$donors, metadata.all$sample)]
  2606. }
  2607. # Convert integers to numeric
  2608. meta.all$age %<>% as.numeric()
  2609. meta.all$disease_duration %<>% as.numeric()
  2610. ```
  2611. ### CTRL vs MSA
  2612. ```{r}
  2613. meta <- meta.all %>%
  2614. filter(condition != "PD") %>%
  2615. mutate(donors = factor(donors),
  2616. ctypes = factor(ctypes))
  2617. metadata <- metadata.all %>%
  2618. filter(condition != "PD")
  2619. cm.raw <- cm.raw.all %>%
  2620. .[, colnames(.) %in% rownames(meta)]
  2621. # set up project parameters
  2622. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2623. ncores = 31,
  2624. rand_seed = 10)
  2625. # create project container
  2626. itd_container <- make_new_container(count_data=cm.raw %>% .[, colnames(.) %in% rownames(meta)],
  2627. meta_data=meta,
  2628. params=param_list,
  2629. label_donor_sex = F)
  2630. itd_container %<>% form_tensor(donor_min_cells=5,
  2631. norm_method='trim',
  2632. scale_factor=10000,
  2633. vargenes_method='norm_var_pvals',
  2634. vargenes_thresh=0.05,
  2635. scale_var = TRUE,
  2636. var_scale_power = 0.5)
  2637. print(length(itd_container[["all_vargenes"]]))
  2638. ```
  2639. ```{r}
  2640. itd_container %<>% run_tucker_ica(ranks=c(5,8),
  2641. tucker_type = 'regular',
  2642. rotation_type = 'hybrid')
  2643. # get donor scores-metadata associations
  2644. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  2645. stat_use='pval')
  2646. # plot donor scores
  2647. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  2648. show_donor_ids = TRUE,
  2649. add_meta_associations='pval')
  2650. # show the donor scores heatmap
  2651. p <- itd_container$plots$donor_matrix
  2652. p
  2653. ```
  2654. ### CTRL vs PD
  2655. ```{r}
  2656. meta <- meta.all %>%
  2657. filter(condition != "MSA") %>%
  2658. mutate(donors = factor(donors),
  2659. ctypes = factor(ctypes))
  2660. metadata <- metadata.all %>%
  2661. filter(condition != "MSA")
  2662. cm.raw <- cm.raw.all %>%
  2663. .[, colnames(.) %in% rownames(meta)]
  2664. # set up project parameters
  2665. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2666. ncores = 31,
  2667. rand_seed = 10)
  2668. # create project container
  2669. itd_container <- make_new_container(count_data=cm.raw,
  2670. meta_data=meta,
  2671. params=param_list,
  2672. label_donor_sex = F)
  2673. itd_container %<>% form_tensor(donor_min_cells=5,
  2674. norm_method='trim',
  2675. scale_factor=10000,
  2676. vargenes_method='norm_var_pvals',
  2677. vargenes_thresh=.05,
  2678. scale_var = TRUE,
  2679. var_scale_power = 0.5)
  2680. print(length(itd_container[["all_vargenes"]]))
  2681. ```
  2682. ```{r}
  2683. itd_container %<>% run_tucker_ica(ranks=c(5,9),
  2684. tucker_type = 'regular',
  2685. rotation_type = 'hybrid')
  2686. # get donor scores-metadata associations
  2687. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"), # Omitting brain bank
  2688. stat_use='pval')
  2689. # plot donor scores
  2690. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"), # Omitting brain bank
  2691. show_donor_ids = TRUE,
  2692. add_meta_associations='pval')
  2693. # show the donor scores heatmap
  2694. p <- itd_container$plots$donor_matrix
  2695. p
  2696. ```
  2697. ### PD vs MSA
  2698. ```{r}
  2699. meta <- meta.all %>%
  2700. filter(condition != "CTRL") %>%
  2701. mutate(donors = factor(donors),
  2702. ctypes = factor(ctypes))
  2703. metadata <- metadata.all %>%
  2704. filter(condition != "CTRL")
  2705. cm.raw <- cm.raw.all %>%
  2706. .[, colnames(.) %in% rownames(meta)]
  2707. # set up project parameters
  2708. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2709. ncores = 31,
  2710. rand_seed = 10)
  2711. # create project container
  2712. itd_container <- make_new_container(count_data=cm.raw,
  2713. meta_data=meta,
  2714. params=param_list,
  2715. label_donor_sex = F)
  2716. itd_container %<>% form_tensor(donor_min_cells=5,
  2717. norm_method='trim',
  2718. scale_factor=10000,
  2719. vargenes_method='norm_var_pvals',
  2720. vargenes_thresh=.05,
  2721. scale_var = TRUE,
  2722. var_scale_power = 0.5)
  2723. print(length(itd_container[["all_vargenes"]]))
  2724. ```
  2725. ```{r}
  2726. itd_container %<>% run_tucker_ica(ranks=c(6,7),
  2727. tucker_type = 'regular',
  2728. rotation_type = 'hybrid')
  2729. # get donor scores-metadata associations
  2730. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2731. stat_use='pval')
  2732. # plot donor scores
  2733. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2734. show_donor_ids = TRUE,
  2735. add_meta_associations='pval')
  2736. # show the donor scores heatmap
  2737. p <- itd_container$plots$donor_matrix
  2738. p
  2739. ```
  2740. ### Microglia, preparation
  2741. ```{r}
  2742. con.tmp <- qread("cao_micro_pvm.qs", nthreads = 10)$data.object
  2743. anno <- qread("anno_micro_pvm.qs")
  2744. cm.raw.all <- con.tmp$getJointCountMatrix(raw = T) %>%
  2745. Matrix::t() %>%
  2746. .[!grepl("MT-|RPS|RPL", rownames(.)), ]
  2747. meta.all <- con.tmp$getDatasetPerCell() %>%
  2748. data.frame(donors = .) %>%
  2749. mutate(ctypes = anno[rownames(.)] %>% unname()) %>%
  2750. .[complete.cases(.), ]
  2751. metadata.all <- read.delim("metadata.tsv")
  2752. for (cc in colnames(metadata.all)[-1]) {
  2753. meta.all[[cc]] <- metadata.all[[cc]][match(meta.all$donors, metadata.all$sample)]
  2754. }
  2755. # Convert integers to numeric
  2756. meta.all$age %<>% as.numeric()
  2757. meta.all$disease_duration %<>% as.numeric()
  2758. ```
  2759. ### CTRL vs MSA
  2760. ```{r}
  2761. meta <- meta.all %>%
  2762. filter(condition != "PD") %>%
  2763. mutate(donors = factor(donors),
  2764. ctypes = factor(ctypes))
  2765. metadata <- metadata.all %>%
  2766. filter(condition != "PD")
  2767. cm.raw <- cm.raw.all %>%
  2768. .[, colnames(.) %in% rownames(meta)]
  2769. # set up project parameters
  2770. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2771. ncores = 31,
  2772. rand_seed = 10)
  2773. # create project container
  2774. itd_container <- make_new_container(count_data=cm.raw %>% .[, colnames(.) %in% rownames(meta)],
  2775. meta_data=meta,
  2776. params=param_list,
  2777. label_donor_sex = F)
  2778. itd_container %<>% form_tensor(donor_min_cells=3,
  2779. norm_method='trim',
  2780. scale_factor=10000,
  2781. vargenes_method='norm_var',
  2782. vargenes_thresh=500,
  2783. scale_var = TRUE,
  2784. var_scale_power = 0.5)
  2785. print(length(itd_container[["all_vargenes"]]))
  2786. ```
  2787. ```{r}
  2788. itd_container %<>% run_tucker_ica(ranks=c(3,7),
  2789. tucker_type = 'regular',
  2790. rotation_type = 'hybrid')
  2791. factors <- c('sex','pmi', "age", "flowcell", "extract")
  2792. # get donor scores-metadata associations
  2793. itd_container %<>% get_meta_associations(vars_test = factors,
  2794. stat_use='pval')
  2795. # plot donor scores
  2796. itd_container %<>% plot_donor_matrix(meta_vars= factors,
  2797. show_donor_ids = TRUE,
  2798. add_meta_associations='pval')
  2799. # show the donor scores heatmap
  2800. p <- itd_container$plots$donor_matrix
  2801. p
  2802. ```
  2803. ### CTRL vs PD
  2804. ```{r}
  2805. meta <- meta.all %>%
  2806. filter(condition != "MSA") %>%
  2807. mutate(donors = factor(donors),
  2808. ctypes = factor(ctypes))
  2809. metadata <- metadata.all %>%
  2810. filter(condition != "MSA")
  2811. cm.raw <- cm.raw.all %>%
  2812. .[, colnames(.) %in% rownames(meta)]
  2813. # set up project parameters
  2814. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2815. ncores = 31,
  2816. rand_seed = 10)
  2817. # create project container
  2818. itd_container <- make_new_container(count_data=cm.raw,
  2819. meta_data=meta,
  2820. params=param_list,
  2821. label_donor_sex = F)
  2822. itd_container %<>% form_tensor(donor_min_cells=3,
  2823. norm_method='trim',
  2824. scale_factor=10000,
  2825. vargenes_method='norm_var',
  2826. vargenes_thresh=500,
  2827. scale_var = TRUE,
  2828. var_scale_power = 0.5)
  2829. print(length(itd_container[["all_vargenes"]]))
  2830. ```
  2831. ```{r}
  2832. itd_container %<>% run_tucker_ica(ranks=c(4,10),
  2833. tucker_type = 'regular',
  2834. rotation_type = 'hybrid')
  2835. # get donor scores-metadata associations
  2836. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2837. stat_use='pval')
  2838. # plot donor scores
  2839. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2840. show_donor_ids = TRUE,
  2841. add_meta_associations='pval')
  2842. # show the donor scores heatmap
  2843. p <- itd_container$plots$donor_matrix
  2844. p
  2845. ```
  2846. ### PD vs MSA
  2847. ```{r}
  2848. meta <- meta.all %>%
  2849. filter(condition != "CTRL") %>%
  2850. mutate(donors = factor(donors),
  2851. ctypes = factor(ctypes))
  2852. metadata <- metadata.all %>%
  2853. filter(condition != "CTRL")
  2854. cm.raw <- cm.raw.all %>%
  2855. .[, colnames(.) %in% rownames(meta)]
  2856. # set up project parameters
  2857. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2858. ncores = 31,
  2859. rand_seed = 10)
  2860. # create project container
  2861. itd_container <- make_new_container(count_data=cm.raw,
  2862. meta_data=meta,
  2863. params=param_list,
  2864. label_donor_sex = F)
  2865. itd_container %<>% form_tensor(donor_min_cells=3,
  2866. norm_method='trim',
  2867. scale_factor=10000,
  2868. vargenes_method='norm_var',
  2869. vargenes_thresh=500,
  2870. scale_var = TRUE,
  2871. var_scale_power = 0.5)
  2872. print(length(itd_container[["all_vargenes"]]))
  2873. ```
  2874. ```{r}
  2875. itd_container %<>% run_tucker_ica(ranks=c(4,10),
  2876. tucker_type = 'regular',
  2877. rotation_type = 'hybrid')
  2878. # get donor scores-metadata associations
  2879. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2880. stat_use='pval')
  2881. # plot donor scores
  2882. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2883. show_donor_ids = TRUE,
  2884. add_meta_associations='pval')
  2885. # show the donor scores heatmap
  2886. p <- itd_container$plots$donor_matrix
  2887. p
  2888. ```
  2889. ### Oligodendrocytes, preparation
  2890. ```{r}
  2891. con.tmp <- qread("con_oligodendrocytes.qs", nthreads = 10)
  2892. anno <- qread("anno_oligo.qs")
  2893. cm.raw.all <- con.tmp$getJointCountMatrix(raw = T) %>%
  2894. .[rownames(.) %in% names(anno), !grepl("MT-|RPS|RPL", colnames(.))] %>%
  2895. Matrix::t()
  2896. meta.all <- con.tmp$getDatasetPerCell() %>%
  2897. data.frame(donors = .) %>%
  2898. mutate(ctypes = anno[rownames(.)] %>% unname()) %>%
  2899. .[complete.cases(.), ]
  2900. metadata.all <- read.delim("metadata.tsv")
  2901. for (cc in colnames(metadata.all)[-1]) {
  2902. meta.all[[cc]] <- metadata.all[[cc]][match(meta.all$donors, metadata.all$sample)]
  2903. }
  2904. # Convert integers to numeric
  2905. meta.all$age %<>% as.numeric()
  2906. meta.all$disease_duration %<>% as.numeric()
  2907. ```
  2908. ### CTRL vs MSA
  2909. ```{r}
  2910. meta <- meta.all %>%
  2911. filter(condition != "PD") %>%
  2912. mutate(donors = factor(donors),
  2913. ctypes = factor(ctypes))
  2914. metadata <- metadata.all %>%
  2915. filter(condition != "PD")
  2916. cm.raw <- cm.raw.all %>%
  2917. .[, colnames(.) %in% rownames(meta)]
  2918. # set up project parameters
  2919. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2920. ncores = 31,
  2921. rand_seed = 10)
  2922. # create project container
  2923. itd_container <- make_new_container(count_data=cm.raw %>% .[, colnames(.) %in% rownames(meta)],
  2924. meta_data=meta,
  2925. params=param_list,
  2926. label_donor_sex = F)
  2927. itd_container %<>% form_tensor(donor_min_cells=5,
  2928. norm_method='trim',
  2929. scale_factor=10000,
  2930. vargenes_method='norm_var_pvals',
  2931. vargenes_thresh=0.05,
  2932. scale_var = TRUE,
  2933. var_scale_power = 1) # Diminishable effect at 0.5, but not on any other level
  2934. print(length(itd_container[["all_vargenes"]]))
  2935. ```
  2936. ```{r}
  2937. itd_container %<>% run_tucker_ica(ranks=c(6,9),
  2938. tucker_type = 'regular',
  2939. rotation_type = 'hybrid')
  2940. # get donor scores-metadata associations
  2941. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  2942. stat_use='pval')
  2943. # plot donor scores
  2944. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  2945. show_donor_ids = TRUE,
  2946. add_meta_associations='pval')
  2947. # show the donor scores heatmap
  2948. p <- itd_container$plots$donor_matrix
  2949. p
  2950. ```
  2951. ### CTRL vs PD
  2952. ```{r}
  2953. meta <- meta.all %>%
  2954. filter(condition != "MSA") %>%
  2955. mutate(donors = factor(donors),
  2956. ctypes = factor(ctypes))
  2957. metadata <- metadata.all %>%
  2958. filter(condition != "MSA")
  2959. cm.raw <- cm.raw.all %>%
  2960. .[, colnames(.) %in% rownames(meta)]
  2961. # set up project parameters
  2962. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  2963. ncores = 31,
  2964. rand_seed = 10)
  2965. # create project container
  2966. itd_container <- make_new_container(count_data=cm.raw,
  2967. meta_data=meta,
  2968. params=param_list,
  2969. label_donor_sex = F)
  2970. itd_container %<>% form_tensor(donor_min_cells=5,
  2971. norm_method='trim',
  2972. scale_factor=10000,
  2973. vargenes_method='norm_var_pvals',
  2974. vargenes_thresh=.05,
  2975. scale_var = TRUE,
  2976. var_scale_power = 0.5)
  2977. print(length(itd_container[["all_vargenes"]]))
  2978. ```
  2979. ```{r}
  2980. itd_container %<>% run_tucker_ica(ranks=c(4,8),
  2981. tucker_type = 'regular',
  2982. rotation_type = 'hybrid')
  2983. # get donor scores-metadata associations
  2984. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2985. stat_use='pval')
  2986. # plot donor scores
  2987. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  2988. show_donor_ids = TRUE,
  2989. add_meta_associations='pval')
  2990. # show the donor scores heatmap
  2991. p <- itd_container$plots$donor_matrix
  2992. p
  2993. ```
  2994. ### PD vs MSA
  2995. ```{r}
  2996. meta <- meta.all %>%
  2997. filter(condition != "CTRL") %>%
  2998. mutate(donors = factor(donors),
  2999. ctypes = factor(ctypes))
  3000. metadata <- metadata.all %>%
  3001. filter(condition != "CTRL")
  3002. cm.raw <- cm.raw.all %>%
  3003. .[, colnames(.) %in% rownames(meta)]
  3004. # set up project parameters
  3005. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  3006. ncores = 31,
  3007. rand_seed = 10)
  3008. # create project container
  3009. itd_container <- make_new_container(count_data=cm.raw,
  3010. meta_data=meta,
  3011. params=param_list,
  3012. label_donor_sex = F)
  3013. itd_container %<>% form_tensor(donor_min_cells=5,
  3014. norm_method='trim',
  3015. scale_factor=10000,
  3016. vargenes_method='norm_var_pvals',
  3017. vargenes_thresh=.05,
  3018. scale_var = TRUE,
  3019. var_scale_power = 1) # Diminishable effect at 0.5, but not on any other level
  3020. print(length(itd_container[["all_vargenes"]]))
  3021. ```
  3022. ```{r}
  3023. itd_container %<>% run_tucker_ica(ranks=c(5,6),
  3024. tucker_type = 'regular',
  3025. rotation_type = 'hybrid')
  3026. # get donor scores-metadata associations
  3027. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  3028. stat_use='pval')
  3029. # plot donor scores
  3030. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  3031. show_donor_ids = TRUE,
  3032. add_meta_associations='pval')
  3033. # show the donor scores heatmap
  3034. p <- itd_container$plots$donor_matrix
  3035. p
  3036. ```
  3037. ### OPCs, preparation
  3038. ```{r}
  3039. con.tmp <- qread("con_opcs.qs", nthreads = 10)
  3040. anno <- qread("anno_opc.qs")
  3041. cm.raw.all <- con.tmp$getJointCountMatrix(raw = T) %>%
  3042. Matrix::t() %>%
  3043. .[!grepl("MT-|RPS|RPL", rownames(.)), ]
  3044. meta.all <- con.tmp$getDatasetPerCell() %>%
  3045. data.frame(donors = .) %>%
  3046. mutate(ctypes = anno[rownames(.)] %>% unname()) %>%
  3047. .[complete.cases(.), ]
  3048. metadata.all <- read.delim("metadata.tsv")
  3049. for (cc in colnames(metadata.all)[-1]) {
  3050. meta.all[[cc]] <- metadata.all[[cc]][match(meta.all$donors, metadata.all$sample)]
  3051. }
  3052. # Convert integers to numeric
  3053. meta.all$age %<>% as.numeric()
  3054. meta.all$disease_duration %<>% as.numeric()
  3055. ```
  3056. ### CTRL vs MSA
  3057. ```{r}
  3058. meta <- meta.all %>%
  3059. filter(condition != "PD") %>%
  3060. mutate(donors = factor(donors),
  3061. ctypes = factor(ctypes))
  3062. metadata <- metadata.all %>%
  3063. filter(condition != "PD")
  3064. cm.raw <- cm.raw.all %>%
  3065. .[, colnames(.) %in% rownames(meta)]
  3066. # set up project parameters
  3067. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  3068. ncores = 31,
  3069. rand_seed = 10)
  3070. # create project container
  3071. itd_container <- make_new_container(count_data=cm.raw %>% .[, colnames(.) %in% rownames(meta)],
  3072. meta_data=meta,
  3073. params=param_list,
  3074. label_donor_sex = F)
  3075. itd_container %<>% form_tensor(donor_min_cells=5,
  3076. norm_method='trim',
  3077. scale_factor=10000,
  3078. vargenes_method='norm_var_pvals',
  3079. vargenes_thresh=0.2,
  3080. scale_var = TRUE,
  3081. var_scale_power = 0.5) # Diminishable effect at 2, but not on any other level
  3082. print(length(itd_container[["all_vargenes"]]))
  3083. ```
  3084. ```{r}
  3085. itd_container %<>% run_tucker_ica(ranks=c(4,5),
  3086. tucker_type = 'regular',
  3087. rotation_type = 'hybrid')
  3088. # get donor scores-metadata associations
  3089. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  3090. stat_use='pval')
  3091. # plot donor scores
  3092. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "flowcell", "extract"), # Omitting brain bank
  3093. show_donor_ids = TRUE,
  3094. add_meta_associations='pval')
  3095. # show the donor scores heatmap
  3096. p <- itd_container$plots$donor_matrix
  3097. p
  3098. ```
  3099. ### CTRL vs PD
  3100. ```{r}
  3101. meta <- meta.all %>%
  3102. filter(condition != "MSA") %>%
  3103. mutate(donors = factor(donors),
  3104. ctypes = factor(ctypes))
  3105. metadata <- metadata.all %>%
  3106. filter(condition != "MSA")
  3107. cm.raw <- cm.raw.all %>%
  3108. .[, colnames(.) %in% rownames(meta)]
  3109. # set up project parameters
  3110. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  3111. ncores = 31,
  3112. rand_seed = 10)
  3113. # create project container
  3114. itd_container <- make_new_container(count_data=cm.raw,
  3115. meta_data=meta,
  3116. params=param_list,
  3117. label_donor_sex = F)
  3118. itd_container %<>% form_tensor(donor_min_cells=5,
  3119. norm_method='trim',
  3120. scale_factor=10000,
  3121. vargenes_method='norm_var_pvals',
  3122. vargenes_thresh=.4,
  3123. scale_var = TRUE,
  3124. var_scale_power = 1) # No effect at 0.5, but 1, 1.5, 2
  3125. print(length(itd_container[["all_vargenes"]]))
  3126. ```
  3127. ```{r}
  3128. itd_container %<>% run_tucker_ica(ranks=c(4,6),
  3129. tucker_type = 'regular',
  3130. rotation_type = 'hybrid')
  3131. # get donor scores-metadata associations
  3132. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  3133. stat_use='pval')
  3134. # plot donor scores
  3135. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  3136. show_donor_ids = TRUE,
  3137. add_meta_associations='pval')
  3138. # show the donor scores heatmap
  3139. p <- itd_container$plots$donor_matrix
  3140. p
  3141. ```
  3142. ### PD vs MSA
  3143. ```{r}
  3144. meta <- meta.all %>%
  3145. filter(condition != "CTRL") %>%
  3146. mutate(donors = factor(donors),
  3147. ctypes = factor(ctypes))
  3148. metadata <- metadata.all %>%
  3149. filter(condition != "CTRL")
  3150. cm.raw <- cm.raw.all %>%
  3151. .[, colnames(.) %in% rownames(meta)]
  3152. # set up project parameters
  3153. param_list <- initialize_params(ctypes_use = meta$ctypes %>% levels(),
  3154. ncores = 31,
  3155. rand_seed = 10)
  3156. # create project container
  3157. itd_container <- make_new_container(count_data=cm.raw,
  3158. meta_data=meta,
  3159. params=param_list,
  3160. label_donor_sex = F)
  3161. itd_container %<>% form_tensor(donor_min_cells=5,
  3162. norm_method='trim',
  3163. scale_factor=10000,
  3164. vargenes_method='norm_var_pvals',
  3165. vargenes_thresh=.4,
  3166. scale_var = TRUE,
  3167. var_scale_power = 0.5)
  3168. print(length(itd_container[["all_vargenes"]]))
  3169. ```
  3170. ```{r}
  3171. itd_container %<>% run_tucker_ica(ranks=c(5,6),
  3172. tucker_type = 'regular',
  3173. rotation_type = 'hybrid')
  3174. # get donor scores-metadata associations
  3175. itd_container %<>% get_meta_associations(vars_test=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  3176. stat_use='pval')
  3177. # plot donor scores
  3178. itd_container %<>% plot_donor_matrix(meta_vars=c('sex','pmi', "age", "brain_bank", "flowcell", "extract"),
  3179. show_donor_ids = TRUE,
  3180. add_meta_associations='pval')
  3181. # show the donor scores heatmap
  3182. p <- itd_container$plots$donor_matrix
  3183. p
  3184. ```
  3185. ```{r, echo = F}
  3186. rm(con.tmp, cm.raw.all, itd_container)
  3187. gc()
  3188. ```
  3189. # Supplementary Figure 6
  3190. For panels a-d, see `scCODA.ipynb`.
  3191. Load data
  3192. ```{r, fig.width=15, fig.height=8}
  3193. anno.major <- qread("anno_major.qs")
  3194. meta <- read.delim("metadata.tsv", sep = "\t")
  3195. anno.micro <- qread("anno_micro_pvm.qs") %>%
  3196. renameAnnotation("Steady-state","MIC_steady-state") %>%
  3197. renameAnnotation("Intermediate1","MIC_intermediate1") %>%
  3198. renameAnnotation("Intermediate2","MIC_intermediate2") %>%
  3199. renameAnnotation("Activated","MIC_activated")
  3200. anno.glia <- c("anno_astro.qs",
  3201. "anno_oligo.qs",
  3202. "anno_opc.qs") %>%
  3203. lapply(qread) %>%
  3204. Reduce(c, .) %>%
  3205. factor() %>%
  3206. renameAnnotation("Homeostatic_astrocytes", "AS_homeostatic") %>%
  3207. renameAnnotation("Reactive_astrocytes", "AS_reactive") %>%
  3208. renameAnnotation("Homeostatic_LINC01608", "OL_LINC01608") %>%
  3209. renameAnnotation("Homeostatic_SLC5A11", "OL_SLC5A11") %>%
  3210. renameAnnotation("Reactive_SCGZ", "OL_SGCZ")
  3211. anno.neurons <- qread("anno_neurons.qs")
  3212. ```
  3213. ## 6e
  3214. ```{r}
  3215. # Minor final
  3216. anno.minor <- anno.major[!anno.major %in% c("PVMs", "Astrocytes", "Oligodendrocytes", "OPCs", "Microglia")] %>%
  3217. {factor(c(., anno.glia, anno.micro))} %>%
  3218. factor(levels = sort(levels(.)))
  3219. df <- data.frame(cid = names(anno.minor), anno = unname(anno.minor)) %>%
  3220. mutate(sample = strsplit(cid, "!!") %>% sget(1)) %>%
  3221. group_by(sample, anno) %>%
  3222. summarize(n = n()) %>%
  3223. mutate(prop = n / sum(n) * 100) %>%
  3224. ungroup() %>%
  3225. filter(anno %in% c("Inh. neurons", "Exc. neurons", "MSN")) %>%
  3226. mutate(age = meta$age[match(sample, meta$sample)]) %>%
  3227. mutate(age_bin = cut(age, breaks = c(0, 60, 70, 80, 90), labels = c("0-60", "60-70", "70-80", "80-90")),
  3228. condition = grepl.replace(sample, c("CTRL", "MSA", "PD")))
  3229. df %>%
  3230. ggplot(aes(age_bin, prop)) +
  3231. geom_boxplot() +
  3232. geom_point(position = position_dodge(width = 0.85)) +
  3233. theme_bw() +
  3234. facet_wrap(~ anno) -> p
  3235. p
  3236. ```
  3237. Export source data
  3238. ```{r, eval = F}
  3239. p$data %>%
  3240. write.table("source_data/SF6e.tsv", sep = "\t", dec = ".", row.names = F)
  3241. ```
  3242. Statistics
  3243. ```{r}
  3244. df %>%
  3245. group_by(anno) %>%
  3246. rstatix::kruskal_test(prop ~ age_bin) %>%
  3247. mutate(padj = p.adjust(p, method = "BH"))
  3248. ```
  3249. ## 6f
  3250. ```{r, fig.width=15, fig.height=8}
  3251. # Minor final
  3252. anno.minor <- anno.major[!anno.major %in% c("Inh. neurons", "MSN", "Exc. neurons", "PVMs", "Astrocytes", "Oligodendrocytes", "OPCs", "Microglia")] %>%
  3253. {factor(c(., anno.neurons, anno.glia, anno.micro))} %>%
  3254. factor(levels = sort(levels(.)))
  3255. df <- data.frame(cid = names(anno.minor), anno = unname(anno.minor)) %>%
  3256. mutate(sample = strsplit(cid, "!!") %>% sget(1)) %>%
  3257. group_by(sample, anno) %>%
  3258. summarize(n = n()) %>%
  3259. mutate(prop = n / sum(n) * 100) %>%
  3260. ungroup() %>%
  3261. filter(anno %in% levels(anno.micro)) %>%
  3262. mutate(age = meta$age[match(sample, meta$sample)]) %>%
  3263. mutate(age_bin = cut(age, breaks = c(0, 60, 70, 80, 90), labels = c("0-60", "60-70", "70-80", "80-90")),
  3264. condition = grepl.replace(sample, c("CTRL", "MSA", "PD")))
  3265. df %>%
  3266. ggplot(aes(age_bin, prop)) +
  3267. geom_boxplot() +
  3268. geom_point(position = position_dodge(width = 0.85)) +
  3269. theme_bw() +
  3270. facet_wrap(~ anno) -> p
  3271. p
  3272. ```
  3273. Export source data
  3274. ```{r, eval = F}
  3275. p$data %>%
  3276. write.table("source_data/SF6f.tsv", sep = "\t", dec = ".", row.names = F)
  3277. ```
  3278. Statistics
  3279. ```{r}
  3280. df %>%
  3281. group_by(anno) %>%
  3282. rstatix::kruskal_test(prop ~ age_bin) %>%
  3283. mutate(padj = p.adjust(p, method = "BH"))
  3284. ```
  3285. # Supplementary Figure 7
  3286. We're calculating cosine similarities to annotated data from [Garma et al.](https://www.nature.com/articles/s41467-024-50414-w). The data are available [here](https://figshare.com/articles/dataset/Raw_and_processed_snRNA-seq_counts_matrices_from_human_striatal_interneurons/22340140).
  3287. ## Prepare data
  3288. Here, we're showing how we prepared the data. This will not be run again.
  3289. ```{r, eval = F}
  3290. lp.raw <- loomR::connect("Interneurons_raw.loom", mode = "r+", skip.validate = T)
  3291. cm.raw <- lp.raw[["matrix"]][,] %>%
  3292. `dimnames<-`(list(
  3293. lp.raw[["col_attrs/obs_names"]][],
  3294. lp.raw[["row_attrs/var_names"]][]
  3295. ))
  3296. lp.raw$close()
  3297. lp.norm <- loomR::connect("Interneurons_processed.loom", mode = "r+", skip.validate = T)
  3298. anno <- setNames(
  3299. lp.norm$col.attrs$`IN subclass`[],
  3300. lp.norm$col.attrs$obs_names[]
  3301. ) %>%
  3302. factor()
  3303. spc <- setNames(
  3304. lp.norm$col.attrs$sample[],
  3305. lp.norm$col.attrs$obs_names[]
  3306. ) %>%
  3307. factor()
  3308. origin <- setNames(
  3309. lp.norm$col.attrs$Origin[],
  3310. lp.norm$col.attrs$obs_names[]
  3311. ) %>%
  3312. factor()
  3313. area <- setNames(
  3314. lp.norm$col.attrs$Region[],
  3315. lp.norm$col.attrs$obs_names[]
  3316. ) %>%
  3317. factor()
  3318. sex <- setNames(
  3319. lp.norm$col.attrs$Sex[],
  3320. lp.norm$col.attrs$obs_names[]
  3321. ) %>%
  3322. factor()
  3323. umap <- `rownames<-`(lp.norm$col.attrs$X_umap[,] %>% t(),
  3324. lp.norm$col.attrs$obs_names[])
  3325. lp.norm$close()
  3326. ```
  3327. Then, we need to prepare a Conos object of those data. This will not be run here.
  3328. ```{r, eval = F}
  3329. preprocessed <- spc %>%
  3330. split(names(.), .) %>%
  3331. .[sapply(., length) > 50] %>%
  3332. lapply(\(cid) cm.raw[cid, ]) %>%
  3333. lapply(Matrix::t) %>%
  3334. lapply(basicP2proc, get.largevis = F, get.tsne = F, make.geneknn = F, n.cores = 20)
  3335. con <- Conos$new(preprocessed, n.cores = 32)
  3336. con$embeddings$PCA$UMAP <- umap
  3337. con$embedding <- umap
  3338. con$clusters$leiden$groups <- anno
  3339. con$clusters$sex$groups <- sex
  3340. con$clusters$area$groups <- area
  3341. con$clusters$origin$groups <- origin
  3342. con$clusters$spc$groups <- spc
  3343. qsave(con, "con_garma.qs", nthreads = 10)
  3344. ```
  3345. ## 7a
  3346. ```{r}
  3347. # Our data
  3348. rydbirk.neurons.anno <- qread("anno_neurons.qs") %>%
  3349. factor(labels = paste("Rydbirk", levels(.), sep = "-"))
  3350. rydbirk.neurons <- qread("cao_neurons.qs", nthreads = 10)$data.object
  3351. rydbirk.neurons.pseudo <- rydbirk.neurons$getJointCountMatrix(raw = T) %>%
  3352. sccore::collapseCellsByType(groups = rydbirk.neurons.anno, min.cell.count = 1) %>%
  3353. t() %>%
  3354. apply(2, as, "integer")
  3355. rydbirk.neurons.pseudo %<>%
  3356. DESeq2::DESeqDataSetFromMatrix(.,
  3357. colnames(.) %>%
  3358. strsplit("-") %>%
  3359. sget(1) %>%
  3360. data.frame() %>%
  3361. `dimnames<-`(list(colnames(rydbirk.neurons.pseudo), "group")),
  3362. design = ~ 1) %>%
  3363. DESeq2::estimateSizeFactors() %>%
  3364. DESeq2::counts(normalized = T)
  3365. # Garma data
  3366. con.garma <- qread("con_garma.qs", nthreads = 10)
  3367. garma.neurons.anno <- con.garma$clusters$anno$groups %>%
  3368. factor() %>%
  3369. factor(labels = paste("Garma", levels(.), sep = "-"))
  3370. garma.neurons.pseudo <- con.garma$getJointCountMatrix(raw = T) %>%
  3371. sccore::collapseCellsByType(groups = garma.neurons.anno, min.cell.count = 1) %>%
  3372. t() %>%
  3373. apply(2, as, "integer")
  3374. garma.neurons.pseudo %<>%
  3375. DESeq2::DESeqDataSetFromMatrix(.,
  3376. colnames(.) %>%
  3377. strsplit("_") %>%
  3378. sget(1) %>%
  3379. data.frame() %>%
  3380. `dimnames<-`(list(colnames(garma.neurons.pseudo), "group")),
  3381. design = ~ 1) %>%
  3382. DESeq2::estimateSizeFactors() %>%
  3383. DESeq2::counts(normalized = T)
  3384. # We rotate Garma into Rydbirk sample PCA space
  3385. cm.rydbirk <- rydbirk.neurons.pseudo %>%
  3386. as.data.frame() %>%
  3387. filter(rowSums(.) > 0)
  3388. cm.garma <- garma.neurons.pseudo %>%
  3389. as.data.frame() %>%
  3390. filter(rowSums(.) > 0)
  3391. genesToKeep <- conos:::getOdGenesUniformly(append(con.garma$samples, rydbirk.neurons$samples), 50) %>%
  3392. intersect(rownames(cm.rydbirk)) %>%
  3393. intersect(rownames(cm.garma))
  3394. pc.res <-
  3395. cm.rydbirk[genesToKeep, ] %>%
  3396. t() %>%
  3397. prcomp(center = T,
  3398. scale = T)
  3399. pc.tmp <- cm.garma[genesToKeep, ] %>%
  3400. as.data.frame() %>%
  3401. filter(rowSums(.) > 0) %>%
  3402. t() %>%
  3403. scale(pc.res$center, pc.res$scale) %*% pc.res$rotation
  3404. ```
  3405. ```{r, fig.width=9, fig.height=9}
  3406. dat.plot <- rbind(pc.res$x, pc.tmp) %>%
  3407. data.frame() %>%
  3408. mutate(id = rownames(.)) %>%
  3409. mutate(study = ifelse(grepl("Rydbirk", id), "Rydbirk", "Garma") %>% factor(),
  3410. anno = strsplit(id, "-") %>% sget(2))
  3411. lsa::cosine(dat.plot %>%
  3412. select(-id, -study, -anno) %>%
  3413. t()) %>%
  3414. reshape2::melt() %>%
  3415. ggplot(aes(Var1, Var2, fill = value)) +
  3416. geom_tile() +
  3417. scale_fill_gradient2(low = "skyblue3", mid = "white", high = "deeppink3") +
  3418. theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
  3419. labs(title = "Top 50 OD genes, Garma PCA rotation into Rydbirk PCA space") -> p
  3420. p
  3421. ```
  3422. Export source data
  3423. ```{r, eval = F}
  3424. p$data %>%
  3425. write.table("source_data/SF7a.tsv", sep = "\t", dec = ".", row.names = F)
  3426. ```
  3427. ## 7b
  3428. ```{r, fig.width=10, fig.height=8}
  3429. cm.garma.raw <- con.garma$getJointCountMatrix(raw = T)
  3430. cm.rydbirk.raw <- rydbirk.neurons$getJointCountMatrix(raw = T)
  3431. idx <- intersect(colnames(cm.garma.raw), colnames(cm.rydbirk.raw))
  3432. cm.garma.ext <- cm.garma.raw %>%
  3433. sccore:::extendMatrix(idx)
  3434. cm.rydbirk.ext <- cm.rydbirk.raw %>%
  3435. sccore:::extendMatrix(idx)
  3436. cm.comb <- rbind(cm.garma.ext, cm.rydbirk.ext)
  3437. anno.comb <- c(garma.neurons.anno %>% .[names(.) %in% rownames(cm.comb)], rydbirk.neurons.anno %>% .[names(.) %in% rownames(cm.comb)]) %>%
  3438. factor()
  3439. cm.comb %<>% .[rownames(.) %in% names(anno.comb), ]
  3440. unique(
  3441. c("GAD1","GAD2","PPP1R1B","SLC17A7","CHAT","CALB2","DCC","ID2","MEIS2","ST18","NKX2-1","NR2F2","PAX6","PVALB","RXFP1","SST","VIP","RELN","SATB2","DRD1","DRD2","FOXP2", "LRP8", "VLDLR") %>%
  3442. c("CCK", "VIP", "CXCL14", "CHAT", "PTHLH", "MOXD1", "CHST9", "TAC3", "SST", "NPY", "PVALB", "GRIK3", "DACH1", "GAD1", "GAD2")
  3443. ) %>%
  3444. sccore::dotPlot(cm.comb, anno.comb) + scale_color_gradient(low = "grey80", high = "firebrick") -> p
  3445. p
  3446. ```
  3447. Export source data
  3448. ```{r, eval = F}
  3449. p$data %>%
  3450. write.table("source_data/SF7b.tsv", sep = "\t", dec = ".", row.names = F)
  3451. ```
  3452. ```{r, echo = F}
  3453. rm(con.garma, cm.garma.ext, cm.garma.raw, cm.garma)
  3454. gc()
  3455. ```
  3456. # Supplementary Figure 8
  3457. ## Prepare data
  3458. We're calculating cosine similarities to annotated data from [Kamath et al.](https://www.nature.com/articles/s41593-022-01061-1). The data are available [here](https://singlecell.broadinstitute.org/single_cell/study/SCP1768/single-cell-genomic-profiling-of-human-dopamine-neurons-identifies-a-population-that-selectively-degenerates-in-parkinsons-disease-single-nuclei-data).
  3459. ```{r, eval = F}
  3460. cm <- Matrix::readMM("GSE178265_Homo_matrix.mtx") %>%
  3461. `dimnames<-`(list(
  3462. read.delim("GSE178265_Homo_features.tsv", header = F)$V1,
  3463. read.delim("GSE178265_Homo_bcd.tsv", header = F)$V1
  3464. ))
  3465. metadata.raw <- read.delim("METADATA_PD.tsv", header = T)[-1, ]
  3466. cells.to.omit <- metadata.raw %>%
  3467. filter(donor_id %in% c("NIH1", "Rat1", "TreeShrew1")) %>%
  3468. pull(NAME)
  3469. meta.per.cell <- metadata.raw %>%
  3470. filter(!NAME %in% cells.to.omit)
  3471. meta.per.sample <- metadata.raw %>%
  3472. filter(!NAME %in% cells.to.omit) %>%
  3473. select(-NAME, -libname, -biosample_id) %>%
  3474. mutate(area = grepl.replace(organ__ontology_label, c("substantia nigra pars compacta", "caudate nucleus"), c("SN", "CN"))) %>%
  3475. mutate(donor_area = paste(donor_id, area, sep = "-")) %>%
  3476. .[match(unique(.$donor_area), .$donor_area), ]
  3477. cids.per.donor.area <- meta.per.cell %>%
  3478. mutate(area = grepl.replace(organ__ontology_label, c("substantia nigra pars compacta", "caudate nucleus"), c("SN", "CN"))) %>%
  3479. mutate(donor_area = paste(donor_id, area, sep = "-")) %$%
  3480. split(NAME, donor_area)
  3481. cm.list <- meta %>%
  3482. sccore::plapply(\(mm) cm[, colnames(cm) %in% rownames(mm)], n.cores = 7)
  3483. cm.area.donor <- cm.list %>%
  3484. lapply(\(area) sccore::plapply(cids.per.donor.area, \(cid) area[, colnames(area) %in% cid], n.cores = 22)) %>%
  3485. lapply(\(cms) cms[sapply(cms, ncol) > 30]) %>%
  3486. lapply(lapply, as, "CsparseMatrix") %>%
  3487. lapply(lapply, basicP2proc, get.largevis = F, get.tsne = F, make.geneknn = F, n.cores = 20)
  3488. ```
  3489. ```{r, echo = F}
  3490. cm.area.donor <- qread("cm_area_donor.qs", nthreads = 10)
  3491. ```
  3492. ```{r}
  3493. # Annotations
  3494. embeddings <- dir(pattern = "UMAP")
  3495. embeddings %<>%
  3496. lapply(\(type) read.delim(type, header = T, row.names = 1)) %>%
  3497. setNames(embeddings %>% strsplit("_") %>% sget(1)) %>%
  3498. lapply(dplyr::rename, subtype = Cell_Type)
  3499. con.list <- names(embeddings) %>%
  3500. lapply(\(nn) {
  3501. con <- Conos$new(cm.area.donor[[nn]], n.cores = 32)
  3502. con$embeddings <- list(UMAP = embeddings[[nn]][, -3])
  3503. con$embedding <- con$embeddings[[1]]
  3504. con$clusters <- list(leiden = list(groups = embeddings[[nn]] %>% {setNames(pull(., subtype), rownames(.))}))
  3505. return(con)
  3506. }) %>%
  3507. setNames(names(embeddings))
  3508. ```
  3509. ```{r, echo = F}
  3510. rm(cm.area.donor)
  3511. gc()
  3512. ```
  3513. ## Plot
  3514. ```{r}
  3515. # Our data
  3516. rydbirk.neurons.anno <- qread("anno_neurons.qs") %>%
  3517. factor(labels = paste("Rydbirk", levels(.), sep = "-"))
  3518. rydbirk.neurons <- qread("cao_neurons.qs", nthreads = 10)$data.object
  3519. rydbirk.neurons.pseudo <- rydbirk.neurons$getJointCountMatrix(raw = T) %>%
  3520. sccore::collapseCellsByType(groups = rydbirk.neurons.anno, min.cell.count = 1) %>%
  3521. t() %>%
  3522. apply(2, as, "integer")
  3523. rydbirk.neurons.pseudo %<>%
  3524. DESeq2::DESeqDataSetFromMatrix(.,
  3525. colnames(.) %>%
  3526. strsplit("-") %>%
  3527. sget(1) %>%
  3528. data.frame() %>%
  3529. `dimnames<-`(list(colnames(rydbirk.neurons.pseudo), "group")),
  3530. design = ~ 1) %>%
  3531. DESeq2::estimateSizeFactors() %>%
  3532. DESeq2::counts(normalized = T)
  3533. # Kamath data
  3534. kamath.neurons.anno1 <- con.list$da$clusters$leiden$groups %>%
  3535. factor() %>%
  3536. factor(labels = paste("Kamath", levels(.), sep = "-"))
  3537. kamath.neurons.anno2 <- con.list$nonda$clusters$leiden$groups %>%
  3538. factor() %>%
  3539. factor(labels = paste("Kamath", levels(.), sep = "-"))
  3540. kamath.neurons.anno <- factor(c(kamath.neurons.anno1, kamath.neurons.anno2))
  3541. kamath.cm1 <- con.list$da$getJointCountMatrix(raw = T)
  3542. kamath.cm2 <- con.list$nonda$getJointCountMatrix(raw = T)
  3543. kamath.neurons.pseudo <- rbind(kamath.cm1, kamath.cm2) %>%
  3544. sccore::collapseCellsByType(groups = kamath.neurons.anno, min.cell.count = 1) %>%
  3545. t() %>%
  3546. apply(2, as, "integer")
  3547. kamath.neurons.pseudo %<>%
  3548. DESeq2::DESeqDataSetFromMatrix(.,
  3549. colnames(.) %>%
  3550. strsplit("_") %>%
  3551. sget(1) %>%
  3552. data.frame() %>%
  3553. `dimnames<-`(list(colnames(kamath.neurons.pseudo), "group")),
  3554. design = ~ 1) %>%
  3555. DESeq2::estimateSizeFactors() %>%
  3556. DESeq2::counts(normalized = T)
  3557. # We rotate Kamath into Rydbirk sample PCA space
  3558. cm.rydbirk <- rydbirk.neurons.pseudo %>%
  3559. as.data.frame() %>%
  3560. filter(rowSums(.) > 0)
  3561. cm.kamath <- kamath.neurons.pseudo %>%
  3562. as.data.frame() %>%
  3563. filter(rowSums(.) > 0)
  3564. ```
  3565. ```{r, fig.width=9, fig.height=8}
  3566. genesToKeep <- conos:::getOdGenesUniformly(append(con.list$da$samples, rydbirk.neurons$samples) %>% append(con.list$nonda$samples), 100) %>%
  3567. intersect(rownames(cm.rydbirk)) %>%
  3568. intersect(rownames(cm.kamath))
  3569. pc.res <-
  3570. cm.rydbirk[genesToKeep, ] %>%
  3571. t() %>%
  3572. prcomp(center = T,
  3573. scale = T)
  3574. pc.tmp <- cm.kamath[genesToKeep, ] %>%
  3575. as.data.frame() %>%
  3576. filter(rowSums(.) > 0) %>%
  3577. t() %>%
  3578. scale(pc.res$center, pc.res$scale) %*% pc.res$rotation
  3579. # Plot
  3580. dat.plot <- rbind(pc.res$x, pc.tmp) %>%
  3581. data.frame() %>%
  3582. mutate(id = rownames(.)) %>%
  3583. mutate(study = ifelse(grepl("Rydbirk", id), "Rydbirk", "Kamath") %>% factor(),
  3584. anno = strsplit(id, "-") %>% sget(2))
  3585. lsa::cosine(dat.plot %>%
  3586. select(-id, -study, -anno) %>%
  3587. t()) %>%
  3588. reshape2::melt() %>%
  3589. ggplot(aes(Var1, Var2, fill = value)) +
  3590. geom_tile() +
  3591. scale_fill_gradient2(low = "skyblue3", mid = "white", high = "deeppink3") +
  3592. theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
  3593. labs(title = "Top 100 OD genes, Kamath PCA rotation into Rydbirk PCA space") -> p
  3594. p
  3595. ```
  3596. Export source data
  3597. ```{r, eval = F}
  3598. p$data %>%
  3599. write.table("source_data/SF8.tsv", sep = "\t", dec = ".", row.names = F)
  3600. ```
  3601. ```{r, echo = F}
  3602. rm(cm.kamath, kamath.cm1, kamath.cm2, rydbirk.neurons, cm.rydbirk, cm.rydbirk.raw)
  3603. gc()
  3604. ```
  3605. # Supplementary Figure 9
  3606. Here, we use public data from [Smajic *et al*.](https://academic.oup.com/brain/article/145/3/964/6469020). We isolated neurons and used the available annotation (IPDCO_hg_midbrain_cell.tsv).
  3607. ```{r, fig.width=8, fig.height=12}
  3608. con.smajic <- qread("smajic_neurons.qs", nthreads = 10)
  3609. con.neurons <- qread("cao_neurons.qs", nthreads = 10)$data.object
  3610. # Get Smajic annotation
  3611. tmp <- data.frame(cid = rownames(con.smajic$embedding)) %>%
  3612. mutate(barcode = strsplit(cid, "_") %>%
  3613. sget(3))
  3614. anno <- data.table::fread("IPDCO_hg_midbrain_cell.tsv", header = T) %>%
  3615. mutate(barcode = strsplit(barcode, "_") %>%
  3616. sget(1)) %>%
  3617. mutate(cid = tmp$cid[match(barcode, tmp$barcode)]) %>%
  3618. filter(!is.na(cid)) %>%
  3619. pull(cell_ontology, cid) %>%
  3620. .[!. %in% c("Astrocytes", "Endothelial cells", "Ependymal", "Microglia", "Oligodendrocytes", "OPCs", "Pericytes")] %>%
  3621. factor()
  3622. plot.list <- list(
  3623. con.smajic$plotGraph(groups = anno, title = "Smajic neurons, annotation", font.size = 3, shuffle.colors = T, plot.na = F) + theme(line = element_blank()),
  3624. con.neurons$plotGraph(groups = anno.neurons, title = "Rydbirk neurons, annotation", font.size = 3) + theme(line = element_blank()),
  3625. con.smajic$plotGraph(groups = anno, gene = "RELN", title = "RELN expression", plot.na = F) + theme(line = element_blank()),
  3626. con.neurons$plotGraph(gene = "RELN", title = "RELN expression", plot.na = F) + theme(line = element_blank()),
  3627. con.smajic$plotGraph(groups = anno, gene = "CADPS2", title = "CADPS2 expression", plot.na = F) + theme(line = element_blank()),
  3628. con.neurons$plotGraph(gene = "CADPS2", title = "CADPS2 expression", plot.na = F) + theme(line = element_blank()))
  3629. cowplot::plot_grid(plotlist = plot.list, nrow = 3)
  3630. ```
  3631. Export source data
  3632. ```{r, eval = F}
  3633. for (i in seq(length(plot.list))) plot.list[[i]]$data %>% write.table(paste0("source_data/SF9_", i, ".tsv"), sep = "\t", dec = ".", row.names = F)
  3634. ```
  3635. ```{r, echo = F}
  3636. rm(con.smajic, con.neurons)
  3637. gc()
  3638. ```
  3639. # Supplementary Figure 10
  3640. These plots were created with results from LIANA in Python.
  3641. # Supplementary Figure 11
  3642. ```{r}
  3643. cm.merged <- con$getJointCountMatrix(raw = T) %>%
  3644. Matrix::t() %>%
  3645. .[, colnames(.) %in% names(anno.major)]
  3646. # Create sample-wise annotation
  3647. anno.donor <- con$getDatasetPerCell()[colnames(cm.merged)]
  3648. anno.subtype <- anno.major %>%
  3649. .[!is.na(.)] %>%
  3650. factor()
  3651. idx <- intersect(anno.donor %>% names(), anno.subtype %>% names())
  3652. anno.donor %<>% .[idx]
  3653. anno.subtype %<>% .[idx] %>%
  3654. {`names<-`(as.character(.), names(.))}
  3655. anno.final <- paste0(anno.donor,"!!",anno.subtype) %>%
  3656. `names<-`(anno.donor %>% names())
  3657. # Create pseudo CM
  3658. cm.pseudo <- sccore::collapseCellsByType(cm.merged %>% Matrix::t(),
  3659. groups = anno.final, min.cell.count = 1) %>%
  3660. t() %>%
  3661. apply(2, as, "integer")
  3662. cm.pseudo %<>%
  3663. {. + 1} %>%
  3664. DESeq2::DESeqDataSetFromMatrix(.,
  3665. colnames(.) %>%
  3666. strsplit("_") %>%
  3667. sget(1) %>%
  3668. data.frame() %>%
  3669. `dimnames<-`(list(colnames(cm.pseudo), "group")),
  3670. design = ~ group) %>%
  3671. DESeq2::estimateSizeFactors() %>%
  3672. DESeq2::counts(normalized = T)
  3673. ```
  3674. ```{r, fig.width=12, fig.height=24}
  3675. plot.list <- c("TSPO", "COQ2", "MAPT", "FBXO47", "ELOVL7", "EDN1", "GAB1", "TENM2", "RABGEF1", "PLA2G4C", "INPP4B", "ZIC1", "ZIC2", "ZIC3", "ZIC4", "SNCA", "TPPP", "TPPP") %>%
  3676. {Map(\(gene, leg) plotGenePseudoBulk(gene, cm.pseudo, leg), gene = ., leg = c(rep(F, 17), T))}
  3677. cowplot::plot_grid(plotlist = plot.list, ncol = 3)
  3678. ```
  3679. Export source data
  3680. ```{r, eval = F}
  3681. for (i in seq(length(plot.list))) plot.list[[i]]$data %>% write.table(paste0("source_data/SF11_", i, ".tsv"), sep = "\t", dec = ".", row.names = F)
  3682. ```
  3683. # Supplementary Figures 12 & 13
  3684. ## Load and prepare data
  3685. ```{r, fig.width=6, fig.height=4}
  3686. cao <- qread("cao_micro_pvm.qs", nthreads = 10)
  3687. cao$plot.theme <- theme_bw()
  3688. anno.sort <- anno.micro[rownames(cao$data.object$embedding)]
  3689. anno.sel <- anno.sort[!anno.sort %in% c("MIC_intermediate1", "PVMs")] %>% factor()
  3690. emb <- cao$data.object$embedding %>%
  3691. `colnames<-`(c("UMAP1","UMAP2")) %>%
  3692. .[rownames(.) %in% names(anno.sel), ]
  3693. sds_obj <- slingshot(emb,
  3694. anno.sel,
  3695. start.clus = "MIC_steady-state",
  3696. stretch = 0
  3697. )
  3698. sds <- as.SlingshotDataSet(sds_obj)
  3699. pseudotime <- sds_obj@assays@data@listData$pseudotime[, 1]
  3700. ```
  3701. ## 12a
  3702. ```{r, fig.width=6, fig.height=4}
  3703. plot.df <- cao$data.object$embedding %>%
  3704. as.data.frame() %>%
  3705. .[rownames(.) %in% names(sds_obj), ] %>%
  3706. `colnames<-`(c("UMAP1","UMAP2")) %>%
  3707. mutate(., annotation = anno.micro[rownames(.)] %>% as.factor()) %>%
  3708. .[complete.cases(.),]
  3709. ldata <- getTscanTrajectory(cao$data.object, anno.sel)
  3710. cao$data.object$embedding %>%
  3711. as.data.frame() %>%
  3712. mutate(., unname(anno.micro[rownames(.)])) %>%
  3713. setNames(c("UMAP1", "UMAP2", "annotation")) %>%
  3714. mutate(., pseudotime = pseudotime[rownames(.)]) %>%
  3715. ggplot() +
  3716. geom_point(aes(UMAP1, UMAP2, col = pseudotime), size = 0.3) +
  3717. geom_line(data = ldata, aes(UMAP1, UMAP2, group = edge), linewidth = 1) +
  3718. theme_bw() +
  3719. theme(line = element_blank()) +
  3720. scale_color_gradient(low = "navyblue", high = "orange") +
  3721. labs(col = "Pseudotime", x = "UMAP1", y = "UMAP2") -> p
  3722. p
  3723. ```
  3724. Export source data
  3725. ```{r, eval = F}
  3726. p$data %>%
  3727. write.table("source_data/SF12a.tsv", sep = "\t", dec = ".", row.names = F)
  3728. ```
  3729. ## 12b
  3730. Here, we show the code for running the generalized additive mixed model. It takes a significant amount of time to run, we provide data in `pseudotime_micro_l1.qs`.
  3731. ```{r, eval = F}
  3732. mat <- cao$data.object$getJointCountMatrix() %>%
  3733. .[match(names(sds_obj), rownames(.)), colSums(.) > 2e2] %>%
  3734. .[, !grepl(pattern = "RPL|RPS|MT-", colnames(.))]
  3735. mt <- mat %>%
  3736. as.matrix() %>%
  3737. as.data.frame() %>%
  3738. tibble::rownames_to_column() %>%
  3739. {message("Mutating"); mutate(.,
  3740. pseudotime = pseudotime[rowname],
  3741. condition = cao$data.object$getDatasetPerCell()[rowname] %>%
  3742. as.character() %>%
  3743. strsplit("_") %>%
  3744. sget(1),
  3745. sample = strsplit(rowname, "!!") %>%
  3746. sget(1))} %>%
  3747. .[complete.cases(.), ] %>%
  3748. {message("Melting"); reshape2::melt(., id.vars = c("rowname", "pseudotime", "condition", "sample"))} %$%
  3749. {message("Splitting"); split(., variable)}
  3750. ```
  3751. ```{r, eval = F}
  3752. res <- mt %>%
  3753. sccore::plapply(\(x) {
  3754. fit_full <- gamm4(data = x, formula = value ~ s(pseudotime, by = factor(condition)), random = ~(1 | sample), REML = F)
  3755. fit_reduced <- gamm4(data = x, formula = value ~ s(pseudotime), random = ~(1 | sample), REML = F)
  3756. fit_none <- gamm4(data = x, formula = value ~ 1, random = ~(1 | sample), REML = F)
  3757. ann <- anova(fit_full$mer, fit_reduced$mer, fit_none$mer)
  3758. if (any(ann$`Pr(>Chisq)` <= 0.05, na.rm = T)) {
  3759. residuals <- predict(fit_full$gam, se.fit = T)$fit %>%
  3760. unname()
  3761. r.sq <- c(summary(fit_full$gam)$r.sq, summary(fit_reduced$gam)$r.sq) %>%
  3762. setNames(c("full", "reduced"))
  3763. out <- list(anova = ann,
  3764. residuals = residuals,
  3765. r.sq = r.sq)
  3766. return(out)
  3767. }
  3768. }, n.cores = 40, mc.preschedule = T, mc.cleanup = T, progress = F) %>%
  3769. .[!sapply(., is.null)]
  3770. qsave(res, "pseudotime_micro_l1.qs")
  3771. ```
  3772. ```{r, fig.height=4, fig.width=6}
  3773. res <- qread("pseudotime_micro_l1.qs")
  3774. rsq.pseudo <- res %>%
  3775. sapply(\(gene) gene$r.sq[1]) %>%
  3776. sort(decreasing = T)
  3777. res.filter <- res[names(rsq.pseudo)[seq(50)] %>% strsplit(".", fixed = T) %>% sget(1)]
  3778. cm.merged <- cao$data.object$getJointCountMatrix() %>%
  3779. .[match(names(pseudotime), rownames(.)), colnames(.) %in% names(res.filter)] %>%
  3780. .[rowSums(.) > 0, ]
  3781. ## Predict smoothend expression
  3782. pseudotime.both <- pseudotime[rownames(cm.merged)]
  3783. weights.both <- sds_obj@assays@data@listData$weights %>% .[match(names(pseudotime.both), rownames(.)), 1] + 1E-7
  3784. scFit <- cm.merged %>%
  3785. Matrix::t() %>%
  3786. tradeSeq::fitGAM(pseudotime = pseudotime.both, cellWeights = weights.both, verbose = T)
  3787. Smooth <- tradeSeq::predictSmooth(scFit, gene = colnames(cm.merged), tidy = F, n=100)
  3788. # Average across replicates and scale
  3789. Smooth <- t(scale(t(Smooth)))
  3790. # Seriate the results
  3791. Smooth <- Smooth[ seriation::get_order(seriation::seriate(Smooth, method="PCA_angle")), ]
  3792. # Create heatmap
  3793. col_fun = circlize::colorRamp2(c(-4, 0, 4), c("navy", "white", "firebrick"))
  3794. Heatmap(Smooth,
  3795. col = col_fun,
  3796. cluster_columns=F,
  3797. cluster_rows=F,
  3798. show_column_names = F,
  3799. row_names_gp = grid::gpar(fontsize = 5)) -> p
  3800. p
  3801. ```
  3802. Export source data
  3803. ```{r, eval = F}
  3804. p@matrix %>%
  3805. write.table("source_data/SF12b.tsv", sep = "\t", dec = ".", row.names = T)
  3806. ```
  3807. ## 13
  3808. ```{r, fig.height=40, fig.width=20}
  3809. cpc <- pseudotime %>%
  3810. names() %>%
  3811. strsplit("_") %>%
  3812. sget(1) %>%
  3813. factor()
  3814. res.filter %>%
  3815. lget("residuals") %>%
  3816. lapply(as.data.frame) %>%
  3817. lapply(setNames, "residuals") %>%
  3818. lapply(mutate, group = cpc, pseudotime = pseudotime) %>%
  3819. data.table::rbindlist(idcol = "gene") %>%
  3820. ggplot(aes(pseudotime, residuals, col = group)) +
  3821. geom_smooth() +
  3822. theme_bw() +
  3823. facet_wrap(~gene, ncol = 5, scales = "free") -> p
  3824. p
  3825. ```
  3826. Export source data
  3827. ```{r, eval = F}
  3828. p$data %>%
  3829. write.table("source_data/SF13.tsv", sep = "\t", dec = ".", row.names = F)
  3830. ```
  3831. # Supplementary Figure 15
  3832. Here, we use public data from [Feleke *et al*.](https://link.springer.com/article/10.1007/s00401-021-02343-x). We isolated microglia based on CSF1R expression and performed a quick annotation using AIF1 expression to identify activated microglia.
  3833. ```{r, fig.width=8, fig.height=8}
  3834. con.micro <- qread("feleke_micro.qs")
  3835. anno.micro <- getConosCluster(con.micro) %>%
  3836. factor(labels = c("Cluster1", "Activated", "Cluster2", "Cluster2"))
  3837. # We set sample groups manually as it can't be inferred from sample names
  3838. sample.groups <- c("CTRL", "CTRL", "DLB", "DLB", "DLB", "DLB", "DLB", "PDD", "PDD", "PD", "PDD", "PD", "PDD", "PD", "PDD", "PDD", "DLB", "PD", "PDD", "PD", "DLB", "PD", "PD", "CTRL", "CTRL", "CTRL", "CTRL", "CTRL") %>%
  3839. setNames(names(con.micro$samples))
  3840. ```
  3841. ```{r, fig.width=4, fig.height=4}
  3842. con.clone <- con.micro$clone()
  3843. con.clone$samples <- con.micro$samples %>% .[which(sample.groups %in% c("CTRL", "PD"))]
  3844. sample.groups.clone <- sample.groups %>% .[. %in% c("CTRL", "PD")]
  3845. cao <- Cacoa$new(con.clone, sample.groups = sample.groups.clone, ref.level = "CTRL", target.level = "PD", cell.groups = anno.micro, n.cores = 32)
  3846. p <- cao$plotCellGroupSizes() + theme(line = element_blank())
  3847. p
  3848. ```
  3849. Export source data
  3850. ```{r, eval = F}
  3851. p$data %>%
  3852. write.table("source_data/SF15_1.tsv", sep = "\t", dec = ".", row.names = F)
  3853. ```
  3854. ```{r, fig.width=4, fig.height=4}
  3855. cao$estimateCellLoadings()
  3856. cao$plotCellLoadings()
  3857. p <- cao$plotCellLoadings(show.pvals = F)
  3858. ```
  3859. Export source data
  3860. ```{r, eval = F}
  3861. p$data %>%
  3862. write.table("source_data/SF15_1.tsv", sep = "\t", dec = ".", row.names = F)
  3863. ```
  3864. ```{r, fig.width=4, fig.height=4}
  3865. p <- con.clone$plotGraph(size = 0.3, groups = anno.micro, font.size = 5) + theme(line = element_blank())
  3866. p
  3867. ```
  3868. Export source data
  3869. ```{r, eval = F}
  3870. p$data %>%
  3871. write.table("source_data/SF15_2.tsv", sep = "\t", dec = ".", row.names = F)
  3872. ```
  3873. ```{r, fig.width=4, fig.height=4}
  3874. p <- con.clone$plotGraph(gene = "AIF1", title = "AIF1", plot.na = F) + theme(line = element_blank())
  3875. p
  3876. ```
  3877. Export source data
  3878. ```{r, eval = F}
  3879. p$data %>%
  3880. write.table("source_data/SF15_3.tsv", sep = "\t", dec = ".", row.names = F)
  3881. ```
  3882. ```{r, echo = F}
  3883. rm(con.clone, con.micro, cao)
  3884. gc()
  3885. ```
  3886. # Supplementary Figure 16
  3887. ## 16a
  3888. We provide the results output from scHLAcount in `scHLAcount.zip`.
  3889. ```{r}
  3890. samples <- dir("scHLAcount/rydbirk/") %>% .[grepl(pattern = "_", .)]
  3891. cms <- lapply(samples, function(x) {
  3892. labels <- read.delim(paste0("scHLAcount/rydbirk/",x,"/labels.tsv"), header = F) %>% .[,1]
  3893. barcodes <- read.delim(paste0("scHLAcount/rydbirk/",x,"/barcodes.tsv"), header = F) %>%
  3894. .[,1] %>%
  3895. sapply(function(y) paste0(x,"one_",y))
  3896. mtx <- Matrix::readMM(paste0("scHLAcount/rydbirk/",x,"/count_matrix.mtx")) %>%
  3897. t() %>%
  3898. `dimnames<-`(list(barcodes, labels)) %>%
  3899. .[rowSums(.) > 0,] # Remove cells with no counts
  3900. tmp <- colnames(mtx) %>%
  3901. strsplit("*", T) %>%
  3902. sapply(`[[`, 1)
  3903. # If more than one allele per HLA type has been detected, sum per HLA type
  3904. if(any(tmp %>% table() %>% as.numeric() > 1)) {
  3905. cs <- colSums(mtx)
  3906. alleles <- unique(tmp)
  3907. mtx <- lapply(alleles, function(y) mtx[,tmp == y]) %>%
  3908. lapply(function(y) {
  3909. if(class(y) == "dgTMatrix") rowSums(y) else y
  3910. }) %>%
  3911. unlist() %>%
  3912. Matrix(nrow = nrow(mtx)) %>%
  3913. `rownames<-`(rownames(mtx))
  3914. }
  3915. colnames(mtx) <- unique(tmp)
  3916. return(mtx)
  3917. }) %>%
  3918. setNames(samples)
  3919. ```
  3920. Calculations
  3921. ```{r}
  3922. # Cell-wise
  3923. cell.counts <- sapply(cms, rowSums) %>%
  3924. unname() %>%
  3925. unlist() %>%
  3926. `names<-`(., gsub("one_","!!",names(.)))
  3927. depth <- getConosDepth(con) %>%
  3928. .[match(names(cell.counts), names(.))] %>%
  3929. {data.frame(cell = names(.),
  3930. sample = names(.) %>% strsplit("!!", T) %>% sapply(`[[`, 1),
  3931. depth = unname(.))}
  3932. depth[is.na(depth)] <- 0
  3933. cell.group <- grepl.replace(names(cell.counts), patterns = c("CTRL","PD","MSA")) %>% as.factor()
  3934. mhc1.raw <- sapply(cms, function(x) {
  3935. tmp <- x[,colnames(x) %in% c("A","B","C")]
  3936. if(class(tmp) != "numeric") rowSums(tmp) else tmp
  3937. }) %>%
  3938. unname() %>%
  3939. unlist() %>%
  3940. `names<-`(., gsub("one_","!!",names(.)))
  3941. mhc2.raw <- sapply(cms, function(x) {
  3942. tmp <- x[,!colnames(x) %in% c("A","B","C")]
  3943. if(class(tmp) != "numeric") rowSums(tmp) else tmp
  3944. }) %>%
  3945. unname() %>%
  3946. unlist() %>%
  3947. `names<-`(., gsub("one_","!!",names(.)))
  3948. cell.df <- data.frame(group = cell.group,
  3949. counts = cell.counts,
  3950. mhc1 = mhc1.raw,
  3951. mhc2 = mhc2.raw,
  3952. depth = depth$depth) %>%
  3953. mutate(., anno = anno.major[match(rownames(.), names(anno.major))],
  3954. sample = rownames(.) %>% sapply(strsplit, "!!", T) %>% sapply(`[[`, 1)) %>%
  3955. mutate(type = grepl.replace(anno %>% as.character(), levels(anno), c("Brain","Brain","Brain","Peripheral","Peripheral","Peripheral","Brain","Brain","Brain","Brain"))) %>%
  3956. `rownames<-`(names(cell.counts)) %>%
  3957. filter(!is.na(anno))
  3958. ```
  3959. Load Smajic data
  3960. ```{r}
  3961. samples <- dir("scHLAcount/smajic") %>% .[grepl(pattern = "SRR", .)]
  3962. cms <- lapply(samples, function(x) {
  3963. labels <- read.delim(paste0("scHLAcount/smajic/",x,"/labels.tsv"), header = F) %>% .[,1]
  3964. barcodes <- read.delim(paste0("scHLAcount/smajic/",x,"/barcodes.tsv"), header = F) %>%
  3965. .[,1] %>%
  3966. sapply(function(y) paste0(x,"_",y,"_1"))
  3967. mtx <- Matrix::readMM(paste0("scHLAcount/smajic/",x,"/count_matrix.mtx")) %>%
  3968. t() %>%
  3969. `dimnames<-`(list(barcodes, labels)) %>%
  3970. .[rowSums(.) > 0,] # Remove cells with no counts
  3971. tmp <- colnames(mtx) %>%
  3972. strsplit("*", T) %>%
  3973. sapply(`[[`, 1)
  3974. # If more than one allele per HLA type has been detected, sum per HLA type
  3975. if(any(tmp %>% table() %>% as.numeric() > 1)) {
  3976. cs <- colSums(mtx)
  3977. alleles <- unique(tmp)
  3978. mtx <- lapply(alleles, function(y) mtx[,tmp == y]) %>%
  3979. lapply(function(y) {
  3980. if(class(y) == "dgTMatrix") rowSums(y) else y
  3981. }) %>%
  3982. unlist() %>%
  3983. Matrix(nrow = nrow(mtx)) %>%
  3984. `rownames<-`(rownames(mtx))
  3985. }
  3986. colnames(mtx) <- unique(tmp)
  3987. return(mtx)
  3988. }) %>%
  3989. setNames(samples)
  3990. # Correct naming
  3991. name.df <- data.frame(samples = samples, ids = c(rep("PD",6) %>% mapply(function(x,y) paste0(x,y), x = ., y = c(1,1,2:5)),
  3992. rep("CTRL",6) %>% mapply(function(x,y) paste0(x,y), x = ., y = 1:6)))
  3993. anno <- readRDS(paste0("scHLAcount/smajic/anno.sma.rds")) %>%
  3994. setNames(., names(.) %>%
  3995. strsplit("_", T) %>%
  3996. lapply(function(x) {
  3997. if(grepl("C", x[[1]])) x[[1]] %<>% gsub("C","CTRL", .)
  3998. return(x)
  3999. }) %>%
  4000. sapply(function(x) paste0(x[[1]],"_",x[[2]])))
  4001. cms <- 1:12 %>%
  4002. lapply(function(x) {
  4003. rnames <- cms[[x]] %>%
  4004. rownames() %>%
  4005. names() %>%
  4006. sapply(function(y) paste0(name.df[x,2],"_",y)) %>%
  4007. unname()
  4008. rownames(cms[[x]]) <- rnames
  4009. return(cms[[x]])
  4010. }) %>%
  4011. setNames(names(cms))
  4012. ```
  4013. Calculations
  4014. ```{r}
  4015. cell.df.rydbirk <- cell.df
  4016. # Cell-wise
  4017. cell.counts <- sapply(cms, rowSums) %>%
  4018. unname() %>%
  4019. unlist()
  4020. rem <- cell.counts %>%
  4021. names() %>%
  4022. table() %>%
  4023. .[. > 1] %>%
  4024. names()
  4025. cell.counts %<>% .[!names(.) %in% rem]
  4026. cell.group <- grepl.replace(names(cell.counts), patterns = c("CTRL","PD")) %>% as.factor()
  4027. mhc1.raw <- sapply(cms, function(x) {
  4028. tmp <- x[,colnames(x) %in% c("A","B","C")]
  4029. if(class(tmp) != "numeric") rowSums(tmp) else tmp
  4030. }) %>%
  4031. unname() %>%
  4032. unlist() %>%
  4033. .[!names(.) %in% rem]
  4034. mhc2.raw <- sapply(cms, function(x) {
  4035. tmp <- x[,!colnames(x) %in% c("A","B","C")]
  4036. if(class(tmp) != "numeric") rowSums(tmp) else tmp
  4037. }) %>%
  4038. unname() %>%
  4039. unlist() %>%
  4040. .[!names(.) %in% rem]
  4041. cell.df <- data.frame(group = cell.group,
  4042. counts = cell.counts,
  4043. mhc1 = mhc1.raw,
  4044. mhc2 = mhc2.raw) %>%
  4045. mutate(., anno = anno[match(rownames(.), names(anno))],
  4046. sample = rownames(.) %>% sapply(strsplit, "_", T) %>% sapply(`[[`, 1)) %>%
  4047. `rownames<-`(names(cell.counts)) %>%
  4048. filter(!is.na(anno))
  4049. ```
  4050. Integrate with our data and plot
  4051. ```{r, fig.width = 8, fig.height = 4}
  4052. cell.df.int <- rbind(cell.df.rydbirk %>%
  4053. select(-c("depth","type")) %>%
  4054. mutate(origin = "Rydbirk"),
  4055. cell.df %>%
  4056. mutate(anno = anno %>% factor(labels = c("Astrocytes","Exc. neurons","Inh. neurons","Endothelial","Eppendymal","Exc. neurons","Inh. neurons","Inh. neurons","Microglia","Oligodendrocytes","OPCs","Pericytes")),
  4057. origin = "Smajic")) %>%
  4058. filter(! anno %in% c("Blood_immune","Endothelial","Eppendymal","Mural","Pericytes","Pericytes/endothelial","Immune")) %>%
  4059. filter(!is.na(anno)) %>%
  4060. mutate(anno = anno %>% factor(),
  4061. origin = origin %>% factor(),
  4062. anno = anno %>% unname() %>% factor(),
  4063. sample = sample %>% unname())
  4064. cell.anno.df <-
  4065. cell.df.int %>%
  4066. group_by(anno, sample, group, origin) %>%
  4067. summarise(mhc1 = mean(mhc1),
  4068. mhc2 = mean(mhc2),
  4069. counts = mean(counts),
  4070. cells = length(sample)) %>%
  4071. as.data.frame() %>%
  4072. select(-cells, -counts, -sample)
  4073. p.text1 <- data.frame(signif = c("n.s.", "n.s.", "n.s.", "n.s.", "n.s.", "0.040", "0.032", "n.s."),
  4074. mhc1 = 4.5,
  4075. anno = levels(cell.anno.df$anno))
  4076. p.text2 <- data.frame(signif = c("0.00057"),
  4077. mhc2 = 8.5,
  4078. anno = " Microglia")
  4079. plot.list <- list(
  4080. ggplot(cell.anno.df,
  4081. aes(anno,
  4082. mhc1)) +
  4083. geom_boxplot(outlier.shape = NA,
  4084. aes(fill = group)) +
  4085. geom_point(position = position_jitterdodge(jitter.width = 0.2),
  4086. aes(fill = group,
  4087. col = origin,
  4088. shape = group),
  4089. size = 2) +
  4090. scale_color_manual(values = c("black",
  4091. "grey50")) +
  4092. labs(x = "",
  4093. y = "Mean counts per sample",
  4094. title = "MHC-I counts",
  4095. fill = "",
  4096. col = "",
  4097. shape = " ") +
  4098. geom_text(data = p.text1, aes(label = signif)) +
  4099. theme_bw() +
  4100. scale_fill_manual(values = pal.major) +
  4101. theme(legend.position = "none",
  4102. axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
  4103. line = element_blank()),
  4104. ggplot(cell.anno.df %>% filter(anno == "Microglia") %>% mutate(anno = " Microglia"), aes(anno, mhc2)) +
  4105. geom_boxplot(outlier.shape = NA, aes(fill = group)) +
  4106. geom_point(position = position_jitterdodge(jitter.width = 0.2), aes(fill = group, col = origin, shape = group), size = 2) +
  4107. scale_color_manual(values = c("black","grey50")) +
  4108. labs(x = "", y = "", title = "MHC-II counts", fill = "", col = "", shape = " ") +
  4109. geom_text(data = p.text2, aes(label = signif)) +
  4110. theme_bw() +
  4111. scale_fill_manual(values = pal.major) +
  4112. theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
  4113. line = element_blank())
  4114. )
  4115. cowplot::plot_grid(plotlist = plot.list, ncol = 2, rel_widths = c(2,0.9))
  4116. ```
  4117. Export source data
  4118. ```{r, eval = F}
  4119. for (i in seq(length(plot.list))) plot.list[[i]]$data %>% write.table(paste0("source_data/SF16a_", i, ".tsv"), sep = "\t", dec = ".", row.names = F)
  4120. ```
  4121. Kruskal-Wallis, asses differences per cell type
  4122. ```{r}
  4123. cell.anno.df %>%
  4124. group_by(anno) %>%
  4125. kruskal_test(mhc1 ~ group) %>%
  4126. data.frame()
  4127. cell.anno.df %>%
  4128. filter(anno == "Microglia") %>%
  4129. group_by(anno) %>%
  4130. kruskal_test(mhc2 ~ group) %>%
  4131. data.frame()
  4132. ```
  4133. Wilcoxon, assess differences between our data and Smajic per condition per cell type
  4134. ```{r}
  4135. cell.anno.df %>%
  4136. filter(group != "MSA",
  4137. !anno %in% c("MSN","PVMs")) %>%
  4138. group_by(anno, group) %>%
  4139. wilcox_test(mhc1 ~ origin) %>%
  4140. data.frame()
  4141. cell.anno.df %>%
  4142. filter(group != "MSA",
  4143. anno == "Microglia") %>%
  4144. group_by(anno, group) %>%
  4145. wilcox_test(mhc2 ~ origin) %>%
  4146. data.frame()
  4147. ```
  4148. ## 16b
  4149. We provide a curated list with MHC and cytokine genes. Please note, the order of clusters may change.
  4150. ```{r, fig.width=4, fig.height=4}
  4151. dat <- read.table("MHC_cytokines_curated.tsv", header = T, sep = "\t")
  4152. cm.merged <- con$getJointCountMatrix(raw = T) %>%
  4153. Matrix::t() %>%
  4154. .[, colnames(.) %in% names(anno.major)] %>%
  4155. .[rownames(.) %in% (dat$name[dat$class == "cytokine"] %>% gsub("-","",.)), ] %>%
  4156. .[rowSums(.) > 0,]
  4157. # Create sample-wise annotation
  4158. anno.donor <- con$getDatasetPerCell()[colnames(cm.merged)]
  4159. anno.subtype <- anno.major %>%
  4160. .[!is.na(.) & (. %in% c("Microglia", "PVMs"))] %>%
  4161. factor()
  4162. idx <- intersect(anno.donor %>% names(), anno.subtype %>% names())
  4163. anno.donor %<>% .[idx]
  4164. anno.subtype %<>% .[idx] %>%
  4165. {`names<-`(as.character(.), names(.))}
  4166. anno.final <- paste0(anno.donor,"!!",anno.subtype) %>%
  4167. `names<-`(anno.donor %>% names())
  4168. # Create pseudo CM
  4169. cm.pseudo <- sccore::collapseCellsByType(cm.merged %>% Matrix::t(),
  4170. groups = anno.final, min.cell.count = 1) %>%
  4171. t() %>%
  4172. apply(2, as, "integer")
  4173. cm.pseudo %<>%
  4174. {. + 1} %>%
  4175. DESeq2::DESeqDataSetFromMatrix(.,
  4176. colnames(.) %>%
  4177. strsplit("_") %>%
  4178. sget(1) %>%
  4179. data.frame() %>%
  4180. `dimnames<-`(list(colnames(cm.pseudo), "group")),
  4181. design = ~ group) %>%
  4182. DESeq2::estimateSizeFactors() %>%
  4183. DESeq2::counts(normalized = T)
  4184. cm.pseudo %<>%
  4185. Matrix::t() %>%
  4186. scale() %>%
  4187. Matrix::t()
  4188. ord <- cm.pseudo %>%
  4189. colnames() %>%
  4190. {data.frame(id = .)} %>%
  4191. mutate(.,
  4192. ct = strsplit(id, "!!") %>%
  4193. sget(2),
  4194. condition = strsplit(id, "!!|_") %>%
  4195. sget(1)) %>%
  4196. arrange(ct, condition) %>%
  4197. pull(id)
  4198. cm.pseudo %<>%
  4199. .[, match(ord, colnames(.))]
  4200. cm.pseudo %<>%
  4201. as.data.frame() %>%
  4202. tibble::rownames_to_column(var = "gene") %>%
  4203. reshape2::melt(id.vars = c("gene")) %>%
  4204. mutate(variable = as.character(variable),
  4205. condition = strsplit(variable, "!!|_") %>%
  4206. sget(1),
  4207. ct = strsplit(variable, "!!") %>%
  4208. sget(2)) %>%
  4209. group_by(condition, ct, gene) %>%
  4210. summarize(m = mean(value)) %>%
  4211. ungroup() %>%
  4212. mutate(variable = paste(condition, ct, sep = "!!")) %>%
  4213. select(-condition, -ct) %>%
  4214. reshape2::dcast(gene ~ variable, value.var = "m") %>%
  4215. tibble::column_to_rownames(var = "gene")
  4216. tmp <- cm.pseudo %>%
  4217. colnames() %>%
  4218. strsplit("_|!!")
  4219. clusters <- tmp %>%
  4220. sget(2)
  4221. condition <- tmp %>%
  4222. sget(1)
  4223. ha <- ComplexHeatmap::HeatmapAnnotation(Annotation = clusters,
  4224. Condition = condition,
  4225. col = list(Annotation = c("Microglia" = unname(pal.major["Microglia"]),
  4226. "PVMs" = unname(pal.major["PVMs"])),
  4227. Condition = c("CTRL" = unname(pal.major["CTRL"]),
  4228. "MSA" = unname(pal.major["MSA"]),
  4229. "PD" = unname(pal.major["PD"]))
  4230. ))
  4231. ComplexHeatmap::Heatmap(cm.pseudo,
  4232. name = "Expression",
  4233. show_column_names = F,
  4234. show_row_names = T,
  4235. cluster_columns = F,
  4236. show_column_dend = F,
  4237. cluster_rows = T,
  4238. top_annotation = ha,
  4239. show_row_dend = F,
  4240. column_split = colnames(cm.pseudo) %>% strsplit("!!|_") %>% sget(2) %>% unname() %>% factor(),
  4241. col=circlize::colorRamp2(c(-1, 1.2), c("white", "firebrick")),
  4242. row_km = 4) -> p
  4243. p
  4244. ```
  4245. Export source data
  4246. ```{r, eval = F}
  4247. p@matrix %>%
  4248. write.table("source_data/SF16b.tsv", sep = "\t", dec = ".", row.names = T)
  4249. ```
  4250. # Supplementary Figure 17
  4251. ## 17c
  4252. ```{r, fig.width=14, fig.height=6}
  4253. c("FOSL2", "TCF4", "STAT1", "NR3C1", "ETV7", "THRB", "BPTF", "RELB", "CEBPD", "HIF1A", "ELF1", "CREM", "ELF2", "ZNF44", "CHD1", "POU2F1", "GTF2IRD1", "NFIA", "NFE2L2", "FOXP1", "FOXO3") %>%
  4254. clusterProfiler::enrichGO("org.Hs.eg.db", "SYMBOL", "BP") %>%
  4255. enrichplot::pairwise_termsim() %>%
  4256. enrichplot::treeplot() +
  4257. scale_fill_manual(values = brewer.pal(6, "Greys")[-1]) -> p
  4258. p
  4259. ```
  4260. Export source data
  4261. ```{r, eval = F}
  4262. p@data %>%
  4263. write.table("source_data/SF17c.tsv", sep = "\t", dec = ".", row.names = F)
  4264. ```
  4265. # Supplementary Figure 18
  4266. ## 18a
  4267. We provide the results from scDRS based on Nalls *et al.* GWAS summary stats. For calculation of these, see `scDRS_PD.ipynb`.
  4268. ```{r, fig.width=6, fig.height=4}
  4269. dat.scores <- qread("gwas/nalls/PD.full_score.qs")
  4270. # Load downstream analyses for cell types versus trait
  4271. dat.ct <- read.delim("gwas/nalls/downstream_celltype.tsv", header = F, sep = "\t") %$%
  4272. strsplit(V1, " ") %>%
  4273. unlist() %>%
  4274. gsub("\\", "", ., fixed = T) %>%
  4275. gsub("\n", "", ., fixed = T) %>%
  4276. .[!sapply(., \(x) x == "")] %>%
  4277. .[c(1:5,69:72, # Header
  4278. 8:12,75:78, # Astro
  4279. 15:19,81:84, # EN
  4280. 21:25,86:89, # Immune
  4281. 28:32,92:95, # IN
  4282. 34:38,97:100, # MSN
  4283. 40:44,102:105, # MIC
  4284. 46:50,107:110, # OPCs
  4285. 52:56,112:115, # OL
  4286. 58:62,117:120, # PVMs
  4287. 64:68,122:125 # Peri
  4288. )]
  4289. dat.sign <- dat.ct %>%
  4290. split(seq(9)) %>%
  4291. bind_rows() %>%
  4292. {`colnames<-`(.[-1, ], .[1, ])} %>%
  4293. as.data.frame()
  4294. dat.sign %<>% mutate(group = c("Astrocytes",
  4295. "Exc. neurons",
  4296. "Immune",
  4297. "Inh. neurons",
  4298. "MSN",
  4299. "Microglia",
  4300. "OPCs",
  4301. "Oligodendrocytes",
  4302. "PVMs",
  4303. "Pericytes/endothelial"))
  4304. dat.sign %<>%
  4305. filter(!group == "Unknown") %>%
  4306. mutate(assoc_sign = as.numeric(assoc_mcp) %>% sapply(\(x) if (x <= 0.05) paste("*", formatC(x, digits = 2), sep = " ") else ""),
  4307. hetero_sign = as.numeric(hetero_mcp) %>% sapply(\(x) if (x <= 0.05) paste("#", formatC(x, digits = 2), sep = " ") else " ")) %>%
  4308. mutate(sign = paste0(assoc_sign,"\n",hetero_sign) %>% gsub("\n ", "", .)) %>%
  4309. dplyr::rename(type = group)
  4310. p <- data.frame(cell = dat.scores$X,
  4311. score = dat.scores$norm_score,
  4312. type = anno.major[match(dat.scores$X,
  4313. names(anno.major))]) %>%
  4314. group_by(type) %>%
  4315. summarize(m = median(score)) %>%
  4316. filter(!is.na(type)) %>%
  4317. mutate(type = as.character(type)) %$%
  4318. arrange(., desc(m)) %>%
  4319. mutate(type = factor(type, levels = type), sign = dat.sign$sign[match(type %>% levels, dat.sign$type)]) %>%
  4320. ggplot(aes(type, m, fill = type)) +
  4321. geom_bar(stat = "identity") +
  4322. geom_text(aes(label = sign), vjust = -0.5) +
  4323. theme_bw() +
  4324. labs(y = "Mean score", x = "", title = "scDRS mean scores and associations") +
  4325. guides(fill = "none") +
  4326. theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
  4327. line = element_blank()) +
  4328. ylim(c(-0.6, 2.6)) +
  4329. scale_fill_manual(values = pal.major) +
  4330. geom_hline(yintercept = 0)
  4331. p
  4332. ```
  4333. Export source data
  4334. ```{r, eval = F}
  4335. p$data %>%
  4336. write.table("source_data/SF18a.tsv", sep = "\t", dec = ".", row.names = F)
  4337. ```
  4338. ## 18b
  4339. ```{r, fig.height=4, fig.width=3.5}
  4340. dat.ct <- read.delim("gwas/nalls/downstream_celltype_microglia.tsv", header = F, sep = "\t") %$%
  4341. strsplit(V1, " ") %>%
  4342. unlist() %>%
  4343. gsub("\\", "", ., fixed = T) %>%
  4344. gsub("\n", "", ., fixed = T) %>%
  4345. gsub("group", "", .) %>%
  4346. .[!sapply(., \(x) x == "")] %>%
  4347. {c("group", .[seq(35)])} %>%
  4348. matrix(ncol = 6, byrow = T) %>%
  4349. as.data.frame() %>%
  4350. `colnames<-`(., .[1, ]) %>%
  4351. .[-1, ]
  4352. anno.micro <- qread("anno_micro_pvm.qs") %>%
  4353. renameAnnotation("Steady-state","MIC_steady-state") %>%
  4354. renameAnnotation("Intermediate1","MIC_intermediate1") %>%
  4355. renameAnnotation("Intermediate2","MIC_intermediate2") %>%
  4356. renameAnnotation("Activated","MIC_activated") %>%
  4357. .[!. == "PVMs"] %>%
  4358. factor()
  4359. dat.sign <-
  4360. dat.ct %>%
  4361. filter(!group == "Unknown") %>%
  4362. mutate(assoc_sign = as.numeric(assoc_mcp) %>% sapply(\(x) if (x <= 0.05) paste("*", formatC(x, digits = 2), sep = " ") else ""),
  4363. hetero_sign = as.numeric(hetero_mcp) %>% sapply(\(x) if (x <= 0.05) paste("#", formatC(x, digits = 2), sep = " ") else " ")) %>%
  4364. mutate(sign = paste0(assoc_sign,"\n",hetero_sign) %>% gsub("\n ", "", .)) %>%
  4365. dplyr::rename(type = group)
  4366. p <- data.frame(cell = dat.scores$X %>% gsub("one_", "!!", .),
  4367. score = dat.scores$norm_score,
  4368. type = anno.major[match(dat.scores$X,
  4369. names(anno.major))]) %>%
  4370. filter(cell %in% names(anno.micro)) %>%
  4371. mutate(type = factor(anno.micro[.$cell])) %>%
  4372. group_by(type) %>%
  4373. summarize(m = mean(score)) %>%
  4374. filter(!is.na(type)) %>%
  4375. mutate(type = as.character(type)) %>%
  4376. arrange(desc(m)) %>%
  4377. mutate(type = factor(type, levels = type), sign = dat.sign$sign[match(type %>% levels, dat.sign$type)]) %>%
  4378. mutate(type = factor(type, levels = type)) %>%
  4379. ggplot(aes(type, m, fill = type)) +
  4380. geom_bar(stat = "identity") +
  4381. geom_text(aes(label = sign), vjust = -0.5, nudge_y = -0.05) +
  4382. theme_bw() +
  4383. theme(line = element_blank()) +
  4384. labs(y = "Mean score", x = "", title = "scDRS for microglia") +
  4385. guides(fill = "none") +
  4386. theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5)) +
  4387. ylim(c(0, 2)) +
  4388. scale_fill_manual(values = pal.major)
  4389. p
  4390. ```
  4391. Export source data
  4392. ```{r, eval = F}
  4393. p$data %>%
  4394. write.table("source_data/SF18b.tsv", sep = "\t", dec = ".", row.names = F)
  4395. ```
  4396. ## 18c
  4397. We provide the results from scDRS based on Chia *et al.* GWAS summary stats. For calculation of these, see `scDRS_MSA.ipynb`.
  4398. ```{r, fig.width=6, fig.height=4}
  4399. dat.scores <- qread("gwas/chia/MSA.full_score.qs")
  4400. # Load downstream analyses for cell types versus trait
  4401. dat.ct <- read.delim("gwas/chia/downstream_celltype.tsv", header = F, sep = "\t") %$%
  4402. strsplit(V1, " ") %>%
  4403. unlist() %>%
  4404. gsub("\\", "", ., fixed = T) %>%
  4405. gsub("\n", "", ., fixed = T) %>%
  4406. .[!sapply(., \(x) x == "")] %>%
  4407. .[c(1:5,69:72, # Header
  4408. 8:12,75:78, # Astro
  4409. 15:19,81:84, # EN
  4410. 21:25,86:89, # Immune
  4411. 28:32,92:95, # IN
  4412. 34:38,97:100, # MSN
  4413. 40:44,102:105, # MIC
  4414. 46:50,107:110, # OPCs
  4415. 52:56,112:115, # OL
  4416. 58:62,117:120, # PVMs
  4417. 64:68,122:125 # Peri
  4418. )]
  4419. dat.sign <- dat.ct %>%
  4420. split(seq(9)) %>%
  4421. bind_rows() %>%
  4422. {`colnames<-`(.[-1, ], .[1, ])} %>%
  4423. as.data.frame()
  4424. dat.sign %<>% mutate(group = c("Astrocytes",
  4425. "Exc. neurons",
  4426. "Immune",
  4427. "Inh. neurons",
  4428. "MSN",
  4429. "Microglia",
  4430. "OPCs",
  4431. "Oligodendrocytes",
  4432. "PVMs",
  4433. "Pericytes/endothelial"))
  4434. dat.sign %<>%
  4435. filter(!group == "Unknown") %>%
  4436. mutate(assoc_sign = as.numeric(assoc_mcp) %>% sapply(\(x) if (x <= 0.05) paste("*", formatC(x, digits = 2), sep = " ") else ""),
  4437. hetero_sign = as.numeric(hetero_mcp) %>% sapply(\(x) if (x <= 0.05) paste("#", formatC(x, digits = 2), sep = " ") else " ")) %>%
  4438. mutate(sign = paste0(assoc_sign,"\n",hetero_sign) %>% gsub("\n ", "", .)) %>%
  4439. dplyr::rename(type = group)
  4440. p <- data.frame(cell = dat.scores$X,
  4441. score = dat.scores$norm_score,
  4442. type = anno.major[match(dat.scores$X,
  4443. names(anno.major))]) %>%
  4444. group_by(type) %>%
  4445. summarize(m = median(score)) %>%
  4446. filter(!is.na(type)) %>%
  4447. mutate(type = as.character(type)) %$%
  4448. arrange(., desc(m)) %>%
  4449. mutate(type = factor(type, levels = type), sign = dat.sign$sign[match(type %>% levels, dat.sign$type)]) %>%
  4450. ggplot(aes(type, m, fill = type)) +
  4451. geom_bar(stat = "identity") +
  4452. geom_text(aes(label = sign), vjust = .5) +
  4453. theme_bw() +
  4454. labs(y = "Mean score", x = "", title = "scDRS mean scores and associations") +
  4455. guides(fill = "none") +
  4456. theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5),
  4457. line = element_blank()) +
  4458. ylim(c(-0.5, 0.5)) +
  4459. scale_fill_manual(values = pal.major) +
  4460. geom_hline(yintercept = 0)
  4461. p
  4462. ```
  4463. Export source data
  4464. ```{r, eval = F}
  4465. p$data %>%
  4466. write.table("source_data/SF18c.tsv", sep = "\t", dec = ".", row.names = F)
  4467. ```
  4468. # Supplementary Figure 19
  4469. All subfigures were made in GraphPad Prism. Data are available in `Phagocytosis_assay_triplicates_raw_data_HH.tsv` (Copenhagen experiment) or `HOUSTON.tsv` (Houston experiment).
  4470. # Supplementary Dataset 2
  4471. Not rerun
  4472. ```{r, eval = F}
  4473. anno.major <- qread("anno_major.qs")
  4474. anno.micro <- qread("anno_micro_pvm.qs") %>%
  4475. renameAnnotation("Steady-state","MIC_steady-state") %>%
  4476. renameAnnotation("Intermediate1","MIC_intermediate1") %>%
  4477. renameAnnotation("Intermediate2","MIC_intermediate2") %>%
  4478. renameAnnotation("Activated","MIC_activated")
  4479. anno.glia <- c("anno_astro.qs",
  4480. "anno_oligo.qs",
  4481. "anno_opc.qs") %>%
  4482. lapply(qread) %>%
  4483. Reduce(c, .) %>%
  4484. factor() %>%
  4485. renameAnnotation("Homeostatic_astrocytes", "AS_homeostatic") %>%
  4486. renameAnnotation("Reactive_astrocytes", "AS_reactive") %>%
  4487. renameAnnotation("Homeostatic_LINC01608", "OL_LINC01608") %>%
  4488. renameAnnotation("Homeostatic_SLC5A11", "OL_SLC5A11") %>%
  4489. renameAnnotation("Reactive_SCGZ", "OL_SGCZ")
  4490. anno.neurons <- qread("anno_neurons.qs")
  4491. # Minor final
  4492. anno.minor <- anno.major[!anno.major %in% c("Inh. neurons", "Exc. neurons", "PVMs", "Astrocytes", "Oligodendrocytes", "OPCs", "Microglia")] %>%
  4493. {factor(c(., anno.neurons, anno.glia, anno.micro))} %>%
  4494. factor(levels = sort(levels(.)))
  4495. # Major final
  4496. anno.major %<>% .[!names(.) %in% names(anno.neurons)] %>%
  4497. {factor(c(., anno.neurons))} %>%
  4498. collapseAnnotation("MSN") %>%
  4499. collapseAnnotation("GABAergic") %>%
  4500. collapseAnnotation("GLUergic") %>%
  4501. renameAnnotation("MSN", "Medium spiny neurons") %>%
  4502. renameAnnotation("GABAergic", "GABAergic neurons") %>%
  4503. renameAnnotation("GLUergic", "GLUergic neurons") %>%
  4504. factor(levels = sort(levels(.)))
  4505. ```
  4506. ```{r, eval = F}
  4507. con.major$n.cores <- 32 # Major object
  4508. markers.major <- con.major$getDifferentialGenes(groups = anno.major,
  4509. z.threshold = 1,
  4510. upregulated.only = T,
  4511. append.specificity.metrics = T,
  4512. append.auc = T)
  4513. markers.major %>%
  4514. lapply(filter, PAdj <= 0.05) %>%
  4515. bind_rows(.id = "Celltype") %>%
  4516. write.table("Table SX - Celltype markers, major annotation.tsv", sep = "\t", dec = ".", row.names = F)
  4517. ```
  4518. # Supplementary Dataset 4
  4519. Not rerun
  4520. ```{r, eval = F}
  4521. res <- list(
  4522. Major = list(CTRLvsMSA = "cao_major_msa.qs",
  4523. CTRLvsPD = "cao_major_pd.qs",
  4524. PDvsMSA = "cao_major_dis.qs"),
  4525. Neurons = list(CTRLvsMSA = "cao_neurons_msa.qs",
  4526. CTRLvsPD = "cao_neurons_pd.qs",
  4527. PDvsMSA = "cao_neurons_dis.qs"),
  4528. Glial = list(CTRLvsMSA = "cao_oligo_astro_opc_msa.qs",
  4529. CTRLvsPD = "cao_oligo_astro_opc_pd.qs",
  4530. PDvsMSA = "cao_oligo_astro_opc_dis.qs"),
  4531. Micro_PVM = list(CTRLvsMSA = "cao_micro_pvm_msa.qs",
  4532. CTRLvsPD = "cao_micro_pvm_pd.qs",
  4533. PDvsMSA = "cao_micro_pvm_dis.qs")) %>%
  4534. lapply(\(celltype) sccore::plapply(celltype, \(comp) qread(comp, nthreads = 10)$test.results$coda, n.cores = 3)) %>%
  4535. lapply(lapply, \(x) data.frame(subtype = names(x$padj),
  4536. loadings.min = apply(x$loadings, 1, min),
  4537. loadings.median = apply(x$loadings, 1, median),
  4538. loadings.max = apply(x$loadings, 1, max),
  4539. padj = unname(x$padj))) %>%
  4540. lapply(bind_rows, .id = "Comparison") %>%
  4541. bind_rows(.id = "Cell type") %>%
  4542. `rownames<-`(NULL)
  4543. res %>%
  4544. write.table("Table SX - Loadings.tsv", sep = "\t", dec = ".", row.names = F)
  4545. ```
  4546. # Supplementary Dataset 5
  4547. Not rerun
  4548. ```{r, eval = F}
  4549. cao <- Cacoa$new(data.object = con, # Major object
  4550. cell.groups = anno.major,
  4551. ref.level = "CTRL",
  4552. target.level = "DISEASE",
  4553. sample.groups = con$samples %>%
  4554. names() %>%
  4555. strsplit("_") %>%
  4556. sget(1) %>%
  4557. {ifelse(. == "CTRL", "CTRL", "DISEASE")} %>%
  4558. `names<-`(con$samples %>%
  4559. names()),
  4560. sample.groups.palette = c(c("yellow", RColorBrewer::brewer.pal(n = 6, "Accent")[5:6]) %>% setNames(c("CTRL","PD","MSA"))))
  4561. cao$sample.groups <- con$samples %>%
  4562. names() %>%
  4563. strsplit("_") %>%
  4564. sget(1) %>%
  4565. `names<-`(con$samples %>%
  4566. names())
  4567. res <- cao$plotCellGroupSizes(show.significance = TRUE,
  4568. filter.empty.cell.types = FALSE)$data %>%
  4569. group_by(group, variable) %>%
  4570. summarize(Min_proportion = min(value),
  4571. Mean_proportion = mean(value),
  4572. Max_proportion = max(value)) %>%
  4573. dplyr::rename(Condition = group,
  4574. Celltype = variable)
  4575. res %>%
  4576. write.table("Table SX - Proportions, major annotation.tsv", sep = "\t", dec = ".", row.names = F)
  4577. ```
  4578. # Supplementary Dataset 6
  4579. Not rerun
  4580. ```{r, eval = F}
  4581. anno.major <- qread("anno_major.qs")
  4582. anno.micro <- qread("anno_micro_pvm.qs") %>%
  4583. renameAnnotation("Steady-state","MIC_steady-state") %>%
  4584. renameAnnotation("Intermediate1","MIC_intermediate1") %>%
  4585. renameAnnotation("Intermediate2","MIC_intermediate2") %>%
  4586. renameAnnotation("Activated","MIC_activated")
  4587. anno.glia <- c("anno_astro.qs",
  4588. "anno_oligo.qs",
  4589. "anno_opc.qs") %>%
  4590. lapply(qread) %>%
  4591. Reduce(c, .) %>%
  4592. factor() %>%
  4593. renameAnnotation("Homeostatic_astrocytes", "AS_homeostatic") %>%
  4594. renameAnnotation("Reactive_astrocytes", "AS_reactive") %>%
  4595. renameAnnotation("Homeostatic_LINC01608", "OL_LINC01608") %>%
  4596. renameAnnotation("Homeostatic_SLC5A11", "OL_SLC5A11") %>%
  4597. renameAnnotation("Reactive_SCGZ", "OL_SGCZ")
  4598. anno.neurons <- qread("anno_neurons.qs")
  4599. # Minor final
  4600. anno.minor <- anno.major[!anno.major %in% c("Inh. neurons", "Exc. neurons", "PVMs", "Astrocytes", "Oligodendrocytes", "OPCs", "Microglia")] %>%
  4601. {factor(c(., anno.neurons, anno.glia, anno.micro))} %>%
  4602. factor(levels = sort(levels(.)))
  4603. # Major final
  4604. anno.major %<>% .[!names(.) %in% names(anno.neurons)] %>%
  4605. {factor(c(., anno.neurons))} %>%
  4606. collapseAnnotation("MSN") %>%
  4607. collapseAnnotation("GABAergic") %>%
  4608. collapseAnnotation("GLUergic") %>%
  4609. renameAnnotation("MSN", "Medium spiny neurons") %>%
  4610. renameAnnotation("GABAergic", "GABAergic neurons") %>%
  4611. renameAnnotation("GLUergic", "GLUergic neurons") %>%
  4612. factor(levels = sort(levels(.)))
  4613. ```
  4614. ```{r, eval = F}
  4615. markers.minor <- con.major$getDifferentialGenes(groups = anno.minor,
  4616. z.threshold = 1,
  4617. upregulated.only = T,
  4618. append.specificity.metrics = T,
  4619. append.auc = T)
  4620. markers.minor %>%
  4621. lapply(filter, PAdj <= 0.05) %>%
  4622. bind_rows(.id = "Celltype") %>%
  4623. write.table("Table SX - Celltype markers, minor annotation.tsv", sep = "\t", dec = ".", row.names = F)
  4624. ```
  4625. # Supplementary Dataset 7
  4626. Not rerun
  4627. ```{r, eval = F}
  4628. cao <- Cacoa$new(data.object = con,
  4629. cell.groups = anno.minor,
  4630. ref.level = "CTRL",
  4631. target.level = "DISEASE",
  4632. sample.groups = con$samples %>%
  4633. names() %>%
  4634. strsplit("_") %>%
  4635. sget(1) %>%
  4636. {ifelse(. == "CTRL", "CTRL", "DISEASE")} %>%
  4637. `names<-`(con$samples %>%
  4638. names()),
  4639. sample.groups.palette = c(c("yellow", RColorBrewer::brewer.pal(n = 6, "Accent")[5:6]) %>% setNames(c("CTRL","PD","MSA"))))
  4640. cao$sample.groups <- con$samples %>%
  4641. names() %>%
  4642. strsplit("_") %>%
  4643. sget(1) %>%
  4644. `names<-`(con$samples %>%
  4645. names())
  4646. res <- cao$plotCellGroupSizes(show.significance = TRUE,
  4647. filter.empty.cell.types = FALSE)$data %>%
  4648. group_by(group, variable) %>%
  4649. summarize(Min_proportion = min(value),
  4650. Mean_proportion = mean(value),
  4651. Max_proportion = max(value)) %>%
  4652. dplyr::rename(Condition = group,
  4653. Celltype = variable)
  4654. res %>%
  4655. write.table("Table SX - Proportions, minor annotation.tsv", sep = "\t", dec = ".", row.names = F)
  4656. ```
  4657. # Supplementary Dataset 8
  4658. Not rerun
  4659. First, correct OPCs/COPs for age covariate according to scITD calculations
  4660. ```{r, eval = F}
  4661. cao_msa <- qread("cao_opc_msa.qs", nthreads = 10)
  4662. cao_msa$plot.theme <- theme_bw()
  4663. cao_pd <- qread("cao_opc_pd.qs", nthreads = 10)
  4664. cao_pd$plot.theme <- theme_bw()
  4665. cao_dis <- qread("cao_opc_dis.qs", nthreads = 10)
  4666. cao_dis$plot.theme <- theme_bw()
  4667. metadata.all <- read.delim("metadata.tsv")
  4668. meta.df.msa <- metadata.all %>%
  4669. filter(sample %in% names(cao_msa$data.object$samples)) %>%
  4670. tibble::column_to_rownames("sample") %>%
  4671. select(age)
  4672. meta.df.pd <- metadata.all %>%
  4673. filter(sample %in% names(cao_pd$data.object$samples)) %>%
  4674. tibble::column_to_rownames("sample") %>%
  4675. select(age)
  4676. meta.df.dis <- metadata.all %>%
  4677. filter(sample %in% names(cao_dis$data.object$samples)) %>%
  4678. tibble::column_to_rownames("sample") %>%
  4679. select(age)
  4680. all.genes_msa <- cao_msa$data.object$samples %>%
  4681. lget("misc") %>%
  4682. lget("rawCounts") %>%
  4683. lapply(colnames) %>%
  4684. Reduce(union, .)
  4685. genes.to.omit_msa <- all.genes_msa %>%
  4686. .[grepl("MT-|RPL|RPS", .)]
  4687. all.genes_pd <- cao_pd$data.object$samples %>%
  4688. lget("misc") %>%
  4689. lget("rawCounts") %>%
  4690. lapply(colnames) %>%
  4691. Reduce(union, .)
  4692. genes.to.omit_pd <- all.genes_pd %>%
  4693. .[grepl("MT-|RPL|RPS", .)]
  4694. all.genes_dis <- cao_dis$data.object$samples %>%
  4695. lget("misc") %>%
  4696. lget("rawCounts") %>%
  4697. lapply(colnames) %>%
  4698. Reduce(union, .)
  4699. genes.to.omit_dis <- all.genes_dis %>%
  4700. .[grepl("MT-|RPL|RPS", .)]
  4701. cao_msa$estimateDEPerCellType(covariates = meta.df.msa, name = "de_age", genes.to.omit = genes.to.omit_msa)
  4702. cao_pd$estimateDEPerCellType(covariates = meta.df.pd, name = "de_age", genes.to.omit = genes.to.omit_pd)
  4703. cao_dis$estimateDEPerCellType(covariates = meta.df.dis, name = "de_age", genes.to.omit = genes.to.omit_dis)
  4704. cao_msa$estimateOntology("GSEA", name = "gsea_age", de.name = "de_age", org.db = org.Hs.eg.db::org.Hs.eg.db)
  4705. cao_pd$estimateOntology("GSEA", name = "gsea_age", de.name = "de_age", org.db = org.Hs.eg.db::org.Hs.eg.db)
  4706. cao_dis$estimateOntology("GSEA", name = "gsea_age", de.name = "de_age", org.db = org.Hs.eg.db::org.Hs.eg.db)
  4707. qsave(cao_msa, "cao_opc_msa.qs", nthreads = 10)
  4708. qsave(cao_pd, "cao_opc_pd.qs", nthreads = 10)
  4709. qsave(cao_dis, "cao_opc_dis.qs", nthreads = 10)
  4710. ```
  4711. ```{r, eval = F}
  4712. go.list <- dir("cacoa/", full.names = T)[-c(4:7, 15:18, 22, 26)] %>%
  4713. lapply(qread, nthreads = 10) %>%
  4714. lapply(purrr::pluck, "test.results") %>%
  4715. lapply(\(x) if ("gsea_age" %in% names(x)) x$gsea_age else x$gsea) %>% # To include age-corrected calculations for OPCs
  4716. setNames(dir("cacoa/")[-c(4:7, 15:18, 22, 26)])
  4717. go.list %>%
  4718. lget("res") %>%
  4719. lapply(lapply, lapply, slot, "result") %>%
  4720. lapply(lapply, data.table::rbindlist, idcol = "Category") %>%
  4721. lapply(data.table::rbindlist, idcol = "Celltype") %>%
  4722. data.table::rbindlist(idcol = "Comparison") %>%
  4723. mutate(Comparison = sapply(Comparison, \(comp) {
  4724. if (grepl("dis", comp)) "PD vs MSA" else if (grepl("msa", comp)) "CTRL vs MSA" else "CTRL vs PD"
  4725. })) %>%
  4726. filter(p.adjust <= 0.05) %>%
  4727. write.table("GSEA.csv", sep = ",", dec = ".", row.names = F)
  4728. ```
  4729. # Supplementary Dataset 9
  4730. Not rerun
  4731. ```{r, eval = F}
  4732. de.list <- dir("cacoa/", full.names = T)[-c(4:7, 15:18, 22, 26)] %>%
  4733. lapply(qread, nthreads = 10) %>%
  4734. lapply(purrr::pluck, "test.results") %>%
  4735. lapply(\(x) if ("de_age" %in% names(x)) x$de_age else x$de) %>% # To include results from age-corrected calculations for OPCs
  4736. setNames(dir("cacoa/")[-c(4:7, 15:18, 22, 26)])
  4737. de.list %>%
  4738. lapply(lget, "res") %>%
  4739. lapply(data.table::rbindlist, idcol = "Celltype") %>%
  4740. lapply(select, Celltype, baseMean, log2FoldChange, lfcSE, stat, pvalue, padj, Gene, Z, Za, CellFrac, SampleFrac) %>%
  4741. data.table::rbindlist(idcol = "Comparison") %>%
  4742. mutate(Comparison = sapply(Comparison, \(comp) {
  4743. if (grepl("dis", comp)) "PD vs MSA" else if (grepl("msa", comp)) "CTRL vs MSA" else "CTRL vs PD"
  4744. })) %>%
  4745. filter(padj <= 0.05) %>%
  4746. write.table("DEGs.csv", sep = ",", dec = ".", row.names = F)
  4747. ```
  4748. # Supplementary Dataset 10
  4749. Not rerun. We need the res.filter object from calculation of smoothed heatmap for microglia activation trajectory.
  4750. ```{r, eval = F}
  4751. go <- clusterProfiler::enrichGO(names(res.filter),
  4752. OrgDb = "org.Hs.eg.db",
  4753. keyType = "SYMBOL",
  4754. universe = colnames(con$getJointCountMatrix()))
  4755. go@result %>%
  4756. filter(pvalue <= 0.05) %>%
  4757. write.table("Microglia_pseudotime_activation-lineage_GO.tsv", sep = "\t", row.names = F)
  4758. ```
  4759. # Supplementary Dataset 11
  4760. Not rerun. We need the Smooth object for the microglia to PVM trajectory.
  4761. ```{r, eval = F}
  4762. go.list <- list(repressed = rownames(Smooth)[1:which(rownames(Smooth) == "EPB41L2")],
  4763. induced = rownames(Smooth)[(which(rownames(Smooth) == "EPB41L2")+1):nrow(Smooth)]) %>%
  4764. lapply(clusterProfiler::enrichGO,
  4765. OrgDb = "org.Hs.eg.db",
  4766. keyType = "SYMBOL",
  4767. universe = colnames(con$getJointCountMatrix()))
  4768. go.list %>%
  4769. lapply(\(x) x@result) %>%
  4770. lapply(filter, pvalue <= 0.05) %>%
  4771. data.table::rbindlist(idcol = "geneset") %>%
  4772. write.table("Microglia_pseudotime_PVM-lineage_GO.tsv", sep = "\t", row.names = F)
  4773. ```
  4774. # Supplementary Dataset 14
  4775. Not rerun. We use the publicly available data from [Rydbirk *et al*.](https://pmc.ncbi.nlm.nih.gov/articles/PMC9164190/).
  4776. ```{r, eval = F}
  4777. # Create universes
  4778. dat.all <- read.delim("CSF-Sv_Soluble-frac__Report.tsv")
  4779. universe.gene <- dat.all %>%
  4780. pull(PG.Genes) %>%
  4781. unique()
  4782. universe.prot <- dat.all %>%
  4783. pull(PG.UniProtIds)
  4784. # DEPs
  4785. dat <- read.delim("Soluble_fraction.txt")
  4786. # KEGG, MSA
  4787. kegg.res <- dat %>%
  4788. filter(Disease.group == "MSA") %>%
  4789. pull(UniProt.ID) %>%
  4790. clusterProfiler::enrichKEGG(keyType = "uniprot", pvalueCutoff = 0.2, universe = universe.prot, organism = "hsa")
  4791. # KEGG, PD
  4792. kegg.res.pd <- dat %>%
  4793. filter(Disease.group == "PD") %>%
  4794. pull(UniProt.ID) %>%
  4795. clusterProfiler::enrichKEGG(keyType = "uniprot", pvalueCutoff = 0.2, universe = universe.prot, organism = "hsa")
  4796. # Write table
  4797. list(MSA = kegg.res, PD = kegg.res.pd) %>%
  4798. lapply(getElement, "result") %>%
  4799. lapply(dplyr::select, Description, GeneRatio, BgRatio, pvalue, p.adjust, ID, geneID) %>%
  4800. bind_rows(.id = "Disease") %>%
  4801. write.table("TableS14_KEGG.tsv", sep = "\t", row.names = F)
  4802. ```
  4803. # Create source data file
  4804. Not rerun here
  4805. ```{r, eval = F}
  4806. tsv_files <- dir("source_data", pattern = ".tsv", full.names = T)
  4807. nn <- tsv_files %>%
  4808. basename() %>%
  4809. tools::file_path_sans_ext() %>%
  4810. gsub("F", "Figure ", ., fixed = T) %>%
  4811. gsub("S", "Supplementary ", ., fixed = T)
  4812. # Sort
  4813. df <- data.frame(tsv = tsv_files, name = nn, stringsAsFactors = FALSE) %>%
  4814. mutate(fig = ifelse(grepl("Sup", name), 2, 1),
  4815. no = gsub("Supplementary|Figure| ", "", name) %>% strsplit("[a-z_]") %>% sget(1)) %>%
  4816. mutate(core = str_remove(name, "Supplementary Figure|Figure") %>%
  4817. str_trim(),
  4818. let = str_extract(core, paste0("^", no, "([a-z])")) %>%
  4819. str_replace(no, ""),
  4820. no2 = str_extract(core, paste0("(?<=", no, "[a-z]_?|_)[0-9]+")),
  4821. no2 = as.numeric(no2),
  4822. no = as.numeric(no)) %>%
  4823. dplyr::select(-core) %>%
  4824. arrange(fig, no, let, no2)
  4825. df %>%
  4826. pull(tsv) %>%
  4827. lapply(., read.delim, check.names = FALSE, sep = "\t", dec = ".") %>%
  4828. setNames(df$name) %>%
  4829. writexl::write_xlsx("source_data/source_data.xlsx")
  4830. ```
  4831. # Session info
  4832. Time to knit
  4833. ```{r}
  4834. Sys.time() - tt
  4835. ```
  4836. ```{r}
  4837. sessionInfo()
  4838. ```

Manuscript_figures.Rmd at commit 98354e9, under GPL-3.0 · at the source

Overview

Authors: Rasmus Rydbirk1,2,3, Frederik Nørby Friis Sørensen2, Jonas Folke3,4, Henriette Haukedal5, Andrea Asenjo Martinez2, Irene Lisa Vargas2, Simone McGarry2, Oline Chantell Hollmann2, Camila Gherardelli6, Sofia Sepulveda6, Adam T. Szafran7, Michael A. Mancini7, Sanne Simone Kaalund3,4, Tomasz Brudek3,4, Lisette Salvesen8, Sara Bech8, Justyna Okarmus9, Peter Kharchenko10, Morten Meyer9,11,12, Claudio Soto6, Kristine Freude5, Abhisek Mukherjee6, Susana Aznar3,4, Konstantin Khodosevich2
  1. Functional Genomics and Metabolism Research Unit, Department of Biochemistry and Molecular Biology, University of Southern Denmark,Odense, Denmark
  2. Biotech Research and Innovation Centre (BRIC), Faculty of Health and Medical Sciences, University of Copenhagen,Copenhagen N, Denmark
  3. Center for Neuroscience and Stereology, Bispebjerg and Frederiksberg Hospital, Copenhagen University Hospital,Copenhagen NV, Denmark
  4. Copenhagen Center for Translational Research, Bispebjerg and Frederiksberg Hospital, Copenhagen University Hospital,Copenhagen NV, Denmark
  5. Department of Veterinary and Animal Sciences, Faculty of Health and Medical Sciences, University of Copenhagen,Frederiksberg, Denmark
  6. Mitchell Center for Alzheimer’s Disease and Related Brain Disorders, Department of Neurology, University of Texas Health Science Center at Houston, McGovern Medical School,Houston, USA
  7. Department of Molecular Biology, Baylor College of Medicine,Houston, TX USA
  8. Department of Neurology, Bispebjerg and Frederiksberg Hospital, Copenhagen University Hospital,Copenhagen NV, Denmark
  9. Department of Neurobiology Research, Institute of Molecular Medicine, University of Southern Denmark,Odense, Denmark
  10. Department of Biomedical Informatics, Harvard Medical School,Boston, MA USA
  11. Department of Neurology, Odense University Hospital,Odense, Denmark
  12. Brain Research Inter-Disciplinary Guided Excellence, Department of Clinical Research, University of Southern Denmark,Odense, Denmark
Journal: Nature communications, volume 17, issue 1, article 5234
Dates: received 21 February 2025; accepted 18 March 2026; published online 15 April 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s41467-026-71525-6 · PMID 41986335 · PMCID PMC13261106 · OpenAlex W7154496173
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: genetics / omics (modality), human (organism), Parkinson's (population), cellular / molecular (subfield)
Methods: Connectivity, Statistics, Smoothing, state filtering, decompositions
Keywords: Neurodegeneration, Molecular neuroscience, Parkinson's disease
MeSH: Brain*, Microglia*, Multiple System Atrophy*, Transcriptome*, Aged, Astrocytes, Female, Gene Expression Profiling, Humans, Male, Middle Aged, Neurons, Oligodendroglia, Parkinson Disease (* major topic)
Topic: Parkinson's Disease Mechanisms and Treatments (Neurology, Medicine), according to OpenAlex
Funding: Lundbeck Foundation (2020-1025, R434-2023-355, R400-2022-1103, R218-2016-947)
Citations: not cited yet (Europe PMC); 162 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

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

rrydbirk/MSAvsPD

License: GPL-3.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 98354e9059384c466d84e52c58d71d158213c132, 3 March 2026
Languages: Jupyter (6), R (2)
Size: 13 files, 8 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, 8 notebooks
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: pandas (6 files), anndata (5 files), Scanpy (4 files), Matplotlib (3 files), NumPy (2 files), seaborn (2 files), circlize (1 file), clusterProfiler (1 file), ComplexHeatmap (1 file), cowplot (1 file), data.table (1 file), DESeq2 (1 file), ggplot2 (1 file), ggpubr (1 file), reshape2 (1 file), rstatix (1 file), scVelo (1 file), statsmodels (1 file), TensorFlow (1 file), tidyverse (1 file), UMAP (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
10 files

Zenodo 18610042

License: GPL-3.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: “Code availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: pandas (6 files), anndata (5 files), Scanpy (4 files), Matplotlib (3 files), NumPy (2 files), seaborn (2 files), circlize (1 file), clusterProfiler (1 file), ComplexHeatmap (1 file), cowplot (1 file), data.table (1 file), DESeq2 (1 file), ggplot2 (1 file), ggpubr (1 file), reshape2 (1 file), rstatix (1 file), scVelo (1 file), statsmodels (1 file), TensorFlow (1 file), tidyverse (1 file), UMAP (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers (HTTP 200)
  • 29 September 2026: the link answers (HTTP 200)
10 files
At the source:

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41467-026-71525-6.

Tracing map

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

What the map holds:

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

Code and data availability statement

The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41467-026-71525-6.

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, 24 authors, 3 keywords, 14 MeSH terms, 1 funder, 161 references.

Cite

This paper

Rydbirk, R., Sørensen, F. N. F., Folke, J., Haukedal, H., Martinez, A. A., Vargas, I. L., McGarry, S., Hollmann, O. C., Gherardelli, C., Sepulveda, S., Szafran, A. T., Mancini, M. A., Kaalund, S. S., Brudek, T., Salvesen, L., Bech, S., Okarmus, J., Kharchenko, P., Meyer, M., . . . Khodosevich, K. (2026). Single-nucleus brain transcriptomics reveals microglia dysfunction in multiple system atrophy. Nature communications, 17(1), 5234. https://doi.org/10.1038/s41467-026-71525-6

BibTeX

@article{rydbirk2026single,
author = {Rydbirk, Rasmus and Sørensen, Frederik Nørby Friis and Folke, Jonas and Haukedal, Henriette and Martinez, Andrea Asenjo and Vargas, Irene Lisa and McGarry, Simone and Hollmann, Oline Chantell and Gherardelli, Camila and Sepulveda, Sofia and Szafran, Adam T. and Mancini, Michael A. and Kaalund, Sanne Simone and Brudek, Tomasz and Salvesen, Lisette and Bech, Sara and Okarmus, Justyna and Kharchenko, Peter and Meyer, Morten and Soto, Claudio and Freude, Kristine and Mukherjee, Abhisek and Aznar, Susana and Khodosevich, Konstantin},
title = {{Single-nucleus brain transcriptomics reveals microglia dysfunction in multiple system atrophy}},
journal = {Nature communications},
year = {2026},
month = apr,
volume = {17},
number = {1},
pages = {5234},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-71525-6},
url = {https://doi.org/10.1038/s41467-026-71525-6},
pmid = {41986335},
pmcid = {PMC13261106}
}

RIS

TY - JOUR
AU - Rydbirk, Rasmus
AU - Sørensen, Frederik Nørby Friis
AU - Folke, Jonas
AU - Haukedal, Henriette
AU - Martinez, Andrea Asenjo
AU - Vargas, Irene Lisa
AU - McGarry, Simone
AU - Hollmann, Oline Chantell
AU - Gherardelli, Camila
AU - Sepulveda, Sofia
AU - Szafran, Adam T.
AU - Mancini, Michael A.
AU - Kaalund, Sanne Simone
AU - Brudek, Tomasz
AU - Salvesen, Lisette
AU - Bech, Sara
AU - Okarmus, Justyna
AU - Kharchenko, Peter
AU - Meyer, Morten
AU - Soto, Claudio
AU - Freude, Kristine
AU - Mukherjee, Abhisek
AU - Aznar, Susana
AU - Khodosevich, Konstantin
TI - Single-nucleus brain transcriptomics reveals microglia dysfunction in multiple system atrophy
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/04/15
VL - 17
IS - 1
SP - 5234
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-71525-6
UR - https://doi.org/10.1038/s41467-026-71525-6
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-71525-6",
"type": "article-journal",
"title": "Single-nucleus brain transcriptomics reveals microglia dysfunction in multiple system atrophy",
"container-title": "Nature communications",
"author": [
{
"family": "Rydbirk",
"given": "Rasmus"
},
{
"family": "Sørensen",
"given": "Frederik Nørby Friis"
},
{
"family": "Folke",
"given": "Jonas"
},
{
"family": "Haukedal",
"given": "Henriette"
},
{
"family": "Martinez",
"given": "Andrea Asenjo"
},
{
"family": "Vargas",
"given": "Irene Lisa"
},
{
"family": "McGarry",
"given": "Simone"
},
{
"family": "Hollmann",
"given": "Oline Chantell"
},
{
"family": "Gherardelli",
"given": "Camila"
},
{
"family": "Sepulveda",
"given": "Sofia"
},
{
"family": "Szafran",
"given": "Adam T."
},
{
"family": "Mancini",
"given": "Michael A."
},
{
"family": "Kaalund",
"given": "Sanne Simone"
},
{
"family": "Brudek",
"given": "Tomasz"
},
{
"family": "Salvesen",
"given": "Lisette"
},
{
"family": "Bech",
"given": "Sara"
},
{
"family": "Okarmus",
"given": "Justyna"
},
{
"family": "Kharchenko",
"given": "Peter"
},
{
"family": "Meyer",
"given": "Morten"
},
{
"family": "Soto",
"given": "Claudio"
},
{
"family": "Freude",
"given": "Kristine"
},
{
"family": "Mukherjee",
"given": "Abhisek"
},
{
"family": "Aznar",
"given": "Susana"
},
{
"family": "Khodosevich",
"given": "Konstantin"
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "5234",
"DOI": "10.1038/s41467-026-71525-6",
"PMID": "41986335",
"PMCID": "PMC13261106",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-71525-6",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
15
]
]
}
}

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

Similar papers

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

[1] doi:10.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: scVelo, UMAP, anndata, 16 other tools, genetics / omics, cellular / molecular, 3 references
[2] doi:10.1038/s41586-026-10629-x [code]
Whole-genome duplication shaped cell-type evolution in the vertebrate brain.
Journal: Nature
In common: scVelo, rstatix, UMAP, 15 other tools, genetics / omics, cellular / molecular, 3 references
[3] doi:10.1038/s42003-026-10034-0 [code]
Region- and cell type-specific changes in gene expression in the cerebellum after classical fear conditioning.
Journal: Communications biology
In common: rstatix, anndata, circlize, 15 other tools, genetics / omics, cellular / molecular, 2 references
[4] doi:10.1126/sciadv.aed2952 [code]
Activation of transposable elements is linked to a region- and cell type-specific interferon response in Parkinson's disease.
Journal: Science advances
In common: scVelo, UMAP, anndata, 12 other tools, Parkinson's, cellular / molecular, 4 references
[5] doi:10.1038/s41467-026-73305-8 [code]
Comparative analysis of the cellular landscape in mammalian striatum.
Journal: Nature communications
In common: anndata, DESeq2, clusterProfiler, 11 other tools, genetics / omics, cellular / molecular, 4 references
[6] doi:10.1038/s41467-026-75722-1 [code]
Single-nucleus analysis of the adult human olfactory epithelium uncovers shared neurogenesis programs with the brain.
Journal: Nature communications
In common: UMAP, anndata, circlize, 11 other tools, genetics / omics, 5 references
[7] doi:10.1101/gr.281113.125 [code]
Single-nucleus multiomic profiling of the aging mouse substantia nigra reveals conserved gene alterations linked to Parkinson's disease.
Journal: Genome research
In common: anndata, circlize, clusterProfiler, 9 other tools, Parkinson's, genetics / omics, cellular / molecular, 5 references
[8] doi:10.1186/s13059-026-04177-w [code]
Genomic sequence evolution underlying human neocortical interareal diversification.
Journal: Genome biology
In common: rstatix, UMAP, anndata, 13 other tools, genetics / omics, cellular / molecular, 2 references
[9] doi:10.1126/sciadv.aeg3223 [code]
The extreme diversity of retinal amacrine cells has deep evolutionary roots.
Journal: Science advances
In common: rstatix, anndata, circlize, 13 other tools, genetics / omics, cellular / molecular, 2 references
[10] doi:10.1038/s41514-026-00391-9 [code]
Region-specific transcriptional signatures of brain aging in the absence of neuropathology at the single-cell level.
Journal: npj aging
In common: anndata, circlize, Scanpy, 12 other tools, genetics / omics, cellular / molecular, 3 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.