lpnguyen commited on
Commit
f7015ee
1 Parent(s): 6f20b77

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -24
app.py CHANGED
@@ -1,13 +1,36 @@
1
  import streamlit as st
2
- from dynamical_system import invasion_fitness, invasion_fitness2
3
  import numpy as np
4
  from tools import plot_3D_invfitness, plot_invasionfitness, make_interactive_video, plot_PIP
 
 
5
 
6
  st.set_page_config(layout="wide")
7
  st.title("Adaptive dynamics")
8
 
9
- st.subheader("When there is no cost on reproduction")
 
 
 
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  zlist = np.linspace(0, 2, 100)
13
  alpha = 0.4
@@ -15,45 +38,127 @@ alpha = 0.4
15
  X, Y = np.meshgrid(zlist, zlist)
16
  inv_fitness3D = invasion_fitness(X, Y, pars=alpha)
17
 
 
18
 
19
- col1, col2 = st.columns(2, gap="large")
20
- with col1:
21
- st.plotly_chart(make_interactive_video(
22
- 0.01, zlist[-1], 0.03, zlist, invasion_fitness, alpha, [-2, 2]))
23
 
24
 
25
- with col2:
26
- zm = st.slider("Mutant trait value", 0.0, 2.0, value=0.2, step=0.01)
27
- st.plotly_chart(plot_invasionfitness(
28
- zm, zlist, invasion_fitness, alpha, [-2, 2]))
29
 
30
- col3, col4 = st.columns(2, gap="large")
31
- with col3:
32
- st.plotly_chart(plot_3D_invfitness(zlist, inv_fitness3D, zm, (-4.1, 4.1)))
33
- with col4:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  st.plotly_chart(plot_PIP(zlist, invasion_fitness, alpha))
 
 
35
 
36
  st.header("When there is cost in reproduction")
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  zlist = np.linspace(0, 1, 100)
39
 
40
- beta = st.slider(r"Value of $\beta$", 0.1, 2.0, value=1.2, step=0.2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  col5, col6 = st.columns(2, gap="large")
42
  with col5:
 
 
 
 
43
  st.plotly_chart(
44
- make_interactive_video(
45
- 0.1, zlist[-1], 0.01, zlist, invasion_fitness2, (alpha, beta), [-0.2, 0.2])
 
 
 
 
46
  )
47
  with col6:
48
- zm2 = st.slider("Mutant trait value ", 0.0, 1.0, value=0.1, step=0.01)
49
- st.plotly_chart(plot_invasionfitness(
50
- zm2, zlist, invasion_fitness2, (alpha, beta), [-0.2, 0.2]))
51
-
52
- X, Y = np.meshgrid(zlist, zlist)
53
- inv_fitness3D2 = invasion_fitness2(X, Y, pars=(alpha, beta))
 
 
54
 
55
  col7, col8 = st.columns(2, gap="large")
56
  with col7:
57
- st.plotly_chart(plot_3D_invfitness(zlist, inv_fitness3D2, zm, (-3.2, 3.2)))
 
 
 
 
 
 
 
 
58
  with col8:
 
 
 
 
 
 
 
 
 
 
 
 
59
  st.plotly_chart(plot_PIP(zlist, invasion_fitness2, (alpha, beta)))
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ from dynamical_system import invasion_fitness, invasion_fitness2, invasion_fitness3, pop_dynamics2
3
  import numpy as np
4
  from tools import plot_3D_invfitness, plot_invasionfitness, make_interactive_video, plot_PIP
5
+ from scipy.integrate import solve_ivp
6
+ import plotly.graph_objects as go
7
 
8
  st.set_page_config(layout="wide")
9
  st.title("Adaptive dynamics")
10
 
11
+ st.subheader("Example 1: When there is no cost on reproduction")
12
+ st.write(
13
+ r"""
14
+ The ecological dynamics of the resident is
15
 
16
+ $\frac{dn_r}{dt} = n_r(z_r - \alpha n_r)$
17
+
18
+ where $z_r$ is the intrinsic growth rate of the resident,
19
+ $\alpha$ is the competition coefficient among resident individual
20
+
21
+ The resident reaches equilibrium $n^* = \frac{z_r}{\alpha}$ before a mutant arises.
22
+ New mutant with a different intrinsic growth rate $z_m$ arises has dynamics as followed
23
+
24
+ $\frac{dn_m}{dt} = n_m(z_m - \alpha (n_r + n_m))$
25
+
26
+ The mutant growth rate is $r(z_m, z) = z_m - \alpha n^*$.
27
+ This is also the invasion fitness of the mutant.
28
+ The invasion fitness depends on the mutant's trait value $z_m$,
29
+ and the resident's trait value $z_r$ through the resident density at equilibrium $n^*$
30
+
31
+ The video shows the process of mutant invasion and replacement
32
+ """
33
+ )
34
 
35
  zlist = np.linspace(0, 2, 100)
36
  alpha = 0.4
 
38
  X, Y = np.meshgrid(zlist, zlist)
39
  inv_fitness3D = invasion_fitness(X, Y, pars=alpha)
40
 
41
+ st.write("Invasion process video")
42
 
43
+ st.plotly_chart(
44
+ make_interactive_video(0.01, zlist[-1], 50, zlist, invasion_fitness, alpha, [-2, 2])
45
+ )
 
46
 
47
 
48
+ st.write(
49
+ """
50
+ Now you can try varying the mutant trait value to see how the fitness landscape change.
 
51
 
52
+ Some suggestions for you to think:
53
+
54
+ - In which case mutants with smaller growth rate value invade?
55
+
56
+ - Do you see the relateness among the three graphs?
57
+
58
+ Hint: Rotate the 3D graph to match with the axes of the first two graph to see if:
59
+
60
+ The first graph is the vertical slice (gray surface) in the last graph
61
+
62
+ PIP is the projection of the fitness surface in the last graph,
63
+
64
+ """
65
+ )
66
+
67
+ zm = st.slider("Mutant trait value", 0.0, 2.0, value=0.2, step=0.01)
68
+
69
+ col1, col2, col3 = st.columns(3)
70
+ with col1:
71
+ st.plotly_chart(plot_invasionfitness(zm, zlist, invasion_fitness, alpha, [-2, 2]))
72
+ with col2:
73
  st.plotly_chart(plot_PIP(zlist, invasion_fitness, alpha))
74
+ with col3:
75
+ st.plotly_chart(plot_3D_invfitness(zlist, inv_fitness3D, zm, (-4, 4)))
76
 
77
  st.header("When there is cost in reproduction")
78
 
79
+ st.write(
80
+ r"""
81
+ Now we include some cost in having a high intrinsical growth rate.
82
+
83
+ The ecological dynamics of the resident is now
84
+
85
+ $\frac{dn_r}{dt} = n_r(z_r - z_r^\beta - \alpha n_r)$
86
+
87
+ Do you see that now if the growth rate $z_r$ increases then there is an additional cost $z_r^\beta$.
88
+
89
+ The value of $\beta$ affect the shape of the cost
90
+ """
91
+ )
92
  zlist = np.linspace(0, 1, 100)
93
 
94
+ col_par1, col_par2 = st.columns(2, gap="large")
95
+ with col_par1:
96
+ beta = st.slider(r"Value of $\beta$", 0.1, 2.0, value=1.2, step=0.01)
97
+ with col_par2:
98
+ z_val = st.slider("Trait value", 0.0, 1.0, value=0.1, step=0.01)
99
+
100
+ z_star = (1 / beta) ** (1 / (beta - 1))
101
+
102
+ ndsol = solve_ivp(
103
+ pop_dynamics2,
104
+ (0, 550),
105
+ [np.random.uniform(0, 0.05)],
106
+ t_eval=np.linspace(0, 550, 200),
107
+ args=((alpha, beta, z_val),),
108
+ )
109
+
110
  col5, col6 = st.columns(2, gap="large")
111
  with col5:
112
+ if ndsol.y[0, -1] > 0:
113
+ st.write("The population density reaches", ndsol.y[0, -1])
114
+ else:
115
+ st.write("The population density reaches", 0)
116
  st.plotly_chart(
117
+ go.Figure(
118
+ data=go.Scatter(x=ndsol.t, y=ndsol.y[0, :], mode="lines"),
119
+ layout=go.Layout(
120
+ xaxis_title="Time", yaxis_title="Population dynamics", yaxis=dict(range=(0, 0.3))
121
+ ),
122
+ ),
123
  )
124
  with col6:
125
+ st.plotly_chart(
126
+ go.Figure(
127
+ data=[
128
+ go.Scatter(x=zlist, y=zlist, name="Intrinsic growth rate"),
129
+ go.Scatter(x=zlist, y=zlist**beta, name="Cost on mortality"),
130
+ ]
131
+ )
132
+ )
133
 
134
  col7, col8 = st.columns(2, gap="large")
135
  with col7:
136
+ st.write("Invasion process video")
137
+ z_start = st.number_input(
138
+ "Enter the start value of z then click play", 1e-5, 1.0, 0.1, step=0.01
139
+ )
140
+ st.plotly_chart(
141
+ make_interactive_video(
142
+ z_start, z_star, 20, zlist, invasion_fitness2, (alpha, beta), [-0.2, 0.2]
143
+ )
144
+ )
145
  with col8:
146
+ zm2 = st.slider("Mutant trait value", 0.0, 1.0, value=0.1, step=0.01)
147
+
148
+ st.plotly_chart(plot_invasionfitness(zm2, zlist, invasion_fitness2, (alpha, beta), [-0.2, 0.2]))
149
+
150
+ X, Y = np.meshgrid(zlist, zlist)
151
+ inv_fitness3D2 = invasion_fitness2(X, Y, pars=(alpha, beta))
152
+
153
+ col9, col10 = st.columns(2, gap="large")
154
+ range = (np.min(inv_fitness3D2) - np.mean(inv_fitness3D2) - 1e-5, np.max(inv_fitness3D2))
155
+ with col9:
156
+ st.plotly_chart(plot_3D_invfitness(zlist, inv_fitness3D2, zm, range))
157
+ with col10:
158
  st.plotly_chart(plot_PIP(zlist, invasion_fitness2, (alpha, beta)))
159
+
160
+
161
+ st.header("Assymetric competition")
162
+ zlist = np.linspace(-3, 3, 100)
163
+ inv_fitness3D3 = invasion_fitness3(zlist, zlist, (0, 2.4))
164
+ st.plotly_chart(plot_PIP(zlist, invasion_fitness3, (0, 2.4)))