This was been updated Friday afternoon, 17 Nov. 2017
# for plotting
library(ggplot2)
# for our web construction and food web properties
library(bipartite)
library(igraph)
library(rARPACK)
# for structural equation models (including path analysis)
library(lavaan)
In this lab, we’ll take a stab at investiagting the same questions as in Thebault and Fontaine (2010). Are consumptive and mutualistic networks structured differently? If so, how do those structures contribute to the stability of those webs?
To investigate those questions, we will use a different approach than that of Thebault and Fontaine. Thebault and Fontaine (2010) simulated dynamic communities using systems of ODEs that are similar to those that we have seen in earlier in this course. For instance, they used the same sort of mathematical expressions, such as negative density dependence and type II functional responses, that we saw previously in our lab using Rosenzweig and MacArthur’s predator-prey model, and in mutualisms.
We will use the approach of May (1973) and Pimm and Lawton (1977, 1978). In this approach, we do not simulate the dynamics. Instead, we assume that the species involved coexist, and that we know how they interact. Specifically, that we know their instantaneous per capita effect on each other’s population growth rate. That is, we know the Jacobian matrix that describes their interactions. That is what Stuart Pimm and John Lawton assumed in their approach in their groundbreaking research (Stevens, 2009).
In our approach, we will establish interactions at random, in which each pair of species (plant and animal) has the same probability of interacting. That probability is connectance (\(L/L^2\)). This means that the structure (who is connected to whom) will be determined randomly rather than as a result of the dynamics of ODE models as in Thebault and Fontaine (2010). Further, the number of species will be and the connectance will both be draw at random, from specified ranges.
We’ll start by creating a bipartite web of mutualists: plants and their pollinators.
# The number of species of plants
Sp <- 5
# The number of species of pollinators
Sa <- 12
# the total number of species
S <- Sa+Sp
We then set the connectance, and then generate random interactions between species.
# The connectance in this web.
contc <- .5
# Create interactions at random, drawing 0's and 1's with a probability of contc=0.5
interactions <- rbinom( n = Sa * Sp, size=1, prob=contc)
# Put those connections into our web
bn <- matrix(interactions, nr=Sp, nc=Sa)
rownames(bn) <- paste("plant", LETTERS[1:Sp], sep="")
colnames(bn) <- paste("bug", LETTERS[1:Sa], sep="")
#...and look at it
bn
## bugA bugB bugC bugD bugE bugF bugG bugH bugI bugJ bugK bugL
## plantA 0 1 0 1 0 0 1 0 0 0 1 0
## plantB 0 0 0 1 0 0 1 1 1 0 1 1
## plantC 0 0 0 1 0 0 1 0 1 1 0 0
## plantD 1 1 1 1 1 0 1 0 1 0 0 0
## plantE 0 1 0 0 1 0 0 0 1 1 0 1
Now that we have randomly constructed web, let’s create a realistic assumption about how much each of the pollinators interact with those plant species. It is generally observed that most interactions are weak (i.e. infrequent) and a few are strong (i.e. frequent). That pattern is an exponential distribution. We will create those interactions and then plot them.
# Exponentially distributed of interaction strengths
# Random numbers from and exponential distribution
x <- rexp(Sa*Sp)
# express these as a probability distribution (divide by the sum)
xp <- x/sum(x)
# assign those exponential probabilites to our interactions.
bne <- bn * xp
# graph everything...
{
layout(matrix(c(1,2,3,3), nc=2, byrow=T) )
hist(bne, main="", xlab="interaction strength")
visweb(bne)
plotweb(bne)
}
That is just an example of a web we will create in our simulation—we create a bipartite web with a random number of species, and random connectance, each within specified bounds.
We have a function we can use to investigate our ideas, which we load here. Make sure that bip_stability.R is in your working directory.
source("bip_stability.R")
In our webs, we can compare the effects of negative vs. positive interactions directly, because we will create one network with interaction strengths, and then simply reverse the signs of the effects of the animals on the plants to get herbivory vs. mutualism.
We simulate 1000 random bipartite webs using a large number of different numbers of plant and animal species. We select a connectance by drawing randomly from a uniform distribution between the values in argument C.
The function bip_stability() performs eigananalysis on the resulting Jacobian matrix to estimate resilience (the real part of the dominant eigenvalue x -1). It also calculates nestedness and modularity in ways similar to that in Thebault and Fontaine (2010), and it tallies diversity as the total number of species and the connectance used for each of the simulated webs.
b <- bip_stability(Spp.a = 16:60, Spp.p = 8:30, C=c(.05, 0.5), reps=1000)
We can get a summary of the output of the 1000 simulated webs here.
summary(b$out)
## S C modularity nestedness
## Min. :18.00 Min. :0.06861 Min. :0.0000 Min. : 1.681
## 1st Qu.:43.00 1st Qu.:0.17644 1st Qu.:0.0000 1st Qu.: 9.161
## Median :55.00 Median :0.27598 Median :0.0885 Median :14.819
## Mean :55.38 Mean :0.28297 Mean :0.1930 Mean :14.588
## 3rd Qu.:68.00 3rd Qu.:0.38889 3rd Qu.:0.3644 3rd Qu.:20.296
## Max. :90.00 Max. :0.54545 Max. :0.8289 Max. :30.228
## resilience.m resilience.h
## Min. :0.00919 Min. :0.004902
## 1st Qu.:0.02857 1st Qu.:0.014018
## Median :0.03895 Median :0.018856
## Mean :0.04443 Mean :0.021689
## 3rd Qu.:0.05582 3rd Qu.:0.027152
## Max. :0.17657 Max. :0.077294
Are these webs stable? What are the medians and ranges of each of the web properties? How do the resiliences of the two interaction types differ?
We can also graph these relations.
pairs(b$out)
Do any of these relate to figures in Thebault and Fontaine (2010)?
Now we do the same sort of analysis that Thebault and Fontaine did to get their Fig. 2 C,D.
We start by scaling our data so that all variables have a mean of zero and a standard deviation of 1.
dat<- data.frame( scale(b$out) )
We specify each of the relationships, where y ~ x is “y as a function of x”. We then fit the model and get the path coefficients.
We start with the mutualism web.
# Step 1: Specify model
model <- 'resilience.m ~ nestedness + modularity + S + C
nestedness ~ S + C
modularity ~ S + C'
# Step 2: Estimate model of mutualism
mod.m.fit <- sem(model, data=dat)
summary(mod.m.fit)
## lavaan 0.6-3 ended normally after 40 iterations
##
## Optimization method NLMINB
## Number of free parameters 11
##
## Number of observations 1000
##
## Estimator ML
## Model Fit Test Statistic 111.512
## Degrees of freedom 1
## P-value (Chi-square) 0.000
##
## Parameter Estimates:
##
## Information Expected
## Information saturated (h1) model Structured
## Standard Errors Standard
##
## Regressions:
## Estimate Std.Err z-value P(>|z|)
## resilience.m ~
## nestedness 0.297 0.080 3.716 0.000
## modularity 0.178 0.040 4.501 0.000
## S -0.621 0.023 -27.444 0.000
## C 0.420 0.085 4.930 0.000
## nestedness ~
## S 0.032 0.007 4.285 0.000
## C 0.967 0.007 130.177 0.000
## modularity ~
## S -0.314 0.015 -20.930 0.000
## C -0.777 0.015 -51.791 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .resilience.m 0.343 0.015 22.361 0.000
## .nestedness 0.054 0.002 22.361 0.000
## .modularity 0.219 0.010 22.361 0.000
Look at the estimates of the regressions. Those are the path coefficients.
Now it is up to you to get a pencil and paper and draw the picture….
Next, do the same thing for herbivory.
# Step 1: Specify model
model <- 'resilience.h ~ nestedness + modularity + S + C
nestedness ~ S + C
modularity ~ S + C'
# Step 2: Estimate model of herbivory
mod.h.fit <- sem(model, data=dat)
hfit <- summary(mod.h.fit)
## lavaan 0.6-3 ended normally after 35 iterations
##
## Optimization method NLMINB
## Number of free parameters 11
##
## Number of observations 1000
##
## Estimator ML
## Model Fit Test Statistic 111.512
## Degrees of freedom 1
## P-value (Chi-square) 0.000
##
## Parameter Estimates:
##
## Information Expected
## Information saturated (h1) model Structured
## Standard Errors Standard
##
## Regressions:
## Estimate Std.Err z-value P(>|z|)
## resilience.h ~
## nestedness 0.501 0.069 7.222 0.000
## modularity -0.087 0.034 -2.533 0.011
## S -0.780 0.020 -39.618 0.000
## C 0.005 0.074 0.068 0.946
## nestedness ~
## S 0.032 0.007 4.285 0.000
## C 0.967 0.007 130.177 0.000
## modularity ~
## S -0.314 0.015 -20.930 0.000
## C -0.777 0.015 -51.791 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .resilience.h 0.259 0.012 22.361 0.000
## .nestedness 0.054 0.002 22.361 0.000
## .modularity 0.219 0.010 22.361 0.000