{ "metadata": { "name": "", "signature": "sha256:3c6491f7b85ab03228c803b5b0d0c3516555638827c1f26dd9d0cd928cf346fd" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "IPython's builtin Widgets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "IPython 2.0 will ship with a basic set of Widgets. These Widget are designed to be lightweight so that users can quickly build interactive UIs for working with data. This is not Qt!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from IPython.html import widgets\n", "from IPython.display import display, clear_output" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is a list of the Widgets that IPython 2.0 will ship with:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "[widget for widget in dir(widgets) if widget.endswith('Widget')]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 2, "text": [ "['AccordionWidget',\n", " 'BoundedFloatTextWidget',\n", " 'BoundedIntTextWidget',\n", " 'ButtonWidget',\n", " 'CheckboxWidget',\n", " 'ContainerWidget',\n", " 'DOMWidget',\n", " 'DropdownWidget',\n", " 'FloatProgressWidget',\n", " 'FloatSliderWidget',\n", " 'FloatTextWidget',\n", " 'HTMLWidget',\n", " 'ImageWidget',\n", " 'IntProgressWidget',\n", " 'IntSliderWidget',\n", " 'IntTextWidget',\n", " 'LatexWidget',\n", " 'PopupWidget',\n", " 'RadioButtonsWidget',\n", " 'SelectWidget',\n", " 'TabWidget',\n", " 'TextWidget',\n", " 'TextareaWidget',\n", " 'ToggleButtonWidget',\n", " 'ToggleButtonsWidget',\n", " 'Widget']" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We are trying to cover the basic set of widgets that are needed as building blocks for more complicated user interfaces. In the long run, we plan on keeping the number of widgets that IPython ships relatively small. We will encourage the larger community to build and distribute more sophisticated custom widgets as separate projects." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Widget basics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is a slider widget whose value is a floating point number. Widgets have sensible default values:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "w = widgets.FloatSliderWidget()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Widgets can be displayed using IPython's `display` function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "display(w)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or by returning a widget as the result of an expression:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "w" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "From an MVC perspective, Python widgets are models. In reality, these models are instantiated automatically in both Python and JavaScript and the two sides are fully synchronized. When displayed, JavaScript based views (through [Backbone.js](http://backbonejs.org/)) are created for the models. Multiple views of the same model will be synchronized.\n", "\n", "The models have strongly typed data attributes. For example, slider widgets have a `.value` attribute that is a `float` and can be used to get or set the slider's value:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "w.value" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 6, "text": [ "0.0" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "w.value = 100.0" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "All widgets have a `.close()` method that removes their views from the page and cleans up the synchronization layer:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "w.close()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `.keys` attributes lists all of the attributes that will be synchronized with JavaScript:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "w.keys" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 9, "text": [ "['_view_name',\n", " 'orientation',\n", " 'min',\n", " 'max',\n", " '_css',\n", " 'value',\n", " 'readout',\n", " 'disabled',\n", " 'visible',\n", " 'step',\n", " 'description']" ] } ], "prompt_number": 9 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Events" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to define event handlers on both the JavaScript and Python sides. On the Python side, these handlers are registered using the `.on_trait_change()` method. On the JavaScript side Backbone.js or jQuery can be used.\n", "\n", "This example also shows how attributes (`min`, `max`, `step`) can be set in the constructor." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def on_value_change(name, value):\n", " print(value)\n", "\n", "int_range = widgets.IntSliderWidget(min=0, max=10, step=2)\n", "int_range.on_trait_change(on_value_change, 'value')\n", "display(int_range)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some widgets have specialized events, such as the `on_click` event of the `ButtonWidget`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def click_handler(widget):\n", " print \"clicked\"\n", "\n", "b = widgets.ButtonWidget(description='Click Me!')\n", "b.on_click(click_handler)\n", "display(b)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 11 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Containers and visibility" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "IPython widgets use an explicit, container based layout approach. The CSS Flexible Box Model provides the actual layout on the page. We offer a range of different containers, from simple containers, to tabs, etc.\n", "\n", "All widgets have a `.visible` attribute that can be used to hide and show the widget on the page." ] }, { "cell_type": "code", "collapsed": false, "input": [ "form = widgets.ContainerWidget()\n", "first = widgets.TextWidget(description=\"First Name:\")\n", "last = widgets.TextWidget(description=\"Last Name:\")\n", "\n", "student = widgets.CheckboxWidget(description=\"Student:\", value=False)\n", "school_info = widgets.ContainerWidget(visible=False, children=[\n", " widgets.TextWidget(description=\"School:\"),\n", " widgets.IntTextWidget(description=\"Grade:\", min=0, max=12)\n", " ])\n", "\n", "state = widgets.DropdownWidget(description='State:', values=['CA', 'OR', 'WA'])\n", "form.children = [first, last, student, school_info, state]\n", "display(form)\n", "\n", "def on_student_toggle(name, value):\n", " if value:\n", " school_info.visible = True\n", " else:\n", " school_info.visible = False\n", "student.on_trait_change(on_student_toggle, 'value')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "state.value" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 13, "text": [ "'CA'" ] } ], "prompt_number": 13 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Layout and CSS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some widgets, such as the various slider ones, have layout options.\n", "\n", "Most widgets are also subclasses of `DOMWidget` and offer methods for managing the CSS of the elements on the page:\n", "\n", "* `add_class`\n", "* `remove_class`\n", "* `set_css`\n", "\n", "In this case we create vertically oriented sliders using the Flexible Box Model." ] }, { "cell_type": "code", "collapsed": false, "input": [ "container = widgets.ContainerWidget()\n", "children = []\n", "for i in range(15):\n", " w = widgets.FloatSliderWidget(orientation='vertical', description=str(i+1), value=50.0)\n", " children.append(w)\n", "container.children = children\n", "display(container)\n", "container.remove_class('vbox')\n", "container.add_class('hbox')\n", "container.set_css('background','lightblue')\n", "container.set_css('border-radius', '10px')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }