OSCR

Genetic and epigenetic convergence at <i>MOBP</i> links ALS and PSP

Code ↔ Paper

2 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 2 matches
  1. [1] § Results › Fine mapping of MOBP locus confirms overlap between PSP and ALS but not FTD ↔ SuSiE Colocalisation GWAS.Rmd, lines 212 to 263 · score 0.58 · fine mapped, SuSiE, top SNP, PIP, credible, MOBP locus · Report a mismatch
  2. [2] § Methods › Co-localisation Analysis ↔ SuSiE Colocalisation GWAS.Rmd, lines 212 to 263 · score 0.53 · fine mapping, SuSiE, PIP, credible, trait, colocalisation · Report a mismatch

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

R Markdown · 746 lines · 17 KB · no license · 2 matches

  1. ---
  2. title: "R Notebook"
  3. output: html_notebook
  4. ---
  5. ```{r}
  6. # Paths to LD matrix (r^2) and BIM file
  7. ld_path <- "/1KG.EUR.onList.refLD.ld"
  8. bim_path <- "/1KG.EUR.onList.reid.bim"
  9. LD <- as.matrix(read.table(ld_path, header = FALSE, check.names = FALSE))
  10. bim <- read.table(bim_path, header = FALSE, stringsAsFactors = FALSE)
  11. colnames(bim)[1:6] <- c("CHR","ID","CM","POS","A1","A2")
  12. ld_ids <- bim$ID
  13. stopifnot(nrow(LD) == length(ld_ids))
  14. rownames(LD) <- colnames(LD) <- ld_ids
  15. R_all <- LD
  16. R_all[R_all < 0] <- 0
  17. R_all <- sqrt(R_all)
  18. # LD-allele reference table
  19. ld_ref <- data.frame(
  20. snp = bim$ID,
  21. A1_ref = toupper(bim$A1),
  22. A2_ref = toupper(bim$A2)
  23. )
  24. ```
  25. ```{r}
  26. ```
  27. ```{r}
  28. library(dplyr)
  29. library(susieR)
  30. attach_ld_cc <- function(ds, trait_label) {
  31. idx <- match(ds$snp, ld_ref$snp)
  32. keep <- !is.na(idx)
  33. if (sum(keep) < 10) {
  34. warning(trait_label, ": only ", sum(keep), " SNPs match LD reference")
  35. }
  36. ds$snp <- ds$snp[keep]
  37. ds$beta <- ds$beta[keep]
  38. ds$varbeta <- ds$varbeta[keep]
  39. ds$MAF <- ds$MAF[keep]
  40. ds$A1 <- ds$A1[keep]
  41. ds$A2 <- ds$A2[keep]
  42. ds$REF <- ds$REF[keep]
  43. ds$ALT <- ds$ALT[keep]
  44. if (!is.null(ds$pos)) ds$pos <- ds$pos[keep]
  45. a1_ref <- ld_ref$A1_ref[idx[keep]]
  46. a2_ref <- ld_ref$A2_ref[idx[keep]]
  47. # flip where A1 is the other allele
  48. flip <- ds$A1 != a1_ref & ds$A1 == a2_ref
  49. ds$beta[flip] <- -ds$beta[flip]
  50. mismatch <- !( (ds$A1 == a1_ref & ds$A2 == a2_ref) |
  51. (ds$A1 == a2_ref & ds$A2 == a1_ref) )
  52. if (any(mismatch)) {
  53. message(trait_label, ": dropping ", sum(mismatch),
  54. " SNPs with incompatible alleles vs LD ref")
  55. keep2 <- !mismatch
  56. ds$snp <- ds$snp[keep2]
  57. ds$beta <- ds$beta[keep2]
  58. ds$varbeta <- ds$varbeta[keep2]
  59. ds$MAF <- ds$MAF[keep2]
  60. ds$A1 <- ds$A1[keep2]
  61. ds$A2 <- ds$A2[keep2]
  62. ds$REF <- ds$REF[keep2]
  63. ds$ALT <- ds$ALT[keep2]
  64. if (!is.null(ds$pos)) ds$pos <- ds$pos[keep2]
  65. idx <- idx[keep][keep2]
  66. } else {
  67. idx <- idx[keep]
  68. }
  69. # subset LD matrix
  70. ds$LD <- R_all[idx, idx]
  71. message(trait_label, ": attached LD for ", length(ds$snp), " SNPs")
  72. ds
  73. }
  74. runsusie_cc <- function(ds, L = 10, maxit = 10000) {
  75. z <- ds$beta / sqrt(ds$varbeta)
  76. susie_fit <- susie_rss(
  77. z = z,
  78. R = ds$LD,
  79. n = ds$N,
  80. L = L,
  81. coverage = 0.95,
  82. max_iter = maxit
  83. )
  84. susie_fit$snp <- ds$snp
  85. if (!is.null(ds$pos)) susie_fit$pos <- ds$pos
  86. susie_fit$label <- ds$label
  87. susie_fit
  88. }
  89. datasets$PD <- attach_ld_cc(datasets$PD, "PD")
  90. datasets$MSA <- attach_ld_cc(datasets$MSA, "MSA")
  91. datasets$AD <- attach_ld_cc(datasets$AD, "AD")
  92. datasets$CJD <- attach_ld_cc(datasets$CJD, "CJD")
  93. datasets$FTD <- attach_ld_cc(datasets$FTD, "FTD")
  94. susie_ALS <- runsusie_cc(dataset.als)
  95. susie_PSP <- runsusie_cc(dataset.psp)
  96. susie_PD <- runsusie_cc(datasets$PD)
  97. susie_MSA <- runsusie_cc(datasets$MSA)
  98. susie_AD <- runsusie_cc(datasets$AD)
  99. susie_CJD <- runsusie_cc(datasets$CJD)
  100. susie_FTD <- runsusie_cc(datasets$FTD)
  101. ```
  102. ```{r}
  103. library(dplyr)
  104. summarise_cs <- function(susie_fit, gwas_df, trait_label) {
  105. pip_tbl <- data.frame(
  106. SNP = susie_fit$snp,
  107. pip = susie_fit$pip,
  108. stringsAsFactors = FALSE
  109. )
  110. cs_list <- susie_fit$sets$cs
  111. if (is.null(cs_list)) {
  112. warning(trait_label, ": no credible sets found by SuSiE.")
  113. return(list(
  114. snp_level = NULL,
  115. cs_level = NULL
  116. ))
  117. }
  118. cs_tbl <- lapply(seq_along(cs_list), function(i) {
  119. snp_idx <- cs_list[[i]]
  120. data.frame(
  121. SNP = susie_fit$snp[snp_idx],
  122. cs_id = paste0("CS", i),
  123. stringsAsFactors = FALSE
  124. )
  125. }) %>% bind_rows()
  126. snp_level <- pip_tbl %>%
  127. left_join(cs_tbl, by = "SNP") %>%
  128. left_join(gwas_df %>% select(SNP, pos, P), by = "SNP") %>%
  129. mutate(trait = trait_label)
  130. cs_level <- snp_level %>%
  131. filter(!is.na(cs_id)) %>%
  132. group_by(trait, cs_id) %>%
  133. summarise(
  134. n_snps = n(),
  135. lead_SNP = SNP[which.max(pip)],
  136. max_pip = max(pip, na.rm = TRUE),
  137. min_pos = min(pos, na.rm = TRUE),
  138. max_pos = max(pos, na.rm = TRUE),
  139. .groups = "drop"
  140. ) %>%
  141. mutate(span_kb = (max_pos - min_pos) / 1e3)
  142. list(
  143. snp_level = snp_level,
  144. cs_level = cs_level
  145. )
  146. }
  147. psp_cs <- summarise_cs(susie_PSP, PSP_f, "PSP")
  148. als_cs <- summarise_cs(susie_ALS, ALS_f, "ALS")
  149. ftd_cs <- summarise_cs(susie_FTD, FTD_h, "FTD")
  150. ad_cs <- summarise_cs(susie_AD, AD_h, "AD")
  151. msa_cs <- summarise_cs(susie_MSA, MSA_h, "MSA")
  152. pd_cs <- summarise_cs(susie_PD, PD_h, "PD")
  153. cjd_cs <- summarise_cs(susie_CJD, CJD_f, "CJD")
  154. psp_cs$cs_level
  155. als_cs$cs_level
  156. ftd_cs$cs_level
  157. cs_all <- bind_rows(
  158. psp_cs$cs_level,
  159. als_cs$cs_level,
  160. ftd_cs$cs_level
  161. )
  162. cs_all
  163. ```
  164. ```{r}
  165. library(ggplot2)
  166. library(ggrepel)
  167. plot_cs_manhattan <- function(cs_obj, trait_label, title_prefix = NULL) {
  168. snps <- cs_obj$snp_level
  169. # credible set colour palette
  170. cs_ids <- sort(unique(na.omit(snps$cs_id)))
  171. n_cs <- length(cs_ids)
  172. cs_cols <- if (n_cs > 0) {
  173. setNames(RColorBrewer::brewer.pal(max(3, n_cs), "Set1")[1:n_cs], cs_ids)
  174. } else character(0)
  175. col_vec <- c("not_CS" = "grey80", cs_cols)
  176. snps$cs_id_plot <- ifelse(is.na(snps$cs_id), "not_CS", snps$cs_id)
  177. snps$neglogP <- -log10(snps$P)
  178. # top SNP labels (max pip per CS)
  179. top_snps <- snps %>%
  180. group_by(cs_id) %>%
  181. filter(pip == max(pip)) %>%
  182. ungroup() %>%
  183. filter(!is.na(cs_id))
  184. p <- ggplot(snps, aes(x = pos, y = neglogP)) +
  185. geom_point(aes(colour = cs_id_plot, size = pip), alpha = 0.9) +
  186. scale_colour_manual(values = col_vec, name = "Credible set") +
  187. scale_size(range = c(1.2, 4), name = "PIP") +
  188. geom_text_repel(
  189. data = top_snps,
  190. aes(label = SNP),
  191. size = 3,
  192. min.segment.length = 0
  193. ) +
  194. theme_classic(base_size = 14) +
  195. labs(
  196. title = paste0(title_prefix, trait_label, " fine-mapping (SuSiE)"),
  197. x = "Genomic position (chr 3, MOBP locus)",
  198. y = expression(-log[10](P))
  199. )
  200. p
  201. }
  202. p_psp <- plot_cs_manhattan(psp_cs, "PSP", "Credible sets: ")
  203. p_als <- plot_cs_manhattan(als_cs, "ALS", "Credible sets: ")
  204. p_ftd <- plot_cs_manhattan(ftd_cs, "FTD", "Credible sets: ")
  205. ```
  206. ```{r}
  207. plot_pip_track <- function(cs_obj, trait_label) {
  208. snps <- cs_obj$snp_level
  209. snps$cs_id_plot <- ifelse(is.na(snps$cs_id), "not_CS", snps$cs_id)
  210. cs_ids <- sort(unique(na.omit(snps$cs_id)))
  211. n_cs <- length(cs_ids)
  212. cs_cols <- if (n_cs > 0) {
  213. setNames(RColorBrewer::brewer.pal(max(3, n_cs), "Set1")[1:n_cs], cs_ids)
  214. } else character(0)
  215. col_vec <- c("not_CS" = "grey80", cs_cols)
  216. ggplot(snps, aes(x = pos, y = pip, colour = cs_id_plot)) +
  217. geom_point(size = 2, alpha = 0.9) +
  218. scale_colour_manual(values = col_vec, name = "Credible set") +
  219. theme_classic(base_size = 14) +
  220. labs(
  221. title = paste(trait_label, "posterior inclusion probabilities"),
  222. x = "Genomic position",
  223. y = "PIP"
  224. )
  225. }
  226. ```
  227. ```{r}
  228. library(dplyr)
  229. library(ggplot2)
  230. library(ggrepel)
  231. plot_pip_with_labels <- function(cs_obj, disease_label,
  232. top_n_per_cs = 3,
  233. min_pip = 0.01) {
  234. # cs_obj is the list from summarise_cs()
  235. snps <- cs_obj$snp_level %>%
  236. mutate(
  237. cs = ifelse(is.na(cs_id), "not_CS", cs_id),
  238. PIP = pip
  239. )
  240. # label only top K SNPs per CS with PIP >= min_pip
  241. lab_df <- snps %>%
  242. filter(cs != "not_CS", PIP >= min_pip) %>%
  243. group_by(cs) %>%
  244. slice_max(order_by = PIP,
  245. n = top_n_per_cs,
  246. with_ties = FALSE) %>%
  247. ungroup()
  248. ggplot(snps, aes(x = pos, y = PIP, colour = cs)) +
  249. geom_point(alpha = 0.9, size = 2) +
  250. geom_text_repel(
  251. data = lab_df,
  252. aes(label = SNP),
  253. size = 3,
  254. box.padding = 0.3,
  255. point.padding = 0.1,
  256. min.segment.length = 0,
  257. max.overlaps = Inf,
  258. colour = "black"
  259. ) +
  260. scale_colour_manual(
  261. values = c(
  262. "CS1" = "#d62728",
  263. "CS2" = "#1f77b4",
  264. "CS3" = "#2ca02c",
  265. "not_CS" = "grey75"
  266. ),
  267. name = "Credible set"
  268. ) +
  269. theme_classic(base_size = 13) +
  270. labs(
  271. title = paste(disease_label, "posterior inclusion probabilities"),
  272. x = "Genomic position (chr3, MOBP locus)",
  273. y = "PIP"
  274. )
  275. }
  276. p_pip_psp <- plot_pip_with_labels(psp_cs, "PSP")
  277. p_pip_als <- plot_pip_with_labels(als_cs, "ALS")
  278. p_pip_ftd <- plot_pip_with_labels(ftd_cs, "FTD")
  279. library(patchwork)
  280. p_pip_psp + p_pip_als + p_pip_ftd +
  281. plot_layout(ncol = 1)
  282. ```
  283. ```{r}
  284. library(dplyr)
  285. library(tidyr)
  286. all_cs_snps <- tibble(SNP = unique(c(psp_cs1, als_cs1, ftd_cs1)))
  287. # presence/absence for each disease
  288. cs_membership <- all_cs_snps %>%
  289. mutate(
  290. PSP = SNP %in% psp_cs1,
  291. ALS = SNP %in% als_cs1,
  292. FTD = SNP %in% ftd_cs1
  293. )
  294. cs_membership
  295. ```
  296. ```{r}
  297. library(dplyr)
  298. library(GenomicRanges)
  299. library(ggplot2)
  300. mobp_gff <- gencode_gff %>%
  301. filter(gene_name == "MOBP")
  302. unique(mobp_gff$seqid)
  303. unique(mobp_gff$strand)
  304. mobp_exons_raw <- mobp_gff %>%
  305. filter(type == "exon") %>%
  306. select(seqid, start, end, strand)
  307. gr_exons <- GRanges(
  308. seqnames = mobp_exons_raw$seqid,
  309. ranges = IRanges(start = mobp_exons_raw$start,
  310. end = mobp_exons_raw$end)
  311. )
  312. gr_exons_merged <- reduce(gr_exons)
  313. mobp_exons_merged <- as.data.frame(gr_exons_merged) %>%
  314. rename(seqid = seqnames) %>%
  315. select(seqid, start, end)
  316. gene_start <- min(mobp_exons_merged$start)
  317. gene_end <- max(mobp_exons_merged$end)
  318. ggplot() +
  319. # gene backbone = intron line
  320. geom_segment(
  321. aes(x = gene_start, xend = gene_end, y = 0, yend = 0),
  322. linewidth = 0.6,
  323. colour = "grey40"
  324. ) +
  325. # merged exons as boxes on the backbone
  326. geom_rect(
  327. data = mobp_exons_merged,
  328. aes(xmin = start, xmax = end,
  329. ymin = -0.1, ymax = 0.1),
  330. fill = "grey20"
  331. ) +
  332. coord_cartesian(
  333. xlim = c(gene_start - 2000, gene_end + 2000), # add a bit of padding
  334. ylim = c(-0.3, 0.3),
  335. expand = FALSE
  336. ) +
  337. theme_classic(base_size = 12) +
  338. labs(
  339. x = "Genomic position on chr3",
  340. y = NULL,
  341. title = "MOBP gene structure (merged exons across transcripts)"
  342. ) +
  343. theme(
  344. axis.text.y = element_blank(),
  345. axis.ticks.y = element_blank()
  346. )
  347. ```
  348. ```{r}
  349. library(dplyr)
  350. library(GenomicRanges)
  351. library(ggplot2)
  352. mobp_exons <- gencode_gff %>%
  353. filter(gene_name == "MOBP", type == "exon")
  354. gr <- GRanges(
  355. seqnames = mobp_exons$seqid,
  356. ranges = IRanges(start = mobp_exons$start, end = mobp_exons$end)
  357. )
  358. gr_merged <- reduce(gr)
  359. mobp_exons_merged <- as.data.frame(gr_merged) %>%
  360. transmute(start = start, end = end)
  361. gene_start <- min(mobp_exons_merged$start)
  362. gene_end <- max(mobp_exons_merged$end)
  363. p_strip <- ggplot() +
  364. # intron backbone
  365. geom_segment(aes(x = gene_start, xend = gene_end, y = 0, yend = 0),
  366. linewidth = 0.6, colour = "grey40") +
  367. # exons (merged)
  368. geom_rect(data = mobp_exons_merged,
  369. aes(xmin = start, xmax = end, ymin = -0.1, ymax = 0.1),
  370. fill = "grey20") +
  371. coord_cartesian(
  372. xlim = c(gene_start - 2000, gene_end + 2000),
  373. ylim = c(-0.3, 0.3),
  374. expand = FALSE
  375. ) +
  376. theme_classic(base_size = 12) +
  377. theme(
  378. axis.title.y = element_blank(),
  379. axis.text.y = element_blank(),
  380. axis.ticks.y = element_blank()
  381. ) +
  382. labs(
  383. x = "Genomic position (chr3)",
  384. title = "MOBP gene structure (merged exons)"
  385. )
  386. p_strip
  387. ```
  388. ```{r}
  389. library(dplyr)
  390. psp_cs1 <- psp_cs$snp_level %>%
  391. filter(cs_id == "CS1") %>%
  392. pull(SNP) %>%
  393. unique()
  394. als_cs1 <- als_cs$snp_level %>%
  395. filter(cs_id == "CS1") %>%
  396. pull(SNP) %>%
  397. unique()
  398. ftd_cs1 <- ftd_cs$snp_level %>%
  399. filter(cs_id == "CS1") %>%
  400. pull(SNP) %>%
  401. unique()
  402. all_cs_snps <- tibble(SNP = unique(c(psp_cs1, als_cs1, ftd_cs1)))
  403. cs_membership <- all_cs_snps %>%
  404. mutate(
  405. PSP = SNP %in% psp_cs1,
  406. ALS = SNP %in% als_cs1,
  407. FTD = SNP %in% ftd_cs1
  408. )
  409. pos_lookup <- bind_rows(
  410. ALS_f %>% select(SNP, pos),
  411. PSP_f %>% select(SNP, pos),
  412. FTD_h %>% select(SNP, pos)
  413. ) %>%
  414. distinct(SNP, .keep_all = TRUE)
  415. cs_snps_pos <- cs_membership %>%
  416. left_join(pos_lookup, by = "SNP")
  417. cs_snps_pos <- cs_snps_pos %>%
  418. mutate(
  419. group = case_when(
  420. PSP & ALS & !FTD ~ "Shared PSP+ALS",
  421. ALS & !PSP & !FTD ~ "ALS only",
  422. PSP & !ALS & !FTD ~ "PSP only",
  423. FTD & !PSP & !ALS ~ "FTD only",
  424. TRUE ~ "Other"
  425. )
  426. )
  427. gene_start <- min(mobp_exons_merged$start)
  428. gene_end <- max(mobp_exons_merged$end)
  429. mobp_exons_merged # from the code that made your strip
  430. library(ggplot2)
  431. library(ggrepel)
  432. snp_y <- 0.25
  433. min_pos <- min(cs_snps_pos$pos, na.rm = TRUE)
  434. left_lim <- min(min_pos, gene_start) - 2000 # include upstream FTD
  435. right_lim <- gene_end + 2000 # always keep full gene
  436. p_mobp_cs <- ggplot() +
  437. # intron backbone
  438. geom_segment(
  439. aes(x = gene_start, xend = gene_end, y = 0, yend = 0),
  440. linewidth = 0.6,
  441. colour = "grey40"
  442. ) +
  443. # exons
  444. geom_rect(
  445. data = mobp_exons_merged,
  446. aes(xmin = start, xmax = end, ymin = -0.1, ymax = 0.1),
  447. fill = "grey20"
  448. ) +
  449. # SNP stems
  450. geom_segment(
  451. data = cs_snps_pos,
  452. aes(x = pos, xend = pos, y = 0, yend = 0.25, colour = group),
  453. linewidth = 0.5
  454. ) +
  455. # SNP points
  456. geom_point(
  457. data = cs_snps_pos,
  458. aes(x = pos, y = 0.25, colour = group),
  459. size = 2
  460. ) +
  461. # labels for shared PSP+ALS
  462. ggrepel::geom_text_repel(
  463. data = cs_snps_pos ,
  464. aes(x = pos, y = 0.25, label = SNP, colour = group),
  465. nudge_y = 0.1,
  466. size = 3,
  467. show.legend = FALSE
  468. ) +
  469. scale_colour_manual(
  470. values = c(
  471. "Shared PSP+ALS" = "#E31A1C",
  472. "ALS only" = "#1F78B4",
  473. "FTD only" = "#33A02C"
  474. ),
  475. name = "CS1 membership"
  476. ) +
  477. coord_cartesian(
  478. xlim = c(left_lim, right_lim),
  479. ylim = c(-0.3, 0.5),
  480. expand = FALSE
  481. ) +
  482. theme_classic(base_size = 12) +
  483. theme(
  484. axis.title.y = element_blank(),
  485. axis.text.y = element_blank(),
  486. axis.ticks.y = element_blank()
  487. ) +
  488. labs(
  489. x = "Genomic position (chr3)",
  490. title = "CS1 credible SNPs across MOBP locus"
  491. )
  492. p_mobp_cs
  493. ```
  494. ```{r}
  495. library(dplyr)
  496. library(tidyr)
  497. library(stringr)
  498. all_cs1_snps <- union(union(psp_cs_snps, als_cs1), ftd_cs1)
  499. summary_tbl <- tibble(SNP = all_cs1_snps) %>%
  500. mutate(
  501. PSP = ifelse(SNP %in% psp_cs1, "✓", ""),
  502. ALS = ifelse(SNP %in% als_cs1, "✓", ""),
  503. FTD = ifelse(SNP %in% ftd_cs1, "✓", "")
  504. )
  505. summary_tbl <- summary_tbl %>%
  506. mutate(
  507. Group = case_when(
  508. PSP == "✓" & ALS == "✓" ~ "Shared PSP+ALS",
  509. ALS == "✓" & PSP == "" ~ "ALS only",
  510. FTD == "✓" ~ "FTD only",
  511. TRUE ~ "Other"
  512. )
  513. )
  514. get_pip_df <- function(cs_obj, label){
  515. cs_obj %>%
  516. select(SNP, PIP) %>%
  517. rename(!!paste0(label, "_PIP") := PIP)
  518. }
  519. pip_psp <- get_pip_df(psp_cs, "PSP")
  520. pip_als <- get_pip_df(als_cs, "ALS")
  521. pip_ftd <- get_pip_df(ftd_cs, "FTD")
  522. summary_tbl <- summary_tbl %>%
  523. left_join(pip_psp, by = "SNP") %>%
  524. left_join(pip_als, by = "SNP") %>%
  525. left_join(pip_ftd, by = "SNP")
  526. summary_tbl <- summary_tbl %>%
  527. arrange(desc(Group), SNP)
  528. summary_tbl
  529. ```
  530. ```{r}
  531. library(dplyr)
  532. psp_cs1_df <- psp_cs$snp_level %>%
  533. filter(cs_id == "CS1") %>%
  534. transmute(
  535. SNP,
  536. pos,
  537. PSP_PIP = pip,
  538. PSP_CS1 = TRUE
  539. )
  540. als_cs1_df <- als_cs$snp_level %>%
  541. filter(cs_id == "CS1") %>%
  542. transmute(
  543. SNP,
  544. pos,
  545. ALS_PIP = pip,
  546. ALS_CS1 = TRUE
  547. )
  548. ftd_cs1_df <- ftd_cs$snp_level %>%
  549. filter(cs_id == "CS1") %>%
  550. transmute(
  551. SNP,
  552. pos,
  553. FTD_PIP = pip,
  554. FTD_CS1 = TRUE
  555. )
  556. cs1_summary <- psp_cs1_df %>%
  557. full_join(als_cs1_df, by = c("SNP", "pos")) %>%
  558. full_join(ftd_cs1_df, by = c("SNP", "pos"))
  559. cs1_summary <- cs1_summary %>%
  560. mutate(
  561. PSP_CS1 = if_else(is.na(PSP_CS1), FALSE, PSP_CS1),
  562. ALS_CS1 = if_else(is.na(ALS_CS1), FALSE, ALS_CS1),
  563. FTD_CS1 = if_else(is.na(FTD_CS1), FALSE, FTD_CS1),
  564. PSP_PIP = if_else(is.na(PSP_PIP), 0, PSP_PIP),
  565. ALS_PIP = if_else(is.na(ALS_PIP), 0, ALS_PIP),
  566. FTD_PIP = if_else(is.na(FTD_PIP), 0, FTD_PIP)
  567. )
  568. cs1_summary <- cs1_summary %>%
  569. mutate(
  570. Group = case_when(
  571. PSP_CS1 & ALS_CS1 & !FTD_CS1 ~ "Shared PSP+ALS",
  572. ALS_CS1 & !PSP_CS1 & !FTD_CS1 ~ "ALS only",
  573. FTD_CS1 & !PSP_CS1 & !ALS_CS1 ~ "FTD only",
  574. TRUE ~ "Other"
  575. ),
  576. PSP = if_else(PSP_CS1, "✓", ""),
  577. ALS = if_else(ALS_CS1, "✓", ""),
  578. FTD = if_else(FTD_CS1, "✓", "")
  579. ) %>%
  580. select(
  581. SNP, pos,
  582. PSP, ALS, FTD,
  583. PSP_PIP, ALS_PIP, FTD_PIP,
  584. Group
  585. ) %>%
  586. arrange(Group, SNP)
  587. cs1_summary
  588. ```

SuSiE Colocalisation GWAS.Rmd at commit e0ce8e7, no license · at the source

Overview

Authors: Katherine Fodder1, Megha Murthy2, Rohan de Silva2,3, Towfique Raj4,5,6,7, Kurt Farrell5,6,7,8,9,10, Jack Humphrey4,5,6,7, Conceição Bettencourt1
  1. Department of Neurodegenerative Disease, UCL Queen Square Institute of Neurology, London, UK
  2. Department of Clinical and Movement Neurosciences, UCL Queen Square Institute of Neurology, London, UK
  3. Reta Lila Weston Institute, UCL Queen Square Institute of Neurology, London, UK
  4. Department of Genetics and Genomic Sciences, Icahn Genomics Institute, Estelle and Daniel Maggin Department of Neurology, Icahn School of Medicine at Mount Sinai, New York, NY, USA
  5. Nash Family Department of Neuroscience, Icahn School of Medicine at Mount Sinai, New York, NY, USA
  6. Ronald M. Loeb Center for Alzheimer’s Disease, Icahn School of Medicine at Mount Sinai, New York, NY, USA
  7. Friedman Brain Institute, Icahn School of Medicine at Mount Sinai, New York, NY, USA
  8. Department of Pathology, Icahn School of Medicine at Mount Sinai, New York, NY, USA
  9. Department of Artificial Intelligence & Human Health, Icahn School of Medicine at Mount Sinai, New York, NY, USA
  10. Neuropathology Brain Bank & Research CoRE, Icahn School of Medicine at Mount Sinai, New York, NY, USA
Dates: published online 27 March 2026
Type: Preprint · Language: English
License: CC BY
Identifiers: DOI 10.64898/2026.03.25.714147 · OpenAlex W7141512504
Open access: green, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: genetics / omics (modality), other condition (population), Alzheimer's / dementia (population), cellular / molecular (subfield)
Methods: Statistics
Topic: Amyotrophic Lateral Sclerosis Research (Clinical Neurology, Medicine), according to OpenAlex
Funding: BrightFocus Foundation; CurePSP; Target ALS; Georgia Clinical and Translational Science Alliance (UL1TR004419); National Institutes of Health (U01-AG068880, R01-NS116006, R01-AG054005, UL1 TR004419, AG066514, NIA R01-AG054005, RF1-AG065926); Tau Consortium; Medical Research Council (MR/N013867/1); National Institute on Aging (K01AG070326, U01 AG068880, R21-AG063130, R01- AG054005, NIA R21-AG063130, RF1-AG065926); National Institute of Neurological Disorders and Stroke (R01 NS116006); National Center for Advancing Translational Sciences (UL1TR004419); Reta Lila Weston Trust for Medical Research
Citations: not cited yet (Europe PMC); 48 references in the paper

Abstract

Myelin oligodendrocyte basic protein (MOBP) is an abundant oligodendrocyte gene implicated in multiple neurodegenerative diseases. Genetic variation at the MOBP locus has been associated with risk for progressive supranuclear palsy (PSP), amyotrophic lateral sclerosis (ALS), frontotemporal lobar degeneration (FTD), corticobasal degeneration (CBD), Alzheimer’s disease (AD), Lewy body dementia (LBD), and Creutzfeldt–Jakob disease (CJD). Epigenetically, MOBP promoter hypermethylation and reduced expression have been reported in multiple system atrophy (MSA). Although MOBP is thought to play a role in oligodendrocyte morphology and myelin structure, how genetic and epigenetic variation at this locus influences gene regulation and contributes to disease risk remains poorly understood across neurodegenerative disorders.

Here, we investigated whether shared or disease-specific genetic mechanisms at MOBP converge on altered DNA methylation and expression across neurodegenerative disorders. We analysed MOBP variants using summary statistics from recent GWAS for ALS, PSP, FTD, LBD, PD, MSA, AD, and CJD. Colocalisation (COLOC and SuSiE-coloc) was used to test whether disease-associated variants overlapped between diseases, and with oligodendrocyte expression quantitative trait loci (eQTLs) and bulk brain methylation quantitative trait loci (mQTLs). To further investigate mQTL effects at this locus, rs1768208, a variant previously associated with PSP, was genotyped in an overlapping brain methylation cohort, allowing direct testing of genotype–methylation associations in frontal white matter tissue.

ALS and PSP GWAS demonstrated strong association at MOBP, with most strongly associated SNPs (e.g. rs631312, rs616147, rs1768208) shared between both disorders. Colocalisation analyses indicated high posterior probability that ALS and PSP share the same causal variant, with weaker overlap with FTD. mQTL colocalisation highlighted cg15069948, located near an exon junction within MOBP, as strongly colocalising with the ALS/PSP risk variants. In complementary tissue analyses, rs1768208-T carriers showed hypomethylation at cg15069948 in PSP brains. No genotype-methylation effects were detected in MSA or Parkinson’s disease.

Together with prior evidence of promoter hypermethylation and reduced expression in MSA, our findings identify cg15069948 as a regulatory methylation site linking ALS/PSP risk variants to altered MOBP methylation, and support MOBP dysregulation as a shared feature of neurodegeneration. However, the underlying mechanisms appear disease-specific, highlighting the complexity of involvement of this gene across neurodegenerative disorders.

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

Repository

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

CBettencourtLab/MOBPAnalysis

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Commit: e0ce8e7e53a02528aa6718f3feec05730e32e1b4, 25 August 2026
Languages: Shell (3), R (2)
Size: 10 files, 5 scripts
Software Heritage: not archived
Found in: “Code Availability”
Holds: README, 2 notebooks
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: ggplot2 (2 files), patchwork (2 files), STAR (2 files), tidyverse (2 files), pheatmap (1 file), reshape2 (1 file), SAMtools (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers
  • 30 September 2026: the link answers
6 files

Code Availability

All code used for analysis will be made available upon publication in a publicly accessible GitHub repository: https://github.com/CBettencourtLab/MOBPAnalysis.

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

Tracing map

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

What the map holds:

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

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

Data

Datasets cited

Data Availability

ALS, MSA, AD, CJD and PD GWAS summary statistics were accessed through the GWAS Catalog (accession numbers GCST90027164, GCST90406924, GCST90027158, GCST90001389 and GCST009325 respectively). FTD GWAS summary statistics were accessed from the UCL Research Data Depository (https://doi.org/10.5522/04/25600692.v1.). eQTL summary statistics were accessed through https://zenodo.org/records/7276971. mQTL summary statistics were provided by the study authors (27).

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

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 30 September 2026: the first record

Recorded: type, language, journal, dates, 7 authors, 11 funders, 48 references.

Cite

This paper

Fodder, K., Murthy, M., de Silva, R., Raj, T., Farrell, K., Humphrey, J., & Bettencourt, C. (2026). Genetic and epigenetic convergence at <i>MOBP</i> links ALS and PSP. bioRxiv (preprint). https://doi.org/10.64898/2026.03.25.714147

BibTeX

@article{fodder2026genetic,
author = {Fodder, Katherine and Murthy, Megha and de Silva, Rohan and Raj, Towfique and Farrell, Kurt and Humphrey, Jack and Bettencourt, Conceição},
title = {{Genetic and epigenetic convergence at <i>MOBP</i> links ALS and PSP}},
journal = {bioRxiv (preprint)},
year = {2026},
month = mar,
publisher = {bioRxiv},
issn = {2692-8205},
doi = {10.64898/2026.03.25.714147},
url = {https://doi.org/10.64898/2026.03.25.714147}
}

RIS

TY - JOUR
AU - Fodder, Katherine
AU - Murthy, Megha
AU - de Silva, Rohan
AU - Raj, Towfique
AU - Farrell, Kurt
AU - Humphrey, Jack
AU - Bettencourt, Conceição
TI - Genetic and epigenetic convergence at <i>MOBP</i> links ALS and PSP
T2 - bioRxiv (preprint)
J2 - bioRxiv
PY - 2026
DA - 2026/03/27
SN - 2692-8205
PB - bioRxiv
DO - 10.64898/2026.03.25.714147
UR - https://doi.org/10.64898/2026.03.25.714147
LA - en
ER -

CSL-JSON

{
"id": "10.64898/2026.03.25.714147",
"type": "article",
"title": "Genetic and epigenetic convergence at <i>MOBP</i> links ALS and PSP",
"container-title": "bioRxiv (preprint)",
"author": [
{
"family": "Fodder",
"given": "Katherine"
},
{
"family": "Murthy",
"given": "Megha"
},
{
"family": "de Silva",
"given": "Rohan"
},
{
"family": "Raj",
"given": "Towfique"
},
{
"family": "Farrell",
"given": "Kurt"
},
{
"family": "Humphrey",
"given": "Jack"
},
{
"family": "Bettencourt",
"given": "Conceição"
}
],
"container-title-short": "bioRxiv",
"DOI": "10.64898/2026.03.25.714147",
"ISSN": "2692-8205",
"publisher": "bioRxiv",
"URL": "https://doi.org/10.64898/2026.03.25.714147",
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
27
]
]
}
}

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

Similar papers

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

[1] doi:10.1038/s41467-024-52025-x [code]
Genetic, transcriptomic, histological, and biochemical analysis of progressive supranuclear palsy implicates glial activation and novel risk genes.
Journal: Nature communications
In common: patchwork, tidyverse, Alzheimer's / dementia, genetics / omics, cellular / molecular, 8 references, author Towfique Raj
[2] doi:10.1038/s41467-026-73007-1 [code]
Single-nucleus epigenomic dysregulation unmasks genetic risk-associated neurodegenerative glia states.
Journal: Nature communications
In common: SAMtools, patchwork, reshape2, 2 other tools, Alzheimer's / dementia, genetics / omics, other condition, 1 other category, 3 references, author Towfique Raj
[3] doi:10.1007/s00401-023-02583-z [code]
Brain DNA methylomic analysis of frontotemporal lobar degeneration reveals OTUD4 in shared dysregulated signatures across pathological subtypes.
Journal: Acta neuropathologica
In common: Alzheimer's / dementia, genetics / omics, cellular / molecular, 2 references, 2 authors
[4] doi:10.1101/2025.08.28.672821 [code]
Early oligodendrocyte dysfunction signature in Alzheimer’s disease: Insights from DNA methylomics and transcriptomics
Journal: bioRxiv (preprint)
In common: ggplot2, tidyverse, Alzheimer's / dementia, genetics / omics, other condition, 1 other category, 4 references, author Conceição Bettencourt
[5] doi:10.1038/s41380-026-03686-1 [code]
Early oligodendrocyte dysfunction signature in Alzheimer's disease: Insights from DNA methylomics and transcriptomics.
Journal: Molecular psychiatry
In common: ggplot2, tidyverse, Alzheimer's / dementia, genetics / omics, cellular / molecular, 4 references, author Conceição Bettencourt
[6] doi:10.1038/s41588-023-01300-6 [code]
Brain expression quantitative trait locus and network analyses reveal downstream effects and putative drivers for brain-related diseases.
Journal: Nature genetics
In common: SAMtools, pheatmap, patchwork, 3 other tools, genetics / omics, cellular / molecular, 5 references
[7] doi:10.1038/s41593-025-02050-w [code]
TDP-43 loss induces cryptic polyadenylation in ALS/FTD.
Journal: Nature neuroscience
In common: STAR, SAMtools, patchwork, 2 other tools, Alzheimer's / dementia, genetics / omics, other condition, 1 other category, author Towfique Raj
[8] doi:10.1038/s41467-025-57751-4 [code]
Cross-ancestry genome-wide association study identifies implications of SORL1 in cerebral beta-amyloid deposition.
Journal: Nature communications
In common: SAMtools, reshape2, ggplot2, 1 other tool, Alzheimer's / dementia, genetics / omics, cellular / molecular, 2 references, author Towfique Raj
[9] doi:10.1038/s41467-025-59949-y [code]
Whole-genome sequencing analyses suggest novel genetic factors associated with Alzheimer's disease and a cumulative effects model for risk liability.
Journal: Nature communications
In common: SAMtools, reshape2, ggplot2, 1 other tool, Alzheimer's / dementia, genetics / omics, 2 references, author Towfique Raj
[10] doi:10.1038/s41467-023-41033-y [code]
Divergent single cell transcriptome and epigenome alterations in ALS and FTD patients with C9orf72 mutation.
Journal: Nature communications
In common: STAR, SAMtools, pheatmap, 4 other tools, Alzheimer's / dementia, genetics / omics, other condition, 1 other category, 1 reference

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/doi/10.64898/2026.03.25.714147.svg)](https://openscicode.org/badge/doi/10.64898/2026.03.25.714147)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.64898/2026.03.25.714147.svg
   :target: https://openscicode.org/badge/doi/10.64898/2026.03.25.714147
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.64898/2026.03.25.714147"><img src="https://openscicode.org/badge/doi/10.64898/2026.03.25.714147.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge 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: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.