Jacobian stability metrics

Code
library(estar)
library(tidyr)
library(dplyr)
library(tibble)
#> Warning: package 'tibble' was built under R version 4.4.3
Code
library(ggplot2)
library(purrr)
library(viridis)
library(MARSS)
library(hesim)
library(kableExtra)
source("custom_aesthetics.R")

label_intensity <- function(intensity, mu){
  paste0("Conc = ", intensity, " micro g/L")
}

Calculation of the so-called “functional stability metrics” (in the context of the estar package) relies on the interaction strengths between species composing a community. This information is classically summarized in the community matrix (sensu Novak et al. 2016, detailed in the Glossary in the main text). In community models, this is equivalent to a time-discrete version (Downing et al. 2020) of the Jacobian matrix composed of the partial derivatives of the dynamical equations describing each species population growth (Domínguez-García, Dakos, and Kéfi 2019). In real-world communities, interaction strengths can be estimated with multivariate autoregressive state-space (MARSS) models.

In this vignette, we focus on explaining how a MARSS model works, how these models can be used with the functions provided by the estar package, and the issues that may arise when empirical data is limited. To facilitate understanding, we illustrate the definition of a MARSS model in the context of this application to an aquatic community. For a more general and formal definition, refer to the MARSS package documentation.

Overview of demonstration data

Similar to what we did for the univariate stability metrics, we illustrate the use of functional stability metrics on a dataset compiled from an ecotoxicological study about the effects of insecticide on a community of aquatic macroinvertebrates (Brink et al. 1996; Wijngaarden et al. 1996). The insecticide chlorpyrifos negatively affects freshwater macroinvertebrates, and, to a lesser degree, zooplankton species. This insecticide was applied at four different concentrations (0.1, 0.9, 6, and 44 \(\mu\)g/ L), with two replicates per concentration level. Additionally, four replicates were used as control, i.e. an undisturbed systems (‘baseline’ in estar terminology). The community is composed of 128 species, classified into 5 functional groups: herbivores, detritiherbivores, carnivores, omnivores, and detritivores.

Organism mean count (log axis) of the five functional groups over the course of ecotoxicological experiment. The vertical dashed line identifies the time when chloryfiros insecticide was applied (at week 0), and facets represent the different concentrations (micro g/L).
Organism mean count (log axis) of the five functional groups over the course of ecotoxicological experiment. The vertical dashed line identifies the time when chloryfiros insecticide was applied (at week 0), and facets represent the different concentrations (micro g/L).

MARSS models

Introduction to MARSS models

A complete MARSS model that describes a state process (\(\mathbf{X}\)) assessed via an observation process (\(\mathbf{Y}\)) is defined as: \[\begin{equation} \begin{gathered} \mathbf{x}_t = \mathbf{B}\mathbf{x}_{t-1}+\mathbf{u}+\mathbf{C}_{t}\mathbf{c}_{t}+\mathbf{w}_t \text{ where } \mathbf{w}_t \sim \ \text{MVN}(0,\mathbf{Q}) \\ \mathbf{y}_t = \mathbf{Z}\mathbf{x}_t+\mathbf{a}+\mathbf{D}_{t}\mathbf{d}_{t}+\mathbf{v}_t \text{ where } \mathbf{v}_t \sim \ \text{MVN}(0,\mathbf{R}) \\ \mathbf{x}_1 \sim\ \text{MVN}(\pi,\Lambda) \text{ or } \mathbf{x}_0 \sim\ \text{MVN}(\pi,\Lambda) \end{gathered} \end{equation}\]

where

\[\begin{equation} X= \begin{bmatrix} x_{fg1, t1} & x_{fg1, t2} & ... & x_{fg1, tT}\\ x_{fg2, t1} & x_{fg2, t2} & ... & x_{fg2, tT}\\ ... & ... & ... & ...\\ x_{fgm, t1} & x_{fgm, t2} & ... & x_{fgm, tT} \end{bmatrix} \end{equation}\] \[\begin{equation} Y= \begin{bmatrix} y_{1, t1} & y_{1, t2} & ... & y_{1, tT}\\ y_{2, t1} & y_{2, t2} & ... & y_{2, tT}\\ ... & ... & ... & ...\\ y_{n, t1} & y_{n, t2} & ... & y_{n, tT} \end{bmatrix} \end{equation}\]

Note that:

The state process (\(\mathbf{X}\)) is described by:

Thus, in matrix formulation:

\[\begin{equation} \begin{bmatrix} x_{1}\\ ... \\ x_{m} \end{bmatrix}_t = \begin{bmatrix} \beta_{\mathrm{1,1}} & ... & \beta_{\mathrm{1,m}} \\ ... & ... & ... \\ \beta_{\mathrm{m,1}} & ... & \beta_{\mathrm{m,m}} \end{bmatrix} \begin{bmatrix} x_{1}\\ ... \\ x_{m} \end{bmatrix}_{t-1} + \begin{bmatrix} u_{1}\\ ...\\ u_{m} \end{bmatrix} + \begin{bmatrix} \gamma_{\mathrm{1,1}} & ... & \gamma_{\mathrm{1,p}} \\ ... & ... & ... \\ \gamma_{\mathrm{m,1}} & ... & \gamma_{\mathrm{m,p}} \end{bmatrix} \begin{bmatrix} c_{\mathrm{1}} \\ ... \\ c_{\mathrm{m}} \end{bmatrix}_{t} + \begin{bmatrix} w_{1}\\ ...\\ w_{m} \end{bmatrix}_t \\ \end{equation}\]

The \(w_{t}\) errors follow a multivariate normal distribution of mean 0, and covariance \(\mathbf{Q}_t\) (a \(m \times m\) matrix). \[\begin{equation} \mathbf{w}_t \sim \,\text{MVN} \begin{pmatrix} 0, \begin{bmatrix} \sigma_{\mathrm{1}} & ... & \sigma_{\mathrm{1,m}} \\ ... & ... & ... \\ \sigma_{\mathrm{m,1}} & ... & \sigma_{\mathrm{m}} \\ \end{bmatrix} \end{pmatrix}\\ \end{equation}\]

where (\(\sigma\)) refer to variances of abundances (diagonal) and covariances among abundances of different species (off-diagonal).

The model initial conditions can be specified at \(t=0\) (\(x_0\)) or \(t=1\) (\(x_1\)).

\[\begin{equation} \begin{bmatrix} x_{fg1}\\ ...\\ x_{fgm} \end{bmatrix}_0 = \begin{bmatrix} \mu_1\\ ...\\ \mu_m \end{bmatrix}_t \end{equation}\]

The observation process (\(\mathbf{Y}\)) is described by:

In matrix formulation:

\[\begin{equation} \begin{bmatrix} y_{1}\\ ... \\ y_{n} \end{bmatrix}_t = \begin{bmatrix} \zeta_{\mathrm{1,1}} & ... & \zeta_{\mathrm{1,m}} \\ ... & ... & ... \\ \zeta_{\mathrm{m,1}} & ... & \zeta_{\mathrm{m,m}} \end{bmatrix} \begin{bmatrix} x_{1}\\ ... \\ x_{m} \end{bmatrix}_{t-1} + \begin{bmatrix} a_{obs1}\\ ...\\ a_{obsn} \end{bmatrix} + \begin{bmatrix} \delta_{\mathrm{1,1}} & ... & \delta_{\mathrm{1,q}} \\ ... & ... & ... \\ \delta_{\mathrm{n,1}} & ... & \delta_{\mathrm{q,q}} \end{bmatrix} \begin{bmatrix} d_{\mathrm{1}} \\ ... \\ d_{\mathrm{q}} \end{bmatrix}_{t} + \begin{bmatrix} v_{obs1}\\ ...\\ v_{obsn} \end{bmatrix}_t \\ \end{equation}\]

The \(v_{t}\) errors follow a multivariate normal distribution of mean 0, and covariance \(\mathbf{R}_t\) (a \(n \times n\) matrix). \[\begin{equation} \mathbf{v}_t \sim \,\text{MVN} \begin{pmatrix} 0, \begin{bmatrix} \sigma_{\mathrm{1}} & ... & \sigma_{\mathrm{1,n}} \\ ... & ... & ... \\ \sigma_{\mathrm{n,1}} & ... & \sigma_{\mathrm{n}} \\ \end{bmatrix} \end{pmatrix}\\ \end{equation}\]

The terms \(\mathbf{y}_t\), \(\mathbf{c}_t\) and \(\mathbf{d}_t\) are empirical data that are provided by the user. The remaining terms \(\mathbf{B}\), \(\mathbf{u}\), \(\mathbf{C}\), \(\mathbf{Q}\), \(\mathbf{Z}\), \(\mathbf{a}\), \(\mathbf{D}\), and \(\mathbf{R}\) can be estimated or some of them (e.g. \(\mathbf{u}\), \(\mathbf{Q}\)) can be fixed to certain values based on the assumptions about the system. The terms \(\mathbf{c}_t\) and \(\mathbf{d}_t\) must be given as an input, without any missing values.

MARSS in estar

When calculating the functional metrics the user can either provide the required community matrix (\(\mathbf{B}\)) or have it estimated from the empirical data using a set of predefined assumptions about the modeled community. Empirical data in this case constitutes time series of population abundances (or biomass) of all the species (or functional groups) in the community. None of the parameters detailed here have default values in functions that calculate the community-based stability metrics. The motivation for it is to avoid the indiscriminate use, and thus force the user to take into consideration the implications of the chosen assumptions.

When fitting MARSS models, the user can have up to eight matrices or vectors of parameters estimated (Holmes, Scheuerell, et al., 2024). This is true for all other parameters of the model, which refer to the (co ) variances and errors of abundance and observation processes. The species interaction matrix (B) is usually fully estimated, i.e. all interaction strengths are estimated. It is however possible to constrain values to specific values or in relation to each other. We showcase the use of MARSS in a system assumed to be at equilibrium, with zero observational error, zero covariates (e..g. environmental conditions affecting abundances or the observation). These assumptions reflect knowledge about the system, which, in our case we assume to be minimal. However, for that reason, we also leave it for the user to define their own assumptions. They will affect the estimation of B. Moreover, it is important to point out that the calculation of asymptotic resilience (Downing et al., 2020) implemented in the package requires that process error and constant covariates.

Pay attention to careful specification of the parameters for the options. For example, a care should be made when specifying the initial and the final time step of the time series. If the user knows the exact timing when the disturbance took place, then the time series should start right from that time point or one time step (whatever appropriate time step is useful) after.

We present a minimal case of one single observation per state process and other simplifying assumptions.

Minimal case

The calculation of asymptotic resilience (Downing et al. (2020)) that is used in the package requires zero process error and constant covariates. Therefore, our minimal case assumes that:

Code
Z_I5 <- matrix(list(0), 5, 5)
diag(Z_I5) <- 1

Such model is formalized as:

\[\begin{equation} X = \mathbf{B} \times X_{t-1} + C.0 + 0 + 0 \\ Y = Z \times X_t + 0 + D_t.0 + v \\ \end{equation}\]

Thus, our aquatic commmunity data must be split by the concentration of the pesticide, into matrices \(Y_{control}, Y_{0.1}, Y_{0.9}, Y_6, Y_{44}\), each containing the time-series of functional group counts under one treatment. We have two replicates per treatment and four replicates for the control but we are modelling one observation as corresponding to one state processes, therefore a choice must be made how to deal with this. One possibility is to randomly pick one of the replicates per treatment. Alternatively, one can choose to average the data over replicates. We here use the mean of species abundances over all replicates:

Code
## calculate z-scores of abundances
aquacommz_allscen.ldf <- aquacomm_fgps %>%
    dplyr::filter(time >= 1 , time <= 28) %>%
    ungroup() %>%
    dplyr::mutate_at(vars(herb, detr_herb, carn, omni, detr), 
                     ~MARSS::zscore(.)) %>%
    dplyr::mutate(across(c(herb, detr_herb, carn, omni, detr),
                         ~dplyr::na_if(., 0))) %>%
    tidyr::pivot_longer(cols = c(herb, detr_herb, carn, omni, detr),
                        names_to = "fgp",
                        values_to = "abund_z")

## summarize abunds over replicates
aquacommz_allscen.summldf <- aquacommz_allscen.ldf %>%
    dplyr::group_by(time, treat, fgp) %>%
    dplyr::summarize(abundz_mu = mean (abund_z),
                     abundz_sd = sd(abund_z)) %>%
    dplyr::ungroup()
#> `summarise()` has grouped output by 'time', 'treat'. You can override using the
#> `.groups` argument.

## convert into time-series matrix
aquacommz_allscen.summmxls <- aquacommz_allscen.summldf %>%
    dplyr::select(time, treat, fgp, abundz_mu) %>%
    split(.$treat) %>%
    purrr::map(~ dplyr::select(., time, fgp, abundz_mu) %>%
        unique() %>%
        tidyr::pivot_wider(id_cols = fgp,
                           names_from = time, values_from = "abundz_mu", 
                           names_prefix = "time ") %>%
        tibble::column_to_rownames(var = "fgp") %>%
        as.matrix())

Next, we prepare the arguments to be used for specifying the MARSS model according to the minimal requirements case outlined above. As we want to estimate all interaction strengths, we set B = "unconstrained".

Code
## 5 groups
### no observation error variance: 0 reps (summarized data), 5 gps
R_05 <- matrix(list(0), 5, 5)

aquacommz_allscen.marssls <- aquacommz_allscen.summmxls %>%
    purrr::map(~ MARSS(.,
                list(B = "unconstrained",
                     U = "zero", A = "zero",
                     Z = "identity", ## Z_I5 could also have been provided here 
                     Q = "diagonal and equal", 
                     R = R_05,
                     tinitx = 1),
                method = "BFGS"))
#> Success! Converged in 102 iterations.
#> Function MARSSkfas used for likelihood calculation.
#> 
#> MARSS fit is
#> Estimation method: BFGS 
#> Estimation converged in 102 iterations. 
#> Log-likelihood: 12.89424 
#> AIC: 36.21151   AICc: 188.8269   
#>  
#>                Estimate
#> B.(1,1)        -0.00384
#> B.(2,1)        -0.48776
#> B.(3,1)         0.49413
#> B.(4,1)        -0.63563
#> B.(5,1)        -0.88599
#> B.(1,2)        -0.79441
#> B.(2,2)        -0.71431
#> B.(3,2)         0.34129
#> B.(4,2)        -1.06959
#> B.(5,2)        -0.23848
#> B.(1,3)         1.06766
#> B.(2,3)         0.88814
#> B.(3,3)        -0.59104
#> B.(4,3)         1.19712
#> B.(5,3)         1.03068
#> B.(1,4)         1.06455
#> B.(2,4)         2.28849
#> B.(3,4)        -0.48379
#> B.(4,4)         1.78597
#> B.(5,4)         1.15372
#> B.(1,5)         0.64510
#> B.(2,5)         0.26483
#> B.(3,5)         0.23857
#> B.(4,5)         0.59291
#> B.(5,5)         0.76098
#> Q.diag          0.03073
#> x0.X.carn      -1.23766
#> x0.X.detr      -1.76648
#> x0.X.detr_herb -1.84701
#> x0.X.herb       0.25242
#> x0.X.omni      -0.26112
#> Initial states (x0) defined at t=1
#> 
#> Standard errors have not been calculated. 
#> Use MARSSparamCIs to compute CIs and bias estimates.
#> 
#> Success! Converged in 64 iterations.
#> Function MARSSkfas used for likelihood calculation.
#> 
#> MARSS fit is
#> Estimation method: BFGS 
#> Estimation converged in 64 iterations. 
#> Log-likelihood: 22.73044 
#> AIC: 16.53912   AICc: 169.1545   
#>  
#>                Estimate
#> B.(1,1)         -0.4165
#> B.(2,1)         -0.0461
#> B.(3,1)          0.7853
#> B.(4,1)         -0.6549
#> B.(5,1)          1.0068
#> B.(1,2)         -0.3959
#> B.(2,2)         -0.0530
#> B.(3,2)         -0.2897
#> B.(4,2)         -1.3143
#> B.(5,2)          0.4224
#> B.(1,3)         -0.1699
#> B.(2,3)          0.8898
#> B.(3,3)         -0.1784
#> B.(4,3)         -0.2465
#> B.(5,3)          0.1291
#> B.(1,4)          0.7078
#> B.(2,4)         -0.7165
#> B.(3,4)          0.2834
#> B.(4,4)          0.6668
#> B.(5,4)         -0.4993
#> B.(1,5)          0.2784
#> B.(2,5)         -0.1199
#> B.(3,5)         -0.4755
#> B.(4,5)          0.0676
#> B.(5,5)          0.4803
#> Q.diag           0.0188
#> x0.X.carn       -0.9269
#> x0.X.detr        0.7523
#> x0.X.detr_herb  -0.5069
#> x0.X.herb       -0.8082
#> x0.X.omni       -1.2319
#> Initial states (x0) defined at t=1
#> 
#> Standard errors have not been calculated. 
#> Use MARSSparamCIs to compute CIs and bias estimates.
#> 
#> Success! Converged in 457 iterations.
#> Function MARSSkfas used for likelihood calculation.
#> 
#> MARSS fit is
#> Estimation method: BFGS 
#> Estimation converged in 457 iterations. 
#> Log-likelihood: -17.78594 
#> AIC: 97.57189   AICc: 250.1873   
#>  
#>                Estimate
#> B.(1,1)         -0.6455
#> B.(2,1)         -1.6432
#> B.(3,1)         -3.2392
#> B.(4,1)          0.8320
#> B.(5,1)          2.3106
#> B.(1,2)          0.9553
#> B.(2,2)          1.1013
#> B.(3,2)          1.2936
#> B.(4,2)         -0.8920
#> B.(5,2)         -2.5817
#> B.(1,3)         -0.1544
#> B.(2,3)         -0.2534
#> B.(3,3)         -1.0449
#> B.(4,3)          0.3990
#> B.(5,3)          0.3992
#> B.(1,4)         -0.1744
#> B.(2,4)         -0.4754
#> B.(3,4)          0.0987
#> B.(4,4)          0.6302
#> B.(5,4)          1.2261
#> B.(1,5)          0.0178
#> B.(2,5)          0.2035
#> B.(3,5)          0.8882
#> B.(4,5)         -0.4878
#> B.(5,5)          0.5761
#> Q.diag           0.1425
#> x0.X.carn        0.3796
#> x0.X.detr       -1.4360
#> x0.X.detr_herb  -5.8122
#> x0.X.herb       -1.1427
#> x0.X.omni       -2.7909
#> Initial states (x0) defined at t=1
#> 
#> Standard errors have not been calculated. 
#> Use MARSSparamCIs to compute CIs and bias estimates.
#> 
#> Success! Converged in 220 iterations.
#> Function MARSSkfas used for likelihood calculation.
#> 
#> MARSS fit is
#> Estimation method: BFGS 
#> Estimation converged in 220 iterations. 
#> Log-likelihood: -23.34317 
#> AIC: 108.6863   AICc: 261.3017   
#>  
#>                Estimate
#> B.(1,1)         -2.3823
#> B.(2,1)          1.0896
#> B.(3,1)         -0.5606
#> B.(4,1)         -0.0179
#> B.(5,1)          0.7345
#> B.(1,2)         -2.6838
#> B.(2,2)          1.1122
#> B.(3,2)         -0.6071
#> B.(4,2)          0.5630
#> B.(5,2)         -0.0574
#> B.(1,3)          3.5143
#> B.(2,3)         -0.4325
#> B.(3,3)          1.2171
#> B.(4,3)         -1.1742
#> B.(5,3)         -0.7598
#> B.(1,4)         -0.0724
#> B.(2,4)          0.4573
#> B.(3,4)          0.2121
#> B.(4,4)          0.5342
#> B.(5,4)          1.4439
#> B.(1,5)          1.0358
#> B.(2,5)         -1.1006
#> B.(3,5)          0.2629
#> B.(4,5)          0.2850
#> B.(5,5)         -0.7703
#> Q.diag           0.1881
#> x0.X.carn        1.7363
#> x0.X.detr       -1.4806
#> x0.X.detr_herb  -0.4085
#> x0.X.herb       -1.2921
#> x0.X.omni        0.8345
#> Initial states (x0) defined at t=1
#> 
#> Standard errors have not been calculated. 
#> Use MARSSparamCIs to compute CIs and bias estimates.
#> 
#> Success! Converged in 187 iterations.
#> Function MARSSkfas used for likelihood calculation.
#> 
#> MARSS fit is
#> Estimation method: BFGS 
#> Estimation converged in 187 iterations. 
#> Log-likelihood: -8.653387 
#> AIC: 79.30677   AICc: 231.9222   
#>  
#>                Estimate
#> B.(1,1)         -0.0208
#> B.(2,1)          0.6099
#> B.(3,1)          0.1791
#> B.(4,1)         -0.0165
#> B.(5,1)          0.5966
#> B.(1,2)          1.1379
#> B.(2,2)          0.6065
#> B.(3,2)          2.7719
#> B.(4,2)         -0.5077
#> B.(5,2)          1.7027
#> B.(1,3)         -0.4974
#> B.(2,3)         -0.2568
#> B.(3,3)         -1.7395
#> B.(4,3)          0.8265
#> B.(5,3)         -0.5155
#> B.(1,4)          0.3383
#> B.(2,4)         -0.2229
#> B.(3,4)         -0.3574
#> B.(4,4)          0.4981
#> B.(5,4)         -0.6097
#> B.(1,5)         -1.6698
#> B.(2,5)          0.3865
#> B.(3,5)         -2.8546
#> B.(4,5)          0.5559
#> B.(5,5)         -0.9264
#> Q.diag           0.0902
#> x0.X.carn       -1.6448
#> x0.X.detr       -0.6463
#> x0.X.detr_herb   0.2271
#> x0.X.herb       -2.2936
#> x0.X.omni       -0.3627
#> Initial states (x0) defined at t=1
#> 
#> Standard errors have not been calculated. 
#> Use MARSSparamCIs to compute CIs and bias estimates.
names(aquacommz_allscen.marssls) <- paste0("Conc. = ", c("0", "0.1", "0.9", "6", "44" ), " micro g/L")

We provide the function estar::extractB() which extracts \(\mathbf{B}\) in matrix form from the fitted MARSS object and names the interacting groups

Code
(aquacomm.Bls <- aquacommz_allscen.marssls %>%
  purrr::map(~estar::extractB(., 
                states_names = c("Herbivores", "DetHerbivores", "Carnivores", "Omnivores", "Detrivores"))))
#> $`Conc. = 0 micro g/L`
#>                Herbivores DetHerbivores Carnivores  Omnivores Detrivores
#> Herbivores    -0.00384054    -0.7944114  1.0676640  1.0645532  0.6450999
#> DetHerbivores -0.48775802    -0.7143126  0.8881352  2.2884880  0.2648297
#> Carnivores     0.49412621     0.3412916 -0.5910375 -0.4837852  0.2385650
#> Omnivores     -0.63562999    -1.0695943  1.1971242  1.7859672  0.5929082
#> Detrivores    -0.88599113    -0.2384849  1.0306840  1.1537171  0.7609775
#> 
#> $`Conc. = 0.1 micro g/L`
#>                Herbivores DetHerbivores Carnivores  Omnivores  Detrivores
#> Herbivores    -0.41652765   -0.39590416 -0.1699447  0.7078464  0.27842473
#> DetHerbivores -0.04607136   -0.05295295  0.8898280 -0.7164686 -0.11986370
#> Carnivores     0.78529501   -0.28965584 -0.1784333  0.2834296 -0.47550796
#> Omnivores     -0.65492182   -1.31427312 -0.2464757  0.6667780  0.06763712
#> Detrivores     1.00676461    0.42235586  0.1290599 -0.4993199  0.48032025
#> 
#> $`Conc. = 0.9 micro g/L`
#>               Herbivores DetHerbivores Carnivores   Omnivores  Detrivores
#> Herbivores    -0.6455068     0.9553172 -0.1544395 -0.17435612  0.01778414
#> DetHerbivores -1.6432166     1.1013087 -0.2533819 -0.47536805  0.20354936
#> Carnivores    -3.2391640     1.2935895 -1.0449297  0.09869478  0.88816165
#> Omnivores      0.8320019    -0.8920486  0.3989834  0.63018015 -0.48775593
#> Detrivores     2.3105803    -2.5817354  0.3991956  1.22614773  0.57609858
#> 
#> $`Conc. = 6 micro g/L`
#>                Herbivores DetHerbivores Carnivores  Omnivores Detrivores
#> Herbivores    -2.38234463   -2.68379362  3.5142992 -0.0723508  1.0358009
#> DetHerbivores  1.08957278    1.11219717 -0.4324573  0.4572830 -1.1006100
#> Carnivores    -0.56060383   -0.60711379  1.2170955  0.2120916  0.2629435
#> Omnivores     -0.01790964    0.56304823 -1.1742214  0.5341647  0.2849972
#> Detrivores     0.73450653   -0.05738783 -0.7598349  1.4439453 -0.7703449
#> 
#> $`Conc. = 44 micro g/L`
#>                Herbivores DetHerbivores Carnivores  Omnivores Detrivores
#> Herbivores    -0.02083992     1.1379372 -0.4973880  0.3383258 -1.6698239
#> DetHerbivores  0.60990448     0.6065011 -0.2567718 -0.2228877  0.3865387
#> Carnivores     0.17913798     2.7718747 -1.7394515 -0.3573693 -2.8545996
#> Omnivores     -0.01646089    -0.5076764  0.8264983  0.4981301  0.5559434
#> Detrivores     0.59659292     1.7027159 -0.5154681 -0.6096649 -0.9263735

Finally, having estimated \(\mathbf{B}\) we can calculate all the functional stability metrics:

Reactivity

A positive value indicates the system is reactive and the higher its value, the faster the perturbation can grow. The aquatic community in our example seems to be reactive even when no insecticide is applied.

Code
aquacomm.Bls %>%
  purrr::map(estar::reactivity)
#> $`Conc. = 0 micro g/L`
#> [1] 2.561053
#> 
#> $`Conc. = 0.1 micro g/L`
#> [1] 1.46357
#> 
#> $`Conc. = 0.9 micro g/L`
#> [1] 2.772984
#> 
#> $`Conc. = 6 micro g/L`
#> [1] 2.50594
#> 
#> $`Conc. = 44 micro g/L`
#> [1] 1.569554

Maximal amplification

The largest response of the community to the perturbation, it is a measure of the transient behavior of the system.

Code
aquacomm.Bls %>%
  purrr::map(estar::max_amp)
#> $`Conc. = 0 micro g/L`
#> [1] 7.235982
#> 
#> $`Conc. = 0.1 micro g/L`
#> [1] 4.568985
#> 
#> $`Conc. = 0.9 micro g/L`
#> [1] 7.173882
#> 
#> $`Conc. = 6 micro g/L`
#> [1] 5.567664
#> 
#> $`Conc. = 44 micro g/L`
#> [1] 3.938252

Initial resilience

Initial resilience is the initial rate of return to equilibrium. The larger its value, the more stable the system, as its “worst case” initial rate of return to equilibrium is faster (Downing et al. 2020).

Code
aquacomm.Bls %>%
  purrr::map(estar::init_resil)
#> $`Conc. = 0 micro g/L`
#> [1] -0.8034616
#> 
#> $`Conc. = 0.1 micro g/L`
#> [1] -0.1462433
#> 
#> $`Conc. = 0.9 micro g/L`
#> [1] -0.5265344
#> 
#> $`Conc. = 6 micro g/L`
#> [1] -1.025015
#> 
#> $`Conc. = 44 micro g/L`
#> [1] -0.686173

Asymptotic resilience

The slowest/long-term asymptotic rate of return to equilibrium after a pulse perturbation. Asymptotic resilience can take on positive real numbers. The larger its value, the more stable the system as such communities have a faster long-term return to stable state.

Code
aquacomm.Bls %>%
  purrr::map(estar::asympt_resil)
#> $`Conc. = 0 micro g/L`
#> [1] -1.249486
#> 
#> $`Conc. = 0.1 micro g/L`
#> [1] -0.8430753
#> 
#> $`Conc. = 0.9 micro g/L`
#> [1] -1.79057
#> 
#> $`Conc. = 6 micro g/L`
#> [1] -1.169717
#> 
#> $`Conc. = 44 micro g/L`
#> [1] -1.112916

Stochastic invariability

Inverse of the maximal response variance to white noise. The larger its value, the more stable the system as it indicates less variability due to random displacements of the system from the equilibrium.

Code
aquacomm.Bls %>%
  map(estar::stoch_var)
#> $`Conc. = 0 micro g/L`
#> [1] 23.9071
#> 
#> $`Conc. = 0.1 micro g/L`
#> [1] 5.286142
#> 
#> $`Conc. = 0.9 micro g/L`
#> [1] 13.90415
#> 
#> $`Conc. = 6 micro g/L`
#> [1] 11.75702
#> 
#> $`Conc. = 44 micro g/L`
#> [1] 13.94729

Performance of functional metrics

We conducted the benchmark analysis of the execution time of the different functional metrics. The code used for the analysis is available in performance_analysis.R.

While the time to run the calls can differ significantly from each other, the execution time did not exceed 0.05 seconds for our example.

Code
load("jacobian_performance.rda")
Code
jacobian_benchmark %>%
  dplyr::select(-neval) %>% 
  kableExtra::kbl() %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
Function call Min. Lower quart. Mean Median Upper quart. Max. Signif.
reactivity 0.0002651 0.0002924 0.0003797 0.0003213 0.0003614 0.0013451 a
max_amp 0.0013689 0.0014863 0.0082912 0.0016132 0.0019386 0.6394164 a
init_resil 0.0002659 0.0002910 0.0003660 0.0003150 0.0003753 0.0016038 a
asympt_resil 0.0002217 0.0002457 0.0003180 0.0002694 0.0003093 0.0016270 a
stoch_var 0.0011134 0.0012181 0.0017989 0.0013416 0.0016967 0.0186624 a
Density distribution of execution times of 100 runs of each of the different functions used to calculate functional metrics, as demonstrated in this vignette.
Density distribution of execution times of 100 runs of each of the different functions used to calculate functional metrics, as demonstrated in this vignette.

References


Session Info
Code
Sys.time()
#> [1] "2025-11-18 15:45:43 CET"
Code
sessionInfo()
#> R version 4.4.1 (2024-06-14 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26100)
#> 
#> Matrix products: default
#> 
#> 
#> locale:
#> [1] LC_COLLATE=C                     LC_CTYPE=English_Germany.utf8   
#> [3] LC_MONETARY=English_Germany.utf8 LC_NUMERIC=C                    
#> [5] LC_TIME=English_Germany.utf8    
#> 
#> time zone: Europe/Berlin
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] hesim_0.5.4       MARSS_3.11.9      purrr_1.2.0       tibble_3.3.0     
#>  [5] vegan_2.6-8       lattice_0.22-6    permute_0.9-7     kableExtra_1.4.0 
#>  [9] forcats_1.0.0     viridis_0.6.5     viridisLite_0.4.2 cowplot_1.1.3    
#> [13] ggplot2_4.0.0     dplyr_1.1.4       tidyr_1.3.1       estar_1.0-0      
#> 
#> loaded via a namespace (and not attached):
#>  [1] gtable_0.3.6       xfun_0.51          bslib_0.9.0        vctrs_0.6.5       
#>  [5] tools_4.4.1        generics_0.1.4     parallel_4.4.1     cluster_2.1.6     
#>  [9] pkgconfig_2.0.3    Matrix_1.7-0       data.table_1.14.8  RColorBrewer_1.1-3
#> [13] S7_0.2.0           lifecycle_1.0.4    compiler_4.4.1     farver_2.1.2      
#> [17] stringr_1.5.1      htmltools_0.5.8.1  sass_0.4.10        yaml_2.3.10       
#> [21] pillar_1.11.1      jquerylib_0.1.4    MASS_7.3-60.2      cachem_1.1.0      
#> [25] nlme_3.1-164       tidyselect_1.2.1   digest_0.6.37      mvtnorm_1.2-5     
#> [29] stringi_1.8.4      labeling_0.4.3     splines_4.4.1      fastmap_1.2.0     
#> [33] grid_4.4.1         expm_0.999-9       cli_3.6.3          magrittr_2.0.4    
#> [37] survival_3.6-4     withr_3.0.2        KFAS_1.5.1         scales_1.4.0      
#> [41] rmarkdown_2.30     gridExtra_2.3      zoo_1.8-12         msm_1.7.1         
#> [45] evaluate_1.0.5     knitr_1.50         mgcv_1.9-1         rlang_1.1.4       
#> [49] Rcpp_1.1.0         glue_1.8.0         xml2_1.3.5         svglite_2.1.0     
#> [53] rstudioapi_0.16.0  jsonlite_2.0.0     R6_2.6.1           systemfonts_1.3.1


Brink, Paul J. van den, René P. A. Van Wijngaarden, Wil G. H. Lucassen, Theo C. M. Brock, and Peter Leeuwangh. 1996. “Effects of the Insecticide Dursban® 4E (Active Ingredient Chlorpyrifos) in Outdoor Experimental Ditches: II. Invertebrate Community Responses and Recovery.” Environmental Toxicology and Chemistry 15 (7): 1143–53. https://doi.org/http://doi.wiley.com/10.1002/etc.5620150719.
Domínguez-García, Virginia, Vasilis Dakos, and Sonia Kéfi. 2019. “Unveiling Dimensions of Stability in Complex Ecological Networks.” Proceedings of the National Academy of Sciences 116 (51): 25714–20. https://doi.org/10.1073/pnas.1904470116.
Downing, Amy L., Craig Jackson, Claire Plunkett, Jayne Ackerman Lockhart, Shannon M. Schlater, and Mathew A. Leibold. 2020. “Temporal Stability Vs. Community Matrix Measures of Stability and the Role of Weak Interactions.” Ecology Letters 23 (10): 1468–78. https://doi.org/10.1111/ele.13538.
Novak, Mark, Justin D. Yeakel, Andrew E. Noble, Daniel F. Doak, Mark Emmerson, James A. Estes, Ute Jacob, M. Timothy Tinker, and J. Timothy Wootton. 2016. “Characterizing Species Interactions to Understand Press Perturbations: What Is the Community Matrix?” Annual Review of Ecology, Evolution, and Systematics 47 (1): 409–32. https://doi.org/10.1146/annurev-ecolsys-032416-010215.
Wijngaarden, René P. A. van, Paul J. van den Brink, Steven J. H. Crum, Theo C. M. Brock, Peter Leeuwangh, and Oude Jan H. Voshaar. 1996. “Effects of the Insecticide Dursban® 4E (Active Ingredient Chlorpyrifos) in Outdoor Experimental Ditches: I. Comparison of Short-Term Toxicity Between the Laboratory and the Field.” Environmental Toxicology and Chemistry 15 (7): 1133–42. https://doi.org/https://doi.org/10.1002/etc.5620150718.

mirror server hosted at Truenetwork, Russian Federation.