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
EXAMPLES:
In each example below we use a single underscore for the function
name. You can use \emph{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>...
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>...
You do not have to use interact as a decorators; you can also
simply write \code{interact(f)} where f is any Python function
that you have defined, though this is frowned on. 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>...
DEFAULTS:
Defaults for the variables of the input function determine
interactive controls. The standard controls are \code{input_box},
\code{slider}, \code{checkbox}, \code{selector}, and
\code{input_grid}. There is also a color selector (see defaults below).
\begin{itemize}
\item u = input_box(default=None, label=None, type=None)
-- input box with given default; use type=str to
get input as an arbitrary string
\item u = slider(vmin, vmax=None,step_size=1,default=None,label=None)
-- slider with given list of possible values; vmin an be a list
\item u = checkbox(default=True, label=None)
-- a checkbox
\item 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)
\item 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)
\end{itemize}
You can create a color selector by setting the default value for a
variable 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 \code{x=(u,v)} in the argument list of
your function. These are all just convenient shortcuts for
creating the controls listed above.
\begin{itemize}
\item u -- blank input_box field
\item u = element -- input_box with default=element, if element not below.
\item u = (umin,umax) -- continuous slider (really 100 steps)
\item u = (umin,umax,du)-- slider with step size du
\item u = list -- buttons if len(list) at most 5; otherwise, drop down
\item u = generator -- a slider (up to 10000 steps)
\item u = bool -- a checkbox
\item u = Color('blue') -- a 2d RGB color selector; returns Color object
\item u = (default, v) -- v as above, with given default value
\item u = (label, v) -- v as above, with given label (a string)
\item u = matrix -- an input_grid with to_value set to matrix.parent()
and default values given by the matrix
\end{itemize}
WARNING: Suppose you would like to make a interactive with a
default rgb color of (1,0,0), so the function would have signature
\code{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>...
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 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 interact campus. Entering
values in the box, changes the global variable xyz.
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>...
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 and 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 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 3D 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 3d
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><font color='black'><h2>Quadratic Root Etch-a-sketch</h2></font></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 doesn't 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>...
|