├── tutorial ├── assets │ ├── __init__.py │ ├── bokeh-transparent.png │ ├── 5_gaussians_3_ways.png │ ├── 5_gaussians_dsblue.png │ ├── 5_gaussians_labeled.png │ ├── datashader_examples.png │ └── document.svg ├── .gitignore ├── environment.yml ├── README.md ├── A4 - Additional Resources.ipynb ├── 11 - Running Bokeh Applictions.ipynb ├── 08 - Graph and Network Plots.ipynb ├── 09 - Geographic Plots.ipynb └── 04 - Data Sources and Transformations.ipynb ├── quickstart └── .gitignore ├── images ├── bokeh-header.png └── bokeh-transparent.png ├── .gitignore ├── README.md ├── LICENSE.txt └── index.ipynb /tutorial/assets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quickstart/.gitignore: -------------------------------------------------------------------------------- 1 | barplot.html 2 | -------------------------------------------------------------------------------- /tutorial/.gitignore: -------------------------------------------------------------------------------- 1 | plot.html 2 | plot.png 3 | plot.svg 4 | -------------------------------------------------------------------------------- /images/bokeh-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataXujing/bokeh-notebooks/master/images/bokeh-header.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | .ipynb_checkpoints/. 3 | .ipynb_checkpoints/ 4 | 5 | .ropeproject 6 | __pycache__ 7 | -------------------------------------------------------------------------------- /images/bokeh-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataXujing/bokeh-notebooks/master/images/bokeh-transparent.png -------------------------------------------------------------------------------- /tutorial/assets/bokeh-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataXujing/bokeh-notebooks/master/tutorial/assets/bokeh-transparent.png -------------------------------------------------------------------------------- /tutorial/assets/5_gaussians_3_ways.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataXujing/bokeh-notebooks/master/tutorial/assets/5_gaussians_3_ways.png -------------------------------------------------------------------------------- /tutorial/assets/5_gaussians_dsblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataXujing/bokeh-notebooks/master/tutorial/assets/5_gaussians_dsblue.png -------------------------------------------------------------------------------- /tutorial/assets/5_gaussians_labeled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataXujing/bokeh-notebooks/master/tutorial/assets/5_gaussians_labeled.png -------------------------------------------------------------------------------- /tutorial/assets/datashader_examples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataXujing/bokeh-notebooks/master/tutorial/assets/datashader_examples.png -------------------------------------------------------------------------------- /tutorial/environment.yml: -------------------------------------------------------------------------------- 1 | name: bokeh-notebooks 2 | dependencies: 3 | - python 4 | - bokeh=0.12.2 5 | - pandas 6 | - jupyter 7 | - nodejs 8 | - ipywidgets 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bokeh in Jupyter Notebooks 2 | ========================== 3 | 4 | Welcome to [Bokeh](https://bokeh.pydata.org/) in Jupyter Notebooks! 5 | 6 | Bokeh is a Python interactive visualization library for large datasets that 7 | natively uses the latest web technologies. Its goal is to provide elegant, 8 | concise construction of novel graphics in the style of Protovis/D3, while 9 | delivering high-performance interactivity over large data to thin clients. 10 | 11 | These Jupyter notebooks provide useful Bokeh examples and a tutorial to get 12 | started. You can visualize the rendered Jupyter notebooks 13 | [on NBViewer](http://nbviewer.ipython.org/github/bokeh/bokeh-notebooks) or 14 | download the repository and execute `jupyter notebook` from your terminal. 15 | 16 | Please visit the [Bokeh web page](https://bokeh.pydata.org/en/latest) for 17 | more information and full documentation. 18 | 19 | Be sure to follow us on Twitter @BokehPlots! 20 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Continuum Analytics, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | Neither the name of Continuum Analytics nor the names of any contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 | THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /tutorial/README.md: -------------------------------------------------------------------------------- 1 | ## Clone or download the repo 2 | First get local copies of the tutorial notebooks: 3 | 4 | ``` 5 | $ git clone https://github.com/bokeh/bokeh-notebooks.git 6 | ``` 7 | 8 | Or download from: https://github.com/bokeh/bokeh-notebooks/archive/master.zip 9 | 10 | ## Install the dependencies 11 | 12 | This tutorial has been tested on: 13 | 14 | * bokeh 0.12.7 15 | * pandas 0.20.3 16 | * notebook 5.0.0 17 | * phantomjs 2.1.1 18 | * pillow 4.2.1 19 | * selenium 3.5.0 20 | 21 | Other combinations may work also. 22 | 23 | The quickest, easiest way to install is to use Anaconda (or Miniconda): 24 | 25 | #### Installing with anaconda 26 | 27 | Install [anaconda](http://anaconda.com/downloads) 28 | 29 | Anaconda should come with all the dependencies included, but you may need to update your versions. 30 | 31 | #### Installing with miniconda 32 | 33 | Install [miniconda](http://conda.pydata.org/miniconda.html). 34 | 35 | Use the command line to create an environment and install the packages: 36 | 37 | ```bash 38 | $ conda env create 39 | $ source activate bokeh-notebooks 40 | ``` 41 | 42 | NOTE: Run this in the `tutorial` directory where `environment.yml` file is. 43 | 44 | ---- 45 | 46 | Once you've got a base install, you can install the remaining dependencies with: 47 | 48 | ```bash 49 | conda install phantomjs pillow selenium 50 | ``` 51 | 52 | ## Get the sample data 53 | 54 | Bokeh has a sample data download that gives us some data to build demo visualizations. To get 55 | it run the following command at your command line: 56 | 57 | ```bash 58 | $ bokeh sampledata 59 | ``` 60 | 61 | ### Install Datashader and Holoviews (optional) 62 | 63 | Some optional sections require the additional packages Flask, Datashader, and Holoviews. 64 | These can be installed with: 65 | 66 | ```bash 67 | $ conda install -c datashader holoviews flask 68 | ``` 69 | 70 | ## Run the Jupyter notebook 71 | 72 | From this folder run jupyter notebook, and open the [00 - Introduction and Setup.ipynb](00 - Introduction and Setup.ipynb) notebook. 73 | 74 | ``` 75 | $ jupyter notebook 76 | ``` 77 | -------------------------------------------------------------------------------- /index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "
\n", 8 | "\n", 9 | "
" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Welcome to [Bokeh](http://bokeh.pydata.org/en/latest) in the Jupyter Notebook!\n", 17 | "\n", 18 | "Bokeh is a Python interactive visualization library that targets modern web browsers for presentation. Its goal is to provide elegant, concise construction of novel graphics in the style of D3.js, and to extend this capability with high-performance interactivity over very large or streaming datasets. Bokeh can help anyone who would like to quickly and easily create interactive plots, dashboards, and data applications." 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "## Quickstart\n", 26 | "\n", 27 | "Get started with a [5-min introduction to Bokeh](quickstart/quickstart.ipynb)." 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "## Tutorial\n", 35 | "\n", 36 | "Start with the [Introduction and Setup](tutorial/00%20-%20Introduction%20and%20Setup.ipynb) notebook and jump to any of the specific topic sections from there." 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "## More information\n", 44 | "\n", 45 | "For the full documentation, see http://bokeh.pydata.org/en/latest\n", 46 | "\n", 47 | "To see the Bokeh source code, visit the GitHub repository: https://github.com/bokeh/bokeh \n", 48 | "\n", 49 | "Be sure to follow us on Twitter [@BokehPlots](http://twitter.com/BokehPlots) as well as on [Youtube](https://www.youtube.com/channel/UCK0rSk29mmg4UT4bIOvPYhw)!" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "## Contact\n", 57 | "\n", 58 | "For questions, please join the [Bokeh mailing list](https://groups.google.com/a/anaconda.com/forum/#!forum/bokeh) or visit the [Gitter chat room](https://gitter.im/bokeh/bokeh)\n", 59 | "\n", 60 | "You can also ask questions on StackOverflow and use the [``#bokeh``](http://stackoverflow.com/questions/tagged/bokeh) tag.\n", 61 | "\n", 62 | "For information about commercial development, custom visualization development or embedding Bokeh in your applications, please contact [sales@anaconda.com](mailto:sales@anaconda.com)\n", 63 | "\n", 64 | "To donate funds to support the development of Bokeh, please contact [info@pydata.org](mailto:info@pydata.org)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "## Thanks\n", 72 | "\n", 73 | "Bokeh is developed with financial support from [Anaconda, Inc.](https://anaconda.com) as well as individual community contributions. Many thanks to [all of the Bokeh Github contributors](https://github.com/bokeh/bokeh/graphs/contributors)." 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "" 89 | ] 90 | } 91 | ], 92 | "metadata": { 93 | "kernelspec": { 94 | "display_name": "Python 3", 95 | "language": "python", 96 | "name": "python3" 97 | }, 98 | "language_info": { 99 | "codemirror_mode": { 100 | "name": "ipython", 101 | "version": 3 102 | }, 103 | "file_extension": ".py", 104 | "mimetype": "text/x-python", 105 | "name": "python", 106 | "nbconvert_exporter": "python", 107 | "pygments_lexer": "ipython3", 108 | "version": "3.6.2" 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 1 113 | } 114 | -------------------------------------------------------------------------------- /tutorial/A4 - Additional Resources.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | " \n", 9 | " \n", 17 | " \n", 20 | " \n", 21 | "
\n", 10 | " \n", 11 | " \n", 15 | " \n", 16 | " \n", 18 | "

Bokeh Tutorial

\n", 19 | "
\n", 22 | "

A4. Additional resources

" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "# Additional resources\n", 30 | "\n", 31 | "There are lots of things we haven't had time to tell you about. In general to learn more about bokeh, the following resources will hopefully be helpful:\n", 32 | "\n" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "## Doumentation\n", 40 | "\n", 41 | "\n", 42 | "##### Main Page - https://bokeh.pydata.org/en/latest \n", 43 | "\n", 44 | "The main documentation front page, with links to many other resources\n", 45 | "\n", 46 | "---\n", 47 | "\n", 48 | "##### User's Guide - https://bokeh.pydata.org/en/latest/docs/user_guide.html\n", 49 | "\n", 50 | "The user's guide has many top-oriented subsections, for example \"Plotting with Basic Glyphs\", \"Configuring Plot Tools\", or \"Adding Interactions\". Each user's guide section typically example code and corresponding live plots that demonstrate how to accomplish various tasks. \n", 51 | "\n", 52 | "---\n", 53 | "\n", 54 | "##### Gallery - https://bokeh.pydata.org/en/latest/docs/gallery.html\n", 55 | "\n", 56 | "One of the best ways to learn is to find an existing example similar to what you want, and to study it and then use it as a starting place. Starting from a known working example can often save time and effort when getting started by allowing you to make small, incremental changes and observing the outcome. The Bokeh docs have a large thumbnail gallery that links to live plots and apps with corresponding code. \n", 57 | "\n", 58 | "\n", 59 | "---\n", 60 | "\n", 61 | "##### Reference Guide - https://bokeh.pydata.org/en/latest/docs/reference.html\n", 62 | "\n", 63 | "If you are already familiar with Bokeh and have questions about specific details of the obejcts you are already using, the reference guide is a good resource for finding information. The reference guide is automatically generated from the project source code and is a complete resources for all bokeh models and their properties. \n", 64 | "\n", 65 | "---\n", 66 | "\n", 67 | "##### Search page - https://bokeh.pydata.org/en/latest/search.html\n", 68 | "\n", 69 | "If you want to search the Bokeh docs, the search page on the site is the best place. General web searches can sometime return results for old versions or out of date information. The site search always returns information for the latest version, and results for any older versions in separate tabs. \n", 70 | "\n", 71 | "---\n", 72 | "\n", 73 | "##### Issue tracker - https://github.com/bokeh/bokeh/issues\n", 74 | "\n", 75 | "The GitHub issue tracker is the place to go to submit ***bug reports*** and ***feature requests***. It it NOT the right place for general support questions (see the *General Community Support* links below).\n", 76 | "\n" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": { 82 | "collapsed": true 83 | }, 84 | "source": [ 85 | "## Example apps and Scripts\n", 86 | "\n", 87 | "In addition to all the live gallery examples, Bokeh has many additional scripts and apps that can be instructive to study and emulate. \n", 88 | "\n", 89 | "##### Examples folder - https://github.com/bokeh/bokeh/tree/master/examples/\n", 90 | "\n", 91 | "The `examples` directory has many subfolders dedicated to different kinds of topics. Some of the hightlights are:\n", 92 | "\n", 93 | "* `app` - example Bokeh apps, run with \"`bokeh serve`\"\n", 94 | "* `howto` - some examples arranged around specific topics such as layout or notebook comms\n", 95 | "* `plotting` - a large collections of examples using the `bokeh.plotting` interface\n", 96 | "* `webgl` - some examples demonstrating WebGL usage\n", 97 | "\n", 98 | "---\n", 99 | "\n", 100 | "##### Example zipfile\n", 101 | "\n", 102 | "To make the things easier to obtain, a zip file of just the examples is also available at\n", 103 | "\n", 104 | "`https://cdn.pydata.org/bokeh/examples/examples-.zip`\n", 105 | "\n", 106 | "For example, the examples zipfile for the `0.12.7` release can be found at:\n", 107 | "\n", 108 | "https://cdn.pydata.org/bokeh/examples/examples-0.12.7.zip\n", 109 | "\n", 110 | "\n" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "## General Commnity Support\n", 118 | "\n", 119 | "Bokeh has a large and growing community. The best place to go for general support questions (either to ask, or to answer!) is one of the community support resources listed below. \n", 120 | "\n", 121 | "* Mailing list - https://groups.google.com/a/anaconda.com/forum/#!forum/bokeh\n", 122 | "* Gitter chat channel - https://gitter.im/bokeh/bokeh\n", 123 | "* StackOverflow (use `#bokeh` tag): http://stackoverflow.com/questions/tagged/bokeh\n", 124 | "\n" 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "## Contributor Resources\n", 132 | "\n", 133 | "Bokeh has a small but growinf developer community. We are always looking to have new contributors. Below are some resources for people involved in working on Bokeh itself.\n", 134 | "\n", 135 | "##### Source code - https://github.com/bokeh/bokeh\n", 136 | "\n", 137 | "Go here to clone the GitHub repo (in order to contribute or get the examples), or to submit issues to the issue tracker \n", 138 | "\n", 139 | "---\n", 140 | "\n", 141 | "##### Issue tracker - https://github.com/bokeh/bokeh/issues\n", 142 | "\n", 143 | "The GitHub issue tracker is the place to go to submit ***bug reports*** and ***feature requests***. For general support questions, see the *General Community Support* links above.\n", 144 | "\n", 145 | "---\n", 146 | "\n", 147 | "#### Developer's Guide - https://bokeh.pydata.org/en/latest/docs/dev_guide.html\n", 148 | "\n", 149 | "If you are interesting in becoming a contributor to Bokeh, the developer's guide is the place to start. It has information about getting a development environment set up, the library architecture, writing and running tests, \n", 150 | "\n", 151 | "---\n", 152 | "\n", 153 | "#### Dev Chat Channel - https://gitter.im/bokeh/bokeh-dev\n", 154 | "\n", 155 | "Come here for assistance with any questions about developing Bokeh itself. \n" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": null, 161 | "metadata": { 162 | "collapsed": true 163 | }, 164 | "outputs": [], 165 | "source": [] 166 | } 167 | ], 168 | "metadata": { 169 | "kernelspec": { 170 | "display_name": "Python 3", 171 | "language": "python", 172 | "name": "python3" 173 | }, 174 | "language_info": { 175 | "codemirror_mode": { 176 | "name": "ipython", 177 | "version": 3 178 | }, 179 | "file_extension": ".py", 180 | "mimetype": "text/x-python", 181 | "name": "python", 182 | "nbconvert_exporter": "python", 183 | "pygments_lexer": "ipython3", 184 | "version": "3.6.2" 185 | } 186 | }, 187 | "nbformat": 4, 188 | "nbformat_minor": 1 189 | } 190 | -------------------------------------------------------------------------------- /tutorial/11 - Running Bokeh Applictions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | " \n", 9 | " \n", 17 | " \n", 20 | " \n", 21 | "
\n", 10 | " \n", 11 | " \n", 15 | " \n", 16 | " \n", 18 | "

Bokeh Tutorial

\n", 19 | "
\n", 22 | "\n", 23 | "

11. Running Bokeh Applications

" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "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", 31 | "\n", 32 | "* respond to UI and tool events generated in a browser with computations or queries using the full power of python\n", 33 | "* automatically push updates the UI (i.e. widgets or plots), in a browser\n", 34 | "* use periodic, timeout, and asychronous callbacks drive streaming updates\n", 35 | "\n", 36 | "***This capability to synchronize between python and the browser is the main purpose of the Bokeh Server.***" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "
NOTE: Exercises below require work outside the notebook
" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": { 49 | "collapsed": true 50 | }, 51 | "source": [ 52 | "# Hello Bokeh\n", 53 | "\n", 54 | "To try out the example below, copy the code into a file ``hello.py`` and then execute:\n", 55 | "```bash\n", 56 | "bokeh serve --show hello.py \n", 57 | "```\n", 58 | "----" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "```python\n", 66 | "# hello.py \n", 67 | "\n", 68 | "from bokeh.io import curdoc\n", 69 | "from bokeh.layouts import column\n", 70 | "from bokeh.models.widgets import TextInput, Button, Paragraph\n", 71 | "\n", 72 | "# create some widgets\n", 73 | "button = Button(label=\"Say HI\")\n", 74 | "input = TextInput(value=\"Bokeh\")\n", 75 | "output = Paragraph()\n", 76 | "\n", 77 | "# add a callback to a widget\n", 78 | "def update():\n", 79 | " output.text = \"Hello, \" + input.value\n", 80 | "button.on_click(update)\n", 81 | "\n", 82 | "# create a layout for everything\n", 83 | "layout = column(button, input, output)\n", 84 | "\n", 85 | "# add the layout to curdoc\n", 86 | "curdoc().add_root(layout)\n", 87 | "```" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "Let's try an exercise to modify this example to add another widget. " 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 1, 100 | "metadata": { 101 | "collapsed": true 102 | }, 103 | "outputs": [], 104 | "source": [ 105 | "# EXERCISE: add a Select widget to this example that offers several different greetings\n", 106 | "\n" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "# Linking Plots and Widgets\n", 114 | "\n", 115 | "To try out the example below, copy the code into a file ``app.py`` and then execute:\n", 116 | "```bash\n", 117 | "bokeh serve --show app.py\n", 118 | "```\n", 119 | "----" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "```python\n", 127 | "# app.py\n", 128 | "\n", 129 | "from numpy.random import random\n", 130 | "\n", 131 | "from bokeh.io import curdoc\n", 132 | "from bokeh.layouts import column, row\n", 133 | "from bokeh.plotting import ColumnDataSource, Figure\n", 134 | "from bokeh.models.widgets import Select, TextInput\n", 135 | "\n", 136 | "def get_data(N):\n", 137 | " return dict(x=random(size=N), y=random(size=N), r=random(size=N) * 0.03)\n", 138 | "\n", 139 | "source = ColumnDataSource(data=get_data(200))\n", 140 | "\n", 141 | "p = Figure(tools=\"\", toolbar_location=None)\n", 142 | "r = p.circle(x='x', y='y', radius='r', source=source,\n", 143 | " color=\"navy\", alpha=0.6, line_color=\"white\")\n", 144 | "\n", 145 | "COLORS = [\"black\", \"firebrick\", \"navy\", \"olive\", \"goldenrod\"]\n", 146 | "select = Select(title=\"Color\", value=\"navy\", options=COLORS)\n", 147 | "input = TextInput(title=\"Number of points\", value=\"200\")\n", 148 | "\n", 149 | "def update_color(attrname, old, new):\n", 150 | " r.glyph.fill_color = select.value\n", 151 | "select.on_change('value', update_color)\n", 152 | "\n", 153 | "def update_points(attrname, old, new):\n", 154 | " N = int(input.value)\n", 155 | " source.data = get_data(N)\n", 156 | "input.on_change('value', update_points)\n", 157 | "\n", 158 | "layout = column(row(select, input, width=400), row(p))\n", 159 | "\n", 160 | "curdoc().add_root(layout)\n", 161 | "```" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 2, 167 | "metadata": { 168 | "collapsed": true 169 | }, 170 | "outputs": [], 171 | "source": [ 172 | "# EXERCISE: add more widgets to change more aspects of this plot\n" 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": {}, 178 | "source": [ 179 | "# Streaming Data\n", 180 | "\n", 181 | "It is possible to efficiently stream new data to column data sources by using the ``stream`` method. This method accepts two argmuments:\n", 182 | "* ``new_data`` — a dictionary with the same structure as the column data source\n", 183 | "* ``rollover`` — a maximum column length on the client (earlier data is dropped) *[optional]*\n", 184 | "\n", 185 | "If no ``rollover`` is specified, data is never dropped on the client and columns grow without bound.\n", 186 | "\n", 187 | "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", 188 | "\n", 189 | "To try out the example below, copy the code into a file ``stream.py`` and then execute:\n", 190 | "```bash\n", 191 | "bokeh serve --show stream.py\n", 192 | "```\n", 193 | "----" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "metadata": {}, 199 | "source": [ 200 | "```python\n", 201 | "# stream.py\n", 202 | "from math import cos, sin\n", 203 | "\n", 204 | "from bokeh.io import curdoc\n", 205 | "from bokeh.models import ColumnDataSource\n", 206 | "from bokeh.plotting import figure\n", 207 | "\n", 208 | "p = figure(x_range=(-1.1, 1.1), y_range=(-1.1, 1.1))\n", 209 | "p.circle(x=0, y=0, radius=1, fill_color=None, line_width=2)\n", 210 | "\n", 211 | "# this is the data source we will stream to\n", 212 | "source = ColumnDataSource(data=dict(x=[1], y=[0]))\n", 213 | "p.circle(x='x', y='y', size=12, fill_color='white', source=source)\n", 214 | "\n", 215 | "def update():\n", 216 | " x, y = source.data['x'][-1], source.data['y'][-1]\n", 217 | " \n", 218 | " # construct the new values for all columns, and pass to stream\n", 219 | " new_data = dict(x=[x*cos(0.1) - y*sin(0.1)], y=[x*sin(0.1) + y*cos(0.1)])\n", 220 | " source.stream(new_data, rollover=8)\n", 221 | "\n", 222 | "curdoc().add_periodic_callback(update, 150)\n", 223 | "curdoc().add_root(p)\n", 224 | "```" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": 3, 230 | "metadata": { 231 | "collapsed": true 232 | }, 233 | "outputs": [], 234 | "source": [ 235 | "### EXERCISE: starting with the above example, create your own streaming plot\n" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": null, 241 | "metadata": { 242 | "collapsed": true 243 | }, 244 | "outputs": [], 245 | "source": [] 246 | } 247 | ], 248 | "metadata": { 249 | "kernelspec": { 250 | "display_name": "Python 3", 251 | "language": "python", 252 | "name": "python3" 253 | }, 254 | "language_info": { 255 | "codemirror_mode": { 256 | "name": "ipython", 257 | "version": 3 258 | }, 259 | "file_extension": ".py", 260 | "mimetype": "text/x-python", 261 | "name": "python", 262 | "nbconvert_exporter": "python", 263 | "pygments_lexer": "ipython3", 264 | "version": "3.6.2" 265 | } 266 | }, 267 | "nbformat": 4, 268 | "nbformat_minor": 1 269 | } 270 | -------------------------------------------------------------------------------- /tutorial/assets/document.svg: -------------------------------------------------------------------------------- 1 | 2 |
Document
<font style="font-size: 39px">Document</font>
roots
[Not supported by viewer]

Select

[Not supported by viewer]

Slider



[Not supported by viewer]
Plot
Plot
+ tools
+ tools
+ renderers
+ renderers

PanTool
[Not supported by viewer]

SaveTool
[Not supported by viewer]
Axis
Axis
+ formatter
+ formatter
+ ticker
+ ticker
GlyphRenderer

[Not supported by viewer]
+ glyph
+ glyph<br>
+ hover_glyph

+ selection_glyph

+ nonselection_glyph
[Not supported by viewer]


BasicTicker

[Not supported by viewer]


BasicTickformatter

[Not supported by viewer]

Circle
[Not supported by viewer]

Circle
[Not supported by viewer]

Circle
[Not supported by viewer]

Circle
[Not supported by viewer]

ResetTool
[Not supported by viewer]
Grid
Grid
+ ticker
+ ticker
Column
Column
+ children
+ children
-------------------------------------------------------------------------------- /tutorial/08 - Graph and Network Plots.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "collapsed": true 7 | }, 8 | "source": [ 9 | "\n", 10 | " \n", 11 | " \n", 19 | " \n", 22 | " \n", 23 | "
\n", 12 | " \n", 13 | " \n", 17 | " \n", 18 | " \n", 20 | "

Bokeh Tutorial

\n", 21 | "
\n", 24 | "\n", 25 | "

08. Graph and Network Plots

" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 1, 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "data": { 35 | "text/html": [ 36 | "\n", 37 | "
\n", 38 | " \n", 39 | " Loading BokehJS ...\n", 40 | "
" 41 | ] 42 | }, 43 | "metadata": {}, 44 | "output_type": "display_data" 45 | }, 46 | { 47 | "data": { 48 | "application/javascript": [ 49 | "\n", 50 | "(function(root) {\n", 51 | " function now() {\n", 52 | " return new Date();\n", 53 | " }\n", 54 | "\n", 55 | " var force = true;\n", 56 | "\n", 57 | " if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n", 58 | " root._bokeh_onload_callbacks = [];\n", 59 | " root._bokeh_is_loading = undefined;\n", 60 | " }\n", 61 | "\n", 62 | "\n", 63 | " \n", 64 | " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", 65 | " root._bokeh_timeout = Date.now() + 5000;\n", 66 | " root._bokeh_failed_load = false;\n", 67 | " }\n", 68 | "\n", 69 | " var NB_LOAD_WARNING = {'data': {'text/html':\n", 70 | " \"
\\n\"+\n", 71 | " \"

\\n\"+\n", 72 | " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", 73 | " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", 74 | " \"

\\n\"+\n", 75 | " \"\\n\"+\n", 79 | " \"\\n\"+\n", 80 | " \"from bokeh.resources import INLINE\\n\"+\n", 81 | " \"output_notebook(resources=INLINE)\\n\"+\n", 82 | " \"\\n\"+\n", 83 | " \"
\"}};\n", 84 | "\n", 85 | " function display_loaded() {\n", 86 | " if (root.Bokeh !== undefined) {\n", 87 | " var el = document.getElementById(\"967a90ed-2e6a-42af-b03f-78d17d5ee163\");\n", 88 | " if (el != null) {\n", 89 | " el.textContent = \"BokehJS \" + Bokeh.version + \" successfully loaded.\";\n", 90 | " }\n", 91 | " } else if (Date.now() < root._bokeh_timeout) {\n", 92 | " setTimeout(display_loaded, 100)\n", 93 | " }\n", 94 | " }\n", 95 | "\n", 96 | "\n", 97 | " function run_callbacks() {\n", 98 | " try {\n", 99 | " root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n", 100 | " }\n", 101 | " finally {\n", 102 | " delete root._bokeh_onload_callbacks\n", 103 | " }\n", 104 | " console.info(\"Bokeh: all callbacks have finished\");\n", 105 | " }\n", 106 | "\n", 107 | " function load_libs(js_urls, callback) {\n", 108 | " root._bokeh_onload_callbacks.push(callback);\n", 109 | " if (root._bokeh_is_loading > 0) {\n", 110 | " console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", 111 | " return null;\n", 112 | " }\n", 113 | " if (js_urls == null || js_urls.length === 0) {\n", 114 | " run_callbacks();\n", 115 | " return null;\n", 116 | " }\n", 117 | " console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", 118 | " root._bokeh_is_loading = js_urls.length;\n", 119 | " for (var i = 0; i < js_urls.length; i++) {\n", 120 | " var url = js_urls[i];\n", 121 | " var s = document.createElement('script');\n", 122 | " s.src = url;\n", 123 | " s.async = false;\n", 124 | " s.onreadystatechange = s.onload = function() {\n", 125 | " root._bokeh_is_loading--;\n", 126 | " if (root._bokeh_is_loading === 0) {\n", 127 | " console.log(\"Bokeh: all BokehJS libraries loaded\");\n", 128 | " run_callbacks()\n", 129 | " }\n", 130 | " };\n", 131 | " s.onerror = function() {\n", 132 | " console.warn(\"failed to load library \" + url);\n", 133 | " };\n", 134 | " console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", 135 | " document.getElementsByTagName(\"head\")[0].appendChild(s);\n", 136 | " }\n", 137 | " };var element = document.getElementById(\"967a90ed-2e6a-42af-b03f-78d17d5ee163\");\n", 138 | " if (element == null) {\n", 139 | " console.log(\"Bokeh: ERROR: autoload.js configured with elementid '967a90ed-2e6a-42af-b03f-78d17d5ee163' but no matching script tag was found. \")\n", 140 | " return false;\n", 141 | " }\n", 142 | "\n", 143 | " var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.7.min.js\"];\n", 144 | "\n", 145 | " var inline_js = [\n", 146 | " function(Bokeh) {\n", 147 | " Bokeh.set_log_level(\"info\");\n", 148 | " },\n", 149 | " \n", 150 | " function(Bokeh) {\n", 151 | " \n", 152 | " },\n", 153 | " \n", 154 | " function(Bokeh) {\n", 155 | " \n", 156 | " document.getElementById(\"967a90ed-2e6a-42af-b03f-78d17d5ee163\").textContent = \"BokehJS is loading...\";\n", 157 | " },\n", 158 | " function(Bokeh) {\n", 159 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.css\");\n", 160 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.css\");\n", 161 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.css\");\n", 162 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.css\");\n", 163 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.css\");\n", 164 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.css\");\n", 165 | " }\n", 166 | " ];\n", 167 | "\n", 168 | " function run_inline_js() {\n", 169 | " \n", 170 | " if ((root.Bokeh !== undefined) || (force === true)) {\n", 171 | " for (var i = 0; i < inline_js.length; i++) {\n", 172 | " inline_js[i].call(root, root.Bokeh);\n", 173 | " }if (force === true) {\n", 174 | " display_loaded();\n", 175 | " }} else if (Date.now() < root._bokeh_timeout) {\n", 176 | " setTimeout(run_inline_js, 100);\n", 177 | " } else if (!root._bokeh_failed_load) {\n", 178 | " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", 179 | " root._bokeh_failed_load = true;\n", 180 | " } else if (force !== true) {\n", 181 | " var cell = $(document.getElementById(\"967a90ed-2e6a-42af-b03f-78d17d5ee163\")).parents('.cell').data().cell;\n", 182 | " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", 183 | " }\n", 184 | "\n", 185 | " }\n", 186 | "\n", 187 | " if (root._bokeh_is_loading === 0) {\n", 188 | " console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", 189 | " run_inline_js();\n", 190 | " } else {\n", 191 | " load_libs(js_urls, function() {\n", 192 | " console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n", 193 | " run_inline_js();\n", 194 | " });\n", 195 | " }\n", 196 | "}(window));" 197 | ] 198 | }, 199 | "metadata": {}, 200 | "output_type": "display_data" 201 | } 202 | ], 203 | "source": [ 204 | "from bokeh.io import show, output_notebook\n", 205 | "from bokeh.plotting import figure\n", 206 | "\n", 207 | "output_notebook()" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 2, 213 | "metadata": { 214 | "collapsed": true 215 | }, 216 | "outputs": [], 217 | "source": [ 218 | "import networkx as nx\n", 219 | "\n", 220 | "G = nx.desargues_graph()" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": 3, 226 | "metadata": {}, 227 | "outputs": [ 228 | { 229 | "data": { 230 | "text/html": [ 231 | "\n", 232 | "\n", 233 | "
\n", 234 | "
\n", 235 | "
\n", 236 | "" 380 | ] 381 | }, 382 | "metadata": {}, 383 | "output_type": "display_data" 384 | } 385 | ], 386 | "source": [ 387 | "from bokeh.models.graphs import from_networkx\n", 388 | "from bokeh.models import Range1d, Plot\n", 389 | "\n", 390 | "# We could use figure here but don't want all the axes and titles\n", 391 | "plot = Plot(x_range=Range1d(-1.1,1.1), y_range=Range1d(-1.1,1.1))\n", 392 | "\n", 393 | "# Create a Bokeh graph from the NetworkX input using nx.spring_layout\n", 394 | "graph = from_networkx(G, nx.spring_layout, scale=2, center=(0,0))\n", 395 | "plot.renderers.append(graph)\n", 396 | "\n", 397 | "# Set some of the default node glyph (Circle) properties\n", 398 | "graph.node_renderer.glyph.update(size=20, fill_color=\"orange\")\n", 399 | "\n", 400 | "show(plot)" 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": 4, 406 | "metadata": { 407 | "collapsed": true 408 | }, 409 | "outputs": [], 410 | "source": [ 411 | "# Exercise: try a different NetworkX layout, and set some `graph.edge_renderer` properties\n" 412 | ] 413 | }, 414 | { 415 | "cell_type": "markdown", 416 | "metadata": {}, 417 | "source": [] 418 | }, 419 | { 420 | "cell_type": "code", 421 | "execution_count": 5, 422 | "metadata": {}, 423 | "outputs": [ 424 | { 425 | "data": { 426 | "text/html": [ 427 | "\n", 428 | "\n", 429 | "
\n", 430 | "
\n", 431 | "
\n", 432 | "" 576 | ] 577 | }, 578 | "metadata": {}, 579 | "output_type": "display_data" 580 | } 581 | ], 582 | "source": [ 583 | "from bokeh.models.graphs import NodesAndLinkedEdges\n", 584 | "from bokeh.models import Circle, HoverTool, MultiLine\n", 585 | "\n", 586 | "G = nx.karate_club_graph()\n", 587 | "\n", 588 | "# We could use figure here but don't want all the axes and titles\n", 589 | "plot = Plot(x_range=Range1d(-1.1,1.1), y_range=Range1d(-1.1,1.1))\n", 590 | "\n", 591 | "# Create a Bokeh graph from the NetworkX input using nx.spring_layout\n", 592 | "graph = from_networkx(G, nx.spring_layout, scale=2, center=(0,0))\n", 593 | "plot.renderers.append(graph)\n", 594 | "\n", 595 | "# Blue circles for nodes, and light grey lines for edges\n", 596 | "graph.node_renderer.glyph = Circle(size=25, fill_color='#2b83ba')\n", 597 | "graph.edge_renderer.glyph = MultiLine(line_color=\"#cccccc\", line_alpha=0.8, line_width=2)\n", 598 | "\n", 599 | "# green hover for both nodes and edges\n", 600 | "graph.node_renderer.hover_glyph = Circle(size=25, fill_color='#abdda4')\n", 601 | "graph.edge_renderer.hover_glyph = MultiLine(line_color='#abdda4', line_width=4)\n", 602 | "\n", 603 | "# When we hover over nodes, highlight adjecent edges too\n", 604 | "graph.inspection_policy = NodesAndLinkedEdges()\n", 605 | "\n", 606 | "plot.add_tools(HoverTool(tooltips=None))\n", 607 | "\n", 608 | "show(plot)" 609 | ] 610 | }, 611 | { 612 | "cell_type": "code", 613 | "execution_count": 6, 614 | "metadata": { 615 | "collapsed": true 616 | }, 617 | "outputs": [], 618 | "source": [ 619 | "# Exercise: try a different inspection (or selection) policy\n" 620 | ] 621 | } 622 | ], 623 | "metadata": { 624 | "kernelspec": { 625 | "display_name": "Python 3", 626 | "language": "python", 627 | "name": "python3" 628 | }, 629 | "language_info": { 630 | "codemirror_mode": { 631 | "name": "ipython", 632 | "version": 3 633 | }, 634 | "file_extension": ".py", 635 | "mimetype": "text/x-python", 636 | "name": "python", 637 | "nbconvert_exporter": "python", 638 | "pygments_lexer": "ipython3", 639 | "version": "3.6.2" 640 | } 641 | }, 642 | "nbformat": 4, 643 | "nbformat_minor": 2 644 | } 645 | -------------------------------------------------------------------------------- /tutorial/09 - Geographic Plots.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | " \n", 9 | " \n", 17 | " \n", 20 | " \n", 21 | "
\n", 10 | " \n", 11 | " \n", 15 | " \n", 16 | " \n", 18 | "

Bokeh Tutorial

\n", 19 | "
\n", 22 | "\n", 23 | "

09. Geographic Plots

" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 1, 29 | "metadata": {}, 30 | "outputs": [ 31 | { 32 | "data": { 33 | "text/html": [ 34 | "\n", 35 | "
\n", 36 | " \n", 37 | " Loading BokehJS ...\n", 38 | "
" 39 | ] 40 | }, 41 | "metadata": {}, 42 | "output_type": "display_data" 43 | }, 44 | { 45 | "data": { 46 | "application/javascript": [ 47 | "\n", 48 | "(function(root) {\n", 49 | " function now() {\n", 50 | " return new Date();\n", 51 | " }\n", 52 | "\n", 53 | " var force = true;\n", 54 | "\n", 55 | " if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n", 56 | " root._bokeh_onload_callbacks = [];\n", 57 | " root._bokeh_is_loading = undefined;\n", 58 | " }\n", 59 | "\n", 60 | "\n", 61 | " \n", 62 | " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", 63 | " root._bokeh_timeout = Date.now() + 5000;\n", 64 | " root._bokeh_failed_load = false;\n", 65 | " }\n", 66 | "\n", 67 | " var NB_LOAD_WARNING = {'data': {'text/html':\n", 68 | " \"
\\n\"+\n", 69 | " \"

\\n\"+\n", 70 | " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", 71 | " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", 72 | " \"

\\n\"+\n", 73 | " \"\\n\"+\n", 77 | " \"\\n\"+\n", 78 | " \"from bokeh.resources import INLINE\\n\"+\n", 79 | " \"output_notebook(resources=INLINE)\\n\"+\n", 80 | " \"\\n\"+\n", 81 | " \"
\"}};\n", 82 | "\n", 83 | " function display_loaded() {\n", 84 | " if (root.Bokeh !== undefined) {\n", 85 | " var el = document.getElementById(\"332f3fa8-ba51-4cdd-9915-ec297efeecb5\");\n", 86 | " if (el != null) {\n", 87 | " el.textContent = \"BokehJS \" + Bokeh.version + \" successfully loaded.\";\n", 88 | " }\n", 89 | " } else if (Date.now() < root._bokeh_timeout) {\n", 90 | " setTimeout(display_loaded, 100)\n", 91 | " }\n", 92 | " }\n", 93 | "\n", 94 | "\n", 95 | " function run_callbacks() {\n", 96 | " try {\n", 97 | " root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n", 98 | " }\n", 99 | " finally {\n", 100 | " delete root._bokeh_onload_callbacks\n", 101 | " }\n", 102 | " console.info(\"Bokeh: all callbacks have finished\");\n", 103 | " }\n", 104 | "\n", 105 | " function load_libs(js_urls, callback) {\n", 106 | " root._bokeh_onload_callbacks.push(callback);\n", 107 | " if (root._bokeh_is_loading > 0) {\n", 108 | " console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", 109 | " return null;\n", 110 | " }\n", 111 | " if (js_urls == null || js_urls.length === 0) {\n", 112 | " run_callbacks();\n", 113 | " return null;\n", 114 | " }\n", 115 | " console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", 116 | " root._bokeh_is_loading = js_urls.length;\n", 117 | " for (var i = 0; i < js_urls.length; i++) {\n", 118 | " var url = js_urls[i];\n", 119 | " var s = document.createElement('script');\n", 120 | " s.src = url;\n", 121 | " s.async = false;\n", 122 | " s.onreadystatechange = s.onload = function() {\n", 123 | " root._bokeh_is_loading--;\n", 124 | " if (root._bokeh_is_loading === 0) {\n", 125 | " console.log(\"Bokeh: all BokehJS libraries loaded\");\n", 126 | " run_callbacks()\n", 127 | " }\n", 128 | " };\n", 129 | " s.onerror = function() {\n", 130 | " console.warn(\"failed to load library \" + url);\n", 131 | " };\n", 132 | " console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", 133 | " document.getElementsByTagName(\"head\")[0].appendChild(s);\n", 134 | " }\n", 135 | " };var element = document.getElementById(\"332f3fa8-ba51-4cdd-9915-ec297efeecb5\");\n", 136 | " if (element == null) {\n", 137 | " console.log(\"Bokeh: ERROR: autoload.js configured with elementid '332f3fa8-ba51-4cdd-9915-ec297efeecb5' but no matching script tag was found. \")\n", 138 | " return false;\n", 139 | " }\n", 140 | "\n", 141 | " var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.7.min.js\"];\n", 142 | "\n", 143 | " var inline_js = [\n", 144 | " function(Bokeh) {\n", 145 | " Bokeh.set_log_level(\"info\");\n", 146 | " },\n", 147 | " \n", 148 | " function(Bokeh) {\n", 149 | " \n", 150 | " },\n", 151 | " \n", 152 | " function(Bokeh) {\n", 153 | " \n", 154 | " document.getElementById(\"332f3fa8-ba51-4cdd-9915-ec297efeecb5\").textContent = \"BokehJS is loading...\";\n", 155 | " },\n", 156 | " function(Bokeh) {\n", 157 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.css\");\n", 158 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.css\");\n", 159 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.css\");\n", 160 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.css\");\n", 161 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.css\");\n", 162 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.css\");\n", 163 | " }\n", 164 | " ];\n", 165 | "\n", 166 | " function run_inline_js() {\n", 167 | " \n", 168 | " if ((root.Bokeh !== undefined) || (force === true)) {\n", 169 | " for (var i = 0; i < inline_js.length; i++) {\n", 170 | " inline_js[i].call(root, root.Bokeh);\n", 171 | " }if (force === true) {\n", 172 | " display_loaded();\n", 173 | " }} else if (Date.now() < root._bokeh_timeout) {\n", 174 | " setTimeout(run_inline_js, 100);\n", 175 | " } else if (!root._bokeh_failed_load) {\n", 176 | " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", 177 | " root._bokeh_failed_load = true;\n", 178 | " } else if (force !== true) {\n", 179 | " var cell = $(document.getElementById(\"332f3fa8-ba51-4cdd-9915-ec297efeecb5\")).parents('.cell').data().cell;\n", 180 | " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", 181 | " }\n", 182 | "\n", 183 | " }\n", 184 | "\n", 185 | " if (root._bokeh_is_loading === 0) {\n", 186 | " console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", 187 | " run_inline_js();\n", 188 | " } else {\n", 189 | " load_libs(js_urls, function() {\n", 190 | " console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n", 191 | " run_inline_js();\n", 192 | " });\n", 193 | " }\n", 194 | "}(window));" 195 | ] 196 | }, 197 | "metadata": {}, 198 | "output_type": "display_data" 199 | } 200 | ], 201 | "source": [ 202 | "from bokeh.io import output_notebook, show\n", 203 | "output_notebook()" 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "metadata": {}, 209 | "source": [ 210 | "It is often useful to be able to relate datasets with their real-world context. You can plot geographic data just like any other type of data, as in the [Texas Unemployment example](http://nbviewer.jupyter.org/github/bokeh/bokeh-notebooks/blob/master/gallery/texas.ipynb), but Bokeh also Bokeh provides several specialized mechanisms for plotting data in geographic coordinates:\n", 211 | "\n", 212 | "* [GMapPlot](https://bokeh.pydata.org/en/latest/docs/user_guide/geo.html#google-maps-support): Bokeh Plots on top of Google Maps\n", 213 | "\n", 214 | "* [TileSource](https://bokeh.pydata.org/en/latest/docs/user_guide/geo.html#tile-providers), especially WMTSTileSource: allows data to be overlaid on data from any map tile server, including \n", 215 | "[Google Maps](http://maps.google.com), \n", 216 | "[Stamen](http://maps.stamen.com), \n", 217 | "[MapQuest](https://www.mapquest.com/), \n", 218 | "[OpenStreetMap](https://www.openstreetmap.org), \n", 219 | "[ESRI](http://www.esri.com), \n", 220 | "and custom servers.\n", 221 | "\n", 222 | "* [GeoJSONDataSource](https://bokeh.pydata.org/en/dev/docs/user_guide/geo.html#geojson-datasource): Allows reading data in [GeoJSON](http://geojson.org/) format for use with Bokeh plots and glyphs, similar to `ColumnDataSource`." 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "## WMTS Tile Source\n", 230 | "\n", 231 | "WTMS is the most common web standard for tiled map data, i.e. maps supplied as standard-sized image patches from which the overall map can be constructed at a given zoom level. WTMS uses Web Mercator format, measuring distances from Greenwich, England as meters north and meters west, which is easy to compute but does distort the global shape. \n", 232 | "\n", 233 | "First let's create an empty Bokeh plot covering the USA, with bounds specified in meters:" 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": 2, 239 | "metadata": { 240 | "collapsed": true 241 | }, 242 | "outputs": [], 243 | "source": [ 244 | "from bokeh.plotting import figure\n", 245 | "from bokeh.tile_providers import WMTSTileSource\n", 246 | "\n", 247 | "# web mercator coordinates\n", 248 | "USA = x_range,y_range = ((-13884029,-7453304), (2698291,6455972))\n", 249 | "\n", 250 | "p = figure(tools='pan, wheel_zoom', x_range=x_range, y_range=y_range)\n", 251 | "p.axis.visible = False" 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "metadata": {}, 257 | "source": [ 258 | "A few WTMS tile sources are already defined in `bokeh.tile_providers`, but here we'll show how to specify the interface using a format string showing Bokeh how to request a tile with the required zoom, x, and y values from a given tile provider:" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 3, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "data": { 268 | "text/html": [ 269 | "
TileRenderer(
id = '25349dc1-ffc4-4ad6-97cc-7c8485687c40', …)
alpha = 1.0,
js_event_callbacks = {},
js_property_callbacks = {},
level = 'underlay',
name = None,
render_parents = True,
subscribed_events = [],
tags = [],
tile_source = WMTSTileSource(id='b7f64f73-5cae-476c-8a8f-7805bf664d23', ...),
visible = True,
x_range_name = 'default',
y_range_name = 'default')
\n", 270 | "\n" 285 | ], 286 | "text/plain": [ 287 | "TileRenderer(id='25349dc1-ffc4-4ad6-97cc-7c8485687c40', ...)" 288 | ] 289 | }, 290 | "execution_count": 3, 291 | "metadata": {}, 292 | "output_type": "execute_result" 293 | } 294 | ], 295 | "source": [ 296 | "url = 'http://a.basemaps.cartocdn.com/dark_all/{Z}/{X}/{Y}.png'\n", 297 | "attribution = \"Tiles by Carto, under CC BY 3.0. Data by OSM, under ODbL\"\n", 298 | "\n", 299 | "p.add_tile(WMTSTileSource(url=url, attribution=attribution))" 300 | ] 301 | }, 302 | { 303 | "cell_type": "markdown", 304 | "metadata": {}, 305 | "source": [ 306 | "If you show the figure, you can then use the wheel zoom and pan tools to navigate over any zoom level, and Bokeh will request the appropriate tiles from the server and insert them at the correct locations in the plot:" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": 4, 312 | "metadata": {}, 313 | "outputs": [ 314 | { 315 | "data": { 316 | "text/html": [ 317 | "\n", 318 | "\n", 319 | "
\n", 320 | "
\n", 321 | "
\n", 322 | "" 466 | ] 467 | }, 468 | "metadata": {}, 469 | "output_type": "display_data" 470 | } 471 | ], 472 | "source": [ 473 | "show(p)" 474 | ] 475 | }, 476 | { 477 | "cell_type": "markdown", 478 | "metadata": {}, 479 | "source": [ 480 | "That's all it takes to put map data into your plot! Of course, you'll usually want to show other data as well, or you could just use the tile server's own web address. You can now add anything you would normally use in a Bokeh plot, as long as you can obtain coordinates for it in Web Mercator format. For example:" 481 | ] 482 | }, 483 | { 484 | "cell_type": "code", 485 | "execution_count": 5, 486 | "metadata": {}, 487 | "outputs": [ 488 | { 489 | "data": { 490 | "text/html": [ 491 | "
\n", 492 | "\n", 505 | "\n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | "
latlonnamexy
030.2672-97.7431Austin-1.088071e+073.537942e+06
140.7128-74.0059NYC-8.238299e+064.970072e+06
\n", 535 | "
" 536 | ], 537 | "text/plain": [ 538 | " lat lon name x y\n", 539 | "0 30.2672 -97.7431 Austin -1.088071e+07 3.537942e+06\n", 540 | "1 40.7128 -74.0059 NYC -8.238299e+06 4.970072e+06" 541 | ] 542 | }, 543 | "execution_count": 5, 544 | "metadata": {}, 545 | "output_type": "execute_result" 546 | } 547 | ], 548 | "source": [ 549 | "import pandas as pd\n", 550 | "import numpy as np\n", 551 | "\n", 552 | "def wgs84_to_web_mercator(df, lon=\"lon\", lat=\"lat\"):\n", 553 | " \"\"\"Converts decimal longitude/latitude to Web Mercator format\"\"\"\n", 554 | " k = 6378137\n", 555 | " df[\"x\"] = df[lon] * (k * np.pi/180.0)\n", 556 | " df[\"y\"] = np.log(np.tan((90 + df[lat]) * np.pi/360.0)) * k\n", 557 | " return df\n", 558 | "\n", 559 | "df = pd.DataFrame(dict(name=[\"Austin\", \"NYC\"], lon=[-97.7431,-74.0059], lat=[30.2672,40.7128]))\n", 560 | "wgs84_to_web_mercator(df)" 561 | ] 562 | }, 563 | { 564 | "cell_type": "code", 565 | "execution_count": 6, 566 | "metadata": {}, 567 | "outputs": [ 568 | { 569 | "data": { 570 | "text/html": [ 571 | "\n", 572 | "\n", 573 | "
\n", 574 | "
\n", 575 | "
\n", 576 | "" 720 | ] 721 | }, 722 | "metadata": {}, 723 | "output_type": "display_data" 724 | } 725 | ], 726 | "source": [ 727 | "p.circle(x=df['x'], y=df['y'], fill_color='orange', size=10)\n", 728 | "show(p)" 729 | ] 730 | }, 731 | { 732 | "cell_type": "code", 733 | "execution_count": 7, 734 | "metadata": { 735 | "collapsed": true 736 | }, 737 | "outputs": [], 738 | "source": [ 739 | "# EXERCISE: find some data in lat, lon (e.g. at http://data.gov), \n", 740 | "# import it into a dataframe or data source, and add it on the map above.\n" 741 | ] 742 | }, 743 | { 744 | "cell_type": "markdown", 745 | "metadata": { 746 | "collapsed": true 747 | }, 748 | "source": [ 749 | "## GeoJSON" 750 | ] 751 | }, 752 | { 753 | "cell_type": "code", 754 | "execution_count": null, 755 | "metadata": { 756 | "collapsed": true 757 | }, 758 | "outputs": [], 759 | "source": [] 760 | } 761 | ], 762 | "metadata": { 763 | "anaconda-cloud": {}, 764 | "kernelspec": { 765 | "display_name": "Python 3", 766 | "language": "python", 767 | "name": "python3" 768 | }, 769 | "language_info": { 770 | "codemirror_mode": { 771 | "name": "ipython", 772 | "version": 3 773 | }, 774 | "file_extension": ".py", 775 | "mimetype": "text/x-python", 776 | "name": "python", 777 | "nbconvert_exporter": "python", 778 | "pygments_lexer": "ipython3", 779 | "version": "3.6.2" 780 | } 781 | }, 782 | "nbformat": 4, 783 | "nbformat_minor": 1 784 | } 785 | -------------------------------------------------------------------------------- /tutorial/04 - Data Sources and Transformations.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | " \n", 9 | " \n", 17 | " \n", 20 | " \n", 21 | "
\n", 10 | " \n", 11 | " \n", 15 | " \n", 16 | " \n", 18 | "

Bokeh Tutorial

\n", 19 | "
\n", 22 | "\n", 23 | "

04. Data Sources and Transformations

" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 1, 29 | "metadata": { 30 | "collapsed": true 31 | }, 32 | "outputs": [], 33 | "source": [ 34 | "from bokeh.io import output_notebook, show\n", 35 | "from bokeh.plotting import figure" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 2, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/html": [ 46 | "\n", 47 | "
\n", 48 | " \n", 49 | " Loading BokehJS ...\n", 50 | "
" 51 | ] 52 | }, 53 | "metadata": {}, 54 | "output_type": "display_data" 55 | }, 56 | { 57 | "data": { 58 | "application/javascript": [ 59 | "\n", 60 | "(function(root) {\n", 61 | " function now() {\n", 62 | " return new Date();\n", 63 | " }\n", 64 | "\n", 65 | " var force = true;\n", 66 | "\n", 67 | " if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n", 68 | " root._bokeh_onload_callbacks = [];\n", 69 | " root._bokeh_is_loading = undefined;\n", 70 | " }\n", 71 | "\n", 72 | "\n", 73 | " \n", 74 | " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", 75 | " root._bokeh_timeout = Date.now() + 5000;\n", 76 | " root._bokeh_failed_load = false;\n", 77 | " }\n", 78 | "\n", 79 | " var NB_LOAD_WARNING = {'data': {'text/html':\n", 80 | " \"
\\n\"+\n", 81 | " \"

\\n\"+\n", 82 | " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", 83 | " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", 84 | " \"

\\n\"+\n", 85 | " \"\\n\"+\n", 89 | " \"\\n\"+\n", 90 | " \"from bokeh.resources import INLINE\\n\"+\n", 91 | " \"output_notebook(resources=INLINE)\\n\"+\n", 92 | " \"\\n\"+\n", 93 | " \"
\"}};\n", 94 | "\n", 95 | " function display_loaded() {\n", 96 | " if (root.Bokeh !== undefined) {\n", 97 | " var el = document.getElementById(\"ff842f7f-c459-41fc-b8d1-db2536c53907\");\n", 98 | " if (el != null) {\n", 99 | " el.textContent = \"BokehJS \" + Bokeh.version + \" successfully loaded.\";\n", 100 | " }\n", 101 | " } else if (Date.now() < root._bokeh_timeout) {\n", 102 | " setTimeout(display_loaded, 100)\n", 103 | " }\n", 104 | " }\n", 105 | "\n", 106 | "\n", 107 | " function run_callbacks() {\n", 108 | " try {\n", 109 | " root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n", 110 | " }\n", 111 | " finally {\n", 112 | " delete root._bokeh_onload_callbacks\n", 113 | " }\n", 114 | " console.info(\"Bokeh: all callbacks have finished\");\n", 115 | " }\n", 116 | "\n", 117 | " function load_libs(js_urls, callback) {\n", 118 | " root._bokeh_onload_callbacks.push(callback);\n", 119 | " if (root._bokeh_is_loading > 0) {\n", 120 | " console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", 121 | " return null;\n", 122 | " }\n", 123 | " if (js_urls == null || js_urls.length === 0) {\n", 124 | " run_callbacks();\n", 125 | " return null;\n", 126 | " }\n", 127 | " console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", 128 | " root._bokeh_is_loading = js_urls.length;\n", 129 | " for (var i = 0; i < js_urls.length; i++) {\n", 130 | " var url = js_urls[i];\n", 131 | " var s = document.createElement('script');\n", 132 | " s.src = url;\n", 133 | " s.async = false;\n", 134 | " s.onreadystatechange = s.onload = function() {\n", 135 | " root._bokeh_is_loading--;\n", 136 | " if (root._bokeh_is_loading === 0) {\n", 137 | " console.log(\"Bokeh: all BokehJS libraries loaded\");\n", 138 | " run_callbacks()\n", 139 | " }\n", 140 | " };\n", 141 | " s.onerror = function() {\n", 142 | " console.warn(\"failed to load library \" + url);\n", 143 | " };\n", 144 | " console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", 145 | " document.getElementsByTagName(\"head\")[0].appendChild(s);\n", 146 | " }\n", 147 | " };var element = document.getElementById(\"ff842f7f-c459-41fc-b8d1-db2536c53907\");\n", 148 | " if (element == null) {\n", 149 | " console.log(\"Bokeh: ERROR: autoload.js configured with elementid 'ff842f7f-c459-41fc-b8d1-db2536c53907' but no matching script tag was found. \")\n", 150 | " return false;\n", 151 | " }\n", 152 | "\n", 153 | " var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.7.min.js\"];\n", 154 | "\n", 155 | " var inline_js = [\n", 156 | " function(Bokeh) {\n", 157 | " Bokeh.set_log_level(\"info\");\n", 158 | " },\n", 159 | " \n", 160 | " function(Bokeh) {\n", 161 | " \n", 162 | " },\n", 163 | " \n", 164 | " function(Bokeh) {\n", 165 | " \n", 166 | " document.getElementById(\"ff842f7f-c459-41fc-b8d1-db2536c53907\").textContent = \"BokehJS is loading...\";\n", 167 | " },\n", 168 | " function(Bokeh) {\n", 169 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.css\");\n", 170 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.7.min.css\");\n", 171 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.css\");\n", 172 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.7.min.css\");\n", 173 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.css\");\n", 174 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.7.min.css\");\n", 175 | " }\n", 176 | " ];\n", 177 | "\n", 178 | " function run_inline_js() {\n", 179 | " \n", 180 | " if ((root.Bokeh !== undefined) || (force === true)) {\n", 181 | " for (var i = 0; i < inline_js.length; i++) {\n", 182 | " inline_js[i].call(root, root.Bokeh);\n", 183 | " }if (force === true) {\n", 184 | " display_loaded();\n", 185 | " }} else if (Date.now() < root._bokeh_timeout) {\n", 186 | " setTimeout(run_inline_js, 100);\n", 187 | " } else if (!root._bokeh_failed_load) {\n", 188 | " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", 189 | " root._bokeh_failed_load = true;\n", 190 | " } else if (force !== true) {\n", 191 | " var cell = $(document.getElementById(\"ff842f7f-c459-41fc-b8d1-db2536c53907\")).parents('.cell').data().cell;\n", 192 | " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", 193 | " }\n", 194 | "\n", 195 | " }\n", 196 | "\n", 197 | " if (root._bokeh_is_loading === 0) {\n", 198 | " console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", 199 | " run_inline_js();\n", 200 | " } else {\n", 201 | " load_libs(js_urls, function() {\n", 202 | " console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n", 203 | " run_inline_js();\n", 204 | " });\n", 205 | " }\n", 206 | "}(window));" 207 | ] 208 | }, 209 | "metadata": {}, 210 | "output_type": "display_data" 211 | } 212 | ], 213 | "source": [ 214 | "output_notebook()" 215 | ] 216 | }, 217 | { 218 | "cell_type": "markdown", 219 | "metadata": {}, 220 | "source": [ 221 | "# Overview\n", 222 | "\n", 223 | "We've seen how Bokeh can work well with Python lists, NumPy arrays, Pandas series, etc. At lower levels, these inputs are converted to a Bokeh `ColumnDataSource`. This data type is the central data source object used throughout Bokeh. Although Bokeh often creates them for us transparently, there are times when it is useful to create them explicitly.\n", 224 | "\n", 225 | "In later sections we will see features like hover tooltips, computed transforms, and CustomJS interactions that make use of the `ColumnDataSource`, so let's take a quick look now. " 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": {}, 231 | "source": [ 232 | "## Creating with Python Dicts\n", 233 | "\n", 234 | "The `ColumnDataSource` can be imported from `bokeh.models`:" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 3, 240 | "metadata": { 241 | "collapsed": true 242 | }, 243 | "outputs": [], 244 | "source": [ 245 | "from bokeh.models import ColumnDataSource" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "The `ColumnDataSource` is a mapping of column names (strings) to sequences of values. Here is a simple example. The mapping is provided by passing a Python `dict` with string keys and simple Python lists as values. The values could also be NumPy arrays, or Pandas sequences.\n", 253 | "\n", 254 | "***NOTE: ALL the columns in a `ColumnDataSource` must always be the SAME length.***\n" 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": 4, 260 | "metadata": { 261 | "collapsed": true 262 | }, 263 | "outputs": [], 264 | "source": [ 265 | "source = ColumnDataSource(data={\n", 266 | " 'x' : [1, 2, 3, 4, 5],\n", 267 | " 'y' : [3, 7, 8, 5, 1],\n", 268 | "})" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "metadata": {}, 274 | "source": [ 275 | "Up until now we have called functions like `p.circle` by passing in literal lists or arrays of data directly, when we do this, Bokeh creates a `ColumnDataSource` for us, automatically. But it is possible to specify a `ColumnDataSource` explicitly by passing it as the `source` argument to a glyph method. Whenever we do this, if we want a property (like `\"x\"` or `\"y\"` or `\"fill_color\"`) to have a sequence of values, we pass the ***name of the column*** that we would like to use for a property:" 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 5, 281 | "metadata": {}, 282 | "outputs": [ 283 | { 284 | "data": { 285 | "text/html": [ 286 | "\n", 287 | "\n", 288 | "
\n", 289 | "
\n", 290 | "
\n", 291 | "" 435 | ] 436 | }, 437 | "metadata": {}, 438 | "output_type": "display_data" 439 | } 440 | ], 441 | "source": [ 442 | "p = figure(plot_width=400, plot_height=400)\n", 443 | "p.circle('x', 'y', size=20, source=source)\n", 444 | "show(p)" 445 | ] 446 | }, 447 | { 448 | "cell_type": "code", 449 | "execution_count": 6, 450 | "metadata": { 451 | "collapsed": true 452 | }, 453 | "outputs": [], 454 | "source": [ 455 | "# Exercise: create a column data source with NumPy arrays as column values and plot it\n" 456 | ] 457 | }, 458 | { 459 | "cell_type": "markdown", 460 | "metadata": {}, 461 | "source": [ 462 | "## Creating with Pandas DataFrames\n", 463 | "\n", 464 | "It's also simple to create `ColumnDataSource` objects directly from Pandas data frames. To do this, just pass the data frame to `ColumnDataSource` when you create it:" 465 | ] 466 | }, 467 | { 468 | "cell_type": "code", 469 | "execution_count": 7, 470 | "metadata": { 471 | "collapsed": true 472 | }, 473 | "outputs": [], 474 | "source": [ 475 | "from bokeh.sampledata.iris import flowers as df\n", 476 | "\n", 477 | "source = ColumnDataSource(df)" 478 | ] 479 | }, 480 | { 481 | "cell_type": "markdown", 482 | "metadata": {}, 483 | "source": [ 484 | "Now we can use it as we did above by passing the column names to glhph methods:" 485 | ] 486 | }, 487 | { 488 | "cell_type": "code", 489 | "execution_count": 8, 490 | "metadata": {}, 491 | "outputs": [ 492 | { 493 | "data": { 494 | "text/html": [ 495 | "\n", 496 | "\n", 497 | "
\n", 498 | "
\n", 499 | "
\n", 500 | "" 644 | ] 645 | }, 646 | "metadata": {}, 647 | "output_type": "display_data" 648 | } 649 | ], 650 | "source": [ 651 | "p = figure(plot_width=400, plot_height=400)\n", 652 | "p.circle('petal_length', 'petal_width', source=source)\n", 653 | "show(p)" 654 | ] 655 | }, 656 | { 657 | "cell_type": "code", 658 | "execution_count": 9, 659 | "metadata": { 660 | "collapsed": true 661 | }, 662 | "outputs": [], 663 | "source": [ 664 | "# Exercise: create a column data source with the autompg sample data frame and plot it\n", 665 | "\n", 666 | "from bokeh.sampledata.autompg import autompg_clean as df\n" 667 | ] 668 | }, 669 | { 670 | "cell_type": "code", 671 | "execution_count": null, 672 | "metadata": { 673 | "collapsed": true 674 | }, 675 | "outputs": [], 676 | "source": [] 677 | } 678 | ], 679 | "metadata": { 680 | "kernelspec": { 681 | "display_name": "Python 3", 682 | "language": "python", 683 | "name": "python3" 684 | }, 685 | "language_info": { 686 | "codemirror_mode": { 687 | "name": "ipython", 688 | "version": 3 689 | }, 690 | "file_extension": ".py", 691 | "mimetype": "text/x-python", 692 | "name": "python", 693 | "nbconvert_exporter": "python", 694 | "pygments_lexer": "ipython3", 695 | "version": "3.6.2" 696 | } 697 | }, 698 | "nbformat": 4, 699 | "nbformat_minor": 1 700 | } 701 | --------------------------------------------------------------------------------