Opened 11 years ago

Closed 11 years ago

#1322 closed enhancement (duplicate)

interact -- interactive functions in the notebook (moved to #2449)

Reported by: jason Owned by: was
Priority: major Milestone: sage-2.10.3
Component: notebook Keywords:
Cc: jason-sage@…, mhansen, TimothyClemans Merged in:
Authors: Reviewers:
Report Upstream: Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Description (last modified by was)

This ticket is a total mess, so I've made a new clean #2449.

See mailing list discussions at

http://groups.google.com/group/sage-devel/browse_thread/thread/f0119a34ca55e95f/65bf86aef687c6d2?lnk=gst&q=interactive#65bf86aef687c6d2

and http://groups.google.com/group/sage-devel/browse_thread/thread/db30b40ab36aa51c/2157c72c6cc50dfe?lnk=gst&q=Manipulate#2157c72c6cc50dfe

Also, from Robert Miller (to Jason Grout):

> I was brainstorming about something like widgets a while ago, before
> the notebook underwent its sea change. We (>= you and I) should make
> this a coding sprint at SD7.

Attachments (8)

menu-widget.patch (3.4 KB) - added by jason 11 years ago.
Extremely rough cut of initial functionality for interactive widgets in the notebook.
manipulate.patch (10.8 KB) - added by jason 11 years ago.
A different very rough cut of functionality.
manipulate-take3.patch (5.7 KB) - added by was 11 years ago.
this is independent of the patches above -- it's standalone -- see comments below for how to use.
manipulate-take3_part2.patch (10.9 KB) - added by was 11 years ago.
part 2 of manipulate with decorators; this is usable again (probably) better docs; but there are several things to do soon and I'm too tired.
manipulate_take3_part3.patch (12.6 KB) - added by was 11 years ago.
this requires that you also install the extcode patch that gives jquery support.
manipulate_take3_part4.patch (24.3 KB) - added by was 11 years ago.
manipulate_take3_part5.patch (18.9 KB) - added by was 11 years ago.
manipulate.hg (167.0 KB) - added by was 11 years ago.
this is a new better version

Download all attachments as: .zip

Change History (33)

comment:1 Changed 11 years ago by jason

  • Cc jason-sage@… added

comment:2 Changed 11 years ago by jason

Test to see if CC feature is working.

Changed 11 years ago by jason

Extremely rough cut of initial functionality for interactive widgets in the notebook.

comment:4 Changed 11 years ago by jason

  • Summary changed from interactive widgets in the notebook to [with alpha patch] interactive widgets in the notebook

There are several problems with the way things are done in menu-widget.patch:

  • We rely on a complete hack of sending an AJAX request with an invalid cell id (-1). The webserver complains ("Warning -- cell -1 no longer exists"), but the code is still executed and everything seems fine. So it'd be great if we could remove the warning and call it a feature :).
  • The variable is not set initially. You have to select a value before using the variable. The variable is not set initially because I couldn't figure out how to set a global variable from within the menu.init function. We could probably look into the polynomial ring stuff and figure out how to inject variables into the global namespace. I have a rough cython file written that attempts to define an "inject_global" function that injects a variable into the global namespace, but when this function is called from menu.init, it doesn't inject into the global namespace.
  • When a value is updated via the menu, it doesn't change or reevaluate any cells in the notebook. It would be very nice to automatically evaluate other cells in the notebook to get real-time dynamic feedback from picking new values from the menu.
  • When manually reevaluating cells, it seems to display the old value first and then update to the new value. This is very annoying and takes time and looks bad.
  • There should be some sort of caching eventually implemented to make things faster. Maybe something like a directive "%depends_on(x)" to say that a cell's output only depends on x. In other words, if x is the same, then we can spit out a cached copy of the cell's output instead of having to reevaluate the cell.

The menu select box is the tip of the iceberg here. It'd be nice to have fancy sliders and things like that using javascript.

comment:5 Changed 11 years ago by jason

Oh, and one more thing: we currently have to import the function:

sage: from sage.server.notebook.widgets.menu import menu
sage: menu('f',[sin,cos,tan]).show()

(a menu is shown.  pick a value for f)

sage: plot(f(x),0,2*pi).show()

(the plot of f(x) (with the selected f) is shown.)

comment:6 Changed 11 years ago by jason

  • Component changed from combinatorics to notebook
  • Keywords graphs removed
  • Milestone changed from sage-wishlist to sage-2.9
  • Owner changed from mhansen to boothby

comment:7 Changed 11 years ago by jason

It appears that the warning about a nonexistant cell comes from the line

            s = encode_list([cell.next_id(), 'no_new_cell', str(id)])

in sage/server/notebook/twisted.py

comment:8 Changed 11 years ago by jason

In addition to applying the first patch above, you need to create an empty init.py file in sage/server/notebook/widgets/

comment:9 Changed 11 years ago by was

See also #1613....

comment:10 Changed 11 years ago by was

Here is a trivial example. You *must* change 155 to an actual existing blank output cell.

def manipulate():
    print r""" 
    <html>
<script>
function manip(id, cmd) {
   var cell_input = get_cell(id);
   cell_input.value = cmd;
   cell_input.style.display = "none";
   evaluate_cell(id, 0);
}
</script>
    <input type="button" value="sin(x)" onclick="manip(155, 'plot(sin,-1,1)')">
    <input type="button" value="cos(x)" onclick="manip(155, 'plot(cos,-1,1)')">
    <input type="button" value="tan(x)" onclick="manip(155, 'plot(tan,-1,1)')">
    <input type="button" value="sin(x^2)" onclick="manip(155, 'plot(sin(x^2),-1,1)')">
    </html>
"""

comment:11 Changed 11 years ago by jason

More stuff:

print r"""
<html>
<script>
function manip(id,cmd, variable, value) {
    var cell_input = get_cell(id);
    cell_input.value = variable+"="+value+"\n"+cmd;
    cell_input.style.display = "none";
    evaluate_cell(id, 0);
}
</script>
</html>
"""

and

def menu(cmd, variable, options):
    ret = """<select name='' onchange='manip(%d,"%s", "%s", this.options[this.selectedIndex].value)'>"""%(__SAGE_NOTEBOOK_CELL_ID__+1,cmd,variable)
    for option in options:
        ret += "<option value='%s'>%s</option>"%(repr(option), repr(option))
    ret += "</select>"
    return ret

def manipulate(cmd, variables):
    controls=''
    for key,val in variables.items():
        controls += menu(cmd, key, val)
    print "<html>"+controls+"</html>"

and

manipulate('plot(f(x),(x,0,3))', {'f':[sin,cos,tan]})

comment:12 Changed 11 years ago by jason

with "manipulate.patch", here is a trivial example. You *must* change the CELL_ID to the id of an existing cell. That cell will be overwritten.

manipulate("factor(y)", {'y': TextBox?(100)}, CELL_ID)

manipulate("factor(y)", {'y': Menu([2, 4, 6, 8])}, CELL_ID)

manipulate("factor(y)", {'y': ButtonGroup?([2, 4, 6, 8])}, CELL_ID)

manipulate("factor(y)", {'y': CheckBox?(checked=10, unchecked=20)}, CELL_ID)

manipulate("factor(p*y)", {'p': TextBox?(100), 'y': Menu([(x-1),x2-2*x+1])}, CELL_ID)

(Note to self: fix the bug of printing the menu using str instead of repr, so x2 looks like 2x)

Changed 11 years ago by jason

A different very rough cut of functionality.

comment:13 Changed 11 years ago by cwitty

Wow, this is a lot of fun!

Here's another, more interesting example. (This uses a CELL_ID of zero, so the first cell in your notebook will be overwritten.)

x = polygen(ZZ)
coeff_range = ButtonGroup([-4,-3,-2,-1,0,1,2,3,4])
manipulate("p = a*x^4 + b*x^3 + c*x^2 + d*x + e; show(plot(p, -4, 4)); show(p); p.roots(ring=RR)", 
           {'a': coeff_range,
            'b': coeff_range,
            'c': coeff_range,
            'd': coeff_range,
            'e': coeff_range}, 0)

Just judging from the functionality, I'd be willing to give a positive review once these two issues were addressed. (I haven't read the code yet, though.)

  1. Having to specify a CELL_ID is lame.
  1. The API of specifying a dictionary is bad. In the above example, the controls don't appear in the expected order (a,b,c,d,e); but that can't be fixed in manipulate, because it doesn't know what order you used when you typed the dictionary literal. Instead, manipulate should take a list of pairs.

Wishlist items:

  1. Slider bars would be nice.
  1. Widgets should be labeled with the variable name they control.
  1. The syntax is pretty ugly. I haven't thought of a way to fix that without some sort of preparser; here's a first suggestion for a preparser-based syntax:
    %manipulate
    x : Menu([2,4,6,8])
    y : Menu([1,10,100,1000])
    --
    x^y
    

For extra bonus points, this could work in conjunction with %pari/%magma/etc.

Changed 11 years ago by was

this is independent of the patches above -- it's standalone -- see comments below for how to use.

comment:14 Changed 11 years ago by was

This patch manipulate-take3.patch is a completely totally different approach to the whole manipulate thing. It is just a prototype!!! It's not supposed to work perfectly, in particular, you must enter a number first and press return to see anything. Anyway, here are some example inputs (each should be entered in its own cell):

@manipulate
def myfactor(n):
    print jsmath(factor(n))


@manipulate
def polys(m):
    R = QQ['x']
    f = R.random_element(m)
    print "f = ", jsmath(f)
    print "real roots = ", f.real_roots()
    show(plot(f))



@manipulate
def ellcurve(label):
    E = EllipticCurve(label)
    show(E)
    show("E conductor = %s"%E.conductor())
    show(E.q_eigenform(7))
    show(plot(E))



@manipulate
def pl(n):
    var('x,y')
    show(x^n-y^n)
    show(plot3d(x^n-y^n, (x,-2,2), (y,-2,2)))

comment:15 Changed 11 years ago by TimothyClemans

I love the new code by William.

Here is my first example using it:

@manipulate
def gcd_steps(numbers):
    a, b = numbers
    w = a
    y = b
    while True:
        x, z = divmod(w, y)
        print '%d = %d * %d + %d' % (w, x, y, z)
        if not z:
            break
        w = y
        y = z

Changed 11 years ago by was

part 2 of manipulate with decorators; this is usable again (probably) better docs; but there are several things to do soon and I'm too tired.

comment:16 Changed 11 years ago by was

Here is the patch that adds full jquery and uijquery support to sage. apply it against the extcode repo.

http://sage.math.washington.edu/home/was/patches/extcode-add_jquery_support.patch

comment:17 Changed 11 years ago by was

Examples of how to use the version as of now:

@manipulate
def foo(f=text_box("sin(x)"), L=slider(-5,0), U=slider(0,5)):
    return plot(f,L,U)
@manipulate
def bar(a,b=slider([1..10])):
    return a+b
@manipulate
def ec(a,b):
    E = EllipticCurve([a,b])
    html("<h1>Data about an Elliptic Curve</h1>")
    print E.cremona_label()
    show(E)
    show(plot(E))
    show(E.q_eigenform(30))
    show(E.torsion_order())

Changed 11 years ago by was

this requires that you also install the extcode patch that gives jquery support.

comment:18 Changed 11 years ago by was

Examples as of manipulate_take3_part3.patch

@manipulate
def factor_example(n=range(2,1000)):
    F = factor(n)
    html("<h1 align=center><font color='darkblue' size=+4>factor(%s) = %s</font></h1>"%(n, F))



@manipulate
def foo(f, xmax=[0,0.1,..20]):
    show(f)
    show(plot(f, -1, xmax))

@manipulate
def pl(n=[0..30], xmin=[-5..0], xmax=[0..10]):
    print n, xmin, xmax
    f = sin(n*x); g = cos(n*x)
    show(plot(f,xmin,xmax) + plot(g,xmin,xmax,color='red'), figsize=[5,2], xmin=xmin, xmax=xmax)


@manipulate
def pl(n=[100,200,..,10^4]):
    html("<h1 align=center>Primes up to %s</h1>"%n)
    show(plot(prime_pi, 1, n) + plot(x/(log(x)-1), 0.1, n, color='red'))


@manipulate
def a3dplot(a=[1..10], b=[1..10]):
    var('x,y')
    f = x^a + y^b
    show(f)
    show(plot3d(f, (x,-2,2), (y,-2,2)))

comment:19 Changed 11 years ago by was

HI: I've put a bundle at

http://sage.math.washington.edu/home/was/patches/manipulate.hg

since people were having trouble applying the plain text patches.

William

comment:20 Changed 11 years ago by was

To get this to work, install jquery as follows:

Get

http://sage.math.washington.edu/home/was/patches/jquery.tar.bz2

and unpack it in SAGE_ROOT

comment:21 Changed 11 years ago by was

Oops, actually extract

http://sage.math.washington.edu/home/was/patches/jquery.tar.bz2

in SAGE_ROOT/data/

Sorry for all the trouble.

comment:22 Changed 11 years ago by mhansen

  • Cc mhansen added

Changed 11 years ago by was

Changed 11 years ago by was

Changed 11 years ago by was

this is a new better version

comment:23 Changed 11 years ago by TimothyClemans

  • Cc TimothyClemans added

comment:24 Changed 11 years ago by was

  • Owner changed from boothby to was
  • Status changed from new to assigned
  • Summary changed from [with alpha patch] interactive widgets in the notebook to interact -- interactive functions in the notebook

I am now posting the hg bundle for people who want to try this out here:

http://sage.math.washington.edu/home/was/patches/interact.hg

comment:25 Changed 11 years ago by was

  • Description modified (diff)
  • Resolution set to duplicate
  • Status changed from assigned to closed
  • Summary changed from interact -- interactive functions in the notebook to interact -- interactive functions in the notebook (moved to #2449)
Note: See TracTickets for help on using tickets.