- interact(*args, **kwds)
- Use interact as a decorator to create interactive Sage notebook
cells with sliders, text boxes, radio buttons, check boxes, and
color selectors. Simply put ``@interact`` on the line before a
function definition in a cell by itself, and choose appropriate
defaults for the variable names to determine the types of
controls (see tables below).
INPUT:
- ``f`` - a Python function
- ``layout`` (optional) - a dictionary with keys 'top', 'bottom', 'left', 'right' and values lists of rows of control variable names. Controls are laid out according to this pattern. If ``layout`` is not a dictionary, it is assumed to be the 'top' value. If ``layout`` is None, then all controls are assigned separate rows in the ``top`` value.
EXAMPLES:
In each example below we use a single underscore for the function
name. You can use *any* name you want; it does not have to
be an underscore.
We create an interact control with two inputs, a text input for
the variable ``a`` and a ``y`` slider that runs through the range of
integers from `0` to `19`.
::
sage: @interact
... def _(a=5, y=(0..20)): print a + y
...
<html>...
::
sage: @interact(layout=[['a','b'],['d']])
... def _(a=x^2, b=(0..20), c=100, d=x+1): print a+b+c+d
...
<html>...
::
sage: @interact(layout={'top': [['a', 'b']], 'left': [['c']], 'bottom': [['d']]})
... def _(a=x^2, b=(0..20), c=100, d=x+1): print a+b+c+d
...
<html>...
Draw a plot interacting with the "continuous" variable ``a``. By
default continuous variables have exactly 50 possibilities.
::
sage: @interact
... def _(a=(0,2)):
... show(plot(sin(x*(1+a*x)), (x,0,6)), figsize=4)
<html>...
Interact a variable in steps of 1 (we also use an unnamed
function)::
sage: @interact
... def _(n=(10,100,1)):
... show(factor(x^n - 1))
<html>...
Interact two variables::
sage: @interact
... def _(a=(1,4), b=(0,10)):
... show(plot(sin(a*x+b), (x,0,6)), figsize=3)
<html>...
Place a block of text among the controls::
sage: @interact
... def _(t1=text_control("Factors an integer."), n="1"):
... print factor(Integer(n))
<html>...
You do not have to use interact as a decorators; you can also
simply write ``interact(f)`` where ``f`` is any Python function
that you have defined, though this is frowned upon. E.g., ``f``
can also be a library function as long as it is written in
Python::
sage: interact(matrix) # put ZZ, 2,2,[1..4] in boxes...
<html>...
If your the time to evaluate your function takes awhile, you may
not want to have it reevaluated every time the inputs change. In
order to prevent this, you can add a keyword ``auto_update=False`` to
your function to prevent it from updating whenever the values are
changed. This will cause a button labeled 'Update' to appear
which you can click on to re-evaluate your function.
::
sage: @interact
... def _(n=(10,100,1), auto_update=False):
... show(factor(x^n - 1))
<html>...
DEFAULTS:
Defaults for the variables of the input function determine
interactive controls. The standard controls are ``input_box``,
``slider``, ``range_slider``, ``checkbox``, ``selector``,
``input_grid``, and ``color_selector``. There is also a text
control (see the defaults below).
* ``u = input_box(default=None, label=None, type=None)`` -
input box with given ``default``; use ``type=str`` to get
input as an arbitrary string
* ``u = slider(vmin, vmax=None, step_size=1, default=None,
label=None)`` - slider with given list of possible values;
``vmin`` can be a list
* ``u = range_slider(vmin, vmax=None, step_size=1,
default=None, label=None)`` - range slider with given list
of possible values; ``vmin`` can be a list
* ``u = checkbox(default=True, label=None)`` - a checkbox
* ``u = selector(values, label=None, nrows=None, ncols=None,
buttons=False)`` - a dropdown menu or buttons (get buttons
if ``nrows``, ``ncols``, or ``buttons`` is set, otherwise a
dropdown menu)
* ``u = input_grid(nrows, ncols, default=None, label=None,
to_value=lambda x:x, width=4)`` - an editable grid of
objects (a matrix or array)
* ``u = color_selector(default=(0,0,1), label=None,
widget='farbtastic', hide_box=False)`` - a color selector with a
possibly hidden input box; the ``widget`` can also be ``'jpicker'``
or ``'colorpicker'``
* ``u = text_control(value='')`` - a block of text
You can also create a color selector by setting the default value for
an ``input_box`` to ``Color(...)``.
There are also some convenient defaults that allow you to make
controls automatically without having to explicitly specify them.
E.g., you can make ``x`` a continuous slider of values between ``u``
and ``v`` by just writing ``x=(u,v)`` in the argument list of
your function. These are all just convenient shortcuts for
creating the controls listed above.
* ``u`` - blank input_box field
* ``u = element`` - input_box with ``default=element``, if
element not below.
* ``u = (umin,umax)`` - continuous slider (really `100` steps)
* ``u = (umin,umax,du)`` - slider with step size ``du``
* ``u = list`` - buttons if ``len(list)`` at most `5`;
otherwise, drop down
* ``u = generator`` - a slider (up to `10000` steps)
* ``u = bool`` - a checkbox
* ``u = Color('blue')`` - a color selector; returns ``Color``
object
* ``u = (default, v)`` - ``v`` as above, with given
``default`` value
* ``u = (label, v)`` - ``v`` as above, with given ``label``
(a string)
* ``u = matrix`` - an ``input_grid`` with ``to_value`` set to
``matrix.parent()`` and default values given by the matrix
.. note::
Suppose you would like to make an interactive with a default
RGB color of ``(1,0,0)``, so the function would have signature
``f(color=(1,0,0))``. Unfortunately, the above shortcuts
reinterpret the ``(1,0,0)`` as a discrete slider with step
size 0 between 1 and 0. Instead you should do the
following::
sage: @interact
... def _(v = input_box((1,0,0))):
... show(plot(sin,color=v))
<html>...
An alternative::
sage: @interact
... def _(c = color_selector((1, 0, 0))):
... show(plot(sin, color = c))
<html>...
MORE EXAMPLES:
We give an input box that allows one to enter completely arbitrary
strings::
sage: @interact
... def _(a=input_box('sage', label="Enter your name", type=str)):
... print "Hello there %s"%a.capitalize()
<html>...
The scope of variables that you control via :func:`interact` are local
to the scope of the function being interacted with. However, by
using the ``global`` Python keyword, you can still modify global
variables as follows::
sage: xyz = 10
sage: @interact
... def _(a=('xyz',5)):
... global xyz
... xyz = a
<html>...
If you enter the above you obtain an :func:`interact` canvas.
Entering values in the box changes the global variable ``xyz``.
Here's a example with several controls::
sage: @interact
... def _(title=["A Plot Demo", "Something silly", "something tricky"], a=input_box(sin(x*sin(x*sin(x))), 'function'),
... clr = Color('red'), thickness=[1..30], zoom=(1,0.95,..,0.1), plot_points=(200..2000)):
... html('<h1 align=center>%s</h1>'%title)
... print plot_points
... show(plot(a, -zoom*pi,zoom*pi, color=clr, thickness=thickness, plot_points=plot_points))
<html>...
For a more compact color control, use an empty label, a different
widget (``'colorpicker'`` or ``'jpicker'``), and hide the input
box::
sage: @interact
... def _(color=color_selector((1,0,1), label='', widget='colorpicker', hide_box=True)):
... show(plot(x/(8/7+sin(x)), (x,-50,50), fill=True, fillcolor=color))
<html>...
We give defaults and name the variables::
sage: @interact
... def _(a=('first', (1,4)), b=(0,10)):
... show(plot(sin(a*x+sin(b*x)), (x,0,6)), figsize=3)
<html>...
Another example involving labels, defaults, and the slider
command::
sage: @interact
... def _(a = slider(1, 4, default=2, label='Multiplier'),
... b = slider(0, 10, default=0, label='Phase Variable')):
... show(plot(sin(a*x+b), (x,0,6)), figsize=4)
<html>...
An example where the range slider control is useful::
sage: @interact
... def _(b = range_slider(-20, 20, 1, default=(-19,3), label='Range')):
... plot(sin(x)/x, b[0], b[1]).show(xmin=b[0],xmax=b[1])
<html>...
An example using checkboxes, obtained by making the default values
bools::
sage: @interact
... def _(axes=('Show axes', True), square=False):
... show(plot(sin, -5,5), axes=axes, aspect_ratio = (1 if square else None))
<html>...
An example generating a random walk that uses a checkbox control
to determine whether points are placed at each step::
sage: @interact
... def foo(pts = checkbox(True, "points"), n = (50,(10..100))):
... s = 0; v = [(0,0)]
... for i in range(n):
... s += random() - 0.5
... v.append((i, s))
... L = line(v, rgbcolor='#4a8de2')
... if pts: L += points(v, pointsize=20, rgbcolor='black')
... show(L)
<html>...
You can rotate and zoom into 3-D graphics while interacting with a
variable::
sage: @interact
... def _(a=(0,1)):
... x,y = var('x,y')
... show(plot3d(sin(x*cos(y*a)), (x,0,5), (y,0,5)), figsize=4)
<html>...
A random polygon::
sage: pts = [(random(), random()) for _ in xrange(20)]
sage: @interact
... def _(n = (4..len(pts)), c=Color('purple') ):
... G = points(pts[:n],pointsize=60) + polygon(pts[:n], rgbcolor=c)
... show(G, figsize=5, xmin=0, ymin=0)
<html>...
Two "sinks" displayed simultaneously via a contour plot and a 3-D
interactive plot::
sage: @interact
... def _(q1=(-1,(-3,3)), q2=(-2,(-3,3))):
... x,y = var('x,y')
... f = q1/sqrt((x+1)^2 + y^2) + q2/sqrt((x-1)^2+(y+0.5)^2)
... C = contour_plot(f, (-2,2), (-2,2), plot_points=30, contours=15, cmap='cool')
... show(C, figsize=3, aspect_ratio=1)
... show(plot3d(f, (x,-2,2), (y,-2,2)), figsize=4)
<html>...
This is similar to above, but you can select the color map from a
dropdown menu::
sage: @interact
... def _(q1=(-1,(-3,3)), q2=(-2,(-3,3)),
... cmap=['autumn', 'bone', 'cool', 'copper', 'gray', 'hot', 'hsv',
... 'jet', 'pink', 'prism', 'spring', 'summer', 'winter']):
... x,y = var('x,y')
... f = q1/sqrt((x+1)^2 + y^2) + q2/sqrt((x-1)^2+(y+0.5)^2)
... C = contour_plot(f, (x,-2,2), (y,-2,2), plot_points=30, contours=15, cmap=cmap)
... show(C, figsize=3, aspect_ratio=1)
<html>...
A quadratic roots etch-a-sketch::
sage: v = []
sage: html('<h2>Quadratic Root Etch-a-sketch</h2>')
<html>...<h2>Quadratic Root Etch-a-sketch</h2>...</html>
sage: @interact
... def _(a=[-10..10], b=[-10..10], c=[-10..10]):
... f = a*x^2 + b*x + c == 0; show(f)
... soln = solve(a*x^2 + b*x + c == 0, x)[0].rhs()
... show(soln)
... P = tuple(CDF(soln))
... v.append(P)
... show(line(v, rgbcolor='purple') + point(P, pointsize=200))
<html>...
In the following example, we only generate data for a given ``n``
once, so that as one varies ``p`` the data does not randomly change.
We do this by simply caching the results for each ``n`` in a
dictionary.::
sage: data = {}
sage: @interact
... def _(n=(500,(100,5000,1)), p=(1,(0.1,10))):
... n = int(n)
... if not data.has_key(n):
... data[n] = [(random(), random()) for _ in xrange(n)]
... show(points([(x^p,y^p) for x,y in data[n]], rgbcolor='black'), xmin=0, ymin=0, axes=False)
<html>...
A conchoid::
sage: @interact
... def _(k=(1.2,(1.1,2)), k_2=(1.2,(1.1,2)), a=(1.5,(1.1,2))):
... u, v = var('u,v')
... f = (k^u*(1+cos(v))*cos(u), k^u*(1+cos(v))*sin(u), k^u*sin(v)-a*k_2^u)
... show(parametric_plot3d(f, (u,0,6*pi), (v,0,2*pi), plot_points=[40,40], texture=(0,0.5,0)))
<html>...
An input grid::
sage: @interact
... def _(A=matrix(QQ,3,3,range(9)), v=matrix(QQ,3,1,range(3))):
... try:
... x = A\v
... html('$$%s %s = %s$$'%(latex(A), latex(x), latex(v)))
... except:
... html('There is no solution to $$%s x=%s$$'%(latex(A), latex(v)))
<html>...