{ "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