13 Deploying Bokeh Apps ¶
In the previous sections we discovered how to use a
to build a Jupyter notebook with interactive visualizations that can be exported to a standalone HTML file, as well as how to use
to set up dynamic interactivity backed by the Jupyter Python kernel. However, frequently we want to package our visualization or dashboard for wider distribution, backed by Python but run outside of the notebook environment. Bokeh Server provides a flexible and scalable architecture to deploy complex interactive visualizations and dashboards, integrating seamlessly with Bokeh and with HoloViews.
Bokeh server apps can be used for a wide range of applications, but here we will show how to use them with Datashader and related libraries:
For a detailed background on Bokeh Server see the Bokeh user guide . In this tutorial we will discover how to deploy the visualizations we have created so far as a standalone Bokeh Server app, and how to flexibly combine HoloViews and Panel to build complex apps. We will also reuse a lot of what we have learned so far---loading large, tabular datasets, applying Datashader operations to them, and adding linked Streams to our app.
A simple Bokeh app ¶
The preceding sections of this tutorial focused solely on the Jupyter notebook, but now let's look at a bare Python script that can be deployed using Bokeh Server:
with open('../apps/server_app.py', 'r') as f: print(f.read())
import dask.dataframe as dd import holoviews as hv from holoviews.operation.datashader import datashade hv.extension('bokeh') # 1. Load data and Datashade it ddf = dd.read_parquet('../data/nyc_taxi_wide.parq')[['dropoff_x', 'dropoff_y']].persist() points = hv.Points(ddf, kdims=['dropoff_x', 'dropoff_y']) shaded = datashade(points).opts(plot=dict(width=800, height=600)) # 2. Instead of Jupyter's automatic rich display, render the object as a bokeh document doc = hv.renderer('bokeh').server_doc(shaded) doc.title = 'HoloViews Bokeh App'
Step 1 of this app should be very familiar by now -- declare that we are using Bokeh to render plots, load some taxi dropoff locations, declare a Points object, Datashade them, and set some plot options.
At this point, if we were working with this code in a notebook, we would simply type
and let Jupyter's rich display support take over, rendering the object into a Bokeh plot and displaying it inline. Here, step 2 adds the code necessary to do those steps explicitly:
get a handle on the Bokeh renderer object using
create a Bokeh document from
shadedby passing it to the renderer's
- optionally, change some properties of the Bokeh document like the title.
This simple chunk of boilerplate code can be added to turn any HoloViews object into a fully functional, deployable Bokeh app!
Deploying the app ¶
Assuming that you have a terminal window open with the
environment activated, in the
directory, you can launch this app using Bokeh Server:
bokeh serve --show server_app.py
If you don't already have a favorite way to get a terminal, one way is to
open it from within Jupyter
, then make sure you are in the
directory, and make sure you are in the right Conda environment if you created one (activating it using
source activate pyviz
# Exercise: Modify the app to display the pickup locations and add a tilesource, then run the app with bokeh serve # Tip: Refer to the previous notebook
Building an app with custom widgets ¶
The above app script can be built entirely without using Jupyter, though we displayed it here using Jupyter for convenience in the tutorial. Jupyter notebooks are also often helpful when initially developing such apps, allowing you to quickly iterate over visualizations in the notebook, deploying it as a standalone app only once we are happy with it. In this section we will combine everything we have learned so far including declaring of various parameters to control our visualization using a set of widgets.
We begin as usual with a set of imports:
import holoviews as hv, geoviews as gv, param, dask.dataframe as dd, panel as pp from colorcet import cm from bokeh.document import Document from holoviews.operation.datashader import rasterize, shade from holoviews.streams import RangeXY from cartopy import crs hv.extension('bokeh', logo=False)