Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2@file
3@brief To add interactive widgets in a notebook and connect it to Python function,
4Source: https://github.com/jakevdp/ipywidgets, the module was modified for Python 3
5See notebook :ref:`havingaforminanotebookrst`.
7Copyright (c) 2013, Jake Vanderplas
8All rights reserved.
10Redistribution and use in source and binary forms, with or without modification,
11are permitted provided that the following conditions are met:
13* Redistributions of source code must retain the above copyright notice, this
14 list of conditions and the following disclaimer.
16* Redistributions in binary form must reproduce the above copyright notice, this
17 list of conditions and the following disclaimer in the documentation and/or
18 other materials provided with the distribution.
20* Neither the name of the {organization} nor the names of its
21 contributors may be used to endorse or promote products derived from
22 this software without specific prior written permission.
24THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34"""
36import copy
39class StaticWidget(object):
41 """
42 Base Class for Static Widgets
43 """
45 def __init__(self, name=None, divclass=None):
46 """
47 constructor
49 @param name name
50 @param divclass class for div section
51 """
52 self.name = name
53 if divclass is None:
54 self.divargs = ""
55 else:
56 self.divargs = 'class:"{0}"'.format(divclass)
58 def __repr__(self):
59 """
60 operator, call method html
61 """
62 return self.html()
64 def _repr_html_(self):
65 """
66 operator, call method html
67 """
68 return self.html()
70 def html(self):
71 "abstract method"
72 raise NotImplementedError( # pragma: no cover
73 "This should overriden.")
75 def copy(self):
76 """
77 calls deepcopy
79 @return copy of self
80 """
81 return copy.deepcopy(self)
83 def renamed(self, name):
84 """
85 rename *name* if *name* is an attribute
87 @return object
88 """
89 if (self.name is not None) and (self.name != name):
90 obj = self.copy()
91 else:
92 obj = self
93 obj.name = name
94 return obj
97class RangeWidget(StaticWidget):
99 """
100 Range (slider) widget
102 The class overloads :meth:`html <pyquickhelper.ipythonhelper.widgets.RangeWidget.html>`
103 and :meth:`values <pyquickhelper.ipythonhelper.widgets.RangeWidget.values>`.
104 """
105 slider_html = ('<b>{name}:</b> <input type="range" name="{name}" '
106 'min="{range[0]}" max="{range[1]}" step="{range[2]}" '
107 'value="{default}" style="{style}" '
108 'oninput="interactUpdate(this.parentNode);" '
109 'onchange="interactUpdate(this.parentNode);">')
111 def __init__(self, min, max, step=1, name=None,
112 default=None, width=350, divclass=None,
113 show_range=False):
114 """
115 @param min min value
116 @param max max value
117 @param step step
118 @param name name
119 @param default default value
120 @param width width in pixel
121 @param divclass class for div section
122 @param show_range boolean
123 """
124 StaticWidget.__init__(self, name, divclass)
125 self.datarange = (min, max, step)
126 self.width = width
127 self.show_range = show_range
128 if default is None:
129 self.default = min
130 else:
131 self.default = default
133 def values(self):
134 """
135 @return all possible values
136 """
137 min, max, step = self.datarange
138 import numpy as np
139 return np.arange(min, max + step, step)
141 def html(self):
142 """
143 HTML code
145 @return string HTML
146 """
147 style = ""
149 if self.width is not None:
150 style += "width:{0}px".format(self.width)
152 output = self.slider_html.format(name=self.name, range=self.datarange,
153 default=self.default, style=style)
154 if self.show_range:
155 output = "{0} {1} {2}".format(self.datarange[0],
156 output,
157 self.datarange[1])
158 return output
161class DropDownWidget(StaticWidget):
163 """
164 drop down list
165 """
167 #: template 1
168 select_html = ('<b>{name}:</b> <select name="{name}" '
169 'onchange="interactUpdate(this.parentNode);"> '
170 '{options}'
171 '</select>'
172 )
174 #: template 2
175 option_html = ('<option value="{value}" '
176 '{selected}>{label}</option>')
178 def __init__(self, values, name=None,
179 labels=None, default=None, divclass=None,
180 delimiter=" "):
181 """
182 @param values values for the list
183 @param name name of the object
184 @param labels ?
185 @param default default value
186 @param divclass class for div section
187 @param delimiter delimiter
188 """
189 StaticWidget.__init__(self, name, divclass)
190 self._values = values
191 self.delimiter = delimiter
192 if labels is None:
193 labels = map(str, values)
194 elif len(labels) != len(values):
195 raise ValueError("length of labels must match length of values")
196 self.labels = labels
198 if default is None:
199 self.default = values[0]
200 elif default in values:
201 self.default = default
202 else:
203 raise ValueError( # pragma: no cover
204 "if specified, default must be in values")
206 def _single_option(self, label, value):
207 """
208 private
209 """
210 if value == self.default:
211 selected = ' selected '
212 else:
213 selected = ''
214 return self.option_html.format(label=label,
215 value=value,
216 selected=selected)
218 def values(self):
219 """
220 return all possible values
221 """
222 return self._values
224 def html(self):
225 """
226 return HTML string
227 """
228 options = self.delimiter.join(
229 [self._single_option(label, value)
230 for (label, value) in zip(self.labels, self._values)]
231 )
232 return self.select_html.format(name=self.name,
233 options=options)
236class RadioWidget(StaticWidget):
238 """
239 radio button
240 """
242 #: template 1
243 radio_html = ('<input type="radio" name="{name}" value="{value}" '
244 '{checked} '
245 'onchange="interactUpdate(this.parentNode);">')
247 def __init__(self, values, name=None,
248 labels=None, default=None, divclass=None,
249 delimiter=" "):
250 """
251 @param values values for the list
252 @param name name of the object
253 @param labels ?
254 @param default default value
255 @param divclass class for div section
256 @param delimiter delimiter
257 """
258 StaticWidget.__init__(self, name, divclass)
259 self._values = values
260 self.delimiter = delimiter
262 if labels is None:
263 labels = map(str, values)
264 elif len(labels) != len(values):
265 raise ValueError("length of labels must match length of values")
266 self.labels = labels
268 if default is None:
269 self.default = values[0]
270 elif default in values:
271 self.default = default
272 else:
273 raise ValueError( # pragma: no cover
274 "if specified, default must be in values: default={0}, values={1}".format(
275 default, values))
277 def _single_radio(self, value):
278 """
279 private
280 """
281 if value == self.default:
282 checked = 'checked="checked"'
283 else:
284 checked = ''
285 return self.radio_html.format(name=self.name, value=value,
286 checked=checked)
288 def values(self):
289 """
290 return all the possible values
291 """
292 return self._values
294 def html(self):
295 """
296 return HTML string
297 """
298 preface = '<b>{name}:</b> '.format(name=self.name)
299 return preface + self.delimiter.join(
300 ["{0}: {1}".format(label, self._single_radio(value))
301 for (label, value) in zip(self.labels, self._values)])