{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", "

Bokeh Tutorial

\n", "
\n", "\n", "

06. Bokeh Applications

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The architecture of Bokeh is such that high-level “model objects” (representing things like plots, ranges, axes, glyphs, etc.) are created in Python, and then converted to a JSON format that is consumed by the client library, BokehJS. Using the Bokeh Server, it is possible to keep the “model objects” in python and in the browser in sync with one another, creating powerful capabilities:\n", "\n", "* respond to UI and tool events generated in a browser with computations or queries using the full power of python\n", "* automatically push updates the UI (i.e. widgets or plots), in a browser\n", "* use periodic, timeout, and asychronous callbacks drive streaming updates\n", "\n", "***This capability to synchronize between python and the browser is the main purpose of the Bokeh Server.***" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
NOTE: Exercises below require work outside the notebook
" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Hello Bokeh\n", "\n", "To try out the example below, copy the code into a file ``hello.py`` and then execute:\n", "```bash\n", "bokeh serve --show hello.py \n", "```\n", "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "# hello.py \n", "\n", "from bokeh.io import curdoc\n", "from bokeh.layouts import column\n", "from bokeh.models.widgets import TextInput, Button, Paragraph\n", "\n", "# create some widgets\n", "button = Button(label=\"Say HI\")\n", "input = TextInput(value=\"Bokeh\")\n", "output = Paragraph()\n", "\n", "# add a callback to a widget\n", "def update():\n", " output.text = \"Hello, \" + input.value\n", "button.on_click(update)\n", "\n", "# create a layout for everything\n", "layout = column(button, input, output)\n", "\n", "# add the layout to curdoc\n", "curdoc().add_root(layout)\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's try an exercise to modify this example to add another widget. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# EXERCISE: add a Select widget to this example that offers several different greetings\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Linking Plots and Widgets\n", "\n", "To try out the example below, copy the code into a file ``app.py`` and then execute:\n", "```bash\n", "bokeh serve --show app.py\n", "```\n", "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "# app.py\n", "\n", "from numpy.random import random\n", "\n", "from bokeh.io import curdoc\n", "from bokeh.layouts import column, row\n", "from bokeh.plotting import ColumnDataSource, Figure\n", "from bokeh.models.widgets import Select, TextInput\n", "\n", "def get_data(N):\n", " return dict(x=random(size=N), y=random(size=N), r=random(size=N) * 0.03)\n", "\n", "source = ColumnDataSource(data=get_data(200))\n", "\n", "p = Figure(tools=\"\", toolbar_location=None)\n", "r = p.circle(x='x', y='y', radius='r', source=source,\n", " color=\"navy\", alpha=0.6, line_color=\"white\")\n", "\n", "COLORS = [\"black\", \"firebrick\", \"navy\", \"olive\", \"goldenrod\"]\n", "select = Select(title=\"Color\", value=\"navy\", options=COLORS)\n", "input = TextInput(title=\"Number of points\", value=\"200\")\n", "\n", "def update_color(attrname, old, new):\n", " r.glyph.fill_color = select.value\n", "select.on_change('value', update_color)\n", "\n", "def update_points(attrname, old, new):\n", " N = int(input.value)\n", " source.data = get_data(N)\n", "input.on_change('value', update_points)\n", "\n", "layout = column(row(select, input, width=400), row(p))\n", "\n", "curdoc().add_root(layout)\n", "```" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# EXERCISE: add more widgets to change more aspects of this plot\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Streaming Data\n", "\n", "It is possible to efficiently stream new data to column data sources by using the ``stream`` method. This method accepts two argmuments:\n", "* ``new_data`` — a dictionary with the same structure as the column data source\n", "* ``rollover`` — a maximum column length on the client (earlier data is dropped) *[optional]*\n", "\n", "If no ``rollover`` is specified, data is never dropped on the client and columns grow without bound.\n", "\n", "It is often useful to use periodic callbacks in conjuction with streaming data The ``add_periodic_callback`` method of ``curdoc()`` accepts a callback function, and a time interval (in ms) to repeatedly execute the callback. \n", "\n", "To try out the example below, copy the code into a file ``stream.py`` and then execute:\n", "```bash\n", "bokeh serve --show stream.py\n", "```\n", "----" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "# stream.py\n", "from math import cos, sin\n", "\n", "from bokeh.io import curdoc\n", "from bokeh.models import ColumnDataSource\n", "from bokeh.plotting import figure\n", "\n", "p = figure(x_range=(-1.1, 1.1), y_range=(-1.1, 1.1))\n", "p.circle(x=0, y=0, radius=1, fill_color=None, line_width=2)\n", "\n", "# this is the data source we will stream to\n", "source = ColumnDataSource(data=dict(x=[1], y=[0]))\n", "p.circle(x='x', y='y', size=12, fill_color='white', source=source)\n", "\n", "def update():\n", " x, y = source.data['x'][-1], source.data['y'][-1]\n", " \n", " # construct the new values for all columns, and pass to stream\n", " new_data = dict(x=[x*cos(0.1) - y*sin(0.1)], y=[x*sin(0.1) + y*cos(0.1)])\n", " source.stream(new_data, rollover=8)\n", "\n", "curdoc().add_periodic_callback(update, 150)\n", "curdoc().add_root(p)\n", "```" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "### EXERCISE: starting with the above example, create your own streaming plot\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Custom Page Templates \n", "\n", "*New in Bokeh 0.12*\n", "\n", "Custom Page Templates will allow you to specify a Jinja2 Template to use for the application page. With this capability, it is possible to deliver single page applications directly from the Bokeh server, without having to embed the Bokeh application in pages from a different server (Flask, Django, etc)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 0 }