将带有小部件的交互式散景图导出到独立HTML

时间:2018-08-23 15:17:18

标签: html export jupyter-notebook bokeh

我正在寻找一种方法,将包含交互式Bokeh图和小部件的Jupyter Notebook导出到独立HTML。当使用工具栏中的Jupyter NB“下载至” HTML函数时,除了交互式散景图外,其他所有内容都可以很好地导出,静态Bokeh图也可以很好地导出(静态图也为“交互式”,但基础数据不会更改)

如何使用在独立HTML中工作的小部件来获得交互式绘图?

下面您可以在安装了Bokeh 13.0的Jupyter Notebook中找到一个可用的示例。

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)

如果我将output_notebook()更改为output_file('tryout.html'),它会给我以下错误,我不理解,也可以找到解决方法:

RuntimeError:未为笔记本类型“无”安装显示挂钩

希望任何人都可以帮助我解决这个问题。

提前谢谢!

1 个答案:

答案 0 :(得分:2)

您要的是不可能的,至少在我了解您的问题的情况下是不可能的。您已经创建了具有真正的Python代码回调的Bokeh服务器应用程序。独立的HTML文档不可能运行真实的Python代码,因为浏览器完全无法运行Python代码。真正的Python代码回调需要实时运行的Python解释程序。如上所述,当您将bokeh服务器应用程序嵌入笔记本中时,该过程就是IPython内核。

如果您只想要可以在笔记本之外运行的Bokeh服务器应用程序(需要在Bokeh服务器上运行,因为这是运行回调的Python进程),那么最简单的方法是将所有代码放入脚本中与

一起运行
bokeh serve --show myapp.py

此类应用的非常粗略的轮廓是:

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)

或者,也可以将Bokeh服务器应用程序嵌入“常规” python脚本中。为此,请参见Embedding Bokeh Server as Library