# Visualizing the Lotka-Volterra Model#

The Lotka-Volterra equations are a set of coupled ordinary differential equations(ODEs) that can be used to model predator prey relationships.

They have 4 parameters that can each be tuned individually which will affect how the flucuations in population behave. In order to explore this 4D parameter space we can use `mpl_interactions`

’ `plot`

function to plot the results of the integrated ODE and have the plot update automatically as we update the parameters.

## Define the function#

```
%matplotlib ipympl
import matplotlib.pyplot as plt
import numpy as np
from mpl_interactions import ipyplot as iplt
```

```
# this cell is based on https://scipy-cookbook.readthedocs.io/items/LoktaVolterraTutorial.html
from scipy import integrate
t = np.linspace(0, 15, 1000) # time
X0 = np.array([10, 5]) # initials conditions: 10 rabbits and 5 foxes
# use `c_` instead of `c` because `c` is an argument to plt.scatter
def f(a, b, c_, d):
def dX_dt(X, t=0):
"""Return the growth rate of fox and rabbit populations."""
rabbits, foxes = X
dRabbit_dt = a * rabbits - b * foxes * rabbits
dFox_dt = -c_ * foxes + d * b * rabbits * foxes
return [dRabbit_dt, dFox_dt]
X, _ = integrate.odeint(dX_dt, X0, t, full_output=True)
return X # expects shape (N, 2)
```

## Make the plots#

Here we make two plots. On the left is a parametric plot that shows all the possible combinations of rabbits and foxes that we can have. The plot on the right has time on the X axis and shows how the fox and rabbit populations evolve in time.

```
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 4.8))
controls = iplt.plot(f, ax=ax1, a=(0.5, 2), b=(0.1, 3), c_=(1, 3), d=(0.1, 2), parametric=True)
ax1.set_xlabel("rabbits")
ax1.set_ylabel("foxes")
iplt.plot(f, ax=ax2, controls=controls, label=["rabbits", "foxes"])
ax2.set_xlabel("time")
ax2.set_ylabel("population")
_ = ax2.legend()
```

You may have noticed that it looks as though we will end up calling our function `f`

twice every time we update the parameters. This would be a bummer because then our computer would be doing twice as much work as it needs to. Fortunately the `control`

object implements a cache and will avoid call a function more than necessary when we move the sliders.

If for some reason you want to disable this you can disable it by setting the `use_cache`

attribute to `False`

:

```
controls.use_cache = False
```