{
"cells": [
{
"cell_type": "markdown",
"id": "b9186963",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Interactive plotting with Bokeh\n",
"\n",
"[reference](https://docs.bokeh.org/en/latest/docs/user_guide/interaction.html)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ff29ee73",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"from bokeh.io import output_notebook, show\n",
"from bokeh.plotting import figure\n",
"output_notebook() # alternatively one could use output_file('file_name.html')"
]
},
{
"cell_type": "markdown",
"id": "6aa9142e",
"metadata": {
"cell_style": "center",
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Column Data Source (CDS)\n",
"([reference](https://docs.bokeh.org/en/latest/docs/user_guide/data.html))\n",
"\n",
"- Preferred way to handle data in ```bokeh```\n",
"- Can take a ```dict()``` or a ```pandas``` ```DataFrame``` as argument\n",
"- Useful for most interactive plotting"
]
},
{
"cell_type": "markdown",
"id": "393a3cdf",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"#### Line plot with a CDS"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d3cdec65",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"from bokeh.models import BooleanFilter, CDSView, ColumnDataSource as CDS\n",
"\n",
"#create CDS\n",
"npoints = 100\n",
"dline = dict(x=np.arange(npoints), \n",
" y=np.random.normal(0, 0.5, size=npoints),\n",
" )\n",
"source = CDS(data=dline)\n",
"source"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "89b8716a",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"#figure options\n",
"TOOLS = \"pan,hover,box_select,lasso_select,help,reset\"\n",
"fig_options = dict(plot_width=400, plot_height=400, tools=TOOLS)\n",
"\n",
"#create figure with specifically chosen tools\n",
"pleft = figure(**fig_options)\n",
"show(pleft)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d512c266",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"marker_options = dict(color='red',\n",
" fill_color='orange', fill_alpha=0.8)\n",
"pleft.triangle('x', 'y', source=source, **marker_options) #pleft.scatter() can be used in a similar way\n",
"\n",
"show(pleft)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "acb3a64b",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"#create CDS view (filtered CDS)\n",
"#later we will see how to to the same with a JavaScript callback\n",
"positives = [True if k>0 else False for k in source.data['y']]\n",
"view = CDSView(source=source, filters=[BooleanFilter(positives)])\n",
"\n",
"#create another figure using the view\n",
"#notice that the y ranges are being shared\n",
"pright = figure(y_range=pleft.y_range, **fig_options)\n",
"pright.circle('x', 'y', source=source, view=view, **marker_options)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "deab5bc2",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"#introducing layouts\n",
"from bokeh.layouts import row\n",
"lay = row(pleft, pright)\n",
"show(lay)"
]
},
{
"cell_type": "markdown",
"id": "2277b8df",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"There are three ways to build interactive plots with ```bokeh```:\n",
"- the one you just saw\n",
" - very straightforward / limited\n",
"- use widgets together with the ```bokeh``` server\n",
" - much more flexible, Python only / requires a running server, some limitations\n",
"- use widgets together with Javascript callbacks\n",
" - \"infinitely\" flexible / requires some Javascript (in general only a bit)\n",
" - it allows the generation of standalone HTML files that can be easily shared and embedded"
]
},
{
"cell_type": "markdown",
"id": "b80ea603",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Using ```CustomJS``` callbacks\n",
"\n",
"[reference](https://docs.bokeh.org/en/latest/docs/user_guide/interaction/callbacks.html)"
]
},
{
"cell_type": "markdown",
"id": "bd6d87ad",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"First we will create widgets:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "10d43b01",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"#many widgets available: https://docs.bokeh.org/en/latest/docs/user_guide/interaction/widgets.html\n",
"#one can even create a custom widget (advanced): https://docs.bokeh.org/en/latest/docs/user_guide/extensions_gallery/widget.html\n",
"from bokeh.models import CustomJS, Slider, Button\n",
"\n",
"button = Button(label=\"Click!\", button_type=\"warning\")\n",
"slider = Slider(start=1, end=40, value=5, step=1)\n",
"show(row(button, slider))"
]
},
{
"cell_type": "markdown",
"id": "cce387c4",
"metadata": {},
"source": [
"Let us add some data to the CDS:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0d997d25",
"metadata": {},
"outputs": [],
"source": [
"def print_cds_columns(s):\n",
" for i,col in enumerate(s.data):\n",
" print('CDS column #{}: {}'.format(i,col))\n",
"\n",
"source.data['size'] = np.ones(npoints)*10\n",
"print_cds_columns(source)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "51b940b4",
"metadata": {},
"outputs": [],
"source": [
"pint = figure(**fig_options)\n",
"pint.circle('x', 'y', size='size', source=source, **marker_options)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "25e7a8e7",
"metadata": {},
"outputs": [],
"source": [
"code = \"\"\"\n",
" var val = slider.value;\n",
" var data = s.data;\n",
" for (var i = 0; i