Package sage :: Package server :: Package notebook :: Module interact
[hide private]
[frames] | no frames]

Module interact

source code


Interact Sage functions in the notebook

This module implements a interact decorator for function in the Sage
notebook.

AUTHORS:
    -- William Stein (2008-03-02): version 1.0 at Sage/Enthought Days 8 in Texas
    -- Jason Grout (2008-03): discussion and first few prototypes
    -- Jason Grout (2008-05): input_grid control



Classes [hide private]
  InteractControl
  InputBox
  ColorInput
  InputGrid
  Selector
  Slider
  InteractCanvas
  control
  input_box
  input_grid
  checkbox
  slider
  selector
Functions [hide private]
 
reset_state()
Reset the interact state of this sage process.
source code
 
new_adapt_number()
Return an integer, always counting up, and starting with 0.
source code
 
html(s)
Render the input string s in a form that tells the notebook to display it in the HTML portion of the output.
source code
 
html_slider(id, callback, steps, default=0, margin=0)
Return the HTML representation of a jQuery slider.
source code
 
html_color_selector(id, change, input_change, default='000000')
Return HTML representation of a jQuery color selector.
source code
 
interact(f)
Use interact as a decorator to create interactive Sage notebook cells with sliders, text boxes, radio buttons, check boxes, and color selectors.
source code
 
automatic_control(default)
Automagically determine the type of control from the default value of the variable.
source code
 
list_of_first_n(v, n)
Given an iterator v, return first n elements it produces as a list.
source code
 
update(cell_id, var, adapt, value, globs)
Called when updating the positions of an interactive control.
source code
Variables [hide private]
  SAGE_CELL_ID = 0
  state = {}
  _k = 0
Function Details [hide private]

reset_state()

source code 

Reset the interact state of this sage process.

EXAMPLES:
    sage: sage.server.notebook.interact.state  # random output
    {1: {'function': <function g at 0x72aaab0>, 'variables': {'m': 3, 'n': 5}, 'adapt': {1: <bound method Slider._adaptor of Slider Interact Control: n [1--|1|---10].>, 2: <bound method Slider._adaptor of Slider Interact Control: m [1--|1|---10].>}}}
    sage: from sage.server.notebook.interact import reset_state
    sage: reset_state()
    sage: sage.server.notebook.interact.state
    {}    

new_adapt_number()

source code 

Return an integer, always counting up, and starting with 0.  This
is used for saving the adapt methods for controls.  An adapt
method is just a function that coerces data into some object,
e.g., makes sure the control always produces int's.

OUTPUT:
    integer

EXAMPLES:
    sage: sage.server.notebook.interact.new_adapt_number()   # random output -- depends on when called
    1    

html(s)

source code 

Render the input string s in a form that tells the notebook
to display it in the HTML portion of the output.

INPUT:
    s -- a string

OUTPUT:
    string -- html format

EXAMPLES:
    sage: sage.server.notebook.interact.html('hello')
    <html>hello</html>    

html_slider(id, callback, steps, default=0, margin=0)

source code 

Return the HTML representation of a jQuery slider.

INPUT:
    id      -- string -- the DOM id of the slider (better be unique)
    callback-- javascript that is executed whenever the slider is done moving
    steps   -- number of steps from minimum to maximum value.
    default -- (default: 0) the default position of the slider
    margin  -- (default: 0) size of margin to insert around the slider

EXAMPLES:
We create a jQuery HTML slider.    If you do the following in the notebook
you should obtain a slider that when moved pops up a window showing its
current position.
    sage: from sage.server.notebook.interact import html_slider, html
    sage: html(html_slider('slider-007', 'alert(position)', steps=5, default=2, margin=5))
    <html>...</html>

html_color_selector(id, change, input_change, default='000000')

source code 

Return HTML representation of a jQuery color selector.

INPUT:
    id -- integer; the id of the html div element that this selector should have
    change -- javascript code to execute when the color selector changes. 
    default -- string (default: '000000'); default color as a 6-character
               HTML hex string.

OUTPUT:
    string -- HTML that creates the slider.

EXAMPLES:
    sage: sage.server.notebook.interact.html_color_selector(0, 'alert("changed")', '', default='0afcac')
    '<table>...'

interact(f)

source code 

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>...

automatic_control(default)

source code 

Automagically determine the type of control from the default
value of the variable.

INPUT:
    default -- the default value for v given by the function; see
               the documentation to interact? for details.

OUTPUT:
    a interact control

EXAMPLES:
    sage: sage.server.notebook.interact.automatic_control('')
    Interact input box labeled None with default value ''
    sage: sage.server.notebook.interact.automatic_control(15)
    Interact input box labeled None with default value 15
    sage: sage.server.notebook.interact.automatic_control(('start', 15))
    Interact input box labeled 'start' with default value 15
    sage: sage.server.notebook.interact.automatic_control((1,100))
    Slider: None [1.0--|1.0|---100.0]
    sage: sage.server.notebook.interact.automatic_control(('alpha', (1,100)))
    Slider: alpha [1.0--|1.0|---100.0]
    sage: sage.server.notebook.interact.automatic_control((2,(1,100)))
    Slider: None [1.0--|2.0|---100.0]
    sage: sage.server.notebook.interact.automatic_control(('alpha label', (2,(1,100))))
    Slider: alpha label [1.0--|2.0|---100.0]
    sage: sage.server.notebook.interact.automatic_control((2, ('alpha label',(1,100))))
    Slider: alpha label [1.0--|2.0|---100.0]
    sage: C = sage.server.notebook.interact.automatic_control((1,52, 5)); C
    Slider: None [1--|1|---52]
    sage: C.values()
    [1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 52]
    sage: sage.server.notebook.interact.automatic_control((17, (1,100,5)))
    Slider: None [1--|16|---100]
    sage: sage.server.notebook.interact.automatic_control([1..4])
    Button bar with 4 buttons
    sage: sage.server.notebook.interact.automatic_control([1..100])
    Drop down menu with 100 options
    sage: sage.server.notebook.interact.automatic_control((1..100))
    Slider: None [1--|1|---100]
    sage: sage.server.notebook.interact.automatic_control((5, (1..100)))
    Slider: None [1--|5|---100]
    sage: sage.server.notebook.interact.automatic_control(matrix(2,2))
    Interact 2 x 2 input grid control labeled None with default value [0, 0, 0, 0]

list_of_first_n(v, n)

source code 

Given an iterator v, return first n elements it produces as a list.

INPUT:
    v -- an interator
    n -- an integer

OUTPUT:
    list

EXAMPLES:
    sage: sage.server.notebook.interact.list_of_first_n(Primes(), 10)
    [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
    sage: sage.server.notebook.interact.list_of_first_n((1..5), 10)
    [1, 2, 3, 4, 5]
    sage: sage.server.notebook.interact.list_of_first_n(QQ, 10)
    [0, 1, -1, 1/2, -1/2, 2, -2, 1/3, -1/3, 3/2, -3/2]

update(cell_id, var, adapt, value, globs)

source code 

Called when updating the positions of an interactive control.

INPUT:
    cell_id -- the id of a interact cell
    var -- a variable associated to that cell
    adapt -- the number of the adapt function
    value -- new value of the control
    globs -- global variables.

EXAMPLES:
The following outputs __SAGE_INTERACT_RESTART__ to indicate that
not all the state of the interrupt canvas has been setup yet (this
setup happens when javascript calls certain functions). 
    sage: sage.server.notebook.interact.update(0, 'a', 0, '5', globals())
    __SAGE_INTERACT_RESTART__