{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Embedding a Bokeh server in a Notebook\n",
    "\n",
    "This notebook shows how a Bokeh server application can be embedded inside a Jupyter notebook. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "import yaml\n",
    "\n",
    "from bokeh.layouts import column\n",
    "from bokeh.models import ColumnDataSource, Slider\n",
    "from bokeh.plotting import figure\n",
    "from bokeh.themes import Theme\n",
    "from bokeh.io import show, output_notebook\n",
    "\n",
    "from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature\n",
    "\n",
    "output_notebook()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "There are various application handlers that can be used to build up Bokeh documents. For example, there is a `ScriptHandler` that uses the code from a `.py` file to produce Bokeh documents. This is the handler that is used when we run `bokeh serve app.py`. Here we are going to use the lesser-known `FunctionHandler`, that gets configured with a plain Python function to build up a document. \n",
    "\n",
    "Here is the function `modify_doc(doc)` that defines our app:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def modify_doc(doc):\n",
    "    df = sea_surface_temperature.copy()\n",
    "    source = ColumnDataSource(data=df)\n",
    "\n",
    "    plot = figure(x_axis_type='datetime', y_range=(0, 25),\n",
    "                  y_axis_label='Temperature (Celsius)',\n",
    "                  title=\"Sea Surface Temperature at 43.18, -70.43\")\n",
    "    plot.line('time', 'temperature', source=source)\n",
    "\n",
    "    def callback(attr, old, new):\n",
    "        if new == 0:\n",
    "            data = df\n",
    "        else:\n",
    "            data = df.rolling('{0}D'.format(new)).mean()\n",
    "        source.data = ColumnDataSource(data=data).data\n",
    "\n",
    "    slider = Slider(start=0, end=30, value=0, step=1, title=\"Smoothing by N Days\")\n",
    "    slider.on_change('value', callback)\n",
    "\n",
    "    doc.add_root(column(slider, plot))\n",
    "\n",
    "    doc.theme = Theme(json=yaml.load(\"\"\"\n",
    "        attrs:\n",
    "            Figure:\n",
    "                background_fill_color: \"#DDDDDD\"\n",
    "                outline_line_color: white\n",
    "                toolbar_location: above\n",
    "                height: 500\n",
    "                width: 800\n",
    "            Grid:\n",
    "                grid_line_dash: [6, 4]\n",
    "                grid_line_color: white\n",
    "    \"\"\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "We take the function above and configure a `FunctionHandler` with it. Then we create an `Application` that uses handler. (It is possible, but uncommon, for Bokeh applications to have more than one handler.) The end result is that the Bokeh server will call `modify_doc` to build new documents for every new sessions that is opened."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from bokeh.application.handlers import FunctionHandler\n",
    "from bokeh.application import Application\n",
    "\n",
    "handler = FunctionHandler(modify_doc)\n",
    "app = Application(handler)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Now we can display our application using ``show``:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "show(app)"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "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.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
