Multi-ancestry gene expression models amplify transcriptome-wide association study discovery and validation.
The 11 matches
- [1] § Results › Gene-level TWAS associations demonstrate high correlation of effect sizes across ancestries ↔ PGC_master_analysis2.Rmd, lines 1703–1836 · score 0.81 · G2S African American, Puerto Rican, Mexican American, gene unique, gene association, training model
- [2] § Results › Gene-level TWAS associations demonstrate high correlation of effect sizes across ancestries ↔ Code.zip/SNP_analysis_p2_zsc.r, lines 826–900 · score 0.73 · G2S African American, Puerto Rican, Mexican American, training model, ZSC, bars
- [3] § Methods › Gene expression models ↔ PGC_master_analysis2.Rmd, lines 1839–1934 · score 0.72 · Puerto Rican, Mexican American, African American, training model, Latino, PR
- [4] § Results › Parallel ancestry-concordant TWAS recapitulate high correlations in effect size estimates ↔ Code.zip/SNP_analysis_zscore.r, lines 72–141 · score 0.69 · multi ancestry, GReX, shared genes, SNP weight, GTEx models, blood
- [5] § Results › Parallel ancestry-concordant TWAS recapitulate high correlations in effect size estimates ↔ Code.zip/SNP_analysis_p2_zsc.r, lines 826–900 · score 0.68 · median weight, Puerto Rican, Mexican American, African American, bars, PR
- [6] § Methods › Linkage disequilibrium comparison of cross-model genes ↔ PGC_master_analysis2.Rmd, lines 2621–2716 · score 0.67 · linkage disequilibrium, ASW, GBR, MXL, PUR, YRI
- [7] § Results › A majority of TWAS findings derive from admixed models ↔ PGC_master_analysis2.Rmd, lines 3699–3731 · score 0.62 · Puerto Rican, African American, wide FDR, Mexican, BD1, PTSD
- [8] § Methods › Evaluation of genetic ancestry as a determinant of model specificity ↔ PGC_master_analysis2.Rmd, lines 3435–3502 · score 0.54 · MAF weighted, allele frequencies, composition, SNP predictor, aggregate, GTEx
- [9] § Results › Broad differences exist across prediction models ↔ PGC_master_analysis2.Rmd, lines 1256–1311 · score 0.54 · shared_overlapping, shared_distinct, SNP predictor, PGC, correlation, GTEx
- [10] § Methods › Cross-model SNP feature comparison ↔ Code.zip/SNP_analysis_zscore.r, lines 404–465 · score 0.52 · shared_overlapping, shared_distinct, zscore, correlation, disease, SNP
- [11] § Methods › Cross-model SNP feature comparison ↔ PGC_master_analysis2.Rmd, lines 1256–1311 · score 0.51 · shared_overlapping, shared_distinct, zscore, correlation, SNP, GTEx
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
R Markdown · 3,731 lines · 139 KB · CC-BY-4.0 · 7 matches
- ---
- title: "PGC_multi_ancestry_analysis"
- author: "Xavier Bledsoe"
- date: "4/30/2025"
- output:
- html_document:
- code_folding: show
- toc: true
- toc_float: true
- number_sections: true
- ---
- ```{r setup, include=FALSE}
- knitr::opts_chunk$set(echo = TRUE, collapse = TRUE)
- library(data.table)
- library(stringr)
- library(ggplot2)
- library(ggrepel)
- library(viridis)
- library(pheatmap)
- library(RColorBrewer)
- library(ggpubr)
- #library(kableExtra)
- library(data.table)
- library(dplyr)
- library(ggrepel)
- library(stringr)
- library(colorspace)
- library(data.table)
- library(ggplot2)
- library(pals)
- library(stringr)
- library(gridExtra)
- library(grid)
- library(ggstance)
- library(viridis)
- library(ggpointdensity)
- library(ggh4x)
- library(forcats)
- ```
- # PGC TWAS analysis
- ## TWAS descriptive statistics
- ### Fig 1a: Nashville Plots of TWAS Data
- For all 6 GWAS from the PGC consortium, we want to visualize the distribution of
- TWAS results across the GALA II/SAGE (G2S) and GTEx whole blood results.
- ```{r fig.height=8, fig.width = 15}
- dt_ <- fread('Data/all_exc_assocs_PGCancestryTWAS.txt', header = TRUE)
- # exclude replication/comparison data from initial analysis.
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022', 'PGC_LATINO_SCZ_2022')
- mod <- c('PrediXcan_Brain_Cortex')
- dt <- dt_[!(gwas_phenotype %in% gwas | training_model %in% mod),]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- tms <- rev(c('G2S All WB', 'G2S African American WB', 'G2S Mexican American WB', 'G2S Puerto Rican WB', 'GTEx European WB'))
- dt$`gene expression model` <- factor(dt$`gene expression model`, levels = tms)
- adtwas2 <- dt
- # print manhattan plots for both the brain specific associations and the raw associations across all tissues
- chrom_sizes <- data.table(CHR = c(1:22), chr_length = c(
- 248956422, #1
- 242193529,
- 198295559,
- 190214555,
- 181538259, #5
- 170805979,
- 159345973,
- 145138636,
- 138394717,
- 133797422, #10
- 135086622,
- 133275309,
- 114364328,
- 114364328,
- 101991189, #15
- 90338345,
- 83257441,
- 80373285,
- 58617616,
- 64444167, #20
- 46709983,
- 50818468
- ))
- # Get the cumulative start locations for each chromosome in terms of base pairs.
- chrom_sizes[, chr_start := (cumsum(chr_length)-248956422)]
- # Set the x-axis label locations for each chromosome to be right in the middle of the chromosome block
- chrom_sizes[, chr_label_loc := (chr_start + chr_length/2)]
- all_genes <- fread('Data/all_ensembl.txt.gz', header = TRUE, stringsAsFactors=FALSE)
- # This file was downloaded from biomart website on 5/25/2022. The parameters were as follows:
- # Dataset: Human genes (GRCh38.p13)
- # Filters: Chromosome/scaffold: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22
- # Attributes: Gene stable ID, Gene start (bp), Chromosome/scaffold name
- # Export all files to: TSV
- #
- # I then uploaded the file to my personal directory and compressed it via the gzip commandline command.
- all_genes <- setNames(all_genes, c('ensembl_gene_id', 'start_position', 'chromosome_name'))
- all_genes_loc <- as.data.table(merge(all_genes, chrom_sizes[, c('CHR','chr_start')], by.x = 'chromosome_name', by.y = 'CHR'))
- all_genes_loc[, gn_start := rowSums(.SD), .SDcols = c("start_position", "chr_start")]
- all_genes_loc <- all_genes_loc[, c('ensembl_gene_id', 'chromosome_name', 'gn_start')]
- #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- dt=adtwas2
- dt$gene <- str_remove_all(dt$gene, '\\..+')
- # Iterate through the tissue models and NIDPs from the TWAS results
- # Get the top 15 p-values for labeling purposes
- top15 <- dt[, .(pvalue = min(pvalue)), by = c('gene','gene_name')][order(pvalue)][1:8, c('gene','gene_name','pvalue')]
- top15x = setDT(merge(top15, all_genes_loc, by.x = 'gene', by.y = 'ensembl_gene_id'))
- top15x$short_name = 'top_15'
- top25 <- dt[, .(pvalue = min(pvalue)), by = c('gene','gene_name')][order(pvalue)][1:25, c('gene','gene_name','pvalue')]
- top25x = setDT(merge(top25, all_genes_loc, by.x = 'gene', by.y = 'ensembl_gene_id'))
- top25x$short_name = 'top_25'
- twas2 <- merge(dt, all_genes_loc, by.x = 'gene', by.y = 'ensembl_gene_id')
- twas2$`gene expression model` <- factor(twas2$`gene expression model`, levels = tms)
- fig2 = ggplot(twas2, aes(x=gn_start, y=-log10(pvalue))) +
- # Show all points
- geom_point( aes(color=`gene expression model`), alpha=0.8, size=1.5) +
- geom_hline(yintercept=-log10(0.05/(dim(adtwas2)[1])), color = "red", size=0.5) +
- facet_wrap(vars(gwas_phenotype), scales = 'free', nrow = 3) +
- xlab('chromosome') +
- ylab('-log 10 pvalue')+
- #scale_color_manual(values = rep(c("grey", "skyblue"), 22 )) +
- scale_x_continuous(label = chrom_sizes[c(1:18,20,22),]$CHR, breaks= chrom_sizes[c(1:18,20,22),]$chr_label_loc ) +
- #scale_y_continuous(expand = c(0, 0),limits = c(0, (max(-log10(twas2$pvalue)) + 3)) ) + # remove space between plot area and x axis
- scale_color_discrete_sequential(palette = 'Batlow') +
- #scale_color_manual(values=as.vector(watlington(15)[c(3,4,1,5,12)])) +
- # Custom the theme:
- #guides(color = guide_legend(title = "Training Model", override.aes = list(size = 3), nrow=2, byrow=FALSE)) +
- guides(color = guide_legend(nrow=3, byrow=FALSE)) +
- theme_minimal()+
- theme(
- legend.position="bottom",
- panel.border = element_blank(),
- panel.grid.major.x = element_blank(),
- panel.grid.minor.x = element_blank(),
- axis.title.x = element_blank(),
- plot.title = element_text(hjust = 0.5),
- legend.text=element_text()
- )
- name = 'Output/all_assocs_nashplot_pgc.pdf'
- pdf(file = name, width = 15, height = 8, pointsize = 12, bg = "white")
- print(fig2)
- dev.off()
- print(fig2)
- ```
- ### Fig 1b: Gene sharing in models
- Certain genes are only assessed in G2S or GTEx but not both. We noted in computation
- analyses that there are far more statistically significant results from the G2S
- models than the GTEx. We want to see if differential gene characterization is
- unerlying this feature. To answer this question, we go to the original predictDB
- models for G2S and GTEx and examine the genes characterized in all the models.
- Then we can take the genes that were sgnificantly associated with a disease and
- characterize those genes according to if they are captured in a G2S model, GTEx
- GTEx model, or both.
- ```{r fig.height=7, fig.width = 4.5}
- load('Data/dbdata.r')
- cotested <- dbdata$cotested
- g2s_only <- dbdata$g2s_only
- gtx_only <- dbdata$gtx_only
- dt_ <- fread('Data/all_exc_BHsig_assocs_PGCancestryTWAS.txt', header = TRUE)
- # exclude replication/comparison data from initial analysis.
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022')
- mod <- c('PrediXcan_Brain_Cortex')
- dt <- dt_[!(gwas_phenotype %in% gwas | training_model %in% mod),]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- tms <- rev(c('G2S All WB', 'G2S African American WB', 'G2S Mexican American WB', 'G2S Puerto Rican WB', 'GTEx European WB'))
- dt$`gene expression model` <- factor(dt$`gene expression model`, levels = tms)
- dt[`gene expression model` == 'GTEx European WB', model := 'GTEX WB']
- dt[`gene expression model` != 'GTEx European WB', model := 'G2S']
- z1 <- unique(dt[, c('gene', 'gwas_phenotype', 'model')])
- z2 <- z1[, .(.N), by = c('gene', 'gwas_phenotype')]
- z2[N == 2, typ := 'co-sig']
- z2[N==1 & gene %in% cotested, typ := 'co-tested']
- z2[N==1 & !(gene %in% cotested), typ := 'only']
- z3 <- setDT(merge(z1, z2, by = c('gene', 'gwas_phenotype')))
- z3[typ != 'co-sig', category := paste(model, typ, sep = ' ')]
- z3[typ == 'co-sig', category := 'co-significant']
- z4 <- z3[, .(.N), by = c('gwas_phenotype', 'model', 'category')]
- z4[gwas_phenotype == 'PGC_ALL_PTSD_2024', dz := 'PTSD']
- z4[gwas_phenotype == 'PGC_all_SCZ_2022', dz := 'SCZ']
- z4[gwas_phenotype == 'PGC_allADHD_2022', dz := 'ADHD']
- z4[gwas_phenotype == 'PGC_allMDD_2023', dz := 'MDD']
- z4[gwas_phenotype == 'PGC_BD1_2021', dz := 'BD1']
- z4[gwas_phenotype == 'SUD_alc_2019', dz := 'AUD']
- z4$category = factor(z4$category, levels = c("G2S only", "G2S co-tested", "GTEX WB only", "GTEX WB co-tested", "co-significant"))
- tm_gp_plot6 <- ggplot(z4, aes(x = model, y = N, fill = category)) +
- geom_bar(stat = 'identity') +
- facet_wrap(vars(dz), scales = 'free', nrow = 3) +
- #scale_fill_manual(values=as.vector(watlington(15)[c(3,4,5,12,1)])) +
- scale_fill_manual(values=c('#cc6576ff', 'deeppink4', 'darkblue', 'cyan3', 'grey30')) +
- theme_minimal() +
- theme(legend.position = 'bottom', legend.title=element_blank()) +
- guides(fill = guide_legend(nrow = 2))
- name = 'Output/all_pgc_ancestry_TMxGP_bar_formatted2g.pdf'
- pdf(file = name, width = 4.5, height = 7, pointsize = 12, bg = "white")
- print(tm_gp_plot6)
- dev.off()
- print(tm_gp_plot6)
- ```
- ### Table of gene overlap across models
- Uncomment for results displayed as table
- ```{r}
- #kable(z4, caption = "Overlap data for genes included in GTEx vs G2S models", align = "ccc", digits = 2) %>%
- # kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F) %>%
- # column_spec(1, bold = T) %>%
- # row_spec(0, bold = T, color = "white", background = "#D7261E")%>%
- # scroll_box(width = "100%", height = "400px") # Adjust height as needed
- ```
- ## SNP level analyses
- ### Fig 2e, S12: Correlation of SNP weights
- Each model has SNP weights which serve as predictors of gene expression. We can take the
- same genes and get all the shared SNP predictors across G2S and GTEx and characterize
- the effect size of the weight on the gene. This will tell us if the models expect the same
- SNPs to have different effects on the same genes.
- ```{r fig.height=11, fig.width = 9}
- all_dat <- list.files('Data/rdata', pattern = '.+\\.txt')
- duo_snps <- data.table()
- for(fil in str_subset(all_dat, '^snpfx_dat_all.+\\.txt')){
- newdat <- fread(paste0('Data/rdata/', fil), header = T)
- duo_snps <- rbind(duo_snps, newdat)
- }
- r2_values <- duo_snps[, .(r2 = summary(lm(weight.GTEx ~ weight.G2S))$adj.r.squared), by = .(gwas_phenotype, model)]
- r_values <- duo_snps[, .(r_val = cor.test(weight.GTEx, weight.G2S)$estimate), by = .(gwas_phenotype, model)]
- fx_shared <- ggplot(data = duo_snps, aes(x = weight.G2S, y = weight.GTEx)) +
- geom_point() +
- geom_smooth(method = 'lm', se=F) +
- geom_text(data = r_values, aes(x = Inf, y = -Inf, label = paste0("R = ", round(r_val, 3))),
- hjust = 1.1, vjust = -0.5, check_overlap = TRUE) +
- xlab(paste0('SNP weight'))+
- ylab(paste0('SNP weight GTEx')) +
- facet_grid(gwas_phenotype~model) +
- theme(legend.position = 'none') +
- theme_bw()
- name = 'Output/fxcorr_grid24_cor.pdf'
- pdf(file = name, width = 9, height = 11, pointsize = 12, bg = "white")
- print(fx_shared)
- dev.off()
- print(fx_shared)
- ```
- ### Correlation of gene zscores
- While the previous analysis examined the model specific effects of SNP weights on gene expression
- this analysis examines the relationship between GReX on disease as characterized by GTEx vs G2S.
- We look at the zscores for the relationship of Gene X on disease Y as modeled by the different TWAS.
- This tells us if the models predict that the effect of genes on disease differs across models.
- ```{r}
- dsgene <- data.table()
- for(fil in str_subset(all_dat, '^dsgene_dat_all.+\\.txt')){
- newdat <- fread(paste0('Data/rdata/', fil), header = T)
- dsgene <- rbind(dsgene, newdat)
- }
- ```
- ```{r fig.height=12.5, fig.width = 10}
- cor_vals <- dsgene[, .(Zcor = cor(zscore.G2S, zscore.GTEx, use="complete.obs"), Pcor = cor(pvalue.G2S, pvalue.GTEx, use="complete.obs")), by = c( 'gwas_phenotype', 'model')]
- dg2 <- setDT(merge(dsgene, cor_vals, by = c('gwas_phenotype', 'model')))
- zsc_plot <- ggplot(data = dg2, aes(x = zscore.G2S, y = zscore.GTEx)) +
- #geom_point() +
- geom_pointdensity(adjust = 4) +
- scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'black') +
- geom_text(aes(x = Inf, y = Inf, label = paste0("R = ", round(Zcor, 3))),
- hjust = 1.1, vjust = -0.3, check_overlap = TRUE, color = 'black', size = 3) +
- facet_grid2(gwas_phenotype~model, axes = 'all') +
- #facet_grid(gwas_phenotype~model) +
- xlab('zscore.G2S') +
- ylab('zscore.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL), strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name = 'Output/zsc_corr_grid24.pdf'
- pdf(file = name, width = 10, height = 12.5, pointsize = 12, bg = "white")
- print(zsc_plot)
- dev.off()
- print(zsc_plot)
- ```
- ### Correlation of gene zscores 2 (Fig 2b, S6-7)
- Repeat the analysis but instead of a density plot, use black points with red trendline.
- ```{r fig.height=12.5, fig.width = 10}
- zsc_plotblk <- ggplot(data = dg2, aes(x = zscore.G2S, y = zscore.GTEx)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'red') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(Zcor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'red', size = 3) +
- facet_grid2(gwas_phenotype~model, axes = 'all') +
- #facet_grid(gwas_phenotype~model) +
- xlab('zscore.G2S') +
- ylab('zscore.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL), strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name = 'Output/zsc_corr_grid24_black.pdf'
- pdf(file = name, width = 10, height = 12.5, pointsize = 12, bg = "white")
- print(zsc_plotblk)
- dev.off()
- print(zsc_plotblk)
- ```
- ### Correlation of pvalues
- Similar to the correlation between zscores, we can also examine the relationship between p-values.
- This will tell us if the different models call the same gene-disease association with differing
- degrees of statistical significance.
- ```{r fig.height=12.5, fig.width = 10}
- pval_plot <- ggplot(data = dg2, aes(x = pvalue.G2S, y = pvalue.GTEx)) +
- #geom_point() +
- geom_pointdensity(adjust = 4) +
- scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'black') +
- geom_text(aes(x = Inf, y = Inf, label = paste0("R = ", round(Pcor, 3))),
- hjust = 1.1, vjust = -0.3, check_overlap = TRUE, color = 'black', size = 3) +
- scale_fill_manual(values=as.vector(kelly()[8:11])) +
- facet_grid2(gwas_phenotype~model, axes = 'all') +
- #facet_grid(gwas_phenotype~model) +
- xlab('pvalue.G2S') +
- ylab('pvalue.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal() +
- theme(panel.spacing = unit(1, "cm", data = NULL), strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name = 'Output/pval_corr_grid24.pdf'
- pdf(file = name, width = 10, height = 12.5, pointsize = 12, bg = "white")
- print(pval_plot)
- dev.off()
- print(pval_plot)
- ```
- ### Correlation of p-values 2 (Figure 2c, S8-9)
- And again, repeat with black points and red trendline.
- ```{r fig.height=12.5, fig.width = 10}
- pval_plotblk <- ggplot(data = dg2, aes(x = pvalue.G2S, y = pvalue.GTEx)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'red') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(Pcor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'red', size = 3) +
- scale_fill_manual(values=as.vector(kelly()[8:11])) +
- facet_grid2(gwas_phenotype~model, axes = 'all') +
- #facet_grid(gwas_phenotype~model) +
- xlab('pvalue.G2S') +
- ylab('pvalue.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal() +
- theme(panel.spacing = unit(1, "cm", data = NULL), strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name = 'Output/pval_corr_grid24_black.pdf'
- pdf(file = name, width = 10, height = 12.5, pointsize = 12, bg = "white")
- print(pval_plotblk)
- dev.off()
- print(pval_plotblk)
- ```
- ### Fig S12:Comparison of r2 values for GTeX vs G2S
- Each gene that is analyzed in the TWAS relies on a number of SNP weights that are used as predictors.
- The PredictDB pipeline that is used to make the model includes information about the correlation
- between the predicted gene expression using its SNP weights and the measured gene expression from
- RNA seq in the original dataset. This R2 is thus a measure of the predictive performance of the model
- regarding that specific gene. The difference in TWAS results may be related to the accuracy with which
- the different model are predicting gene expression. As a result, the code below compares the R2 values
- for genes across the different models that emerged from the TWAS.
- ```{r fig.height=12.5, fig.width = 10}
- r2corr <- ggplot(data = dsgene, aes(x = pred_perf_r2.G2S, y = pred_perf_r2.GTEx)) +
- geom_point() +
- geom_abline(intercept = 0, slope = 1, color = 'grey80', linetype = "dashed")+
- geom_smooth(method = 'lm', se=F) +
- xlab(paste0('R2 G2S'))+
- ylab(paste0('R2 GTEx')) +
- facet_grid(gwas_phenotype~model) +
- theme(legend.position = 'none') +
- theme_bw()
- name = 'Output/r2_mod_corr_grid24.pdf'
- pdf(file = name, width = 9, height = 11, pointsize = 12, bg = "white")
- print(r2corr)
- dev.off()
- print(r2corr)
- ```
- ### Correlation of zscores by gene significance
- Earlier we examined the total zscore correlations across models. It is possible to examine these
- in more granularity, splitting categories according to if the genes of interest were deemed significant
- in one, both, or none of the models.
- ```{r fig.height=5, fig.width = 5}
- fdga <- dsgene[, .(Ngroups = sum(!is.na(zscore.G2S) & !is.na(zscore.GTEx))), by = c('eqtl_source', 'twas_specificity', 'gwas_phenotype', 'model')]
- fdsgene2 <- setDT(merge(dsgene[!is.na(zscore.G2S) & !is.na(zscore.GTEx),], fdga, by = c('eqtl_source','twas_specificity', 'gwas_phenotype', 'model')))
- ffx_corr <- fdsgene2[Ngroups >2,
- .(fx_r2 = cor.test(zscore.G2S, zscore.GTEx)$estimate,
- fx_r2_ciL = cor.test(zscore.G2S, zscore.GTEx)$conf.int[1],
- fx_r2_ciH = cor.test(zscore.G2S, zscore.GTEx)$conf.int[2],
- N = .N), by = c('eqtl_source','twas_specificity', 'gwas_phenotype', 'model')]
- modnm = c('G2S_aa', 'G2S_all', 'G2S_mx', 'G2S_pr')
- ffx_corr$twas_specificity <- factor(ffx_corr$twas_specificity, levels = c('none', 'GTEx_WB', modnm, 'shared'))
- ffx_corr[twas_specificity == 'shared', spec := 'G2S & GTEx']
- ffx_corr[twas_specificity == 'none', spec := 'none']
- ffx_corr[!(twas_specificity %in% c('shared','none')), spec := 'G2S or GTEx']
- fx2 <- ffx_corr[, .(mfxr = mean(fx_r2)), by = c('eqtl_source', 'spec')]
- fx2_cord <- ggplot(data = fx2, aes(x = spec, y = mfxr, color = eqtl_source, group = eqtl_source)) +
- geom_hline(yintercept = 0, color = 'red') +
- #geom_errorbar(aes(ymin = fx_r2_ciL, ymax = fx_r2_ciH), width = 0.1, color = 'black', position=position_dodge(width=0.3)) +
- geom_point(position=position_dodge(width=0.3), size = 2) +
- scale_color_manual(values=c('green4', 'slateblue3')) +
- ylab('effect size correlation') +
- xlab('twas model significance') +
- ylim(c(-1, 1))+
- #facet_grid(gwas_phenotype~model, scales = 'free') +
- theme_bw() +
- theme(axis.text.x = element_text(angle = 60, hjust = 1))
- name = 'Output/genefx_corplot_grid24d_all.pdf'
- pdf(file = name, width = 5, height = 5, pointsize = 12, bg = "white")
- print(fx2_cord)
- dev.off()
- print(fx2_cord)
- ```
- ### Fig S16: correlation of zscores by gene significance 2
- We extend the analyses from above but split across models and clinical phenotypes
- ```{r fig.height=11, fig.width = 13}
- fdga <- dsgene[, .(Ngroups = sum(!is.na(zscore.G2S) & !is.na(zscore.GTEx))), by = c('eqtl_source', 'twas_specificity', 'gwas_phenotype', 'model')]
- fdsgene2 <- setDT(merge(dsgene[!is.na(zscore.G2S) & !is.na(zscore.GTEx),], fdga, by = c('eqtl_source','twas_specificity', 'gwas_phenotype', 'model')))
- ffx_corr <- fdsgene2[Ngroups >2,
- .(fx_r2 = cor.test(zscore.G2S, zscore.GTEx)$estimate,
- fx_r2_ciL = cor.test(zscore.G2S, zscore.GTEx)$conf.int[1],
- fx_r2_ciH = cor.test(zscore.G2S, zscore.GTEx)$conf.int[2],
- N = .N), by = c('eqtl_source','twas_specificity', 'gwas_phenotype', 'model')]
- modnm = c('G2S_aa', 'G2S_all', 'G2S_mx', 'G2S_pr')
- ffx_corr$twas_specificity <- factor(ffx_corr$twas_specificity, levels = c('none', 'GTEx_WB', modnm, 'shared'))
- fx_cord <- ggplot(data = ffx_corr, aes(x = twas_specificity, y = fx_r2, color = eqtl_source, group = eqtl_source)) +
- geom_hline(yintercept = 0, color = 'red') +
- geom_errorbar(aes(ymin = fx_r2_ciL, ymax = fx_r2_ciH), width = 0.1, color = 'black', position=position_dodge(width=0.3)) +
- geom_point(position=position_dodge(width=0.3), size = 2) +
- scale_color_manual(values=c('green4', 'slateblue3')) +
- ylab('effect size correlation') +
- xlab('twas model significance') +
- ylim(c(-1, 1))+
- facet_grid(gwas_phenotype~model, scales = 'free') +
- theme_bw() +
- theme(axis.text.x = element_text(angle = 60, hjust = 1))
- name = 'Output/genefx_corplot_grid24d.pdf'
- pdf(file = name, width = 13, height = 11, pointsize = 12, bg = "white")
- print(fx_cord)
- dev.off()
- print(fx_cord)
- ```
- ### Fig S17: correlation of pvalues by gene significance
- And again, we can examine the same analysis according to pvalue to get a visual representation
- of how the models handle statistical significance.
- ```{r fig.height=11, fig.width = 13}
- pdga <- dsgene[, .(Ngroups = sum(!is.na(pvalue.G2S) & !is.na(pvalue.GTEx))), by = c('eqtl_source', 'twas_specificity', 'gwas_phenotype', 'model')]
- pdsgene2 <- setDT(merge(dsgene[!is.na(pvalue.G2S) & !is.na(pvalue.GTEx),], pdga, by = c('eqtl_source','twas_specificity', 'gwas_phenotype', 'model')))
- pfx_corr <- pdsgene2[Ngroups >2,
- .(pv_r = cor.test(pvalue.G2S, pvalue.GTEx)$estimate,
- pv_r_ciL = cor.test(pvalue.G2S, pvalue.GTEx)$conf.int[1],
- pv_r_ciH = cor.test(pvalue.G2S, pvalue.GTEx)$conf.int[2],
- N = .N), by = c('eqtl_source','twas_specificity', 'gwas_phenotype', 'model')]
- modnm = c('G2S_aa', 'G2S_all', 'G2S_mx', 'G2S_pr')
- pfx_corr$twas_specificity <- factor(pfx_corr$twas_specificity, levels = c('none', 'GTEx_WB', modnm, 'shared'))
- pv_cor <- ggplot(data = pfx_corr, aes(x = twas_specificity, y = pv_r, color = eqtl_source, group = eqtl_source)) +
- geom_hline(yintercept = 0, color = 'red') +
- geom_errorbar(aes(ymin = pv_r_ciL, ymax = pv_r_ciH), width = 0.1, color = 'black', position=position_dodge(width=0.3)) +
- geom_point(position=position_dodge(width=0.3), size = 2) +
- scale_color_manual(values=c('coral1', 'deepskyblue2')) +
- #geom_label(aes(y = -0.75 + 0.25*sum('shared_distinct' %in% eqtl_source), label = paste('N =', N))) +
- #geom_label(aes(y = -1 , label = paste(N), color = eqtl_source), position = position_dodgev(height = -0.7)) +
- ylab('pvalue correlation') +
- xlab('twas model significance') +
- ylim(c(-1, 1))+
- facet_grid(gwas_phenotype~model, scales = 'free') +
- theme_bw() +
- theme(axis.text.x = element_text(angle = 60, hjust = 1))
- name = 'Output/genepv_corplot_grid24.pdf'
- pdf(file = name, width = 13, height = 11, pointsize = 12, bg = "white")
- print(pv_cor)
- dev.off()
- print(pv_cor)
- ```
- ### Fig 3b,S15: Median SNP weight magnitudes
- The SNPs used for the analysis may be different across the models but overall, I'm interested in
- seeing if the different models are able to assign SNPs of different effect sizes to the genes. To
- capture this, the code below characterizes the median magnitude of the SNP weights across G2S and
- GTEx.
- ```{r fig.height=11, fig.width = 9}
- all_snps <- data.table()
- for(fil in str_subset(all_dat, '^snp_dat_all.+\\.txt')){
- newdat <- fread(paste0('Data/rdata/', fil), header = T)
- all_snps <- rbind(all_snps, newdat)
- }
- wts <- setDT(melt(all_snps[, c('model', 'gwas_phenotype', 'weight.G2S', 'weight.GTEx')], id.vars = c('model', 'gwas_phenotype')))
- eqtl_medwtplot <- ggplot(data = wts, aes(x = variable, y = abs(value), fill = variable)) +
- geom_boxplot(outlier.shape = NA) +
- xlab('model')+
- ylab('median weight magnitude') +
- theme_minimal()+
- facet_grid(gwas_phenotype~model, scales = 'free') +
- coord_cartesian(ylim= c(0,0.15)) +
- theme(legend.position = 'none') +
- theme_bw()
- name = 'Output/eqtl_medwtplot_grid24.pdf'
- pdf(file = name, width = 9, height = 11, pointsize = 12, bg = "white")
- print(eqtl_medwtplot)
- dev.off()
- print(eqtl_medwtplot)
- ```
- ### Fig 2f: SNP, Gene, and Sig Gene correlations
- Let's group the zscore and SNP weight correlations into a single figure for easier comparitive
- analysis.
- ```{r fig.width = 5.5, fig.height = 11}
- wt_r2_values <- duo_snps[, .(r2_SNPpredictors = summary(lm(weight.GTEx ~ weight.G2S))$adj.r.squared, wt_rse = summary(lm(weight.GTEx ~ weight.G2S))$sigma, N_r2_SNP = .N), by = .(gwas_phenotype, model)]
- #wt_r2_valuessig <- duo_sig[, .(r2_SNPpredictors = summary(lm(weight.GTEx ~ weight.G2S))$adj.r.squared, wt_rse = summary(lm(weight.GTEx ~ weight.G2S))$sigma, N_r2_SNP = .N), by = .(gwas_phenotype, model)]
- wt_r_values <- duo_snps[, .(r_SNPpredictors = cor.test(weight.GTEx,weight.G2S)$estimate,
- wt_ciL = cor.test(weight.GTEx,weight.G2S)$conf.int[1],
- wt_ciH = cor.test(weight.GTEx,weight.G2S)$conf.int[2],
- N_wt_SNP = .N), by = .(gwas_phenotype, model)]
- gnfx_r_values <- dsgene[, .(r_gnfx = cor.test(zscore.GTEx,zscore.G2S)$estimate,
- gnfx_ciL = cor.test(zscore.GTEx,zscore.G2S)$conf.int[1],
- gnfx_ciH = cor.test(zscore.GTEx,zscore.G2S)$conf.int[2],
- N_gnfx = .N), by = .(gwas_phenotype, model)]
- gnfx_r_valsig <- dsgene[twas_specificity != 'none', .(r_gnfx_sig = cor.test(zscore.GTEx,zscore.G2S)$estimate,
- gnfx_sig_ciL = cor.test(zscore.GTEx,zscore.G2S)$conf.int[1],
- gnfx_sig_ciH = cor.test(zscore.GTEx,zscore.G2S)$conf.int[2],
- N_sig_gnfx = .N), by = .(gwas_phenotype, model)]
- cordat <- setDT(merge(wt_r_values, merge(gnfx_r_values, gnfx_r_valsig, by = c('gwas_phenotype', 'model')), by = c('gwas_phenotype', 'model')))
- wt_r_values <- duo_snps[, .(r = cor.test(weight.GTEx,weight.G2S)$estimate,
- ciL = cor.test(weight.GTEx,weight.G2S)$conf.int[1],
- ciH = cor.test(weight.GTEx,weight.G2S)$conf.int[2],
- N = .N,
- measure = 'SNP_predictor'), by = .(gwas_phenotype, model)]
- gnfx_r_values <- dsgene[, .(r = cor.test(zscore.GTEx,zscore.G2S)$estimate,
- ciL = cor.test(zscore.GTEx,zscore.G2S)$conf.int[1],
- ciH = cor.test(zscore.GTEx,zscore.G2S)$conf.int[2],
- N = .N,
- measure = 'effect size'), by = .(gwas_phenotype, model)]
- gnfx_r_valsig <- dsgene[twas_specificity != 'none', .(r = cor.test(zscore.GTEx,zscore.G2S)$estimate,
- ciL = cor.test(zscore.GTEx,zscore.G2S)$conf.int[1],
- ciH = cor.test(zscore.GTEx,zscore.G2S)$conf.int[2],
- N = .N,
- measure = 'effect size (sig)'), by = .(gwas_phenotype, model)]
- cordat <- rbind(wt_r_values, gnfx_r_values, gnfx_r_valsig)
- cordat <- rbind(wt_r_values, gnfx_r_values, gnfx_r_valsig)
- cordat$measure <- factor(cordat$measure, levels = c('SNP_predictor', 'effect size', 'effect size (sig)'))
- cordat[gwas_phenotype == 'PGC_BD1_2021', disease := 'BD1']
- cordat[gwas_phenotype == 'PGC_all_SCZ_2022', disease := 'SCZ']
- cordat[gwas_phenotype == 'SUD_alc_2019', disease := 'SUD-A']
- cordat[gwas_phenotype == 'PGC_allADHD_2022', disease := 'ADHD']
- cordat[gwas_phenotype == 'PGC_ALL_PTSD_2024', disease := 'PTSD']
- cordat[gwas_phenotype == 'PGC_allMDD_2023', disease := 'MDD']
- allcor_plot <- ggplot(data = cordat, aes(x = measure, y = r, group = model, color = model)) +
- #geom_line(position=position_dodge(width=0.5))+
- geom_errorbar(aes(ymin = ciL, ymax = ciH), width = 0.3, color = 'black', position=position_dodge(width=0.5)) +
- geom_point(position=position_dodge(width=0.5)) +
- #facet_grid2(disease~., axes = 'all') +
- facet_grid(disease~.) +
- guides(color = guide_legend(nrow = 2)) +
- xlab('measurement') +
- ylab('r correlation coefficient') +
- ylim(c(0,1)) +
- theme_bw() +
- theme(axis.text = element_text(size = 14),
- axis.title = element_text(size = 14),
- strip.text = element_text(size = 14),
- legend.text = element_text(size=14),
- legend.title = element_text(size=14),
- legend.position = 'bottom')
- name = 'Output/allcordat_grid.pdf'
- pdf(file = name, width = 5.5, height = 11, pointsize = 12, bg = "white")
- print(allcor_plot)
- dev.off()
- print(allcor_plot)
- ```
- ### Fig 3e,S22: r2 by model specificity
- As before, we split the zscore correlations by model specificity. Here we replicate this analytical design
- with the r2 but instead of dots and bars for range, we'll visualize this with violin plots and imbedded boxplots.
- ```{r fig.width = 9, fig.height = 11}
- r2_dat <- data.table()
- for(fil in str_subset(all_dat, '^r2_dat_all.+\\.txt')){
- newdat <- fread(paste0('Data/rdata/', fil), header = T)
- r2_dat <- rbind(r2_dat, newdat)
- }
- r2_vplot <- ggplot(data = r2_dat, aes(x = variable, y = value, fill = eqtl_source)) +
- geom_violin(scale = 'width', position=position_dodge(1), drop = F) +
- geom_boxplot(width = 0.1, color = 'black', position=position_dodge(1), outlier.size = 0.5) +
- xlab('eQTL model specificity') +
- ylab('R2 per gene') +
- facet_grid(gwas_phenotype~model, scales = 'free') +
- theme_minimal() +
- theme(axis.text.x = element_text(angle = 60, hjust = 1))
- name = 'Output/r2_vplot_grid24.pdf'
- pdf(file = name, width = 9, height = 11, pointsize = 12, bg = "white")
- print(r2_vplot)
- dev.off()
- print(r2_vplot)
- ```
- ### r2 plot agregated across all factors
- ```{r}
- duo_sig <- data.table()
- for(fil in str_subset(all_dat, '^fxsig_dat_all.+\\.txt')){
- newdat <- fread(paste0('Data/rdata/', fil), header = T)
- duo_sig <- rbind(duo_sig, newdat)
- }
- r2_values <- duo_sig[, .(r2 = summary(lm(weight.GTEx ~ weight.G2S))$adj.r.squared), by = .(gwas_phenotype, model)]
- r_values <- duo_sig[, .(r_val = cor.test(weight.GTEx, weight.G2S)$estimate), by = .(gwas_phenotype, model)]
- fx_sharedsig <- ggplot(data = duo_sig, aes(x = weight.G2S, y = weight.GTEx, color = model_specificity)) +
- geom_point() +
- geom_smooth(method = 'lm', se=F, weight = 1, fullrange = T) +
- geom_text(inherit.aes = F, data = r_values, aes(x = Inf, y = -Inf, label = paste0("R = ", round(r_val, 3))),
- hjust = 1.1, vjust = -0.5, check_overlap = TRUE) +
- xlab(paste0('SNP weight'))+
- ylab(paste0('SNP weight GTEx')) +
- facet_grid(gwas_phenotype~model, scales = 'free') +
- theme(legend.position = 'none') +
- theme_bw()
- name = 'Output/r2_aggregate_1.pdf'
- pdf(file = name, width = 4, height = 4, pointsize = 12, bg = "white")
- print(fx_sharedsig)
- dev.off()
- print(fx_sharedsig)
- ```
- ### Fig 2d, S11: Number of used eQTL's per gene
- How many eQTLs were used for each gene that was tested in the different TWAS analyses?
- ```{r fig.height=12.5, fig.width = 10}
- eqtl_dat <- data.table()
- for(fil in str_subset(all_dat, '^eqtl_dat_all.+\\.txt')){
- newdat <- fread(paste0('Data/rdata/', fil), header = T)
- eqtl_dat <- rbind(eqtl_dat, newdat)
- }
- eqtl_vplot <- ggplot(data = eqtl_dat, aes(x = variable, y = value, fill = variable)) +
- geom_violin(scale = 'width') +
- geom_boxplot(width = 0.1, color = 'black', fill = 'white',outlier.shape = NA) +
- xlab('eQTL model specificity')+
- ylab('Number of eQTLs per gene') +
- theme_minimal()+
- facet_grid(gwas_phenotype~model, scales = 'free') +
- theme_bw() +
- theme(legend.position = 'none', axis.text.x = element_text(angle = 60, hjust = 1))
- name = 'Output/eqtl_vplot_grid24.pdf'
- pdf(file = name, width = 9, height = 11, pointsize = 12, bg = "white")
- print(eqtl_vplot)
- dev.off()
- print(eqtl_vplot)
- ```
- ### Fig 3c, S13: r2 by model
- split r2 by model instead of significance or correlation.
- ```{r fig.height=12.5, fig.width = 10}
- preds <- melt(dsgene[, c('gwas_phenotype', 'gene', 'model', 'pred_perf_r2.G2S', 'pred_perf_r2.GTEx')], id.vars = c('gwas_phenotype', 'gene', 'model' ))
- r2_vplot <- ggplot(data = preds, aes(x = variable, y = value, fill = variable)) +
- geom_violin(scale = 'width') +
- geom_boxplot(width = 0.1, color = 'black', fill = 'white',outlier.shape = NA) +
- xlab('model')+
- ylab('Prediction performance r2') +
- theme_minimal()+
- facet_grid(gwas_phenotype~model, scales = 'free') +
- theme_bw() +
- theme(legend.position = 'none', axis.text.x = element_text(angle = 60, hjust = 1))
- name = 'Output/predperf_vplot_grid24.pdf'
- pdf(file = name, width = 9, height = 11, pointsize = 12, bg = "white")
- print(r2_vplot)
- dev.off()
- print(r2_vplot)
- ```
- ## MDD Ancestry-concordant TWAS
- We wanted to see if the results we got were the specific to a study design where we applied two different models
- to the same GWAS summary statistics. We pulled GWAS of MDD done in predominantly African Americans vs Europeans
- and then applied more ancestry concordant models to each for the TWAS. (G2S_AA + African American MDD GWAS and then
- GTEx + Eur GWAS). For this we repeated a number of the descriptive analyzes performed above.
- ### zscore corrrelation all
- Correlation of Zscores. I performed this multiple times considering different statistical significance thresholds.
- ```{r}
- library(data.table)
- library(ggplot2)
- library(pals)
- library(gridExtra)
- library(ggh4x)
- library(DBI)
- # get the correlations needed between the different models and twas analyses
- mda <- fread('Data/dual_data/all_exc_assocs_PGCancestryTWAS_AA.txt', header = T)[gwas_phenotype == 'PGC_allMDD_2023',]
- mde <- fread('Data/dual_data/all_exc_assocs_PGCancestryTWAS_EUR.txt', header = T)
- mdeg <- unique(mde$gene_name)
- mdag <- unique(mda$gene_name)
- uniq_mde <- setdiff(mdeg, mdag)
- uniq_mda <- setdiff(mdag, mdeg)
- jointmdd <- setDT(merge(mda[training_model != 'PrediXcan_Brain_Cortex',], mde, by = c('gene_name', 'training_model'), suffixes = c('.multi', '.eur')))
- cor.test(jointmdd$zscore.multi, jointmdd$zscore.eur)
- ```
- ### zscore cor all shared
- ```{r fig.width = 8, fig.height = 2.6}
- # correlation between zscores across the two cohorts is 0.803 across all models.
- mdcor <- jointmdd[, .(zsc_cor = cor.test(zscore.multi, zscore.eur)$estimate), by = c('training_model')]
- mdcorsig <- jointmdd[bhpval.eur <= 0.05 & bhpval.multi <= 0.05, .(zsc_cor = cor.test(zscore.multi, zscore.eur)$estimate), by = c('training_model')]
- mdcorsig2 <- jointmdd[bhpval.eur <= 0.05 | bhpval.multi <= 0.05, .(zsc_cor = cor.test(zscore.multi, zscore.eur)$estimate), by = c('training_model')]
- crossmdd <- setDT(merge(mda[training_model != 'PrediXcan_Brain_Cortex' & training_model != 'PrediXcan_Whole_Blood',], mde[training_model == 'PrediXcan_Whole_Blood',], by = c('gene_name'), suffixes = c('.multi_g2S', '.eur_gtex')))
- cmdcor <- crossmdd[, .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- cmdcorsig <- crossmdd[bhpval.eur_gtex <= 0.05 & bhpval.multi_g2S <= 0.05, .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- cmdcorsig2 <- crossmdd[bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05, .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- ## Make plots
- pdat1 <- setDT(merge(crossmdd, cmdcor, by = 'training_model.multi_g2S'))
- cmd_genecorr <- ggplot(data = pdat1, aes(x = zscore.multi_g2S, y=zscore.eur_gtex)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'green4') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(zsc_cor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'green4', size = 3) +
- facet_grid2(.~training_model.multi_g2S, axes = 'all') +
- ggtitle('All shared genes') +
- xlab('zscore.G2S') +
- ylab('zscore.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL),
- strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name='Output/dual_zsc_corr_grid_all.pdf'
- pdf(file = name, width = 8, height = 2.6, pointsize = 12, bg = "white")
- print(cmd_genecorr)
- dev.off()
- print(cmd_genecorr)
- ```
- ### zscore cor all co-sig
- ```{r fig.width = 8, fig.height = 2.6}
- pdat2 <- setDT(merge(crossmdd[bhpval.eur_gtex <= 0.05 & bhpval.multi_g2S <= 0.05,], cmdcorsig, by = 'training_model.multi_g2S'))
- cmd_genecorr_sig <- ggplot(data = pdat2, aes(x = zscore.multi_g2S, y=zscore.eur_gtex)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'springgreen3') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(zsc_cor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'springgreen3', size = 3) +
- facet_grid2(.~training_model.multi_g2S, axes = 'all') +
- ggtitle('All co-significant genes') +
- xlab('zscore.G2S') +
- ylab('zscore.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL),
- strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name='Output/dual_zsc_corr_grid_sig.pdf'
- pdf(file = name, width = 8, height = 2.6, pointsize = 12, bg = "white")
- print(cmd_genecorr_sig)
- dev.off()
- print(cmd_genecorr_sig)
- ```
- ### zscore cor all sig
- ```{r fig.width = 8, fig.height = 2.6}
- pdat3 <- setDT(merge(crossmdd[bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05,], cmdcorsig2, by = 'training_model.multi_g2S'))
- cmd_genecorr_sig2 <- ggplot(data = pdat3, aes(x = zscore.multi_g2S, y=zscore.eur_gtex)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'lightgreen') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(zsc_cor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'lightgreen', size = 3) +
- facet_grid2(.~training_model.multi_g2S, axes = 'all') +
- ggtitle('All significant genes') +
- xlab('zscore.G2S') +
- ylab('zscore.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL),
- strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name='Output/dual_zsc_corr_grid2_sig2.pdf'
- pdf(file = name, width = 8, height = 2.6, pointsize = 12, bg = "white")
- print(cmd_genecorr_sig2)
- dev.off()
- cmd_genecorr_sig2
- ```
- ### pval cor all shared 1
- ```{r fig.width = 8, fig.height = 2.6}
- cmdcor <- crossmdd[, .(zsc_cor = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$estimate,
- zsc_ciL = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- cmdcorsig <- crossmdd[bhpval.eur_gtex <= 0.05 & bhpval.multi_g2S <= 0.05, .(zsc_cor = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$estimate,
- zsc_ciL = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- cmdcorsig2 <- crossmdd[bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05, .(zsc_cor = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$estimate,
- zsc_ciL = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(pvalue.multi_g2S, pvalue.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- ## Make plots
- pdat1 <- setDT(merge(crossmdd, cmdcor, by = 'training_model.multi_g2S'))
- cmd_genecorr <- ggplot(data = pdat1, aes(x = zscore.multi_g2S, y=zscore.eur_gtex)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'gold') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(zsc_cor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'gold', size = 3) +
- facet_grid2(.~training_model.multi_g2S, axes = 'all') +
- ggtitle('All shared genes') +
- xlab('pvalue.G2S') +
- ylab('pvalue.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL),
- strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name='Output/dual_pval_corr_grid_all.pdf'
- pdf(file = name, width = 8, height = 2.6, pointsize = 12, bg = "white")
- print(cmd_genecorr)
- dev.off()
- print(cmd_genecorr)
- ```
- ### pval cor all co-sig
- And then again with pvalues.
- ```{r fig.width = 8, fig.height = 2.6}
- pdat2 <- setDT(merge(crossmdd[bhpval.eur_gtex <= 0.05 & bhpval.multi_g2S <= 0.05,], cmdcorsig, by = 'training_model.multi_g2S'))
- cmd_genecorr_sig <- ggplot(data = pdat2, aes(x = zscore.multi_g2S, y=zscore.eur_gtex)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'yellow3') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(zsc_cor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'yellow3', size = 3) +
- facet_grid2(.~training_model.multi_g2S, axes = 'all') +
- ggtitle('All co-significant genes') +
- xlab('pvalue.G2S') +
- ylab('pvalue.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL),
- strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name='Output/dual_pval_corr_grid2_sig.pdf'
- pdf(file = name, width = 8, height = 2.6, pointsize = 12, bg = "white")
- print(cmd_genecorr_sig)
- dev.off()
- print(cmd_genecorr_sig)
- ```
- ### pval cor all sig
- ```{r fig.width = 8, fig.height = 2.6}
- pdat3 <- setDT(merge(crossmdd[bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05,], cmdcorsig2, by = 'training_model.multi_g2S'))
- cmd_genecorr_sig2 <- ggplot(data = pdat3, aes(x = zscore.multi_g2S, y=zscore.eur_gtex)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'lightgreen') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(zsc_cor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'goldenrod', size = 3) +
- facet_grid2(.~training_model.multi_g2S, axes = 'all') +
- ggtitle('All significant genes') +
- xlab('pvalue.G2S') +
- ylab('pvalue.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL),
- strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name='Output/dual_pval_corr_grid2_sig2.pdf'
- pdf(file = name, width = 8, height = 2.6, pointsize = 12, bg = "white")
- print(cmd_genecorr_sig2)
- dev.off()
- print(cmd_genecorr_sig2)
- ```
- ### Pval cor All shared
- ```{r fig.width = 8, fig.height = 2.6}
- snp_dat_all <- fread('Data/dual_data/dual_duo_snps_used.txt', header = T)
- cmd_snpcor <- snp_dat_all[, .(wt_cor = cor.test(weight.G2S, weight.GTEx)$estimate,
- zsc_ciL = cor.test(weight.G2S, weight.GTEx)$conf.int[1],
- zsc_ciH = cor.test(weight.G2S, weight.GTEx)$conf.int[2],
- .N), by = c('model')]
- cordat <- setDT(merge(snp_dat_all, cmd_snpcor, by = 'model'))
- cmd_snpcorr <- ggplot(data = cordat, aes(x = weight.G2S, y=weight.GTEx)) +
- geom_point() +
- #geom_pointdensity(adjust = 4) +
- #scale_color_viridis() +
- geom_smooth(method = 'lm', se=F, color = 'purple') +
- geom_text(aes(x = -Inf, y = Inf, label = paste0("R = ", round(wt_cor, 3))),
- hjust = 0.1, vjust = -0.3, check_overlap = TRUE, color = 'purple', size = 3) +
- facet_grid2(.~model, axes = 'all') +
- ggtitle('All shared genes') +
- xlab('weight.G2S') +
- ylab('weight.GTEx') +
- coord_cartesian( clip = "off")+
- theme_minimal()+
- theme(panel.spacing = unit(1, "cm", data = NULL),
- strip.text.x = element_text(margin = margin(5, 5, 12, 5, "pt")))
- name='Output/dual_weight_corr_grid_all.pdf'
- pdf(file = name, width = 8, height = 2.6, pointsize = 12, bg = "white")
- print(cmd_snpcorr)
- dev.off()
- print(cmd_snpcorr)
- ```
- ### Effect size correlation
- normalized zscore correlation across models
- ```{r fig.width = 12, fig.height = 4.25}
- duo_snps <- snp_dat_all
- ds_gene <- duo_snps[, .(N_g2s_SNPs = sum(!(is.na(weight.G2S)) & shared == F),
- N_GTeX_SNPs = sum(!(is.na(weight.GTEx)) & shared == F),
- N_shared_SNPs = sum(shared == TRUE),
- N_total_snps = length(unique(rsid)),
- prop_g2s = sum(!(is.na(weight.G2S)))/length(unique(rsid))), by = 'gene']
- #group genes by model presence
- ds_gene[, eqtl_source := fcase(N_g2s_SNPs == 0 & N_shared_SNPs == 0, "GTEx",
- N_GTeX_SNPs == 0 & N_shared_SNPs == 0, "G2S",
- N_shared_SNPs != 0, "shared_overlapping",
- N_shared_SNPs == 0 & (N_g2s_SNPs != 0 & N_GTeX_SNPs != 0), "shared_distinct")]
- dubs <- setDT(merge(crossmdd, ds_gene, by.x = c('gene.multi_g2S'), by.y = c('gene')))
- cmdcor_source <- dubs[, .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S', 'eqtl_source')]
- fx_cor <- ggplot(data = cmdcor_source, aes(x = eqtl_source, y = zsc_cor, color = training_model.multi_g2S)) +
- geom_hline(yintercept = 0, color = 'red') +
- geom_errorbar(aes(ymin = zsc_ciL, ymax = zsc_ciH), width = 0.1, color = 'black') +
- geom_point(size = 2) +
- geom_label(aes(y = -0.75, label = paste('N =', N)), size = 3) +
- #scale_color_manual(values=c('green4', 'slateblue3')) +
- ylab('normalized effect size correlation') +
- xlab('SNP predictor model specificity') +
- ylim(c(-1, 1))+
- facet_grid(.~training_model.multi_g2S, scales = 'free') +
- theme_bw() +
- theme(axis.text.x = element_text(angle = 60, hjust = 1))
- name = 'Output/dual_genefx_corplot_grid.pdf'
- pdf(file = name, width = 12, height = 4.25, pointsize = 12, bg = "white")
- print(fx_cor)
- dev.off()
- print(fx_cor)
- ```
- ### Fig 4b: N SNPs per gene
- N Snp weights used per gene across the two models.
- ```{r fig.width = 12, fig.height = 4.25}
- cmdcor_source <- dubs[eqtl_source == 'shared_overlapping' & (bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05), .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S', 'eqtl_source')]
- cmd_sigs <- dubs[bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05, .(.N), by = c('training_model.multi_g2S', 'eqtl_source')]
- snp_dat_all_L <- setDT(melt(snp_dat_all[, -c('shared')], id.vars = c('gene', 'rsid','model')))
- snp_dat_N <- snp_dat_all_L[!is.na(value) & variable == 'weight.G2S', .(N = length(unique(rsid))), by = c('gene', 'model')]
- snp_dat_all_L2 <- snp_dat_all_L
- snp_dat_all_L2[,gr := paste0(gene, rsid)]
- snp_dat_N2 <- snp_dat_all_L2[!is.na(value) & variable == 'weight.GTEx', .(N = length(unique(gr))), by = 'gene']
- snp_dat_N2[, model := 'GTEx_Whole_Blood']
- snp_dat_Ns <- rbind(snp_dat_N, snp_dat_N2)
- # median weight across all SNPs used
- eqtl_vplot <- ggplot(data = snp_dat_Ns, aes(x = model, y = N, fill = model)) +
- geom_violin(scale = 'width', position=position_dodge(1), drop = F) +
- geom_boxplot(width = 0.1, color = 'black', position=position_dodge(1), outlier.size = 0.5) +
- xlab('SNP predictor model ')+
- ylab('SNP predictors per gene') +
- theme_minimal()+
- theme(legend.position = 'none') +
- theme_bw() +
- theme(text = element_text(size = 13), axis.text = element_text(size = 13))
- name = 'Output/dual_snpPredNplot_gridvplot.pdf'
- pdf(file = name, width = 11, height = 3, pointsize = 12, bg = "white")
- print(eqtl_vplot)
- dev.off()
- print(eqtl_vplot)
- ```
- ### Fig 4c: Median SNP magnitude
- Median magnitude of the used SNP weights across the models.
- ```{r fig.width = 12, fig.height = 4.25}
- snp_dat_all_L1 <- snp_dat_all_L[!is.na(value) & variable == 'weight.G2S', -c('variable')]
- snp_dat_all_L2 <- unique(snp_dat_all_L[!is.na(value) & variable == 'weight.GTEx', -c('variable', 'model')])
- snp_dat_all_L2[, model := 'GTEx_Whole_Blood']
- snp_dat_wts <- rbind(snp_dat_all_L1, snp_dat_all_L2)
- eqtl_wtplot <- ggplot(data = snp_dat_wts, aes(x = model, y = abs(value), fill = model)) +
- geom_boxplot(color = 'black', position=position_dodge(1), outlier.shape = NA) +
- xlab('SNP predictor model ')+
- ylab('median SNP weight magnitude') +
- coord_cartesian(ylim= c(0,0.125)) +
- theme_minimal()+
- theme(legend.position = 'none') +
- theme_bw() +
- theme(text = element_text(size = 13), axis.text = element_text(size = 13))
- name = 'Output/dual_snpPred_wt_plot_gridvplot.pdf'
- pdf(file = name, width = 11, height = 3, pointsize = 12, bg = "white")
- print(eqtl_wtplot)
- dev.off()
- print(eqtl_wtplot)
- ```
- ### Fig 4d: All correlation Comparison
- Compile into single figure
- ```{r fig.width = 12, fig.height = 4.25}
- crossmdd2 <- crossmdd
- crossmdd2[bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05, sig := 'sig']
- crossmdd2[!(bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05), sig := 'nonsig']
- cmd_snpcor <- snp_dat_all[, .(wt_cor = cor.test(weight.G2S, weight.GTEx)$estimate,
- zsc_ciL = cor.test(weight.G2S, weight.GTEx)$conf.int[1],
- zsc_ciH = cor.test(weight.G2S, weight.GTEx)$conf.int[2],
- .N), by = c('model')]
- cmdcor <- crossmdd[, .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- cmdcorsig <- crossmdd[bhpval.eur_gtex <= 0.05 & bhpval.multi_g2S <= 0.05, .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- cmdcorsig2 <- crossmdd[bhpval.eur_gtex <= 0.05 | bhpval.multi_g2S <= 0.05, .(zsc_cor = cor.test(zscore.multi_g2S, zscore.eur_gtex)$estimate,
- zsc_ciL = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[1],
- zsc_ciH = cor.test(zscore.multi_g2S, zscore.eur_gtex)$conf.int[2],
- .N), by = c('training_model.multi_g2S')]
- snp1 <- setnames(cmd_snpcor, c('wt_cor', 'zsc_ciL', 'zsc_ciH'), c('cor', 'ciL', 'ciH'))
- #snp1 <- cmd_snpcor
- snp1$group <- 'SNP weights'
- gene1 <- setnames(cmdcor, c('training_model.multi_g2S', 'zsc_cor', 'zsc_ciL', 'zsc_ciH'), c('model','cor', 'ciL', 'ciH'))
- #gene1 <- cmdcor
- gene1$group <- 'all genes'
- genesig <- setnames(cmdcorsig2, c('training_model.multi_g2S', 'zsc_cor', 'zsc_ciL', 'zsc_ciH'), c('model','cor', 'ciL', 'ciH'))
- #genesig <- cmdcorsig2
- genesig$group <- 'sig genes'
- compdata <- setDT(rbind(snp1, gene1, genesig))
- compdata$group <- factor(compdata$group, levels=c('SNP weights', 'all genes', 'sig genes'))
- allcor_plot <- ggplot(data = compdata, aes(x = group, y = cor, color = model, group = model)) +
- geom_errorbar(aes(ymin = ciL, ymax = ciH), width = 0.3, color = 'black', position=position_dodge(width=0.9)) +
- geom_point( position=position_dodge(width = 0.9), size = 3) +
- xlab('measurement') +
- ylab('r correlation coefficient') +
- ylim(c(0,1)) +
- theme_bw() +
- theme(text = element_text(size = 13), axis.text = element_text(size = 13))
- name = 'Output/dual_allcordat_mddcomp.pdf'
- pdf(file = name, width = 11, height = 3, pointsize = 12, bg = "white")
- print(allcor_plot)
- dev.off()
- print(allcor_plot)
- ```
- ## NeuroimaGene analysis
- Use the NeuroimaGene resource to get the neuroimaging features associated with the
- TWAS results for each disease.
- ### Fig 6a: Neuroimaging visualizations
- ```{r neuroimaGene1}
- library(neuroimaGene)
- ########## NeuroimaGene analysis
- all <- dt
- bdg <- unique(all[gwas_phenotype == 'PGC_BD1_2021',]$gene)
- szg <- unique(all[gwas_phenotype == 'PGC_all_SCZ_2022']$gene)
- adg <- unique(all[gwas_phenotype == 'PGC_allADHD_2022']$gene)
- mdg <- unique(all[gwas_phenotype == 'PGC_allMDD_2023']$gene)
- ptg <- unique(all[gwas_phenotype == 'PGC_ALL_PTSD_2024']$gene)
- aug <- unique(all[gwas_phenotype == 'SUD_alc_2019']$gene)
- bdng <- neuroimaGene(bdg)
- neuro_vis(bdng)
- ```
- ```{r}
- szng <- neuroimaGene(szg)
- neuro_vis(szng)
- ```
- ```{r}
- adng <- neuroimaGene(adg)
- neuro_vis(adng)
- ```
- ```{r}
- mdng <- neuroimaGene(mdg)
- neuro_vis(mdng)
- ```
- ```{r}
- ptng <- neuroimaGene(ptg)
- neuro_vis(ptng)
- ```
- ```{r}
- aung <- neuroimaGene(aug)
- neuro_vis(aung)
- ```
- ```{r}
- bdng2 <- neuroimaGene(bdg, atlas = 'aseg_volume')
- neuro_vis(bdng2, atlas = 'Subcortex')
- ```
- ```{r}
- szng2 <- neuroimaGene(szg, atlas = 'aseg_volume')
- neuro_vis(szng2, atlas = 'Subcortex')
- ```
- ```{r}
- adng2 <- neuroimaGene(adg, atlas = 'aseg_volume')
- neuro_vis(adng2, atlas = 'Subcortex')
- ```
- ```{r}
- mdng2 <- neuroimaGene(mdg, atlas = 'aseg_volume')
- neuro_vis(mdng2, atlas = 'Subcortex')
- ```
- ```{r}
- ptng2 <- neuroimaGene(ptg, atlas = 'aseg_volume')
- neuro_vis(ptng2, atlas = 'Subcortex')
- ```
- ```{r}
- aung2 <- neuroimaGene(aug, atlas = 'aseg_volume')
- neuro_vis(aung2, atlas = 'Subcortex')
- ```
- Compile data
- ```{r}
- adng$group <- 'ADHD'
- adng2$group <- 'ADHD'
- aung2$group <- 'AUD'
- aung$group <- 'AUD'
- bdng$group <- 'BD1'
- bdng2$group <- 'BD1'
- mdng$group <- 'MDD'
- mdng2$group <- 'MDD'
- ptng$group <- 'PTSD'
- ptng2$group <- 'PTSD'
- szng$group <- 'SCZ'
- szng2$group <- 'SCZ'
- ng_data_ <- rbind(bdng, szng, adng, mdng, ptng, aung, bdng2, szng2, adng2, mdng2, ptng2, aung2)
- ng_data <- setDT(merge(ng_data_, neuroimaGene::anno, by = 'gwas_phenotype'))
- ```
- Comparison with no G2S
- ```{r}
- eur <- dt[training_model == 'PrediXcan_Whole_Blood']
- bdg_e <- unique(eur[gwas_phenotype == 'PGC_BD1_2021',]$gene)
- szg_e <- unique(eur[gwas_phenotype == 'PGC_all_SCZ_2022']$gene)
- adg_e <- unique(eur[gwas_phenotype == 'PGC_allADHD_2022']$gene)
- mdg_e <- unique(eur[gwas_phenotype == 'PGC_allMDD_2023']$gene)
- ptg_e <- unique(eur[gwas_phenotype == 'PGC_ALL_PTSD_2024']$gene)
- aug_e <- unique(eur[gwas_phenotype == 'SUD_alc_2019']$gene)
- bdng_e <- neuroimaGene(bdg_e)
- szng_e <- neuroimaGene(szg_e)
- adng_e <- neuroimaGene(adg_e)
- mdng_e <- neuroimaGene(mdg_e)
- ptng_e <- neuroimaGene(ptg_e)
- aung_e <- neuroimaGene(aug_e)
- bdng2_e <- neuroimaGene(bdg_e, atlas = 'aseg_volume')
- szng2_e <- neuroimaGene(szg_e, atlas = 'aseg_volume')
- adng2_e <- neuroimaGene(adg_e, atlas = 'aseg_volume')
- mdng2_e <- neuroimaGene(mdg_e, atlas = 'aseg_volume')
- ptng2_e <- neuroimaGene(ptg_e, atlas = 'aseg_volume')
- aung2_e <- neuroimaGene(aug_e, atlas = 'aseg_volume')
- adng_e$group <- 'ADHD'
- adng2_e$group <- 'ADHD'
- aung2_e$group <- 'AUD'
- aung_e$group <- 'AUD'
- bdng_e$group <- 'BD1'
- bdng2_e$group <- 'BD1'
- mdng_e$group <- 'MDD'
- mdng2_e$group <- 'MDD'
- ptng_e$group <- 'PTSD'
- ptng2_e$group <- 'PTSD'
- szng_e$group <- 'SCZ'
- szng2_e$group <- 'SCZ'
- ng_data_e_ <- rbind(bdng_e, szng_e, adng_e, mdng_e, ptng_e, aung_e, bdng2_e, szng2_e, adng2_e, mdng2_e, ptng2_e, aung2_e)
- ng_data_e <- setDT(merge(ng_data_e_, neuroimaGene::anno, by = 'gwas_phenotype'))[, -c('zscore', 'atl_BHpval', 'fMRI_node_1', 'fMRI_node_2')]
- ```
- now g2s
- ```{r}
- g2s <- dt[training_model != 'PrediXcan_Whole_Blood']
- bdg_g <- unique(g2s[gwas_phenotype == 'PGC_BD1_2021',]$gene)
- szg_g <- unique(g2s[gwas_phenotype == 'PGC_all_SCZ_2022']$gene)
- adg_g <- unique(g2s[gwas_phenotype == 'PGC_allADHD_2022']$gene)
- mdg_g <- unique(g2s[gwas_phenotype == 'PGC_allMDD_2023']$gene)
- ptg_g <- unique(g2s[gwas_phenotype == 'PGC_ALL_PTSD_2024']$gene)
- aug_g <- unique(g2s[gwas_phenotype == 'SUD_alc_2019']$gene)
- bdng_g <- neuroimaGene(bdg_g)
- szng_g <- neuroimaGene(szg_g)
- adng_g <- neuroimaGene(adg_g)
- mdng_g <- neuroimaGene(mdg_g)
- ptng_g <- neuroimaGene(ptg_g)
- aung_g <- neuroimaGene(aug_g)
- bdng2_g <- neuroimaGene(bdg_g, atlas = 'aseg_volume')
- szng2_g <- neuroimaGene(szg_g, atlas = 'aseg_volume')
- adng2_g <- neuroimaGene(adg_g, atlas = 'aseg_volume')
- mdng2_g <- neuroimaGene(mdg_g, atlas = 'aseg_volume')
- ptng2_g <- neuroimaGene(ptg_g, atlas = 'aseg_volume')
- aung2_g <- neuroimaGene(aug_g, atlas = 'aseg_volume')
- adng_g$group <- 'ADHD'
- adng2_g$group <- 'ADHD'
- aung2_g$group <- 'AUD'
- aung_g$group <- 'AUD'
- bdng_g$group <- 'BD1'
- bdng2_g$group <- 'BD1'
- mdng_g$group <- 'MDD'
- mdng2_g$group <- 'MDD'
- ptng_g$group <- 'PTSD'
- ptng2_g$group <- 'PTSD'
- szng_g$group <- 'SCZ'
- szng2_g$group <- 'SCZ'
- ng_data_g_ <- rbind(bdng_g, szng_g, adng_g, mdng_g, ptng_g, aung_g, bdng2_g, szng2_g, adng2_g, mdng2_g, ptng2_g, aung2_g)
- ng_data_g <- setDT(merge(ng_data_g_, neuroimaGene::anno, by = 'gwas_phenotype'))[, -c('zscore', 'atl_BHpval', 'fMRI_node_1', 'fMRI_node_2')]
- ```
- Separate out and print the neuroimagene findings specific to G2S models
- ```{r}
- ng_data_g$id <- paste0(ng_data_g$gwas_phenotype, ng_data_g$group)
- ng_data_e$id <- paste0(ng_data_e$gwas_phenotype, ng_data_e$group)
- ng_data_gonly <- ng_data_g[!(id %in% ng_data_e$id),][measurement != 'QC',]
- ng_data_gonly[, xlabel := paste0(atlas, '\n', measurement)]
- ng_plotdata <- ng_data_gonly[, .(N = length(unique(gwas_phenotype))), by = c('group', 'xlabel')]
- ng_plotdata$group <- factor(ng_plotdata$group, levels = c("PTSD", "SCZ", "ADHD", "MDD", "BD1", "AUD"))
- ng_barplot <- ggplot(ng_plotdata, aes(y = N, x = xlabel, fill = xlabel)) +
- geom_bar(stat = 'identity') +
- facet_grid(group~.) +
- scale_fill_brewer(palette = 'Dark2') +
- ylab('G2S specific NIDPs') +
- xlab('measurement') +
- theme_minimal() +
- theme(axis.text.x = element_text(angle = 270), legend.position = 'none')
- name = 'Output/ng_g2s_barplot.pdf'
- pdf(file = name, width = 2.5, height = 7, pointsize = 12, bg = "white")
- print(ng_barplot)
- dev.off()
- print(ng_barplot)
- ```
- ### Fig S1: Descriptive Summary Data
- Show the number of results for each model/disease pair and split by shared vs individually significant.
- **Special thanks to Nathan Watkins and Tavian Bowen-Moore**
- ```{r, echo=FALSE}
- library(data.table)
- library(ggplot2)
- library(gridExtra)
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- dt1 <- dt[!training_model == 'PrediXcan_Whole_Blood']
- dt2 <- dt[training_model == 'PrediXcan_Whole_Blood']
- # Function to clean gene names
- clean_gene_name <- function(gene_name) {
- sub("\\..*", "", gene_name)
- }
- # Function to create and store plots
- create_plots <- function(MAtwas, MUtwas) {
- # Clean gene names in both datasets
- MAtwas[, gene_name := clean_gene_name(gene_name)]
- MUtwas[, gene_name := clean_gene_name(gene_name)]
- # List to store plots
- plots <- list()
- for (blood_type in unique(MUtwas$training_model)) {
- # Loop through each unique blood type in MUtwas
- for (phenotype in unique(MAtwas$gwas_phenotype)) {
- # Subset the data based on the current phenotype and blood type
- tut <- MUtwas[training_model == blood_type & gwas_phenotype == phenotype,]
- tot <- MAtwas[training_model == 'PrediXcan_Whole_Blood' & gwas_phenotype == phenotype,]
- # Check if all entries in tut are 'GTEX_whole_blood'
- if (all(tut$training_model == 'PrediXcan_Whole_Blood')) {
- next
- }
- # Split the tut data.table into 2 data.tables according to training model
- aa <- tut[training_model == blood_type,]
- eur <- tot
- # Get vectors of all gene associations with the disease in each set
- aa_gns <- unique(aa$gene_name)
- eur_gns <- unique(eur$gene_name)
- # Create vectors of gene names that are unique to AA, GTEx, and shared
- unique_eur <- setdiff(eur_gns, aa_gns)
- unique_aa <- setdiff(aa_gns, eur_gns)
- shared <- intersect(aa_gns, eur_gns)
- # Custom names and color mapping for plotting
- custom_names <- c('AA_Whole_Blood' = 'AA',
- 'All_Whole_Blood' = 'ALL',
- 'MX_Whole_Blood' = 'MX',
- 'PR_Whole_Blood' = 'PR',
- 'PrediXcan_Whole_Blood' = 'GTEx')
- color_mapping <- c('AA' = 'orange',
- 'ALL' = 'red',
- 'MX' = 'pink',
- 'PR' = 'green',
- 'GTEx' = 'blue',
- 'shared' = 'cyan')
- dz_names <- c('PGC_allADHD_2022' = 'ADHD',
- 'PGC_all_SCZ_2022' = 'SCZ',
- 'PGC_allMDD_2023' = 'MDD',
- 'PGC_BD1_2021' = 'BD1',
- 'SUD_alc_2019' = 'SUD-A',
- 'PGC_ALL_PTSD_2024' = 'PTSD')
- # Set the disease name
- dz_name <- dz_names[unique(aa$gwas_phenotype)]
- # Create data.table with data for plotting
- gene_cts <- data.table(study_specificity = c('GTEx', custom_names[blood_type], 'shared'),
- N = c(length(unique_eur), length(unique_aa), length(shared)))
- # Set the factor levels for study_specificity
- gene_cts$study_specificity <- factor(gene_cts$study_specificity, levels = names(color_mapping))
- # Create and plot the ggplot object
- p2 <- ggplot(data = gene_cts,
- aes(x = study_specificity, y = N, fill = study_specificity)) +
- geom_bar(stat = 'identity') +
- ggtitle(dz_name) +
- xlab("Study Specificity") +
- ylab("Number of Genes") +
- scale_fill_manual(values = color_mapping) +
- theme_minimal() +
- theme(
- plot.title = element_text(size = 10), # Reduce title size
- axis.title = element_text(size = 9), # Reduce axis titles size
- axis.text = element_text(size = 9), # Reduce axis text size
- plot.margin = margin(10, 10, 10, 10),
- legend.position = 'none'
- )
- # Store the plot in the list
- plots[[paste(phenotype, blood_type, sep = "_")]] <- p2
- }
- }
- return(plots)
- }
- # Generate and save plots to PDF
- save_plots_to_pdf <- function(plots, file_name) {
- pdf(file_name, width = 13, height = 8)
- do.call(grid.arrange, c(plots, ncol = 6, padding = unit(1, "lines")))
- dev.off()
- }
- # usage
- plots <- create_plots(dt2, dt1)
- save_plots_to_pdf(plots, "Output/gene_unique_comp2.pdf")
- knitr::include_graphics("Output/gene_unique_comp2.pdf")
- ```
- # Corrplots
- ### Fig 5a: correlation plots
- Get correlation of disase TWAS results across models to see if the models are predicting the same
- inter-disease transcriptomic relationships.
- ```{r}
- library(data.table)
- library(corrplot)
- dt_ <- fread('Data/all_exc_assocs_PGCancestryTWAS.txt', header = TRUE)
- # exclude replication/comparison data from initial analysis.
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022', 'PGC_LATINO_SCZ_2022')
- mod <- c('PrediXcan_Brain_Cortex')
- dt <- dt_[!(gwas_phenotype %in% gwas | training_model %in% mod),]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- dt1a <- dt[!training_model == 'PrediXcan_Whole_Blood']
- dt2a <- dt[training_model == 'PrediXcan_Whole_Blood']
- # Function to clean gene names
- clean_gene_name <- function(gene_name) {
- sub("\\..*", "", gene_name)
- }
- # Function to create and save correlation plots
- create_and_save_corr_plots <- function(MAtwas, MUtwas) {
- # Clean gene names in both datasets
- MAtwas[, gene_name := clean_gene_name(gene_name)]
- MUtwas[, gene_name := clean_gene_name(gene_name)]
- # Get unique training models from MUtwas and add GTEX from MAtwas
- training_models <- unique(MUtwas$training_model)
- training_models <- c(training_models, 'PrediXcan_Whole_Blood')
- # Define a custom color palette
- custom_colors <- colorRampPalette(c("red", "grey60", "blue"))(1000)
- # Open a PDF device with Letter dimensions
- pdf("Output/correlograms.pdf", width = 8.5, height = 11)
- for (model in training_models) {
- modl <- copy(model)
- # Filter data for the current training model
- if (model == 'PrediXcan_Whole_Blood') {
- filtered_data <- MAtwas[training_model == 'PrediXcan_Whole_Blood', c('gwas_phenotype', 'gene', 'zscore')]
- } else {
- filtered_data <- MUtwas[training_model == modl, c('gwas_phenotype', 'gene', 'zscore')]
- }
- unique_genes <- unique(filtered_data$gene)
- unique_phenotypes <- unique(filtered_data$gwas_phenotype)
- matrix_data <- matrix(NA, nrow = length(unique_genes), ncol = length(unique_phenotypes))
- rownames(matrix_data) <- unique_genes
- colnames(matrix_data) <- unique_phenotypes
- for (i in 1:nrow(filtered_data)) {
- row <- filtered_data[i, ]
- matrix_data[row$gene, row$gwas_phenotype] <- row$zscore
- }
- cor_matrix <- cor(matrix_data, use = "pairwise.complete.obs")
- # Adjust plot margins to accommodate longer titles
- par(mar = c(1, 1, 5, 1))
- corrplot(corr = cor_matrix,
- method = "circle",
- type = "lower",
- tl.pos = "tl",
- order = "original",
- col = custom_colors, # Use custom colors
- title = paste("Correlation plot for training model:", model),
- mar = c(0, 0, 2, 0)) # Adjust margins to fit the title
- }
- # Close the PDF device
- dev.off()
- }
- # Example usage
- create_and_save_corr_plots(dt2a, dt1a)
- ```
- ## Cell type analysis
- What are the cell types most implicated in the brain analyses based on the TWAS genes that emerged as significant.
- ```{r}
- pg <- fread('../../PanglaoDB_markers_27_Mar_2020.tsv', header = T)
- overlap <- merge(
- dt[, .(`gene_name`, gwas_phenotype)],
- pg[, .(`official gene symbol`, `cell type`)],
- by.x = "gene_name",
- by.y = "official gene symbol",
- allow.cartesian = TRUE
- )
- # Count overlaps for each disease × cell_type pair
- result <- overlap[, .(n_genes = uniqueN(gene_name), genes = paste(unique(gene_name), collapse = '|')), by = c('gwas_phenotype', 'cell type')]
- # Optional: ensure long format (already long here)
- setorder(result, gwas_phenotype, `n_genes`)
- write.table(result[n_genes > 1, ], 'Output/disease_cell_types.txt', col.names = T, row.names = F, quote = F, sep = '\t')
- ```
- ## TWAS Power from GWAS ancestries
- ### Fig S24: Ancestry specific TWAS
- We hypothesized that the derivation of statistically significant twas results from different GWAS was affected by the N for each ancestry specific GWAS. We next examine how similar the TWAS results from the GWAS subsets are to the general data across multiple significance cutoffs.
- ```{r}
- allnom <- fread('Data/all_exc_assocs_PGCancestryTWAS.txt', header = T)
- allnom <- allnom[pvalue <= 0.05,]
- # exclude replication/comparison data from initial analysis.
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024')
- mod <- c('PrediXcan_Brain_Cortex')
- anc <- allnom[gwas_phenotype %in% gwas & !(training_model %in% mod),]
- gpdict1 <- data.table(gwas_phenotype = gwas, diagnosis = c('MDD', 'PTSD', 'SCZ', 'SCZ', 'PTSD', 'PTSD'), gwas_ancestry = c('AA', 'AA', 'AA', 'EA', 'EUR', 'HNA'))
- gpdict2 <- data.table(gwas_phenotype = c('PGC_allADHD_2022', 'PGC_allMDD_2023', 'PGC_ALL_PTSD_2024', 'PGC_all_SCZ_2022', 'PGC_BD1_2021', 'SUD_alc_2019'),
- diagnosis = c('ADHD', 'MDD', 'PTSD', 'SCZ', 'BD1', 'AUD'),
- gwas_ancestry = c('multi', 'multi', 'multi', 'multi', 'EUR', 'multi'))
- dt_ <- fread('Data/all_exc_BHsig_assocs_PGCancestryTWAS.txt', header = TRUE)
- dt <- dt_[!(gwas_phenotype %in% gwas | training_model %in% mod),]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- anc2 <- setDT(merge(anc, gpdict1, by = 'gwas_phenotype'))
- dt2 <- setDT(merge(dt, gpdict2, by = c('gwas_phenotype')))
- duo <- setDT(merge(dt2, anc2, by = c('gene', 'diagnosis', 'training_model'), suffixes = c('.multi', '.sa')))
- pdata <- data.table()
- for (dz in unique(duo$diagnosis)) {
- for (g_anc in unique(duo$gwas_ancestry.sa)) {
- for(pthresh in c(5*10^seq(-2, -5, -1), 1*10^seq(-2, -5, -1))) {
- if(nrow(duo[pvalue.sa <= pthresh & (diagnosis == dz & gwas_ancestry.sa == g_anc),]) >= 5) {
- mod <- lm(data = duo[pvalue.sa <= pthresh & (diagnosis == dz & gwas_ancestry.sa == g_anc),], zscore.multi~zscore.sa)
- newdat <- data.table(pvalue = pthresh, diagnosis = dz, gwas_ancestry = g_anc, N = nrow(duo[pvalue.sa <= pthresh & (diagnosis == dz & gwas_ancestry.sa == g_anc),]), r2 = summary(mod)$adj.r.squared, regression_p = summary(mod)$coefficients[2,4])
- pdata <- rbind(pdata, newdat)
- }
- }
- }
- }
- pz <- ggplot(pdata, aes(x = -log10(pvalue), y = r2, color = -log10(regression_p))) +
- geom_hline(yintercept = 0) +
- geom_point() +
- facet_wrap(diagnosis~gwas_ancestry, scales = 'free', nrow = 6) +
- scale_y_continuous(limits = c(-0.5, 1)) +
- scale_x_continuous(limits = c(0, 5)) +
- theme_minimal() +
- theme(legend.position = 'bottom')
- name = 'Output/anc_specific_r2.pdf'
- pdf(file = name, width = 3.5, height = 10, pointsize = 12, bg = "white")
- print(pz)
- dev.off()
- print(pz)
- ```
- ### Fig S25: produce TWAS plots for multi-ancestry GWAS
- ```{r}
- library(data.table)
- library(ggplot2)
- library(ggrepel)
- library(stringr)
- library(colorspace)
- dt_ <- fread('Data/all_exc_assocs_PGCancestryTWAS.txt', header = TRUE)
- # include replication/comparison data from initial analysis.
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022','PGC_LATINO_SCZ_2022')
- mod <- c('PrediXcan_Brain_Cortex')
- dt <- dt_[gwas_phenotype %in% gwas & !(training_model %in% mod),]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- tms <- rev(c('G2S All WB', 'G2S African American WB', 'G2S Mexican American WB', 'G2S Puerto Rican WB', 'GTEx European WB'))
- dt$`gene expression model` <- factor(dt$`gene expression model`, levels = tms)
- dt$gene <- str_remove_all(dt$gene, '\\..+')
- # Iterate through the tissue models and NIDPs from the TWAS results
- # Get the top 15 p-values for labeling purposes
- top15 <- dt[, .(pvalue = min(pvalue)), by = c('gene','gene_name')][order(pvalue)][1:8, c('gene','gene_name','pvalue')]
- top15x = setDT(merge(top15, all_genes_loc, by.x = 'gene', by.y = 'ensembl_gene_id'))
- top15x$short_name = 'top_15'
- top25 <- dt[, .(pvalue = min(pvalue)), by = c('gene','gene_name')][order(pvalue)][1:25, c('gene','gene_name','pvalue')]
- top25x = setDT(merge(top25, all_genes_loc, by.x = 'gene', by.y = 'ensembl_gene_id'))
- top25x$short_name = 'top_25'
- twas2 <- merge(dt, all_genes_loc, by.x = 'gene', by.y = 'ensembl_gene_id')
- twas2$`gene expression model` <- factor(twas2$`gene expression model`, levels = tms)
- fig2 = ggplot(twas2, aes(x=gn_start, y=-log10(pvalue))) +
- # Show all points
- geom_point( aes(color=`gene expression model`), alpha=0.8, size=1.5) +
- geom_hline(yintercept=-log10(0.05/(dim(adtwas2)[1])), color = "red", size=0.5) +
- facet_wrap(vars(gwas_phenotype), scales = 'free', nrow = 6) +
- xlab('chromosome') +
- ylab('-log 10 pvalue')+
- #scale_color_manual(values = rep(c("grey", "skyblue"), 22 )) +
- scale_x_continuous(label = chrom_sizes[c(1:18,20,22),]$CHR, breaks= chrom_sizes[c(1:18,20,22),]$chr_label_loc ) +
- scale_color_discrete_diverging(palette = 'Berlin') +
- guides(color = guide_legend(nrow=3, byrow=FALSE)) +
- theme_minimal()+
- theme(
- legend.position="bottom",
- panel.border = element_blank(),
- panel.grid.major.x = element_blank(),
- panel.grid.minor.x = element_blank(),
- axis.title.x = element_blank(),
- plot.title = element_text(hjust = 0.5),
- legend.text=element_text()
- )
- name = 'Output/all_assocs_nashplot_pgc_ancs2.pdf'
- pdf(file = name, width = 14, height = 15, pointsize = 12, bg = "white")
- print(fig2)
- dev.off()
- ```
- ```{r}
- print(fig2)
- ```
- # Revisions Round 1
- ```{r}
- dir.create('Output/revisions')
- ```
- ### Fig S2: Statistical contributors to model power
- ```{r}
- # Do power comparison for N individuals in training set vs number of associations.
- # Read in all significant data and subset GWAS findings of interest
- sig <- fread('Data/all_exc_BHsig_assocs_PGCancestryTWAS.txt', header = T)
- dt <- sig[!(gwas_phenotype %in% c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022')),]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- dt[training_model == 'PrediXcan_Brain_Cortex', `gene expression model` := 'GTEx European Brain']
- dtn <- dt[, .(N_assocs =.N), by = c('gene expression model')]
- dtn[ `gene expression model` == 'G2S All WB', N_samples := 2733]
- dtn[`gene expression model` == 'G2S African American WB', N_samples := 757]
- dtn[`gene expression model` == 'G2S Mexican American WB', N_samples := 784]
- dtn[ `gene expression model` == 'G2S Puerto Rican WB', N_samples := 893]
- dtn[ `gene expression model` == 'GTEx European WB', N_samples := 670]
- dtn[ `gene expression model` == 'GTEx European Brain', N_samples := 205]
- dtn[ `gene expression model` == 'G2S All WB', Mean_Afr := 0.32]
- dtn[`gene expression model` == 'G2S African American WB', Mean_Afr := 0.8]
- dtn[`gene expression model` == 'G2S Mexican American WB', Mean_Afr := 0.04]
- dtn[ `gene expression model` == 'G2S Puerto Rican WB', Mean_Afr := 0.22]
- dtn[ `gene expression model` == 'G2S All WB', Mean_IAM := 0.24]
- dtn[`gene expression model` == 'G2S African American WB', Mean_IAM := 0.01]
- dtn[`gene expression model` == 'G2S Mexican American WB', Mean_IAM := 0.57]
- dtn[ `gene expression model` == 'G2S Puerto Rican WB', Mean_IAM := 0.10]
- library(ggrepel)
- lmod <- lm(data = dtn, N_assocs ~ N_samples)
- lmod <- lm(data = dtn, N_assocs ~ N_samples)
- lmodall <- lm(data = dtn[c(1,2,3,6),], N_assocs ~ Mean_Afr)
- summary(lmodall)
- lmod_g2s <- lm(data = dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain')),], N_assocs ~ N_samples)
- dtn_plot_g2s <- ggplot(dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain')),], aes(x = N_samples, y = N_assocs, color = `gene expression model`)) +
- geom_point() +
- geom_smooth(method = 'lm', color = 'black', se = F) +
- #geom_text(aes(x = -Inf, y = -Inf, label = summary(lmod_g2s)$pvalue)) +
- annotate(geom="text", x=Inf, y=-Inf, label=paste('r2=',round(summary(lmod_g2s)$adj.r.squared, 3)), color="red3", hjust = 1.2, vjust = -0.25) +
- geom_label_repel(aes(label = `gene expression model`)) +
- theme_minimal() +
- theme(legend.position = 'none')
- name = 'Output/revisions/assoc_by_modelN_g2s.pdf'
- pdf(file = name, width = 5, height = 4, pointsize = 12, bg = "white")
- print(dtn_plot_g2s)
- dev.off()
- print(dtn_plot_g2s)
- ```
- ```{r}
- lmod_g2s2 <- lm(data = dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain', 'G2S All WB')),], N_assocs ~ N_samples)
- summary(lmod_g2s2)
- dtn_plot_g2s2 <- ggplot(dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain', 'G2S All WB')),], aes(x = N_samples, y = N_assocs, color = `gene expression model`)) +
- geom_point() +
- geom_smooth(method = 'lm', color = 'black', se = F) +
- annotate(geom="text", x=Inf, y=-Inf, label=paste('r2=',round(summary(lmod_g2s2)$adj.r.squared, 3)), color="red3", hjust = 1.2, vjust = -0.25) +
- geom_label_repel(aes(label = `gene expression model`)) +
- theme(legend.position = 'none')
- name = 'Output/revisions/assoc_by_modelN_g2s_single.pdf'
- pdf(file = name, width = 5, height = 4, pointsize = 12, bg = "white")
- print(dtn_plot_g2s2)
- dev.off()
- print(dtn_plot_g2s2)
- ```
- ```{r}
- lmod_g2s2b <- lm(data = dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain', 'G2S All WB')),], N_assocs ~ Mean_Afr)
- summary(lmod_g2s2b)
- dtn_plot_g2s2b <- ggplot(dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain', 'G2S All WB')),], aes(x = Mean_Afr, y = N_assocs, color = `gene expression model`)) +
- geom_point() +
- geom_smooth(method = 'lm', color = 'black', se = F) +
- scale_color_brewer(palette = 'Accent') +
- annotate(geom="text", x=Inf, y=-Inf, label=paste('r2=',round(summary(lmod_g2s2b)$adj.r.squared, 3)), color="red3", hjust = 1.2, vjust = -0.25) +
- geom_label_repel(aes(label = `gene expression model`)) +
- theme(legend.position = 'none')
- name = 'Output/revisions/assoc_by_Afr_g2s.pdf'
- pdf(file = name, width = 5, height = 4, pointsize = 12, bg = "white")
- print(dtn_plot_g2s2b)
- dev.off()
- print(dtn_plot_g2s2b)
- ```
- ```{r}
- lmod_g2s2c <- lm(data = dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain', 'G2S All WB')),], N_assocs ~ Mean_IAM)
- dtn_plot_g2s2c <- ggplot(dtn[!(`gene expression model` %in% c('GTEx European WB', 'GTEx European Brain', 'G2S All WB')),], aes(x = Mean_IAM, y = N_assocs, color = `gene expression model`)) +
- geom_point() +
- geom_smooth(method = 'lm', color = 'black', se = F) +
- scale_color_brewer(palette = 'Accent') +
- annotate(geom="text", x=Inf, y=-Inf, label=paste('r2=',round(summary(lmod_g2s2c)$adj.r.squared, 3)), color="red3", hjust = 1.2, vjust = -0.25) +
- geom_label_repel(aes(label = `gene expression model`)) +
- theme(legend.position = 'none')
- name = 'Output/revisions/assoc_by_IAM_g2s.pdf'
- pdf(file = name, width = 5, height = 4, pointsize = 12, bg = "white")
- print(dtn_plot_g2s2c)
- dev.off()
- print(dtn_plot_g2s2c)
- ```
- ## Werth Replication Analysis
- ### Figure S5: Comparisons of TWAS vs prior discoveries
- ```{r}
- library(data.table)
- library(ggplot2)
- library(reshape2)
- library(pals)
- library(stringr)
- dt_ <- fread('Data/all_exc_BHsig_assocs_PGCancestryTWAS.txt', header = TRUE)
- # exclude replication/comparison data from initial analysis.
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022')
- mod <- c('PrediXcan_Brain_Cortex')
- dt <- dt_[!(gwas_phenotype %in% gwas | training_model %in% mod),]
- euro <- dt[training_model == 'PrediXcan_Whole_Blood',]
- anc <- dt[training_model != 'PrediXcan_Whole_Blood',]
- dup <- setDT(merge(anc, euro, by = c('gene_name', 'gwas_phenotype')))
- euro$gptm <- paste0(euro$gene_name, '_', euro$gwas_phenotype)
- anc$gptm <- paste0(anc$gene_name, '_', anc$gwas_phenotype)
- anc2 <- anc[!(gptm %in% euro$gptm),]
- euro2 <- euro[!(gptm %in% anc$gptm),]
- #Run ADHD replication analysis.
- adhd_w <- fread('Data/twas_atlas_data/replication_datasets/adhd_22_werth.txt', header = T)
- adhd_w_wb <- adhd_w[, c('gene_name', 'Whole_Blood_unconditioned')][!is.na(Whole_Blood_unconditioned),]
- adhd_w_wb$fdr_p <- p.adjust(adhd_w_wb$Whole_Blood_unconditioned, 'BH')
- adhd_ta <- adhd_w_wb[Whole_Blood_unconditioned <= 0.05,]
- adhd_anc_specific <- anc2[gwas_phenotype == 'PGC_allADHD_2022' & !(gene_name %in% adhd_ta$gene_name),]
- a1 <- nrow(adhd_anc_specific[, .(.N), by = 'gene_name'])
- adhd_euro_specific <- euro2[gwas_phenotype == 'PGC_allADHD_2022' & !(gene_name %in% adhd_ta$gene_name),]
- a2 <- nrow(adhd_euro_specific[, .(.N), by = 'gene_name'])
- a3 <- adhd_ta_specific <- length(unique(adhd_ta[!(gene_name %in% dt$gene_name),]$gene_name))
- a4 <- length(unique(anc2[gwas_phenotype == 'PGC_allADHD_2022' & (gene_name %in% adhd_ta$gene_name),]$gene_name))
- a5 <- length(unique(euro2[gwas_phenotype == 'PGC_allADHD_2022' & (gene_name %in% adhd_ta$gene_name),]$gene_name))
- # then BD
- bd_w <- fread('Data/twas_atlas_data/replication_datasets/bd_22_werth.txt', header = T)
- bd_w_wb <- bd_w[, c('gene_name', 'Whole_Blood_unconditioned')][!is.na(Whole_Blood_unconditioned),]
- bd_w_wb$fdr_p <- p.adjust(bd_w_wb$Whole_Blood_unconditioned, 'BH')
- bd_ta <- bd_w_wb[Whole_Blood_unconditioned <= 0.05,]
- bd_anc_specific <- anc2[gwas_phenotype == 'PGC_BD1_2021' & !(gene_name %in% bd_ta$gene_name),]
- b1 <- nrow(bd_anc_specific[, .(.N), by = 'gene_name'])
- bd_euro_specific <- euro2[gwas_phenotype == 'PGC_BD1_2021' & !(gene_name %in% bd_ta$gene_name),]
- b2 <- nrow(bd_euro_specific[, .(.N), by = 'gene_name'])
- b3 <- bd_ta_specific <- length(unique(bd_ta[!(gene_name %in% dt$gene_name),]$gene_name))
- b4 <- length(unique(anc2[gwas_phenotype == 'PGC_BD1_2021' & (gene_name %in% bd_ta$gene_name),]$gene_name))
- b5 <- length(unique(euro2[gwas_phenotype == 'PGC_BD1_2021' & (gene_name %in% bd_ta$gene_name),]$gene_name))
- # and MDD
- mdd_w <- fread('Data/twas_atlas_data/replication_datasets/mdd_22_werth.txt', header = T)
- mdd_w_wb <- mdd_w[, c('gene_name', 'Whole_Blood_unconditioned')][!is.na(Whole_Blood_unconditioned),]
- mdd_w_wb$fdr_p <- p.adjust(mdd_w_wb$Whole_Blood_unconditioned, 'BH')
- mdd_ta <- mdd_w_wb[Whole_Blood_unconditioned <= 0.05,]
- mdd_anc_specific <- anc2[gwas_phenotype == 'PGC_allMDD_2023' & !(gene_name %in% mdd_ta$gene_name),]
- m1 <- nrow(mdd_anc_specific[, .(.N), by = 'gene_name'])
- mdd_euro_specific <- euro2[gwas_phenotype == 'PGC_allMDD_2023' & !(gene_name %in% mdd_ta$gene_name),]
- m2 <- nrow(mdd_euro_specific[, .(.N), by = 'gene_name'])
- m3 <- mdd_ta_specific <- length(unique(mdd_ta[!(gene_name %in% dt$gene_name),]$gene_name))
- m4 <- length(unique(anc2[gwas_phenotype == 'PGC_allMDD_2023' & (gene_name %in% mdd_ta$gene_name),]$gene_name))
- m5 <- length(unique(euro2[gwas_phenotype == 'PGC_allMDD_2023' & (gene_name %in% mdd_ta$gene_name),]$gene_name))
- # and lastly scz
- scz_w <- fread('Data/twas_atlas_data/replication_datasets/scz_22_werth.txt', header = T)
- scz_w_wb <- scz_w[, c('gene_name', 'Whole_Blood_unconditioned')][!is.na(Whole_Blood_unconditioned),]
- scz_w_wb$fdr_p <- p.adjust(scz_w_wb$Whole_Blood_unconditioned, 'BH')
- scz_ta <- scz_w_wb[Whole_Blood_unconditioned <= 0.05,]
- scz_anc_specific <- anc2[gwas_phenotype == 'PGC_all_SCZ_2022' & !(gene_name %in% scz_ta$gene_name),]
- s1 <- nrow(scz_anc_specific[, .(.N), by = 'gene_name'])
- scz_euro_specific <- euro2[gwas_phenotype == 'PGC_all_SCZ_2022' & !(gene_name %in% scz_ta$gene_name),]
- s2 <- nrow(scz_euro_specific[, .(.N), by = 'gene_name'])
- s3 <- scz_ta_specific <- length(unique(scz_ta[!(gene_name %in% dt$gene_name),]$gene_name))
- s4 <- length(unique(anc2[gwas_phenotype == 'PGC_all_SCZ_2022' & (gene_name %in% scz_ta$gene_name),]$gene_name))
- s5 <- length(unique(euro2[gwas_phenotype == 'PGC_all_SCZ_2022' & (gene_name %in% scz_ta$gene_name),]$gene_name))
- #compile data into single object
- ant_twas_dat <- data.table(study = c('ADHD', 'MDD', 'BD1', 'SCZ'),
- g2s_new = c(a1, m1, b1, s1),
- euro_new = c(a2, m2, b2, s2),
- Werth_unique = c(a3,m3,b3,s3),
- g2s_rep = c(a4,m4,b4,s4),
- euro_rep = c(a5, m5, b5, s5))
- atd <- setDT(melt(ant_twas_dat, id.vars = 'study'))
- atd[variable %in% c('g2s_new', 'g2s_rep'), cohort := 'G2S']
- atd[variable %in% c('euro_new', 'euro_rep'), cohort := 'GTEx']
- atd[variable %in% c('Werth_unique'), cohort := 'Werth']
- tots <- atd[, .(value = sum(value)), by = c('variable', 'cohort')]
- tots$study = 'All Conditions'
- atd2 <- rbind(atd, tots)
- #visualize data
- p10 <- ggplot(atd[variable %in% c('g2s_rep', 'euro_rep'),], aes(x = cohort, y = value, color = cohort, fill = cohort)) +
- geom_bar(stat = 'identity', position = 'dodge') +
- geom_label(aes(label = value, y = value +2), fill = "white", color = 'black', label.size = NA) +
- facet_grid(.~study) +
- ylab('Replicated Genes') +
- scale_fill_brewer(palette = 'Dark2') +
- scale_color_brewer(palette = 'Dark2') +
- theme_minimal() +
- theme(axis.text.x = element_text(angle = 60, hjust = 1),
- axis.title.x = element_blank(),
- legend.position = 'none')
- name = 'Output/revisions/werth_rep.pdf'
- pdf(file = name, width = 7, height = 3, pointsize = 12, bg = "white")
- print(p10)
- dev.off()
- print(p10)
- p11 <- ggplot(tots[variable %in% c('g2s_rep', 'euro_rep'),], aes(x = cohort, y = value, color = cohort, fill = cohort)) +
- geom_bar(stat = 'identity', position = 'dodge') +
- geom_label(aes(label = value, y = value +4), fill = "white", color = 'black', label.size = NA) +
- facet_grid(.~study) +
- ylab('Replicated Genes') +
- scale_fill_brewer(palette = 'Dark2') +
- scale_color_brewer(palette = 'Dark2') +
- theme_minimal() +
- theme(axis.text.x = element_text(angle = 60, hjust = 1),
- axis.title = element_blank(),
- legend.position = 'none')
- name = 'Output/revisions/werth_total_rep.pdf'
- pdf(file = name, width = 1.8, height = 3, pointsize = 12, bg = "white")
- print(p11)
- dev.off()
- ```
- ## Pvalue vs Zscore monotonicity
- ### Fig S10: Pvalue change relative to zscores
- ```{r}
- dt <- fread("Data/all_exc_assocs_PGCancestryTWAS.txt", header = T)
- plotdata <- dt[gwas_phenotype == 'PGC_allADHD_2022' & training_model %in% c('PrediXcan_Whole_Blood', 'AA_Whole_Blood')]
- pz_comp <- setDT(merge(plotdata[training_model == 'PrediXcan_Whole_Blood', c('gene_name', 'gwas_phenotype', 'zscore', 'pvalue')],
- plotdata[training_model == 'AA_Whole_Blood', c('gene_name', 'gwas_phenotype', 'zscore', 'pvalue')],
- suffixes = c('.gtex', '.g2s_AA'), by = c('gene_name', 'gwas_phenotype')))
- pz_comp[, zdif := abs(zscore.gtex - zscore.g2s_AA)]
- pz_comp[, pdif := abs(pvalue.gtex - pvalue.g2s_AA)]
- zp_gtg2 <- ggplot(pz_comp, aes(x = zscore.gtex, y = pvalue.g2s_AA)) +
- geom_point(color = 'seagreen')
- zp_g2g2 <- ggplot(pz_comp, aes(x = zscore.g2s_AA, y = pvalue.g2s_AA)) +
- geom_point(color = 'magenta')
- zp_g2gt <- ggplot(pz_comp, aes(x = zscore.g2s_AA, y = pvalue.gtex)) +
- geom_point(color = 'goldenrod2')
- zp_gtgt <- ggplot(pz_comp, aes(x = zscore.gtex, y = pvalue.gtex)) +
- geom_point(color = 'slateblue')
- z_vs_p_plot <- ggarrange(zp_gtg2, zp_g2g2, zp_gtgt, zp_g2gt, ncol = 2, nrow = 2)
- pdf(file = 'Output/revisions/z_vs_p_analysis.pdf', height = 9, width = 9)
- print(z_vs_p_plot)
- dev.off()
- print(z_vs_p_plot)
- #
- zp_gtg2 <- ggplot(pz_comp, aes(x = zscore.gtex, y = pvalue.g2s_AA)) +
- geom_point(color = 'seagreen')
- zp_g2g2 <- ggplot(pz_comp, aes(x = zscore.g2s_AA, y = pvalue.g2s_AA)) +
- geom_point(color = 'magenta')
- zp_g2gt <- ggplot(pz_comp, aes(x = zscore.g2s_AA, y = pvalue.gtex)) +
- geom_point(color = 'goldenrod2')
- zp_gtgt <- ggplot(pz_comp, aes(x = zscore.gtex, y = pvalue.gtex)) +
- geom_point(color = 'slateblue')
- z_vs_p_plot <- ggarrange(zp_gtg2, zp_g2g2, zp_gtgt, zp_g2gt, ncol = 2, nrow = 2)
- pdf(file = 'Output/revisions/z_vs_p_analysis.pdf', height = 9, width = 9)
- print(z_vs_p_plot)
- dev.off()
- pp_gtg2 <- ggplot(pz_comp, aes(x = pvalue.gtex, y = pvalue.g2s_AA)) +
- geom_point(color = 'seagreen')
- pp_g2g2 <- ggplot(pz_comp, aes(x = pvalue.g2s_AA, y = pvalue.g2s_AA)) +
- geom_point(color = 'magenta')
- pp_g2gt <- ggplot(pz_comp, aes(x = pvalue.g2s_AA, y = pvalue.gtex)) +
- geom_point(color = 'goldenrod2')
- pp_gtgt <- ggplot(pz_comp, aes(x = pvalue.gtex, y = pvalue.gtex)) +
- geom_point(color = 'slateblue')
- p_vs_p_plot <- ggarrange(pp_gtg2, pp_g2g2, pp_gtgt, pp_g2gt, ncol = 2, nrow = 2)
- pdf(file = 'Output/revisions/p_vs_p_analysis.pdf', height = 9, width = 9)
- print(p_vs_p_plot)
- dev.off()
- print(p_vs_p_plot)
- zz_gtg2 <- ggplot(pz_comp, aes(x = zscore.gtex, y = zscore.g2s_AA)) +
- geom_point(color = 'seagreen')
- zz_g2g2 <- ggplot(pz_comp, aes(x = zscore.g2s_AA, y = zscore.g2s_AA)) +
- geom_point(color = 'magenta')
- zz_g2gt <- ggplot(pz_comp, aes(x = zscore.g2s_AA, y = zscore.gtex)) +
- geom_point(color = 'goldenrod2')
- zz_gtgt <- ggplot(pz_comp, aes(x = zscore.gtex, y = zscore.gtex)) +
- geom_point(color = 'slateblue')
- z_vs_z_plot <- ggarrange(zz_gtg2, zz_g2g2, zz_gtgt, zz_g2gt, ncol = 2, nrow = 2)
- pdf(file = 'Output/revisions/z_vs_z_analysis.pdf', height = 9, width = 9)
- print(z_vs_z_plot)
- dev.off()
- print(z_vs_z_plot)
- #####
- pzc <- copy(pz_comp)
- pzc[, pdif := pvalue.gtex - pvalue.g2s_AA]
- pzc[, zdif := abs(zscore.gtex) - abs(zscore.g2s_AA)]
- pzc[, zpsign := sign(zdif) * sign(pdif)]
- zmagpplot <- ggplot(pzc, aes(x = zdif, y = pdif)) +
- geom_point()
- pdf(file = 'Output/revisions/deltazmagvsp.pdf', height = 9, width = 9)
- print(zmagpplot)
- dev.off()
- print(zmagpplot)
- azp_gtg2 <- ggplot(pz_comp, aes(x = abs(zscore.gtex), y = pvalue.g2s_AA)) +
- geom_point(color = 'seagreen')
- azp_g2g2 <- ggplot(pz_comp, aes(x = abs(zscore.g2s_AA), y = pvalue.g2s_AA)) +
- geom_point(color = 'magenta')
- azp_g2gt <- ggplot(pz_comp, aes(x = abs(zscore.g2s_AA), y = pvalue.gtex)) +
- geom_point(color = 'goldenrod2')
- azp_gtgt <- ggplot(pz_comp, aes(x = abs(zscore.gtex), y = pvalue.gtex)) +
- geom_point(color = 'slateblue')
- zm_vs_p_plot <- ggarrange(azp_gtg2, azp_g2g2, azp_gtgt, azp_g2gt, ncol = 2, nrow = 2)
- pdf(file = 'Output/revisions/zmag_vs_p_analysis.pdf', height = 9, width = 9)
- print(zm_vs_p_plot)
- dev.off()
- print(zm_vs_p_plot)
- ```
- ## Fig S18-20: Linkage Disequilibrium analyses
- How does linkage disequilibrium affect the relationship of genes that are called significant for a phenotype?
- ```{r}
- lddir <- 'Data/LD_genelists_shared_distinct/'
- assocs <- c ('ENSG00000172247_MX_Whole_Blood_SUD_alc_2019_snps_20',
- # 'ENSG00000237513_AA_Whole_Blood_PGC_ALL_PTSD_2024_snps_15',
- 'ENSG00000237513_AA_Whole_Blood_PGC_all_SCZ_2022_snps_15',
- 'ENSG00000255284_MX_Whole_Blood_PGC_allADHD_2022_snps_17')
- assoc <- c ('ENSG00000172247_MX_Whole_Blood_SUD_alc_2019_snps_20')
- pops <- c('CEU', 'GBR', 'YRI', 'MXL', 'PUR', 'ASW')
- for(assoc in assocs){
- tab_all <- fread(paste0(lddir, 'LD_results2/',assoc,'_LD_all.txt'), header = F)
- tab_all$population <- str_remove(tab_all$V11, '.+:')
- pop_charts <- c()
- for( pop in pops){
- tab <- tab_all[population == pop,]
- head(pop)
- setnames(tab, c('V1', 'V5', 'V9', 'V10'), c('SNP1', 'SNP2', 'R2', 'Dprime'))
- init <- fread(paste0(lddir, assoc, '.txt'), header = T)
- g2s_rsids <- init[!is.na(weight.G2S),]$rsid
- gtex_rsids <- init[!is.na(weight.GTEx),]$rsid
- comp <- tab[, c('SNP1', 'SNP2', 'R2', 'Dprime')]
- comp2 <- comp[(SNP1 %in% g2s_rsids & SNP2 %in% gtex_rsids),]
- comp3 <- comp[(SNP2 %in% g2s_rsids & SNP1 %in% gtex_rsids) , ]
- comp3 <- setnames(comp3, c('SNP2' , 'SNP1'), c('SNP1' , 'SNP2'))
- comp4 <- setDT(rbind(comp2, comp3))
- setnames(comp4, c('SNP1' , 'SNP2'), c('G2S', 'GTEx'))
- mattabl <- matrix(, nrow = length(g2s_rsids), ncol = length(gtex_rsids))
- rownames(mattabl) <- g2s_rsids
- colnames(mattabl) <- gtex_rsids
- for(i in 1:nrow(comp4)){
- g2 <- comp4[i,]$G2S
- gt <- comp4[i,]$GTEx
- r2 <- comp4[i,]$R2
- mattabl[g2, gt] <- r2
- }
- snp_locs1 <- tab[, c(1,2)]
- snp_locs1$pos <- str_remove(snp_locs1$V2, '.+:')
- snp_locs1 <- unique(snp_locs1)
- setnames(snp_locs1, 'SNP1', 'SNP')
- snp_locs2 <- tab[, c(5,6)]
- snp_locs2$pos <- str_remove(snp_locs2$V6, '.+:')
- snp_locs2 <- unique(snp_locs2)
- setnames(snp_locs2, 'SNP2', 'SNP')
- allsnps <- setDT(rbind(snp_locs1[, c('SNP', 'pos')], snp_locs2[, c('SNP', 'pos')]))
- g2_ord <- unique(allsnps[SNP %in% g2s_rsids,])[order(pos)]$SNP
- gt_ord <- unique(allsnps[SNP %in% gtex_rsids,])[order(pos)]$SNP
- comp4$G2S <- factor(comp4$G2S, levels = g2_ord)
- comp4$GTEx <- factor(comp4$GTEx, levels = gt_ord)
- LDplot1 <- ggplot(comp4, aes( x = G2S, y = GTEx, fill = R2)) +
- geom_tile() +
- theme_minimal() +
- ggtitle(pop) +
- scale_fill_distiller(palette = "RdYlGn", direction = 1) +
- theme(axis.text.x = element_text(angle = 40, hjust = 1))
- pop_charts[[pop]] = LDplot1
- }
- name <- paste0('Output/revisions/ALL_', assoc,'_LD_corplots.pdf')
- pdf(file = name, width = 9, height = 10, pointsize = 12, bg = "white")
- do.call(grid.arrange, c(pop_charts, ncol = 2, padding = unit(1, "lines")))
- dev.off()
- }
- #images are output to output directory, not in std out.
- ```
- ### Fig S21: Max R2 to SNP weight comparison
- For each gene, how does the maximum LD between SNPs used in the model compare to the weight of the SNP? We want to assess whether SNPs that are more frequently in LD have greater effects on gene expression.
- ```{r}
- ######## get relationship between max r2 and SNP weight
- library(data.table)
- library(ggplot2)
- library(gridExtra)
- library(stringr)
- lddir <- 'Data/LD_genelists_shared_distinct/'
- assocs <- c('ENSG00000172247_MX_Whole_Blood_SUD_alc_2019_snps_20',
- #'ENSG00000237513_AA_Whole_Blood_PGC_ALL_PTSD_2024_snps_15',
- 'ENSG00000237513_AA_Whole_Blood_PGC_all_SCZ_2022_snps_15',
- 'ENSG00000255284_MX_Whole_Blood_PGC_allADHD_2022_snps_17')
- pops <- c('CEU', 'GBR', 'YRI', 'MXL', 'PUR', 'ASW')
- all_dat <- list.files('Data/rdata', pattern = '.+\\.txt')
- snp_dat <- data.table()
- for(fil in str_subset(all_dat, '^snp_dat_all.+\\.txt')){
- newdat <- fread(paste0('Data/rdata/', fil), header = T)
- snp_dat <- rbind(snp_dat , newdat)
- }
- #initiate data.table to hold r2 and pvalue results
- cordat <- data.table(association = c(), gene = c(), training_model = c(), gwas_phenotype = c(), population = c(), group = c(), adj.r.squared = c(), lm_pvalue = c())
- #initiate data.table to hold all points from plots
- fulldata <- data.table()
- for(assoc in assocs){
- tab_all <- fread(paste0(lddir, 'LD_results2/',assoc,'_LD_all.txt'), header = F)
- tab_all$population <- str_remove(tab_all$V11, '.+:')
- gene_nm <- str_remove(assoc, '_.+')
- mod1 <- str_remove(assoc, paste0(gene_nm , '_'))
- mod <- str_remove(mod1, '_PGC.+')
- mod <- str_remove(mod, '_SUD.+')
- phen1 <- str_remove(assoc, paste0(gene_nm , '_', mod, '_'))
- phen <- str_remove(phen1, '_snps.+')
- sdat <- snp_dat[gene == gene_nm & (model == mod & gwas_phenotype == phen),]
- pop_charts2 <- c()
- for( pop in pops){
- tab <- tab_all[population == pop,]
- head(pop)
- setnames(tab, c('V1', 'V5', 'V9', 'V10'), c('SNP1', 'SNP2', 'R2', 'Dprime'))
- init <- fread(paste0(lddir, assoc, '.txt'), header = T)
- g2s_rsids <- init[!is.na(weight.G2S),]$rsid
- gtex_rsids <- init[!is.na(weight.GTEx),]$rsid
- comp <- tab[, c('SNP1', 'SNP2', 'R2', 'Dprime')]
- comp2 <- comp[(SNP1 %in% g2s_rsids & SNP2 %in% gtex_rsids),]
- comp3 <- comp[(SNP2 %in% g2s_rsids & SNP1 %in% gtex_rsids) , ]
- comp3 <- setnames(comp3, c('SNP2' , 'SNP1'), c('SNP1' , 'SNP2'))
- comp4 <- setDT(rbind(comp2, comp3))
- setnames(comp4, c('SNP1' , 'SNP2'), c('G2S', 'GTEx'))
- g2s_max1 <- comp4[, .(maxr2 = max(R2)), by = 'G2S']
- gtex_max1 <- comp4[, .(maxr2 = max(R2)), by = 'GTEx']
- g2s_max <- setDT(merge(g2s_max1, sdat[, c('rsid', 'weight.G2S')], by.x = 'G2S', by.y = 'rsid'))
- g2s_max$group <- 'G2S'
- gtex_max <- setDT(merge(gtex_max1, sdat[, c('rsid', 'weight.GTEx')], by.x = 'GTEx', by.y = 'rsid'))
- gtex_max$group <- 'GTEx'
- setnames(g2s_max, c('G2S', 'weight.G2S'), c('SNP', 'weight'))
- setnames(gtex_max, c('GTEx', 'weight.GTEx'),c('SNP', 'weight'))
- lmg2s = lm(abs(g2s_max$weight)~g2s_max$maxr2)
- lmgtex = lm(abs(gtex_max$weight)~gtex_max$maxr2)
- newdat_g2s = data.table(association = assoc,
- gene = gene_nm,
- training_model = mod,
- gwas_phenotype = phen,
- population = pop,
- group = 'G2S',
- adj.r.squared = summary(lmg2s)$adj.r.squared,
- lm_pvalue = summary(lmg2s)$coefficients[2,4])
- newdat_gtex = data.table(association = assoc,
- gene = gene_nm,
- training_model = mod,
- gwas_phenotype = phen,
- population = pop,
- group = 'GTEx',
- adj.r.squared = summary(lmgtex)$adj.r.squared,
- lm_pvalue = summary(lmgtex)$coefficients[2,4])
- cordat <- rbind(cordat, newdat_g2s)
- cordat <- rbind(cordat, newdat_gtex)
- plotdata <- setDT(rbind(g2s_max, gtex_max))
- plotdata[, association := assoc]
- plotdata[, population := pop]
- fulldata <- setDT(rbind(fulldata, plotdata))
- }
- }
- write.table(cordat, file = paste0(lddir, 'LD_results2/all_results_correlation_data.txt'), col.names = T, row.names = F, quote = F, sep = '\t')
- write.table(fulldata, file = paste0(lddir, 'LD_results2/all_results_r2byweight_data.txt'), col.names = T, row.names = F, quote = F, sep = '\t')
- ld_all <- fread(paste0(lddir, 'LD_results2/all_results_r2byweight_data.txt'), header = T)
- lda_lm <- lm(data = ld_all, abs(weight)~maxr2 + association)
- lda_lm2 <- lm(data = ld_all, abs(weight)~maxr2 + association + population)
- lda_lm3 <- lm(data = ld_all, abs(weight)~maxr2 + population)
- allplot <- ggplot(ld_all, aes(x = maxr2, y = abs(weight), color = association)) +
- geom_smooth(method = "lm", color = "grey70") +
- geom_point() +
- theme_minimal() +
- facet_wrap(.~population) +
- guides(color = guide_legend(nrow = 3)) +
- theme(legend.position = 'bottom')
- name <- paste0('Output/revisions/ALL_LD_corplots_weights.pdf')
- pdf(file = name, width = 6, height = 6, pointsize = 12, bg = "white")
- print(allplot)
- dev.off()
- print(allplot)
- ```
- ## Correlogram and heatmap in fig 5
- ### Fig 5: Updated correlogram and heatmap
- ```{r}
- library(data.table)
- library(corrplot)
- dt_ <- fread("Data/all_exc_assocs_PGCancestryTWAS.txt", header = T)
- # exclude replication/comparison data from initial analysis.
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024')
- mod <- c('PrediXcan_Brain_Cortex')
- dt <- dt_[!(gwas_phenotype %in% c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024', 'PGC_LATINO_SCZ_2022', 'PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022')) & training_model != 'PrediXcan_Brain_Cortex',]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- dt1 <- dt[!training_model == 'PrediXcan_Whole_Blood']
- dt2 <- dt[training_model == 'PrediXcan_Whole_Blood']
- # Clean gene names in both datasets
- MAtwas <- dt2
- MUtwas <- dt1
- # Get unique training models from MUtwas and add GTEX from MAtwas
- training_models <- unique(MUtwas$training_model)
- training_models <- c(training_models, 'PrediXcan_Whole_Blood')
- # Define a custom color palette
- custom_colors <- colorRampPalette(c("#1a9850","#1a9850", "#ffffbf", "#d73027"))(1000)
- # Open a PDF device with Letter dimensions
- pdf('Output/revisions/correlograms.pdf', width = 5, height = 5.5)
- for (model in training_models[1]) {
- # Filter data for the current training model
- if (model == 'PrediXcan_Whole_Blood') {
- filtered_data <- MAtwas[training_model == model, .(gwas_phenotype, gene, zscore)]
- } else {
- filtered_data <- MUtwas[training_model == model, .(gwas_phenotype, gene, zscore)]
- }
- unique_genes <- unique(filtered_data$gene)
- unique_phenotypes <- unique(filtered_data$gwas_phenotype)
- matrix_data <- matrix(NA, nrow = length(unique_genes), ncol = length(unique_phenotypes))
- rownames(matrix_data) <- unique_genes
- dz_names <- c('PGC_allADHD_2022' = 'ADHD',
- 'PGC_all_SCZ_2022' = 'SCZ',
- 'PGC_allMDD_2023' = 'MDD',
- 'PGC_BD1_2021' = 'BD1',
- 'SUD_alc_2019' = 'SUD-A',
- 'PGC_ALL_PTSD_2024' = 'PTSD')
- colnames(matrix_data) <- unique_phenotypes
- colnames(matrix_data) <- dz_names[colnames(matrix_data)]
- for (i in 1:nrow(filtered_data)) {
- row <- filtered_data[i, ]
- matrix_data[row$gene, dz_names[row$gwas_phenotype]] <- row$zscore
- }
- cor_matrix <- cor(matrix_data, use = "pairwise.complete.obs")
- cor_matrix[cor_matrix == 1.0] <- NA
- # Adjust plot margins to accommodate longer titles
- par(mar = c(1, 1, 5, 1))
- corrplot(corr = cor_matrix,
- method = "circle",
- type = "lower",
- #tl.pos = "tl",
- order = "original",
- tl.col = 'black',
- diag = FALSE,
- is.corr = FALSE,
- col.lim = range(cor_matrix, na.rm = T),
- col = custom_colors, # Use custom colors
- title = paste("Correlation plot for training model:", model),
- mar = c(0, 0, 2, 0)) # Adjust margins to fit the title
- }
- # Close the PDF device
- dev.off()
- ```
- ```{r}
- # and heat map too
- cleardups <- function(t1){
- otpt <- t1[2,]
- for(nn in 3:nrow(t1)){
- d1 <- t1[nn,1]
- d2 <- t1[nn,2]
- d_combo <- paste0(d1, d2)
- d_combo2 <- paste0(d2, d1)
- if( d_combo %in% paste0(otpt[[1]], otpt[[2]]) | d_combo2 %in% paste0(otpt[[1]], otpt[[2]])){
- #print(TRUE)
- } else if(d1 != d2){
- #print(FALSE)
- otpt <- setDT(rbind(otpt, t1[nn,]))
- }
- }
- otpt[1 != 2,]
- otpt[[3]] <- rank(-otpt[[3]])
- return(otpt)
- }
- load('Data/correlation_matrices/AA_Whole_Blood_cor_matrix.rdata')
- cortab <- as.data.table(cor_matrix)
- cortab$disease1 <- rownames(cor_matrix)
- cortab <- setnames(melt(cortab, id.vars = 'disease1', value.name = 'G2S_AA'), 'variable', 'disease2')
- cortab$disease2 <- as.character(cortab$disease2)
- cortab <- cleardups(cortab)
- AA_cor <- copy(cortab)
- load('Data/correlation_matrices/All_Whole_Blood_cor_matrix.rdata')
- cortab <- as.data.table(cor_matrix)
- cortab$disease1 <- rownames(cor_matrix)
- cortab <- setnames(melt(cortab, id.vars = 'disease1', value.name = 'G2S_All'), 'variable', 'disease2')
- cortab$disease2 <- as.character(cortab$disease2)
- cortab <- cleardups(cortab)
- All_cor <- copy(cortab)
- load('Data/correlation_matrices/MX_Whole_Blood_cor_matrix.rdata')
- cortab <- as.data.table(cor_matrix)
- cortab$disease1 <- rownames(cor_matrix)
- cortab <- setnames(melt(cortab, id.vars = 'disease1', value.name = 'G2S_MX'), 'variable', 'disease2')
- cortab$disease2 <- as.character(cortab$disease2)
- cortab <- cleardups(cortab)
- MX_cor <- copy(cortab)
- load('Data/correlation_matrices/PR_Whole_Blood_cor_matrix.rdata')
- cortab <- as.data.table(cor_matrix)
- cortab$disease1 <- rownames(cor_matrix)
- cortab <- setnames(melt(cortab, id.vars = 'disease1', value.name = 'G2S_PR'), 'variable', 'disease2')
- cortab$disease2 <- as.character(cortab$disease2)
- cortab <- cleardups(cortab)
- PR_cor <- copy(cortab)
- load('Data/correlation_matrices/PrediXcan_Whole_Blood_cor_matrix.rdata')
- cortab <- as.data.table(cor_matrix)
- cortab$disease1 <- rownames(cor_matrix)
- cortab <- setnames(melt(cortab, id.vars = 'disease1', value.name = 'GTEx_WB'), 'variable', 'disease2')
- cortab$disease2 <- as.character(cortab$disease2)
- cortab <- cleardups(cortab)
- GT_cor <- copy(cortab)
- multicor <- data.table()
- multicor <- setDT(merge(AA_cor, All_cor, by = c('disease1', 'disease2')))
- multicor <- setDT(merge(multicor, MX_cor, by = c('disease1', 'disease2')))
- multicor <- setDT(merge(multicor, PR_cor, by = c('disease1', 'disease2')))
- multicor <- setDT(merge(multicor, GT_cor, by = c('disease1', 'disease2')))
- rowmean <- rowMeans(multicor[,-c(1,2)])
- multicor$mean <- rowmean
- multicor$traits = paste0(multicor$disease1, ' - ', multicor$disease2)
- mcL <- setDT(melt(multicor, id.vars = c('disease1', 'disease2', 'traits')))
- order_vec <- mcL[variable == 'mean', c('variable', 'value', 'traits')][order(-value)]$traits
- mcL$traits <- factor(mcL$traits, levels = order_vec)
- cor_rank <- ggplot(mcL[variable != 'mean',], aes(x = variable, y = traits, fill = value)) +
- geom_tile(color = 'black') +
- geom_text(aes(label = value)) +
- scale_fill_distiller(palette = "RdYlGn", direction = 1) +
- xlab('model') +
- ylab('disease pair')+
- labs(fill = "Correlation\nRanking") +
- theme_minimal() +
- theme(axis.text.x = element_text(angle = 40, hjust = 1))
- name = 'Output/revisions/mod_cor_rank.pdf'
- pdf(file = name, width = 6.5, height = 6, pointsize = 12, bg = "white")
- print(cor_rank)
- dev.off()
- print(cor_rank)
- ```
- ### Figure S26: brain model vs whole blood model comparison
- ```{r}
- # Create comparison for brain vs G2S vs whole blood GTEx
- # Read in all significant data and subset GWAS findings of interest
- sig <- fread('Data/all_exc_BHsig_assocs_PGCancestryTWAS.txt', header = T)
- dt <- sig[!(gwas_phenotype %in% c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022')),]
- dt[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dt[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dt[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dt[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dt[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- dt[training_model == 'PrediXcan_Brain_Cortex', `gene expression model` := 'GTEx European Brain']
- G2S_mods <- c('All_Whole_Blood', 'AA_Whole_Blood', 'MX_Whole_Blood', 'PR_Whole_Blood')
- mod_dz_tabl <- data.table()
- for( dz in unique(dt$gwas_phenotype)){
- gns <- unique(dt[gwas_phenotype == dz,]$gene_name)
- temp <- data.table( gwas_phenotype = dz, gene_name = gns )
- temp[, GTEx_WB := gene_name %in% unique(dt[gwas_phenotype == dz & training_model == 'PrediXcan_Whole_Blood',]$gene_name)]
- temp[, GTEx_Brain := gene_name %in% unique(dt[gwas_phenotype == dz & training_model == 'PrediXcan_Brain_Cortex',]$gene_name)]
- temp[, G2S := gene_name %in% unique(dt[gwas_phenotype == dz & training_model %in% G2S_mods,]$gene_name)]
- temp[ (GTEx_WB == F & GTEx_Brain == F) & G2S == F, type := 'none']
- temp[ (GTEx_WB == F & GTEx_Brain == F) & G2S == T, type := 'G2S_only']
- temp[ (GTEx_WB == F & GTEx_Brain == T) & G2S == F, type := 'GTEx brain only']
- temp[ (GTEx_WB == F & GTEx_Brain == T) & G2S == T, type := 'GTEx_brain + G2S']
- temp[ (GTEx_WB == T & GTEx_Brain == F) & G2S == F, type := 'GTEx_WB only']
- temp[ (GTEx_WB == T & GTEx_Brain == F) & G2S == T, type := 'GTEx_WB + G2S']
- temp[ (GTEx_WB == T & GTEx_Brain == T) & G2S == F, type := 'GTEx_WB + GTEx_brain']
- temp[ (GTEx_WB == T & GTEx_Brain == T) & G2S == T, type := 'all']
- newtemp <- temp[, .(.N), by = type]
- newtemp[, gwas_phenotype := dz]
- mod_dz_tabl <- rbind(mod_dz_tabl, newtemp)
- }
- mod_typs <- ggplot(mod_dz_tabl, aes(x = type, y = N, fill = type)) +
- geom_bar(stat = 'identity') +
- facet_wrap(gwas_phenotype~., nrow = 3) +
- theme(axis.text.x = element_text(angle = 60, hjust = 1))
- pdf(file = 'Output/revisions/mod_types_brain.pdf', height = 12, width = 10)
- print(mod_typs)
- dev.off()
- print(mod_typs)
- mod_typs2 <- ggplot(mod_dz_tabl[type %in% c('GTEx_brain + G2S', 'GTEx brain only')], aes(x = type, y = N, fill = type)) +
- geom_bar(stat = 'identity') +
- facet_wrap(gwas_phenotype~., nrow = 3, scales = 'free_y') +
- theme(axis.text.x = element_text(angle = 60, hjust = 1))
- pdf(file = 'Output/revisions/mod_types_brain2.pdf', height = 10, width = 6)
- print(mod_typs2)
- dev.off()
- print(mod_typs2)
- newmod <- mod_dz_tabl[type %in% c('GTEx_brain + G2S', 'GTEx brain only')]
- sums <- newmod[, .(sum = sum(N)), by = 'gwas_phenotype']
- newmod1 <- setDT(merge(newmod, sums, by = 'gwas_phenotype'))
- newmod1[, percentage := N / sum]
- mod_typs3 <- ggplot(newmod1, aes(x = gwas_phenotype, y = percentage, fill = type, color = type)) +
- geom_bar(stat = 'identity', position = 'stack') +
- geom_label(data = newmod1[type == 'GTEx_brain + G2S',], aes(x = gwas_phenotype, y = percentage - 0.06, label = round(percentage, 3)), fill = 'white', show.legend = F)+
- #facet_wrap(gwas_phenotype~., nrow = 3) +
- theme_minimal() +
- theme(axis.text.x = element_text(angle = 45, hjust = 1))
- pdf(file = 'Output/revisions/mod_types_brain3.pdf', height = 4, width = 7)
- print(mod_typs3)
- dev.off()
- print(mod_typs3)
- ```
- # Revisions Round 2
- ### Cell-type gene expression analysis using DEGs
- ```{r}
- library(data.table)
- library(ggplot2)
- dt_ <- fread('Data/trimmed_means.csv', header = T)
- dt <- dt_[!(rowSums(dt_[,-1] == 0)),]
- genes <- dt[[1]]
- expr_mat <- as.matrix(dt[, -1])
- rownames(expr_mat) <- genes
- cell_types <- colnames(expr_mat)
- # Row-wise z-score (across cell types, per gene)
- expr_scaled <- t(scale(t(expr_mat)))
- # scale() works column-wise, so transpose, scale, transpose back
- # Now each gene has mean=0, sd=1 across cell types
- # Build results table
- results <- rbindlist(lapply(cell_types, function(ct) {
- data.table(
- gene = genes,
- cell_type = ct,
- expr = expr_mat[, ct], # raw trimmed mean (log2 CPM)
- z_score = expr_scaled[, ct], # how extreme vs other cell types
- log2fc = expr_mat[, ct] - rowMeans(expr_mat[, cell_types != ct])
- # log2FC: already in log space so subtraction = fold change
- )
- }))
- # Convert z-score to p-value and correct for multiple testing
- results[, p_nominal := 2 * pnorm(-abs(z_score))]
- results[, p_adj := p.adjust(p_nominal, method = "BH")]
- # Filter to DEGs: significant + meaningfully upregulated
- degs <- results[
- p_adj < 0.05 & # statistically specific
- log2fc > 1 & # at least 2-fold above mean of other cell types
- expr > 1 # expressed at least log2(CPM) > 1 in this cell type
- ][order(cell_type, -z_score)]
- # How many DEGs per cell type?
- degs[, .N, by = 'cell_type'][order(-N)]
- ```
- ```{r}
- # write top findings to output file
- top_markers <- degs[, head(.SD, 10), by = cell_type, .SDcols = names(degs)[-2]]
- write.table(top_markers, 'Output/revisions2/cell/brain_degs.txt', col.names = T, row.names = F, quote = F)
- ```
- ### Cell type enrichment analysis
- ```{r}
- sdt_ <- fread('Data/all_exc_BHsig_assocs_PGCancestryTWAS.txt', header = TRUE)
- gwas <- c('PGC_AA_MDD_2023', 'PGC_AA_PTSD_2024','PGC_AA_SCZ_2022','PGC_ASIAN_SCZ_2022','PGC_EUR_PTSD_2024','PGC_HNA_PTSD_2024', 'PGC_EURO_SCZ_2022')
- mod <- c('PrediXcan_Brain_Cortex')
- sdt <- sdt_[!(gwas_phenotype %in% gwas | training_model %in% mod),]
- overlap_b <- merge(
- sdt[, .(`gene_name`, gwas_phenotype)],
- top_markers[, .(`gene`, `cell_type`)],
- by.x = "gene_name",
- by.y = "gene",
- allow.cartesian = TRUE
- )
- # Count overlaps for each disease × cell_type pair
- result_b <- overlap_b[, .(n_genes = uniqueN(gene_name), genes = paste(unique(gene_name), collapse = '|')), by = c('gwas_phenotype', 'cell_type')]
- write.table(result_b, 'Output/revisions2/cell/disease_cell_types_brain.txt', col.names = T, row.names = F, quote = F, sep = '\t')
- ```
- ### Cell type overlap with DEGs from brain
- ```{r}
- dt <- copy(sdt)
- pg <- fread('Data/PanglaoDB_markers_27_Mar_2020.tsv', header = T)
- overlap <- merge(
- dt[, .(`gene_name`, gwas_phenotype)],
- pg[, .(`official gene symbol`, `cell type`)],
- by.x = "gene_name",
- by.y = "official gene symbol",
- allow.cartesian = TRUE
- )
- # Count overlaps for each disease × cell_type pair
- result <- overlap[, .(n_genes = uniqueN(gene_name), genes = paste(unique(gene_name), collapse = '|')), by = c('gwas_phenotype', 'cell type')]
- duo <- intersect(overlap$gene_name, overlap_b$gene_name)
- combo <- result[sapply(strsplit(genes, "\\|"), function(g) any(g %in% duo))]
- write.table(combo, 'Output/revisions2/cell/disease_cell_types_brain_DuoDEGs.txt', col.names = T, row.names = F, quote = F, sep = '\t')
- combo
- ```
- # Genetic Ancestry and SNP predictors
- First I want to get all the SNPs used by GTEx and G2S and annotate them with population specific allele frequencies.
- ```{r}
- otpt <- 'Output/revisions2/allelefreq/'
- dir.create(otpt)
- # read in 1000 genomes allele frequency data and SNP annotations
- rsids <- fread('Data/all_rsid_locs_af_anc.annovar.hg38_multianno.txt', header = T)
- anno_ <- fread('Data/all_snplist_avsnp151_convert.avinput', header = F)
- anno <- setNames(anno_, c('Chr', 'Start', 'End', 'Ref', 'Alt', 'rsid'))
- freq <- setDT(merge(anno, rsids, by = c('Chr', 'Start', 'End', 'Ref', 'Alt')))
- # Read in all SNP data from GTEx and G2S models
- all_snps <- fread('Data/all_snpdata.txt', header = T)
- # remove multi-allelic SNPs for now.
- multi_allelic <- freq[, .(.N), by = 'rsid'][N > 1]$rsid
- #annotate GTEx and G2S SNPs and rename columns
- dt_ <- setDT(merge(all_snps, freq[!(rsid %in% multi_allelic),], by = 'rsid'))
- setnames(dt_, c('gnomad41_genome_AF', 'gnomad41_genome_AF_afr', 'gnomad41_genome_AF_ami', 'gnomad41_genome_AF_amr', 'gnomad41_genome_AF_asj', 'gnomad41_genome_AF_eas', 'gnomad41_genome_AF_fin', 'gnomad41_genome_AF_mid', 'gnomad41_genome_AF_nfe', 'gnomad41_genome_AF_sas'),
- c('ALL', 'AFR', 'AMISH', 'ADM_AMR', 'ASHKENAZI', 'E_ASIAN', 'FINN', 'MIDEAST', 'EUR', 'S_ASIAN'))
- cols <- c(names(all_snps),c('Ref', 'Alt', 'ALL', 'AFR', 'AMISH', 'ADM_AMR', 'ASHKENAZI', 'E_ASIAN', 'FINN', 'MIDEAST', 'EUR', 'S_ASIAN'))
- dt <- dt_[, ..cols]
- dt <- dt %>% mutate_at(c('ALL', 'AFR', 'AMISH', 'ADM_AMR', 'ASHKENAZI', 'E_ASIAN', 'FINN', 'MIDEAST', 'EUR', 'S_ASIAN'), as.numeric)
- # get magnitude of difference between African and european allele frequency.
- dt <- dt[, afr_eu_dif := abs(dt$AFR - dt$EUR)][!is.na(afr_eu_dif),]
- # first, get weights that are not shared and assess the AF difference between the two groups
- dt[shared == TRUE, type := 'shared']
- dt[shared == FALSE & !is.na(weight.G2S), type := 'G2S']
- dt[shared == FALSE & !is.na(weight.GTEx), type := 'GTEx']
- #SNP data table created
- ```
- next I want to add the weights for each SNP-gene combination.
- ATTN: You will have to download the following models from the kachuri et al zenodo page located at the following address:
- - AA.cis-eQTL.tar.gz
- -after unzipping the tarball, the file for AA will be ._gala.sage.AA_Whole_Blood_tw_0.5_signif.db. I renamed this to AA_Whole_Blood.db and put it in [KACHURI_MODELS_DIR]
- - MX.cis-eQTL.tar.gz
- - PR.cis-eQTL.tar.gz
- - All.cis-eQTL.tar.gz
- [https://zenodo.org/records/7735723]
- The gtex model can be found here
- - PrediXcan_Whole_Blood.db
- [https://zenodo.org/records/3842289]
- ```{r}
- # Extract weights from all SNPs in the models of interest
- aamod <- '[KACHURI_MODELS_DIR]/AA_Whole_Blood.db'
- allmod <- '[KACHURI_MODELS_DIR]/All_Whole_Blood.db'
- mamod <- '[KACHURI_MODELS_DIR]/MX_Whole_Blood.db'
- prmod <- '[KACHURI_MODELS_DIR]/PR_Whole_Blood.db'
- gtmod <- '[GTEx_MODELS_DIR]/db/PrediXcan_Whole_Blood.db'
- mods <- data.table(modpath = c(aamod, allmod, mamod, prmod),
- modnm = c('G2S_aa', 'G2S_all', 'G2S_mx', 'G2S_pr'),
- modlongnm = c('AA_Whole_Blood', 'All_Whole_Blood', 'MX_Whole_Blood', 'PR_Whole_Blood'))
- gtx <- dbConnect(RSQLite::SQLite(), gtmod)
- gtx_weight <- setDT(dbReadTable(gtx, 'weights'))
- dbDisconnect(gtx)
- g2s <- data.table()
- for(modp in mods$modpath) {
- # first read in the model data
- mod <- dbConnect(RSQLite::SQLite(), modp)
- mod_weight <- setDT(dbReadTable(mod, 'weights'))
- nm <- mods[modpath == modp,]$modlongnm
- mod_weight$training_model <- nm
- mod_weight$gene <- str_remove(mod_weight$gene, '\\..+')
- g2s <- rbind(g2s, mod_weight)
- dbDisconnect(mod)
- }
- gtx_weight$training_model <- 'GTEx'
- ```
- Now having gotten the weights and the SNPs, I want to harmonize the SNPs for the sake of merging. the ref and alt alleles may not be the same across G2S and GTEx. When this is the case, the weight is inaccurate. I need to find the matching and flipped alleles and then adjust the weight accordingly.
- ```{r}
- #check rsid matching gtex vs g2s
- g2s_rsid <- unique(g2s[, c('rsid', 'ref_allele','eff_allele')])
- gtx_rsid <- unique(gtx_weight[, c('rsid', 'ref_allele','eff_allele')])
- dim(g2s_rsid)
- length(unique(g2s_rsid$rsid))
- # one rsid per rsid/ref/alt grouping
- dim(gtx_rsid)
- length(unique(gtx_rsid$rsid))
- # same for gtex
- length(intersect(gtx_rsid$rsid, g2s_rsid$rsid))
- #52,284 shared rsids
- #merge across rsid, ref, and alt,
- rsid_both <- setDT(merge(gtx_rsid, g2s_rsid, by = c('rsid', 'ref_allele', 'eff_allele')))
- rsid2 <- intersect(gtx_rsid$rsid, g2s_rsid$rsid)
- discordant <- setDT(rbind(gtx_rsid, g2s_rsid))[rsid %in% rsid2 & !(rsid %in% rsid_both$rsid),][order(rsid)]
- # get all aligned SNP weights
- all_rsids <- setDT(rbind(gtx_rsid, g2s_rsid))[ !(rsid %in% discordant$rsid),]
- ## Harmonize SNPs across GTEx and G2S
- # Subset the used rsids by those that have consistent ref and eff alleles
- # then get the frequencies relying on both rsid, ref, and alt
- dt_same_ <- setDT(merge(dt, all_rsids, by.x = c('rsid', 'Ref', 'Alt'), by.y = c('rsid' ,'ref_allele', 'eff_allele')))
- dt_same_$allele_order <- 'match'
- dt_dif_ <- setDT(merge(dt, all_rsids, by.x = c('rsid', 'Alt', 'Ref'), by.y = c('rsid' ,'ref_allele', 'eff_allele')))
- dt_dif_$allele_order <- 'flip'
- # adjust allele frequencies (assuming biallelic SNPs)
- af_cols <- c('ALL', 'AFR', 'AMISH', 'ADM_AMR', 'ASHKENAZI', 'E_ASIAN', 'FINN', 'MIDEAST', 'EUR', 'S_ASIAN')
- dt_dif_[ , (af_cols) := lapply(.SD, function(x) 1-x), .SDcols = af_cols]
- # adjust weights for opposite direction of effect
- dt_dif_$weight.G2S <- -1 * dt_dif_$weight.G2S
- dt_dif_$weight.GTEx <- -1 * dt_dif_$weight.GTEx
- # join all
- dt2 <- unique(setDT(rbind(dt_same_, dt_dif_)))
- ## Now we can treat the allele frequencies as true values rather than just the differences
- dt2a <- dt2[model == 'All_Whole_Blood',]
- dt2a
- ```
- Now that I have harmonized and annotated the SNPs of interest with allele frequencies, I want to begin characterizing the genes according to aggregate statistics derived from the SNP predictors.
- ```{r}
- # Read in all eQTL data
- eqtldat <- fread('Data/eQTL_data_all.txt', header = T)
- eqtldat[is.na(weight.G2S), snptype := 'GTEx_SNP']
- eqtldat[is.na(weight.GTEx), snptype := 'G2S_SNP']
- eqtldat[is.na(snptype), snptype := 'shared_SNP']
- edat_type <- eqtldat[Significant == 'Significant', .(.N, N_genes = length(unique(gene))), by = c('gwas_phenotype', 'snptype', 'category')][order(gwas_phenotype)]
- # plot each gene. data is percentage of SNPs that are G2S specific
- eqtldat[snptype == 'GTEx_SNP', snptype_q := -1]
- eqtldat[snptype == 'shared_SNP', snptype_q := 0]
- eqtldat[snptype == 'G2S_SNP', snptype_q := 1]
- edat_prop <- eqtldat[ Significant == 'Significant', .(type_quant = sum(snptype_q)), by = c('gwas_phenotype', 'category', 'gene')]
- eqtldat[, category_collapsed := fct_collapse(category,
- "G2S" = c("G2S only", "G2S co-tested"),
- "GTEX" = c("GTEX WB co-tested"),
- "Shared" = c("co-significant")
- )]
- gene_features <- eqtldat[, .(
- # SNP counts
- n_snps = .N,
- # model-specific SNP counts
- n_g2s_snps = sum(!is.na(weight.G2S)),
- n_gtex_snps = sum(!is.na(weight.GTEx)),
- # proportions
- prop_g2s_snps = mean(!is.na(weight.G2S)),
- prop_gtex_snps = mean(!is.na(weight.GTEx)),
- # weights
- mean_g2s_weight_magnitude = mean(abs(weight.G2S), na.rm = TRUE),
- mean_gtex_weight_magnitude = mean(abs(weight.GTEx), na.rm = TRUE),
- # MAF
- mean_afr_maf = mean(AFR, na.rm = TRUE),
- mean_eur_maf = mean(EUR, na.rm = TRUE),
- mean_afr_eur_maf_diff = mean(abs(AFR -EUR), na.rm = TRUE),
- n_maf_diff_over_0.3 = sum(AFR-EUR > 0.3, na.rm = TRUE), #total number of SNPs with maf dif > 0.3
- mean_afr_maf_weighted = mean(AFR*abs(weight.G2S), na.rm = TRUE),
- mean_eur_maf_weighted = mean(EUR*abs(weight.GTEx), na.rm = TRUE),
- mean_maf_diff_weighted = mean(AFR*abs(weight.G2S), na.rm = TRUE)-mean(EUR*abs(weight.GTEx), na.rm = TRUE),
- # SNP type composition
- prop_common = mean(SNP_type == "COMMON"),
- prop_rare = mean(SNP_type == "RARE"),
- prop_afr_specific = mean(SNP_type == "AFR"),
- prop_eur_specific = mean(SNP_type == "EUR"),
- n_afr_specific = sum(SNP_type == "AFR"),
- n_eur_specific = sum(SNP_type == "EUR")
- ), by = .(gene, gwas_phenotype, category_collapsed)]
- dt <- gene_features[gwas_phenotype == "PGC_all_SCZ_2022",]
- dt$category_collapsed <- as.factor(dt$category_collapsed)
- dt[is.nan(mean_gtex_weight_magnitude), mean_gtex_weight_magnitude := 0]
- dt[is.nan(mean_g2s_weight_magnitude), mean_g2s_weight_magnitude := 0]
- ```
- Now we have data on the SNP characteristics for each gene involved in gene-trait associations. Next I want to figure out how the SNP characteristics differ for genes that were significantly associated with Schizophrenia in different models.
- ```{r}
- # Melt to long format for plotting
- features_of_interest <- names(dt)[-c(1:3)]
- gf_long <- melt(dt[category_collapsed != "None"],
- id.vars = "category_collapsed",
- measure.vars = features_of_interest)
- # Violin plots - distribution of each feature by category
- ff <- ggplot(gf_long, aes(x = category_collapsed, y = value,
- fill = category_collapsed)) +
- geom_violin(alpha = 0.7) +
- geom_boxplot(width = 0.1, outlier.shape = NA) +
- facet_wrap(~variable, scales = "free_y") +
- theme_minimal() +
- labs(title = "Feature distributions by association category",
- x = NULL, y = NULL) +
- theme(legend.position = "none",
- axis.text.x = element_text(angle = 45, hjust = 1))
- name = 'Output/revisions2/all_measures_SCZ.png'
- png(filename = name, width = 11, height = 6, units = "in", pointsize = 12, bg = "white", type = 'cairo', res = 600)
- print(ff)
- dev.off()
- print(ff)
- ```
- ### Fig S4: Odds ratios for G2S vs GTEx significance
- ```{r}
- library(coin) # for permutation tests - robust with small groups
- # The key scientific contrasts
- # G2S only vs None: what makes a gene significant in G2S?
- # G2S only vs Shared: what makes a gene G2S-exclusive vs both?
- # GTEX only vs Shared: what makes a gene GTEx-exclusive?
- # For each feature, test G2S vs GTEX vs Shared
- kruskal_results <- dt[category_collapsed != "None",
- lapply(.SD, function(x) kruskal.test(x ~ category_collapsed)$p.value),
- .SDcols = features_of_interest]
- # Tidy it up
- kruskal_long <- setDT(melt(kruskal_results, variable.name = "feature",
- value.name = "p_value"))
- kruskal_long[, p_adj := p.adjust(p_value, method = "BH")]
- kruskal_long[, `-log10 p_adj` := -1*log10(p_adj)]
- kruskal_long[order(p_adj)]
- kruskal_long[, Significance := fifelse(p_adj <= 0.05, "Sig", "Insig")]
- f1 <- ggplot(data = kruskal_long, aes(x = feature, y = `-log10 p_adj`, color = Significance, shape = Significance)) +
- geom_segment( aes(x=feature, xend=feature, y=0, yend=`-log10 p_adj`), color="grey") +
- geom_point(size=4) +
- theme_minimal() +
- coord_flip()
- name = 'Output/revisions2/all_measures_SCZ_kruskal.png'
- png(filename = name, width = 6, height = 6, units = "in", pointsize = 12, bg = "white", type = 'cairo', res = 600)
- print(f1)
- dev.off()
- print(f1)
- ```
- ### Fig S3: Print significantly different features with DOE
- ```{r}
- # Get significant features first
- sig_features <- kruskal_long[p_adj <= 0.05, as.character(feature)]
- dtz <- copy(dt)
- dtz[, (sig_features) := lapply(.SD, scale), .SDcols =sig_features]
- # Pairwise Wilcoxon for each significant feature
- # The three scientifically meaningful contrasts
- contrasts <- list(
- c("G2S", "Shared"), # G2S-exclusive vs both models
- c("GTEX", "Shared"), # GTEX-exclusive vs both models
- c("G2S", "GTEX") # the key contrast you care about most
- )
- direction_results <- rbindlist(lapply(sig_features, function(feat) {
- rbindlist(lapply(contrasts, function(pair) {
- x <- dtz[category_collapsed == pair[1], get(feat)]
- y <- dtz[category_collapsed == pair[2], get(feat)]
- wt <- wilcox.test(x, y, conf.int = TRUE)
- data.table(
- feature = feat,
- contrast = paste(pair[1], "vs", pair[2]),
- median_A = median(x, na.rm = TRUE),
- median_B = median(y, na.rm = TRUE),
- difference = median(x, na.rm = TRUE) - median(y, na.rm = TRUE),
- direction = fifelse(median(x, na.rm=TRUE) > median(y, na.rm=TRUE),
- paste("higher in", pair[1]),
- paste("higher in", pair[2])),
- p_value = wt$p.value,
- p_adj = p.adjust(wt$p.value, method = "BH")
- )
- }))
- }))
- # View ordered by contrast then significance
- direction_results[order(contrast, p_adj)]
- ```
- ### Fig S3: DOE and effect size of feature regression
- ```{r}
- library(viridis)
- # Dot plot: effect size on x, feature on y, faceted by contrast
- f3 <- ggplot(direction_results[p_adj <= 0.05],
- aes(color = abs(difference),
- y = reorder(feature, abs(difference)),
- shape = direction,
- x = -log10(p_adj))) +
- geom_vline(xintercept = 0, linetype = "dashed", color = "gray60") +
- geom_point(alpha = 1, size = 3) +
- facet_wrap(~contrast, ncol = 3) +
- scale_color_viridis_c(option = "viridis") +
- #scale_color_manual(
- # values = c("#3B8BD4", "#1D9E75"),
- # labels = c("Higher in B", "Higher in A")
- #) +
- theme_minimal() +
- labs(#title = "Direction of effect for significant SNP features",
- #subtitle = "Point size = -log10 adjusted p-value",
- color = "Median difference abs(A - B)",
- y = NULL,
- color = NULL,
- x = "-log10 p-adj",
- shape = "Model impact")
- name = 'Output/revisions2/all_measures_SCZ_wilcoxon.png'
- png(filename = name, width = 9, height = 5, units = "in", pointsize = 12, bg = "white", type = 'cairo', res = 600)
- print(f3)
- dev.off()
- print(f3)
- ```
- ```{r}
- #now look specifically for the effects when binning for coverage
- # Among genes where GTEx coverage is EQUAL (n_gtex_snps similar),
- # does prop_afr_specific still differ between G2S and GTEX?
- # Bin by prop_g2s-prop_gtex to control for coverage
- dt[category_collapsed != "None",
- model_coverage := cut(abs(prop_g2s_snps-prop_gtex_snps),
- breaks = quantile(abs(prop_g2s_snps-prop_gtex_snps),
- probs = seq(0,1,0.25),
- na.rm = TRUE),
- include.lowest = TRUE)]
- #dt[ ,':='(model_coverage=NULL)]
- # Now test mean_maf_diff_weighted within coverage-matched genes
- dt[category_collapsed %in% c("G2S", "GTEX") &
- model_coverage == levels(model_coverage)[1], # mindist coverage bin
- wilcox.test(mean_maf_diff_weighted ~ category_collapsed)]
- ```
- ```{r}
- dt[, g2s_binary := fifelse(
- category_collapsed %in% c("G2S", "Shared"), 1, 0)]
- dt[, g2s_binary := fifelse(
- category_collapsed %in% c("G2S"), 1, 0)]
- model_logistic <- glm(
- g2s_binary ~ n_snps + n_g2s_snps + n_gtex_snps +
- prop_g2s_snps + prop_gtex_snps + mean_g2s_weight_magnitude +
- mean_gtex_weight_magnitude + n_maf_diff_over_0.3 +
- mean_maf_diff_weighted + prop_common + prop_rare +
- n_eur_specific,
- data = dt[category_collapsed != "None"],
- family = binomial
- )
- summary(model_logistic)
- exp(coef(model_logistic)) # odds ratios
- exp(confint(model_logistic)) # confidence intervals
- summary(model_logistic)
- ```
- ## Model-wide FDR thresholding
- ```{r}
- dt_ <- fread('Data/all_exc_assocs_PGCancestryTWAS.txt', header =T)
- mods <- c("AA_Whole_Blood","All_Whole_Blood","MX_Whole_Blood","PrediXcan_Whole_Blood","PR_Whole_Blood")
- test_phens <- c("PGC_allADHD_2022", "PGC_allMDD_2023","PGC_ALL_PTSD_2024","PGC_all_SCZ_2022","PGC_BD1_2021","SUD_alc_2019")
- dt <- dt_[gwas_phenotype %in% test_phens & training_model %in% mods, -c('bhpval','bfpval')]
- dt$bfpval <- p.adjust(dt$pvalue, "bonferroni")
- dt$bhpval <- p.adjust(dt$pvalue, "BH")
- dtbh <- dt[bhpval <= 0.05,]
- dtbh$gg <- paste(dtbh$gene, dtbh$gwas_phenotype, sep = '_')
- dtbh_shared <- dtbh[training_model != "PrediXcan_Whole_Blood" & gg %in% dtbh[training_model == "PrediXcan_Whole_Blood",]$gg,]
- dtbh[gg %in% dtbh_shared$gg, status := 'shared']
- dtbh_g2s <- dtbh[training_model != "PrediXcan_Whole_Blood" & !(gg %in% dtbh[training_model == "PrediXcan_Whole_Blood",]$gg),]
- dtbh[gg %in% dtbh_g2s$gg, status := 'G2S only']
- dtbh_gtex <- dtbh[training_model == "PrediXcan_Whole_Blood" & !(gg %in% dtbh_shared$gg),]
- dtbh[gg %in% dtbh_gtex$gg, status := 'GTEx only']
- dtbhn <- dtbh[, .(.N), by = c('gwas_phenotype', 'training_model')]
- dtbhn[training_model == 'All_Whole_Blood', `gene expression model` := 'G2S All WB']
- dtbhn[training_model == 'AA_Whole_Blood', `gene expression model` := 'G2S African American WB']
- dtbhn[training_model == 'MX_Whole_Blood', `gene expression model` := 'G2S Mexican American WB']
- dtbhn[training_model == 'PR_Whole_Blood', `gene expression model` := 'G2S Puerto Rican WB']
- dtbhn[training_model == 'PrediXcan_Whole_Blood', `gene expression model` := 'GTEx European WB']
- dtbhn
- ```
PGC_master_analysis2.Rmd, under CC-BY-4.0 · at the source
Overview
- Medical Scientist Training Program, Vanderbilt University, Nashville, TN USA
- Division of Genetic Medicine, Vanderbilt University Medical Center, Nashville, TN USA
- Chapman University, Orange, CA USA
- Gonzaga University, Spokane, WA USA
- Vanderbilt Diabetes Center, Nashville, TN USA
- Vanderbilt Memory & Alzheimer’s Center, Nashville, TN USA
Abstract
The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.
Repositories
Its files are read in the Code ↔ Paper reader above, with 11 matches between paragraphs and lines of code.
Zenodo 14889757
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
11 files
- Code.zip/
SNP_analysis_p2_zsc.r , R, 1,034 lines, 2 matches - Code.zip/
SNP_analysis_zscore.r , R, 473 lines, 2 matches - Code.zip/
comp_BH.sh , Shell, 13 lines - Code.zip/
compile_twas_data.sh , Shell, 27 lines - Code.zip/
group_by_sig.sh , Shell, 25 lines - Code.zip/
masterscript.sh , Shell, 27 lines - Code.zip/
run_twas.sh , Shell, 47 lines - Code.zip/
runsig_region_rm.sh , Shell, 6 lines - Code.zip/
twas_sig.r , R, 70 lines - PGC_master_analysis2.Rmd
, R, 3,731 lines, 7 matches - README.txt, Text, 74 lines
hakyimlab/MetaXcan
e069063a10539fe92adadb645fc667a40c2cf885, 8 September 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
124 files
- DevNotes.Rmd, R, 13 lines
- software/
BuildExpressionProduct.p , Python, 63 linesy - software/
CovarianceBuilder.py , Python, 88 lines - software/
M00_prerequisites.py , Python, 176 lines - software/
M01_covariances_correlat , Python, 358 linesions.py - software/
M02_variances.py , Python, 83 lines - software/
M03_betas.py , Python, 188 lines - software/
M04_zscores.py , Python, 152 lines - software/
MPSimulation.py , Python, 101 lines - software/
MetaMany.py , Python, 163 lines - software/
MetaXcanUI.py , Python, 44 lines - software/
MulTiXcan.py , Python, 110 lines - software/
PrediXcan.py , Python, 45 lines - software/
PrediXcanAssociation.py , Python, 83 lines - software/
Predict.py , Python, 281 lines - software/
SMulTiXcan.py , Python, 100 lines - software/
SPrediXcan.py , Python, 77 lines - software/
ToHDF5.py , Python, 61 lines - software/
__init__.py , Python, 1 line - software/
build_minimal_data_requi , Shell, 23 linesrements.sh - software/
build_minimal_example_da , Shell, 11 linesta.sh - software/
ez_setup.py , Python, 391 lines - software/
metax/ , Python, 16 linesConstants.py - software/
metax/ , Python, 50 linesDataSet.py - software/
metax/ , Python, 11 linesDataSetSNP.py - software/
metax/ , Python, 49 linesExceptions.py - software/
metax/ , Python, 7 linesFormats.py - software/
metax/ , Python, 56 linesGene.py - software/
metax/ , Python, 156 linesKeyedDataSet.py - software/
metax/ , Python, 34 linesLogging.py - software/
metax/ , Python, 379 linesMainScreen.py - software/
metax/ , Python, 282 linesMainScreenView.py - software/
metax/ , Python, 237 linesMatrixManager.py - software/
metax/ , Python, 87 linesMatrixManager2.py - software/
metax/ , Python, 61 linesMetaXcanUITask.py - software/
metax/ , Python, 130 linesNamingConventions.py - software/
metax/ , Python, 86 linesPerson.py - software/
metax/ , Python, 189 linesPrediXcanFormatUtilities .py - software/
metax/ , Python, 315 linesPredictionModel.py - software/
metax/ , Python, 281 linesThousandGenomesUtilities .py - software/
metax/ , Python, 254 linesUtilities.py - software/
metax/ , Python, 170 linesWeightDBUtilities.py - software/
metax/ , Python, 5 lines__init__.py - software/
metax/ , Python, 150 linescross_model/ JointAnalysis.py - software/
metax/ , Python, 211 linescross_model/ Utilities.py - software/
metax/ , Python, 1 linecross_model/ __init__.py - software/
metax/ , Python, 93 linesdeprecated/ DBLoaders.py - software/
metax/ , Python, 92 linesdeprecated/ MatrixUtilities.py - software/
metax/ , Python, 72 linesdeprecated/ MethodGuessing.py - software/
metax/ , Python, 126 linesdeprecated/ Normalization.py - software/
metax/ , Python, 211 linesdeprecated/ SQLUtilities.py - software/
metax/ , Python, 210 linesdeprecated/ ZScoreCalculation.py - software/
metax/ , Python, 1 linedeprecated/ __init__.py - software/
metax/ , Python, 30 linesexpression/ Expression.py - software/
metax/ , Python, 164 linesexpression/ HDF5Expression.py - software/
metax/ , Python, 130 linesexpression/ PlainTextExpression.py - software/
metax/ , Python, 1 lineexpression/ __init__.py - software/
metax/ , Python, 73 linesgenotype/ BGENGenotype.py - software/
metax/ , Python, 83 linesgenotype/ CYVCF2Genotype.py - software/
metax/ , Python, 104 linesgenotype/ DosageGenotype.py - software/
metax/ , Python, 96 linesgenotype/ GTExGenotype.py - software/
metax/ , Python, 158 linesgenotype/ GeneExpressionMatrixMana ger.py - software/
metax/ , Python, 33 linesgenotype/ Genotype.py - software/
metax/ , Python, 99 linesgenotype/ GenotypeAnalysis.py - software/
metax/ , Python, 17 linesgenotype/ Helpers.py - software/
metax/ , Python, 75 linesgenotype/ ModelTrainingGenotype.py - software/
metax/ , Python, 69 linesgenotype/ PYVCFGenotype.py - software/
metax/ , Python, 15 linesgenotype/ Utilities.py - software/
metax/ , Python, 1 linegenotype/ __init__.py - software/
metax/ , Python, 290 linesgwas/ GWAS.py - software/
metax/ , Python, 90 linesgwas/ GWASSpecialHandling.py - software/
metax/ , Python, 122 linesgwas/ Utilities.py - software/
metax/ , Python, 1 linegwas/ __init__.py - software/
metax/ , Python, 132 linesmetaxcan/ AssociationCalculation.p y - software/
metax/ , Python, 84 linesmetaxcan/ MetaXcanResultsManager.p y - software/
metax/ , Python, 347 linesmetaxcan/ Utilities.py - software/
metax/ , Python, 1 linemetaxcan/ __init__.py - software/
metax/ , Python, 83 linesmisc/ DataFrameStreamer.py - software/
metax/ , Python, 128 linesmisc/ FeatureMatrix.py - software/
metax/ , Python, 82 linesmisc/ GWASAndModels.py - software/
metax/ , Python, 118 linesmisc/ Genomics.py - software/
metax/ , Python, 82 linesmisc/ KeyedDataSource.py - software/
metax/ , Python, 69 linesmisc/ Math.py - software/
metax/ , Python, 1 linemisc/ __init__.py - software/
metax/ , Python, 240 linespredixcan/ MultiPrediXcanAssociatio n.py - software/
metax/ , Python, 136 linespredixcan/ PrediXcanAssociation.py - software/
metax/ , Python, 253 linespredixcan/ Simulations.py - software/
metax/ , Python, 360 linespredixcan/ Utilities.py - software/
metax/ , Python, 1 linepredixcan/ __init__.py - software/
setup.py , Python, 56 lines - software/
tests/ , Python, 147 linesCreateGTExLike.py - software/
tests/ , Python, 295 linesSampleData.py - software/
tests/ , Python, 6 lines__init__.py - software/
tests/ , R, 6 lines_td/ beta_builder.R - software/
tests/ , Python, 39 lines_td/ convert_model_to_text.py - software/
tests/ , Python, 46 lines_td/ trim_data_for_multi_tiss ue_test.py - software/
tests/ , Python, 45 linescov_data.py - software/
tests/ , Python, 15 linesgen_data.py - software/
tests/ , Python, 17 linesscz2_sample.py - software/
tests/ , Python, 103 linestest_M00_prerequisites.p y - software/
tests/ , Python, 95 linestest_M01_covariances_cor relations.py - software/
tests/ , Python, 249 linestest_M03_betas.py - software/
tests/ , Python, 198 linestest_Person.py - software/
tests/ , Python, 97 linestest_association_calcula tion.py - software/
tests/ , Python, 30 linestest_dataframe_streamer. py - software/
tests/ , Python, 71 linestest_dataset.py - software/
tests/ , Python, 47 linestest_dataset_snp.py - software/
tests/ , Python, 152 linestest_dbloaders.py - software/
tests/ , Python, 66 linestest_feature_matrix.py - software/
tests/ , Python, 154 linestest_gene.py - software/
tests/ , Python, 90 linestest_gtex_genotype.py - software/
tests/ , Python, 272 linestest_gwas.py - software/
tests/ , Python, 40 linestest_gwas_special_handli ng.py - software/
tests/ , Python, 75 linestest_gwas_utilities.py - software/
tests/ , Python, 40 linestest_keyed_data_source.p y - software/
tests/ , Python, 413 linestest_keyed_dataset.py - software/
tests/ , Python, 101 linestest_matrix_manager.py - software/
tests/ , Python, 167 linestest_prediction_model.py - software/
tests/ , Python, 58 linestest_predixcan_format_ut ilities.py - software/
tests/ , Python, 156 linestest_thousand_genomes_ut ilities.py - software/
tests/ , Python, 235 linestest_utilities.py - software/
tests/ , Python, 194 linestest_weight_db_utilities .py - LICENSE, License, 23 lines
- README.md, Text, 313 lines
qingnanl/gsdensity_manuscript_code
733148850a249f17016b7ba8a4d4f89177f81f8d, 20 November 2023Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
17 files
- Add_noise_to_data.ipynb, Jupyter, 172 lines
- curate_data.R, R, 463 lines
- mb.r, R, 131 lines
- method.benchmarking.func
tions.R , R, 450 lines - method.benchmarking.func
tions.rd.R , R, 806 lines - mouse_brain_dev.r, R, 167 lines
- normalize_sim_rand.R, R, 59 lines
- panc.preprocess.R, R, 87 lines
- panc.process.R, R, 138 lines
- run_sergio_code.py, Python, 23 lines
- run_sergio_dyn.1.py, Python, 28 lines
- sergio_analysis_function
s.R , R, 147 lines - sergio_dyn_gen.R, R, 125 lines
- sergio_steady_gen.R, R, 108 lines
- tnbc.subtype.cc.R, R, 60 lines
- tnbc_preprocess.r, R, 154 lines
- README.md, Text, 42 lines
Zenodo 18315835
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
11 files
- Code.zip/
SNP_analysis_p2_zsc.r , R, 1,034 lines - Code.zip/
SNP_analysis_zscore.r , R, 473 lines - Code.zip/
comp_BH.sh , Shell, 13 lines - Code.zip/
compile_twas_data.sh , Shell, 27 lines - Code.zip/
group_by_sig.sh , Shell, 25 lines - Code.zip/
masterscript.sh , Shell, 27 lines - Code.zip/
run_twas.sh , Shell, 47 lines - Code.zip/
runsig_region_rm.sh , Shell, 6 lines - Code.zip/
twas_sig.r , R, 70 lines - PGC_master_analysis2.Rmd
, R, 3,731 lines - README.txt, Text, 74 lines
Code availability statement
The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to the authors' code: hakyimlab/
MetaXcan , qingnanl/gsdensity_manuscript_cod , Zenodo 14889757e
Read it in the paper: doi.org/10.1038/s41467-026-75193-4.
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:
- 4 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 158 scripts, each with its path and the digest of its content;
- 11 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
No dataset and no data link were found in the paper.
Code and data availability statement
The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to the authors' code: hakyimlab/
MetaXcan , qingnanl/gsdensity_manuscript_cod , Zenodo 14889757e
Read it in the paper: doi.org/10.1038/s41467-026-75193-4.
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, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 6 authors, 3 keywords, 11 MeSH terms, 15 funders, 47 references.
Cite
This paper
Bledsoe, X., Watkins, N., Bowen-Moore, T., Shaw, M., Shah, R. V., & Gamazon, E. R. (2026). Multi-ancestry gene expression models amplify transcriptome-wide association study discovery and validation. Nature communications, 17(1), 8331. https://
BibTeX
@article{bledsoe2026mult
author = {Bledsoe, Xavier and Watkins, Nathan and Bowen-Moore, Tavian and Shaw, Marlisa and Shah, Ravi V and Gamazon, Eric R},
title = {{Multi-ancestry gene expression models amplify transcriptome-wide association study discovery and validation}},
journal = {Nature communications},
year = {2026},
month = jul,
volume = {17},
number = {1},
pages = {8331},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/
url = {https://
pmid = {42401576},
pmcid = {PMC13470059}
}
RIS
TY - JOUR
AU - Bledsoe, Xavier
AU - Watkins, Nathan
AU - Bowen-Moore, Tavian
AU - Shaw, Marlisa
AU - Shah, Ravi V
AU - Gamazon, Eric R
TI - Multi-ancestry gene expression models amplify transcriptome-wide association study discovery and validation
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/
VL - 17
IS - 1
SP - 8331
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "Multi-ancestry gene expression models amplify transcriptome-wide association study discovery and validation",
"container-title": "Nature communications",
"author": [
{
"family": "Bledsoe",
"given": "Xavier"
},
{
"family": "Watkins",
"given": "Nathan"
},
{
"family": "Bowen-Moore",
"given": "Tavian"
},
{
"family": "Shaw",
"given": "Marlisa"
},
{
"family": "Shah",
"given": "Ravi V"
},
{
"family": "Gamazon",
"given": "Eric R"
}
],
"container-title-short":
"volume": "17",
"issue": "1",
"page": "8331",
"DOI": "10.1038/
"PMID": "42401576",
"PMCID": "PMC13470059",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
4
]
]
}
}
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/s41380-026-03571-x [code]
- Convergent coexpression reveals shared biological mechanisms underlying common and rare variant risk in six neuropsychiatric disorders.Journal: Molecular psychiatryIn common: Monocle 3, igraph, Seurat, 10 other tools, genetics / omics, cellular / molecular, 5 references
- [2] doi:10.1016/j.celrep.2026.117500 [code]
- Spatio-molecular gene expression reflects dorsal anterior cingulate cortex structure and function in the human brain.Journal: Cell reportsIn common: igraph, ComplexHeatmap, pheatmap, 8 other tools, genetics / omics, cellular / molecular, 5 references
- [3] doi:10.1016/j.xcrm.2026.102766 [code]
- A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.Journal: Cell reports. MedicineIn common: Monocle 3, igraph, ComplexHeatmap, 12 other tools, genetics / omics, cellular / molecular
- [4] doi:10.1038/s41467-026-69944-6 [code]
- Multi-modal dissection of cell-type specific TDP-43 pathology in the motor cortex.Journal: Nature communicationsIn common: Monocle 3, igraph, ComplexHeatmap, 11 other tools, genetics / omics, 1 reference
- [5] doi:10.1038/s42003-026-10957-8 [code]
- Brain defence by the extracellular matrix protein Cochlin.Journal: Communications biologyIn common: Monocle 3, igraph, ComplexHeatmap, 12 other tools, cellular / molecular
- [6] 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 communicationsIn common: Monocle 3, igraph, pheatmap, 11 other tools, genetics / omics, 1 reference
- [7] doi:10.1038/s41380-026-03497-4 [code]
- Transcriptome-informed brain cartography of polygenic risk and association with brain structure in major psychiatric disorders.Journal: Molecular psychiatryIn common: ComplexHeatmap, pheatmap, patchwork, 6 other tools, genetics / omics, cellular / molecular, 6 references
- [8] doi:10.1002/imt2.70163 [code]
- Spatial multi-omics unveils sphingolipid metabolic reprogramming within the retinal pathological niche.Journal: iMetaIn common: Monocle 3, igraph, ComplexHeatmap, 11 other tools, genetics / omics, cellular / molecular
- [9] doi:10.1038/s41586-026-10214-2 [code]
- Multidimensional profiling of heterogeneity in supratentorial ependymomas.Journal: NatureIn common: Monocle 3, igraph, ComplexHeatmap, 11 other tools, genetics / omics
- [10] 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 geneticsIn common: pheatmap, reshape2, h5py, 6 other tools, genetics / omics, cellular / molecular, 6 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 4 repositories of the authors' code, each at its verified commit and with its license, 158 scripts, and 11 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:c29256b5238977e4…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
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.
