2

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

如何使用独立 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: no display hook installed for notebook type None

希望有人能够帮助我解决这个问题。

提前致谢!

4

1 回答 1

4

你所要求的是不可能的,至少不是我理解你的问题。您已经创建了一个带有真实 Python 代码回调的 Bokeh 服务器应用程序。独立的 HTML 文档不可能运行真正的 Python 代码,因为浏览器没有任何能力运行 Python 代码。真正的 Python 代码回调需要一个实时运行的 Python 解释器进程。当您在笔记本中嵌入散景服务器应用程序时,如上所述,该过程就是 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

于 2018-08-23T16:06:01.703 回答