##// END OF EJS Templates
Cleanup examples...
Jonathan Frederic -
Show More
@@ -0,0 +1,70 b''
1 {
2 "metadata": {
3 "name": ""
4 },
5 "nbformat": 3,
6 "nbformat_minor": 0,
7 "worksheets": [
8 {
9 "cells": [
10 {
11 "cell_type": "heading",
12 "level": 1,
13 "metadata": {},
14 "source": [
15 "Widgets"
16 ]
17 },
18 {
19 "cell_type": "markdown",
20 "metadata": {},
21 "source": [
22 "This directory includes a tutorial and collection of examples related to the IPython notebook widget framework."
23 ]
24 },
25 {
26 "cell_type": "heading",
27 "level": 2,
28 "metadata": {},
29 "source": [
30 "Tutorial"
31 ]
32 },
33 {
34 "cell_type": "markdown",
35 "metadata": {},
36 "source": [
37 "- [Part 1 - Basics](Part 1 - Basics.ipynb) \n",
38 "- [Part 2 - Events](Part 2 - Events.ipynb) \n",
39 "- [Part 3 - Placement](Part 3 - Placement.ipynb) \n",
40 "- [Part 4 - Styles](Part 4 - Styles.ipynb) \n",
41 "- [Part 5 - Alignment](Part 5 - Alignment.ipynb) \n",
42 "- [Part 6 - Custom Widget](Part 6 - Custom Widget.ipynb) "
43 ]
44 },
45 {
46 "cell_type": "heading",
47 "level": 2,
48 "metadata": {},
49 "source": [
50 "Examples"
51 ]
52 },
53 {
54 "cell_type": "markdown",
55 "metadata": {},
56 "source": [
57 "- [Widget Tester](Widget Tester.ipynb) \n",
58 "- [Variable Inspector](Variable Inspector.ipynb) \n",
59 "- [Export As (nbconvert)](Export As (nbconvert%29.ipynb) \n",
60 "- [Nonblocking Console](Nonblocking Console.ipynb) \n",
61 "- [D3](D3.ipynb) \n",
62 "- [File Upload Widget](File Upload Widget.ipynb) \n",
63 "- [Dialogs](Dialogs.ipynb) "
64 ]
65 }
66 ],
67 "metadata": {}
68 }
69 ]
70 } No newline at end of file
@@ -17,7 +17,9 b''
17 17 "cell_type": "markdown",
18 18 "metadata": {},
19 19 "source": [
20 "To use IPython widgets in the notebook, the widget namespace and optionally the display function need to be imported."
20 "[Index](index.ipynb)\n",
21 "\n",
22 "To use IPython widgets in the notebook, the widget namespace needs to be imported."
21 23 ]
22 24 },
23 25 {
@@ -126,7 +128,7 b''
126 128 "cell_type": "markdown",
127 129 "metadata": {},
128 130 "source": [
129 "The basic widgets can all be constructed without arguments. The following creates a FloatRangeWidget without displaying it"
131 "The basic widgets can all be constructed without arguments. The following creates a *FloatSliderWidget* without displaying it"
130 132 ]
131 133 },
132 134 {
@@ -297,6 +299,13 b''
297 299 }
298 300 ],
299 301 "prompt_number": 10
302 },
303 {
304 "cell_type": "markdown",
305 "metadata": {},
306 "source": [
307 "In [Part 2](Part 2 - Events.ipynb) of this [series](index.ipynb), you will learn about widget events."
308 ]
300 309 }
301 310 ],
302 311 "metadata": {}
@@ -14,6 +14,13 b''
14 14 {
15 15 "cells": [
16 16 {
17 "cell_type": "markdown",
18 "metadata": {},
19 "source": [
20 "[< Back to Part 1](Part 1 - Basics.ipynb) or [Index](index.ipynb)"
21 ]
22 },
23 {
17 24 "cell_type": "code",
18 25 "collapsed": false,
19 26 "input": [
@@ -39,7 +46,7 b''
39 46 "cell_type": "markdown",
40 47 "metadata": {},
41 48 "source": [
42 "The widget properties are IPython traitlets. Traitlets are eventful. To handle property value changes, the `on_trait_change` method of the widget can be used to register an event handling callback. The doc string for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional."
49 "As mentioned in Part 1, the widget properties are IPython traitlets. Traitlets are eventful. To handle property value changes, the `on_trait_change` method of the widget can be used to register an event handling callback. The doc string for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional."
43 50 ]
44 51 },
45 52 {
@@ -95,7 +102,7 b''
95 102 "- callback(trait_name, new_value)\n",
96 103 "- callback(trait_name, old_value, new_value)\n",
97 104 "\n",
98 "An example of how to output an IntRangeWiget's value as it is changed can be seen below."
105 "Using this method, an example of how to output an IntSliderWiget's value as it is changed can be seen below."
99 106 ]
100 107 },
101 108 {
@@ -157,7 +164,7 b''
157 164 "cell_type": "markdown",
158 165 "metadata": {},
159 166 "source": [
160 "The `ButtonWidget` is a special widget, like the `ContainerWidget` and `MulticontainerWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register a click even handler. The doc string of the `on_click` can be seen below."
167 "The `ButtonWidget` is a special widget, like the `ContainerWidget` and `TabWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register a click even handler. The doc string of the `on_click` can be seen below."
161 168 ]
162 169 },
163 170 {
@@ -264,6 +271,13 b''
264 271 "metadata": {},
265 272 "outputs": [],
266 273 "prompt_number": 6
274 },
275 {
276 "cell_type": "markdown",
277 "metadata": {},
278 "source": [
279 "In [Part 3](Part 3 - Placement.ipynb) of this [series](index.ipynb), you will learn about widget placement."
280 ]
267 281 }
268 282 ],
269 283 "metadata": {}
@@ -14,6 +14,13 b''
14 14 {
15 15 "cells": [
16 16 {
17 "cell_type": "markdown",
18 "metadata": {},
19 "source": [
20 "[< Back to Part 2](Part 2 - Events.ipynb) or [Index](index.ipynb)"
21 ]
22 },
23 {
17 24 "cell_type": "code",
18 25 "collapsed": false,
19 26 "input": [
@@ -37,7 +44,7 b''
37 44 "cell_type": "markdown",
38 45 "metadata": {},
39 46 "source": [
40 "To display widget A inside widget B, widget A must be a child of widget B. With IPython widgets, the widgets are instances that live in the back-end (usally Python). There can be multiple views displayed in the front-end that represent one widget in the backend. Each view can be displayed at a different time. Only one instance of any particular model can be child of another. In other words, *widget A* cannot have *widget B* listed twice in it's children list.\n",
47 "To display widget A inside widget B, widget A must be a child of widget B. Only one instance of any particular model can be child of another. In other words, *widget A* cannot have *widget B* listed twice in it's children list.\n",
41 48 "\n",
42 49 "Widgets that can contain other widgets have a `children` property. This property can be set via a kwarg in the widget's constructor or after construction. Calling display on an object with children automatically displays those children too (as seen below)."
43 50 ]
@@ -164,6 +171,13 b''
164 171 "metadata": {},
165 172 "outputs": [],
166 173 "prompt_number": 7
174 },
175 {
176 "cell_type": "markdown",
177 "metadata": {},
178 "source": [
179 "In [Part 4](Part 4 - Styles.ipynb) of this [series](index.ipynb), you will learn about widget styling."
180 ]
167 181 }
168 182 ],
169 183 "metadata": {}
@@ -14,6 +14,13 b''
14 14 {
15 15 "cells": [
16 16 {
17 "cell_type": "markdown",
18 "metadata": {},
19 "source": [
20 "[< Back to Part 3](Part 3 - Placement.ipynb) or [Index](index.ipynb)"
21 ]
22 },
23 {
17 24 "cell_type": "code",
18 25 "collapsed": false,
19 26 "input": [
@@ -37,7 +44,7 b''
37 44 "cell_type": "markdown",
38 45 "metadata": {},
39 46 "source": [
40 "When trying to design an attractive widget GUI, styling becomes important. Widget views are DOM (document object model) elements that can be controlled with CSS. There are two helper methods defined on widget that allow the manipulation of the widget's CSS. The first is the `set_css` method, whos doc string is displayed below. This method allows one or more CSS attributes to be set at once. "
47 "When trying to design an attractive widget GUI, styling becomes important. Most Widgets views are DOM (document object model) elements that can be controlled with CSS. There are two helper methods defined on widget that allow the manipulation of the widget's CSS. The first is the `set_css` method, whos doc string is displayed below. This method allows one or more CSS attributes to be set at once. "
41 48 ]
42 49 },
43 50 {
@@ -193,7 +200,7 b''
193 200 "cell_type": "markdown",
194 201 "metadata": {},
195 202 "source": [
196 "Since `add_class` if a DOM operation, it will only affect widgets that have been displayed. `add_class` must be called after the widget has been displayed. Extending the example above, the corners of the container can be rounded by adding the `corner-all` notebook class to the container (as seen below). "
203 "Since `add_class` if a DOM operation, **it will only affect widgets that have already been displayed**. `add_class` must be called after the widget has been displayed. Extending the example above, the corners of the container can be rounded by adding the `corner-all` notebook class to the container (as seen below). "
197 204 ]
198 205 },
199 206 {
@@ -272,7 +279,7 b''
272 279 "cell_type": "markdown",
273 280 "metadata": {},
274 281 "source": [
275 "It's also useful to be able to remove DOM classes from widgets. The `remove_class` widget method allows you to remove classes from widgets that have been displayed. Like `add_widget`, it must be called after the widget has been displayed. The doc string of `remove_class` can be seen below."
282 "It's also useful to be able to remove DOM classes from widgets. The `remove_class` widget method allows you to remove classes from widgets that have been displayed. Like `add_class`, it must be called after the widget has been displayed. The doc string of `remove_class` can be seen below."
276 283 ]
277 284 },
278 285 {
@@ -333,6 +340,13 b''
333 340 "metadata": {},
334 341 "outputs": [],
335 342 "prompt_number": 10
343 },
344 {
345 "cell_type": "markdown",
346 "metadata": {},
347 "source": [
348 "In [Part 5](Part 5 - Alignment.ipynb) of this [series](index.ipynb), you will learn about widget alignment."
349 ]
336 350 }
337 351 ],
338 352 "metadata": {}
@@ -14,6 +14,13 b''
14 14 {
15 15 "cells": [
16 16 {
17 "cell_type": "markdown",
18 "metadata": {},
19 "source": [
20 "[< Back to Part 4](Part 4 - Styles.ipynb) or [Index](index.ipynb)"
21 ]
22 },
23 {
17 24 "cell_type": "code",
18 25 "collapsed": false,
19 26 "input": [
@@ -107,7 +114,7 b''
107 114 "cell_type": "markdown",
108 115 "metadata": {},
109 116 "source": [
110 "`ContainerWidget`s allow for custom alignment of widgets. The `hbox` and `vbox` methods (parameterless) cause the `ContainerWidget` to both horizontally and vertically align its children. The following example compares `vbox` to `hbox`."
117 "`ContainerWidget`s allow for custom alignment of widgets. The `hbox` and `vbox` DOM classes cause the `ContainerWidget` to both horizontally and vertically align its children. The following example compares `vbox` to `hbox`."
111 118 ]
112 119 },
113 120 {
@@ -160,7 +167,7 b''
160 167 "cell_type": "markdown",
161 168 "metadata": {},
162 169 "source": [
163 "The `ContainerWidget` `pack_start`, `pack_center`, and `pack_end` methods (parameterless) adjust the alignment of the widgets on the axis that they are being rendered on. Below is an example of the different alignments."
170 "The `start`, `center`, and `end` DOM classes adjust the alignment of the widgets on the axis that they are being rendered on. Below is an example of the different alignments."
164 171 ]
165 172 },
166 173 {
@@ -191,7 +198,7 b''
191 198 "cell_type": "markdown",
192 199 "metadata": {},
193 200 "source": [
194 "The `ContainerWidget` `flex0`, `flex1`, and `flex2` methods (parameterless) modify the containers flexibility. Changing a container flexibility affects how and if the container will occupy the remaining space. Setting `flex0` has the same result as setting no flex. Below is an example of different flex configurations. The number on the boxes correspond to the applied flex."
201 "The `box-flex0`, `box-flex1`, and `box-flex2` DOM classes modify the container's flexibility. Changing a container flexibility affects how and if the container will occupy the remaining space. Applying `box-flex0` has the same result as not applying flex. Below is an example of different flex configurations. The number on the boxes correspond to the applied flex."
195 202 ]
196 203 },
197 204 {
@@ -249,7 +256,7 b''
249 256 "cell_type": "markdown",
250 257 "metadata": {},
251 258 "source": [
252 "The `ContainerWidget` `align_start`, `align_center`, and `align_end` methods (parameterless) adjust the alignment of the widgets on the axis perpindicular to the one that they are being rendered on. Below is an example of the different alignments."
259 "The `align_start`, `align_center`, and `align_end` DOM classes adjust the alignment of the widgets on the axis perpindicular to the one that they are being rendered on. Below is an example of the different alignments."
253 260 ]
254 261 },
255 262 {
@@ -305,6 +312,13 b''
305 312 "metadata": {},
306 313 "outputs": [],
307 314 "prompt_number": 9
315 },
316 {
317 "cell_type": "markdown",
318 "metadata": {},
319 "source": [
320 "In [Part 6](Part 6 - Custom Widget.ipynb) of this [series](index.ipynb), you will learn how to create your own custom widget."
321 ]
308 322 }
309 323 ],
310 324 "metadata": {}
@@ -17,6 +17,8 b''
17 17 "cell_type": "markdown",
18 18 "metadata": {},
19 19 "source": [
20 "[< Back to Part 5](Part 5 - Alignment.ipynb) or [Index](index.ipynb)\n",
21 "\n",
20 22 "Before reading, the author recommends the reader to review\n",
21 23 "\n",
22 24 "- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n",
@@ -31,32 +33,14 b''
31 33 "input": [
32 34 "from __future__ import print_function # For py 2.7 compat\n",
33 35 "\n",
34 "from IPython.html import widgets # Widget definitions\n",
35 "from IPython.display import display # Used to display widgets in the notebook"
36 ],
37 "language": "python",
38 "metadata": {},
39 "outputs": [],
40 "prompt_number": 19
41 },
42 {
43 "cell_type": "markdown",
44 "metadata": {},
45 "source": [
46 "The 3 part of this tutorial requires the 3rd party `dateutil` library. https://pypi.python.org/pypi/python-dateutil"
47 ]
48 },
49 {
50 "cell_type": "code",
51 "collapsed": false,
52 "input": [
53 "# Import the dateutil library to parse date strings.\n",
54 "from dateutil import parser"
36 "from IPython.html import widgets # Widget definitions.\n",
37 "from IPython.display import display # Used to display widgets in the notebook.\n",
38 "from IPython.utils.traitlets import Unicode # Used to declare properties of our widget."
55 39 ],
56 40 "language": "python",
57 41 "metadata": {},
58 42 "outputs": [],
59 "prompt_number": 20
43 "prompt_number": 1
60 44 },
61 45 {
62 46 "cell_type": "heading",
@@ -100,24 +84,19 b''
100 84 "cell_type": "code",
101 85 "collapsed": false,
102 86 "input": [
103 "# Import the base Widget class and the traitlets Unicode class.\n",
104 "from IPython.html.widgets import DOMWidget\n",
105 "from IPython.utils.traitlets import Unicode\n",
106 "\n",
107 "# Define our DateWidget and its target model and default view.\n",
108 "class DateWidget(DOMWidget):\n",
87 "class DateWidget(widgets.DOMWidget):\n",
109 88 " _view_name = Unicode('DatePickerView', sync=True)"
110 89 ],
111 90 "language": "python",
112 91 "metadata": {},
113 92 "outputs": [],
114 "prompt_number": 21
93 "prompt_number": 2
115 94 },
116 95 {
117 96 "cell_type": "markdown",
118 97 "metadata": {},
119 98 "source": [
120 "- **_view_name** is the default Backbone view to display when the user calls `display` to display an instance of this widget.\n"
99 "Our widget inherits from `widgets.DOMWidget` since it is intended that it will be displayed in the notebook directly. The `_view_name` trait is specially named, the widget framework will read the `_view_name` trait to determine what Backbone view the widget is associated with. **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."
121 100 ]
122 101 },
123 102 {
@@ -158,17 +137,17 b''
158 137 "metadata": {},
159 138 "output_type": "display_data",
160 139 "text": [
161 "<IPython.core.display.Javascript at 0x1e409d0>"
140 "<IPython.core.display.Javascript at 0x2a2e0d0>"
162 141 ]
163 142 }
164 143 ],
165 "prompt_number": 22
144 "prompt_number": 3
166 145 },
167 146 {
168 147 "cell_type": "markdown",
169 148 "metadata": {},
170 149 "source": [
171 "Now we need to define a view that can be used to represent the model. To do this, the `IPython.DOMWidgetView` is extended. A render function must be defined. The render function is used to render a widget view instance to the DOM. For now the render function renders a div that contains the text *Hello World!* Lastly, the view needs to be registered with the widget manager like the model was.\n",
150 "Now we need to define a view that can be used to represent the model. To do this, the `IPython.DOMWidgetView` is extended. A render function must be defined. The render function is used to render a widget view instance to the DOM. For now the render function renders a div that contains the text *Hello World!* Lastly, the view needs to be registered with the widget manager.\n",
172 151 "\n",
173 152 "**Final JavaScript code below:**"
174 153 ]
@@ -210,11 +189,11 b''
210 189 "metadata": {},
211 190 "output_type": "display_data",
212 191 "text": [
213 "<IPython.core.display.Javascript at 0x1e40a50>"
192 "<IPython.core.display.Javascript at 0x2a2e3d0>"
214 193 ]
215 194 }
216 195 ],
217 "prompt_number": 23
196 "prompt_number": 4
218 197 },
219 198 {
220 199 "cell_type": "heading",
@@ -240,7 +219,7 b''
240 219 "language": "python",
241 220 "metadata": {},
242 221 "outputs": [],
243 "prompt_number": 24
222 "prompt_number": 5
244 223 },
245 224 {
246 225 "cell_type": "heading",
@@ -262,26 +241,21 b''
262 241 "cell_type": "markdown",
263 242 "metadata": {},
264 243 "source": [
265 "In the last section we created a simple widget that displayed *Hello World!* To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model. The new property must be a traitlet property so the widget machinery can automatically handle it. The property needs to be constructed with a `sync=True` keyword argument so the widget machinery knows to syncronize it with the fron-end. Adding this to the code from the last section:"
244 "In the last section we created a simple widget that displayed *Hello World!* To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model. The new property must be a traitlet property so the widget machinery can automatically handle it. The property needs to be constructed with a `sync=True` keyword argument so the widget machinery knows to syncronize it with the front-end. Adding this to the code from the last section:"
266 245 ]
267 246 },
268 247 {
269 248 "cell_type": "code",
270 249 "collapsed": false,
271 250 "input": [
272 "# Import the base Widget class and the traitlets Unicode class.\n",
273 "from IPython.html.widgets import DOMWidget\n",
274 "from IPython.utils.traitlets import Unicode\n",
275 "\n",
276 "# Define our DateWidget and its target model and default view.\n",
277 "class DateWidget(DOMWidget):\n",
251 "class DateWidget(widgets.DOMWidget):\n",
278 252 " _view_name = Unicode('DatePickerView', sync=True)\n",
279 253 " value = Unicode(sync=True)"
280 254 ],
281 255 "language": "python",
282 256 "metadata": {},
283 257 "outputs": [],
284 "prompt_number": 25
258 "prompt_number": 6
285 259 },
286 260 {
287 261 "cell_type": "heading",
@@ -295,7 +269,7 b''
295 269 "cell_type": "markdown",
296 270 "metadata": {},
297 271 "source": [
298 "In the JavaScript there is no need to define the same properties in the JavaScript model. When the JavaScript model is created for the first time, it copies all of the attributes from the Python model. We need to replace *Hello World!* with an actual HTML date picker widget."
272 "In the JavaScript there is no need to define counterparts to the traitlets. When the JavaScript model is created for the first time, it copies all of the traitlet `sync=True` attributes from the Python model. We need to replace *Hello World!* with an actual HTML date picker widget."
299 273 ]
300 274 },
301 275 {
@@ -347,11 +321,11 b''
347 321 "metadata": {},
348 322 "output_type": "display_data",
349 323 "text": [
350 "<IPython.core.display.Javascript at 0x1e40810>"
324 "<IPython.core.display.Javascript at 0x2a2e6d0>"
351 325 ]
352 326 }
353 327 ],
354 "prompt_number": 26
328 "prompt_number": 7
355 329 },
356 330 {
357 331 "cell_type": "markdown",
@@ -423,11 +397,11 b''
423 397 "metadata": {},
424 398 "output_type": "display_data",
425 399 "text": [
426 "<IPython.core.display.Javascript at 0x1e40390>"
400 "<IPython.core.display.Javascript at 0x2a2e090>"
427 401 ]
428 402 }
429 403 ],
430 "prompt_number": 27
404 "prompt_number": 8
431 405 },
432 406 {
433 407 "cell_type": "markdown",
@@ -521,11 +495,11 b''
521 495 "metadata": {},
522 496 "output_type": "display_data",
523 497 "text": [
524 "<IPython.core.display.Javascript at 0x1e40890>"
498 "<IPython.core.display.Javascript at 0x2a2e750>"
525 499 ]
526 500 }
527 501 ],
528 "prompt_number": 28
502 "prompt_number": 9
529 503 },
530 504 {
531 505 "cell_type": "heading",
@@ -552,7 +526,7 b''
552 526 "language": "python",
553 527 "metadata": {},
554 528 "outputs": [],
555 "prompt_number": 29
529 "prompt_number": 10
556 530 },
557 531 {
558 532 "cell_type": "markdown",
@@ -570,7 +544,7 b''
570 544 "language": "python",
571 545 "metadata": {},
572 546 "outputs": [],
573 "prompt_number": 30
547 "prompt_number": 11
574 548 },
575 549 {
576 550 "cell_type": "markdown",
@@ -591,13 +565,13 b''
591 565 {
592 566 "metadata": {},
593 567 "output_type": "pyout",
594 "prompt_number": 31,
568 "prompt_number": 12,
595 569 "text": [
596 "u''"
570 "u'2014-01-01'"
597 571 ]
598 572 }
599 573 ],
600 "prompt_number": 31
574 "prompt_number": 12
601 575 },
602 576 {
603 577 "cell_type": "markdown",
@@ -615,7 +589,7 b''
615 589 "language": "python",
616 590 "metadata": {},
617 591 "outputs": [],
618 "prompt_number": 32
592 "prompt_number": 13
619 593 },
620 594 {
621 595 "cell_type": "heading",
@@ -629,6 +603,25 b''
629 603 "cell_type": "markdown",
630 604 "metadata": {},
631 605 "source": [
606 "The 3rd party `dateutil` library is required to continue. https://pypi.python.org/pypi/python-dateutil"
607 ]
608 },
609 {
610 "cell_type": "code",
611 "collapsed": false,
612 "input": [
613 "# Import the dateutil library to parse date strings.\n",
614 "from dateutil import parser"
615 ],
616 "language": "python",
617 "metadata": {},
618 "outputs": [],
619 "prompt_number": 14
620 },
621 {
622 "cell_type": "markdown",
623 "metadata": {},
624 "source": [
632 625 "In the last section we created a fully working date picker widget. Now we will add custom validation and support for labels. Currently only the ISO date format \"YYYY-MM-DD\" is supported. We will add support for all of the date formats recognized by the 3rd party Python dateutil library."
633 626 ]
634 627 },
@@ -644,96 +637,61 b''
644 637 "cell_type": "markdown",
645 638 "metadata": {},
646 639 "source": [
647 "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. We can take advantage of this to perform validation and parsing of different date string formats. Below a method that listens to value has been added to the DateWidget."
640 "The standard property name used for widget labels is `description`. In the code block below, `description` has been added to the Python widget."
648 641 ]
649 642 },
650 643 {
651 644 "cell_type": "code",
652 645 "collapsed": false,
653 646 "input": [
654 "# Import the base Widget class and the traitlets Unicode class.\n",
655 "from IPython.html.widgets import DOMWidget\n",
656 "from IPython.utils.traitlets import Unicode\n",
657 "\n",
658 "# Define our DateWidget and its target model and default view.\n",
659 "class DateWidget(DOMWidget):\n",
647 "class DateWidget(widgets.DOMWidget):\n",
660 648 " _view_name = Unicode('DatePickerView', sync=True)\n",
661 649 " value = Unicode(sync=True)\n",
662 " \n",
663 " # This function automatically gets called by the traitlet machinery when\n",
664 " # value is modified because of this function's name.\n",
665 " def _value_changed(self, name, old_value, new_value):\n",
666 " pass\n",
667 " "
650 " description = Unicode(sync=True)"
668 651 ],
669 652 "language": "python",
670 653 "metadata": {},
671 654 "outputs": [],
672 "prompt_number": 33
655 "prompt_number": 15
673 656 },
674 657 {
675 658 "cell_type": "markdown",
676 659 "metadata": {},
677 660 "source": [
678 "Now the function that parses the date string and only sets it in the correct format can be added."
661 "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. We can take advantage of this to perform validation and parsing of different date string formats. Below a method that listens to value has been added to the DateWidget."
679 662 ]
680 663 },
681 664 {
682 665 "cell_type": "code",
683 666 "collapsed": false,
684 667 "input": [
685 "# Import the dateutil library to parse date strings.\n",
686 "from dateutil import parser\n",
687 "\n",
688 "# Import the base Widget class and the traitlets Unicode class.\n",
689 "from IPython.html.widgets import DOMWidget\n",
690 "from IPython.utils.traitlets import Unicode\n",
691 "\n",
692 "# Define our DateWidget and its target model and default view.\n",
693 "class DateWidget(DOMWidget):\n",
668 "class DateWidget(widgets.DOMWidget):\n",
694 669 " _view_name = Unicode('DatePickerView', sync=True)\n",
695 670 " value = Unicode(sync=True)\n",
671 " description = Unicode(sync=True)\n",
696 672 " \n",
697 673 " # This function automatically gets called by the traitlet machinery when\n",
698 674 " # value is modified because of this function's name.\n",
699 675 " def _value_changed(self, name, old_value, new_value):\n",
700 " \n",
701 " # Parse the date time value.\n",
702 " try:\n",
703 " parsed_date = parser.parse(new_value)\n",
704 " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
705 " except:\n",
706 " parsed_date_string = ''\n",
707 " \n",
708 " # Set the parsed date string if the current date string is different.\n",
709 " if self.value != parsed_date_string:\n",
710 " self.value = parsed_date_string"
676 " pass"
711 677 ],
712 678 "language": "python",
713 679 "metadata": {},
714 680 "outputs": [],
715 "prompt_number": 34
681 "prompt_number": 16
716 682 },
717 683 {
718 684 "cell_type": "markdown",
719 685 "metadata": {},
720 686 "source": [
721 "The standard property name used for widget labels is `description`. In the code block below, `description` has been added to the Python widget."
687 "Now the function that parses the date string and only sets it in the correct format can be added."
722 688 ]
723 689 },
724 690 {
725 691 "cell_type": "code",
726 692 "collapsed": false,
727 693 "input": [
728 "# Import the dateutil library to parse date strings.\n",
729 "from dateutil import parser\n",
730 "\n",
731 "# Import the base Widget class and the traitlets Unicode class.\n",
732 "from IPython.html.widgets import DOMWidget\n",
733 "from IPython.utils.traitlets import Unicode\n",
734 "\n",
735 "# Define our DateWidget and its target model and default view.\n",
736 "class DateWidget(DOMWidget):\n",
694 "class DateWidget(widgets.DOMWidget):\n",
737 695 " _view_name = Unicode('DatePickerView', sync=True)\n",
738 696 " value = Unicode(sync=True)\n",
739 697 " description = Unicode(sync=True)\n",
@@ -756,13 +714,13 b''
756 714 "language": "python",
757 715 "metadata": {},
758 716 "outputs": [],
759 "prompt_number": 35
717 "prompt_number": 17
760 718 },
761 719 {
762 720 "cell_type": "markdown",
763 721 "metadata": {},
764 722 "source": [
765 "Finally, a callback list is added so the user can perform custom validation. If any one of the callbacks returns False, the new date time is not set.\n",
723 "Finally, a `CallbackDispatcher` is added so the user can perform custom validation. If any one of the callbacks registered with the dispatcher returns False, the new date time is not set.\n",
766 724 "\n",
767 725 "**Final Python code below:**"
768 726 ]
@@ -771,15 +729,7 b''
771 729 "cell_type": "code",
772 730 "collapsed": false,
773 731 "input": [
774 "# Import the dateutil library to parse date strings.\n",
775 "from dateutil import parser\n",
776 "\n",
777 "# Import the base Widget class and the traitlets Unicode class.\n",
778 "from IPython.html.widgets import DOMWidget, CallbackDispatcher\n",
779 "from IPython.utils.traitlets import Unicode\n",
780 "\n",
781 "# Define our DateWidget and its target model and default view.\n",
782 "class DateWidget(DOMWidget):\n",
732 "class DateWidget(widgets.DOMWidget):\n",
783 733 " _view_name = Unicode('DatePickerView', sync=True)\n",
784 734 " value = Unicode(sync=True)\n",
785 735 " description = Unicode(sync=True)\n",
@@ -790,7 +740,7 b''
790 740 " # Specify the number of positional arguments supported. For \n",
791 741 " # validation we only are worried about one parameter, the\n",
792 742 " # new value that should be validated.\n",
793 " self.validation = CallbackDispatcher(acceptable_nargs=[1])\n",
743 " self.validation = widgets.CallbackDispatcher(acceptable_nargs=[1])\n",
794 744 " \n",
795 745 " # This function automatically gets called by the traitlet machinery when\n",
796 746 " # value is modified because of this function's name.\n",
@@ -817,7 +767,7 b''
817 767 "language": "python",
818 768 "metadata": {},
819 769 "outputs": [],
820 "prompt_number": 45
770 "prompt_number": 18
821 771 },
822 772 {
823 773 "cell_type": "heading",
@@ -953,11 +903,11 b''
953 903 "metadata": {},
954 904 "output_type": "display_data",
955 905 "text": [
956 "<IPython.core.display.Javascript at 0x1efe210>"
906 "<IPython.core.display.Javascript at 0x2a5a6d0>"
957 907 ]
958 908 }
959 909 ],
960 "prompt_number": 40
910 "prompt_number": 19
961 911 },
962 912 {
963 913 "cell_type": "heading",
@@ -989,7 +939,7 b''
989 939 "language": "python",
990 940 "metadata": {},
991 941 "outputs": [],
992 "prompt_number": 46
942 "prompt_number": 20
993 943 },
994 944 {
995 945 "cell_type": "markdown",
@@ -1012,7 +962,7 b''
1012 962 "language": "python",
1013 963 "metadata": {},
1014 964 "outputs": [],
1015 "prompt_number": 47
965 "prompt_number": 21
1016 966 },
1017 967 {
1018 968 "cell_type": "code",
@@ -1024,7 +974,7 b''
1024 974 "language": "python",
1025 975 "metadata": {},
1026 976 "outputs": [],
1027 "prompt_number": 48
977 "prompt_number": 22
1028 978 },
1029 979 {
1030 980 "cell_type": "code",
@@ -1036,7 +986,7 b''
1036 986 "language": "python",
1037 987 "metadata": {},
1038 988 "outputs": [],
1039 "prompt_number": 49
989 "prompt_number": 23
1040 990 },
1041 991 {
1042 992 "cell_type": "code",
@@ -1050,13 +1000,20 b''
1050 1000 {
1051 1001 "metadata": {},
1052 1002 "output_type": "pyout",
1053 "prompt_number": 50,
1003 "prompt_number": 24,
1054 1004 "text": [
1055 1005 "u'2014-12-02'"
1056 1006 ]
1057 1007 }
1058 1008 ],
1059 "prompt_number": 50
1009 "prompt_number": 24
1010 },
1011 {
1012 "cell_type": "markdown",
1013 "metadata": {},
1014 "source": [
1015 "This concludes Part 6 of the [series](index.ipynb)."
1016 ]
1060 1017 }
1061 1018 ],
1062 1019 "metadata": {}
General Comments 0
You need to be logged in to leave comments. Login now