Hide keyboard shortcuts

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`. 

6 

7Copyright (c) 2013, Jake Vanderplas 

8All rights reserved. 

9 

10Redistribution and use in source and binary forms, with or without modification, 

11are permitted provided that the following conditions are met: 

12 

13* Redistributions of source code must retain the above copyright notice, this 

14 list of conditions and the following disclaimer. 

15 

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. 

19 

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. 

23 

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""" 

35 

36import copy 

37 

38 

39class StaticWidget(object): 

40 

41 """ 

42 Base Class for Static Widgets 

43 """ 

44 

45 def __init__(self, name=None, divclass=None): 

46 """ 

47 constructor 

48 

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) 

57 

58 def __repr__(self): 

59 """ 

60 operator, call method html 

61 """ 

62 return self.html() 

63 

64 def _repr_html_(self): 

65 """ 

66 operator, call method html 

67 """ 

68 return self.html() 

69 

70 def html(self): 

71 "abstract method" 

72 raise NotImplementedError( # pragma: no cover 

73 "This should overriden.") 

74 

75 def copy(self): 

76 """ 

77 calls deepcopy 

78 

79 @return copy of self 

80 """ 

81 return copy.deepcopy(self) 

82 

83 def renamed(self, name): 

84 """ 

85 rename *name* if *name* is an attribute 

86 

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 

95 

96 

97class RangeWidget(StaticWidget): 

98 

99 """ 

100 Range (slider) widget 

101 

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);">') 

110 

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 

132 

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) 

140 

141 def html(self): 

142 """ 

143 HTML code 

144 

145 @return string HTML 

146 """ 

147 style = "" 

148 

149 if self.width is not None: 

150 style += "width:{0}px".format(self.width) 

151 

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 

159 

160 

161class DropDownWidget(StaticWidget): 

162 

163 """ 

164 drop down list 

165 """ 

166 

167 #: template 1 

168 select_html = ('<b>{name}:</b> <select name="{name}" ' 

169 'onchange="interactUpdate(this.parentNode);"> ' 

170 '{options}' 

171 '</select>' 

172 ) 

173 

174 #: template 2 

175 option_html = ('<option value="{value}" ' 

176 '{selected}>{label}</option>') 

177 

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 

197 

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") 

205 

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) 

217 

218 def values(self): 

219 """ 

220 return all possible values 

221 """ 

222 return self._values 

223 

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) 

234 

235 

236class RadioWidget(StaticWidget): 

237 

238 """ 

239 radio button 

240 """ 

241 

242 #: template 1 

243 radio_html = ('<input type="radio" name="{name}" value="{value}" ' 

244 '{checked} ' 

245 'onchange="interactUpdate(this.parentNode);">') 

246 

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 

261 

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 

267 

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)) 

276 

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) 

287 

288 def values(self): 

289 """ 

290 return all the possible values 

291 """ 

292 return self._values 

293 

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)])