##// END OF EJS Templates
s/const/fixed/
MinRK -
Show More
@@ -1,12 +1,12 b''
1 1 from .widget import Widget, DOMWidget, CallbackDispatcher
2 2
3 3 from .widget_bool import CheckboxWidget, ToggleButtonWidget
4 4 from .widget_button import ButtonWidget
5 5 from .widget_container import ContainerWidget, PopupWidget
6 6 from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
7 7 from .widget_image import ImageWidget
8 8 from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
9 9 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
10 10 from .widget_selectioncontainer import TabWidget, AccordionWidget
11 11 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
12 from .interaction import interact, interactive, const
12 from .interaction import interact, interactive, fixed
@@ -1,248 +1,248 b''
1 1 """Interact with functions using widgets."""
2 2
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2013, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 from __future__ import print_function
16 16
17 17 try: # Python >= 3.3
18 18 from inspect import signature, Parameter
19 19 except ImportError:
20 20 from IPython.utils.signatures import signature, Parameter
21 21 from inspect import getcallargs
22 22
23 23 from IPython.html.widgets import (Widget, TextWidget,
24 24 FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
25 25 ContainerWidget, DOMWidget)
26 26 from IPython.display import display, clear_output
27 27 from IPython.utils.py3compat import string_types, unicode_type
28 28 from IPython.utils.traitlets import HasTraits, Any, Unicode
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Classes and Functions
32 32 #-----------------------------------------------------------------------------
33 33
34 34
35 35 def _matches(o, pattern):
36 36 """Match a pattern of types in a sequence."""
37 37 if not len(o) == len(pattern):
38 38 return False
39 39 comps = zip(o,pattern)
40 40 return all(isinstance(obj,kind) for obj,kind in comps)
41 41
42 42
43 43 def _get_min_max_value(min, max, value):
44 44 """Return min, max, value given input values with possible None."""
45 45 if value is None:
46 46 if not max > min:
47 47 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
48 48 value = min + abs(min-max)/2
49 49 value = type(min)(value)
50 50 elif min is None and max is None:
51 51 if value == 0.0:
52 52 min, max, value = 0.0, 1.0, 0.5
53 53 elif value == 0:
54 54 min, max, value = 0, 1, 0
55 55 elif isinstance(value, float):
56 56 min, max = (-value, 3.0*value) if value > 0 else (3.0*value, -value)
57 57 elif isinstance(value, int):
58 58 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
59 59 else:
60 60 raise TypeError('expected a number, got: %r' % value)
61 61 else:
62 62 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
63 63 return min, max, value
64 64
65 65 def _widget_abbrev_single_value(o):
66 66 """Make widgets from single values, which can be used written as parameter defaults."""
67 67 if isinstance(o, string_types):
68 68 return TextWidget(value=unicode_type(o))
69 69 elif isinstance(o, dict):
70 70 # get a single value in a Python 2+3 way:
71 71 value = next(iter(o.values()))
72 72 return DropdownWidget(value=value, values=o)
73 73 elif isinstance(o, bool):
74 74 return CheckboxWidget(value=o)
75 75 elif isinstance(o, float):
76 76 min, max, value = _get_min_max_value(None, None, o)
77 77 return FloatSliderWidget(value=o, min=min, max=max)
78 78 elif isinstance(o, int):
79 79 min, max, value = _get_min_max_value(None, None, o)
80 80 return IntSliderWidget(value=o, min=min, max=max)
81 81 else:
82 82 return None
83 83
84 84 def _widget_abbrev(o):
85 85 """Make widgets from abbreviations: single values, lists or tuples."""
86 86 if isinstance(o, (list, tuple)):
87 87 if _matches(o, (int, int)):
88 88 min, max, value = _get_min_max_value(o[0], o[1], None)
89 89 return IntSliderWidget(value=value, min=min, max=max)
90 90 elif _matches(o, (int, int, int)):
91 91 min, max, value = _get_min_max_value(o[0], o[1], None)
92 92 return IntSliderWidget(value=value, min=min, max=max, step=o[2])
93 93 elif _matches(o, (float, float)):
94 94 min, max, value = _get_min_max_value(o[0], o[1], None)
95 95 return FloatSliderWidget(value=value, min=min, max=max)
96 96 elif _matches(o, (float, float, float)):
97 97 min, max, value = _get_min_max_value(o[0], o[1], None)
98 98 return FloatSliderWidget(value=value, min=min, max=max, step=o[2])
99 99 elif _matches(o, (float, float, int)):
100 100 min, max, value = _get_min_max_value(o[0], o[1], None)
101 101 return FloatSliderWidget(value=value, min=min, max=max, step=float(o[2]))
102 102 elif all(isinstance(x, string_types) for x in o):
103 103 return DropdownWidget(value=unicode_type(o[0]),
104 104 values=[unicode_type(k) for k in o])
105 105 else:
106 106 return _widget_abbrev_single_value(o)
107 107
108 108 def _widget_from_abbrev(abbrev):
109 109 """Build a Widget intstance given an abbreviation or Widget."""
110 if isinstance(abbrev, Widget) or isinstance(abbrev, const):
110 if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
111 111 return abbrev
112 112
113 113 widget = _widget_abbrev(abbrev)
114 114 if widget is None:
115 115 raise ValueError("%r cannot be transformed to a Widget" % abbrev)
116 116 return widget
117 117
118 118 def _yield_abbreviations_for_parameter(param, kwargs):
119 119 """Get an abbreviation for a function parameter."""
120 120 name = param.name
121 121 kind = param.kind
122 122 ann = param.annotation
123 123 default = param.default
124 124 empty = Parameter.empty
125 125 not_found = (None, None)
126 126 if kind == Parameter.POSITIONAL_OR_KEYWORD:
127 127 if name in kwargs:
128 128 yield name, kwargs.pop(name)
129 129 elif ann is not empty:
130 130 if default is empty:
131 131 yield name, ann
132 132 else:
133 133 yield name, ann
134 134 elif default is not empty:
135 135 yield name, default
136 136 else:
137 137 yield not_found
138 138 elif kind == Parameter.KEYWORD_ONLY:
139 139 if name in kwargs:
140 140 yield name, kwargs.pop(name)
141 141 elif ann is not empty:
142 142 yield name, ann
143 143 elif default is not empty:
144 144 yield name, default
145 145 else:
146 146 yield not_found
147 147 elif kind == Parameter.VAR_KEYWORD:
148 148 # In this case name=kwargs and we yield the items in kwargs with their keys.
149 149 for k, v in kwargs.copy().items():
150 150 kwargs.pop(k)
151 151 yield k, v
152 152
153 153 def _find_abbreviations(f, kwargs):
154 154 """Find the abbreviations for a function and kwargs passed to interact."""
155 155 new_kwargs = []
156 156 for param in signature(f).parameters.values():
157 157 for name, value in _yield_abbreviations_for_parameter(param, kwargs):
158 158 if value is None:
159 159 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
160 160 new_kwargs.append((name, value))
161 161 return new_kwargs
162 162
163 163 def _widgets_from_abbreviations(seq):
164 164 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
165 165 result = []
166 166 for name, abbrev in seq:
167 167 widget = _widget_from_abbrev(abbrev)
168 168 widget.description = name
169 169 result.append(widget)
170 170 return result
171 171
172 172 def interactive(__interact_f, **kwargs):
173 173 """Build a group of widgets to interact with a function."""
174 174 f = __interact_f
175 175 co = kwargs.pop('clear_output', True)
176 176 kwargs_widgets = []
177 177 container = ContainerWidget()
178 178 container.result = None
179 179 container.args = []
180 180 container.kwargs = dict()
181 181 kwargs = kwargs.copy()
182 182
183 183 new_kwargs = _find_abbreviations(f, kwargs)
184 184 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
185 185 # that will lead to a valid call of the function. This protects against unspecified
186 186 # and doubly-specified arguments.
187 187 getcallargs(f, **{n:v for n,v in new_kwargs})
188 188 # Now build the widgets from the abbreviations.
189 189 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
190 190 kwargs_widgets.extend(_widgets_from_abbreviations(sorted(kwargs.items(), key = lambda x: x[0])))
191 191
192 192 # This has to be done as an assignment, not using container.children.append,
193 # so that traitlets notices the update. We skip any objects (such as const) that
193 # so that traitlets notices the update. We skip any objects (such as fixed) that
194 194 # are not DOMWidgets.
195 195 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
196 196 container.children = c
197 197
198 198 # Build the callback
199 199 def call_f(name, old, new):
200 200 container.args = []
201 201 for widget in kwargs_widgets:
202 202 value = widget.value
203 203 container.kwargs[widget.description] = value
204 204 if co:
205 205 clear_output(wait=True)
206 206 container.result = f(*container.args, **container.kwargs)
207 207
208 208 # Wire up the widgets
209 209 for widget in kwargs_widgets:
210 210 widget.on_trait_change(call_f, 'value')
211 211
212 212 container.on_displayed(lambda _: call_f(None, None, None))
213 213
214 214 return container
215 215
216 216 def interact(__interact_f=None, **kwargs):
217 217 """interact(f, **kwargs)
218 218
219 219 Interact with a function using widgets."""
220 220 # positional arg support in: https://gist.github.com/8851331
221 221 if __interact_f is not None:
222 222 # This branch handles the cases:
223 223 # 1. interact(f, **kwargs)
224 224 # 2. @interact
225 225 # def f(*args, **kwargs):
226 226 # ...
227 227 f = __interact_f
228 228 w = interactive(f, **kwargs)
229 229 f.widget = w
230 230 display(w)
231 231 else:
232 232 # This branch handles the case:
233 233 # @interact(a=30, b=40)
234 234 # def f(*args, **kwargs):
235 235 # ...
236 236 def dec(f):
237 237 w = interactive(f, **kwargs)
238 238 f.widget = w
239 239 display(w)
240 240 return f
241 241 return dec
242 242
243 class const(HasTraits):
244 """A pseudo-widget whose value is constant and never client synced."""
243 class fixed(HasTraits):
244 """A pseudo-widget whose value is fixed and never synced to the client."""
245 245 value = Any(help="Any Python object")
246 246 description = Unicode('', help="Any Python object")
247 247 def __init__(self, value, **kwargs):
248 super(const, self).__init__(value=value, **kwargs)
248 super(fixed, self).__init__(value=value, **kwargs)
General Comments 0
You need to be logged in to leave comments. Login now