散景 | Jupyter 笔记本 |蟒蛇 |情节未显示

Posted

技术标签:

【中文标题】散景 | Jupyter 笔记本 |蟒蛇 |情节未显示【英文标题】:Bokeh | Jupyter Notebook | Python | Plot Not Showing 【发布时间】:2018-03-14 12:10:49 【问题描述】:

过去几周我一直在学习 Bokeh 包(我认为它在可视化方面非常出色)。

不幸的是,我遇到了一个我一生都无法解决的问题,想办法解决。

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

Using bokeh to plot interactive pie chart in Jupyter/Python - 参考答案#3

https://github.com/bokeh/bokeh/blob/0.12.9/examples/howto/notebook_comms/Jupyter%20Interactors.ipynb

以下代码(在 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)

在阅读散景文档并阅读 GitHub 上的视图线程后,“回调”函数对我来说有点不清楚,因为我不完全确定要解析什么(如果实际上 attr、旧、新需要确定元素也解析了)

任何帮助将不胜感激

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

亲切的问候,

阿德里安

【问题讨论】:

你看过this指南吗?你错过了重要的push_notebook 感谢您的回复!我已经在 J​​upyter 中执行了这段代码,它运行良好。但是,将 push_notebook 添加到我的代码中并不会改变任何内容。你在你的机器上执行过这个吗? 我认为你在show函数中也需要notebook_handle=True。目前我无法运行你的代码,但如果没有其他人可以帮助你,我今晚会看看。也许如果您添加导入等以运行示例,更多人可能会更快地帮助您。我不太确定您为什么要进行自定义 js 回调?可能来自楔形示例?我认为plot.circle 你不需要那个,但我只能在今晚进行测试。 【参考方案1】:

您目前正在混合使用不同的交互方式,但不幸的是,您总是会因为每种不同的方式而错过一些东西。

您使用的滑块来自散景,但不幸的是,它看起来像 slider.on_change 只有在您通过散景服务器运行时才有效。来自documentation:

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

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

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

然后你需要一个方法来将数据推送到输出。我猜散景服务器可以以某种方式自然地做到这一点,对于没有散景服务器push_notebook 的 jupyter 笔记本来说似乎是解决方案。请注意,您需要show(..., notebook_handle=True) 才能推送。

方案一使用散景服务器

滑块和其他小部件会自动将其状态同步回 python,因此您可以使用slider.on_change。您不需要 CustomJS。数据流应如下所示:

python script -> bokeh server -> html -> userinput -> bokeh server -> python callbacks -> bokeh server updates plots

解决方案 2 使用散景滑块,但通过 CustomJS 同步

如果您不想运行单独的进程,您可以使用 jupyter 内核在您的 python 笔记本中执行代码。数据流:

jupyter notebook -> html -> user input -> customjs -> jupyter kernel -> python callbacks -> push_notebook to update plots

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

如果您还没有使用散景小部件,您可以使用 ipywidgets,它专为 jupyter notebook 中的交互性而设计。数据流如下:

jupyter notebook -> html -> user input -> ipywidgets sync automatically -> python callbacks -> push_notebook

我在这里使用interact,但其他小部件应该可以按预期工作。

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,如果您不使用 conda,则需要调用 jupyter nbextension enable --py --sys-prefix widgetsnbextension。详情see the documentation

【讨论】:

解决方案 2 完美运行。感谢您对我的帮助和详尽的解释。你是个好人。我自己的知识更多,但是解决方案 1 与解决方案 2 相比有什么优点和缺点(反之亦然)?我想这个答案是主观的,取决于我想要达到的目标,所以如果你能分享任何个人意见或最佳实践方法,那就太好了。在提出问题之前,我尝试了解决方案 3,但我觉得如果我开始构建 Bokeh Dashboards,它并没有提供那么大的灵活性。 CustomJS 当然只有在 ipython 存在时才有效,所以如果你想转移到“纯 web 应用程序”散景服务器可能是要走的路。我从未尝试过散景服务器,但如果它真的像亚历克斯回答那样简单,我肯定会尝试。这真的取决于你想做什么。【参考方案2】:

我想您的问题与服务器有关,尽管您同时拥有 CustomJS 和服务器回调。

我不熟悉以前在笔记本中做散景服务器的方式(push_notebook)。 新方法是这样的:您将代码包装在一个带有一个参数(文档)的函数中,并在该文档上调用add_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")

【讨论】:

我在散景中找不到太多关于这种新方式的信息。这是否已经记录在用户指南中,还是目前仅在 API 文档中?这是否也适用于 jupyter 笔记本或仅适用于散景服务器? 此示例在笔记本中运行,基本上启动了一个服务于app 的服务器进程(或线程,不确定)。据我所知,这没有完全记录。(特别是在用户指南中) 更正:实际上它是用example引用的here 首先,感谢你们两位花时间帮助我,非常感谢。这两份文件 Alex 真的很有帮助!今晚将阅读它们,以了解如何构建这些应用程序。

以上是关于散景 | Jupyter 笔记本 |蟒蛇 |情节未显示的主要内容,如果未能解决你的问题,请参考以下文章

matplotlib:figimage 未显示在 Jupyter 笔记本中

在jupyter实验室中加载bokehJS

绘图图表未显示在 Jupyter 笔记本中

未使用下拉菜单选择更新散景图

防止情节在 jupyter notebook 中显示

嵌入式散景数据表未在 Django 中显示