##// END OF EJS Templates
Merge pull request #7547 from takluyver/widget-eg-fix...
Min RK -
r20133:a560cee7 merge
parent child Browse files
Show More
@@ -1,1046 +1,837
1 1 {
2 2 "cells": [
3 3 {
4 4 "cell_type": "markdown",
5 5 "metadata": {},
6 6 "source": [
7 7 "Before reading, make sure to review\n",
8 8 "\n",
9 9 "- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n",
10 10 "- [Backbone.js](https://www.codeschool.com/courses/anatomy-of-backbonejs)\n",
11 11 "- [The widget IPEP](https://github.com/ipython/ipython/wiki/IPEP-23%3A-Backbone.js-Widgets)\n",
12 12 "- [The original widget PR discussion](https://github.com/ipython/ipython/pull/4374)"
13 13 ]
14 14 },
15 15 {
16 16 "cell_type": "code",
17 "execution_count": 1,
17 "execution_count": null,
18 18 "metadata": {
19 19 "collapsed": false
20 20 },
21 21 "outputs": [],
22 22 "source": [
23 23 "from __future__ import print_function # For py 2.7 compat\n",
24 24 "\n",
25 25 "from IPython.html import widgets # Widget definitions\n",
26 26 "from IPython.display import display # Used to display widgets in the notebook\n",
27 27 "from IPython.utils.traitlets import Unicode # Used to declare attributes of our widget"
28 28 ]
29 29 },
30 30 {
31 31 "cell_type": "markdown",
32 32 "metadata": {},
33 33 "source": [
34 34 "# Abstract"
35 35 ]
36 36 },
37 37 {
38 38 "cell_type": "markdown",
39 39 "metadata": {},
40 40 "source": [
41 41 "This notebook implements a custom date picker widget,\n",
42 42 "in order to demonstrate the widget creation process.\n",
43 43 "\n",
44 44 "To create a custom widget, both Python and JavaScript code is required."
45 45 ]
46 46 },
47 47 {
48 48 "cell_type": "markdown",
49 49 "metadata": {},
50 50 "source": [
51 51 "# Section 1 - Basics"
52 52 ]
53 53 },
54 54 {
55 55 "cell_type": "markdown",
56 56 "metadata": {},
57 57 "source": [
58 58 "## Python"
59 59 ]
60 60 },
61 61 {
62 62 "cell_type": "markdown",
63 63 "metadata": {},
64 64 "source": [
65 65 "When starting a project like this, it is often easiest to make a simple base implementation,\n",
66 66 "to verify that the underlying framework is working as expected.\n",
67 67 "To start, we will create an empty widget and make sure that it can be rendered.\n",
68 68 "The first step is to define the widget in Python."
69 69 ]
70 70 },
71 71 {
72 72 "cell_type": "code",
73 "execution_count": 2,
73 "execution_count": null,
74 74 "metadata": {
75 75 "collapsed": false
76 76 },
77 77 "outputs": [],
78 78 "source": [
79 79 "class DateWidget(widgets.DOMWidget):\n",
80 80 " _view_name = Unicode('DatePickerView', sync=True)"
81 81 ]
82 82 },
83 83 {
84 84 "cell_type": "markdown",
85 85 "metadata": {},
86 86 "source": [
87 87 "Our widget inherits from `widgets.DOMWidget` since it is intended that it will be displayed in the notebook directly.\n",
88 88 "The `_view_name` trait is special; the widget framework will read the `_view_name` trait to determine what Backbone view the widget is associated with.\n",
89 89 "**Using `sync=True` is very important** because it tells the widget framework that that specific traitlet should be synced between the front- and back-ends."
90 90 ]
91 91 },
92 92 {
93 93 "cell_type": "markdown",
94 94 "metadata": {},
95 95 "source": [
96 96 "## JavaScript"
97 97 ]
98 98 },
99 99 {
100 100 "cell_type": "markdown",
101 101 "metadata": {},
102 102 "source": [
103 103 "In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies.\n",
104 104 "All IPython widget code depends on `widgets/js/widget.js`,\n",
105 105 "where the base widget model and base view are defined.\n",
106 106 "We use require.js to load this file:"
107 107 ]
108 108 },
109 109 {
110 110 "cell_type": "code",
111 "execution_count": 3,
111 "execution_count": null,
112 112 "metadata": {
113 113 "collapsed": false
114 114 },
115 "outputs": [
116 {
117 "data": {
118 "application/javascript": [
119 "\n",
120 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
121 "\n",
122 "});"
123 ],
124 "text/plain": [
125 "<IPython.core.display.Javascript at 0x109491690>"
126 ]
127 },
128 "metadata": {},
129 "output_type": "display_data"
130 }
131 ],
115 "outputs": [],
132 116 "source": [
133 117 "%%javascript\n",
134 118 "\n",
135 119 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
136 120 "\n",
137 121 "});"
138 122 ]
139 123 },
140 124 {
141 125 "cell_type": "markdown",
142 126 "metadata": {},
143 127 "source": [
144 128 "Now we need to define a view that can be used to represent the model.\n",
145 129 "To do this, the `IPython.DOMWidgetView` is extended.\n",
146 130 "**A render function must be defined**.\n",
147 131 "The render function is used to render a widget view instance to the DOM.\n",
148 132 "For now, the render function renders a div that contains the text *Hello World!*\n",
149 "Lastly, the view needs to be registered with the widget manager.\n",
133 "Lastly, the view needs to be registered with the widget manager, for which we need to load another module.\n",
150 134 "\n",
151 135 "**Final JavaScript code below:**"
152 136 ]
153 137 },
154 138 {
155 139 "cell_type": "code",
156 "execution_count": 4,
140 "execution_count": null,
157 141 "metadata": {
158 142 "collapsed": false
159 143 },
160 "outputs": [
161 {
162 "data": {
163 "application/javascript": [
164 "\n",
165 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
166 " \n",
167 " // Define the DatePickerView\n",
168 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
169 " render: function(){ this.$el.text('Hello World!'); },\n",
170 " });\n",
171 " \n",
172 " // Register the DatePickerView with the widget manager.\n",
173 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
174 "});"
175 ],
176 "text/plain": [
177 "<IPython.core.display.Javascript at 0x1094917d0>"
178 ]
179 },
180 "metadata": {},
181 "output_type": "display_data"
182 }
183 ],
144 "outputs": [],
184 145 "source": [
185 146 "%%javascript\n",
186 147 "\n",
187 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
148 "require([\"widgets/js/widget\", \"widgets/js/manager\"], function(widget, manager){\n",
188 149 " \n",
189 150 " // Define the DatePickerView\n",
190 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
151 " var DatePickerView = widget.DOMWidgetView.extend({\n",
191 152 " render: function(){ this.$el.text('Hello World!'); },\n",
192 153 " });\n",
193 154 " \n",
194 155 " // Register the DatePickerView with the widget manager.\n",
195 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
156 " manager.WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
196 157 "});"
197 158 ]
198 159 },
199 160 {
200 161 "cell_type": "markdown",
201 162 "metadata": {},
202 163 "source": [
203 164 "## Test"
204 165 ]
205 166 },
206 167 {
207 168 "cell_type": "markdown",
208 169 "metadata": {},
209 170 "source": [
210 171 "To test what we have so far, create the widget, just like you would the builtin widgets:"
211 172 ]
212 173 },
213 174 {
214 175 "cell_type": "code",
215 "execution_count": 5,
176 "execution_count": null,
216 177 "metadata": {
217 178 "collapsed": false
218 179 },
219 180 "outputs": [],
220 181 "source": [
221 182 "DateWidget()"
222 183 ]
223 184 },
224 185 {
225 186 "cell_type": "markdown",
226 187 "metadata": {},
227 188 "source": [
228 189 "# Section 2 - Something useful"
229 190 ]
230 191 },
231 192 {
232 193 "cell_type": "markdown",
233 194 "metadata": {},
234 195 "source": [
235 196 "## Python"
236 197 ]
237 198 },
238 199 {
239 200 "cell_type": "markdown",
240 201 "metadata": {},
241 202 "source": [
242 203 "In the last section we created a simple widget that displayed *Hello World!*\n",
243 204 "To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model.\n",
244 205 "The new attribute must be a traitlet, so the widget machinery can handle it.\n",
245 206 "The traitlet must be constructed with a `sync=True` keyword argument, to tell the widget machinery knows to synchronize it with the front-end.\n",
246 207 "Adding this to the code from the last section:"
247 208 ]
248 209 },
249 210 {
250 211 "cell_type": "code",
251 "execution_count": 6,
212 "execution_count": null,
252 213 "metadata": {
253 214 "collapsed": false
254 215 },
255 216 "outputs": [],
256 217 "source": [
257 218 "class DateWidget(widgets.DOMWidget):\n",
258 219 " _view_name = Unicode('DatePickerView', sync=True)\n",
259 220 " value = Unicode(sync=True)"
260 221 ]
261 222 },
262 223 {
263 224 "cell_type": "markdown",
264 225 "metadata": {},
265 226 "source": [
266 227 "## JavaScript"
267 228 ]
268 229 },
269 230 {
270 231 "cell_type": "markdown",
271 232 "metadata": {},
272 233 "source": [
273 234 "In the JavaScript, there is no need to define counterparts to the traitlets.\n",
274 235 "When the JavaScript model is created for the first time,\n",
275 236 "it copies all of the traitlet `sync=True` attributes from the Python model.\n",
276 237 "We need to replace *Hello World!* with an actual HTML date picker widget."
277 238 ]
278 239 },
279 240 {
280 241 "cell_type": "code",
281 "execution_count": 7,
242 "execution_count": null,
282 243 "metadata": {
283 244 "collapsed": false
284 245 },
285 "outputs": [
286 {
287 "data": {
288 "application/javascript": [
289 "\n",
290 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
291 " \n",
292 " // Define the DatePickerView\n",
293 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
294 " render: function(){\n",
295 " \n",
296 " // Create the date picker control.\n",
297 " this.$date = $('<input />')\n",
298 " .attr('type', 'date')\n",
299 " .appendTo(this.$el);\n",
300 " },\n",
301 " });\n",
302 " \n",
303 " // Register the DatePickerView with the widget manager.\n",
304 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
305 "});"
306 ],
307 "text/plain": [
308 "<IPython.core.display.Javascript at 0x109491750>"
309 ]
310 },
311 "metadata": {},
312 "output_type": "display_data"
313 }
314 ],
246 "outputs": [],
315 247 "source": [
316 248 "%%javascript\n",
317 249 "\n",
318 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
250 "require([\"widgets/js/widget\", \"widgets/js/manager\"], function(widget, manager){\n",
319 251 " \n",
320 252 " // Define the DatePickerView\n",
321 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
253 " var DatePickerView = widget.DOMWidgetView.extend({\n",
322 254 " render: function(){\n",
323 255 " \n",
324 256 " // Create the date picker control.\n",
325 257 " this.$date = $('<input />')\n",
326 258 " .attr('type', 'date')\n",
327 259 " .appendTo(this.$el);\n",
328 260 " },\n",
329 261 " });\n",
330 262 " \n",
331 263 " // Register the DatePickerView with the widget manager.\n",
332 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
264 " manager.WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
333 265 "});"
334 266 ]
335 267 },
336 268 {
337 269 "cell_type": "markdown",
338 270 "metadata": {},
339 271 "source": [
340 272 "In order to get the HTML date picker to update itself with the value set in the back-end, we need to implement an `update()` method."
341 273 ]
342 274 },
343 275 {
344 276 "cell_type": "code",
345 "execution_count": 8,
277 "execution_count": null,
346 278 "metadata": {
347 279 "collapsed": false
348 280 },
349 "outputs": [
350 {
351 "data": {
352 "application/javascript": [
353 "\n",
354 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
355 " \n",
356 " // Define the DatePickerView\n",
357 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
358 " render: function(){\n",
359 " \n",
360 " // Create the date picker control.\n",
361 " this.$date = $('<input />')\n",
362 " .attr('type', 'date')\n",
363 " .appendTo(this.$el);\n",
364 " },\n",
365 " \n",
366 " update: function() {\n",
367 " \n",
368 " // Set the value of the date control and then call base.\n",
369 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
370 " return DatePickerView.__super__.update.apply(this);\n",
371 " },\n",
372 " });\n",
373 " \n",
374 " // Register the DatePickerView with the widget manager.\n",
375 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
376 "});"
377 ],
378 "text/plain": [
379 "<IPython.core.display.Javascript at 0x109491750>"
380 ]
381 },
382 "metadata": {},
383 "output_type": "display_data"
384 }
385 ],
281 "outputs": [],
386 282 "source": [
387 283 "%%javascript\n",
388 284 "\n",
389 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
285 "require([\"widgets/js/widget\", \"widgets/js/manager\"], function(widget, manager){\n",
390 286 " \n",
391 287 " // Define the DatePickerView\n",
392 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
288 " var DatePickerView = widget.DOMWidgetView.extend({\n",
393 289 " render: function(){\n",
394 290 " \n",
395 291 " // Create the date picker control.\n",
396 292 " this.$date = $('<input />')\n",
397 293 " .attr('type', 'date')\n",
398 294 " .appendTo(this.$el);\n",
399 295 " },\n",
400 296 " \n",
401 297 " update: function() {\n",
402 298 " \n",
403 299 " // Set the value of the date control and then call base.\n",
404 300 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
405 301 " return DatePickerView.__super__.update.apply(this);\n",
406 302 " },\n",
407 303 " });\n",
408 304 " \n",
409 305 " // Register the DatePickerView with the widget manager.\n",
410 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
306 " manager.WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
411 307 "});"
412 308 ]
413 309 },
414 310 {
415 311 "cell_type": "markdown",
416 312 "metadata": {},
417 313 "source": [
418 314 "To get the changed value from the frontend to publish itself to the backend,\n",
419 315 "we need to listen to the change event triggered by the HTM date control and set the value in the model.\n",
420 316 "After the date change event fires and the new value is set in the model,\n",
421 317 "it is very important that we call `this.touch()` to let the widget machinery know which view changed the model.\n",
422 318 "This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
423 319 "\n",
424 320 "**Final JavaScript code below:**"
425 321 ]
426 322 },
427 323 {
428 324 "cell_type": "code",
429 "execution_count": 9,
325 "execution_count": null,
430 326 "metadata": {
431 327 "collapsed": false
432 328 },
433 "outputs": [
434 {
435 "data": {
436 "application/javascript": [
437 "\n",
438 "\n",
439 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
440 " \n",
441 " // Define the DatePickerView\n",
442 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
443 " render: function(){\n",
444 " \n",
445 " // Create the date picker control.\n",
446 " this.$date = $('<input />')\n",
447 " .attr('type', 'date')\n",
448 " .appendTo(this.$el);\n",
449 " },\n",
450 " \n",
451 " update: function() {\n",
452 " \n",
453 " // Set the value of the date control and then call base.\n",
454 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
455 " return DatePickerView.__super__.update.apply(this);\n",
456 " },\n",
457 " \n",
458 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
459 " events: {\"change\": \"handle_date_change\"},\n",
460 " \n",
461 " // Callback for when the date is changed.\n",
462 " handle_date_change: function(event) {\n",
463 " this.model.set('value', this.$date.val());\n",
464 " this.touch();\n",
465 " },\n",
466 " });\n",
467 " \n",
468 " // Register the DatePickerView with the widget manager.\n",
469 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
470 "});"
471 ],
472 "text/plain": [
473 "<IPython.core.display.Javascript at 0x109491b10>"
474 ]
475 },
476 "metadata": {},
477 "output_type": "display_data"
478 }
479 ],
329 "outputs": [],
480 330 "source": [
481 331 "%%javascript\n",
482 332 "\n",
483 333 "\n",
484 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
334 "require([\"widgets/js/widget\", \"widgets/js/manager\"], function(widget, manager){\n",
485 335 " \n",
486 336 " // Define the DatePickerView\n",
487 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
337 " var DatePickerView = widget.DOMWidgetView.extend({\n",
488 338 " render: function(){\n",
489 339 " \n",
490 340 " // Create the date picker control.\n",
491 341 " this.$date = $('<input />')\n",
492 342 " .attr('type', 'date')\n",
493 343 " .appendTo(this.$el);\n",
494 344 " },\n",
495 345 " \n",
496 346 " update: function() {\n",
497 347 " \n",
498 348 " // Set the value of the date control and then call base.\n",
499 349 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
500 350 " return DatePickerView.__super__.update.apply(this);\n",
501 351 " },\n",
502 352 " \n",
503 353 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
504 354 " events: {\"change\": \"handle_date_change\"},\n",
505 355 " \n",
506 356 " // Callback for when the date is changed.\n",
507 357 " handle_date_change: function(event) {\n",
508 358 " this.model.set('value', this.$date.val());\n",
509 359 " this.touch();\n",
510 360 " },\n",
511 361 " });\n",
512 362 " \n",
513 363 " // Register the DatePickerView with the widget manager.\n",
514 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
364 " manager.WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
515 365 "});"
516 366 ]
517 367 },
518 368 {
519 369 "cell_type": "markdown",
520 370 "metadata": {},
521 371 "source": [
522 372 "## Test"
523 373 ]
524 374 },
525 375 {
526 376 "cell_type": "markdown",
527 377 "metadata": {},
528 378 "source": [
529 379 "To test, create the widget the same way that the other widgets are created."
530 380 ]
531 381 },
532 382 {
533 383 "cell_type": "code",
534 "execution_count": 10,
384 "execution_count": null,
535 385 "metadata": {
536 386 "collapsed": false
537 387 },
538 388 "outputs": [],
539 389 "source": [
540 390 "my_widget = DateWidget()\n",
541 391 "display(my_widget)"
542 392 ]
543 393 },
544 394 {
545 395 "cell_type": "markdown",
546 396 "metadata": {},
547 397 "source": [
548 398 "Display the widget again to make sure that both views remain in sync."
549 399 ]
550 400 },
551 401 {
552 402 "cell_type": "code",
553 "execution_count": 11,
403 "execution_count": null,
554 404 "metadata": {
555 405 "collapsed": false
556 406 },
557 407 "outputs": [],
558 408 "source": [
559 409 "my_widget"
560 410 ]
561 411 },
562 412 {
563 413 "cell_type": "markdown",
564 414 "metadata": {},
565 415 "source": [
566 416 "Read the date from Python"
567 417 ]
568 418 },
569 419 {
570 420 "cell_type": "code",
571 "execution_count": 12,
421 "execution_count": null,
572 422 "metadata": {
573 423 "collapsed": false
574 424 },
575 "outputs": [
576 {
577 "data": {
578 "text/plain": [
579 "u''"
580 ]
581 },
582 "execution_count": 12,
583 "metadata": {},
584 "output_type": "execute_result"
585 }
586 ],
425 "outputs": [],
587 426 "source": [
588 427 "my_widget.value"
589 428 ]
590 429 },
591 430 {
592 431 "cell_type": "markdown",
593 432 "metadata": {},
594 433 "source": [
595 434 "Set the date from Python"
596 435 ]
597 436 },
598 437 {
599 438 "cell_type": "code",
600 "execution_count": 13,
439 "execution_count": null,
601 440 "metadata": {
602 441 "collapsed": false
603 442 },
604 443 "outputs": [],
605 444 "source": [
606 445 "my_widget.value = \"1998-12-01\" # December 1st, 1998"
607 446 ]
608 447 },
609 448 {
610 449 "cell_type": "markdown",
611 450 "metadata": {},
612 451 "source": [
613 452 "# Section 3 - Extra credit"
614 453 ]
615 454 },
616 455 {
617 456 "cell_type": "markdown",
618 457 "metadata": {},
619 458 "source": [
620 459 "The 3rd party `dateutil` library is required to continue. https://pypi.python.org/pypi/python-dateutil"
621 460 ]
622 461 },
623 462 {
624 463 "cell_type": "code",
625 "execution_count": 14,
464 "execution_count": null,
626 465 "metadata": {
627 466 "collapsed": false
628 467 },
629 468 "outputs": [],
630 469 "source": [
631 470 "# Import the dateutil library to parse date strings.\n",
632 471 "from dateutil import parser"
633 472 ]
634 473 },
635 474 {
636 475 "cell_type": "markdown",
637 476 "metadata": {},
638 477 "source": [
639 478 "In the last section we created a fully working date picker widget.\n",
640 479 "Now we will add custom validation and support for labels.\n",
641 480 "So far, only the ISO date format \"YYYY-MM-DD\" is supported.\n",
642 481 "Now, we will add support for all of the date formats recognized by the Python dateutil library."
643 482 ]
644 483 },
645 484 {
646 485 "cell_type": "markdown",
647 486 "metadata": {},
648 487 "source": [
649 488 "## Python"
650 489 ]
651 490 },
652 491 {
653 492 "cell_type": "markdown",
654 493 "metadata": {},
655 494 "source": [
656 495 "The standard property name used for widget labels is `description`.\n",
657 496 "In the code block below, `description` has been added to the Python widget."
658 497 ]
659 498 },
660 499 {
661 500 "cell_type": "code",
662 "execution_count": 15,
501 "execution_count": null,
663 502 "metadata": {
664 503 "collapsed": false
665 504 },
666 505 "outputs": [],
667 506 "source": [
668 507 "class DateWidget(widgets.DOMWidget):\n",
669 508 " _view_name = Unicode('DatePickerView', sync=True)\n",
670 509 " value = Unicode(sync=True)\n",
671 510 " description = Unicode(sync=True)"
672 511 ]
673 512 },
674 513 {
675 514 "cell_type": "markdown",
676 515 "metadata": {},
677 516 "source": [
678 517 "The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names. Any method with the format \"`_X_changed`\" will be called when \"`X`\" is modified.\n",
679 518 "We can take advantage of this to perform validation and parsing of different date string formats.\n",
680 519 "Below, a method that listens to value has been added to the DateWidget."
681 520 ]
682 521 },
683 522 {
684 523 "cell_type": "code",
685 "execution_count": 16,
524 "execution_count": null,
686 525 "metadata": {
687 526 "collapsed": false
688 527 },
689 528 "outputs": [],
690 529 "source": [
691 530 "class DateWidget(widgets.DOMWidget):\n",
692 531 " _view_name = Unicode('DatePickerView', sync=True)\n",
693 532 " value = Unicode(sync=True)\n",
694 533 " description = Unicode(sync=True)\n",
695 534 "\n",
696 535 " # This function automatically gets called by the traitlet machinery when\n",
697 536 " # value is modified because of this function's name.\n",
698 537 " def _value_changed(self, name, old_value, new_value):\n",
699 538 " pass"
700 539 ]
701 540 },
702 541 {
703 542 "cell_type": "markdown",
704 543 "metadata": {},
705 544 "source": [
706 545 "Now the function parses the date string,\n",
707 546 "and only sets the value in the correct format."
708 547 ]
709 548 },
710 549 {
711 550 "cell_type": "code",
712 "execution_count": 17,
551 "execution_count": null,
713 552 "metadata": {
714 553 "collapsed": false
715 554 },
716 555 "outputs": [],
717 556 "source": [
718 557 "class DateWidget(widgets.DOMWidget):\n",
719 558 " _view_name = Unicode('DatePickerView', sync=True)\n",
720 559 " value = Unicode(sync=True)\n",
721 560 " description = Unicode(sync=True)\n",
722 561 " \n",
723 562 " # This function automatically gets called by the traitlet machinery when\n",
724 563 " # value is modified because of this function's name.\n",
725 564 " def _value_changed(self, name, old_value, new_value):\n",
726 565 " \n",
727 566 " # Parse the date time value.\n",
728 567 " try:\n",
729 568 " parsed_date = parser.parse(new_value)\n",
730 569 " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
731 570 " except:\n",
732 571 " parsed_date_string = ''\n",
733 572 " \n",
734 573 " # Set the parsed date string if the current date string is different.\n",
735 574 " if self.value != parsed_date_string:\n",
736 575 " self.value = parsed_date_string"
737 576 ]
738 577 },
739 578 {
740 579 "cell_type": "markdown",
741 580 "metadata": {},
742 581 "source": [
743 582 "Finally, a `CallbackDispatcher` is added so the user can perform custom validation.\n",
744 583 "If any one of the callbacks registered with the dispatcher returns False,\n",
745 584 "the new date is not set.\n",
746 585 "\n",
747 586 "**Final Python code below:**"
748 587 ]
749 588 },
750 589 {
751 590 "cell_type": "code",
752 "execution_count": 18,
591 "execution_count": null,
753 592 "metadata": {
754 593 "collapsed": false
755 594 },
756 595 "outputs": [],
757 596 "source": [
758 597 "class DateWidget(widgets.DOMWidget):\n",
759 598 " _view_name = Unicode('DatePickerView', sync=True)\n",
760 599 " value = Unicode(sync=True)\n",
761 600 " description = Unicode(sync=True)\n",
762 601 " \n",
763 602 " def __init__(self, **kwargs):\n",
764 603 " super(DateWidget, self).__init__(**kwargs)\n",
765 604 " \n",
766 605 " self.validate = widgets.CallbackDispatcher()\n",
767 606 " \n",
768 607 " # This function automatically gets called by the traitlet machinery when\n",
769 608 " # value is modified because of this function's name.\n",
770 609 " def _value_changed(self, name, old_value, new_value):\n",
771 610 " \n",
772 611 " # Parse the date time value.\n",
773 612 " try:\n",
774 613 " parsed_date = parser.parse(new_value)\n",
775 614 " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
776 615 " except:\n",
777 616 " parsed_date_string = ''\n",
778 617 " \n",
779 618 " # Set the parsed date string if the current date string is different.\n",
780 619 " if old_value != new_value:\n",
781 620 " valid = self.validate(parsed_date)\n",
782 621 " if valid in (None, True):\n",
783 622 " self.value = parsed_date_string\n",
784 623 " else:\n",
785 624 " self.value = old_value\n",
786 625 " self.send_state() # The traitlet event won't fire since the value isn't changing.\n",
787 626 " # We need to force the back-end to send the front-end the state\n",
788 627 " # to make sure that the date control date doesn't change."
789 628 ]
790 629 },
791 630 {
792 631 "cell_type": "markdown",
793 632 "metadata": {},
794 633 "source": [
795 634 "## JavaScript"
796 635 ]
797 636 },
798 637 {
799 638 "cell_type": "markdown",
800 639 "metadata": {},
801 640 "source": [
802 641 "Using the Javascript code from the last section,\n",
803 642 "we add a label to the date time object.\n",
804 643 "The label is a div with the `widget-hlabel` class applied to it.\n",
805 644 "`widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built-in widgets.\n",
806 645 "Similar to the `widget-hlabel` class is the `widget-hbox-single` class.\n",
807 646 "The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget.\n",
808 647 "\n",
809 648 "We hide the label if the description value is blank."
810 649 ]
811 650 },
812 651 {
813 652 "cell_type": "code",
814 "execution_count": 19,
653 "execution_count": null,
815 654 "metadata": {
816 655 "collapsed": false
817 656 },
818 "outputs": [
819 {
820 "data": {
821 "application/javascript": [
822 "\n",
823 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
824 " \n",
825 " // Define the DatePickerView\n",
826 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
827 " render: function(){\n",
828 " this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
829 " it fit with the other built in widgets.*/\n",
830 " // Create a label.\n",
831 " this.$label = $('<div />')\n",
832 " .addClass('widget-hlabel')\n",
833 " .appendTo(this.$el)\n",
834 " .hide(); // Hide the label by default.\n",
835 " \n",
836 " // Create the date picker control.\n",
837 " this.$date = $('<input />')\n",
838 " .attr('type', 'date')\n",
839 " .appendTo(this.$el);\n",
840 " },\n",
841 " \n",
842 " update: function() {\n",
843 " \n",
844 " // Set the value of the date control and then call base.\n",
845 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
846 " \n",
847 " // Hide or show the label depending on the existance of a description.\n",
848 " var description = this.model.get('description');\n",
849 " if (description == undefined || description == '') {\n",
850 " this.$label.hide();\n",
851 " } else {\n",
852 " this.$label.show();\n",
853 " this.$label.text(description);\n",
854 " }\n",
855 " \n",
856 " return DatePickerView.__super__.update.apply(this);\n",
857 " },\n",
858 " \n",
859 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
860 " events: {\"change\": \"handle_date_change\"},\n",
861 " \n",
862 " // Callback for when the date is changed.\n",
863 " handle_date_change: function(event) {\n",
864 " this.model.set('value', this.$date.val());\n",
865 " this.touch();\n",
866 " },\n",
867 " });\n",
868 " \n",
869 " // Register the DatePickerView with the widget manager.\n",
870 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
871 "});"
872 ],
873 "text/plain": [
874 "<IPython.core.display.Javascript at 0x1094eef90>"
875 ]
876 },
877 "metadata": {},
878 "output_type": "display_data"
879 }
880 ],
657 "outputs": [],
881 658 "source": [
882 659 "%%javascript\n",
883 660 "\n",
884 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
661 "require([\"widgets/js/widget\", \"widgets/js/manager\"], function(widget, manager){\n",
885 662 " \n",
886 663 " // Define the DatePickerView\n",
887 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
664 " var DatePickerView = widget.DOMWidgetView.extend({\n",
888 665 " render: function(){\n",
889 666 " this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
890 667 " it fit with the other built in widgets.*/\n",
891 668 " // Create a label.\n",
892 669 " this.$label = $('<div />')\n",
893 670 " .addClass('widget-hlabel')\n",
894 671 " .appendTo(this.$el)\n",
895 672 " .hide(); // Hide the label by default.\n",
896 673 " \n",
897 674 " // Create the date picker control.\n",
898 675 " this.$date = $('<input />')\n",
899 676 " .attr('type', 'date')\n",
900 677 " .appendTo(this.$el);\n",
901 678 " },\n",
902 679 " \n",
903 680 " update: function() {\n",
904 681 " \n",
905 682 " // Set the value of the date control and then call base.\n",
906 683 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
907 684 " \n",
908 685 " // Hide or show the label depending on the existance of a description.\n",
909 686 " var description = this.model.get('description');\n",
910 687 " if (description == undefined || description == '') {\n",
911 688 " this.$label.hide();\n",
912 689 " } else {\n",
913 690 " this.$label.show();\n",
914 691 " this.$label.text(description);\n",
915 692 " }\n",
916 693 " \n",
917 694 " return DatePickerView.__super__.update.apply(this);\n",
918 695 " },\n",
919 696 " \n",
920 697 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
921 698 " events: {\"change\": \"handle_date_change\"},\n",
922 699 " \n",
923 700 " // Callback for when the date is changed.\n",
924 701 " handle_date_change: function(event) {\n",
925 702 " this.model.set('value', this.$date.val());\n",
926 703 " this.touch();\n",
927 704 " },\n",
928 705 " });\n",
929 706 " \n",
930 707 " // Register the DatePickerView with the widget manager.\n",
931 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
708 " manager.WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
932 709 "});"
933 710 ]
934 711 },
935 712 {
936 713 "cell_type": "markdown",
937 714 "metadata": {},
938 715 "source": [
939 716 "## Test"
940 717 ]
941 718 },
942 719 {
943 720 "cell_type": "markdown",
944 721 "metadata": {},
945 722 "source": [
946 723 "To test the drawing of the label we create the widget like normal but supply the additional description property a value."
947 724 ]
948 725 },
949 726 {
950 727 "cell_type": "code",
951 "execution_count": 20,
728 "execution_count": null,
952 729 "metadata": {
953 730 "collapsed": false
954 731 },
955 732 "outputs": [],
956 733 "source": [
957 734 "# Add some additional widgets for aesthetic purpose\n",
958 "display(widgets.TextWidget(description=\"First:\"))\n",
959 "display(widgets.TextWidget(description=\"Last:\"))\n",
735 "display(widgets.Text(description=\"First:\"))\n",
736 "display(widgets.Text(description=\"Last:\"))\n",
960 737 "\n",
961 738 "my_widget = DateWidget()\n",
962 739 "display(my_widget)\n",
963 740 "my_widget.description=\"DOB:\""
964 741 ]
965 742 },
966 743 {
967 744 "cell_type": "markdown",
968 745 "metadata": {},
969 746 "source": [
970 747 "Now we will try to create a widget that only accepts dates in the year 2014. We render the widget without a description to verify that it can still render without a label."
971 748 ]
972 749 },
973 750 {
974 751 "cell_type": "code",
975 "execution_count": 21,
752 "execution_count": null,
976 753 "metadata": {
977 754 "collapsed": false
978 755 },
979 756 "outputs": [],
980 757 "source": [
981 758 "my_widget = DateWidget()\n",
982 759 "display(my_widget)\n",
983 760 "\n",
984 761 "def require_2014(date):\n",
985 762 " return not date is None and date.year == 2014\n",
986 763 "my_widget.validate.register_callback(require_2014)"
987 764 ]
988 765 },
989 766 {
990 767 "cell_type": "code",
991 "execution_count": 22,
768 "execution_count": null,
992 769 "metadata": {
993 770 "collapsed": false
994 771 },
995 772 "outputs": [],
996 773 "source": [
997 774 "# Try setting a valid date\n",
998 775 "my_widget.value = \"December 2, 2014\""
999 776 ]
1000 777 },
1001 778 {
1002 779 "cell_type": "code",
1003 "execution_count": 23,
780 "execution_count": null,
1004 781 "metadata": {
1005 782 "collapsed": false
1006 783 },
1007 784 "outputs": [],
1008 785 "source": [
1009 786 "# Try setting an invalid date\n",
1010 787 "my_widget.value = \"June 12, 1999\""
1011 788 ]
1012 789 },
1013 790 {
1014 791 "cell_type": "code",
1015 "execution_count": 24,
792 "execution_count": null,
1016 793 "metadata": {
1017 794 "collapsed": false
1018 795 },
1019 "outputs": [
1020 {
1021 "data": {
1022 "text/plain": [
1023 "u'2014-12-02'"
1024 ]
1025 },
1026 "execution_count": 24,
1027 "metadata": {},
1028 "output_type": "execute_result"
1029 }
1030 ],
796 "outputs": [],
1031 797 "source": [
1032 798 "my_widget.value"
1033 799 ]
800 },
801 {
802 "cell_type": "code",
803 "execution_count": null,
804 "metadata": {
805 "collapsed": true
806 },
807 "outputs": [],
808 "source": []
1034 809 }
1035 810 ],
1036 811 "metadata": {
1037 812 "cell_tags": [
1038 813 [
1039 814 "<None>",
1040 815 null
1041 816 ]
1042 ]
817 ],
818 "kernelspec": {
819 "display_name": "Python 3",
820 "name": "python3"
821 },
822 "language_info": {
823 "codemirror_mode": {
824 "name": "ipython",
825 "version": 3
826 },
827 "file_extension": ".py",
828 "mimetype": "text/x-python",
829 "name": "python",
830 "nbconvert_exporter": "python",
831 "pygments_lexer": "ipython3",
832 "version": "3.4.2"
833 }
1043 834 },
1044 835 "nbformat": 4,
1045 836 "nbformat_minor": 0
1046 } No newline at end of file
837 }
@@ -1,580 +1,586
1 1 {
2 2 "cells": [
3 3 {
4 4 "cell_type": "markdown",
5 5 "metadata": {},
6 6 "source": [
7 7 "[Index](Index.ipynb) - [Back](Widget Basics.ipynb) - [Next](Widget Events.ipynb)"
8 8 ]
9 9 },
10 10 {
11 11 "cell_type": "markdown",
12 12 "metadata": {},
13 13 "source": [
14 14 "# Widget List"
15 15 ]
16 16 },
17 17 {
18 18 "cell_type": "markdown",
19 19 "metadata": {},
20 20 "source": [
21 21 "## Complete list"
22 22 ]
23 23 },
24 24 {
25 25 "cell_type": "markdown",
26 26 "metadata": {
27 27 "slideshow": {
28 28 "slide_type": "slide"
29 29 }
30 30 },
31 31 "source": [
32 32 "For a complete list of the widgets available to you, you can list the classes in the widget namespace (as seen below). `Widget` and `DOMWidget`, not listed below, are base classes."
33 33 ]
34 34 },
35 35 {
36 36 "cell_type": "code",
37 37 "execution_count": null,
38 38 "metadata": {
39 39 "collapsed": false
40 40 },
41 41 "outputs": [],
42 42 "source": [
43 43 "from IPython.html import widgets\n",
44 44 "[n for n in dir(widgets) if not n.endswith('Widget') and n[0] == n[0].upper() and not n[0] == '_']"
45 45 ]
46 46 },
47 47 {
48 48 "cell_type": "markdown",
49 49 "metadata": {
50 50 "slideshow": {
51 51 "slide_type": "slide"
52 52 }
53 53 },
54 54 "source": [
55 55 "## Numeric widgets"
56 56 ]
57 57 },
58 58 {
59 59 "cell_type": "markdown",
60 60 "metadata": {},
61 61 "source": [
62 62 "There are 8 widgets distributed with IPython that are designed to display numeric values. Widgets exist for displaying integers and floats, both bounded and unbounded. The integer widgets share a similar naming scheme to their floating point counterparts. By replacing `Float` with `Int` in the widget name, you can find the Integer equivalent."
63 63 ]
64 64 },
65 65 {
66 66 "cell_type": "markdown",
67 67 "metadata": {
68 68 "slideshow": {
69 69 "slide_type": "slide"
70 70 }
71 71 },
72 72 "source": [
73 73 "### FloatSlider"
74 74 ]
75 75 },
76 76 {
77 77 "cell_type": "code",
78 78 "execution_count": null,
79 79 "metadata": {
80 80 "collapsed": false
81 81 },
82 82 "outputs": [],
83 83 "source": [
84 84 "widgets.FloatSlider(\n",
85 85 " value=7.5,\n",
86 86 " min=5.0,\n",
87 87 " max=10.0,\n",
88 88 " step=0.1,\n",
89 89 " description='Test:',\n",
90 90 ")"
91 91 ]
92 92 },
93 93 {
94 94 "cell_type": "markdown",
95 95 "metadata": {},
96 96 "source": [
97 97 "Sliders can also be **displayed vertically**."
98 98 ]
99 99 },
100 100 {
101 101 "cell_type": "code",
102 102 "execution_count": null,
103 103 "metadata": {
104 104 "collapsed": false
105 105 },
106 106 "outputs": [],
107 107 "source": [
108 108 "widgets.FloatSlider(\n",
109 109 " value=7.5,\n",
110 110 " min=5.0,\n",
111 111 " max=10.0,\n",
112 112 " step=0.1,\n",
113 113 " description='Test',\n",
114 114 " orientation='vertical',\n",
115 115 ")"
116 116 ]
117 117 },
118 118 {
119 119 "cell_type": "markdown",
120 120 "metadata": {
121 121 "slideshow": {
122 122 "slide_type": "slide"
123 123 }
124 124 },
125 125 "source": [
126 126 "### FloatProgress"
127 127 ]
128 128 },
129 129 {
130 130 "cell_type": "code",
131 131 "execution_count": null,
132 132 "metadata": {
133 133 "collapsed": false
134 134 },
135 135 "outputs": [],
136 136 "source": [
137 137 "widgets.FloatProgress(\n",
138 138 " value=7.5,\n",
139 139 " min=5.0,\n",
140 140 " max=10.0,\n",
141 141 " step=0.1,\n",
142 142 " description='Loading:',\n",
143 143 ")"
144 144 ]
145 145 },
146 146 {
147 147 "cell_type": "markdown",
148 148 "metadata": {
149 149 "slideshow": {
150 150 "slide_type": "slide"
151 151 }
152 152 },
153 153 "source": [
154 154 "### BoundedFloatText"
155 155 ]
156 156 },
157 157 {
158 158 "cell_type": "code",
159 159 "execution_count": null,
160 160 "metadata": {
161 161 "collapsed": false
162 162 },
163 163 "outputs": [],
164 164 "source": [
165 165 "widgets.BoundedFloatText(\n",
166 166 " value=7.5,\n",
167 167 " min=5.0,\n",
168 168 " max=10.0,\n",
169 169 " description='Text:',\n",
170 170 ")"
171 171 ]
172 172 },
173 173 {
174 174 "cell_type": "markdown",
175 175 "metadata": {
176 176 "slideshow": {
177 177 "slide_type": "slide"
178 178 }
179 179 },
180 180 "source": [
181 181 "### FloatText"
182 182 ]
183 183 },
184 184 {
185 185 "cell_type": "code",
186 186 "execution_count": null,
187 187 "metadata": {
188 188 "collapsed": false
189 189 },
190 190 "outputs": [],
191 191 "source": [
192 192 "widgets.FloatText(\n",
193 193 " value=7.5,\n",
194 194 " description='Any:',\n",
195 195 ")"
196 196 ]
197 197 },
198 198 {
199 199 "cell_type": "markdown",
200 200 "metadata": {
201 201 "slideshow": {
202 202 "slide_type": "slide"
203 203 }
204 204 },
205 205 "source": [
206 206 "## Boolean widgets"
207 207 ]
208 208 },
209 209 {
210 210 "cell_type": "markdown",
211 211 "metadata": {},
212 212 "source": [
213 213 "There are two widgets that are designed to display a boolean value."
214 214 ]
215 215 },
216 216 {
217 217 "cell_type": "markdown",
218 218 "metadata": {},
219 219 "source": [
220 220 "### ToggleButton"
221 221 ]
222 222 },
223 223 {
224 224 "cell_type": "code",
225 225 "execution_count": null,
226 226 "metadata": {
227 227 "collapsed": false
228 228 },
229 229 "outputs": [],
230 230 "source": [
231 231 "widgets.ToggleButton(\n",
232 232 " description='Click me',\n",
233 233 " value=False,\n",
234 234 ")"
235 235 ]
236 236 },
237 237 {
238 238 "cell_type": "markdown",
239 239 "metadata": {
240 240 "slideshow": {
241 241 "slide_type": "slide"
242 242 }
243 243 },
244 244 "source": [
245 245 "### Checkbox"
246 246 ]
247 247 },
248 248 {
249 249 "cell_type": "code",
250 250 "execution_count": null,
251 251 "metadata": {
252 252 "collapsed": false
253 253 },
254 254 "outputs": [],
255 255 "source": [
256 256 "widgets.Checkbox(\n",
257 257 " description='Check me',\n",
258 258 " value=True,\n",
259 259 ")"
260 260 ]
261 261 },
262 262 {
263 263 "cell_type": "markdown",
264 264 "metadata": {
265 265 "slideshow": {
266 266 "slide_type": "slide"
267 267 }
268 268 },
269 269 "source": [
270 270 "## Selection widgets"
271 271 ]
272 272 },
273 273 {
274 274 "cell_type": "markdown",
275 275 "metadata": {},
276 276 "source": [
277 277 "There are four widgets that can be used to display single selection lists. All four inherit from the same base class. You can specify the **enumeration of selectables by passing a list**. You can **also specify the enumeration as a dictionary**, in which case the **keys will be used as the item displayed** in the list and the corresponding **value will be returned** when an item is selected."
278 278 ]
279 279 },
280 280 {
281 281 "cell_type": "markdown",
282 282 "metadata": {
283 283 "slideshow": {
284 284 "slide_type": "slide"
285 285 }
286 286 },
287 287 "source": [
288 288 "### Dropdown"
289 289 ]
290 290 },
291 291 {
292 292 "cell_type": "code",
293 293 "execution_count": null,
294 294 "metadata": {
295 295 "collapsed": false
296 296 },
297 297 "outputs": [],
298 298 "source": [
299 299 "from IPython.display import display\n",
300 300 "w = widgets.Dropdown(\n",
301 " values=[1, 2, 3],\n",
302 " value=2,\n",
301 " values=['1', '2', '3'],\n",
302 " value='2',\n",
303 303 " description='Number:',\n",
304 304 ")\n",
305 305 "display(w)"
306 306 ]
307 307 },
308 308 {
309 309 "cell_type": "code",
310 310 "execution_count": null,
311 311 "metadata": {
312 312 "collapsed": false
313 313 },
314 314 "outputs": [],
315 315 "source": [
316 316 "w.value"
317 317 ]
318 318 },
319 319 {
320 320 "cell_type": "markdown",
321 321 "metadata": {},
322 322 "source": [
323 323 "The following is also valid:"
324 324 ]
325 325 },
326 326 {
327 327 "cell_type": "code",
328 328 "execution_count": null,
329 329 "metadata": {
330 330 "collapsed": false
331 331 },
332 332 "outputs": [],
333 333 "source": [
334 334 "w = widgets.Dropdown(\n",
335 335 " values={'One': 1, 'Two': 2, 'Three': 3},\n",
336 336 " value=2,\n",
337 337 " description='Number:',\n",
338 338 ")\n",
339 339 "display(w)"
340 340 ]
341 341 },
342 342 {
343 343 "cell_type": "code",
344 344 "execution_count": null,
345 345 "metadata": {
346 346 "collapsed": false
347 347 },
348 348 "outputs": [],
349 349 "source": [
350 350 "w.value"
351 351 ]
352 352 },
353 353 {
354 354 "cell_type": "markdown",
355 355 "metadata": {
356 356 "slideshow": {
357 357 "slide_type": "slide"
358 358 }
359 359 },
360 360 "source": [
361 361 "### RadioButtons"
362 362 ]
363 363 },
364 364 {
365 365 "cell_type": "code",
366 366 "execution_count": null,
367 367 "metadata": {
368 368 "collapsed": false
369 369 },
370 370 "outputs": [],
371 371 "source": [
372 372 "widgets.RadioButtons(\n",
373 373 " description='Pizza topping:',\n",
374 374 " values=['pepperoni', 'pineapple', 'anchovies'],\n",
375 375 ")"
376 376 ]
377 377 },
378 378 {
379 379 "cell_type": "markdown",
380 380 "metadata": {
381 381 "slideshow": {
382 382 "slide_type": "slide"
383 383 }
384 384 },
385 385 "source": [
386 386 "### Select"
387 387 ]
388 388 },
389 389 {
390 390 "cell_type": "code",
391 391 "execution_count": null,
392 392 "metadata": {
393 393 "collapsed": false
394 394 },
395 395 "outputs": [],
396 396 "source": [
397 397 "widgets.Select(\n",
398 398 " description='OS:',\n",
399 399 " values=['Linux', 'Windows', 'OSX'],\n",
400 400 ")"
401 401 ]
402 402 },
403 403 {
404 404 "cell_type": "markdown",
405 405 "metadata": {
406 406 "slideshow": {
407 407 "slide_type": "slide"
408 408 }
409 409 },
410 410 "source": [
411 411 "### ToggleButtons"
412 412 ]
413 413 },
414 414 {
415 415 "cell_type": "code",
416 416 "execution_count": null,
417 417 "metadata": {
418 418 "collapsed": false
419 419 },
420 420 "outputs": [],
421 421 "source": [
422 422 "widgets.ToggleButtons(\n",
423 423 " description='Speed:',\n",
424 424 " values=['Slow', 'Regular', 'Fast'],\n",
425 425 ")"
426 426 ]
427 427 },
428 428 {
429 429 "cell_type": "markdown",
430 430 "metadata": {
431 431 "slideshow": {
432 432 "slide_type": "slide"
433 433 }
434 434 },
435 435 "source": [
436 436 "## String widgets"
437 437 ]
438 438 },
439 439 {
440 440 "cell_type": "markdown",
441 441 "metadata": {},
442 442 "source": [
443 443 "There are 4 widgets that can be used to display a string value. Of those, the **`Text` and `Textarea` widgets accept input**. The **`Latex` and `HTML` widgets display the string** as either Latex or HTML respectively, but **do not accept input**."
444 444 ]
445 445 },
446 446 {
447 447 "cell_type": "markdown",
448 448 "metadata": {
449 449 "slideshow": {
450 450 "slide_type": "slide"
451 451 }
452 452 },
453 453 "source": [
454 454 "### Text"
455 455 ]
456 456 },
457 457 {
458 458 "cell_type": "code",
459 459 "execution_count": null,
460 460 "metadata": {
461 461 "collapsed": false
462 462 },
463 463 "outputs": [],
464 464 "source": [
465 465 "widgets.Text(\n",
466 466 " description='String:',\n",
467 467 " value='Hello World',\n",
468 468 ")"
469 469 ]
470 470 },
471 471 {
472 472 "cell_type": "markdown",
473 473 "metadata": {},
474 474 "source": [
475 475 "### Textarea"
476 476 ]
477 477 },
478 478 {
479 479 "cell_type": "code",
480 480 "execution_count": null,
481 481 "metadata": {
482 482 "collapsed": false
483 483 },
484 484 "outputs": [],
485 485 "source": [
486 486 "widgets.Textarea(\n",
487 487 " description='String:',\n",
488 488 " value='Hello World',\n",
489 489 ")"
490 490 ]
491 491 },
492 492 {
493 493 "cell_type": "markdown",
494 494 "metadata": {
495 495 "slideshow": {
496 496 "slide_type": "slide"
497 497 }
498 498 },
499 499 "source": [
500 500 "### Latex"
501 501 ]
502 502 },
503 503 {
504 504 "cell_type": "code",
505 505 "execution_count": null,
506 506 "metadata": {
507 507 "collapsed": false
508 508 },
509 509 "outputs": [],
510 510 "source": [
511 511 "widgets.Latex(\n",
512 512 " value=\"$$\\\\frac{n!}{k!(n-k)!} = \\\\binom{n}{k}$$\",\n",
513 513 ")"
514 514 ]
515 515 },
516 516 {
517 517 "cell_type": "markdown",
518 518 "metadata": {},
519 519 "source": [
520 520 "### HTML"
521 521 ]
522 522 },
523 523 {
524 524 "cell_type": "code",
525 525 "execution_count": null,
526 526 "metadata": {
527 527 "collapsed": false
528 528 },
529 529 "outputs": [],
530 530 "source": [
531 531 "widgets.HTML(\n",
532 532 " value=\"Hello <b>World</b>\"\n",
533 533 ")"
534 534 ]
535 535 },
536 536 {
537 537 "cell_type": "markdown",
538 538 "metadata": {
539 539 "slideshow": {
540 540 "slide_type": "slide"
541 541 }
542 542 },
543 543 "source": [
544 544 "## Button"
545 545 ]
546 546 },
547 547 {
548 548 "cell_type": "code",
549 549 "execution_count": null,
550 550 "metadata": {
551 551 "collapsed": false
552 552 },
553 553 "outputs": [],
554 554 "source": [
555 555 "widgets.Button(description='Click me')"
556 556 ]
557 557 },
558 558 {
559 559 "cell_type": "markdown",
560 560 "metadata": {},
561 561 "source": [
562 562 "[Index](Index.ipynb) - [Back](Widget Basics.ipynb) - [Next](Widget Events.ipynb)"
563 563 ]
564 564 }
565 565 ],
566 566 "metadata": {
567 567 "kernelspec": {
568 "codemirror_mode": {
569 "name": "python",
570 "version": 2
571 },
572 568 "display_name": "Python 2",
573 "language": "python",
574 569 "name": "python2"
575 570 },
576 "signature": "sha256:83b39d018a7a6ae0a324b9f3d38debafbfb2ed0a114e4bbd357fb318f8f23438"
571 "language_info": {
572 "codemirror_mode": {
573 "name": "ipython",
574 "version": 2
575 },
576 "file_extension": ".py",
577 "mimetype": "text/x-python",
578 "name": "python",
579 "nbconvert_exporter": "python",
580 "pygments_lexer": "ipython2",
581 "version": "2.7.8"
582 }
577 583 },
578 584 "nbformat": 4,
579 585 "nbformat_minor": 0
580 } No newline at end of file
586 }
General Comments 0
You need to be logged in to leave comments. Login now