中文 | Español | English | português | Turkish

library(ecoevoapps)
library(deSolve)
library(tidyverse)
library(patchwork)
library(RColorBrewer)
library(knitr)
library(kableExtra)
knitr::opts_chunk$set(echo=FALSE)
theme_set(ecoevoapps::theme_apps())

The Lotka-Volterra competition equations explore the dynamics of two species that compete with each other for food, space, or other resources. The idea behind this model is that as a species grows in population, it starts being limited both by competition between individuals within the same species (intra-specific competition), and also by competition from other species (inter-specific competition). Details of the model are available in many ecology texts and on various websites.

There are several ways of writing the classic Lotka-Volterra competition models. The primary way is to express competition in terms of each species' carrying capacity ($K_1$ and $K_2$) and the relative strength of interspecific competition $\alpha$ and $\beta$. This is the form of the model that is presented in the first tab below. In his classic 2000 paper "Mechanisms of Maintenance of Species Diversity", Peter Chesson advocated for expression the Lotka-Volterra competition equations in terms of the absolute competition coefficients for each species; the second tab below allows users to explore that form of the Lotka-Volterra competition model.

{.tabset}

Model in terms of carrying capacity and relative competitive effects

Equations for Lotka-Volterra Competition expressed with carrying capacities: $$\frac{dN_1}{dt} = r_1N_1\left(1 - \frac{N_1 + \alpha N_2}{K_1}\right)$$ $$\frac{dN_2}{dt} = r_2N_2\left(1 - \frac{N_2 + \beta N_1}{K_2}\right)$$

pars_vars <- c("$r_1$", 
               "$r_2$", 
               "$N_1$", 
               "$N_2$", 
               "$K_1$", 
               "$K_2$", 
               "$\\alpha$", 
               "$\\beta$")
descriptions <- c("Intrinsic growth rate of Species 1",
                 "Intrinsic growth rate of Species 2",
                 "Population size of Species 1",
                 "Population size of Species 2",
                 "Carrying capacity of Species 1",
                 "Carrying capacity of Species 2",
                 "Relative per capita effect of Species 2 on Species 1",
                 "Relative per capita effect of Species 1 on Species 2")
param_df <- data.frame(pars_vars, descriptions)
kable(x = param_df, format = "html", 
      col.names = c("Parameter/Variable", "Description")) %>%
  kable_styling(full_width = FALSE, 
                bootstrap_options = c("striped", "hover", "condensed"),
                position = "center")

Zero net growth isoclines (solved for $N_2$): $$N_2 = - \frac{N_1}{\alpha} + \frac{K_1}{\alpha}$$ $$N_2 = -\beta N_1 + K_2$$


sidebarLayout(
  sidebarPanel(
    # Allow user to select which plots to display
    checkboxGroupInput(inputId = "plots_to_show",
                       label = "Select plots",
                       choices = c("Zero net growth isoclines (ZNGIs)" = "ZNGI")),

    hr(),

    # User-defined parameter values
    sliderInput(inputId = "r1", 
                label = HTML("r<sub>1</sub>: Intrinsic growth rate of Species 1"),
                min = 0.01, max = 1, value = 0.2, step = 0.01),
    sliderInput(inputId = "r2", 
                label = HTML("r<sub>2</sub>: Intrinsic growth rate of Species 2"),
                min = 0.01, max = 1, value = 0.5, step = 0.01),
    numericInput(inputId = "K1", 
                 label = HTML("K<sub>1</sub>: Carrying capacity of Species 1"),
                 min = 1, value = 300),
    numericInput(inputId = "K2", 
                 label = HTML("K<sub>2</sub>: Carrying capacity of Species 2"),
                 min = 1, value = 200),
    sliderInput(inputId = "alpha", 
                label = HTML("&alpha;: Relative effect of Species 2 on Species 1"),
                min = 0.01, max = 2, value = 0.3, step = 0.01),
    sliderInput(inputId = "beta", 
                label = HTML("&beta;: Relative effect of Species 1 on Species 2"),
                min = 0.01, max = 2, value = 0.2, step = 0.01),
    # User-defined initial values
    numericInput(inputId = "N1", 
                 label = "Initial population size of Species 1",
                 min = 1, value = 50),
    numericInput(inputId = "N2", 
                 label = "Initial population size of Species 2",
                 min = 1, value = 70),

    numericInput(inputId = "max_time", 
                 label = "Length of simulation",
                 min = 1, value = 100)
  ),

  # Panel of plots
  mainPanel(
    renderPlot(N_vs_Time(), width = 600, height = 500),
      renderPlot(ZNGI(), width = 600, height = 500))
)

# Get user-defined parameters
init <- reactive({
  c(N1 = input$N1, N2 = input$N2)
})
time <- reactive({
  seq(from = 0, to = input$max_time, by = 0.1)
})
params <- reactive({
  c(r1 = input$r1, r2 = input$r2, K1 = input$K1, K2 = input$K2, 
    a = input$alpha, b = input$beta)
})



# Run lotka_volterra_competition function
lvcomp_out <- reactive({
  run_lvcomp_model(time = time(), init = init(), params = params()) %>% 
    data.frame()
})


N_vs_Time <- reactive({
  plot_lvcomp_time(lvcomp_out())
})

# Plot ZNGIs with population trajectories

ZNGI <- reactive({
  if ("ZNGI" %in% input$plots_to_show) {
    plot_lvcomp_portrait(lvcomp_out(), params = params(), margin_text = T)
  } 
})

# Make a list of plots to print based on user request
plot_list <- reactive({ 
  list(N_vs_Time(), ZNGI()) %>%
    discard(is.null)
  })

plots_to_print <- reactive({ 
  wrap_plots(plot_list(), ncol = 1)
  })

Model in terms of absolute competition coefficients

Equations for Lotka-Volterra Competition expressed without carrying capacities: $$\frac{dN_1}{dt} = r_1N_1\left(1 - \alpha_{11}N_1 - \alpha_{12}N_2\right)$$ $$\frac{dN_2}{dt} = r_2N_2\left(1 - \alpha_{22}N_2 - \alpha_{21}N_1\right)$$

pars_vars_wo_K <- c("$r_1$",
                    "$r_2$",
                    "$N_1$",
                    "$N_2$",
                    "$\\alpha_{11}$",
                    "$\\alpha_{12}$",
                    "$\\alpha_{22}$",
                    "$\\alpha_{21}$")
descriptions_wo_K <- c("Intrinsic growth rate of Species 1",
                       "Intrinsic growth rate of Species 2",
                       "Population size of Species 1",
                       "Population size of Species 2",
                       "Per capita effect of Species 1 on itself",
                       "Per capita effect of Species 2 on Species 1",
                       "Per capita effect of Species 2 on itself",
                       "Per capita effect of Species 1 on Species 2")
param_df_wo_K <- data.frame(pars_vars_wo_K, descriptions_wo_K)
kable(x = param_df_wo_K, format = "html",
      col.names = c("Parameter/Variable", "Description")) %>%
  kable_styling(full_width = FALSE,
                bootstrap_options = c("striped", "hover", "condensed"),
                position = "center")

Zero net growth isoclines (solved for $N_2$): $$N_2 = -\frac{\alpha_{11}}{\alpha_{12}}N_1 + \frac{1}{\alpha_{12}}$$ $$N_2 = -\frac{\alpha_{21}}{\alpha_{22}}N_1 + \frac{1}{\alpha_{22}}$$


sidebarLayout(
  sidebarPanel(
    # Allow users to select which plots to display
    checkboxGroupInput(inputId = "plots_to_show_wo_K",
                       label = "Select plots to display",
                       choices = c("N vs. Time" = "N_vs_Time_wo_K",
                                   "Zero net growth isoclines (ZNGIs)" = "ZNGI_wo_K"),
                       selected = c("N_vs_Time_wo_K")),

    hr(),

    # User-defined parameter values
    sliderInput(inputId = "r1_wo_K",
                label = HTML("r<sub>1</sub>: Intrinsic growth rate of Species 1"),
                min = 0.01, max = 1, value = 0.2, step = 0.01),
    sliderInput(inputId = "r2_wo_K",
                label = HTML("r<sub>2</sub>: Intrinsic growth rate of Species 2"),
                min = 0.01, max = 1, value = 0.5, step = 0.01),

    # Allow user to choose input method for competition coefficients
    radioButtons(inputId = "alpha_input_wo_K",
                 label = "Input method for competition coefficients:",
                 choices = c("Slider" = "slider", "Manual" = "manual"),
                 selected = "slider"),

    # Conditional panel for slider input of competition coefficients
    conditionalPanel(
      condition = "input.alpha_input_wo_K == 'slider'",
      sliderInput(inputId = "alpha11_slider",
                  label = HTML("&alpha;<sub>11</sub>: Per capita effect of Species 1 on itself"),
                  min = 0.0001, max = 0.01, value = 0.0033, step = NULL),
      sliderInput(inputId = "alpha12_slider",
                  label = HTML("&alpha;<sub>12</sub>: Per capita effect of Species 2 on Species 1"),
                  min = 0.0001, max = 0.01, value = 0.001, step = NULL),
      sliderInput(inputId = "alpha22_slider",
                  label = HTML("&alpha;<sub>22</sub>: Per capita effect of Species 2 on itself"),
                  min = 0.0001, max = 0.01, value = 0.005, step = NULL),
      sliderInput(inputId = "alpha21_slider",
                  label = HTML("&alpha;<sub>21</sub>: Per capita effect of Species 1 on Species 2"),
                  min = 0.0001, max = 0.01, value = 0.001, step = NULL)
    ),

    # Conditional panel for manual input of competition coefficients
    conditionalPanel(
      condition = "input.alpha_input_wo_K == 'manual'",
      numericInput(inputId = "alpha11_manual",
                   label = HTML("&alpha;<sub>11</sub>: Per capita effect of Species 1 on itself"),
                   min = 0.0001, max = 1, value = 0.0033, step = 0.0001),
      numericInput(inputId = "alpha12_manual",
                   label = HTML("&alpha;<sub>12</sub>: Per capita effect of Species 2 on Species 1"),
                   min = 0.0001, max = 1, value = 0.001, step = 0.0001),
      numericInput(inputId = "alpha22_manual",
                   label = HTML("&alpha;<sub>22</sub>: Per capita effect of Species 2 on itself"),
                   min = 0.0001, max = 1, value = 0.005, step = 0.0001),
      numericInput(inputId = "alpha21_manual",
                   label = HTML("&alpha;<sub>21</sub>: Per capita effect of Species 1 on Species 2"),
                   min = 0.0001, max = 1, value = 0.001, step = 0.0001)
    ),

    # User-defined initial values
    numericInput(inputId = "N1_wo_K",
                 label = "Initial population size of Species 1",
                 min = 1, value = 50),
    numericInput(inputId = "N2_wo_K",
                 label = "Initial population size of Species 2",
                 min = 1, value = 70),

    numericInput(inputId = "max_time_wo_K",
                 label = "Length of simulation",
                 min = 1, value = 100)
  ),

  # Panel of plots 
  mainPanel(renderPlot(N_vs_Time_wo_K(), width = 600, height = 500),
            renderPlot(ZNGI_wo_K(), width = 600, height = 500))
)

# Store inputted competition coefficients as new reactive objects
alpha11_wo_K <- reactive({
  if (input$alpha_input_wo_K == "slider") {
    input$alpha11_slider
  } else if (input$alpha_input_wo_K == "manual") {
    input$alpha11_manual
  }
})
alpha12_wo_K <- reactive({
  if (input$alpha_input_wo_K == "slider") {
    input$alpha12_slider
  } else if (input$alpha_input_wo_K == "manual") {
    input$alpha12_manual
  }
})
alpha22_wo_K <- reactive({
  if (input$alpha_input_wo_K == "slider") {
    input$alpha22_slider
  } else if (input$alpha_input_wo_K == "manual") {
    input$alpha22_manual
  }
})
alpha21_wo_K <- reactive({
  if (input$alpha_input_wo_K == "slider") {
    input$alpha21_slider
  } else if (input$alpha_input_wo_K == "manual") {
    input$alpha21_manual
  }
})

# Get user-defined parameters
init_wo_K <- reactive({
  c(N1 = input$N1_wo_K, N2 = input$N2_wo_K)
})
time_wo_K <- reactive({
  seq(from = 0, to = input$max_time_wo_K, by = 0.1)
})
params_wo_K <- reactive({
  c(r1 = input$r1_wo_K, r2 = input$r2_wo_K,
    a11 = alpha11_wo_K(), a12 = alpha12_wo_K(),
    a22 = alpha22_wo_K(), a21 = alpha21_wo_K())
})


# Run lotka_volterra_competition_wo_K function
lvcomp_out_wo_K <- reactive({
    run_lvcomp_model(time = time_wo_K(), 
init = init_wo_K(), params = params_wo_K()) %>% 
      data.frame()
})

N_vs_Time_wo_K <- reactive({
  plot_lvcomp_time(lvcomp_out_wo_K())
})
# Convert data to long format

# Plot ZNGIs with population trajectories
ZNGI_wo_K <- reactive({
  if ("ZNGI_wo_K" %in% input$plots_to_show_wo_K) {
    plot_lvcomp_portrait(lvcomp_out_wo_K(), params = params_wo_K(),
                         margin_text = T)
  } 
})

# Make a list of plots to print based on user request
plot_list_wo_K <- reactive({
  list(N_vs_Time_wo_K(), ZNGI_wo_K()) %>%
    discard(is.null)
})

plots_to_print_wo_K <- reactive({
  wrap_plots(plot_list_wo_K(), ncol = 1)
})

References


suppressWarnings(ecoevoapps::print_app_footer())


gauravsk/ecoevoapps documentation built on July 9, 2024, 9:37 p.m.