{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Visualizing the Lotka-Volterra Model\n", "\n", "The [Lotka-Volterra](https://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equations) equations are a set of coupled [ordinary differential equations](https://en.wikipedia.org/wiki/Ordinary_differential_equation)(ODEs) that can be used to model predator prey relationships.\n", "\n", "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. \n", "\n", "## Define the function\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib ipympl\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "from mpl_interactions import ipyplot as iplt" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# this cell is based on https://scipy-cookbook.readthedocs.io/items/LoktaVolterraTutorial.html\n", "from scipy import integrate\n", "\n", "t = np.linspace(0, 15, 1000) # time\n", "X0 = np.array([10, 5]) # initials conditions: 10 rabbits and 5 foxes\n", "\n", "\n", "def f(a, b, c, d):\n", " def dX_dt(X, t=0):\n", " \"\"\" Return the growth rate of fox and rabbit populations. \"\"\"\n", " rabbits, foxes = X\n", " dRabbit_dt = a * rabbits - b * foxes * rabbits\n", " dFox_dt = -c * foxes + d * b * rabbits * foxes\n", " return [dRabbit_dt, dFox_dt]\n", "\n", " X, _ = integrate.odeint(dX_dt, X0, t, full_output=True)\n", " return X # expects shape (N, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Make the plots\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "gif": "lotka-volterra1.gif" }, "outputs": [], "source": [ "fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 4.8))\n", "controls = iplt.plot(\n", " f, ax=ax1, a=(0.5, 2), b=(0.1, 3), c=(1, 3), d=(0.1, 2), parametric=True\n", ")\n", "ax1.set_xlabel(\"rabbits\")\n", "ax1.set_ylabel(\"foxes\")\n", "\n", "iplt.plot(f, ax=ax2, controls=controls, label=[\"rabbits\", \"foxes\"])\n", "ax2.set_xlabel(\"time\")\n", "ax2.set_ylabel(\"population\")\n", "_ = ax2.legend()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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. Forutunately the `control` object implements a cache and will avoid call a function more than necessary when we move the sliders.\n", "\n", "\n", "If for some reason you want to disable this you can disable it by setting the `use_cache` attribute to `False`:\n", "```python\n", "controls.use_cache = False\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.8" } }, "nbformat": 4, "nbformat_minor": 4 }