This Sage worksheet was developed for the MAA PREP Workshop "Sage: Using Open-Source Mathematics Software with Undergraduates" (funding provided by NSF DUE 0817071).
Invaluable resources are the Sage wiki http://wiki.sagemath.org/interact (type "sage interact" into Google) and the interact documentation, as well as http://interact.sagemath.org.
{{{id=43| /// }}}
Start by getting the commands for what you want the output to look like. Here we just want a simple plot.
{{{id=27| plot(x^2,(x,-3,3)) ///Then abstract out the parts you want to change. We'll be letting the user change the function, so let's make that a variable $f$.
{{{id=28| f=x^3 plot(f,(x,-3,3)) ///Now make this a "def" function. The "show" or "print" is needed since the output is not automatically printed from within a function. Note also that we give the variable a default value of x^2. This is what $f$ is if the user does not specify a value for $f$.
{{{id=29| def myplot(f=x^2): show(plot(f,(x,-3,3))) /// }}}Let's test the def function myplot by just calling it.
{{{id=30| myplot() ///If we call it with a different value for f, we should get a different plot.
{{{id=32| myplot(f=x^3) ///Now to make a control to enter the function, we just preface the function with @interact.
{{{id=35| @interact def myplot(f=x^2): show(plot(f,(x,-3,3))) /// }}}Tech tip: Technically what the @interact does is wrap the function, so the above is equivalent to:
def myplot(..): ...
myplot=interact(myplot)
{{{id=54| /// }}}Note that we can still call our function, even when we've used @interact. This is often useful in debugging it.
{{{id=51| myplot(x^4) ///We can go ahead and replace other parts of the expression with variables. Note the "_" is the function name now. That is a convention for throw-away names that we don't care about.
{{{id=15| @interact def g(f=x^2,a=-3,b=3): show(plot(f,(x,a,b))) /// }}} {{{id=59| g(x^3,a=2) ///If we pass ('label', default_value) in for a control, then the control gets the label when printed.
{{{id=56| @interact def _(f=('$f$',x^2),a=('lower',-3),b=('upper',3)): show(plot(f,(x,a,b))) /// }}}We can specify the type of control explicitly, along with options.
{{{id=79| input_box? ///File: /home/sageserver/sage-5.0.1/devel/sagenb/sagenb/notebook/interact.py
Type: <type ‘classobj’>
Definition: input_box( [noargspec] )
Docstring:
An input box interactive control. Use this in conjunction with the interact() command.
INPUT:
- default - an object; the default put in this input box
- label - a string; the label rendered to the left of the box.
- type - a type; coerce inputs to this; this doesn’t have to be an actual type, since anything callable will do.
- height - an integer (default: 1); the number of rows. If greater than 1 a value won’t be returned until something outside the textarea is clicked.
- width - an integer; width of text box in characters
- kwargs - a dictionary; additional keyword options
EXAMPLES:
sage: input_box("2+2", 'expression') Interact input box labeled 'expression' with default value '2+2' sage: input_box('sage', label="Enter your name", type=str) Interact input box labeled 'Enter your name' with default value 'sage' sage: input_box('Multiline\nInput',label='Click to change value',type=str,height=5) Interact input box labeled 'Click to change value' with default value 'Multiline\nInput'
Here's another type of control: a color picker.
{{{id=81| color_selector? ///File: /home/sageserver/sage-5.0.1/devel/sagenb/sagenb/notebook/interact.py
Type: <type ‘classobj’>
Definition: color_selector( [noargspec] )
Docstring:
A color selector (also called a color chooser, picker, or tool) interactive control. Use this with the interact() command.
INPUT:
- default - an instance of or valid constructor argument to Color (default: (0,0,1)); the selector’s default color; a string argument must be a valid color name (e.g., ‘red’) or HTML hex color (e.g., ‘#abcdef’)
- label - a string (default: None); the label rendered to the left of the selector.
- widget - a string (default: ‘jpicker’); the color selector widget to use; choices are ‘colorpicker’, ‘jpicker’ and ‘farbtastic’
- hide_box - a boolean (default: False); whether to hide the input box associated with the color selector widget
EXAMPLES:
sage: color_selector() Interact color selector labeled None, with default RGB color (0.0, 0.0, 1.0), widget 'jpicker', and visible input box sage: color_selector((0.5, 0.5, 1.0), widget='jpicker') Interact color selector labeled None, with default RGB color (0.5, 0.5, 1.0), widget 'jpicker', and visible input box sage: color_selector(default = Color(0, 0.5, 0.25)) Interact color selector labeled None, with default RGB color (0.0, 0.5, 0.25), widget 'jpicker', and visible input box sage: color_selector('purple', widget = 'colorpicker') Interact color selector labeled None, with default RGB color (0.50..., 0.0, 0.50...), widget 'colorpicker', and visible input box sage: color_selector('crayon', widget = 'colorpicker') Traceback (most recent call last): ... ValueError: unknown color 'crayon' sage: color_selector('#abcdef', label='height', widget='jpicker') Interact color selector labeled 'height', with default RGB color (0.6..., 0.8..., 0.9...), widget 'jpicker', and visible input box sage: color_selector('abcdef', label='height', widget='jpicker') Traceback (most recent call last): ... ValueError: unknown color 'abcdef'
Here are a bunch of options. Notice the new controls:
That was a bit ugly because all of the controls were stacked on top of each other. We can layout the controls in a grid in the top, bottom, left, or right using the 'layout' parameter.
{{{id=24| @interact(layout=dict(top=[['f', 'color']], left=[['axes'],['fill']], bottom=[['zoom']])) def _(f=input_box(x^2,width=20), color=color_selector(widget='colorpicker', label=""), axes=True, fill=True, zoom=range_slider(-3,3, default=(-3,3))): show(plot(f,(x,zoom[0], zoom[1]), color=color, axes=axes,fill=fill)) /// }}}Sage has:
We illustrate some of these.
{{{id=9| @interact def _(frame=checkbox(True, label='Use frame')): show(plot(sin(x), (x,-5,5)), frame=frame) /// }}} {{{id=10| var('x,y') colormaps=sage.plot.colors.colormaps.keys() @interact def _(cmap=selector(colormaps)): contour_plot(x^2-y^2,(x,-2,2),(y,-2,2),cmap=cmap).show() /// }}} {{{id=13| var('x,y') colormaps=sage.plot.colors.colormaps.keys() @interact def _(cmap=selector(['RdBu', 'jet', 'gray','gray_r'],buttons=True), type=['density','contour']): if type=='contour': contour_plot(x^2-y^2,(x,-2,2),(y,-2,2),cmap=cmap, aspect_ratio=1).show() else: density_plot(x^2-y^2,(x,-2,2),(y,-2,2),cmap=cmap, frame=True,axes=False,aspect_ratio=1).show() /// }}} {{{id=65| /// }}}By default, ranges are sliders that divide the range into 500 steps (I think that's the right number...)
{{{id=33| @interact def _(n=(1,20)): print factorial(n) /// }}}You can set the step size to get, for example, just integer values.
{{{id=42| @interact def _(n=slider(1,20,step_size=1)): print factorial(n) /// }}}Or you can explicitly specify the slider values.
{{{id=40| @interact def _(n=slider([1..20])): print factorial(n) /// }}}And the slider values don't even have to be numbers!
{{{id=41| @interact def _(fun=('function', slider([sin,cos,tan,sec,csc,cot]))): print fun(4.39293) /// }}} {{{id=72| /// }}}Matrices are automatically converted to a grid of input boxes.
{{{id=71| @interact def _(m=('matrix', identity_matrix(2))): print m.eigenvalues() /// }}}Here's how to get vectors from a grid of boxes.
{{{id=69| @interact def _(v=('vector', input_grid(1, 3, default=[[1,2,3]], to_value=lambda x: vector(flatten(x))))): print v.norm() /// }}}Sometimes we don't want any updates until we specifically say so. We can use the auto_update=False option for that.
{{{id=76| @interact def _(m=('matrix', identity_matrix(2)), auto_update=False): print m.eigenvalues() /// }}} {{{id=78| /// }}}