##// END OF EJS Templates
Adding .widget to function.
Brian E. Granger -
Show More
@@ -1,138 +1,139 b''
1 """Interact with functions using widgets.
1 """Interact with functions using widgets.
2 """
2 """
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.html.widgets import (Widget, TextWidget,
16 from IPython.html.widgets import (Widget, TextWidget,
17 FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
17 FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
18 ContainerWidget)
18 ContainerWidget)
19 from IPython.display import display, clear_output
19 from IPython.display import display, clear_output
20 from IPython.utils.py3compat import string_types, unicode_type
20 from IPython.utils.py3compat import string_types, unicode_type
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Classes and Functions
23 # Classes and Functions
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 def _matches(o, pattern):
27 def _matches(o, pattern):
28 if not len(o) == len(pattern):
28 if not len(o) == len(pattern):
29 return False
29 return False
30 comps = zip(o,pattern)
30 comps = zip(o,pattern)
31 return all(isinstance(obj,kind) for obj,kind in comps)
31 return all(isinstance(obj,kind) for obj,kind in comps)
32
32
33
33
34 def _get_min_max_value(min, max, value):
34 def _get_min_max_value(min, max, value):
35 """Return min, max, value given input values with possible None."""
35 """Return min, max, value given input values with possible None."""
36 if value is None:
36 if value is None:
37 if not max > min:
37 if not max > min:
38 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
38 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
39 value = min + abs(min-max)/2
39 value = min + abs(min-max)/2
40 value = type(min)(value)
40 value = type(min)(value)
41 elif min is None and max is None:
41 elif min is None and max is None:
42 if value == 0.0:
42 if value == 0.0:
43 min, max, value = 0.0, 1.0, 0.5
43 min, max, value = 0.0, 1.0, 0.5
44 elif value == 0:
44 elif value == 0:
45 min, max, value = 0, 1, 0
45 min, max, value = 0, 1, 0
46 elif isinstance(value, float):
46 elif isinstance(value, float):
47 min, max = -value, 3.0*value
47 min, max = -value, 3.0*value
48 elif isinstance(value, int):
48 elif isinstance(value, int):
49 min, max = -value, 3*value
49 min, max = -value, 3*value
50 else:
50 else:
51 raise TypeError('expected a number, got: %r' % number)
51 raise TypeError('expected a number, got: %r' % number)
52 else:
52 else:
53 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
53 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
54 return min, max, value
54 return min, max, value
55
55
56
56
57 def _widget_abbrev(o):
57 def _widget_abbrev(o):
58 if isinstance(o, string_types):
58 if isinstance(o, string_types):
59 return TextWidget(value=unicode_type(o))
59 return TextWidget(value=unicode_type(o))
60 elif isinstance(o, dict):
60 elif isinstance(o, dict):
61 labels = [unicode_type(k) for k in o]
61 labels = [unicode_type(k) for k in o]
62 values = o.values()
62 values = o.values()
63 w = DropdownWidget(value=values[0], values=values, labels=labels)
63 w = DropdownWidget(value=values[0], values=values, labels=labels)
64 return w
64 return w
65 # Special case float and int == 0.0
65 # Special case float and int == 0.0
66 # get_range(value):
66 # get_range(value):
67 elif isinstance(o, bool):
67 elif isinstance(o, bool):
68 return CheckboxWidget(value=o)
68 return CheckboxWidget(value=o)
69 elif isinstance(o, float):
69 elif isinstance(o, float):
70 min, max, value = _get_min_max_value(None, None, o)
70 min, max, value = _get_min_max_value(None, None, o)
71 return FloatSliderWidget(value=o, min=min, max=max)
71 return FloatSliderWidget(value=o, min=min, max=max)
72 elif isinstance(o, int):
72 elif isinstance(o, int):
73 min, max, value = _get_min_max_value(None, None, o)
73 min, max, value = _get_min_max_value(None, None, o)
74 return IntSliderWidget(value=o, min=min, max=max)
74 return IntSliderWidget(value=o, min=min, max=max)
75 if isinstance(o, (list, tuple)):
75 if isinstance(o, (list, tuple)):
76 if _matches(o, (int, int)):
76 if _matches(o, (int, int)):
77 min, max, value = _get_min_max_value(o[0], o[1], None)
77 min, max, value = _get_min_max_value(o[0], o[1], None)
78 return IntSliderWidget(value=value, min=min, max=max)
78 return IntSliderWidget(value=value, min=min, max=max)
79 elif _matches(o, (int, int, int)):
79 elif _matches(o, (int, int, int)):
80 min, max, value = _get_min_max_value(o[0], o[1], None)
80 min, max, value = _get_min_max_value(o[0], o[1], None)
81 return IntSliderWidget(value=value, min=min, max=max, step=o[2])
81 return IntSliderWidget(value=value, min=min, max=max, step=o[2])
82 elif _matches(o, (float, float)):
82 elif _matches(o, (float, float)):
83 min, max, value = _get_min_max_value(o[0], o[1], None)
83 min, max, value = _get_min_max_value(o[0], o[1], None)
84 return FloatSliderWidget(value=value, min=min, max=max)
84 return FloatSliderWidget(value=value, min=min, max=max)
85 elif _matches(o, (float, float, float)):
85 elif _matches(o, (float, float, float)):
86 min, max, value = _get_min_max_value(o[0], o[1], None)
86 min, max, value = _get_min_max_value(o[0], o[1], None)
87 return FloatSliderWidget(value=value, min=min, max=max, step=o[2])
87 return FloatSliderWidget(value=value, min=min, max=max, step=o[2])
88 elif _matches(o, (float, float, int)):
88 elif _matches(o, (float, float, int)):
89 min, max, value = _get_min_max_value(o[0], o[1], None)
89 min, max, value = _get_min_max_value(o[0], o[1], None)
90 return FloatSliderWidget(value=value, min=min, max=max, step=float(o[2]))
90 return FloatSliderWidget(value=value, min=min, max=max, step=float(o[2]))
91 elif all(isinstance(x, string_types) for x in o):
91 elif all(isinstance(x, string_types) for x in o):
92 return DropdownWidget(value=unicode_type(o[0]),
92 return DropdownWidget(value=unicode_type(o[0]),
93 values=[unicode_type(k) for k in o])
93 values=[unicode_type(k) for k in o])
94
94
95
95
96 def interactive(f, **kwargs):
96 def interactive(f, **kwargs):
97 """Interact with a function using widgets."""
97 """Interact with a function using widgets."""
98
98
99 co = kwargs.pop('clear_output', True)
99 co = kwargs.pop('clear_output', True)
100 # First convert all args to Widget instances
100 # First convert all args to Widget instances
101 widgets = []
101 widgets = []
102 container = ContainerWidget()
102 container = ContainerWidget()
103 container.result = None
103 container.result = None
104 container.kwargs = dict()
104 container.kwargs = dict()
105 for key, value in kwargs.items():
105 for key, value in kwargs.items():
106 if isinstance(value, Widget):
106 if isinstance(value, Widget):
107 widget = value
107 widget = value
108 else:
108 else:
109 widget = _widget_abbrev(value)
109 widget = _widget_abbrev(value)
110 if widget is None:
110 if widget is None:
111 raise ValueError("Object cannot be transformed to a Widget")
111 raise ValueError("Object cannot be transformed to a Widget")
112 widget.description = key
112 widget.description = key
113 widgets.append((key,widget))
113 widgets.append((key,widget))
114 widgets.sort(key=lambda e: e[1].__class__.__name__)
114 widgets.sort(key=lambda e: e[1].__class__.__name__)
115 container.children = [e[1] for e in widgets]
115 container.children = [e[1] for e in widgets]
116
116
117 # Build the callback
117 # Build the callback
118 def call_f(name, old, new):
118 def call_f(name, old, new):
119 actual_kwargs = {}
119 actual_kwargs = {}
120 for key, widget in widgets:
120 for key, widget in widgets:
121 value = widget.value
121 value = widget.value
122 container.kwargs[key] = value
122 container.kwargs[key] = value
123 actual_kwargs[key] = value
123 actual_kwargs[key] = value
124 if co:
124 if co:
125 clear_output(wait=True)
125 clear_output(wait=True)
126 container.result = f(**actual_kwargs)
126 container.result = f(**actual_kwargs)
127
127
128 # Wire up the widgets
128 # Wire up the widgets
129 for key, widget in widgets:
129 for key, widget in widgets:
130 widget.on_trait_change(call_f, 'value')
130 widget.on_trait_change(call_f, 'value')
131
131
132 container.on_displayed(lambda _: call_f(None, None, None))
132 container.on_displayed(lambda _: call_f(None, None, None))
133
133
134 return container
134 return container
135
135
136 def interact(f, **kwargs):
136 def interact(f, **kwargs):
137 w = interactive(f, **kwargs)
137 w = interactive(f, **kwargs)
138 f.widget = w
138 display(w)
139 display(w)
General Comments 0
You need to be logged in to leave comments. Login now