{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Using Interact" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `interact` function (`ipywidgets.interact`) automatically creates user interface (UI) controls for exploring code and data interactively. It is the easiest way to get started using IPython's widgets." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from __future__ import print_function\n", "from ipywidgets import interact, interactive, fixed, interact_manual\n", "import ipywidgets as widgets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic `interact`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At the most basic level, `interact` autogenerates UI controls for function arguments, and then calls the function with those arguments when you manipulate the controls interactively. To use `interact`, you need to define a function that you want to explore. Here is a function that prints its only argument `x`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def f(x):\n", " return x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When you pass this function as the first argument to `interact` along with an integer keyword argument (`x=10`), a slider is generated and bound to the function parameter." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=10);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When you move the slider, the function is called, which prints the current value of `x`.\n", "\n", "If you pass `True` or `False`, `interact` will generate a checkbox:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=True);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you pass a string, `interact` will generate a text area." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x='Hi there!');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`interact` can also be used as a decorator. This allows you to define a function and interact with it in a single shot. As this example shows, `interact` also works with functions that have multiple arguments." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@interact(x=True, y=1.0)\n", "def g(x, y):\n", " return (x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fixing arguments using `fixed`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are times when you may want to explore a function using `interact`, but fix one or more of its arguments to specific values. This can be accomplished by wrapping values with the `fixed` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def h(p, q):\n", " return (p, q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When we call `interact`, we pass `fixed(20)` for q to hold it fixed at a value of `20`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(h, p=5, q=fixed(20));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that a slider is only produced for `p` as the value of `q` is fixed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Widget abbreviations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When you pass an integer-valued keyword argument of `10` (`x=10`) to `interact`, it generates an integer-valued slider control with a range of `[-10,+3*10]`. In this case, `10` is an *abbreviation* for an actual slider widget:\n", "\n", "```python\n", "IntSlider(min=-10,max=30,step=1,value=10)\n", "```\n", "\n", "In fact, we can get the same result if we pass this `IntSlider` as the keyword argument for `x`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=widgets.IntSlider(min=-10,max=30,step=1,value=10));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This examples clarifies how `interact` proceses its keyword arguments:\n", "\n", "1. If the keyword argument is a `Widget` instance with a `value` attribute, that widget is used. Any widget with a `value` attribute can be used, even custom ones.\n", "2. Otherwise, the value is treated as a *widget abbreviation* that is converted to a widget before it is used.\n", "\n", "The following table gives an overview of different widget abbreviations:\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", "
Keyword argumentWidget
`True` or `False`Checkbox
`'Hi there'`Text
`value` or `(min,max)` or `(min,max,step)` if integers are passedIntSlider
`value` or `(min,max)` or `(min,max,step)` if floats are passedFloatSlider
`['orange','apple']` or `{'one':1,'two':2}`Dropdown
\n", "Note that a dropdown is used if a list or a dict is given (signifying discrete choices), and a slider is used if a tuple is given (signifying a range)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You have seen how the checkbox and textarea widgets work above. Here, more details about the different abbreviations for sliders and dropdowns are given.\n", "\n", "If a 2-tuple of integers is passed `(min,max)`, an integer-valued slider is produced with those minimum and maximum values (inclusively). In this case, the default step size of `1` is used." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=(0,4));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If a 3-tuple of integers is passed `(min,max,step)`, the step size can also be set." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=(0,8,2));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A float-valued slider is produced if the elements of the tuples are floats. Here the minimum is `0.0`, the maximum is `10.0` and step size is `0.1` (the default)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=(0.0,10.0));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The step size can be changed by passing a third element in the tuple." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=(0.0,10.0,0.01));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For both integer and float-valued sliders, you can pick the initial value of the widget by passing a default keyword argument to the underlying Python function. Here we set the initial value of a float slider to `5.5`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@interact(x=(0.0,20.0,0.5))\n", "def h(x=5.5):\n", " return x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dropdown menus are constructed by passing a list of strings. In this case, the strings are both used as the names in the dropdown menu UI and passed to the underlying Python function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x=['apples','oranges']);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want a dropdown menu that passes non-string values to the Python function, you can pass a dictionary. The keys in the dictionary are used for the names in the dropdown menu UI and the values are the arguments that are passed to the underlying Python function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(f, x={'one': 10, 'two': 20});" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `interactive`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to `interact`, IPython provides another function, `interactive`, that is useful when you want to reuse the widgets that are produced or access the data that is bound to the UI controls." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is a function that returns the sum of its two arguments." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def f(a, b):\n", " return a+b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unlike `interact`, `interactive` returns a `Widget` instance rather than immediately displaying the widget." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "w = interactive(f, a=10, b=20)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The widget is a `Box`, which is a container for other widgets." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "type(w)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The children of the `Box` are two integer-valued sliders produced by the widget abbreviations above." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "w.children" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To actually display the widgets, you can use IPython's `display` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import display\n", "display(w)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At this point, the UI controls work just like they would if `interact` had been used. You can manipulate them interactively and the function will be called. However, the widget instance returned by `interactive` also gives you access to the current keyword arguments and return value of the underlying Python function. Note that unlike `interact`, the return value of the function will not be displayed automatically, but you can display a value inside the function with `IPython.display.display`.\n", "\n", "Here are the current keyword arguments. If you rerun this cell after manipulating the sliders, the values will have changed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "w.kwargs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is the current return value of the function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "w.result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Disabling continuous updates" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When interacting with long running functions, realtime feedback is a burden instead of being helpful. See the following example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def slow_function(i):\n", " print(int(i),list(x for x in range(int(i)) if \n", " str(x)==str(x)[::-1] and \n", " str(x**2)==str(x**2)[::-1]))\n", " return" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "slow_function(1e6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the output is updated even while dragging the mouse on the slider. This is not useful for long running functions due to lagging:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ipywidgets import FloatSlider\n", "interact(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are two ways to mitigate this. You can either only execute on demand, or restrict execution to mouse release events." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `interact_manual`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `interact_manual` function provides a variant of interaction that allows you to restrict execution so it is only done on demand. A button is added to the interact controls that allows you to trigger an execute event." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact_manual(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `continuous_update`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you are using slider widgets, you can set the `continuous_update` kwarg to `False`. `continuous_update` is a kwarg of slider widgets that restricts executions to mouse release events." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "interact(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5, continuous_update=False));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arguments that are dependent of each other" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Arguments that are dependent of each other can be expressed manually using `observe`. See the following example, where one variable is used to describe the bounds of another. For more information, please see the [widget events example notebook](./Widget Events.ipynb)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x_widget = FloatSlider(min=0.0, max=10.0, step=0.05)\n", "y_widget = FloatSlider(min=0.5, max=10.0, step=0.05, value=5.0)\n", "\n", "def update_x_range(*args):\n", " x_widget.max = 2.0 * y_widget.value\n", "y_widget.observe(update_x_range, 'value')\n", "\n", "def printer(x, y):\n", " print(x, y)\n", "interact(printer,x=x_widget, y=y_widget);" ] } ], "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.5.2" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 1, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 1 }