Merge pull request #4960 from ellisonbg/newinteract

Interact/Interactive for widget
pull/37/head
Brian E. Granger 12 years ago
commit 5904212460

@ -9,3 +9,4 @@ from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, In
from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
from .widget_selectioncontainer import TabWidget, AccordionWidget
from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
from .interaction import interact, interactive, fixed

@ -0,0 +1,251 @@
"""Interact with functions using widgets."""
#-----------------------------------------------------------------------------
# Copyright (c) 2013, the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function
try: # Python >= 3.3
from inspect import signature, Parameter
except ImportError:
from IPython.utils.signatures import signature, Parameter
from inspect import getcallargs
from IPython.html.widgets import (Widget, TextWidget,
FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
ContainerWidget, DOMWidget)
from IPython.display import display, clear_output
from IPython.utils.py3compat import string_types, unicode_type
from IPython.utils.traitlets import HasTraits, Any, Unicode
#-----------------------------------------------------------------------------
# Classes and Functions
#-----------------------------------------------------------------------------
def _matches(o, pattern):
"""Match a pattern of types in a sequence."""
if not len(o) == len(pattern):
return False
comps = zip(o,pattern)
return all(isinstance(obj,kind) for obj,kind in comps)
def _get_min_max_value(min, max, value=None, step=None):
"""Return min, max, value given input values with possible None."""
if value is None:
if not max > min:
raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
value = min + abs(min-max)/2
value = type(min)(value)
elif min is None and max is None:
if value == 0.0:
min, max, value = 0.0, 1.0, 0.5
elif value == 0:
min, max, value = 0, 1, 0
elif isinstance(value, (int, float)):
min, max = (-value, 3*value) if value > 0 else (3*value, -value)
else:
raise TypeError('expected a number, got: %r' % value)
else:
raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
if step is not None:
# ensure value is on a step
r = (value - min) % step
value = value - r
return min, max, value
def _widget_abbrev_single_value(o):
"""Make widgets from single values, which can be used as parameter defaults."""
if isinstance(o, string_types):
return TextWidget(value=unicode_type(o))
elif isinstance(o, dict):
return DropdownWidget(values=o)
elif isinstance(o, bool):
return CheckboxWidget(value=o)
elif isinstance(o, float):
min, max, value = _get_min_max_value(None, None, o)
return FloatSliderWidget(value=o, min=min, max=max)
elif isinstance(o, int):
min, max, value = _get_min_max_value(None, None, o)
return IntSliderWidget(value=o, min=min, max=max)
else:
return None
def _widget_abbrev(o):
"""Make widgets from abbreviations: single values, lists or tuples."""
float_or_int = (float, int)
if isinstance(o, (list, tuple)):
if o and all(isinstance(x, string_types) for x in o):
return DropdownWidget(values=[unicode_type(k) for k in o])
elif _matches(o, (float_or_int, float_or_int)):
min, max, value = _get_min_max_value(o[0], o[1])
if all(isinstance(_, int) for _ in o):
cls = IntSliderWidget
else:
cls = FloatSliderWidget
return cls(value=value, min=min, max=max)
elif _matches(o, (float_or_int, float_or_int, float_or_int)):
step = o[2]
if step <= 0:
raise ValueError("step must be >= 0, not %r" % step)
min, max, value = _get_min_max_value(o[0], o[1], step=step)
if all(isinstance(_, int) for _ in o):
cls = IntSliderWidget
else:
cls = FloatSliderWidget
return cls(value=value, min=min, max=max, step=step)
else:
return _widget_abbrev_single_value(o)
def _widget_from_abbrev(abbrev):
"""Build a Widget intstance given an abbreviation or Widget."""
if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
return abbrev
widget = _widget_abbrev(abbrev)
if widget is None:
raise ValueError("%r cannot be transformed to a Widget" % (abbrev,))
return widget
def _yield_abbreviations_for_parameter(param, kwargs):
"""Get an abbreviation for a function parameter."""
name = param.name
kind = param.kind
ann = param.annotation
default = param.default
empty = Parameter.empty
not_found = (None, None)
if kind == Parameter.POSITIONAL_OR_KEYWORD:
if name in kwargs:
yield name, kwargs.pop(name)
elif ann is not empty:
if default is empty:
yield name, ann
else:
yield name, ann
elif default is not empty:
yield name, default
else:
yield not_found
elif kind == Parameter.KEYWORD_ONLY:
if name in kwargs:
yield name, kwargs.pop(name)
elif ann is not empty:
yield name, ann
elif default is not empty:
yield name, default
else:
yield not_found
elif kind == Parameter.VAR_KEYWORD:
# In this case name=kwargs and we yield the items in kwargs with their keys.
for k, v in kwargs.copy().items():
kwargs.pop(k)
yield k, v
def _find_abbreviations(f, kwargs):
"""Find the abbreviations for a function and kwargs passed to interact."""
new_kwargs = []
for param in signature(f).parameters.values():
for name, value in _yield_abbreviations_for_parameter(param, kwargs):
if value is None:
raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
new_kwargs.append((name, value))
return new_kwargs
def _widgets_from_abbreviations(seq):
"""Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
result = []
for name, abbrev in seq:
widget = _widget_from_abbrev(abbrev)
widget.description = name
result.append(widget)
return result
def interactive(__interact_f, **kwargs):
"""Build a group of widgets to interact with a function."""
f = __interact_f
co = kwargs.pop('clear_output', True)
kwargs_widgets = []
container = ContainerWidget()
container.result = None
container.args = []
container.kwargs = dict()
kwargs = kwargs.copy()
new_kwargs = _find_abbreviations(f, kwargs)
# Before we proceed, let's make sure that the user has passed a set of args+kwargs
# that will lead to a valid call of the function. This protects against unspecified
# and doubly-specified arguments.
getcallargs(f, **{n:v for n,v in new_kwargs})
# Now build the widgets from the abbreviations.
kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
kwargs_widgets.extend(_widgets_from_abbreviations(sorted(kwargs.items(), key = lambda x: x[0])))
# This has to be done as an assignment, not using container.children.append,
# so that traitlets notices the update. We skip any objects (such as fixed) that
# are not DOMWidgets.
c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
container.children = c
# Build the callback
def call_f(name, old, new):
container.kwargs = {}
for widget in kwargs_widgets:
value = widget.value
container.kwargs[widget.description] = value
if co:
clear_output(wait=True)
container.result = f(**container.kwargs)
# Wire up the widgets
for widget in kwargs_widgets:
widget.on_trait_change(call_f, 'value')
container.on_displayed(lambda _: call_f(None, None, None))
return container
def interact(__interact_f=None, **kwargs):
"""interact(f, **kwargs)
Interact with a function using widgets."""
# positional arg support in: https://gist.github.com/8851331
if __interact_f is not None:
# This branch handles the cases:
# 1. interact(f, **kwargs)
# 2. @interact
# def f(*args, **kwargs):
# ...
f = __interact_f
w = interactive(f, **kwargs)
f.widget = w
display(w)
return f
else:
# This branch handles the case:
# @interact(a=30, b=40)
# def f(*args, **kwargs):
# ...
def dec(f):
w = interactive(f, **kwargs)
f.widget = w
display(w)
return f
return dec
class fixed(HasTraits):
"""A pseudo-widget whose value is fixed and never synced to the client."""
value = Any(help="Any Python object")
description = Unicode('', help="Any Python object")
def __init__(self, value, **kwargs):
super(fixed, self).__init__(value=value, **kwargs)

@ -0,0 +1,408 @@
"""Test interact and interactive."""
#-----------------------------------------------------------------------------
# Copyright (C) 2014 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function
from collections import OrderedDict
import nose.tools as nt
import IPython.testing.tools as tt
# from IPython.core.getipython import get_ipython
from IPython.html import widgets
from IPython.html.widgets import interact, interactive, Widget, interaction
from IPython.utils.py3compat import annotate
# from IPython.utils.capture import capture_output
#-----------------------------------------------------------------------------
# Utility stuff
#-----------------------------------------------------------------------------
class DummyComm(object):
comm_id = 'a-b-c-d'
def send(self, *args, **kwargs):
pass
def close(self, *args, **kwargs):
pass
_widget_attrs = {}
displayed = []
def setup():
_widget_attrs['comm'] = Widget.comm
Widget.comm = DummyComm()
_widget_attrs['_ipython_display_'] = Widget._ipython_display_
def raise_not_implemented(*args, **kwargs):
raise NotImplementedError()
Widget._ipython_display_ = raise_not_implemented
def teardown():
for attr, value in _widget_attrs.items():
setattr(Widget, attr, value)
def f(**kwargs):
pass
def clear_display():
global displayed
displayed = []
def record_display(*args):
displayed.extend(args)
#-----------------------------------------------------------------------------
# Actual tests
#-----------------------------------------------------------------------------
def check_widget(w, **d):
"""Check a single widget against a dict"""
for attr, expected in d.items():
if attr == 'cls':
nt.assert_is(w.__class__, expected)
else:
value = getattr(w, attr)
nt.assert_equal(value, expected,
"%s.%s = %r != %r" % (w.__class__.__name__, attr, value, expected)
)
def check_widgets(container, **to_check):
"""Check that widgets are created as expected"""
# build a widget dictionary, so it matches
widgets = {}
for w in container.children:
widgets[w.description] = w
for key, d in to_check.items():
nt.assert_in(key, widgets)
check_widget(widgets[key], **d)
def test_single_value_string():
a = u'hello'
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
cls=widgets.TextWidget,
description='a',
value=a,
)
def test_single_value_bool():
for a in (True, False):
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
cls=widgets.CheckboxWidget,
description='a',
value=a,
)
def test_single_value_dict():
for d in [
dict(a=5),
dict(a=5, b='b', c=dict),
]:
c = interactive(f, d=d)
w = c.children[0]
check_widget(w,
cls=widgets.DropdownWidget,
description='d',
values=d,
value=next(iter(d.values())),
)
def test_single_value_float():
for a in (2.25, 1.0, -3.5):
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
cls=widgets.FloatSliderWidget,
description='a',
value=a,
min= -a if a > 0 else 3*a,
max= 3*a if a > 0 else -a,
step=0.1,
readout=True,
)
def test_single_value_int():
for a in (1, 5, -3):
c = interactive(f, a=a)
nt.assert_equal(len(c.children), 1)
w = c.children[0]
check_widget(w,
cls=widgets.IntSliderWidget,
description='a',
value=a,
min= -a if a > 0 else 3*a,
max= 3*a if a > 0 else -a,
step=1,
readout=True,
)
def test_list_tuple_2_int():
with nt.assert_raises(ValueError):
c = interactive(f, tup=(1,1))
with nt.assert_raises(ValueError):
c = interactive(f, tup=(1,-1))
for min, max in [ (0,1), (1,10), (1,2), (-5,5), (-20,-19) ]:
c = interactive(f, tup=(min, max), lis=[min, max])
nt.assert_equal(len(c.children), 2)
d = dict(
cls=widgets.IntSliderWidget,
min=min,
max=max,
step=1,
readout=True,
)
check_widgets(c, tup=d, lis=d)
def test_list_tuple_3_int():
with nt.assert_raises(ValueError):
c = interactive(f, tup=(1,2,0))
with nt.assert_raises(ValueError):
c = interactive(f, tup=(1,2,-1))
for min, max, step in [ (0,2,1), (1,10,2), (1,100,2), (-5,5,4), (-100,-20,4) ]:
c = interactive(f, tup=(min, max, step), lis=[min, max, step])
nt.assert_equal(len(c.children), 2)
d = dict(
cls=widgets.IntSliderWidget,
min=min,
max=max,
step=step,
readout=True,
)
check_widgets(c, tup=d, lis=d)
def test_list_tuple_2_float():
with nt.assert_raises(ValueError):
c = interactive(f, tup=(1.0,1.0))
with nt.assert_raises(ValueError):
c = interactive(f, tup=(0.5,-0.5))
for min, max in [ (0.5, 1.5), (1.1,10.2), (1,2.2), (-5.,5), (-20,-19.) ]:
c = interactive(f, tup=(min, max), lis=[min, max])
nt.assert_equal(len(c.children), 2)
d = dict(
cls=widgets.FloatSliderWidget,
min=min,
max=max,
step=.1,
readout=True,
)
check_widgets(c, tup=d, lis=d)
def test_list_tuple_3_float():
with nt.assert_raises(ValueError):
c = interactive(f, tup=(1,2,0.0))
with nt.assert_raises(ValueError):
c = interactive(f, tup=(-1,-2,1.))
with nt.assert_raises(ValueError):
c = interactive(f, tup=(1,2.,-1.))
for min, max, step in [ (0.,2,1), (1,10.,2), (1,100,2.), (-5.,5.,4), (-100,-20.,4.) ]:
c = interactive(f, tup=(min, max, step), lis=[min, max, step])
nt.assert_equal(len(c.children), 2)
d = dict(
cls=widgets.FloatSliderWidget,
min=min,
max=max,
step=step,
readout=True,
)
check_widgets(c, tup=d, lis=d)
def test_list_tuple_str():
values = ['hello', 'there', 'guy']
first = values[0]
dvalues = OrderedDict((v,v) for v in values)
c = interactive(f, tup=tuple(values), lis=list(values))
nt.assert_equal(len(c.children), 2)
d = dict(
cls=widgets.DropdownWidget,
value=first,
values=dvalues
)
check_widgets(c, tup=d, lis=d)
def test_list_tuple_invalid():
for bad in [
(),
(5, 'hi'),
('hi', 5),
({},),
(None,),
]:
with nt.assert_raises(ValueError):
print(bad) # because there is no custom message in assert_raises
c = interactive(f, tup=bad)
def test_defaults():
@annotate(n=10)
def f(n, f=4.5):
pass
c = interactive(f)
check_widgets(c,
n=dict(
cls=widgets.IntSliderWidget,
value=10,
),
f=dict(
cls=widgets.FloatSliderWidget,
value=4.5,
),
)
def test_annotations():
@annotate(n=10, f=widgets.FloatTextWidget())
def f(n, f):
pass
c = interactive(f)
check_widgets(c,
n=dict(
cls=widgets.IntSliderWidget,
value=10,
),
f=dict(
cls=widgets.FloatTextWidget,
),
)
def test_priority():
@annotate(annotate='annotate', kwarg='annotate')
def f(kwarg='default', annotate='default', default='default'):
pass
c = interactive(f, kwarg='kwarg')
check_widgets(c,
kwarg=dict(
cls=widgets.TextWidget,
value='kwarg',
),
annotate=dict(
cls=widgets.TextWidget,
value='annotate',
),
)
@nt.with_setup(clear_display)
def test_decorator_kwarg():
with tt.monkeypatch(interaction, 'display', record_display):
@interact(a=5)
def foo(a):
pass
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
cls=widgets.IntSliderWidget,
value=5,
)
@nt.with_setup(clear_display)
def test_decorator_no_call():
with tt.monkeypatch(interaction, 'display', record_display):
@interact
def foo(a='default'):
pass
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
cls=widgets.TextWidget,
value='default',
)
@nt.with_setup(clear_display)
def test_call_interact():
def foo(a='default'):
pass
with tt.monkeypatch(interaction, 'display', record_display):
ifoo = interact(foo)
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
cls=widgets.TextWidget,
value='default',
)
@nt.with_setup(clear_display)
def test_call_interact_kwargs():
def foo(a='default'):
pass
with tt.monkeypatch(interaction, 'display', record_display):
ifoo = interact(foo, a=10)
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
cls=widgets.IntSliderWidget,
value=10,
)
@nt.with_setup(clear_display)
def test_call_decorated_on_trait_change():
"""test calling @interact decorated functions"""
d = {}
with tt.monkeypatch(interaction, 'display', record_display):
@interact
def foo(a='default'):
d['a'] = a
return a
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
cls=widgets.TextWidget,
value='default',
)
# test calling the function directly
a = foo('hello')
nt.assert_equal(a, 'hello')
nt.assert_equal(d['a'], 'hello')
# test that setting trait values calls the function
w.value = 'called'
nt.assert_equal(d['a'], 'called')
@nt.with_setup(clear_display)
def test_call_decorated_kwargs_on_trait_change():
"""test calling @interact(foo=bar) decorated functions"""
d = {}
with tt.monkeypatch(interaction, 'display', record_display):
@interact(a='kwarg')
def foo(a='default'):
d['a'] = a
return a
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
cls=widgets.TextWidget,
value='kwarg',
)
# test calling the function directly
a = foo('hello')
nt.assert_equal(a, 'hello')
nt.assert_equal(d['a'], 'hello')
# test that setting trait values calls the function
w.value = 'called'
nt.assert_equal(d['a'], 'called')
def test_fixed():
c = interactive(f, a=widgets.fixed(5), b='text')
nt.assert_equal(len(c.children), 1)
w = c.children[0]
check_widget(w,
cls=widgets.TextWidget,
value='text',
description='b',
)

@ -53,7 +53,7 @@ class FloatSliderWidget(_BoundedFloatWidget):
_view_name = Unicode('FloatSliderView', sync=True)
orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
help="Vertical or horizontal.", sync=True)
readout = Bool(False, help="Display the current value of the slider next to it.", sync=True)
readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
class FloatProgressWidget(_BoundedFloatWidget):

@ -53,7 +53,7 @@ class IntSliderWidget(_BoundedIntWidget):
_view_name = Unicode('IntSliderView', sync=True)
orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
help="Vertical or horizontal.", sync=True)
readout = Bool(False, help="Display the current value of the slider next to it.", sync=True)
readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
class IntProgressWidget(_BoundedIntWidget):

File diff suppressed because one or more lines are too long

@ -0,0 +1,269 @@
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Exploring the Lorenz System of Differential Equations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this Notebook we explore the Lorenz system of differential equations:\n",
"\n",
"$$\n",
"\\begin{aligned}\n",
"\\dot{x} & = \\sigma(y-x) \\\\\n",
"\\dot{y} & = \\rho x - y - xz \\\\\n",
"\\dot{z} & = -\\beta z + xy\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"This is one of the classic systems in non-linear differential equations. It exhibits a range of different behaviors as the parameters ($\\sigma$, $\\beta$, $\\rho$) are varied."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Imports"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, we import the needed things from IPython, NumPy, Matplotlib and SciPy."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%pylab inline"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.html.widgets.interact import interact, interactive\n",
"from IPython.display import clear_output, display, HTML"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import numpy as np\n",
"from scipy import integrate\n",
"\n",
"from matplotlib import pyplot as plt\n",
"from mpl_toolkits.mplot3d import Axes3D\n",
"from matplotlib.colors import cnames\n",
"from matplotlib import animation"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Computing the trajectories and plotting the result"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We define a function that can integrate the differential equations numerically and then plot the solutions. This function has arguments that control the parameters of the differential equation ($\\sigma$, $\\beta$, $\\rho$), the numerical integration (`N`, `max_time`) and the visualization (`angle`)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def solve_lorenz(N=10, angle=0.0, max_time=4.0, sigma=10.0, beta=8./3, rho=28.0):\n",
"\n",
" fig = plt.figure()\n",
" ax = fig.add_axes([0, 0, 1, 1], projection='3d')\n",
" ax.axis('off')\n",
"\n",
" # prepare the axes limits\n",
" ax.set_xlim((-25, 25))\n",
" ax.set_ylim((-35, 35))\n",
" ax.set_zlim((5, 55))\n",
" \n",
" def lorenz_deriv((x, y, z), t0, sigma=sigma, beta=beta, rho=rho):\n",
" \"\"\"Compute the time-derivative of a Lorentz system.\"\"\"\n",
" return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z]\n",
"\n",
" # Choose random starting points, uniformly distributed from -15 to 15\n",
" np.random.seed(1)\n",
" x0 = -15 + 30 * np.random.random((N, 3))\n",
"\n",
" # Solve for the trajectories\n",
" t = np.linspace(0, max_time, int(250*max_time))\n",
" x_t = np.asarray([integrate.odeint(lorenz_deriv, x0i, t)\n",
" for x0i in x0])\n",
" \n",
" # choose a different color for each trajectory\n",
" colors = plt.cm.jet(np.linspace(0, 1, N))\n",
"\n",
" for i in range(N):\n",
" x, y, z = x_t[i,:,:].T\n",
" lines = ax.plot(x, y, z, '-', c=colors[i])\n",
" setp(lines, linewidth=2)\n",
"\n",
" ax.view_init(30, angle)\n",
" show()\n",
"\n",
" return t, x_t"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's call the function once to view the solutions. For this set of parameters, we see the trajectories swirling around two points, called attractors. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"t, x_t = solve_lorenz(angle=0, N=10)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using IPython's `interactive` function, we can explore how the trajectories behave as we change the various parameters."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"w = interactive(solve_lorenz, angle=(0.,360.), N=(0,50), sigma=(0.0,50.0), rho=(0.0,50.0))\n",
"display(w)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The object returned by `interactive` is a `Widget` object and it has attributes that contain the current result and arguments:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"t, x_t = w.result"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"w.arguments"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After interacting with the system, we can take the result and perform further computations. In this case, we compute the average positions in $x$, $y$ and $z$."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"xyz_avg = x_t.mean(axis=1)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"xyz_avg.shape"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Creating histograms of the average positions (across different trajectories) show that on average the trajectories swirl about the attractors."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"hist(xyz_avg[:,0])\n",
"title('Average $x(t)$')"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"hist(xyz_avg[:,1])\n",
"title('Average $y(t)$')"
],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Loading…
Cancel
Save