问题
I'm looking for a way to export my Jupyter Notebook containing interactive Bokeh plots with widgets to standalone HTML. When using the Jupyter NB "download to" HTML function located in the toolbar, everything but the interactive Bokeh plots export well, also the static Bokeh plots (static plots are 'interactive' as well, but the underlying data does not change)
How do I get the interactive plots with widgets working in a standalone HTML?
Below you can find a working example in Jupyter Notebook with Bokeh 13.0 installed.
import numpy as np
import pandas as pd
from bokeh.io import save, curdoc,output_file ,show, output_notebook, push_notebook
from bokeh.plotting import figure, gridplot
from bokeh.models import ColumnDataSource, Panel
from bokeh.models.widgets import Slider, Tabs, DataTable, TableColumn
from bokeh.layouts import layout, WidgetBox
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
# output_file('tryout.html')
output_notebook()
# Static Bokeh plot:
data = pd.DataFrame(np.random.random([10,2]),columns=['x','y'])
dataMean = pd.DataFrame([],columns=['mean','std'])
dataMean.loc[:,'mean'] =data.mean()
dataMean.loc[:,'std'] =data.std()
src1 = ColumnDataSource(data)
src2 = ColumnDataSource(dataMean)
p = figure(plot_width = 700, plot_height = 400,
title = 'Test case',x_axis_label = 'x', y_axis_label = 'y')
p.line(source=src1,y='y',x='x',color='blue',line_width=2)
p.circle(source=src1,y='y',x='x',color='green')
columnsT = [TableColumn(field="mean", title="mean"),
TableColumn(field="std", title='std')]
data_table = DataTable(source=src2, columns=columnsT, width=400, height=400)
data_table.index_position = None
controls = WidgetBox(data_table)
layO = layout([[p],[controls]])
# Make a tab with the layout
tab1 = Panel(child=layO, title = 'test')
tabs = Tabs(tabs=[tab1])
show(tabs)
# Now the same plot, but fitted with a slider widget
def modify_doc(doc):
def make_dataset(N = 2):
data = pd.DataFrame(np.random.random([N,2]),columns=['x','y'])
dataMean = pd.DataFrame([],columns=['mean','std'])
dataMean.loc[:,'mean'] =data.mean()
dataMean.loc[:,'std'] =data.std()
return ColumnDataSource(data),ColumnDataSource(dataMean)
def make_plot(src):
# Blank plot with correct labels
p = figure(plot_width = 700, plot_height = 400,
title = 'Test case',x_axis_label = 'x', y_axis_label = 'y')
p.line(source=src,y='y',x='x',color='blue',line_width=2)
p.circle(source=src,y='y',x='x',color='green')
return p
def update(attr, old, new):
new_src, new_src2 = make_dataset(N_select.value)
src.data.update(new_src.data)
src2.data.update(new_src2.data)
N_select = Slider(start = 2, end = 20, step = 1, value = 2, title = 'number of points',width=700)
N_select.on_change('value', update)
columnsT = [
TableColumn(field="mean", title="mean"),
TableColumn(field="std", title='std')]
src, src2 = make_dataset(N_select.value)
data_table = DataTable(source=src2, columns=columnsT, width=400, height=400)
data_table.index_position = None
p = make_plot(src)
# Put controls in a single element
controls = WidgetBox(N_select,data_table)
layO = layout([[p],[controls]])
# Make a tab with the layout
tab1 = Panel(child=layO, title = 'test')
tabs = Tabs(tabs=[tab1])
doc.add_root(tabs)
handler= FunctionHandler(modify_doc)
app = Application(handler)
show(app)
If I change the output_notebook() to output_file('tryout.html'), it givesme the following error, which I dont understand and could find a solution for as well:
RuntimeError: no display hook installed for notebook type None
Hope anybody is able to help me out with this.
thanks in advance!
回答1:
What you are asking for is not possible, at least not as I understand your question. You have created a Bokeh server application, with real Python code callbacks. It is not possible for a standalone HTML document to run real Python code, because browsers have no ability whatsoever to run Python code. Real Python code callbacks require a live, running Python interpreter process. When you embed a bokeh server app in the notebook, as you have done above, that process is the IPython kernel.
If you simply want a Bokeh sever app (which requires running on a Bokeh server, because that is the Python process that runs your callbacks) that can run outside the notebook, the easiest way is to put all the code in a script that you run with
bokeh serve --show myapp.py
The very rough outline of such apps is:
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import Slider
from bokeh.plotting import figure
# create plots
plot = figure(...)
# create widgets
slider = Slider(...)
# add callbacks to widgets
def update(attr, old, new):
pass
slider.on_change('value', update)
# put things in a layout
layout = column(slider, plot)
# add to curdoc
curdoc().add_root(layout)
Alternatively it's also possible to embed Bokeh server apps in "regular" python scripts. For that, see Embedding Bokeh Server as Library.
来源:https://stackoverflow.com/questions/51989100/export-interactive-bokeh-plots-with-widgets-to-standalone-html