heritable

Motivation

A key goal in any breeding trial is to calculate heritability, which describes the extent of which a trait of interest is underpinned by genetic variance. heritable is the one-stop shop for heritability calculations in R. Here, we have implemented existing methods for heritability to aid more reproducible and transparent reporting of it’s calculations. This vignette is a brief overview of heritable’s workflow and key features.

heritable is compatible with model outputs from asreml and lme4 and extracts the relevant variance components to calculate heritability for single environment trials.

Installation

Note that this package is under active development. You can install the development version of heritable from GitHub with:

# install.packages("pak")
# pak::pak("anu-aagi/heritable")
library(heritable)

A demo

Let’s work with the lettuce dataset that contains phenotypic measurements of downy mildew resistance score of 89 lettuce genotypes across 3 locations (environments), with 3 replicates.For demonstration purposes, we will use a subset of single environment (loc == L2), which is displayed in the plot below.

library(dplyr)
head(lettuce_phenotypes)
#> # A tibble: 6 × 4
#>   loc   gen   rep       y
#>   <fct> <fct> <fct> <dbl>
#> 1 L1    G1    R1      2  
#> 2 L1    G1    R2      2.5
#> 3 L1    G2    R1      1.5
#> 4 L1    G2    R2      2  
#> 5 L1    G3    R1      1  
#> 6 L1    G3    R2      2

lettuce_subset <- lettuce_phenotypes |>
  filter(loc == "L2")

We also have access to a genomic relationship matrix (GRM) calculated from 300 genetic markers that we will use for narrow-sense heritability.

# View the structure of the GRM
dim(lettuce_GRM)
#> [1] 89 89
lettuce_GRM[1:5, 1:5]
#>     G1  G2  G3  G4  G5
#> G1 268   9  13  -3 -46
#> G2   9 270 -19 -50 104
#> G3  13 -19 250  21  -5
#> G4  -3 -50  21 281  21
#> G5 -46 104  -5  21 296

Broad-sense heritability

Broad-sense heritability represents the ratio of genetic variance over phenotypic variance. Genetic variance here incorporates additive, epistatic and dominance effects.

Here, we have provided code for both asreml and lme4 to fit a model with genotype as a random effect. Note that all heritability estimates should be the same as the data is balanced.

# Fit an asreml model with genotype as random effect
library(asreml)
lettuce_asreml <- asreml(
  fixed = y ~ rep,
  random = ~ gen,
  data = lettuce_subset,
  trace = FALSE
)

# Fit an lme4 model with genotype as random effect
library(lme4)
lettuce_lme4 <- lmer(y ~ rep + (1 | gen), data = lettuce_subset)

Use the H2() wrapper to compute broad-sense heritability.

The wrapper has three key inputs

# Calculate broad-sense heritability using multiple methods
H2(lettuce_asreml, target = "gen", method = c("Standard", "Cullis", "Oakey"))
#>  Standard    Cullis     Oakey 
#> 0.8294971 0.8294971 0.8294971
H2(lettuce_lme4, target = "gen", method = c("Standard", "Cullis", "Oakey"))
#>  Standard    Cullis     Oakey 
#> 0.8294971 0.8294971 0.8294971

Alternatively if you want a single method, you can call each method’s function directly. These are named with the H2_ prefix, followed up the method name.

H2_Cullis(lettuce_asreml, target = "gen")
#> [1] 0.8294971
H2_Delta(lettuce_lme4, target = "gen")
#> [1] 0.8294971

Learn more about each method by looking up their help file ?H2_Cullis

Narrow-sense heritability

Narrow-sense heritability is currently only implemented for asreml model object as there is no native workflow to fit a GRM using lme4. However it is possible using other extension packages such as lme4qtl and lme4breeding

In the following model, we will fit the lettuce_GRM genomic relationship matrix using asreml::vm()

# Fit model with GRM for narrow-sense heritability
lettuce_asreml_grm <- asreml(
  fixed = y ~ loc,
  random = ~ vm(gen, lettuce_GRM) + rep,
  data = lettuce_phenotypes,
  trace = FALSE
)

Similar to H2(), we can use the h2() wrapper to compute narrow-sense heritability. Remembering to specify:

# Calculate narrow-sense heritability
h2(lettuce_asreml_grm, target = "gen", method = "Oakey")
#> Error in UseMethod("h2_Oakey"): no applicable method for 'h2_Oakey' applied to an object of class "asreml"

Similarly, you can call the single method sub-functions using the prefix h2_ followed by the method name. Here we are calculating pairwise heritability between every genotype. See ?h2_Delta_pairwise() to learn more.

h2_Delta(lettuce_asreml_grm, target = "gen", type = "BLUP")
#> Error in UseMethod("h2_Delta_pairwise"): no applicable method for 'h2_Delta_pairwise' applied to an object of class "asreml"

Alternative output formats

Depending on which heritable function, the output will vary:

If you interested in comparing heritability values across multiple models or methods, we can leverage tidyverse functions to wrangle the output as a dataframe/tibble

library(purrr)
library(tidyr)

tibble(
  model = list(lettuce_lme4, lettuce_asreml) # Include model as a list variable
  ) |>
  mutate(H2 = map(model, # Apply the `H2()` function over each model object
                  ~H2(.x, target = "gen", method = c("Standard", "Delta", "Oakey"))
                  )
         )|>
  unnest_wider(H2) # Expand the output
#> # A tibble: 2 × 4
#>   model     Standard Delta Oakey
#>   <list>       <dbl> <dbl> <dbl>
#> 1 <lmerMod>    0.829 0.829 0.829
#> 2 <asreml>     0.829 0.829 0.829