2011 Josef C Uyeda & Stevan J Arnold (revised July 9, 2021)

Estimating heritability for garter snake litters

Getting data into R

Get your data into R by following the following steps.Save the entire Exercise 1.1 directory, including our data file: R_inland_snake_data.txt If needed, set your working directory by putting the path to the downloaded folder you created in the following statement. If you opened this R session and script from the Exercise directory, you can use relative paths and skip this step. Be sure and use the / not the  spacing convention!

library(dplyr)
setwd('./') #You may need to set your working directory to where you downloaded the files

Our dataset contains garter snake scale counts for mothers and their offspring. Scale counts are good for this sort of comparison because they do not vary with ontogeny. Why is this important? Why does this simplify estimating heritability from a parent-offspring regression?

thamnophis <- read.table('R_inland_snake_data.txt',header=TRUE)
thamnophis

Here, each family represents a gravid female snake that was caught and all of her offspring. The first entry for a given family is the mother’s trait data. The subsequent entries are her kids. We will use dplyr to reorganize the dataset into two sets of columns for each family calculating the mother’s and the kids’ trait means. Male snakes tend to have higher vertebral counts than female snakes. This dataset has already had the effects of sex removed (which explains why some kids have fractional scale counts).

thamnophis <- group_by(thamnophis, family) # Use the variable `family` as a grouping variable
moms <- filter(thamnophis, row_number()==1) # Extract first row for each family
kids <- filter(thamnophis, row_number()!=1) %>% dplyr::summarize(., across(body:post, ~ mean(.x, na.rm=TRUE))) #Extract all but the first row for each family, and summarize by averaging all traits, from `body` to `post`.
families <- left_join(moms, kids, "family", suffix=c(".mom", ".kids")) #Re-join mom and kids
families

Now we can estimate heritabilities from a parent-offspring regression. Plot the mother and offspring body vertebrae and fit a linear regression. Then add a trendline from the linear regression fit.

plot(families$body.mom, families$body.kids, pch=19, col="blue", cex=1.5, xlab="Body (Dam)", ylab="Body (Offspring)")
lm1 <- lm(body.kids ~ body.mom, data=families)
abline(lm1, lwd=5, lty=2)

summary(lm1)

Call:
lm(formula = body.kids ~ body.mom, data = families)

Residuals:
    Min      1Q  Median      3Q     Max 
-7.7707 -1.5516 -0.0373  1.7237  8.0121 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 110.40290   10.30783  10.711  < 2e-16 ***
body.mom      0.33906    0.06204   5.465  1.9e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.698 on 149 degrees of freedom
  (10 observations deleted due to missingness)
Multiple R-squared:  0.167, Adjusted R-squared:  0.1614 
F-statistic: 29.87 on 1 and 149 DF,  p-value: 1.898e-07
h2 <- list() #heritability
Vp <- list() #phenotypic variance
Va <- list() #additive genetic variance

h2$body <- 2*unname(lm1$coefficients[2]) #Remember we only have 1 of the parents. Use the slope from the linear model 
               # by using `lm1$coefficients[2]`
Vp$body <- var(moms$body, na.rm=TRUE) # Could also include offspring, but non-independent samples
Va$body <- h2$body*Vp$body # Use equation for heritability

Now repeat the analysis for tail (and other variables).

fits <- list()
par(mfrow=c(2,3))
for(i in 3:8){ #iterate over each of the traits
  trait <- colnames(thamnophis)[i]
  fits[[trait]] <- lm(families[[i+6]] ~ families[[i]])
  plot(families[[i]], families[[i+6]], pch=19, col="blue", cex=1.5, xlab="Dam", ylab="Offspring", main=trait)
  abline(fits[[trait]], lty=2, lwd=5)
}


h2 <- sapply(fits, function(x) 2*unname(x$coefficients[2]))
h2
       body        tail         mid        ilab        slab        post 
 0.67811916  0.46110175  0.25110435  0.07257756 -0.08889161  0.35312629 

How much confidence should we have in these estimates? One way to estimate uncertainty and confidence limits with minimal distributional assumptions is to conduct a bootstrap.

nreps <- 1000 # Number of bootstrap replicates
bootsample <- matrix(NA, nrow=nreps, ncol=6) # Create an empty matrix where we will store results
colnames(bootsample) <- colnames(thamnophis)[3:8] # Set the column names of the empty results matrix
for(i in 1:nreps){
  samp <- sample(1:nrow(families), nrow(families), replace=TRUE) # Key step to a bootstrap: Resample families with replacement
  .newfamilies <- families[samp,] #Use the resampled families to create a new dataset where different families are randomly reweighted in frequency
  h2row <- list() #Stpre results for each trait
  for(j in 3:8){ #iterate over each of the traits
    trait <- colnames(thamnophis)[j] 
    h2row[[trait]] <- 2*unname(lm(.newfamilies[[j+6]] ~ .newfamilies[[j]])$coefficients[2])
  }
  bootsample[i,] <- do.call(c, h2row)
}

Now we can plot our resulting distributions:


par(mfrow=c(3,2))
for(i in 1:ncol(bootsample)){
  hist(bootsample[,i], main=colnames(bootsample)[i], xlim=c(-0.5, 1.5), breaks=nreps/20, xlab="heritability") 
  abline(v=mean(bootsample[,i]), lty=2, lwd=3)
  abline(v=0, lwd=2, col="red")
  abline(v=1, lwd=2, col="red")
}

Here, we ignored variation in the sizes of families. How should that affect our analyses?

LS0tCnRpdGxlOiAiQ2FsY3VsYXRpbmcgaGVyaXRhYmlsaXR5IGZyb20gdGhlIHBhcmVudC1vZmZzcHJpbmcgcmVncmVzc2lvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKMjAxMSBKb3NlZiBDIFV5ZWRhICYgU3RldmFuIEogQXJub2xkCihyZXZpc2VkIEp1bHkgOSwgMjAyMSkKCiMgRXN0aW1hdGluZyBoZXJpdGFiaWxpdHkgZm9yIGdhcnRlciBzbmFrZSBsaXR0ZXJzCiMjIEdldHRpbmcgZGF0YSBpbnRvIFIKCkdldCB5b3VyIGRhdGEgaW50byBSIGJ5IGZvbGxvd2luZyB0aGUgZm9sbG93aW5nIHN0ZXBzLlNhdmUgdGhlIGVudGlyZSBFeGVyY2lzZSAxLjEgZGlyZWN0b3J5LCBpbmNsdWRpbmcgb3VyIGRhdGEgZmlsZTogUl9pbmxhbmRfc25ha2VfZGF0YS50eHQKSWYgbmVlZGVkLCBzZXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeSBieSBwdXR0aW5nIHRoZSBwYXRoIHRvIHRoZSBkb3dubG9hZGVkIGZvbGRlciB5b3UgY3JlYXRlZCBpbiB0aGUgZm9sbG93aW5nIHN0YXRlbWVudC4gCklmIHlvdSBvcGVuZWQgdGhpcyBSIHNlc3Npb24gYW5kIHNjcmlwdCBmcm9tIHRoZSBFeGVyY2lzZSBkaXJlY3RvcnksIHlvdSBjYW4gdXNlIHJlbGF0aXZlIHBhdGhzIGFuZCBza2lwIHRoaXMgc3RlcC4KQmUgc3VyZSBhbmQgdXNlIHRoZSAvIG5vdCB0aGUgXCBzcGFjaW5nIGNvbnZlbnRpb24hCgpgYGB7cn0KbGlicmFyeShkcGx5cikKc2V0d2QoJy4vJykgI1lvdSBtYXkgbmVlZCB0byBzZXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeSB0byB3aGVyZSB5b3UgZG93bmxvYWRlZCB0aGUgZmlsZXMKYGBgCgpPdXIgZGF0YXNldCBjb250YWlucyBnYXJ0ZXIgc25ha2Ugc2NhbGUgY291bnRzIGZvciBtb3RoZXJzIGFuZCB0aGVpciBvZmZzcHJpbmcuIFNjYWxlIGNvdW50cyBhcmUgZ29vZCBmb3IgdGhpcyBzb3J0IG9mIGNvbXBhcmlzb24gYmVjYXVzZQp0aGV5IGRvIG5vdCB2YXJ5IHdpdGggb250b2dlbnkuIFdoeSBpcyB0aGlzIGltcG9ydGFudD8gV2h5IGRvZXMgdGhpcyBzaW1wbGlmeSBlc3RpbWF0aW5nIGhlcml0YWJpbGl0eSBmcm9tIGEgcGFyZW50LW9mZnNwcmluZyByZWdyZXNzaW9uPwoKYGBge3J9CnRoYW1ub3BoaXMgPC0gcmVhZC50YWJsZSgnUl9pbmxhbmRfc25ha2VfZGF0YS50eHQnLGhlYWRlcj1UUlVFKQp0aGFtbm9waGlzCmBgYAoKSGVyZSwgZWFjaCBmYW1pbHkgcmVwcmVzZW50cyBhIGdyYXZpZCBmZW1hbGUgc25ha2UgdGhhdCB3YXMgY2F1Z2h0IGFuZCBhbGwgb2YgaGVyIG9mZnNwcmluZy4gVGhlIGZpcnN0IGVudHJ5IGZvciBhIGdpdmVuIGZhbWlseSBpcyB0aGUgbW90aGVyJ3MgdHJhaXQgCmRhdGEuIFRoZSBzdWJzZXF1ZW50IGVudHJpZXMgYXJlIGhlciBraWRzLiBXZSB3aWxsIHVzZSBgZHBseXJgIHRvIHJlb3JnYW5pemUgdGhlIGRhdGFzZXQgaW50byB0d28gc2V0cyBvZiBjb2x1bW5zIGZvciBlYWNoIGZhbWlseSBjYWxjdWxhdGluZwp0aGUgbW90aGVyJ3MgYW5kIHRoZSBraWRzJyB0cmFpdCBtZWFucy4gTWFsZSBzbmFrZXMgdGVuZCB0byBoYXZlIGhpZ2hlciB2ZXJ0ZWJyYWwgY291bnRzIHRoYW4gZmVtYWxlIHNuYWtlcy4gVGhpcyBkYXRhc2V0IGhhcyBhbHJlYWR5IGhhZCB0aGUgZWZmZWN0cwpvZiBzZXggcmVtb3ZlZCAod2hpY2ggZXhwbGFpbnMgd2h5IHNvbWUga2lkcyBoYXZlIGZyYWN0aW9uYWwgc2NhbGUgY291bnRzKS4KCmBgYHtyfQp0aGFtbm9waGlzIDwtIGdyb3VwX2J5KHRoYW1ub3BoaXMsIGZhbWlseSkgIyBVc2UgdGhlIHZhcmlhYmxlIGBmYW1pbHlgIGFzIGEgZ3JvdXBpbmcgdmFyaWFibGUKbW9tcyA8LSBmaWx0ZXIodGhhbW5vcGhpcywgcm93X251bWJlcigpPT0xKSAjIEV4dHJhY3QgZmlyc3Qgcm93IGZvciBlYWNoIGZhbWlseQpraWRzIDwtIGZpbHRlcih0aGFtbm9waGlzLCByb3dfbnVtYmVyKCkhPTEpICU+JSBkcGx5cjo6c3VtbWFyaXplKC4sIGFjcm9zcyhib2R5OnBvc3QsIH4gbWVhbigueCwgbmEucm09VFJVRSkpKSAjRXh0cmFjdCBhbGwgYnV0IHRoZSBmaXJzdCByb3cgZm9yIGVhY2ggZmFtaWx5LCBhbmQgc3VtbWFyaXplIGJ5IGF2ZXJhZ2luZyBhbGwgdHJhaXRzLCBmcm9tIGBib2R5YCB0byBgcG9zdGAuCmZhbWlsaWVzIDwtIGxlZnRfam9pbihtb21zLCBraWRzLCAiZmFtaWx5Iiwgc3VmZml4PWMoIi5tb20iLCAiLmtpZHMiKSkgI1JlLWpvaW4gbW9tIGFuZCBraWRzCmZhbWlsaWVzCmBgYAoKTm93IHdlIGNhbiBlc3RpbWF0ZSBoZXJpdGFiaWxpdGllcyBmcm9tIGEgcGFyZW50LW9mZnNwcmluZyByZWdyZXNzaW9uLiBQbG90IHRoZSBtb3RoZXIgYW5kIG9mZnNwcmluZyBib2R5IHZlcnRlYnJhZSBhbmQgZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24uIApUaGVuIGFkZCBhIHRyZW5kbGluZSBmcm9tIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBmaXQuIAoKYGBge3J9CnBsb3QoZmFtaWxpZXMkYm9keS5tb20sIGZhbWlsaWVzJGJvZHkua2lkcywgcGNoPTE5LCBjb2w9ImJsdWUiLCBjZXg9MS41LCB4bGFiPSJCb2R5IChEYW0pIiwgeWxhYj0iQm9keSAoT2Zmc3ByaW5nKSIpCmxtMSA8LSBsbShib2R5LmtpZHMgfiBib2R5Lm1vbSwgZGF0YT1mYW1pbGllcykKYWJsaW5lKGxtMSwgbHdkPTUsIGx0eT0yKQpzdW1tYXJ5KGxtMSkKYGBgCgoKYGBge3J9CmgyIDwtIGxpc3QoKSAjaGVyaXRhYmlsaXR5ClZwIDwtIGxpc3QoKSAjcGhlbm90eXBpYyB2YXJpYW5jZQpWYSA8LSBsaXN0KCkgI2FkZGl0aXZlIGdlbmV0aWMgdmFyaWFuY2UKCmgyJGJvZHkgPC0gMip1bm5hbWUobG0xJGNvZWZmaWNpZW50c1syXSkgI1JlbWVtYmVyIHdlIG9ubHkgaGF2ZSAxIG9mIHRoZSBwYXJlbnRzLiBVc2UgdGhlIHNsb3BlIGZyb20gdGhlIGxpbmVhciBtb2RlbCAKICAgICAgICAgICAgICAgIyBieSB1c2luZyBgbG0xJGNvZWZmaWNpZW50c1syXWAKVnAkYm9keSA8LSB2YXIobW9tcyRib2R5LCBuYS5ybT1UUlVFKSAjIENvdWxkIGFsc28gaW5jbHVkZSBvZmZzcHJpbmcsIGJ1dCBub24taW5kZXBlbmRlbnQgc2FtcGxlcwpWYSRib2R5IDwtIGgyJGJvZHkqVnAkYm9keSAjIFVzZSBlcXVhdGlvbiBmb3IgaGVyaXRhYmlsaXR5CmBgYAoKTm93IHJlcGVhdCB0aGUgYW5hbHlzaXMgZm9yIHRhaWwgKGFuZCBvdGhlciB2YXJpYWJsZXMpLgoKYGBge3J9CmZpdHMgPC0gbGlzdCgpCnBhcihtZnJvdz1jKDIsMykpCmZvcihpIGluIDM6OCl7ICNpdGVyYXRlIG92ZXIgZWFjaCBvZiB0aGUgdHJhaXRzCiAgdHJhaXQgPC0gY29sbmFtZXModGhhbW5vcGhpcylbaV0KICBmaXRzW1t0cmFpdF1dIDwtIGxtKGZhbWlsaWVzW1tpKzZdXSB+IGZhbWlsaWVzW1tpXV0pCiAgcGxvdChmYW1pbGllc1tbaV1dLCBmYW1pbGllc1tbaSs2XV0sIHBjaD0xOSwgY29sPSJibHVlIiwgY2V4PTEuNSwgeGxhYj0iRGFtIiwgeWxhYj0iT2Zmc3ByaW5nIiwgbWFpbj10cmFpdCkKICBhYmxpbmUoZml0c1tbdHJhaXRdXSwgbHR5PTIsIGx3ZD01KQp9CgpoMiA8LSBzYXBwbHkoZml0cywgZnVuY3Rpb24oeCkgMip1bm5hbWUoeCRjb2VmZmljaWVudHNbMl0pKQpoMgpgYGAKCkhvdyBtdWNoIGNvbmZpZGVuY2Ugc2hvdWxkIHdlIGhhdmUgaW4gdGhlc2UgZXN0aW1hdGVzPyBPbmUgd2F5IHRvIGVzdGltYXRlCnVuY2VydGFpbnR5IGFuZCBjb25maWRlbmNlIGxpbWl0cyB3aXRoIG1pbmltYWwgZGlzdHJpYnV0aW9uYWwgYXNzdW1wdGlvbnMgaXMKdG8gY29uZHVjdCBhIGJvb3RzdHJhcC4KCmBgYHtyfQpucmVwcyA8LSAxMDAwICMgTnVtYmVyIG9mIGJvb3RzdHJhcCByZXBsaWNhdGVzCmJvb3RzYW1wbGUgPC0gbWF0cml4KE5BLCBucm93PW5yZXBzLCBuY29sPTYpICMgQ3JlYXRlIGFuIGVtcHR5IG1hdHJpeCB3aGVyZSB3ZSB3aWxsIHN0b3JlIHJlc3VsdHMKY29sbmFtZXMoYm9vdHNhbXBsZSkgPC0gY29sbmFtZXModGhhbW5vcGhpcylbMzo4XSAjIFNldCB0aGUgY29sdW1uIG5hbWVzIG9mIHRoZSBlbXB0eSByZXN1bHRzIG1hdHJpeApmb3IoaSBpbiAxOm5yZXBzKXsKICBzYW1wIDwtIHNhbXBsZSgxOm5yb3coZmFtaWxpZXMpLCBucm93KGZhbWlsaWVzKSwgcmVwbGFjZT1UUlVFKSAjIEtleSBzdGVwIHRvIGEgYm9vdHN0cmFwOiBSZXNhbXBsZSBmYW1pbGllcyB3aXRoIHJlcGxhY2VtZW50CiAgLm5ld2ZhbWlsaWVzIDwtIGZhbWlsaWVzW3NhbXAsXSAjVXNlIHRoZSByZXNhbXBsZWQgZmFtaWxpZXMgdG8gY3JlYXRlIGEgbmV3IGRhdGFzZXQgd2hlcmUgZGlmZmVyZW50IGZhbWlsaWVzIGFyZSByYW5kb21seSByZXdlaWdodGVkIGluIGZyZXF1ZW5jeQogIGgycm93IDwtIGxpc3QoKSAjU3RwcmUgcmVzdWx0cyBmb3IgZWFjaCB0cmFpdAogIGZvcihqIGluIDM6OCl7ICNpdGVyYXRlIG92ZXIgZWFjaCBvZiB0aGUgdHJhaXRzCiAgICB0cmFpdCA8LSBjb2xuYW1lcyh0aGFtbm9waGlzKVtqXSAKICAgIGgycm93W1t0cmFpdF1dIDwtIDIqdW5uYW1lKGxtKC5uZXdmYW1pbGllc1tbais2XV0gfiAubmV3ZmFtaWxpZXNbW2pdXSkkY29lZmZpY2llbnRzWzJdKQogIH0KICBib290c2FtcGxlW2ksXSA8LSBkby5jYWxsKGMsIGgycm93KQp9CgpgYGAKCk5vdyB3ZSBjYW4gcGxvdCBvdXIgcmVzdWx0aW5nIGRpc3RyaWJ1dGlvbnM6CgpgYGB7cn0KCnBhcihtZnJvdz1jKDMsMikpCmZvcihpIGluIDE6bmNvbChib290c2FtcGxlKSl7CiAgaGlzdChib290c2FtcGxlWyxpXSwgbWFpbj1jb2xuYW1lcyhib290c2FtcGxlKVtpXSwgeGxpbT1jKC0wLjUsIDEuNSksIGJyZWFrcz1ucmVwcy8yMCwgeGxhYj0iaGVyaXRhYmlsaXR5IikgCiAgYWJsaW5lKHY9bWVhbihib290c2FtcGxlWyxpXSksIGx0eT0yLCBsd2Q9MykKICBhYmxpbmUodj0wLCBsd2Q9MiwgY29sPSJyZWQiKQogIGFibGluZSh2PTEsIGx3ZD0yLCBjb2w9InJlZCIpCn0KYGBgCgpIZXJlLCB3ZSBpZ25vcmVkIHZhcmlhdGlvbiBpbiB0aGUgc2l6ZXMgb2YgZmFtaWxpZXMuIEhvdyBzaG91bGQgdGhhdCBhZmZlY3Qgb3VyIGFuYWx5c2VzPyAK