{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Usage Guide" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic Usage\n", "\n", "The `mpl_interactions.pyplot` module generalizes functions from matplotlib to be able to plot the results of a function rather than an array. So if we wanted to explore how the function \n", "\n", "$$ f(x, \\tau) = \\sin(x \\cdot \\tau)\\cdot x^\\beta$$\n", "\n", "behaves as a function of $\\tau$ and $\\beta$. Normally to do this we would need to calculate $f$ for multiple values of tau and beta and then plot multiple lines onto a plot.\n", "\n", "With `mpl_interactions` we can plot the function and use sliders to control the values of $tau$ of and $beta$.\n", "\n", "\n", "**Note:** For this first section we will use numpy arrays to specify what values `tau` and `beta` can have. But they can also be specified in a few other ways that may be more convenient - see the [How to specify Parameters](#How-to-Specify-Parameters) section below." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# imports\n", "%matplotlib ipympl\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "import mpl_interactions.ipyplot as iplt" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# define the function\n", "def f(x, tau, beta):\n", " return np.sin(x * tau) * x ** beta\n", "\n", "\n", "x = np.linspace(0, 2 * np.pi, 1000)\n", "tau = np.linspace(5, 10)\n", "beta = np.linspace(0.25, 1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "gif": "usage-basic.apng" }, "outputs": [], "source": [ "# make the interactive figure\n", "\n", "fig, ax = plt.subplots()\n", "controls = iplt.plot(x, f, tau=tau, beta=beta)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The interactive functions behave as closely to their Matplotlib equivalents as possible. So all of these are valid calls:\n", "```python\n", "controls1 = iplt.plot(f, tau=tau, beta=beta)\n", "controls2 = iplt.plot(f, 'o--', tau=tau, beta=beta)\n", "controls3 = iplt.plot(x, f, tau=tau, beta=beta)\n", "controls4 = iplt.plot(x, f, 'o--', tau=tau, beta=beta)\n", "```\n", "\n", "However, if you run all three of those lines together then you will create three sets of controls. To have sliders affect multiple lines you can pass the controls to the function instead of using keyword arguments." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "gif": "usage-multi-func.apng" }, "outputs": [], "source": [ "fig, ax = plt.subplots()\n", "\n", "\n", "def f1(tau, beta):\n", " return np.sin(x * tau) * x * beta\n", "\n", "\n", "def f2(tau, beta):\n", " return np.sin(x * beta) * x * tau\n", "\n", "\n", "controls = iplt.plot(f1, \"k--\", tau=tau, beta=beta, label=\"f1\")\n", "iplt.plot(f2, controls=controls, label=\"f2\")\n", "_ = plt.legend()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Only Using some of the parameters + specifying axes\n", "\n", "Sometimes you may want to use one controls object for multiple functions but the functions take different arguments. There are two ways you can use the same controls object to control functions with different signatures.\n", "\n", "1. Progressively add arguments\n", " - If you provide both a kwarg and a `controls` object to an interactive plotting function then the \n", " \n", "2. Index the controls object to select only the parameters you want.\n", "\n", "This example also shows how to choose what axis the plot shows up on. If you do not specify the `ax` argument then the function will plot on the current axis in the same way that that Matplotlib works." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "gif": "usage-index-controls.apng" }, "outputs": [], "source": [ "def f1(tau):\n", " return np.sin(x * tau) * x * tau\n", "\n", "\n", "def f2(tau, beta):\n", " return np.sin(x * beta) * x * tau\n", "\n", "\n", "fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 4.8))\n", "\n", "# approach 1: adding extra kwargs\n", "controls = iplt.plot(f1, tau=tau, ax=ax1)\n", "_ = iplt.plot(f2, controls=controls, beta=beta, ax=ax1)\n", "\n", "# approach 2: Indexing the controls object\n", "\n", "iplt.plot(f1, controls=controls[\"tau\"], ax=ax2)\n", "_ = iplt.plot(f2, controls=controls, ax=ax2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Combining Multiple types of Plots\n", "\n", "You are not limited to only using the plot function - or to only using one type of interactive plot in a single graph. You can mix and match them as you please." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "gif": "usage-mixed-types.apng" }, "outputs": [], "source": [ "x = np.linspace(0, np.pi, 200)\n", "\n", "\n", "def f_line(x, tau, beta):\n", " return np.sin(x * tau) * x * beta\n", "\n", "\n", "def f_scatter(x, tau):\n", " return np.sin(x * tau) * x * tau + np.random.randn(len(x)) * 0.5\n", "\n", "\n", "fig, ax = plt.subplots()\n", "controls = iplt.plot(x, f_line, tau=tau, beta=beta)\n", "_ = iplt.scatter(x, f_scatter, s=0.5, controls=controls[\"tau\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How to Specify Parameters\n", "\n", "In the above example we specified the possible values for `tau` and `beta` by passing in a numpy array. However, you are not limited to giving numpy arrays to create sliders. You can also use:\n", "\n", "### Tuples\n", "\n", "Will be passed as an argument to `np.linspace` and that resulting array will be used as the slider values.\n", "\n", "n.b. If you use Matplotlib sliders instead of ipywidgets sliders then tuples of length will just be used to define the max and min value of the slider as Matplotlib sliders do not require" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "gif": "usage-tuple-params.apng" }, "outputs": [], "source": [ "fig, ax = plt.subplots()\n", "controls = iplt.plot(x, f, tau=(5, 10, 5), beta=(0.25, 1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tuples for RangeSliders\n", "\n", "You can create a RangeSlider by passing a tuple prefixed with an \"r\"." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "gif": "usage-rangeslider.apng" }, "outputs": [], "source": [ "def f_x(min_max, **kwargs):\n", " # break up the tuple\n", " min_, max_ = min_max\n", " return np.linspace(min_, max_, 100)\n", " # break up the tuple\n", "def f_range(x, tau, **kwargs):\n", " return np.sin(x*tau)\n", "fig, ax = plt.subplots()\n", "controls = iplt.plot(f_x, f_range, tau=(5, 10, 5), min_max = (\"r\", 0, 10))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Categoricals\n", "\n", "If you pass a parameter as a python `set` then the categorical selection widget will be created rather than a slider. One thing to be aware of is that sets are unordered in Python, so if you want to maintain the ordering you can pass in values defined with a set containing a single tuple: `{(