OSCR

Convergent coexpression reveals shared biological mechanisms underlying common and rare variant risk in six neuropsychiatric disorders.

Code ↔ Paper

6 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 6 matches
  1. [1] § Methods › Heritability analysis for coexpression convergent genes ↔ example/run_BHR.R, lines 951–1069 · score 0.64 · baseline model, heritability explained, burden score, BHR, allele, variance
  2. [2] § Methods › Gene prioritization from GWAS and rare variant burden studies ↔ pops.py, lines 16–57 · score 0.57 · Polygenic Priority Score, PoPS, trained, gene annotation, chromosome, MAGMA
  3. [3] § Methods › Enrichment of evolutionarily constrained and functionally prioritized gene-sets ↔ R/gson.R, lines 289–426 · score 0.54 · access date, Targets Database, modules, matching, genes
  4. [4] § Methods › Gene prioritization from GWAS and rare variant burden studies ↔ R/gseAnalyzer.R, lines 1–32 · score 0.52 · pvalue cutoff, ranked genes, thresholds
  5. [5] § Methods › Functional annotation of convergent genes ↔ R/enricher.R, lines 83–115 · score 0.50 · cluster Profiler, Hochberg, FDR, BH, pvalue, enrichment
  6. [6] § Methods › Heritability analysis for coexpression convergent genes ↔ ldsc.py, lines 422–481 · score 0.50 · LD scores, kb, bin, window, partition, MAF

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 · 1,180 lines · 67 KB · MIT · 1 match

  1. library(bhr)
  2. source("correct_winners_curse.R")
  3. library(pracma)
  4. ########################################BHR basic estimates (h2, intercept) #############################
  5. path = "/Users/daniel/Desktop/rare_h2/ms/genebass_summary_statistics_null/"
  6. phenotype_file <- read.csv("~/rv_h2/reference_files/ms_phenotype_sheet.csv")
  7. traits = phenotype_file[phenotype_file$phenotype_rg == 1,"phenotype_key"]
  8. baseline_model <- read.table("~/rv_h2/reference_files/ms_baseline_oe5.txt")
  9. bhr_summary_statistic_names <- c("bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1",
  10. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low1e-05_high0.0001_group2",
  11. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0.0001_high0.001_group3",
  12. "bhr_ms_gene_ss_400k_final_withnullburden_synonymous_low0_high1e-05_group1",
  13. "bhr_ms_gene_ss_400k_final_withnullburden_synonymous_low1e-05_high0.0001_group2",
  14. "bhr_ms_gene_ss_400k_final_withnullburden_synonymous_low0.0001_high0.001_group3",
  15. "bhr_ms_gene_ss_400k_final_withnullburden_missense-benign_low0_high1e-05_group1",
  16. "bhr_ms_gene_ss_400k_final_withnullburden_missense-benign_low1e-05_high0.0001_group2",
  17. "bhr_ms_gene_ss_400k_final_withnullburden_missense-benign_low0.0001_high0.001_group3",
  18. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0_high1e-05_group1",
  19. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low1e-05_high0.0001_group2",
  20. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0.0001_high0.001_group3")
  21. results_holder <- matrix(data = NA, ncol = 23, nrow = length(bhr_summary_statistic_names) * length(traits))
  22. counter = 1
  23. for (ss in bhr_summary_statistic_names){
  24. summary_statistics <- readRDS(paste0(path,ss,".ms.munged.Rds"))
  25. for (trait in traits){
  26. n_bhr_trait <- head(summary_statistics[summary_statistics$phenotype_key == trait,"N"],1)
  27. print(c(trait, n_bhr_trait))
  28. output = BHR(mode = "univariate",
  29. trait1_sumstats = summary_statistics[summary_statistics$phenotype_key == trait,],
  30. annotations = list(baseline_model))
  31. results_holder[counter,] <- c(trait,
  32. ss,
  33. output$mixed_model$heritabilities[1,ncol(baseline_model)],
  34. output$mixed_model$heritabilities[2,ncol(baseline_model)],
  35. output$mixed_model$enrichments[1,1],
  36. output$mixed_model$enrichments[2,1],
  37. output$mixed_model$enrichments[1,2],
  38. output$mixed_model$enrichments[2,2],
  39. output$mixed_model$enrichments[1,3],
  40. output$mixed_model$enrichments[2,3],
  41. output$mixed_model$enrichments[1,4],
  42. output$mixed_model$enrichments[2,4],
  43. ((1-sum(output$mixed_model$fractions[1,]))/(1-sum(output$mixed_model$fraction_burden_score))),
  44. output$significant_genes$number_significant_genes,
  45. output$significant_genes$fraction_burdenh2_significant,
  46. output$significant_genes$fraction_burdenh2_significant_se,
  47. output$qc$intercept,
  48. output$qc$intercept_se,
  49. output$qc$attenuation_ratio,
  50. output$qc$attenuation_ratio_se,
  51. output$qc$lambda_gc,
  52. output$qc$lambda_gc_se,
  53. output$qc$mu_genome)
  54. print(paste0("Finished BHR estimate for ",trait," in summary statistic group ",ss))
  55. counter = counter + 1
  56. }
  57. }
  58. results_holder_df = as.data.frame(results_holder)
  59. results_holder_df[,3:23] <- sapply(results_holder_df[,3:23],as.numeric)
  60. colnames(results_holder_df) <- c("phenotype_key", "summary_statistic", "bhr_h2", "bhr_h2_se",
  61. "bhr_enrichment_oe1", "bhr_enrichment_oe1_se",
  62. "bhr_enrichment_oe2", "bhr_enrichment_oe2_se",
  63. "bhr_enrichment_oe3", "bhr_enrichment_oe3_se",
  64. "bhr_enrichment_oe4", "bhr_enrichment_oe4_se",
  65. "bhr_enrichment_oe5",
  66. "n_significant_genes","fraction_h2_significant_genes", "fraction_h2_significant_genes_se",
  67. "intercept", "intercept_se", "attenuation_ratio", "attenuation_ratio_se", "lambda_gc", "lambda_gc_se", "mu_genome")
  68. results_holder_df = merge(results_holder_df, phenotype_file[c("phenotype_key", "display_name", "phenocode", "n_bhr", "phenotype_core")], by = "phenotype_key")
  69. write.csv(results_holder_df, "~/rv_h2/outputs/bhr_output_h2.csv")
  70. ######################Basic BHR estimates, plus slope correction ##########################
  71. source("~/rv_h2/BHR.R")
  72. source("~/rv_h2/BHR_h2.R")
  73. source("~/rv_h2/randomeffects_jackknife.R")
  74. source("~/rv_h2/BHR_meta.R")
  75. path = "/Users/daniel/Desktop/rare_h2/ms/genebass_summary_statistics_null/"
  76. phenotype_file <- read.csv("~/rv_h2/reference_files/ms_phenotype_sheet.csv")
  77. traits = phenotype_file[phenotype_file$phenotype_rg == 1,"phenotype_key"]
  78. baseline_model <- read.table("~/rv_h2/reference_files/ms_baseline_oe5.txt")
  79. bhr_summary_statistic_names <- c("bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1",
  80. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low1e-05_high0.0001_group2",
  81. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0.0001_high0.001_group3",
  82. "bhr_ms_gene_ss_400k_final_withnullburden_synonymous_low0_high1e-05_group1",
  83. "bhr_ms_gene_ss_400k_final_withnullburden_synonymous_low1e-05_high0.0001_group2",
  84. "bhr_ms_gene_ss_400k_final_withnullburden_synonymous_low0.0001_high0.001_group3",
  85. "bhr_ms_gene_ss_400k_final_withnullburden_missense-benign_low0_high1e-05_group1",
  86. "bhr_ms_gene_ss_400k_final_withnullburden_missense-benign_low1e-05_high0.0001_group2",
  87. "bhr_ms_gene_ss_400k_final_withnullburden_missense-benign_low0.0001_high0.001_group3",
  88. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0_high1e-05_group1",
  89. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low1e-05_high0.0001_group2",
  90. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0.0001_high0.001_group3")
  91. results_holder <- matrix(data = NA, ncol = 23, nrow = length(bhr_summary_statistic_names) * length(traits))
  92. counter = 1
  93. for (ss in bhr_summary_statistic_names){
  94. summary_statistics <- readRDS(paste0(path,ss,".ms.munged.Rds"))
  95. for (trait in traits){
  96. n_bhr_trait <- head(summary_statistics[summary_statistics$phenotype_key == trait,"N"],1)
  97. print(c(trait, n_bhr_trait))
  98. output = BHR(mode = "univariate",
  99. trait1_sumstats = summary_statistics[summary_statistics$phenotype_key == trait,],
  100. annotations = list(baseline_model),
  101. slope_correction = 4.55087151/n_bhr_trait)
  102. results_holder[counter,] <- c(trait,
  103. ss,
  104. output$mixed_model$heritabilities[1,ncol(baseline_model)],
  105. output$mixed_model$heritabilities[2,ncol(baseline_model)],
  106. output$mixed_model$enrichments[1,1],
  107. output$mixed_model$enrichments[2,1],
  108. output$mixed_model$enrichments[1,2],
  109. output$mixed_model$enrichments[2,2],
  110. output$mixed_model$enrichments[1,3],
  111. output$mixed_model$enrichments[2,3],
  112. output$mixed_model$enrichments[1,4],
  113. output$mixed_model$enrichments[2,4],
  114. ((1-sum(output$mixed_model$fractions[1,]))/(1-sum(output$mixed_model$fraction_burden_score))),
  115. output$significant_genes$number_significant_genes,
  116. output$significant_genes$fraction_burdenh2_significant,
  117. output$significant_genes$fraction_burdenh2_significant_se,
  118. output$qc$intercept,
  119. output$qc$intercept_se,
  120. output$qc$attenuation_ratio,
  121. output$qc$attenuation_ratio_se,
  122. output$qc$lambda_gc,
  123. output$qc$lambda_gc_se,
  124. output$qc$mu_genome)
  125. print(paste0("Finished BHR estimate for ",trait," in summary statistic group ",ss))
  126. counter = counter + 1
  127. }
  128. }
  129. results_holder_df = as.data.frame(results_holder)
  130. results_holder_df[,3:23] <- sapply(results_holder_df[,3:23],as.numeric)
  131. colnames(results_holder_df) <- c("phenotype_key", "summary_statistic", "bhr_h2", "bhr_h2_se",
  132. "bhr_enrichment_oe1", "bhr_enrichment_oe1_se",
  133. "bhr_enrichment_oe2", "bhr_enrichment_oe2_se",
  134. "bhr_enrichment_oe3", "bhr_enrichment_oe3_se",
  135. "bhr_enrichment_oe4", "bhr_enrichment_oe4_se",
  136. "bhr_enrichment_oe5",
  137. "n_significant_genes","fraction_h2_significant_genes", "fraction_h2_significant_genes_se",
  138. "intercept", "intercept_se", "attenuation_ratio", "attenuation_ratio_se", "lambda_gc", "lambda_gc_se", "mu_genome")
  139. results_holder_df = merge(results_holder_df, phenotype_file[c("phenotype_key", "display_name", "phenocode", "n_bhr", "phenotype_core")], by = "phenotype_key")
  140. write.csv(results_holder_df, "~/rv_h2/outputs/bhr_output_h2_ldcorrection.csv")
  141. #############################################BHR gene set enrichments#####################
  142. source("~/rv_h2/BHR.R")
  143. source("~/rv_h2/BHR_h2.R")
  144. source("~/rv_h2/randomeffects_jackknife.R")
  145. source("~/rv_h2/BHR_meta.R")
  146. phenotype_file <- read.csv("~/rv_h2/reference_files/ms_phenotype_sheet.csv")
  147. gene_set_path = "/Users/daniel/Desktop/rare_h2/ms/gene_sets/gene_set_output/"
  148. bhr_gene_sets <- c("brain_GABAergic",
  149. "brain_Glutamatergic",
  150. "cosmic_all",
  151. "cosmic_oncogene",
  152. "cosmic_tsg",
  153. "ICA_cordblood_Erythroid",
  154. "ICA_cordblood_Megakaryocytes",
  155. "liver_Epithelial",
  156. "segblood",
  157. "segcortex",
  158. "segliver",
  159. "siggene_50NA",
  160. "siggene_2453NA",
  161. "siggene_3063NA",
  162. "siggene_21001NA",
  163. "siggene_30010NA",
  164. "siggene_30080NA",
  165. "siggene_30620NA",
  166. "siggene_30680NA",
  167. "siggene_30750NA",
  168. "siggene_30770NA",
  169. "siggene_30780NA",
  170. "siggene_50NA")
  171. summary_statistics <- readRDS("/Users/daniel/Desktop/rare_h2/ms/genebass_summary_statistics_null/bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1.ms.munged.Rds")
  172. traits = phenotype_file[phenotype_file$phenotype_core == 1,"phenotype_key"]
  173. baseline_model <- read.table("~/rv_h2/reference_files/ms_baseline_oe5.txt")
  174. results_holder <- matrix(data = NA, ncol = 6, nrow = length(bhr_gene_sets) * length(traits))
  175. counter = 1
  176. for (bhr_gene_set in bhr_gene_sets){
  177. bhr_gene_set_annotation <- read.table(paste0(gene_set_path,"bhr_ms_" ,bhr_gene_set,".txt"), header = TRUE)
  178. for (trait in traits){
  179. output = BHR(mode = "univariate",
  180. trait1_sumstats = summary_statistics[summary_statistics$phenotype_key == trait,],
  181. annotations = list(baseline_model, bhr_gene_set_annotation))
  182. results_holder[counter,] <- c(trait,
  183. bhr_gene_set,
  184. output$mixed_model$fractions[1,ncol(baseline_model)],
  185. output$mixed_model$fractions[2,ncol(baseline_model)],
  186. output$mixed_model$enrichments[1,ncol(baseline_model)],
  187. output$mixed_model$enrichments[2,ncol(baseline_model)])
  188. counter = counter + 1
  189. print(paste0("Completed trait ",trait))
  190. }
  191. print(paste0("Completed gene set: ", bhr_gene_set))
  192. }
  193. results_holder_df = as.data.frame(results_holder)
  194. results_holder_df[,3:6] <- sapply(results_holder_df[,3:6],as.numeric)
  195. colnames(results_holder_df) <- c("phenotype_key", "gene_set", "fraction_h2", "fraction_h2_se", "enrichment", "enrichment_se")
  196. results_holder_df$enrichment_z <- (results_holder_df$enrichment - 1) / results_holder_df$enrichment_se
  197. results_holder_df = merge(results_holder_df, phenotype_file[c("phenotype_key", "display_name", "phenocode", "n_bhr", "phenotype_core")], by = "phenotype_key")
  198. results_holder_df_rename <- results_holder_df
  199. results_holder_df_rename$gene_set_display <- ifelse(results_holder_df_rename$gene_set == "brain_Glutamatergic", "Glutamatergic_neurons",
  200. ifelse(results_holder_df_rename$gene_set == "segliver", "Liver",
  201. ifelse(results_holder_df_rename$gene_set == "ICA_cordblood_Megakaryocytes", "Megakaryocytes",
  202. ifelse(results_holder_df_rename$gene_set == "cosmic_all", "Cancer_genes",
  203. ifelse(results_holder_df_rename$gene_set == "cosmic_oncogene", "Cancer_oncogenes",
  204. ifelse(results_holder_df_rename$gene_set == "segblood", "Whole_blood",
  205. ifelse(results_holder_df_rename$gene_set == "cosmic_tsg", "Cancer_TSG",
  206. ifelse(results_holder_df_rename$gene_set == "ICA_cordblood_Erythroid", "Erythrocyte",
  207. ifelse(results_holder_df_rename$gene_set == "brain_GABAergic", "GABAergic_neuron",
  208. ifelse(results_holder_df_rename$gene_set == "liver_Epithelial", "Hepatocyte",
  209. ifelse(results_holder_df_rename$gene_set == "segcortex", "Cortex", NA)))))))))))
  210. write.csv(results_holder_df_rename[c("gene_set", "gene_set_display", "phenotype_key", "display_name",
  211. "fraction_h2", "fraction_h2_se", "enrichment", "enrichment_se", "enrichment_z")], "~/rv_h2/outputs/bhr_output_geneset.csv")
  212. #################################################BHR aggregate for each trait, and for all traits############################################
  213. source("~/rv_h2/BHR.R")
  214. source("~/rv_h2/BHR_h2.R")
  215. source("~/rv_h2/randomeffects_jackknife.R")
  216. source("~/rv_h2/BHR_meta.R")
  217. path = "/Users/daniel/Desktop/rare_h2/ms/genebass_summary_statistics_null/"
  218. phenotype_file <- read.csv("~/rv_h2/reference_files/ms_phenotype_sheet.csv")
  219. traits = phenotype_file[phenotype_file$phenotype_rg == 1,"phenotype_key"]
  220. baseline_model <- read.table("~/rv_h2/reference_files/ms_baseline_oe5.txt")
  221. bhr_summary_statistic_names <- c("bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1",
  222. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low1e-05_high0.0001_group2",
  223. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0.0001_high0.001_group3",
  224. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0_high1e-05_group1",
  225. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low1e-05_high0.0001_group2",
  226. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0.0001_high0.001_group3")
  227. #Aggregate h2 for each trait for g1-g3 (ultra-rare + rare)
  228. ss_list <- list(readRDS(paste0(path, bhr_summary_statistic_names[1],".ms.munged.Rds")),
  229. readRDS(paste0(path, bhr_summary_statistic_names[2],".ms.munged.Rds")),
  230. readRDS(paste0(path, bhr_summary_statistic_names[3],".ms.munged.Rds")),
  231. readRDS(paste0(path, bhr_summary_statistic_names[4],".ms.munged.Rds")),
  232. readRDS(paste0(path, bhr_summary_statistic_names[5],".ms.munged.Rds")),
  233. readRDS(paste0(path, bhr_summary_statistic_names[6],".ms.munged.Rds")))
  234. results_holder <- matrix(data = NA, ncol = 3, nrow = length(traits))
  235. counter = 1
  236. for (trait in traits){
  237. output <- BHR(mode = 'aggregate',
  238. ss_list_trait1 = ss_list, trait_list = list(trait),
  239. annotations = baseline_model)
  240. results_holder[counter,] <- c(trait,
  241. output$aggregated_mixed_model_h2,
  242. output$aggregated_mixed_model_h2se)
  243. print(paste0("Completed ",trait))
  244. counter = counter + 1
  245. }
  246. results_holder_df = as.data.frame(results_holder)
  247. results_holder_df[,2:3] <- sapply(results_holder_df[,2:3],as.numeric)
  248. colnames(results_holder_df) <- c("phenotype_key", "aggregated_h2", "aggregate_h2_se")
  249. results_holder_df = merge(results_holder_df, phenotype_file[c("phenotype_key", "display_name")], by = "phenotype_key")
  250. results_holder_df$ss_group = "g13_lof_mis"
  251. write.csv(results_holder_df, "~/rv_h2/outputs/bhr_output_aggregated_per_trait_h2.csv")
  252. #Aggregate across all core traits
  253. results_holder <- matrix(data = NA, ncol = 3, nrow = 1)
  254. output <- BHR(mode = 'aggregate', ss_list_trait1 = ss_list,
  255. trait_list = phenotype_file[phenotype_file$phenotype_core == 1,"phenotype_key"],
  256. annotations = baseline_model)
  257. results_holder[1,] <- c("All_traits",
  258. output$aggregated_mixed_model_h2,
  259. output$aggregated_mixed_model_h2se)
  260. results_holder_df = as.data.frame(results_holder)
  261. results_holder_df[,2:3] <- sapply(results_holder_df[,2:3],as.numeric)
  262. colnames(results_holder_df) <- c("phenotype_key", "aggregated_h2", "aggregated_h2_se")
  263. write.csv(results_holder_df, "~/rv_h2/outputs/bhr_output_aggregated_all_traits_h2.csv")
  264. #################################################BHR aggregate for each trait, and for all traits, with slope correction ############################################
  265. source("~/rv_h2/BHR.R")
  266. source("~/rv_h2/BHR_h2.R")
  267. source("~/rv_h2/randomeffects_jackknife.R")
  268. source("~/rv_h2/BHR_meta.R")
  269. path = "/Users/daniel/Desktop/rare_h2/ms/genebass_summary_statistics_null/"
  270. phenotype_file <- read.csv("~/rv_h2/reference_files/ms_phenotype_sheet.csv")
  271. traits = phenotype_file[phenotype_file$phenotype_rg == 1,"phenotype_key"]
  272. baseline_model <- read.table("~/rv_h2/reference_files/ms_baseline_oe5.txt")
  273. bhr_summary_statistic_names <- c("bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1",
  274. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low1e-05_high0.0001_group2",
  275. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0.0001_high0.001_group3",
  276. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0_high1e-05_group1",
  277. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low1e-05_high0.0001_group2",
  278. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0.0001_high0.001_group3")
  279. #Aggregate h2 for each trait for g1-g3 (ultra-rare + rare)
  280. ss_list <- list(readRDS(paste0(path, bhr_summary_statistic_names[1],".ms.munged.Rds")),
  281. readRDS(paste0(path, bhr_summary_statistic_names[2],".ms.munged.Rds")),
  282. readRDS(paste0(path, bhr_summary_statistic_names[3],".ms.munged.Rds")),
  283. readRDS(paste0(path, bhr_summary_statistic_names[4],".ms.munged.Rds")),
  284. readRDS(paste0(path, bhr_summary_statistic_names[5],".ms.munged.Rds")),
  285. readRDS(paste0(path, bhr_summary_statistic_names[6],".ms.munged.Rds")))
  286. results_holder <- matrix(data = NA, ncol = 3, nrow = length(traits))
  287. counter = 1
  288. summary_statistics <- readRDS(paste0(path,"bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1.ms.munged.Rds"))
  289. for (trait in traits){
  290. n_bhr_trait <- head(summary_statistics[summary_statistics$phenotype_key == trait,"N"],1)
  291. output <- BHR(mode = 'aggregate',
  292. ss_list_trait1 = ss_list, trait_list = list(trait),
  293. annotations = baseline_model,
  294. slope_correction = 4.55087151/n_bhr_trait)
  295. results_holder[counter,] <- c(trait,
  296. output$aggregated_mixed_model_h2,
  297. output$aggregated_mixed_model_h2se)
  298. print(paste0("Completed ",trait))
  299. counter = counter + 1
  300. }
  301. results_holder_df = as.data.frame(results_holder)
  302. results_holder_df[,2:3] <- sapply(results_holder_df[,2:3],as.numeric)
  303. colnames(results_holder_df) <- c("phenotype_key", "aggregated_h2", "aggregate_h2_se")
  304. results_holder_df = merge(results_holder_df, phenotype_file[c("phenotype_key", "display_name")], by = "phenotype_key")
  305. results_holder_df$ss_group = "g13_lof_mis"
  306. write.csv(results_holder_df, "~/rv_h2/outputs/bhr_output_aggregated_per_trait_h2_ldcorrection.csv")
  307. #Aggregate across all core traits
  308. source("~/rv_h2/BHR.R")
  309. source("~/rv_h2/BHR_h2.R")
  310. source("~/rv_h2/randomeffects_jackknife.R")
  311. source("~/rv_h2/BHR_meta.R")
  312. path = "/Users/daniel/Desktop/rare_h2/ms/genebass_summary_statistics_null/"
  313. phenotype_file <- read.csv("~/rv_h2/reference_files/ms_phenotype_sheet.csv")
  314. baseline_model <- read.table("~/rv_h2/reference_files/ms_baseline_oe5.txt")
  315. bhr_summary_statistic_names <- c("bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1",
  316. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low1e-05_high0.0001_group2",
  317. "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0.0001_high0.001_group3",
  318. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0_high1e-05_group1",
  319. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low1e-05_high0.0001_group2",
  320. "bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_low0.0001_high0.001_group3")
  321. #Aggregate h2 for each trait for g1-g3 (ultra-rare + rare)
  322. ss_list <- list(readRDS(paste0(path, bhr_summary_statistic_names[1],".ms.munged.Rds")),
  323. readRDS(paste0(path, bhr_summary_statistic_names[2],".ms.munged.Rds")),
  324. readRDS(paste0(path, bhr_summary_statistic_names[3],".ms.munged.Rds")),
  325. readRDS(paste0(path, bhr_summary_statistic_names[4],".ms.munged.Rds")),
  326. readRDS(paste0(path, bhr_summary_statistic_names[5],".ms.munged.Rds")),
  327. readRDS(paste0(path, bhr_summary_statistic_names[6],".ms.munged.Rds")))
  328. #remember to add slope line to meta for this
  329. results_holder <- matrix(data = NA, ncol = 3, nrow = 1)
  330. output <- BHR(mode = 'aggregate', ss_list_trait1 = ss_list,
  331. trait_list = phenotype_file[phenotype_file$phenotype_core == 1,"phenotype_key"],
  332. annotations = baseline_model)
  333. results_holder[1,] <- c("All_traits",
  334. output$aggregated_mixed_model_h2,
  335. output$aggregated_mixed_model_h2se)
  336. results_holder_df = as.data.frame(results_holder)
  337. results_holder_df[,2:3] <- sapply(results_holder_df[,2:3],as.numeric)
  338. colnames(results_holder_df) <- c("phenotype_key", "aggregated_h2", "aggregated_h2_se")
  339. write.csv(results_holder_df, "~/rv_h2/outputs/bhr_output_aggregated_all_traits_h2_ldcorrection.csv")
  340. ####Significant gene fractions
  341. phenotype_file <- read.csv("~/rv_h2/reference_files/ms_phenotype_sheet.csv")
  342. sig_genes = read.csv("~/rv_h2/reference_files/siggenes_for_AMM.csv")
  343. traits = phenotype_file[phenotype_file$phenotype_core == 1,"phenotype_key"]
  344. summary_statistics_plof_grp1 <- readRDS("~/Documents/oconnor_rotation/rarevariantproject/bhr_ms_gene_ss_400k_withnullburden_pLoF_nvar449780_low0_high1e-05_group1.ms.munged.Rds")
  345. baseline_model <- read.table("~/rv_h2/reference_files/ms_baseline_oe5.txt")
  346. consensus_genes <- read.table("~/rv_h2/reference_files/bhr_ms_consensus_gene_list.txt")[c("gene_id", "gene")]
  347. get_frac_assns <- function(trait){
  348. print(trait)
  349. trait_sumstats = summary_statistics_plof_grp1[summary_statistics_plof_grp1$phenotype_key == trait,]
  350. sig_genes_trait = sig_genes$gene[sig_genes$id == trait]
  351. print(length(sig_genes_trait))
  352. output = BHR(mode = "univariate",
  353. trait1_sumstats = trait_sumstats,
  354. annotations = list(baseline_model),
  355. fixed_genes = sig_genes_trait,
  356. gwc_exclusion = FALSE)
  357. trait_sumstats_sig = trait_sumstats[trait_sumstats$gene %in% sig_genes_trait,]
  358. trait_sig_df <- data.frame(phenotype_key = trait,
  359. gene = trait_sumstats_sig$gene,
  360. varexplained = trait_sumstats_sig$w_t_beta^2/trait_sumstats_sig$burden_score,
  361. bhr_h2 = output$mixed_model$heritabilities[1,ncol(output$mixed_model$heritabilities)],
  362. frac_sig = output$significant_genes$fraction_burdenh2_significant,
  363. frac_sig_se = output$significant_genes$fraction_burdenh2_significant_se)
  364. trait_sig_df$chisq = trait_sumstats$N[1]*trait_sig_df$varexplained
  365. thresh = qchisq(p = 0.05/nrow(trait_sumstats),df = 1,lower.tail = FALSE)
  366. trait_sig_df$chisq_winnerscursecorr = correct_winners_curse(trait_sig_df$chisq,thresh)
  367. trait_sig_df$varexplained_winnerscursecorr = trait_sig_df$chisq_winnerscursecorr/trait_sumstats$N[1]
  368. trait_sig_df$frac_sig_winnerscursecorr = sum(trait_sig_df$varexplained_winnerscursecorr)/trait_sig_df$bhr_h2[1]
  369. return(trait_sig_df)
  370. }
  371. sig_results <- lapply(traits[traits %in% sig_genes$id],get_frac_assns)
  372. sig_df = sig_results[[1]]
  373. for (trait in 2:length(sig_results)){
  374. print(trait)
  375. sig_df = rbind(sig_df,sig_results[[trait]])
  376. }
  377. sig_df$display_name = phenotype_file$display_name[match(sig_df$phenotype_key,phenotype_file$phenotype_key)]
  378. sig_df$proportion_bhr_explained = sig_df$varexplained_winnerscursecorr/sig_df$bhr_h2
  379. sig_df$labelgene = consensus_genes$gene[match(sig_df$gene,consensus_genes$gene_id)]
  380. ordered_sigdf = sig_df[order(sig_df$phenotype_key,-sig_df$varexplained_winnerscursecorr),]
  381. write.csv(ordered_sigdf, "~/rv_h2/outputs/BHR_Significant_Genes_Info.csv", quote = FALSE, row.names = FALSE)
  382. ####Significant gene fractions, common variant space
  383. variant_table <- fread2("~/Documents/oconnor_rotation/rarevariantproject/variants_MAFfilt_subsetcols.tsv", header = TRUE)
  384. sumstat_lookup <- read.csv("reference_files/sumstat_lookup.csv", header = FALSE)
  385. sigclump_df = data.frame()
  386. for (trait in 1:nrow(sumstat_lookup)){
  387. print(trait)
  388. print(sumstat_lookup$V21[trait])
  389. print("loading files")
  390. clumpfile = paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/significant_clump/clump_output/", strsplit(sumstat_lookup$V21[trait],split = ".bgz|.gz")[[1]],".plink.tsv_clump.clumped")
  391. gwas_file = paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/significant_clump/gwas_sumstats/",strsplit(sumstat_lookup$V10[trait],split = ".bgz|.gz")[[1]],"_lean")
  392. ldsc_file = paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/significant_clump/input_sumstats/",strsplit(sumstat_lookup$V7[trait],split = ".bgz|.gz")[[1]])
  393. clumps = read.table(clumpfile, header = TRUE)
  394. clumps = clumps[clumps$P < 5e-8,]
  395. gwas = fread2(gwas_file, header = FALSE)
  396. ldsc = read.table(ldsc_file, header = TRUE)
  397. names(gwas) <- c("variant","minor_AF","beta")
  398. print("extracting significant clumps variances")
  399. snps = clumps$SNP
  400. chrs = variant_table$chr[match(snps,variant_table$rsid)]
  401. bps = variant_table$pos[match(snps,variant_table$rsid)]
  402. refs = variant_table$ref[match(snps,variant_table$rsid)]
  403. alts = variant_table$alt[match(snps,variant_table$rsid)]
  404. identifiers = paste(chrs,bps,refs,alts,sep = ":")
  405. betas = gwas$beta[match(identifiers,gwas$variant)]
  406. mafs = gwas$minor_AF[match(identifiers,gwas$variant)]
  407. varexplained = (betas*(sqrt(2*mafs*(1 - mafs))))^2
  408. traitclumpdf <- data.frame(trait = sumstat_lookup$V21[trait],
  409. SNP = snps,
  410. varexplained = varexplained,
  411. N = ldsc$N[1])
  412. traitclumpdf = traitclumpdf[!is.na(traitclumpdf$varexplained),]
  413. traitclumpdf$chisq = traitclumpdf$varexplained * ldsc$N[1]
  414. thresh = qchisq(5e-8,1,lower.tail = FALSE)
  415. traitclumpdf$chisq_winnerscursecorr = correct_winners_curse(traitclumpdf$chisq,thresh)
  416. traitclumpdf$varexplained_winnerscursecorr = traitclumpdf$chisq_winnerscursecorr/ldsc$N[1]
  417. sigclump_df <- rbind(sigclump_df,traitclumpdf)
  418. }
  419. #aside: get Ns
  420. get_N <- function(trait){
  421. print(trait)
  422. print(sumstat_lookup$V21[trait])
  423. ldsc_file = paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/significant_clump/input_sumstats/",strsplit(sumstat_lookup$V7[trait],split = ".bgz|.gz")[[1]])
  424. ldsc = read.table(ldsc_file, header = TRUE)
  425. return(ldsc$N[1])
  426. }
  427. ldsc_h2 = read.csv("~/Documents/oconnor_rotation/rarevariantproject/rv_h2/ldsc_h2.csv")
  428. ldsc_h2$N = sapply(1:nrow(ldsc_h2), get_N)
  429. write.csv(ldsc_h2, "outputs//ldsc_h2.csv", row.names = FALSE, quote = FALSE)
  430. sigclump_df <- sigclump_df[sigclump_df$trait %in% phenotype_file$phenotype_key[phenotype_file$phenotype_core ==1],]
  431. sigclump_df <- sigclump_df[!is.na(sigclump_df$varexplained),]
  432. get_HESSh2 <- function(trait){
  433. print(trait)
  434. HESS_h2_result = read.table(paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/HESS/step2_output/", trait,"_HESSformat.tsv_step2.log_HESSh2"), sep = " ")
  435. return(as.numeric(HESS_h2_result$V5))
  436. }
  437. get_HESSh2_se <- function(trait){
  438. HESS_h2_result = read.table(paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/HESS/step2_output/", trait,"_HESSformat.tsv_step2.log_HESSh2"), sep = " ")
  439. return(parse_number(HESS_h2_result$V6))
  440. }
  441. sigclump_df$HESS_h2 = sapply(sigclump_df$trait,get_HESSh2)
  442. sigclump_df$HESS_h2_se = sapply(sigclump_df$trait,get_HESSh2_se)
  443. sigclump_df$fraction_HESS = sigclump_df$varexplained_winnerscursecorr/sigclump_df$HESS_h2
  444. sigclump_df_ordered = sigclump_df[order(sigclump_df$trait,-sigclump_df$varexplained_winnerscursecorr),]
  445. names(sigclump_df_ordered)[1] <- "phenotype_key"
  446. sigclump_df_ordered$fraction_HESS_sig = sapply(sigclump_df_ordered$phenotype_key,
  447. function(x) {
  448. return(sum(sigclump_df_ordered$varexplained_winnerscursecorr[sigclump_df_ordered$phenotype_key == x])/(sigclump_df_ordered$HESS_h2[sigclump_df_ordered$phenotype_key == x][1]))
  449. })
  450. write.csv(sigclump_df_ordered,"outputs/common_significant_associations.csv", quote = FALSE, row.names = FALSE)
  451. ####Significant gene fractions, common variant space (HESS partitions)
  452. HESS_df <- data.frame()
  453. for (trait in phenotype_file$phenotype_key[phenotype_file$phenotype_core == 1]){
  454. #print(trait)
  455. trait_hess_results <- read.table(paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/HESS/step2_output/",
  456. trait,
  457. "_HESSformat.tsv_step2.txt"),
  458. header = TRUE)
  459. trait_hess_results$trait = trait
  460. HESS_df = rbind(HESS_df,trait_hess_results)
  461. }
  462. write.csv(HESS_df,"outputs/HESS_output.csv", row.names = FALSE, quote = FALSE)
  463. ######################################## Genetic Correlation #############################
  464. #Read in results from cluster
  465. ldsc_rg_guide <- read.table("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/LDSC_rg/ldsc_rg_guide.tsv", sep = ":")
  466. get_ldsc_rg <- function(pair){
  467. input = read.table(paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/LDSC_rg/output/",pair,".txt"), sep = " ")
  468. return(as.numeric(input$V3[1]))
  469. }
  470. get_ldsc_rg_se <- function(pair){
  471. input = read.table(paste0("~/Documents/oconnor_rotation/rarevariantproject/final_commonvar_manuscript/LDSC_rg/output/",pair,".txt"), sep = " ")
  472. return(parse_number(input$V4[1]))
  473. }
  474. ldsc_rg_guide$ldsc_rg = sapply(1:nrow(ldsc_rg_guide), get_ldsc_rg)
  475. ldsc_rg_guide$ldsc_rg_se = sapply(1:nrow(ldsc_rg_guide), get_ldsc_rg_se)
  476. get_bhr_rg <- function(pair){
  477. print(pair)
  478. input = read.table(paste0("~/Documents/oconnor_rotation/rarevariantproject/BHR_rg_cluster/output/",pair,".txt"), header = TRUE)
  479. return(input$x[1])
  480. }
  481. get_bhr_rg_se <- function(pair){
  482. print(pair)
  483. input = read.table(paste0("~/Documents/oconnor_rotation/rarevariantproject/BHR_rg_cluster/output/",pair,".txt"), header = TRUE)
  484. return(input$x[2])
  485. }
  486. ldsc_rg_guide$bhr_rg = sapply(1:nrow(ldsc_rg_guide), get_bhr_rg)
  487. ldsc_rg_guide$bhr_rg_se = sapply(1:nrow(ldsc_rg_guide), get_bhr_rg_se)
  488. bhr_h2 = data.frame(googlesheets4::read_sheet("https://docs.google.com/spreadsheets/d/1AwvDRKEUJ6EtUbvnvSV34JkPV0Y7ozJHw-vDJOW2PpY/edit#gid=881218879", sheet = "bhr_h2"))
  489. bhr_h2_plofgrp1 =bhr_h2[bhr_h2$summary_statistic == "bhr_ms_gene_ss_400k_final_withnullburden_pLoF_low0_high1e-05_group1",]
  490. ldsc_rg_guide$bhr_h2_trait1 = bhr_h2_plofgrp1$bhr_h2[match(ldsc_rg_guide$V3,bhr_h2_plofgrp1$phenotype_key)]
  491. ldsc_rg_guide$bhr_h2_trait1_se = bhr_h2_plofgrp1$bhr_h2_se[match(ldsc_rg_guide$V3,bhr_h2_plofgrp1$phenotype_key)]
  492. ldsc_rg_guide$bhr_h2_trait2 = bhr_h2_plofgrp1$bhr_h2[match(ldsc_rg_guide$V6,bhr_h2_plofgrp1$phenotype_key)]
  493. ldsc_rg_guide$bhr_h2_trait2_se = bhr_h2_plofgrp1$bhr_h2_se[match(ldsc_rg_guide$V6,bhr_h2_plofgrp1$phenotype_key)]
  494. ldsc_rg_guide$trait1_bhrh2_z = ldsc_rg_guide$bhr_h2_trait1/ldsc_rg_guide$bhr_h2_trait1_se
  495. ldsc_rg_guide$trait2_bhrh2_z = ldsc_rg_guide$bhr_h2_trait2/ldsc_rg_guide$bhr_h2_trait2_se
  496. rg_output = ldsc_rg_guide[,c("V3","V6","ldsc_rg","ldsc_rg_se","bhr_rg","bhr_rg_se","trait1_bhrh2_z","trait2_bhrh2_z")]
  497. rg_output_sigbhrh2 = rg_output[abs(rg_output$trait1_bhrh2_z) > 1.96 & abs(rg_output$trait2_bhrh2_z) > 1.96,]
  498. names(rg_output_sigbhrh2) <- c("trait1","trait2","ldsc_rg","ldsc_rg_se","bhr_rg","bhr_rg_se")
  499. names(rg_output) <- c("trait1","trait2","ldsc_rg","ldsc_rg_se","bhr_rg","bhr_rg_se")
  500. write.csv(rg_output,"outputs/rg_output.csv", quote = FALSE, row.names = FALSE)
  501. #rg between missense and plof
  502. plof_sumstats = readRDS("~/Documents/oconnor_rotation/rarevariantproject/bhr_ms_gene_ss_400k_withnullburden_pLoF_nvar449780_low0_high1e-05_group1.ms.munged.Rds")
  503. missense_sumstats = readRDS("~/Documents/oconnor_rotation/rarevariantproject/bhr_ms_gene_ss_400k_final_withnullburden_missense-notbenign_nvar1590551_low0_high1e-05_group1.ms.munged.Rds")
  504. traits = phenotype_file$phenotype_key[phenotype_file$phenotype_core == 1]
  505. get_plof_missense_stats <- function(trait){
  506. plof_sumstats_trait = plof_sumstats[plof_sumstats$phenotype_key == trait,]
  507. missense_sumstats_trait = missense_sumstats[missense_sumstats$phenotype_key == trait,]
  508. bhr_plof = BHR_h2(plof_sumstats_trait,
  509. annotations = list(baseline_model),
  510. num_blocks = 100,
  511. genomewide_correction = FALSE,
  512. gwc_exclusion = NULL,
  513. overdispersion = FALSE,
  514. num_null_conditions = 0,
  515. output_jackknife_h2 = FALSE,
  516. fixed_genes = NULL,
  517. all_models = FALSE,
  518. slope_correction = FALSE )
  519. bhr_missense = BHR_h2(missense_sumstats_trait,
  520. annotations = list(baseline_model),
  521. num_blocks = 100,
  522. genomewide_correction = FALSE,
  523. gwc_exclusion = NULL,
  524. overdispersion = FALSE,
  525. num_null_conditions = 0,
  526. output_jackknife_h2 = FALSE,
  527. fixed_genes = NULL,
  528. all_models = FALSE,
  529. slope_correction = FALSE )
  530. if (bhr_plof$mixed_model$heritabilities[1,5] < 0 | bhr_missense$mixed_model$heritabilities[1,5] < 0 ){
  531. output = list(plof_h2 = bhr_plof$mixed_model$heritabilities[1,5],
  532. plof_h2_se = bhr_plof$mixed_model$heritabilities[2,5],
  533. missense_h2 = bhr_missense$mixed_model$heritabilities[1,5],
  534. missense_h2_se = bhr_missense$mixed_model$heritabilities[2,5],
  535. rg = NA,
  536. rg_se = NA)
  537. print(output)
  538. return(output)
  539. }
  540. bhr_rg_trait = BHR_rg(plof_sumstats_trait,
  541. missense_sumstats_trait,
  542. annotations = list(baseline_model),
  543. num_blocks = 100,
  544. genomewide_correction = FALSE,
  545. overdispersion = FALSE,
  546. num_null_conditions = 0,
  547. output_jackknife_rg = FALSE,
  548. fixed_genes = NULL)
  549. output = list(plof_h2 = bhr_plof$mixed_model$heritabilities[1,5],
  550. plof_h2_se = bhr_plof$mixed_model$heritabilities[2,5],
  551. missense_h2 = bhr_missense$mixed_model$heritabilities[1,5],
  552. missense_h2_se = bhr_missense$mixed_model$heritabilities[2,5],
  553. rg = bhr_rg_trait$rg$rg_mixed,
  554. rg_se = bhr_rg_trait$rg$rg_mixed_se)
  555. print(output)
  556. return(output)
  557. }
  558. plof_missense_compare_bhr <- sapply(traits, get_plof_missense_stats)
  559. names = rownames(plof_missense_compare_bhr)
  560. plof_missense_compare_bhr_df = as.data.frame(t(plof_missense_compare_bhr))
  561. plof_missense_compare_bhr_df = as.data.frame(sapply(1:ncol(plof_missense_compare_bhr_df), function(x) as.numeric(unlist(plof_missense_compare_bhr_df[,x]))))
  562. names(plof_missense_compare_bhr_df) <- names
  563. plof_missense_compare_bhr_df$display_name = phenotype_file$display_name[phenotype_file$phenotype_core ==1]
  564. write.csv(plof_missense_compare_bhr_df,"outputs/plof_missense_compare.csv", quote = FALSE, row.names = FALSE)
  565. ######################################## SCZ and BP #############################
  566. #BipEx
  567. #Read in the baseline model file
  568. library(pracma)
  569. library(tidyverse)
  570. library(readr)
  571. baseline_model <- read.table("~/Documents/oconnor_rotation/rarevariantproject/final_manuscript_repo/bhr/reference_files/ms_baseline_oe5.txt")
  572. #Read in the publicly available bipex variant table.
  573. bp_variantlevel_bipex <- bigreadr::fread2("~/Downloads/BipEx_variant_results.tsv")
  574. #Subset variants
  575. variant_filter = bp_variantlevel_bipex$group == "Bipolar Disorder" & #Filter to Bipolar Disorder counts
  576. bp_variantlevel_bipex$in_analysis == TRUE & #Use variant filter from Palmer et al, 2022
  577. !is.na(bp_variantlevel_bipex$gene_id) & #Remove variants with NA gene ID
  578. str_detect(bp_variantlevel_bipex$locus, "^chr\\d") #Subset to autosomal variants
  579. bp_variantlevel_bipex <- bp_variantlevel_bipex[variant_filter,
  580. c("gene_id",
  581. "consequence",
  582. "ac_case",
  583. "ac_ctrl",
  584. "locus",
  585. "mpc")]
  586. #Function to wrangle into BHR sumstats format
  587. wrangle_sumstats <- function(table,n_cases,n_controls, var_filter) {
  588. #Filter to variants of interest
  589. table = table[var_filter,]
  590. #Compute sample prevalence, will be used to compute per-sd beta
  591. prevalence = n_cases/(n_cases+n_controls)
  592. #Compute variant MAF in cases, will be used to compute per-sd beta
  593. table$AF_case = table$ac_case/(2*n_cases)
  594. #Compute variant MAFoverall, will be used to compute per-sd beta
  595. table$AF = (table$ac_case + table$ac_ctrl)/(2*(n_cases + n_controls))
  596. #calculate per-sd betas
  597. table$beta = (2 * (table$AF_case - table$AF) * prevalence)/sqrt(2 * table$AF * (1 - table$AF) * prevalence * (1 - prevalence))
  598. #calculate variant variances
  599. table$twopq = 2*table$AF * (1 - table$AF)
  600. #convert betas from per-sd (i.e. sqrt(variance explained)) to per-allele (i.e. in units of phenotype) betas.
  601. #per-allele are the usual betas reported by an exome wide association study.
  602. table$beta_perallele = table$beta/sqrt(table$twopq)
  603. #aggregate into gene-level table.
  604. sumstats = data.frame(gene = unique(table$gene_id))
  605. #each element of variant_variances is a list of variances for all variants in a gene.
  606. sumstats$variant_variances = lapply(sumstats$gene,
  607. function(x) table$twopq[table$gene_id == x])
  608. #each element of variant_variances is a list of per-allele betas for all variants in a gene.
  609. sumstats$betas = lapply(sumstats$gene,
  610. function(x) table$beta_perallele[table$gene_id == x])
  611. names(sumstats) <- c("gene", "variant_variances","betas")
  612. #add chromosome and position information
  613. #position doesn't need to be super precise, as it is only used to order genes for jackknife
  614. sumstats$gene_position <- parse_number(sapply(strsplit(table$locus[match(sumstats$gene,table$gene_id)], split = ":"), function(x) x[[2]]))
  615. sumstats$chromosome = parse_number(sapply(strsplit(table$locus[match(sumstats$gene,table$gene_id)], split = ":"), function(x) x[[1]]))
  616. #N = sum of case and control counts
  617. sumstats$N = n_cases + n_controls
  618. #we have found that in these smaller sample analyses, there are some genes with
  619. #large burden scores that are clearly outliers
  620. #we remove genes with burden scores more than 8 sd from the mean as a conservative filter.
  621. burdenscores = sapply(sumstats$variant_variances, function(x) sum(x))
  622. sumstats <- sumstats[abs(scale(burdenscores)) < 8,]
  623. return(sumstats)
  624. }
  625. bp_sumstats_ptv = wrangle_sumstats(bp_variantlevel_bipex,
  626. 14210, #N from Palmer et al, 2022
  627. 14422, #N from Palmer et al, 2022
  628. bp_variantlevel_bipex$consequence == "ptv")
  629. bp_sumstats_missenseMPC2 = wrangle_sumstats(bp_variantlevel_bipex[!is.na(bp_variantlevel_bipex$mpc),],
  630. 14210,
  631. 14422,
  632. bp_variantlevel_bipex$consequence[!is.na(bp_variantlevel_bipex$mpc)] %in% c("damaging_missense", "other_missense") &
  633. bp_variantlevel_bipex$mpc[!is.na(bp_variantlevel_bipex$mpc)] > 2)
  634. bp_sumstats_synonymous = wrangle_sumstats(bp_variantlevel_bipex,
  635. 14210,
  636. 14422,
  637. bp_variantlevel_bipex$consequence == "synonymous")
  638. #Run BHR
  639. bp_ptv_bhr <- bhr::BHR(bp_sumstats_ptv,
  640. annotations = list(baseline_model), #baseline model including constraint annotations
  641. num_blocks = 100, #number of blocks for jackknife
  642. num_null_conditions = 5, #5*num_genes null moment conditions
  643. mode = "univariate") #run in univariate mode to compute burden h2
  644. bp_missense_bhr <- bhr::BHR(bp_sumstats_missenseMPC2,
  645. annotations = list(baseline_model),
  646. num_blocks = 100,
  647. num_null_conditions = 5,
  648. mode = "univariate")
  649. bp_synonymous_bhr <- bhr::BHR(bp_sumstats_synonymous,
  650. annotations = list(baseline_model),
  651. num_blocks = 100,
  652. genomewide_correction = FALSE,
  653. num_null_conditions = 5,
  654. mode = "univariate")
  655. #convert observed scale to liability scale h2
  656. #calculate sample prevalence
  657. bp_sample_prevalence = 14210/(14210 + 14422)
  658. #this population prevalence estimate is from Ferrari et al, 2016 Bipolar Disorders
  659. population_prevalence_bp = 0.007
  660. obs2lia_factor <- function(K, P){
  661. X <- qnorm(K,lower.tail=FALSE)
  662. z <- (1/sqrt(2*pi))*(exp(-(X**2)/2))
  663. factor <- (K*(1-K)*K*(1-K))/(P*(1-P)*(z**2))
  664. return(factor)
  665. }
  666. bp_scalingfactor = obs2lia_factor(population_prevalence_bp,bp_sample_prevalence)
  667. #Burden heritability of schizophrenia
  668. #Read in table from SCHEMA website
  669. SCHEMA_variants <- bigreadr::fread2("~/Downloads/SCHEMA_variant_results.tsv",
  670. select = c("gene_id",
  671. "consequence",
  672. "ac_case",
  673. "ac_ctrl",
  674. "group",
  675. "locus",
  676. "in_analysis"))
  677. #Filter variants
  678. SCHEMA_variant_filter = (SCHEMA_variants$in_analysis | SCHEMA_variants$consequence == "synonymous_variant") & #Either filtered SCHEMA damaging variant, or synonymous
  679. SCHEMA_variants$group %in% c("EUR (exomes)","EUR (gnomAD exomes)","EUR-N (exomes)") & #In one of the primary EUR cohorts
  680. !is.na(SCHEMA_variants$gene_id) & #non-NA gene ID
  681. str_detect(SCHEMA_variants$locus, "X", negate = TRUE) & #autosomal
  682. str_detect(SCHEMA_variants$locus, "Y", negate = TRUE) #autosomal
  683. SCHEMA_variants = SCHEMA_variants[SCHEMA_variant_filter,]
  684. SCHEMA_variants = SCHEMA_variants[!is.na(SCHEMA_variants$ac_case),]
  685. #Aggregate variants into nextera and non-nextera variant tables
  686. EUR_Nextera <- SCHEMA_variants[SCHEMA_variants$group %in% c("EUR (exomes)","EUR (gnomAD exomes)"),]
  687. EUR_agg_Nextera <- aggregate(cbind(EUR_Nextera$ac_case,EUR_Nextera$ac_ctrl), by = list(EUR_Nextera$locus),FUN = sum)
  688. EUR_agg_Nextera <- EUR_agg_Nextera[EUR_agg_Nextera$V1 + EUR_agg_Nextera$V2 <= 5,]
  689. EUR_agg_Nextera$gene_id = EUR_Nextera$gene_id[match(EUR_agg_Nextera$Group.1,EUR_Nextera$locus)]
  690. EUR_agg_Nextera$consequence = EUR_Nextera$consequence[match(EUR_agg_Nextera$Group.1,EUR_Nextera$locus)]
  691. names(EUR_agg_Nextera) <- c("locus","ac_case","ac_ctrl","gene_id","consequence")
  692. EUR_NonNextera <- SCHEMA_variants[SCHEMA_variants$group %in% c("EUR-N (exomes)"),]
  693. EUR_agg_NonNextera <- aggregate(cbind(EUR_NonNextera$ac_case,EUR_NonNextera$ac_ctrl), by = list(EUR_NonNextera$locus),FUN = sum)
  694. EUR_agg_NonNextera <- EUR_agg_NonNextera[EUR_agg_NonNextera$V1 + EUR_agg_NonNextera$V2 <= 5,]
  695. EUR_agg_NonNextera$gene_id = EUR_NonNextera$gene_id[match(EUR_agg_NonNextera$Group.1,EUR_NonNextera$locus)]
  696. EUR_agg_NonNextera$consequence = EUR_NonNextera$consequence[match(EUR_agg_NonNextera$Group.1,EUR_NonNextera$locus)]
  697. names(EUR_agg_NonNextera) <- c("locus","ac_case","ac_ctrl","gene_id","consequence")
  698. #PTV wrangling
  699. scz_ptv_sumstats_Nextera <- wrangle_sumstats(EUR_agg_Nextera,
  700. 8874,
  701. 19074+23561,
  702. EUR_agg_Nextera$consequence %in% c("stop_gained",
  703. "frameshift_variant",
  704. "splice_acceptor_variant",
  705. "splice_donor_variant"))
  706. scz_ptv_sumstats_NonNextera <- wrangle_sumstats(EUR_agg_NonNextera,
  707. 7277,
  708. 11187,
  709. EUR_agg_NonNextera$consequence %in% c("stop_gained",
  710. "frameshift_variant",
  711. "splice_acceptor_variant",
  712. "splice_donor_variant"))
  713. #Missense wrangling
  714. scz_missenseMPC2_sumstats_Nextera <- wrangle_sumstats(EUR_agg_Nextera,
  715. 8874,
  716. 19074+23561,
  717. EUR_agg_Nextera$consequence %in% c("missense_variant_mpc_2-3",
  718. "missense_variant_mpc_>=3"))
  719. scz_missenseMPC2_sumstats_NonNextera <- wrangle_sumstats(EUR_agg_NonNextera,
  720. 7277,
  721. 11187,
  722. EUR_agg_NonNextera$consequence %in% c("missense_variant_mpc_2-3",
  723. "missense_variant_mpc_>=3"))
  724. #Synonymous wrangling
  725. scz_synonymous_sumstats_Nextera <- wrangle_sumstats(EUR_agg_Nextera,
  726. 8874,
  727. 19074+23561,
  728. EUR_agg_Nextera$consequence %in% c("synonymous_variant"))
  729. scz_synonymous_sumstats_NonNextera <- wrangle_sumstats(EUR_agg_NonNextera,
  730. 7277,
  731. 11187,
  732. EUR_agg_NonNextera$consequence %in% c("synonymous_variant"))
  733. #PTV BHR Models
  734. scz_ptv_bhr_Nextera <- bhr::BHR(scz_ptv_sumstats_Nextera,
  735. annotations = list(baseline_model),
  736. num_blocks = 100,
  737. mode = "univariate",
  738. output_jackknife_h2 = TRUE,
  739. all_models = TRUE)
  740. scz_ptv_bhr_NonNextera <- bhr::BHR(scz_ptv_sumstats_NonNextera,
  741. annotations = list(baseline_model),
  742. num_blocks = 100,
  743. mode = "univariate",
  744. output_jackknife_h2 = TRUE,
  745. all_models = TRUE)
  746. #Missense BHR Models
  747. scz_missenseMPC2_bhr_Nextera <- bhr::BHR(scz_missenseMPC2_sumstats_Nextera,
  748. annotations = list(baseline_model),
  749. num_blocks = 100,
  750. mode = "univariate",
  751. output_jackknife_h2 = TRUE,
  752. all_models = TRUE)
  753. scz_missenseMPC2_bhr_NonNextera <- bhr::BHR(scz_missenseMPC2_sumstats_NonNextera,
  754. annotations = list(baseline_model),
  755. num_blocks = 100,
  756. mode = "univariate",
  757. output_jackknife_h2 = TRUE,
  758. all_models = TRUE)
  759. #Synonymous BHR Models
  760. scz_synonymous_bhr_Nextera <- bhr::BHR(scz_synonymous_sumstats_Nextera,
  761. annotations = list(baseline_model),
  762. num_blocks = 100,
  763. mode = "univariate",
  764. output_jackknife_h2 = TRUE,
  765. all_models = TRUE)
  766. scz_synonymous_bhr_NonNextera <- bhr::BHR(scz_synonymous_sumstats_NonNextera,
  767. annotations = list(baseline_model),
  768. num_blocks = 100,
  769. mode = "univariate",
  770. output_jackknife_h2 = TRUE,
  771. all_models = TRUE)
  772. #Functions for meta-analysis
  773. get_metabeta <- function(betas, ses){
  774. we = 1 / (ses)^2
  775. return(sum(betas * we) / sum(we))
  776. }
  777. get_metase <- function(ses){
  778. we = 1 / (ses)^2
  779. return(sqrt(1/sum(we)))
  780. }
  781. #Function for meta-analyzing nextera and non-nextera samples, and extracting key parameters of interest
  782. SCZ_meta_analysis <- function(modelNextera,modelNonNextera,sumstatsNextera,sumstatsNonNextera, liability = TRUE){
  783. #calculate factor for conversion to liability scale.
  784. #Population prevalence is from Charlson et al, 2016, Schizophrenia Bulletin
  785. nextera_prevalence = 8874/(19074+23561+8874)
  786. nonnextera_prevalence = 7277/(11187+7277)
  787. population_prevalence = 0.0028
  788. obs2lia_factor <- function(K, P){
  789. X <- qnorm(K,lower.tail=FALSE)
  790. z <- (1/sqrt(2*pi))*(exp(-(X**2)/2))
  791. factor <- (K*(1-K)*K*(1-K))/(P*(1-P)*(z**2))
  792. return(factor)
  793. }
  794. nextera_scalingfactor = obs2lia_factor(population_prevalence,nextera_prevalence)
  795. nonnextera_scalingfactor = obs2lia_factor(population_prevalence,nonnextera_prevalence)
  796. #If observed scale desired, set scaling factor to 1
  797. if (liability == FALSE){
  798. nextera_scalingfactor = 1
  799. nonnextera_scalingfactor = 1
  800. }
  801. #extract heritability from constrained genes in nextera and non-nextera samples
  802. h2_constrained = c(modelNextera$mixed_model$heritabilities[1,1]*nextera_scalingfactor,
  803. modelNonNextera$mixed_model$heritabilities[1,1]*nonnextera_scalingfactor)
  804. h2_constrained_se = c(modelNextera$mixed_model$heritabilities[2,1]*nextera_scalingfactor,
  805. modelNonNextera$mixed_model$heritabilities[2,1]*nonnextera_scalingfactor)
  806. #extract overall heritability in nextera and non-nextera samples
  807. h2_all = c(modelNextera$mixed_model$heritabilities[1,5]*nextera_scalingfactor,
  808. modelNonNextera$mixed_model$heritabilities[1,5]*nonnextera_scalingfactor)
  809. h2_all_se = c(modelNextera$mixed_model$heritabilities[2,5]*nextera_scalingfactor,
  810. modelNonNextera$mixed_model$heritabilities[2,5]*nonnextera_scalingfactor)
  811. #meta-analyze constrained heritability ("numerator" of fraction explained by constrained genes)
  812. numerator = get_metabeta(h2_constrained,h2_constrained_se)
  813. numerator_se = get_metase(h2_constrained_se)
  814. #meta-analyze total heritability ("denominator" of fraction explained by constrained genes)
  815. denominator = get_metabeta(h2_all,h2_all_se)
  816. denominator_se = get_metase(h2_all_se)
  817. #get point estimate of fraction explained by constrained genes
  818. fraction = numerator/denominator
  819. #compute fraction of alleles in constrained annotation
  820. sumstatsNextera_annot = merge(sumstatsNextera, baseline_model, by.x = "gene", by.y = "gene")
  821. sumstatsNonNextera_annot = merge(sumstatsNonNextera, baseline_model, by.x = "gene", by.y = "gene")
  822. sumstatsNextera_annot$burden_score = sapply(sumstatsNextera_annot$variant_variances, function(x) sum(x))
  823. sumstatsNonNextera_annot$burden_score = sapply(sumstatsNonNextera_annot$variant_variances, function(x) sum(x))
  824. total_variants = sum(sumstatsNextera_annot$burden_score) + sum(sumstatsNonNextera_annot$burden_score)
  825. constrained_variants = sum(sumstatsNextera_annot$burden_score * sumstatsNextera_annot$baseline_oe1_total5) + sum(sumstatsNonNextera_annot$burden_score*sumstatsNonNextera_annot$baseline_oe1_total5)
  826. fraction_constrained_variants = constrained_variants/total_variants
  827. #compute constraint enrichment point estimate
  828. enrichment = fraction/fraction_constrained_variants
  829. #get SE of fraction with delta method
  830. #First, compute covariance matrix of (h2 total, h2 constrained), for nextera and non-nextera
  831. sigma = matrix(data = NA, nrow = 2,ncol = 2)
  832. sigma[1,1] = numerator_se^2
  833. sigma[2,2] = denominator_se^2
  834. #jackknife variances of h2 constrained and h2 total, and jackknfie covariance between h2 constrained and h2 total
  835. Nextera_constrained_jackknife = modelNextera$subthreshold_genes$jackknife_h2[1,]*nextera_scalingfactor
  836. Nextera_total_jackknife = modelNextera$subthreshold_genes$jackknife_h2[5,]*nextera_scalingfactor
  837. variance_constrained_Nextera = ((length(Nextera_constrained_jackknife) -1)/length(Nextera_constrained_jackknife))*sum((Nextera_constrained_jackknife - mean(Nextera_constrained_jackknife))^2)
  838. variance_total_Nextera = ((length(Nextera_total_jackknife) -1)/length(Nextera_total_jackknife))*sum((Nextera_total_jackknife - mean(Nextera_total_jackknife))^2)
  839. covariance_Nextera_jackknife = ((length(Nextera_constrained_jackknife) -1)/length(Nextera_constrained_jackknife)) * sum((Nextera_constrained_jackknife - mean(Nextera_constrained_jackknife))*(Nextera_total_jackknife - mean(Nextera_total_jackknife)))
  840. sigma_nextera = matrix(data = NA, nrow = 2,ncol = 2)
  841. sigma_nextera[1,1] = variance_constrained_Nextera
  842. sigma_nextera[2,2] = variance_total_Nextera
  843. sigma_nextera[1,2] = covariance_Nextera_jackknife
  844. sigma_nextera[2,1] = covariance_Nextera_jackknife
  845. NonNextera_constrained_jackknife = modelNonNextera$subthreshold_genes$jackknife_h2[1,]*nonnextera_scalingfactor
  846. NonNextera_total_jackknife = modelNonNextera$subthreshold_genes$jackknife_h2[5,]*nonnextera_scalingfactor
  847. variance_constrained_NonNextera = ((length(NonNextera_constrained_jackknife) -1)/length(NonNextera_constrained_jackknife))*sum((NonNextera_constrained_jackknife - mean(NonNextera_constrained_jackknife))^2)
  848. variance_total_NonNextera = ((length(NonNextera_total_jackknife) -1)/length(NonNextera_total_jackknife))*sum((NonNextera_total_jackknife - mean(NonNextera_total_jackknife))^2)
  849. covariance_NonNextera_jackknife = ((length(NonNextera_constrained_jackknife) -1)/length(NonNextera_constrained_jackknife)) * sum((NonNextera_constrained_jackknife - mean(NonNextera_constrained_jackknife))*(NonNextera_total_jackknife - mean(NonNextera_total_jackknife)))
  850. sigma_NonNextera = matrix(data = NA, nrow = 2,ncol = 2)
  851. sigma_NonNextera[1,1] = variance_constrained_NonNextera
  852. sigma_NonNextera[2,2] = variance_total_NonNextera
  853. sigma_NonNextera[1,2] = covariance_NonNextera_jackknife
  854. sigma_NonNextera[2,1] = covariance_NonNextera_jackknife
  855. #meta-analyze covariance matrices
  856. sigma_meta = pracma::inv(pracma::inv(sigma_nextera) + pracma::inv(sigma_NonNextera))
  857. #get gradient
  858. dg_dh2c = 1/denominator
  859. dg_dh2all = (-numerator)/(denominator^2)
  860. fraction_gradient = matrix(c(dg_dh2c,dg_dh2all), ncol = 1)
  861. #compute variance of fraction of heritability explained by constrained genes
  862. fraction_se = sqrt(t(fraction_gradient) %*% sigma_meta %*% fraction_gradient)
  863. #convert fraction to enrichment
  864. enrichment_se = fraction_se/fraction_constrained_variants
  865. return(list(bhr_h2 = denominator,
  866. bhr_h2_se = denominator_se,
  867. fraction_constrained = fraction,
  868. fraction_se = fraction_se,
  869. enrichment_constrained = enrichment,
  870. enrichment_constrained_se = enrichment_se))
  871. }
  872. scz_ptv_bhr_output = SCZ_meta_analysis(scz_ptv_bhr_Nextera,
  873. scz_ptv_bhr_NonNextera,
  874. scz_ptv_sumstats_Nextera,
  875. scz_ptv_sumstats_NonNextera)
  876. scz_missense_bhr_output = SCZ_meta_analysis(scz_missenseMPC2_bhr_Nextera,
  877. scz_missenseMPC2_bhr_NonNextera,
  878. scz_missenseMPC2_sumstats_Nextera,
  879. scz_missenseMPC2_sumstats_NonNextera)
  880. scz_synonymous_bhr_output = SCZ_meta_analysis(scz_synonymous_bhr_Nextera,
  881. scz_synonymous_bhr_NonNextera,
  882. scz_synonymous_sumstats_Nextera,
  883. scz_synonymous_sumstats_NonNextera)
  884. #Gather output
  885. output_df_SCZBP <- data.frame(dx =c(rep("SCZ",3),rep("BP",3)),
  886. class = c(c("pLoF","Missense (MPC >2)", "Syn"),c("pLoF","Missense (MPC >2)", "Syn")),
  887. bhr_h2 = c(scz_ptv_bhr_output$bhr_h2,
  888. scz_missense_bhr_output$bhr_h2,
  889. scz_synonymous_bhr_output$bhr_h2,
  890. bp_ptv_bhr$mixed_model$heritabilities[1,5]*bp_scalingfactor,
  891. bp_missense_bhr$mixed_model$heritabilities[1,5]*bp_scalingfactor,
  892. bp_synonymous_bhr$mixed_model$heritabilities[1,5]*bp_scalingfactor),
  893. bhr_h2_se = c(scz_ptv_bhr_output$bhr_h2_se,
  894. scz_missense_bhr_output$bhr_h2_se,
  895. scz_synonymous_bhr_output$bhr_h2_se,
  896. bp_ptv_bhr$mixed_model$heritabilities[2,5]*bp_scalingfactor,
  897. bp_missense_bhr$mixed_model$heritabilities[2,5]*bp_scalingfactor,
  898. bp_synonymous_bhr$mixed_model$heritabilities[2,5]*bp_scalingfactor),
  899. fraction_constrained = c(scz_ptv_bhr_output$fraction_constrained,
  900. scz_missense_bhr_output$fraction_constrained,
  901. scz_synonymous_bhr_output$fraction_constrained,
  902. bp_ptv_bhr$mixed_model$fractions[1,1],
  903. bp_missense_bhr$mixed_model$fractions[1,1],
  904. bp_synonymous_bhr$mixed_model$fractions[1,1]),
  905. fraction_constrained_se = c(scz_ptv_bhr_output$fraction_constrained_se,
  906. scz_missense_bhr_output$fraction_constrained_se,
  907. scz_synonymous_bhr_output$fraction_constrained_se,
  908. bp_ptv_bhr$mixed_model$fractions[2,1],
  909. bp_missense_bhr$mixed_model$fractions[2,1],
  910. bp_synonymous_bhr$mixed_model$fractions[2,1]),
  911. enrichment_constrained = c(scz_ptv_bhr_output$enrichment_constrained,
  912. scz_missense_bhr_output$enrichment_constrained,
  913. scz_synonymous_bhr_output$enrichment_constrained,
  914. bp_ptv_bhr$mixed_model$enrichments[1,1],
  915. bp_missense_bhr$mixed_model$enrichments[1,1],
  916. bp_synonymous_bhr$mixed_model$enrichments[1,1]),
  917. enrichment_constrained_se = c(scz_ptv_bhr_output$enrichment_constrained_se,
  918. scz_missense_bhr_output$enrichment_constrained_se,
  919. scz_synonymous_bhr_output$enrichment_constrained_se,
  920. bp_ptv_bhr$mixed_model$enrichments[2,1],
  921. bp_missense_bhr$mixed_model$enrichments[2,1],
  922. bp_synonymous_bhr$mixed_model$enrichments[2,1]))
  923. #fractions of SCZ h2 explained by sig genes
  924. #Load in gnomad information to match gene ids to gene names
  925. gnomad_information <- data.frame(data.table::fread("~/Documents/oconnor_rotation/rarevariantproject/final_manuscript_repo/rv_h2/reference_files/gnomad.v2.1.1.lof_metrics.by_gene.txt",
  926. select = c("gene","gene_id", "chromosome", "start_position", "end_position", "pLI")))
  927. gnomad_information = gnomad_information[gnomad_information$chromosome != "X",]
  928. gnomad_information = gnomad_information[gnomad_information$chromosome != "Y",]
  929. gnomad_information_counts = data.frame(table(gnomad_information$gene))
  930. gnomad_information_counts = gnomad_information_counts[gnomad_information_counts$Freq == 1,]
  931. gene_information <- gnomad_information[gnomad_information$gene %in% gnomad_information_counts$Var1,]
  932. gene_information$midpoint <- (gene_information$start_position + gene_information$end_position)/2
  933. #9 autosomal SCHEMA genes
  934. SCHEMAgenes = c("SETD1A", "CUL1", "XPO7","TRIO","CACNA1G","SP4","GRIA3","GRIN2A","HERC1","RB1CC1")
  935. SCHEMAgenes_id = gene_information$gene_id[match(SCHEMAgenes,gene_information$gene)]
  936. SCHEMAgenes_id = SCHEMAgenes_id[!is.na(SCHEMAgenes_id)]
  937. #Run BHR with SCHEMA significant genes as fixed effects.
  938. nextera_model_SCHEMA = bhr::BHR(scz_ptv_sumstats_Nextera,
  939. annotations = list(baseline_model),
  940. fixed_genes =SCHEMAgenes_id,
  941. num_blocks = 100,
  942. mode = "univariate")
  943. nonnextera_model_SCHEMA = bhr::BHR(scz_ptv_sumstats_NonNextera,
  944. annotations = list(baseline_model),
  945. fixed_genes =SCHEMAgenes_id,
  946. num_blocks = 100,
  947. mode = "univariate")
  948. #Meta analyze fraction of heritability explained by sig genes
  949. meta_frac_SCHEMA = get_metabeta(c(nextera_model_SCHEMA$significant_genes$fraction_burdenh2_significant,
  950. nonnextera_model_SCHEMA$significant_genes$fraction_burdenh2_significant),
  951. c(nextera_model_SCHEMA$significant_genes$fraction_burdenh2_significant_se,
  952. nonnextera_model_SCHEMA$significant_genes$fraction_burdenh2_significant_se))
  953. meta_frac_SCHEMA_se = get_metase(c(nextera_model_SCHEMA$significant_genes$fraction_burdenh2_significant_se,
  954. nonnextera_model_SCHEMA$significant_genes$fraction_burdenh2_significant_se))
  955. #rg between scz and bp
  956. nextera_bp_rg = bhr::BHR(mode = "bivariate",
  957. trait1_sumstats = scz_ptv_sumstats_Nextera,
  958. trait2_sumstats = bp_sumstats_ptv,
  959. annotations = list(baseline_model),
  960. num_blocks = 100)
  961. nonnextera_bp_rg = bhr::BHR(mode = "bivariate",
  962. trait1_sumstats = scz_ptv_sumstats_NonNextera,
  963. trait2_sumstats = bp_sumstats_ptv,
  964. annotations = list(baseline_model),
  965. num_blocks = 100)
  966. write.csv(output_df_SCZBP,"~/Documents/SCZ_BP_output.csv", quote = FALSE, row.names = FALSE)

run_BHR.R at commit 108e9c8, under MIT · at the source

Overview

Authors: Hanna Abe1, Calwing Liao2,3,4, Lide Han5, Theodore Morley5, Michael E Talkowski2,3,4, Kristen J Brennand6, Douglas M Ruderfer5,7
  1. Vanderbilt University, Vanderbilt Genetics Institute, Nashville, TN USA
  2. Analytic and Translational Genetics Unit, Department of Medicine, Massachusetts General Hospital, Boston, MA USA
  3. Stanley Center for Psychiatric Research, Broad Institute of MIT and Harvard, Cambridge, MA USA
  4. Center for Genomic Medicine, Massachusetts General Hospital, Boston, MA USA
  5. Division of Genetic Medicine, Department of Medicine, Vanderbilt University Medical Center, Nashville, TN USA
  6. Departments of Psychiatry and Genetics, Division of Molecular Psychiatry, Department of Genetics, Wu Tsai Institute, Yale University School of Medicine, New Haven, CT USA
  7. Department of Biomedical Informatics and Psychiatry and Behavioral Sciences, Vanderbilt University Medical Center, Nashville, TN USA
Institutions: Vanderbilt University (United States); Broad Institute (United States); Massachusetts General Hospital (United States); Stanley Center for Psychiatric Research; Vanderbilt University Medical Center (United States); Yale University (United States)
Journal: Molecular psychiatry, volume 31, issue 8, pages 4787-4798
Dates: received 26 August 2025; accepted 16 March 2026; published online 7 April 2026; in print 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41380-026-03571-x · PMID 41946833 · PMCID PMC13364661 · OpenAlex W4413379657
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: genetics / omics (modality), human (organism), cellular / molecular (subfield)
Methods: Statistics, Machine learning, Preprocessing, Connectivity
Keywords: Genetics, Psychiatric disorders
MeSH: Mental Disorders*, Brain, Gene Expression Profiling, Genetic Predisposition to Disease, Genetic Variation, Genome-Wide Association Study, Humans, Neurodegenerative Diseases, Polymorphism, Single Nucleotide, Transcriptome (* major topic)
Topic: Genetic Associations and Epidemiology (Genetics, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: U.S. Department of Health & Human Services | NIH | National Institute of Mental Health (NIMH) (R01MH123155); U.S. Department of Health &amp; Human Services | NIH | National Institute of Mental Health (R01MH123155); NIMH NIH HHS (R01 MH123155)
Citations: not cited yet (Europe PMC); 53 references in the paper

Abstract

Genome-wide association studies (GWAS) and large-scale rare variant burden analyses have identified both common and rare loss-of-function variants associated with neuropsychiatric and neurodegenerative disorders. Yet, the shared biological processes influenced by both classes of variation remain poorly characterized. In this study, we utilized transcriptomic data from 933 post-mortem brain samples to identify genes that show convergent coexpression with GWAS and rare variant burden risk genes across six brain disorders. Despite largely distinct sets of significant risk genes from GWAS and rare variant burden studies, we found a significant overlap in their convergently coexpressed genes. These convergent genes showed enrichment for common and rare variant heritability and highlighted key biological pathways and cell-type markers impacted by both types of genetic variation. Compared to genes coexpressed with one variant class, shared convergent genes exhibited stronger evolutionary constraint and greater enrichment for known drug targets, underscoring their potential therapeutic relevance. Collectively, our results establish a systematic and generalizable framework for integrating coexpression data with genetic risk to reveal transcriptional programs supported by both common and rare variant evidence, offering mechanistic insights into neuropsychiatric diseases.

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

Repositories

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

FinucaneLab/gene_features

License: GPL-3.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 41d006d5c0e9cbdb8dfafdf0ee821f165e5e708c, 19 May 2022
Languages: R (80), Shell (1)
Size: 1,381 files, 81 scripts
Software Heritage: not archived
Found in: the text, “Gene prioritization from GWAS and rare variant b”
Holds: README, license file, environment (code/install.R)
Not found: CITATION.cff, tests, continuous integration, documentation
Tools: tidyverse (80 files), data.table (79 files), Seurat (79 files), reticulate (77 files), Harmony (2 files), Monocle 3 (1 file), reshape2 (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
83 files

ajaynadig/bhr

License: MIT
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 108e9c897d1b7da2a6b0bace9f63e54da55e25a0, 19 June 2026
Languages: MATLAB (13), R (10), Python (1)
Size: 37 files, 24 scripts
Software Heritage: archived
Found in: “Code availability”
Holds: README, license file, environment (DESCRIPTION), tests, 1 notebook
Not found: CITATION.cff, continuous integration, documentation
Tools: tidyverse (4 files), data.table (2 files), Statistics and Machine Learning Toolbox (2 files), ggplot2 (1 file), patchwork (1 file), reshape2 (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
26 files

FinucaneLab/pops

License: GPL-3.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 76eb86cba10254490003c8f4dc7ff5ce492d3667, 21 July 2025
Languages: Python (2)
Size: 25 files, 2 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, environment (requirements.txt)
Not found: CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (2 files), pandas (2 files), scikit-learn (1 file), SciPy (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
4 files

hakyimlab/MetaXcan

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: e069063a10539fe92adadb645fc667a40c2cf885, 8 September 2026
Languages: Python (118), R (2), Shell (2)
Size: 318 files, 122 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, environment (software/conda_env.yaml, software/requirements.txt, software/setup.cfg, software/setup.py), tests, documentation, 1 notebook
Not found: CITATION.cff, continuous integration
Tools: NumPy (52 files), pandas (40 files), SciPy (7 files), h5py (4 files), statsmodels (4 files)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
124 files

RuderferLab/coexpression_convergence

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: 8e847ffc072415891ecd6f5178c3f982836c65b5, 21 July 2022
Languages: R (2)
Size: 5 files, 2 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: data.table (1 file), tidyverse (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
3 files

bulik/ldsc

License: GPL-3.0
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Commit: 2fdeeb3b44379408794154993dbd6101b8946b7e, 16 January 2026
Languages: Python (19), MATLAB (4), Perl (1), R (1)
Size: 1,093 files, 25 scripts
Software Heritage: archived
Found in: “Code availability”
Holds: README, license file, environment (environment.yml, requirements.txt, setup.py), tests
Not found: CITATION.cff, continuous integration, documentation
Tools: NumPy (18 files), pandas (11 files), SciPy (5 files), BEDTools (2 files)
Availability: 1 check, the latest on 26 September 2026: the link answers
  • 26 September 2026: the link answers
27 files
At the source: github.com/bulik/ldsc

YuLab-SMU/clusterProfiler

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: d10e74853722ca5f3fb3a0c3466c4649e0fedada, 26 September 2026
Languages: R (59), Quarto (1)
Size: 163 files, 60 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, environment (DESCRIPTION), tests, continuous integration, documentation, 3 notebooks
Not found: license file, CITATION.cff
Tools: clusterProfiler (9 files), tidyverse (8 files), igraph (3 files), ggplot2 (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
61 files

Code availability

For gene prioritization: MAGMA (https://cncr.nl/research/magma), Polygenic priority score (PoPs, https://github.com/FinucaneLab/pops), TWAS-SPrediXcan (https://github.com/hakyimlab/MetaXcan) For convergent coexpression analysis (https://github.com/RuderferLab/coexpression_convergence). For SNP and rare variant heritability estimation: SLDSC (https://github.com/bulik/ldsc), BHR (https://github.com/ajaynadig/bhr). For gene ontology and other functional enrichment analysis: enrichr (https://maayanlab.cloud/Enrichr), ClusterProfiler (https://github.com/YuLab-SMU/clusterProfiler), rrvgo (10.18129/B9.bioc.rrvgo), and SMR (https://yanglab.westlake.edu.cn/software/smr).

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:

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

GWAS summary statistics data from Psychiatric genomics consortium (PGC) : (https://pgc.unc.edu/for-researchers/download-results). Exome burden summary: (https://schema.broadinstitute.org). Postmortem transcriptome data can be accessed from: CMC (10.7303/syn22000731.1), GTEx brain tissues (https://www.gtexportal.org/). The Open Targets Platform (https://platform.opentargets.org). SMR database (https://cnsgenomics.com/software/smr/#DataResource).

For gene prioritization: MAGMA (https://cncr.nl/research/magma), Polygenic priority score (PoPs, https://github.com/FinucaneLab/pops), TWAS-SPrediXcan (https://github.com/hakyimlab/MetaXcan) For convergent coexpression analysis (https://github.com/RuderferLab/coexpression_convergence). For SNP and rare variant heritability estimation: SLDSC (https://github.com/bulik/ldsc), BHR (https://github.com/ajaynadig/bhr). For gene ontology and other functional enrichment analysis: enrichr (https://maayanlab.cloud/Enrichr), ClusterProfiler (https://github.com/YuLab-SMU/clusterProfiler), rrvgo (10.18129/B9.bioc.rrvgo), and SMR (https://yanglab.westlake.edu.cn/software/smr).

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

Versions

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

Version 1, 29 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 7 authors, 2 keywords, 10 MeSH terms, 3 funders, 53 references.

Cite

This paper

Abe, H., Liao, C., Han, L., Morley, T., Talkowski, M. E., Brennand, K. J., & Ruderfer, D. M. (2026). Convergent coexpression reveals shared biological mechanisms underlying common and rare variant risk in six neuropsychiatric disorders. Molecular psychiatry, 31(8), 4787-4798. https://doi.org/10.1038/s41380-026-03571-x

BibTeX

@article{abe2026convergent,
author = {Abe, Hanna and Liao, Calwing and Han, Lide and Morley, Theodore and Talkowski, Michael E and Brennand, Kristen J and Ruderfer, Douglas M},
title = {{Convergent coexpression reveals shared biological mechanisms underlying common and rare variant risk in six neuropsychiatric disorders}},
journal = {Molecular psychiatry},
year = {2026},
month = apr,
volume = {31},
number = {8},
pages = {4787--4798},
publisher = {Springer Nature},
issn = {1359-4184},
doi = {10.1038/s41380-026-03571-x},
url = {https://doi.org/10.1038/s41380-026-03571-x},
pmid = {41946833},
pmcid = {PMC13364661}
}

RIS

TY - JOUR
AU - Abe, Hanna
AU - Liao, Calwing
AU - Han, Lide
AU - Morley, Theodore
AU - Talkowski, Michael E
AU - Brennand, Kristen J
AU - Ruderfer, Douglas M
TI - Convergent coexpression reveals shared biological mechanisms underlying common and rare variant risk in six neuropsychiatric disorders
T2 - Molecular psychiatry
J2 - Mol Psychiatry
PY - 2026
DA - 2026/04/07
VL - 31
IS - 8
SP - 4787
EP - 4798
SN - 1359-4184
PB - Springer Nature
DO - 10.1038/s41380-026-03571-x
UR - https://doi.org/10.1038/s41380-026-03571-x
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41380-026-03571-x",
"type": "article-journal",
"title": "Convergent coexpression reveals shared biological mechanisms underlying common and rare variant risk in six neuropsychiatric disorders",
"container-title": "Molecular psychiatry",
"author": [
{
"family": "Abe",
"given": "Hanna"
},
{
"family": "Liao",
"given": "Calwing"
},
{
"family": "Han",
"given": "Lide"
},
{
"family": "Morley",
"given": "Theodore"
},
{
"family": "Talkowski",
"given": "Michael E"
},
{
"family": "Brennand",
"given": "Kristen J"
},
{
"family": "Ruderfer",
"given": "Douglas M"
}
],
"container-title-short": "Mol Psychiatry",
"volume": "31",
"issue": "8",
"page": "4787-4798",
"DOI": "10.1038/s41380-026-03571-x",
"PMID": "41946833",
"PMCID": "PMC13364661",
"ISSN": "1359-4184",
"publisher": "Springer Nature",
"URL": "https://doi.org/10.1038/s41380-026-03571-x",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
7
]
]
}
}

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-026-75193-4 [code]
Multi-ancestry gene expression models amplify transcriptome-wide association study discovery and validation.
Journal: Nature communications
In common: Monocle 3, igraph, Seurat, 10 other tools, genetics / omics, cellular / molecular, 5 references
[2] doi:10.1038/s41593-026-02247-7 [code]
Transcriptomic and phenotypic convergence of neurodevelopmental disorder risk genes in vitro and in vivo.
Journal: Nature neuroscience
In common: Statistics and Machine Learning Toolbox, genetics / omics, cellular / molecular, 12 references, author Kristen J. Brennand
[3] doi:10.1038/s41588-026-02646-3 [code]
Co-expression-based models improve eQTL predictions for transcriptome-wide association studies and highlight new schizophrenia-associated genes.
Journal: Nature genetics
In common: reshape2, h5py, data.table, 5 other tools, genetics / omics, cellular / molecular, 11 references
[4] doi:10.1186/s12967-026-08266-z [code]
Single-cell multi-omic integration analysis prioritizes druggable genes and reveals cell-type-specific causal effects in glioblastomagenesis.
Journal: Journal of translational medicine
In common: Monocle 3, reticulate, igraph, 7 other tools, genetics / omics, cellular / molecular, 5 references
[5] doi:10.1038/s44318-026-00818-9 [code]
FAM134B-mediated ER-phagy degrades APP and suppresses Alzheimer's disease pathology.
Journal: The EMBO journal
In common: Monocle 3, BEDTools, Harmony, 13 other tools, cellular / molecular
[6] doi:10.1038/s41467-026-71542-5 [code]
Astrocyte fatty acid metabolism as a driver of risk for major depressive disorder.
Journal: Nature communications
In common: igraph, Seurat, reshape2, 4 other tools, genetics / omics, cellular / molecular, 10 references
[7] doi:10.1038/s41467-026-76675-1 [code]
Long-read proteogenomic atlas of human neuronal differentiation reveals isoform diversity informing neurodevelopmental risk mechanisms.
Journal: Nature communications
In common: Monocle 3, BEDTools, reticulate, 12 other tools, genetics / omics, 1 reference
[8] 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: Monocle 3, Harmony, igraph, 12 other tools, genetics / omics, cellular / molecular, 1 reference
[9] doi:10.1038/s41467-026-76676-0 [code]
Determinants of functional burden pleiotropy and gene dosage responses across human traits.
Journal: Nature communications
In common: igraph, reshape2, data.table, 8 other tools, genetics / omics, cellular / molecular, 5 references
[10] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: Monocle 3, reticulate, igraph, 13 other tools, cellular / molecular

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.