Introduction
This post was originally written as a response to Wright et al., 2017, and is supplemental to the eLetter we wrote in response to that acticle.
Overview
In a break from Wright et al., we used the more recent approach to calulating R2 for mixed model from Nakagawa & Schielzeth 2013 as implemented in the MuMIn package.
The Nakagawa and Shielzeth method calculates a marginal R2 that shows the proportion of variation attributable to fixed effects only (analagous to those reported by Wright et al.), and also a conditional R2 that shows the total variation explained by the model (both fixed and random effects)
### Load Packages
require(ggplot2) # Needed for plotting
require(cowplot) # Needed for publication-quality ggplots
require(dplyr) # Needed for data wrangling
require(readxl) # Needed to read in the Excel file
require(lme4) # Needed for mixed modelling
require(MuMIn) # Needed for R^2 calculation
require(knitr) # Needed to print out tables
require(readxl) # Needed to read in excel files
### Import a function to make a nice table with AIC and R^2
source("AIC.R2.table.R")
### Import the Wright et al. dataset
# Specify the Science URL for the Wright et al. dataset
# NOTE: if this doesn't work, use read_excel() to import the dataset directly.
dataURL <- "http://science.sciencemag.org/highwire/filestream/698792/field_highwire_adjunct_files/1/aal4760-Wright-SM_Data_Set_S1.xlsx"
# Download the xlsx dataset and read into R
tmpfile <- tempfile(fileext = ".xlsx")
download.file(dataURL, tmpfile, mode = "wb")
data <- read_excel(path = tmpfile, sheet = "Global leaf size dataset")
# Clean up the dataset
global <- data %>%
# Select columns: family, species, site, size, latitude, & climate variables
select(Family, Species = `Genus species`, Site = `Site name`,
Leaf.size = `Leaf size (cm2)`, Latitude, MAT, MAP, MIann,
Tgs, RADann, Compound_Simple) %>%
# Filter out all rows without a leaf size
filter(!is.na(Leaf.size))
# Show dataset structure
#str(global)
##### Random Effect Models #####
# Model with Site + Species random effects
sitesp <- lmer(log10(Leaf.size) ~ (1|Site) + (1|Species), data = global)
# Model with Family random effect
family <- lmer(log10(Leaf.size) ~ (1|Family), data = global)
# Model with Site + Family + Species random effects
sitefamilysp <- lmer(log10(Leaf.size) ~ (1|Site) + (1|Family) + (1|Species),
data = global)
Latitude
The best model for explaining latitudinal gradients in leaf size includes Site, Species, and Family as random effects. Models with family alone outperform models that include Latitude without random effects. In the model used by Wright et al., with species and site as random effects, most of the variance was explained by these random effects, rather than latitude.
##### Latitude Models #####
# Full Wright et al. model: Latitude + Site + Species
lat.m1 <- lmer(log10(Leaf.size) ~ poly(Latitude, 2, raw = TRUE) +
(1|Site) + (1|Species), data = global)
# Full Wright et al model with Family: Latitude + Site + Family + Species
lat.m2 <- lmer(log10(Leaf.size) ~ poly(Latitude, 2, raw = TRUE) +
(1|Site) + (1|Family) + (1|Species), data = global)
# Model with only Latitude: no random effects
lat.m3 <- lm(log10(Leaf.size) ~ poly(Latitude, 2, raw = TRUE), data = global)
# Make a table with AIC and Marginal and Conditional R^2
lat.tbl <- AIC.R2.table(lat.m1, lat.m2, lat.m3, sitesp, family, sitefamilysp,
mnames = c("Latitude + Species + Site (Wright)",
"Latitude + Site + Family + Species", "Latitude", "Site + Species",
"Family", "Site + Family + Species"))
# Print out a markdown table
kable(lat.tbl, format = "markdown")
Model | AIC | dAIC | df | R2.marg | R2.cond |
---|---|---|---|---|---|
Latitude + Site + Family + Species | 14986.72 | 0.00 | 7 | 0.171 | 0.948 |
Site + Family + Species | 15386.82 | 400.10 | 5 | 0.000 | 0.947 |
Latitude + Species + Site (Wright) | 16538.27 | 1551.54 | 6 | 0.231 | 0.945 |
Site + Species | 16948.59 | 1961.87 | 4 | 0.000 | 0.945 |
Family | 29081.79 | 14095.06 | 3 | 0.000 | 0.481 |
Latitude | 30835.92 | 15849.20 | 4 | 0.282 | 0.282 |
MAP
##### MAP Models #####
# Full Wright et al. model: MAP + Site + Species
map.m1 <- lmer(log10(Leaf.size) ~ MAP +
(1|Site) + (1|Species), data = global)
# Full Wright et al model with Family: MAP + Site + Family + Species
map.m2 <- lmer(log10(Leaf.size) ~ MAP +
(1|Site) + (1|Family) + (1|Species), data = global)
# Model with only MAP: no random effects
map.m3 <- lm(log10(Leaf.size) ~ MAP, data = global)
# Make a table with AIC and Marginal and Conditional R^2
MAT.tbl <- AIC.R2.table(map.m1, map.m2, map.m3, sitesp, family, sitefamilysp,
mnames = c("MAP + Species + Site (Wright)",
"MAP + Site + Family + Species", "MAP", "Site + Species",
"Family", "Site + Family + Species"))
# Print out a markdown table
kable(MAT.tbl, format = "markdown")
Model | AIC | dAIC | df | R2.marg | R2.cond |
---|---|---|---|---|---|
MAP + Site + Family + Species | 15305.31 | 0.00 | 6 | 0.051 | 0.947 |
Site + Family + Species | 15386.82 | 81.51 | 5 | 0.000 | 0.947 |
MAP + Species + Site (Wright) | 16859.78 | 1554.46 | 5 | 0.076 | 0.945 |
Site + Species | 16948.59 | 1643.28 | 4 | 0.000 | 0.945 |
Family | 29081.79 | 13776.47 | 3 | 0.000 | 0.481 |
MAP | 33228.50 | 17923.18 | 3 | 0.142 | 0.142 |
MAT
##### MAT Models #####
# Full Wright et al. model: MAT + Site + Species
mat.m1 <- lmer(log10(Leaf.size) ~ MAT +
(1|Site) + (1|Species), data = global)
# Full Wright et al model with Family: MAT + Site + Family + Species
mat.m2 <- lmer(log10(Leaf.size) ~ MAT +
(1|Site) + (1|Family) + (1|Species), data = global)
# Model with only MAT: no random effects
mat.m3 <- lm(log10(Leaf.size) ~ MAT, data = global)
# Make a table with AIC and Marginal and Conditional R^2
MAT.tbl <- AIC.R2.table(mat.m1, mat.m2, mat.m3, sitesp, family, sitefamilysp,
mnames = c("MAT + Species + Site (Wright)",
"MAT + Site + Family + Species", "MAT", "Site + Species",
"Family", "Site + Family + Species"))
# Print out a markdown table
kable(MAT.tbl, format = "markdown")
Model | AIC | dAIC | df | R2.marg | R2.cond |
---|---|---|---|---|---|
MAT + Site + Family + Species | 15216.39 | 0.00 | 6 | 0.075 | 0.947 |
Site + Family + Species | 15386.82 | 170.43 | 5 | 0.000 | 0.947 |
MAT + Species + Site (Wright) | 16751.16 | 1534.76 | 5 | 0.112 | 0.944 |
Site + Species | 16948.59 | 1732.20 | 4 | 0.000 | 0.945 |
Family | 29081.79 | 13865.39 | 3 | 0.000 | 0.481 |
MAT | 33029.21 | 17812.81 | 3 | 0.155 | 0.155 |
MI
##### MI Models #####
# Full Wright et al. model: MI + Site + Species
mi.m1 <- lmer(log10(Leaf.size) ~ MIann +
(1|Site) + (1|Species), data = global)
# Full Wright et al model with Family: MI + Site + Family + Species
mi.m2 <- lmer(log10(Leaf.size) ~ MIann +
(1|Site) + (1|Family) + (1|Species), data = global)
# Model with only MI: no random effects
mi.m3 <- lm(log10(Leaf.size) ~ MIann, data = global)
# Make a table with AIC and Marginal and Conditional R^2
MI.tbl <- AIC.R2.table(mi.m1, mi.m2, mi.m3, sitesp, family, sitefamilysp,
mnames = c("MI + Species + Site (Wright)",
"MI + Site + Family + Species", "MI", "Site + Species",
"Family", "Site + Family + Species"))
# Print out a markdown table
kable(MI.tbl, format = "markdown")
Model | AIC | dAIC | df | R2.marg | R2.cond |
---|---|---|---|---|---|
Site + Family + Species | 15386.82 | 0.00 | 5 | 0.000 | 0.947 |
MI + Site + Family + Species | 15391.32 | 4.50 | 6 | 0.002 | 0.947 |
Site + Species | 16948.59 | 1561.77 | 4 | 0.000 | 0.945 |
MI + Species + Site (Wright) | 16952.43 | 1565.60 | 5 | 0.003 | 0.945 |
Family | 29081.79 | 13694.97 | 3 | 0.000 | 0.481 |
MI | 35029.96 | 19643.14 | 3 | 0.020 | 0.020 |
TGS
##### TGS Models #####
# Full Wright et al. model: TGS + Site + Species
tgs.m1 <- lmer(log10(Leaf.size) ~ Tgs +
(1|Site) + (1|Species), data = global)
# Full Wright et al model with Family: TGS + Site + Family + Species
tgs.m2 <- lmer(log10(Leaf.size) ~ Tgs +
(1|Site) + (1|Family) + (1|Species), data = global)
# Model with only TGS: no random effects
tgs.m3 <- lm(log10(Leaf.size) ~ Tgs, data = global)
# Make a table with AIC and Marginal and Conditional R^2
TGS.tbl <- AIC.R2.table(tgs.m1, tgs.m2, tgs.m3, sitesp, family, sitefamilysp,
mnames = c("TGS + Species + Site (Wright)",
"TGS + Site + Family + Species", "TGS", "Site + Species",
"Family", "Site + Family + Species"))
# Print out a markdown table
kable(TGS.tbl, format = "markdown")
Model | AIC | dAIC | df | R2.marg | R2.cond |
---|---|---|---|---|---|
TGS + Site + Family + Species | 15089.07 | 0.00 | 6 | 0.120 | 0.947 |
Site + Family + Species | 15386.82 | 297.76 | 5 | 0.000 | 0.947 |
TGS + Species + Site (Wright) | 16620.02 | 1530.96 | 5 | 0.172 | 0.944 |
Site + Species | 16948.59 | 1859.52 | 4 | 0.000 | 0.945 |
Family | 29081.79 | 13992.72 | 3 | 0.000 | 0.481 |
TGS | 32060.89 | 16971.82 | 3 | 0.214 | 0.214 |
RAD
##### RAD Models #####
# Full Wright et al. model: RAD + Site + Species
rad.m1 <- lmer(log10(Leaf.size) ~ RADann +
(1|Site) + (1|Species), data = global)
# Full Wright et al model with Family: RAD + Site + Family + Species
rad.m2 <- lmer(log10(Leaf.size) ~ RADann +
(1|Site) + (1|Family) + (1|Species), data = global)
# Model with only RAD: no random effects
rad.m3 <- lm(log10(Leaf.size) ~ RADann, data = global)
# Make a table with AIC and Marginal and Conditional R^2
RAD.tbl <- AIC.R2.table(rad.m1, rad.m2, rad.m3, sitesp, family, sitefamilysp,
mnames = c("RAD + Species + Site (Wright)",
"RAD + Site + Family + Species", "RAD", "Site + Species",
"Family", "Site + Family + Species"))
# Print out a markdown table
kable(RAD.tbl, format = "markdown")
Model | AIC | dAIC | df | R2.marg | R2.cond |
---|---|---|---|---|---|
Site + Family + Species | 15386.82 | 0.00 | 5 | 0.000 | 0.947 |
RAD + Site + Family + Species | 15395.92 | 9.10 | 6 | 0.003 | 0.947 |
Site + Species | 16948.59 | 1561.77 | 4 | 0.000 | 0.945 |
RAD + Species + Site (Wright) | 16953.90 | 1567.08 | 5 | 0.006 | 0.945 |
Family | 29081.79 | 13694.97 | 3 | 0.000 | 0.481 |
RAD | 35260.60 | 19873.78 | 3 | 0.003 | 0.003 |
Plotting the data
Let’s recreate the plot in Wright et al (more or less)
# Leaf Size ~ Latitude
ggplot(data = global, aes(x = Latitude, y = log10(Leaf.size)))+
geom_point(pch = 1, aes(color = Compound_Simple), alpha = 0.7) +
scale_color_manual(values = c("darkorange", "darkorchid4")) +
geom_smooth(method = 'lm', formula = y ~ poly(x, 2), color = "black", se = F) +
ylab("Log[Leaf Size]") +
geom_quantile(quantiles = c(0.05, 0.95),formula = y ~ poly(x, 2), lty = 2, color = "black")
Now let’s plot Latitude against leaf size, but with separate lines for each family (we’ll use straight lines here, and take out the simple-compound coloring)
# Leaf Size ~ Latitude by family
ggplot(data = global, aes(x = Latitude, y = log10(Leaf.size)))+
geom_point(pch = 1, alpha = 0.7) +
ylab("Log[Leaf Size]") +
geom_smooth(method = 'lm', formula = y~x, aes(group = Family), color = "black", se = F)
References
Wright IJ, Dong N, Maire V, Prentice IC, Westoby M, Díaz S, Gallagher R. 2017. Global climatic drivers of leaf size. Science, 357, 917-921. DOI: 10.1126/science.aal4760
Session Information
R version 3.4.2 (2017-09-28)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] quantreg_5.33 SparseM_1.77 bindrcpp_0.2 knitr_1.20 MuMIn_1.40.0
[6] lme4_1.1-17 Matrix_1.2-11 readxl_1.0.0 dplyr_0.7.4 cowplot_0.7.0
[11] ggplot2_2.2.1
loaded via a namespace (and not attached):
[1] Rcpp_0.12.17 highr_0.6 nloptr_1.0.4
[4] pillar_1.1.0 compiler_3.4.2 cellranger_1.1.0
[7] plyr_1.8.4 bindr_0.1 prettydoc_0.2.1
[10] tools_3.4.2 digest_0.6.15 evaluate_0.10
[13] tibble_1.4.2 gtable_0.2.0 nlme_3.1-131
[16] lattice_0.20-35 pkgconfig_2.0.1 rlang_0.2.0
[19] yaml_2.1.19 stringr_1.3.0 MatrixModels_0.4-1
[22] stats4_3.4.2 rprojroot_1.2 grid_3.4.2
[25] glue_1.2.0 R6_2.2.1 rmarkdown_1.9
[28] minqa_1.2.4 magrittr_1.5 codetools_0.2-15
[31] backports_1.1.2 scales_0.5.0 htmltools_0.3.6
[34] splines_3.4.2 MASS_7.3-50 assertthat_0.2.0
[37] colorspace_1.3-2 labeling_0.3 stringi_1.1.7
[40] lazyeval_0.2.1 munsell_0.4.3