## Developing Dashboard Applications with Bokeh
*Luke Canavan*
Bokeh seeks to connect PyData tools and users to web-based, interactive visualization
[KeplerGO/lightkurve](https://github.com/KeplerGO/lightkurve)
Community of Users
### Bokeh 1.0 Announcement Features include: * Highly customizable plotting primitives * Interactive plot tools (pan, hover, zoom, etc) * HTML Widgets (sliders, dropdowns, etc) * Native support for network graphs and geo data * Jupyter Notebook, Jupyter Lab, Zeppelin support * JS and Python callbacks on data changes and events * And much more
### Outline * Building visualizations from primitives * Styling using Palettes and Themes * Layouts with bokeh.layouts and custom templates * Running as a server application
### Goal
### Building visualizations from primitives
Pick what graphical primitives to use, provide the data, and specify how to map visual properties to data fields. Bokeh will take care of the rest.
### Building Blocks
``` >>> from bokeh.models import Circle >>> circle = Circle(x=5, y=10, fill_color="red") >>> circle.to_json(include_defaults=False) { 'id': '1002', 'x': {'value': 5}, 'y': {'value': 10}, 'fill_color': {'value': 'red'} } ```
### Write data driven visualizations ``` >>> from bokeh.models import ColumnDataSource >>> data = { "time": [...], "value": [...], "color": [...]} ### From Dict[str, list] >>> source = ColumnDataSource(data) ### From Pandas DataFrame >>> df = pd.DataFrame(data) >>> source = ColumnDataSource(df) ```
### Map visual properties to data fields ``` >>> source = ColumnDataSource(...) ### Using bokeh.models API >>> plot.add_glyph( source, Circle(x='time', y='value', fill_color='color')) ### Using bokeh.plotting API >>> plot.circle( x='time', y='value', fill_color='color', source=source) ```
To Reiterate: Pick what graphical primitives to use, provide the data, and specify how to map visual properties to data fields. Bokeh will take care of the rest. More reading at [Enjoying the bokeh.models API](https://bokeh.github.io/blog/2017/7/5/idiomatic_bokeh/)
### Styling using Palettes and Themes
Bokeh offers many aesthetically pleasing color palettes including the Brewer and D3 palettes.
[Made with Holoviews](http://holoviews.org/gallery/demos/bokeh/autompg_violins.html#bokeh-gallery-autompg-violins)
Bokeh also offers perceptually uniform color palettes to allow users to map data to color ranges.
[Made with Datashader](http://datashader.org/getting_started/1_Introduction.html)
Themes are great for maintaining consistent style across several plots ``` attrs: Axis: axis_line_color: "#49483E" axis_label_text_color: "#888888" major_label_text_color: "#888888" major_tick_line_color: "#49483E" minor_tick_line_color: null axis_label_standoff: 10 Plot: background_fill_color: "#282828" border_fill_color: "#282828" outline_line_color: "#49483E" outline_line_alpha: 0.25 ```
Community-created Themes
Caliber
Monokai Dark
Minimal Dark
More reading at [Styling Bokeh Visualizations](https://bokeh.github.io/blog/2017/7/24/styling-bokeh/)
### Layouts with bokeh.layouts and custom templates
Plots and Widgets can be responsive
The bokeh.layouts API offers a "rows and columns"-based layout interface ``` from bokeh.layouts import layout page = layout([ [bollinger], [sliders, plot], [p1, p2, p3], ], sizing_mode='stretch_both') show(page) ```
The bokeh.layouts API offers a "rows and columns"-based layout interface
### Using custom templates Support for embedding plots into custom Jinja templates ```
{{ embed(roots.plot1) }}
{{ embed(roots.plot2) }}
{{ plot_script }} ```
Bokeh + CSS Layout Models = Amazing Layouts
[CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/)
Dask Distributed's diagnostic UI uses CSS Grid
[Dask Examples](http://examples.dask.org/)
### Running as a Bokeh server application
Bokeh Server keeps Python and JS models in sync.
Python callbacks can executed on property changes (and JS will react too) ``` def update(attr, old, new): plot.title.text = new x = Select(title='X-Axis', value='mpg', options=columns) x.on_change('value', update) ```
Streaming data source methods: ``.stream`` to append data incrementally to column ends ``.patch`` for random access updates anyway
Document-level Python callbacks are intended for server-driven updates like pushes and polling ``` def stream_image(): ... source.data["image"] = [image] doc.add_periodic_callback(acquire_image, 100) ```
### Face Detection Example
### Resources: * **GitHub:** github.com/bokeh/bokeh * **Documentation:** bokeh.pydata.org * **Mailing list:** groups.google.com/a/continuum.io/forum/#!forum/bokeh * **Gitter Chat:** gitter.im/bokeh/bokeh * **#bokeh** tag on StackOverflow
### Thanks