From 486e2c6748f42720f52cd2f430439d67714d3860 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 12 Apr 2017 14:10:43 +0100
Subject: [PATCH 1/4] Added BokehRenderer.app method to create bokeh apps in
scripts and notebooks
---
holoviews/plotting/bokeh/renderer.py | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/holoviews/plotting/bokeh/renderer.py b/holoviews/plotting/bokeh/renderer.py
index 7f0b97529b..15492065c2 100644
--- a/holoviews/plotting/bokeh/renderer.py
+++ b/holoviews/plotting/bokeh/renderer.py
@@ -4,10 +4,13 @@
import param
from param.parameterized import bothmethod
+
+from bokeh.application.handlers import FunctionHandler
+from bokeh.application import Application
from bokeh.charts import Chart
from bokeh.document import Document
from bokeh.embed import notebook_div
-from bokeh.io import load_notebook, curdoc
+from bokeh.io import load_notebook, curdoc, show
from bokeh.models import (Row, Column, Plot, Model, ToolbarBox,
WidgetBox, Div, DataTable, Tabs)
from bokeh.plotting import Figure
@@ -92,6 +95,28 @@ def get_widget(self_or_cls, plot, widget_type, **kwargs):
return super(BokehRenderer, self_or_cls).get_widget(plot, widget_type, **kwargs)
+ @bothmethod
+ def app(self_or_cls, plot, notebook=False):
+ """
+ Creates a bokeh app from a HoloViews object or plot. By
+ default simply uses attaches plot to bokeh's curdoc and
+ returns the Document, if notebook option is supplied creates
+ an Application instance, displays it and returns it.
+ """
+ renderer = self_or_cls.instance(mode='server')
+ if not notebook:
+ doc, _ = renderer(plot)
+ return doc
+
+ def modify_doc(doc):
+ renderer(plot, doc=doc)
+
+ handler = FunctionHandler(modify_doc)
+ app = Application(handler)
+ show(app)
+ return app
+
+
def server_doc(self, plot, doc=None):
"""
Get server document.
From 50130608c9a6d6df755faf7755438836f8be9cca Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 12 Apr 2017 14:31:52 +0100
Subject: [PATCH 2/4] Ensure that importing single backend sets it as active
---
holoviews/plotting/bokeh/__init__.py | 3 +++
holoviews/plotting/mpl/__init__.py | 3 +++
holoviews/plotting/plotly/__init__.py | 3 +++
3 files changed, 9 insertions(+)
diff --git a/holoviews/plotting/bokeh/__init__.py b/holoviews/plotting/bokeh/__init__.py
index 79fdd60839..be8360e5b1 100644
--- a/holoviews/plotting/bokeh/__init__.py
+++ b/holoviews/plotting/bokeh/__init__.py
@@ -33,6 +33,9 @@
Store.renderers['bokeh'] = BokehRenderer.instance()
+if len(Store.renderers) == 1:
+ Store.current_backend = 'bokeh'
+
associations = {Overlay: OverlayPlot,
NdOverlay: OverlayPlot,
GridSpace: GridPlot,
diff --git a/holoviews/plotting/mpl/__init__.py b/holoviews/plotting/mpl/__init__.py
index 4e3d9919ee..95510562d0 100644
--- a/holoviews/plotting/mpl/__init__.py
+++ b/holoviews/plotting/mpl/__init__.py
@@ -81,6 +81,9 @@ def get_color_cycle():
Store.renderers['matplotlib'] = MPLRenderer.instance()
+if len(Store.renderers) == 1:
+ Store.current_backend = 'matplotlib'
+
# Defines a wrapper around GridPlot and RasterGridPlot
# switching to RasterGridPlot if the plot only contains
# Raster Elements
diff --git a/holoviews/plotting/plotly/__init__.py b/holoviews/plotting/plotly/__init__.py
index 9c28b961b5..1f5b59b047 100644
--- a/holoviews/plotting/plotly/__init__.py
+++ b/holoviews/plotting/plotly/__init__.py
@@ -13,6 +13,9 @@
Store.renderers['plotly'] = PlotlyRenderer.instance()
+if len(Store.renderers) == 1:
+ Store.current_backend = 'plotly'
+
Store.register({Points: PointPlot,
Scatter: PointPlot,
Curve: CurvePlot,
From 949435bd52fdb4fa0f9d6900387479b53e0f344d Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 12 Apr 2017 14:40:24 +0100
Subject: [PATCH 3/4] Updated bokeh example apps
---
.../plotting/bokeh/examples/apps/{apps => }/crossfilter.py | 2 --
holoviews/plotting/bokeh/examples/apps/{apps => }/player.py | 0
.../bokeh/examples/apps/{apps => }/selection_stream.py | 6 +++---
3 files changed, 3 insertions(+), 5 deletions(-)
rename holoviews/plotting/bokeh/examples/apps/{apps => }/crossfilter.py (97%)
rename holoviews/plotting/bokeh/examples/apps/{apps => }/player.py (100%)
rename holoviews/plotting/bokeh/examples/apps/{apps => }/selection_stream.py (80%)
diff --git a/holoviews/plotting/bokeh/examples/apps/apps/crossfilter.py b/holoviews/plotting/bokeh/examples/apps/crossfilter.py
similarity index 97%
rename from holoviews/plotting/bokeh/examples/apps/apps/crossfilter.py
rename to holoviews/plotting/bokeh/examples/apps/crossfilter.py
index f9fe0ab3b0..96efaaadd6 100644
--- a/holoviews/plotting/bokeh/examples/apps/apps/crossfilter.py
+++ b/holoviews/plotting/bokeh/examples/apps/crossfilter.py
@@ -35,7 +35,6 @@
continuous = [x for x in columns if x not in discrete]
quantileable = [x for x in continuous if len(df[x].unique()) > 20]
-hv.Store.current_backend = 'bokeh'
renderer = hv.Store.renderers['bokeh']
options = hv.Store.options(backend='bokeh')
options.Points = hv.Options('plot', width=800, height=600, size_index=None,)
@@ -52,7 +51,6 @@ def create_figure():
opts['scaling_factor'] = (1./df[size.value].max())*200
points = hv.Points(df, kdims=kdims, label=label)(plot=opts, style=style)
plot = renderer.get_plot(points)
- plot.initialize_plot()
return plot.state
def update(attr, old, new):
diff --git a/holoviews/plotting/bokeh/examples/apps/apps/player.py b/holoviews/plotting/bokeh/examples/apps/player.py
similarity index 100%
rename from holoviews/plotting/bokeh/examples/apps/apps/player.py
rename to holoviews/plotting/bokeh/examples/apps/player.py
diff --git a/holoviews/plotting/bokeh/examples/apps/apps/selection_stream.py b/holoviews/plotting/bokeh/examples/apps/selection_stream.py
similarity index 80%
rename from holoviews/plotting/bokeh/examples/apps/apps/selection_stream.py
rename to holoviews/plotting/bokeh/examples/apps/selection_stream.py
index 5deb34fd7c..6d1f125868 100644
--- a/holoviews/plotting/bokeh/examples/apps/apps/selection_stream.py
+++ b/holoviews/plotting/bokeh/examples/apps/selection_stream.py
@@ -3,8 +3,7 @@
import holoviews.plotting.bokeh
from holoviews.streams import Selection1D
-hv.Store.current_backend = 'bokeh'
-renderer = hv.Store.renderers['bokeh'].instance(mode='server')
+renderer = hv.Store.renderers['bokeh']
hv.Store.options(backend='bokeh').Points = hv.Options('plot', tools=['box_select'])
data = np.random.multivariate_normal((0, 0), [[1, 0.1], [0.1, 1]], (1000,))
@@ -13,5 +12,6 @@
mean_sel = hv.DynamicMap(lambda index: hv.HLine(points['y'][index].mean()
if index else -10),
kdims=[], streams=[sel])
-doc,_ = renderer((points * mean_sel))
+
+doc = renderer.app((points * mean_sel))
doc.title = 'HoloViews Selection Stream'
From 0a0320febee5249ce370965896b67895be76af01 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 12 Apr 2017 15:33:42 +0100
Subject: [PATCH 4/4] Added docstrings for bokeh app examples
---
holoviews/plotting/bokeh/examples/apps/crossfilter.py | 7 +++++++
holoviews/plotting/bokeh/examples/apps/player.py | 10 ++++++----
.../plotting/bokeh/examples/apps/selection_stream.py | 6 ++++++
3 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/holoviews/plotting/bokeh/examples/apps/crossfilter.py b/holoviews/plotting/bokeh/examples/apps/crossfilter.py
index 96efaaadd6..2b8ef044d5 100644
--- a/holoviews/plotting/bokeh/examples/apps/crossfilter.py
+++ b/holoviews/plotting/bokeh/examples/apps/crossfilter.py
@@ -1,3 +1,10 @@
+"""
+An example demonstrating how to put together a crossfilter app based
+on the Auto MPG dataset. Demonstrates how to dynamically generate
+bokeh plots using the HoloViews API and replacing the bokeh plot
+based on the current widget selections.
+"""
+
import numpy as np
import pandas as pd
import holoviews as hv
diff --git a/holoviews/plotting/bokeh/examples/apps/player.py b/holoviews/plotting/bokeh/examples/apps/player.py
index 800e22a190..f11a48e9c2 100644
--- a/holoviews/plotting/bokeh/examples/apps/player.py
+++ b/holoviews/plotting/bokeh/examples/apps/player.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
+"""
+Example of a simple player widget demonstrating how to connnect
+a simple HoloViews plot with custom widgets and combine them
+into a bokeh layout.
+"""
import numpy as np
from bokeh.io import curdoc
from bokeh.layouts import layout
-from bokeh.models import (
- ColumnDataSource, HoverTool, SingleIntervalTicker, Slider, Button, Label,
- CategoricalColorMapper,
-)
+from bokeh.models import Slider, Button
import holoviews as hv
import holoviews.plotting.bokeh
diff --git a/holoviews/plotting/bokeh/examples/apps/selection_stream.py b/holoviews/plotting/bokeh/examples/apps/selection_stream.py
index 6d1f125868..4bbaec492d 100644
--- a/holoviews/plotting/bokeh/examples/apps/selection_stream.py
+++ b/holoviews/plotting/bokeh/examples/apps/selection_stream.py
@@ -1,3 +1,9 @@
+"""
+Example app demonstrating how to use the HoloViews API to generate
+a bokeh app with complex interactivity. Uses a Selection1D stream
+to compute the mean y-value of the current selection.
+"""
+
import numpy as np
import holoviews as hv
import holoviews.plotting.bokeh