Bokeh | Jupyter笔记本| Python |未显示绘图

Bokeh | Jupyter笔记本| Python |未显示绘图,python,hover,slider,bokeh,Python,Hover,Slider,Bokeh,在过去的几周里,我一直在学习Bokeh软件包(在我看来,它非常适合可视化) 不幸的是,我遇到了一个我一生都无法解决的问题,那就是如何解决 下面的两个链接很有帮助,但我似乎无法复制我的问题 -请参阅答案#3 下面的代码(Jupyter)正确地显示了图形,并正确地显示了滑块,但我不确定如何将两者连接起来,因为当我移动滑块时,图形保持静态 我使用的是Python 3.6和Bokeh 12.9 N = 300 source = ColumnDataSource(data={'x':random(N)

在过去的几周里,我一直在学习Bokeh软件包(在我看来,它非常适合可视化)

不幸的是,我遇到了一个我一生都无法解决的问题,那就是如何解决

下面的两个链接很有帮助,但我似乎无法复制我的问题

-请参阅答案#3

下面的代码(Jupyter)正确地显示了图形,并正确地显示了滑块,但我不确定如何将两者连接起来,因为当我移动滑块时,图形保持静态

我使用的是Python 3.6和Bokeh 12.9

N = 300

source = ColumnDataSource(data={'x':random(N), 'y':random(N)}) 

plot = figure(plot_width=950, plot_height=400) 

plot.circle(x='x', y='y', source=source)

callback = CustomJS(code=""" 
if (IPython.notebook.kernel !== undefined) {
    var kernel = IPython.notebook.kernel;
    cmd = "update_plot(" + cb_obj.value + ")";
    kernel.execute(cmd, {}, {})}; 
""")

slider = Slider(start=100, end=1000, value=N, step=10, callback=callback)

def callback(attr, old, new):
    N = slider.value
    source.data={'x':random(N), 'y':random(N)}

slider.on_change('value', callback)

layout = column(slider, plot) 

curdoc().add_root(layout)

show(widgetbox(slider, width = 300)) 

show(plot)
在阅读了bokeh文档和GitHub上的一个视图线程之后,“回调”函数对我来说有点不清楚,因为我不完全确定该解析什么(如果事实上attr、old、new也需要解析某些元素)

任何帮助都将不胜感激

希望我没有错过任何明显的东西

亲切问候,


Adrian

我想你的问题与服务器有关,尽管你有一个CustomJS和一个服务器回调

我不熟悉以前在笔记本中使用bokeh服务器的方法(
push\u notebook
)。 新方法是这样的:将代码包装在一个函数中,该函数使用一个参数(文档),然后对该文档调用
add\u layout
。然后,您构建一个具有该功能的应用程序并显示它

这使得:

from bokeh.models import ColumnDataSource, Slider
from bokeh.layouts import column
from bokeh.plotting import figure, show, output_notebook
from numpy.random import random
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler

output_notebook()

def modify_doc(doc):
    N = 300

    source = ColumnDataSource(data={'x':random(N), 'y':random(N)}) 

    plot = figure(plot_width=950, plot_height=400) 

    plot.circle(x='x', y='y', source=source)

    slider = Slider(start=100, end=1000, value=N, step=10)

    def callback(attr, old, new):
        N = new  # but slider.value would also work
        source.data={'x': random(N), 'y': random(N)}

    slider.on_change('value', callback)

    layout = column(slider, plot) 

    doc.add_root(layout)

app = Application(FunctionHandler(modify_doc))
show(app, notebook_url="localhost:8888")

您目前正在混合不同的交互方式,但不幸的是,您总是错过了每种不同方式的一些东西

您使用的滑块来自bokeh,但不幸的是,它看起来像
滑块。on_change
仅在您运行bokeh服务器时有效。从:

使用bokeh serve启动bokeh服务器,并使用.on_change(或对于某些小部件,.on_单击)设置事件处理程序

我在运行jupyter笔记本和bokeh服务器上找不到那么多,但似乎讨论了这种可能性。它还提到了
bokeh.application
,但我从未使用过它,所以不知道它是如何工作的

另外,您还使用了一个自定义js回调函数,它调用jupyter内核并尝试执行
update\u plot(value)
,但您从未定义过这样的函数,因此它什么也不做

然后需要一种方法将数据推送到输出。我想bokeh服务器可以在某种程度上实现这一点,因为没有bokeh服务器的jupyter笔记本电脑似乎是解决方案。请注意,您需要
show(…,notebook\u handle=True)
才能推送

解决方案1使用bokeh服务器 滑块和其他小部件会自动将其状态同步回python,因此您可以使用
滑块。您不需要CustomJS。数据流应如下所示:

python脚本->bokeh服务器->html->userinput->bokeh服务器->python回调->bokeh服务器更新绘图

output_notebook()

N = 300

source = ColumnDataSource(data={'x':random(N), 'y':random(N)}) 

plot = figure(plot_width=950, plot_height=400) 

plot.circle(x='x', y='y', source=source)

callback = CustomJS(code=""" 
if (IPython.notebook.kernel !== undefined) {
    var kernel = IPython.notebook.kernel;
    cmd = "update_plot(" + cb_obj.value + ")";
    kernel.execute(cmd, {}, {})}; 
""")

slider = Slider(start=100, end=1000, value=N, step=10, callback=callback)

# must have the same name as the function that the CustomJS tries to call
def update_plot(N):
    source.data={'x':random(N), 'y':random(N)}
    # push notebooks to update plots
    push_notebook()

layout = column(slider, plot) 
# notebook_handle must be true, otherwise push_notebook will not work
h1 = show(layout, notebook_handle=True)
解决方案2使用bokeh滑块,但通过CustomJS同步 如果不想运行单独的进程,可以使用jupyter内核在python笔记本中执行代码。数据流:

jupyter笔记本->html->用户输入->customjs->jupyter内核->python回调->push_笔记本更新绘图

output_notebook()

N = 300

source = ColumnDataSource(data={'x':random(N), 'y':random(N)}) 

plot = figure(plot_width=950, plot_height=400) 

plot.circle(x='x', y='y', source=source)

callback = CustomJS(code=""" 
if (IPython.notebook.kernel !== undefined) {
    var kernel = IPython.notebook.kernel;
    cmd = "update_plot(" + cb_obj.value + ")";
    kernel.execute(cmd, {}, {})}; 
""")

slider = Slider(start=100, end=1000, value=N, step=10, callback=callback)

# must have the same name as the function that the CustomJS tries to call
def update_plot(N):
    source.data={'x':random(N), 'y':random(N)}
    # push notebooks to update plots
    push_notebook()

layout = column(slider, plot) 
# notebook_handle must be true, otherwise push_notebook will not work
h1 = show(layout, notebook_handle=True)
解决方案3使用ipywidgets 如果你没有嫁给bokeh小部件,你可以使用iPyWidget,它是为jupyter笔记本中的互动性而设计的。数据流如下所示:

jupyter笔记本->html->用户输入->ipywidgets自动同步->python回调->push_笔记本

我在这里使用
交互
,但是其他小部件应该按预期工作

from ipywidgets import interact

output_notebook()

N = 300

source = ColumnDataSource(data={'x':random(N), 'y':random(N)}) 

plot = figure(plot_width=950, plot_height=400) 

plot.circle(x='x', y='y', source=source)

def update_plot(v):
    N = v
    print(N)
    source.data={'x':random(N), 'y':random(N)}
    # push changed plots to the frontend
    push_notebook()

# notebook_handle must be true so that push_notebook works
show(plot, notebook_handle=True)

请注意,您需要正确安装ipywidgets,这包括调用
jupyter nbextension enable--py--sys prefix widgetsnbextension
,如果您不使用conda。有关详细信息,请参见指南?您缺少重要的
推送笔记本
。感谢回复!我已经在Jupyter中执行了这段代码,它工作得非常好。然而,将push_笔记本添加到我的代码中不会改变任何东西。您是否在您的机器上执行了此操作?我想您还需要
show
功能中的
notebook\u handle=True
。目前我无法运行您的代码,但如果没有其他人可以帮助您,我将在今晚查看。也许,如果您添加导入等来运行示例,更多的人可能会更快地帮助您。我不太清楚你为什么要做自定义js回调?可能是从楔块的例子?我认为对于plot.circle,你不需要它,但我只能在今晚进行测试。我真的找不到关于bokeh新方法的太多信息。这已经记录在用户指南中了,还是目前仅记录在API文档中?这也适用于jupyter笔记本还是仅适用于bokeh服务器?此示例在笔记本中运行,基本上启动一个服务器进程(或线程,不确定),为
应用程序提供服务。据我所知,这并没有完整的文档记录。(特别是在用户指南中)更正:事实上,它引用了一个最重要的,感谢你们两位花时间帮助我,非常感谢。这两个文件都非常有用!今晚我将阅读它们,以了解如何构建这些应用程序。解决方案2非常有效。谢谢你的帮助和详尽的解释。你真是太好了。据我所知,更多信息,但解决方案1是否比解决方案2有任何优点和缺点(反之亦然)?我想这个答案是主观的,取决于我想要实现什么,所以如果你能分享任何个人意见或最佳实践方法,那就太好了。在提出问题之前,我尝试了解决方案3,但我觉得如果我开始构建Bokeh仪表盘,它并没有提供那么多的灵活性。当然,CustomJS只在ipython存在时才起作用,所以如果你想移动到“pu”