{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Saving Animations\n",
    "\n",
    "Since the controls object knows how to update figures as the sliders change their values it is also able to save an animation (e.g. `.gif` or `.mp4` by updating the slider values for you. Under the hood this makes use of {class}`~matplotlib.animation.FuncAnimation` and you can pass any relevant kwargs in via `func_anim_kwargs`. Other `kwargs` will passed to {meth}`Animation.save <matplotlib.animation.Animation.save>`.\n",
    "\n",
    "Saving animations will work with either ipywidgets Sliders or with matplotlib Sliders. However, it will not work with other widgets. (This is an potential area of improvement, PRs welcome)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib ipympl\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "import mpl_interactions.ipyplot as iplt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Usage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.linspace(0, 2 * np.pi, 200)\n",
    "\n",
    "\n",
    "def f(x, amp, freq):\n",
    "    return amp * np.sin(x * freq)\n",
    "\n",
    "\n",
    "# Create the plot as normal\n",
    "fig, ax = plt.subplots()\n",
    "controls = iplt.plot(x, f, freq=(0.05, 10, 250), amp=(1, 10))\n",
    "_ = iplt.title(\"the Frequency is: {freq:.2f}\", controls=controls[\"freq\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# save as a gif\n",
    "anim = controls.save_animation(\"freq-plot-1.gif\", fig, \"freq\", interval=35)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Which Generates this GIF\n",
    "\n",
    "![](../_static/images/freq-plot-1.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Embeding the animation in a noteook.\n",
    "\n",
    "To embed the animation you can do:\n",
    "\n",
    "1. Link to it in markdown cell with `![alt-text](path/to/image)`\n",
    "2. Drag the file into a markdown cell\n",
    "3. Embed {meth}`Animation.to_html5_video <matplotlib.animation.Animation.to_html5_video>` using [`IPython.display.Video`](https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html#IPython.display.Video):\n",
    "\n",
    "   ```python\n",
    "   from IPython.display import Video\n",
    "   Video(anim.to_html5_video(), embed=True)\n",
    "   ```\n",
    "\n",
    "4. Use IPython to display the saved gif\n",
    "\n",
    "You can also read more in this excellent blog post: <http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-as-interactive-javascript-widgets>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "# NBVAL_IGNORE_OUTPUT\n",
    "from IPython.display import Image\n",
    "\n",
    "Image(\"freq-plot-1.gif\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Matplotlib Sliders with `valstep=None`\n",
    "\n",
    "Matplotlib sliders have an optional attribute `valstep` that allows for discrete slider steps. `mpl_interactions` uses this for all sliders that it creates, however if you passed a custom made slider in as a kwarg you may not have used `valstep` if this is the case then the {meth}`.save_animation` method cannot infer how many frames it should render, so you can specify this with the `N_frames` arguments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib.widgets import Slider\n",
    "\n",
    "import mpl_interactions.ipyplot as iplt\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "plt.subplots_adjust(bottom=0.25)\n",
    "x = np.linspace(0, 2 * np.pi, 200)\n",
    "\n",
    "\n",
    "def f(x, freq):\n",
    "    return np.sin(x * freq)\n",
    "\n",
    "\n",
    "axfreq = plt.axes([0.25, 0.1, 0.65, 0.03])\n",
    "slider = Slider(axfreq, label=\"freq\", valmin=0.05, valmax=10)  # note the lack of valstep\n",
    "controls2 = iplt.plot(x, f, freq=slider, ax=ax)\n",
    "_ = iplt.title(\"the Frequency is: {freq:.2f}\", controls=controls2[\"freq\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# save as a gif\n",
    "anim2 = controls2.save_animation(\"freq-plot-2.gif\", fig, \"freq\", interval=35, N_frames=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Gives this GIF:\n",
    "\n",
    "![](../_static/images/freq-plot-2.gif)"
   ]
  }
 ],
 "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.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
