knitr::opts_chunk$set(fig.width=4.5, fig.height=3.5)
Updog is an empirical Bayes approach to genotype individuals (particularly polyploids) from next generation sequencing (NGS) data. We had in mind NGS data that results from a reduced representation library, such as "genotyping-by-sequencing" (GBS) [@elshire2011robust] or "restriction site-associated DNA sequencing" (RAD-seq) [@baird2008rapid].
Updog wields the power of hierarchical modeling to account for some key features of NGS data overlooked in most other analyses: allelic bias, overdispersion, and outlying observations. Updog will also automatically account for sequencing errors.
To efficiently account for these features, updog needs to know the distribution of the individual genotypes in the population. Updog can accurately estimate this distribution if the population consists of full siblings (option model = "s1"
or model = "f1"
) or if the population is in Hardy-Weinberg equilibrium (model = "hw"
).
You can read more about the updog method in @gerard2018harnessing.
Load updog
and the snpdat
dataset. The data frame snpdat
contains three example SNPs (single nucleotide polymorphisms) from the study of @shirasawa2017high. The individuals in this dataset resulted from a single generation of selfing (an S1 population). You can read more about it by typing ?snpdat
.
set.seed(1) library(updogAlpha) data("snpdat")
We'll use the tidyverse
to extract the First SNP.
library(tidyverse) snpdat %>% filter(snp == "SNP1") %>% select(counts, size, id) -> smalldat head(smalldat)
We will separate the counts between the children and the parent (the first individual). Note that you do not need the parental counts to fit updog, but they can help improve estimates of the parameters in the updog model.
pcounts <- smalldat$counts[1] psize <- smalldat$size[1] ocounts <- smalldat$counts[-1] osize <- smalldat$size[-1] ploidy <- 6 # sweet potatoes are hexaploid
We can first use plot_geno
to visualize the raw data.
plot_geno(ocounts = ocounts, osize = osize, ploidy = ploidy)
Now we fit updog
. We use model = "s1"
because the individuals resulted from one generation of selfing of the same parent.
uout <- updog(ocounts = ocounts, osize = osize, ploidy = ploidy, p1counts = pcounts, p1size = psize, model = "s1")
We use plot.updog
to visualize the fit. Points are color coded according to the genotype with the highest posterior probability. For example, a genotype of "4" represents four copies of the reference allele and two copies of the alternative allele (AAAAaa). The level of transparency is proportional to the posterior probability of a point being an outlier. The lines represent the mean counts at a given genotype. The "+" symbol with a black dot is the location of the parent.
plot(uout)
I have incorporated a colorblind safe palate.
plot(uout, use_colorblind = TRUE)
The fit seems reasonable. We can test how reasonable our genotype distribution is using summary.updog
.
summary(uout)
The goodness of fit $p$-value is quite large, indicating no evidence of lack of fit.
We can sample from the fitted model using rupdog
.
rout <- rupdog(uout)
If we plot the sampled output, it looks similar to the real data.
plot(rout, show_outlier = FALSE)
For downstream analyses, you might want to filter out poorly behaved SNPs. These SNPs might be poorly behaved for a variety of reasons (they might not be real SNPs, it might be much more very difficult to map one allele to the correct location relative to the other allele, etc). Updog gives you some measures to filter out these SNPs.
The most intuitive measure would be the (posterior) proportion of individuals mis-genotyped:
uout$prop_mis
For this SNP, we expect about r round(uout$prop_mis, digits = 4) * 100
percent of the individuals to be mis-genotyped. The specific cutoff you use is context and data dependent. But as a starting point, you could try a loose cutoff by keeping SNPs only if they have a prop_mis
of less than 0.2.
From our simulation studies, we also generally get rid of SNPs with overdispersion parameters greater than 0.05 or SNPs with bias parameters either less than 0.5 or greater than 2. However, if you have higher or lower read depths than what we looked at in our simulations, you should adjust these levels accordingly.
You should probably also get rid of SNPs if they have a high sequencing error rate, but we didn't explore this in simulations so I don't have any heuristic recommendations.
For population studies, I would always use the options model = "hw"
, update_outprop = FALSE
, and out_prop = 0
. This is for two (extremely heuristic) reasons:
model = "uniform"
.update_outprop = FALSE
, and out_prop = 0
.Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.