中文 | Español | English | português | Turkish
knitr::opts_chunk$set(echo = FALSE) library(ecoevoapps) library(tidyverse) library(patchwork) library(knitr) library(kableExtra)
在互利关系(mutualism)中,两个互相影响的物种对彼此都有益。互利可以有多种形式,包括(但不限于)植物和传粉者之间的互动、动物帮助植物传播种子或防御天敌。比如,榕小蜂帮榕树传粉,同时也食用榕果并在其中产卵(Cook & Rasplus 2003)。另一个例子是蚂蚁和金合欢之间的互利关系:金合欢为蚂蚁提供食宿,而蚂蚁帮助金合欢抵御食草动物(Janzen 1966)。Bronstein (2015)一书详细概述了各种互利共生关系。
此app模拟了两个物种之间的直接互利关系(Holland 2012)。该模型的核心在于,每个物种的种群增长率($dN/dt$)同时受到同种个体和其互利物种个体的影响 -- 这有些类似于经典的Lotka-Volterra 竞争模型。当每个物种单独存在时,它们只受到种间竞争,并因此种群只能增长至其环境承载力。但当两个物种作用于彼此时,它们给彼此带来有利影响,因此可以使彼此的种群规模超过其环境承载力。这个模型假设了互利关系带来的边际收益是递减的,即互利收益会随种群增长而趋于饱和。
综上,模型可写为:
$$\frac{dN_1}{dt} = r_1N_1 + \frac{\alpha_{12}N_2}{b_2 + N_2}N_1 - d_1N_1^2$$ $$\frac{dN_2}{dt} = r_2N_2 + \frac{\alpha_{21}N_1}{b_1 + N_1}N_2 - d_2N_2^2$$
模型参数的描述可见下文表格。动态方程的第一项($r_iN_i$) 描述了种群在无任何种间竞争或互利关系下的增长。第二项($\frac{\alpha_{ij}N_j}{b_j + N_j}N_i$) 描述了各种群随其互利物种的增长而增长的饱和函数(呈Michaelis–Menten 曲线,其中半饱和常数为$b_i$)。最后一项表示种群增长率随其规模增长而减缓。
pars <- c("$r_1$", "$r_2$", "$N_1$", "$N_2$", "$\\alpha_{12}$", "$\\alpha_{21}$", "$d_1$", "$d_2$", "$b_i$") descriptions <- c("物种1的人均增长率", "物种2的人均增长率", "物种1的种群规模", "物种2的种群规模", "物种2对于物种1的人均有利影响", "物种1对于物种2的人均有利影响", "物种1的自限性", "物种2的自限性", "Michelis-Menten方程的半饱和常数,即种群$i$对$j$的有利影响为最大值一半时,种群$i$的规模") param_df <- data.frame(pars, descriptions) kable(x = param_df, format = "html", col.names = c("参数/变量", "描述")) %>% kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"), position = "center")
这个模型可以模拟种群轨迹随时间的变化(选择“种群规模vs.时间”),该选项可帮助我们探索种群如何在互利影响下如何增长。我们也可以通过零增长等斜线 (zero net growth isocline)来研究互利关系对于种群的长期影响。零增长等斜线表述了在什么条件下各种群会零增长($dN_1/dt = dN_2/dt = 0$) ,以及两个种群会在什么规模下平衡(选择“相图”)。
##### UI ##### # Input panel wellPanel( fluidRow( column(4, numericInput(inputId = "r1", label = HTML("r<sub>1</sub>: 物种1的人均增长率"), value = 0.5, step = 0.1)), column(4, numericInput(inputId = "r2", label = HTML("r<sub>2</sub>: 物种2的人均增长率"), value = 0.5, step = 0.1)), column(4, numericInput(inputId = "N1", label = "物种1的起始种群规模", value = 20, min = 0, step = 1))), fluidRow( column(4, numericInput(inputId = "a12", label = HTML("α<sub>12</sub>: 物种2对1的影响"), value = 0.8, min = 0, step = 0.1)), column(4, numericInput(inputId = "a21", label = HTML("α<sub>21</sub>: 物种1对2的影响"), value = 0.4, min = 0, step = 0.1)), column(4, numericInput(inputId = "N2", label = "物种2的起始种群规模", value = 40, min = 0, step = 1))), fluidRow( column(4, numericInput(inputId = "d1", label = HTML("d<sub>1</sub>: 物种1的自限性"), value = 0.02, min = 0, step = 0.01)), column(4, numericInput(inputId = "d2", label = HTML("d<sub>2</sub>: 物种2的自限性"), value = 0.01, min = 0, step = 0.01)), column(4, numericInput(inputId = "time", label = "模拟时长", value = 50, min = 1, step = 1))), fluidRow( column(4, numericInput(inputId = "b1", label = HTML("b<sub>1</sub>: 物种1的半饱和常数"), value = 10, min = 0, step = 1)), column(4, numericInput(inputId = "b2", label = HTML("b<sub>2</sub>: 物种2的半饱和常数"), value = 10, min = 0, step = 1)), column(2, radioButtons(inputId = "plot", label = "图表", choices = c("种群规模vs.时间" = "time", "相图(Phase portrait)" = "phase", "全选" = "both"), selected = "both")), column(2, conditionalPanel( condition = "input.plot != 'time'", checkboxGroupInput(inputId = "phase_opt", label = "包括", choices = c("向量场" = "vec", "种群轨迹" = "traj"), selected = c("vec", "traj"))))) ) # Output panel fluidRow( column(12, renderPlot(plot(), height = 500)) ) ##### Server ##### # Validate input observeEvent(input$a12, { if (input$a12 <= 0) updateNumericInput(inputId = "a12", value = 0.1) }) observeEvent(input$a21, { if (input$a21 <= 0) updateNumericInput(inputId = "a21", value = 0.1) }) observeEvent(input$d1, { if (input$d1 <= 0) updateNumericInput(inputId = "d1", value = 0.01) }) observeEvent(input$d2, { if (input$d2 <= 0) updateNumericInput(inputId = "d2", value = 0.01) }) observeEvent(input$b1, { if (input$b1 <= 0) updateNumericInput(inputId = "b1", value = 1) }) observeEvent(input$b2, { if (input$b2 <= 0) updateNumericInput(inputId = "b2", value = 1) }) observeEvent(input$N1, { if (input$N1 <= 0) updateNumericInput(inputId = "N1", value = 1) }) observeEvent(input$N2, { if (input$N2 <= 0) updateNumericInput(inputId = "N2", value = 1) }) observeEvent(input$time, { if (input$time < 1) updateNumericInput(inputId = "time", value = 1) }) # Retrieve user inputs params <- reactive({c(r1 = input$r1, r2 = input$r2, a12 = input$a12, a21 = input$a21, d1 = input$d1, d2 = input$d2, b1 = input$b1, b2 = input$b2)}) init <- reactive({c(N1 = input$N1, N2 = input$N2)}) time <- reactive({input$time}) vec <- reactive({"vec" %in% input$phase_opt}) traj <- reactive({"traj" %in% input$phase_opt}) # Run mutualism model sim <- reactive({run_mutualism(time(), init(), params())}) # Plot population trajectories over time plot <- reactive({ if (input$plot == "time") { plot_mutualism_time(sim()) + ggplot2::theme(aspect.ratio = 1) } else if (input$plot == "phase") { plot_mutualism_portrait(sim(), vec(), traj()) + ggplot2::theme(aspect.ratio = 1) } else { wrap_plots(plot_mutualism_time(sim()), plot_mutualism_portrait(sim(), vec(), traj()), nrow = 1) + ggplot2::theme(aspect.ratio = 1) } })
# Print footer suppressWarnings(print_app_footer())
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.