Last updated: 2021-05-17
Checks: 7 0
Knit directory: soybean_exploration/
This reproducible R Markdown analysis was created with workflowr (version 1.6.2). The Checks tab describes the reproducibility checks that were applied when the results were created. The Past versions tab lists the development history.
Great! Since the R Markdown file has been committed to the Git repository, you know the exact version of the code that produced these results.
Great job! The global environment was empty. Objects defined in the global environment can affect the analysis in your R Markdown file in unknown ways. For reproduciblity it’s best to always run the code in an empty environment.
The command set.seed(20210309) was run prior to running the code in the R Markdown file. Setting a seed ensures that any results that rely on randomness, e.g. subsampling or permutations, are reproducible.
Great job! Recording the operating system, R version, and package versions is critical for reproducibility.
Nice! There were no cached chunks for this analysis, so you can be confident that you successfully produced the results during this run.
Great job! Using relative paths to the files within your workflowr project makes it easier to run your code on other machines.
Great! You are using Git for version control. Tracking code development and connecting the code version to the results is critical for reproducibility.
The results in this page were generated with repository version b89d097. See the Past versions tab to see a history of the changes made to the R Markdown and HTML files.
Note that you need to be careful to ensure that all relevant files for the analysis have been committed to Git prior to generating the results (you can use wflow_publish or wflow_git_commit). workflowr only checks the R Markdown file, but you know if there are other scripts or data files that it depends on. Below is the status of the Git repository when the results were generated:
Ignored files:
Ignored: .Rhistory
Ignored: .Rproj.user/
Note that any generated files, e.g. HTML, png, CSS, etc., are not included in this status report because it is ok for generated content to have uncommitted changes.
These are the previous versions of the repository in which changes were made to the R Markdown (analysis/NBS_pairwise_tests.Rmd) and HTML (docs/NBS_pairwise_tests.html) files. If you’ve configured a remote Git repository (see ?wflow_git_remote), click on the hyperlinks in the table below to view the files as they were in that past version.
| File | Version | Author | Date | Message |
|---|---|---|---|---|
| Rmd | b89d097 | Lyron Winderbaum | 2021-05-17 | Update discussion on NBS genes present in global interactions |
| Rmd | e17a079 | Lyron Winderbaum | 2021-05-17 | Pairwise Tests |
| html | e17a079 | Lyron Winderbaum | 2021-05-17 | Pairwise Tests |
# # Cleanup and Global Settings
# rm(list = ls())
# if (!is.null(sessionInfo()$otherPkgs)) {
# invisible(lapply(paste0('package:', names(sessionInfo()$otherPkgs)),
# detach, character.only=TRUE, unload=TRUE))
# }
# graphics.off()
# options(stringsAsFactors = FALSE)
library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.2.1 ✔ purrr 0.3.2
✔ tibble 2.1.3 ✔ dplyr 0.8.3
✔ tidyr 1.0.0 ✔ stringr 1.4.0
✔ readr 1.3.1 ✔ forcats 0.4.0
── Conflicts ─────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
# Read tidy data saved at the of initial_data_organisation.Rmd
load(file.path('data', 'pav_data.RData'))
# Reduce to NBS genes
nbs_table = pav_table[, c(TRUE, names(pav_table)[-1] %in% nbs$Name)]
# Merge on Yield and reduce to lines for which we have yield data
meta.df = subset(meta.df, !is.na(Yield))
nbs_table = merge(meta.df[, c('Line', 'Yield')], nbs_table)
# Reduce to genes with some decent level of variation
nbs_table = nbs_table[, c(TRUE, TRUE, colMeans(nbs_table[, -(1:2)]) <= 0.98 & colMeans(nbs_table[, -(1:2)]) >= 0.02)]
# # Proportion presence
# hist(colMeans(nbs_table[, -(1:2)]))
# Simplify gene names slightly
names(nbs_table) = sub('00.1.p$', '', names(nbs_table))
names(nbs_table) = sub('^GlymaLee.', 'GL', names(nbs_table))
names(nbs_table) = sub('^UWASoyPan', 'UWA', names(nbs_table))
# Move Line information into row.names
row.names(nbs_table) = nbs_table$Line
nbs_table$Line = NULL
So, if we restrict to NBS genes that occur in at least 2% and no more than 98% of individuals in our dataset this leaves us with 76 genes (noting we shorten GlymaLee to GL and UWASoyPan to UWA for convenience):
gene_nms = names(nbs_table)[-1]
gene_nms
[1] "GL01G0309" "GL01G0884" "GL03G0420" "GL03G0421" "GL03G0454"
[6] "GL03G0455" "GL03G0456" "GL03G0457" "GL03G0459" "GL03G0706"
[11] "GL03G0707" "GL06G2286" "GL06G2289" "GL06G2291" "GL06G2293"
[16] "GL06G2305" "GL06G2306" "GL06G2326" "GL06G2328" "GL07G0600"
[21] "GL07G0702" "GL10G0346" "GL14G0220" "GL15G1986" "GL15G1992"
[26] "GL15G1993" "GL15G1995" "GL16G1111" "GL16G1113" "GL16G1115"
[31] "GL16G1308" "GL16G1752" "GL16G1755" "GL16G1756" "GL18G0757"
[36] "GL18G0763" "GL18G0766" "UWA00005" "UWA00022" "UWA00043"
[41] "UWA00155" "UWA00201" "UWA00202" "UWA00251" "UWA00276"
[46] "UWA00316" "UWA00326" "UWA00427" "UWA00670" "UWA00725"
[51] "UWA00772" "UWA00953" "UWA00975" "UWA01217" "UWA01253"
[56] "UWA01320" "UWA01330" "UWA01418" "UWA01530" "UWA01729"
[61] "UWA01876" "UWA01973" "UWA02043" "UWA02496" "UWA02799"
[66] "UWA03194" "UWA03230" "UWA03233" "UWA03261" "UWA03336"
[71] "UWA03340" "UWA03402" "UWA04314" "UWA04354" "UWA04967"
[76] "UWA05312"
We we consider all possible pairwise interactions (of which there are 2850), and perform a t-test for the interaction term in these linear models with Yield as the response:
gene_nms = names(nbs_table)[-1]
df_pairs = data.frame()
for (i in 1:(length(gene_nms)-1)) {
for (j in (i + 1):length(gene_nms)) {
f = as.formula(paste('Yield ~', gene_nms[i], '*', gene_nms[j]))
m = lm(f, data = nbs_table)
int_nm = paste0(gene_nms[i], ':', gene_nms[j])
if (int_nm %in% row.names(summary(m)$coefficients)) {
df_pairs = rbind(
df_pairs,
data.frame(gene.1 = gene_nms[i], gene.2 = gene_nms[j],
p.val = summary(m)$coefficients[int_nm, "Pr(>|t|)"])
)
} else {
df_pairs = rbind(
df_pairs,
data.frame(gene.1 = gene_nms[i], gene.2 = gene_nms[j], p.val = NA)
)
}
}
}
df_pairs = df_pairs[order(df_pairs$p.val),]
df_pairs = na.omit(df_pairs)
234 of these interactions cannot be computed (because there is no difference in gene presence/absence between the genes), leaving us with 2764 interactions. Lets have a quick look at the p-value distribution:
hist(df_pairs$p.val)

| Version | Author | Date |
|---|---|---|
| e17a079 | Lyron Winderbaum | 2021-05-17 |
sig_lvl = c(0.1, 0.05, 0.01)
rbind(sig_lvl,
p_vals = sapply(sig_lvl, function(x){return(sum(df_pairs$p.val < x))}))
[,1] [,2] [,3]
sig_lvl 0.1 0.05 0.01
p_vals 410.0 234.00 83.00
But we should apply a correction for multiple testing, using the Holm-Bonferroni method we get:
sig_lvl = c(0.1, 0.05, 0.01)
rbind(sig_lvl,
p_vals = sapply(sig_lvl, function(x){return(sum(df_pairs$p.val*(nrow(df_pairs):1) < x))}))
[,1] [,2] [,3]
sig_lvl 0.1 0.05 0.01
p_vals 3.0 3.00 1.00
So which are these three interesting interactions?
subset(df_pairs, p.val*(nrow(df_pairs):1) < 0.05)
gene.1 gene.2 p.val
2524 UWA00725 UWA04967 3.520042e-06
1006 GL06G2293 UWA01973 4.094386e-06
2240 UWA00155 UWA01876 1.020067e-05
We can try the same procedure for all genes, not just the NBS genes. But first lets just tidy the full data in the same way we tidied the NBS data.
pav_table = merge(meta.df[, c('Line', 'Yield')], pav_table)
# Reduce to genes with some decent level of variation
pav_table = pav_table[, c(TRUE, TRUE, colMeans(pav_table[, -(1:2)]) <= 0.98 & colMeans(pav_table[, -(1:2)]) >= 0.02)]
The filter to only include genes with proportion of occurance between 2% and 98% reduces the 51415 genes down to just 2648 genes — a huge number of these genes are either very rare or very common, making it difficult to assess their imporance on Yield to to sample size limitations. Finish tidying:
# Simplify gene names slightly
names(pav_table) = sub('00.1.p$', '', names(pav_table))
names(pav_table) = sub('^GlymaLee.', 'GL', names(pav_table))
names(pav_table) = sub('^UWASoyPan', 'UWA', names(pav_table))
# Move Line information into row.names
row.names(pav_table) = pav_table$Line
pav_table$Line = NULL
and we can repeat the pairwise test procedure:
gene_nms = names(pav_table)[-1]
# source(file.path('analysis', 'pairwsie_tests_all.R'))
df_pairs = read.csv(file.path('output', 'pairwise_tests_all.csv'))
df_pairs$gene.1 = gene_nms[df_pairs$gene.1]
df_pairs$gene.2 = gene_nms[df_pairs$gene.2]
df_pairs = df_pairs[order(df_pairs$p.val),]
df_pairs = na.omit(df_pairs)
Note I did some hackery there to run the code in a seperate script, store output, and load it in a particular format to get around re-running slow clode and get around the GitHub file size limit.
Of the 3,499,335 pairs of genes, 373,817 cannot compute interaction terms because of the two genes having exact overlap. This leaves 3,125,518 pairs for testing. Lets take a look at the p-value distribution:
hist(df_pairs$p.val)

| Version | Author | Date |
|---|---|---|
| e17a079 | Lyron Winderbaum | 2021-05-17 |
Nice, lookes like a clear addition between a uniform distribution and an exponential distribution, just what we would expect if there are some real interactions mixed in. Lets count the small p-values:
sig_lvl = c(0.1, 0.05, 0.01)
rbind(sig_lvl,
p_vals = sapply(sig_lvl, function(x){return(sum(df_pairs$p.val < x))}))
[,1] [,2] [,3]
sig_lvl 0.1 0.05 0.01
p_vals 391570.0 236331.00 76505.00
and adjust for multiple testing using the Holm-Bonferroni method:
sig_lvl = c(0.1, 0.05, 0.01)
rbind(sig_lvl,
p_vals = sapply(sig_lvl, function(x){return(sum(df_pairs$p.val*(nrow(df_pairs):1) < x))}))
[,1] [,2] [,3]
sig_lvl 0.1 0.05 0.01
p_vals 84.0 61.00 33.00
So which are these 37 interesting interactions significant at the 1% level after multiple test correction?
subset(df_pairs, p.val*(nrow(df_pairs):1) < 0.01)
gene.1 gene.2 p.val
3097588 UWA02279 UWA02696 6.146775e-13
1542202 UWA00342 UWA00538 6.363480e-13
2024585 UWA00863 UWA01138 4.987603e-12
3189725 UWA02696 UWA04952 1.142622e-11
1732291 UWA00538 UWA02709 1.343754e-11
1623532 UWA00424 UWA02696 1.408472e-11
1428447 UWA00241 UWA01567 1.810912e-11
1038728 GL18G1234 UWA00380 7.721450e-11
1356040 UWA00182 UWA00538 9.987116e-11
1042318 GL18G1267 UWA03220 2.077257e-10
1040101 GL18G1234 UWA03220 2.603432e-10
2628157 UWA01537 UWA03107 2.879676e-10
2459484 UWA01367 UWA02285 2.956599e-10
2357075 UWA01224 UWA01345 3.966186e-10
2581604 UWA01489 UWA04190 6.680222e-10
134582 GL03G0315 UWA01036 6.977990e-10
1493252 UWA00298 UWA01985 7.364664e-10
1040945 GL18G1267 UWA00380 7.871351e-10
943086 GL17G1410 UWA01538 9.280403e-10
942572 GL17G1410 UWA00636 9.899005e-10
1368915 UWA00189 UWA01420 1.267221e-09
1480419 UWA00291 UWA00538 1.676407e-09
1026151 GL18G0922 UWA01693 1.959441e-09
1378575 UWA00201 UWA00220 2.090802e-09
1405736 UWA00223 UWA01138 2.826983e-09
738653 GL15G0651 UWA03178 3.051131e-09
1523367 UWA00318 UWA02285 3.115504e-09
1025597 GL18G0922 UWA00780 3.414061e-09
1427774 UWA00241 UWA00363 3.562766e-09
2226649 UWA01087 UWA01293 3.717602e-09
1940091 UWA00773 UWA02820 3.894434e-09
540811 GL09G1235 GL09G1453 3.896788e-09
1731950 UWA00538 UWA01863 4.026035e-09
Do any of these interactions involve NBS genes? Yes! Are any of these interactions between NBS genes? No! GL15G1995, UWA00005, UWA00202, UWA01330, and UWA05312 are NBS genes, so the below is the subset of interactions significant at the 1% level after multiple testing correction that involve NBS genes:
subset(df_pairs, p.val*(nrow(df_pairs):1) < 0.01 & (gene.1 %in% names(nbs_table)[-1] | gene.2 %in% names(nbs_table)[-1]))
gene.1 gene.2 p.val
1378575 UWA00201 UWA00220 2.090802e-09
sessionInfo()
R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.5 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so
locale:
[1] LC_CTYPE=en_AU.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_AU.UTF-8 LC_COLLATE=en_AU.UTF-8
[5] LC_MONETARY=en_AU.UTF-8 LC_MESSAGES=en_AU.UTF-8
[7] LC_PAPER=en_AU.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_AU.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] forcats_0.4.0 stringr_1.4.0 dplyr_0.8.3 purrr_0.3.2
[5] readr_1.3.1 tidyr_1.0.0 tibble_2.1.3 ggplot2_3.2.1
[9] tidyverse_1.2.1
loaded via a namespace (and not attached):
[1] tidyselect_1.1.0 xfun_0.10 haven_2.3.1 lattice_0.20-41
[5] colorspace_1.4-1 vctrs_0.3.1 generics_0.0.2 htmltools_0.4.0
[9] yaml_2.2.0 rlang_0.4.6 later_1.0.0 pillar_1.4.2
[13] withr_2.1.2 glue_1.3.1 modelr_0.1.5 readxl_1.3.1
[17] lifecycle_0.1.0 munsell_0.5.0 gtable_0.3.0 workflowr_1.6.2
[21] cellranger_1.1.0 rvest_0.3.4 evaluate_0.14 knitr_1.25
[25] httpuv_1.5.2 broom_0.5.2 Rcpp_1.0.3 promises_1.1.0
[29] backports_1.1.5 scales_1.0.0 jsonlite_1.6 fs_1.3.1
[33] hms_0.5.1 digest_0.6.23 stringi_1.4.3 grid_3.6.3
[37] rprojroot_1.3-2 cli_1.1.0 tools_3.6.3 magrittr_1.5
[41] lazyeval_0.2.2 crayon_1.3.4 whisker_0.4 pkgconfig_2.0.3
[45] xml2_1.2.2 lubridate_1.7.4 assertthat_0.2.1 rmarkdown_1.16
[49] httr_1.4.1 rstudioapi_0.10 R6_2.4.0 nlme_3.1-149
[53] git2r_0.26.1 compiler_3.6.3