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