在代理/ jupyterhub后面的jupyter笔记本中使用散景服务器

时间:2018-02-05 15:27:41

标签: jupyter-notebook jupyter bokeh jupyterhub

我想在jupyterhub(AKA是一个身份验证代理)后面的jupyter笔记本实例上开发散景应用程序。我想让交互式散景应用程序回调到笔记本内核。我不想使用笔记本小部件等因为我希望能够将笔记本导出为python文件并且可以使用散景服务器提供。

我的笔记本中的以下代码给出了一个没有错误的空输出:

from bokeh.layouts import row
from bokeh.models.widgets import Button
from bokeh.io import show, output_notebook
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
output_notebook()
# Create the Document Application
def modify_doc(doc):
    layout = row(Button(label="Hello,"),Button(label="world!"))
    doc.add_root(layout)

handler = FunctionHandler(modify_doc)
app = Application(handler)

# Output = BokehJS 0.12.10 successfully loaded.


# New cell
show(app, notebook_url="my-jupyterhub-url.com:80")

# Output = "empty" cell

检查单元格是否添加了脚本标记:

<script src="http://my-jupyterhub-url.com:46249/autoload.js?bokeh-autoload-element=f8fa3bd0-9caf-473d-87a5-6c7b9680648b&amp;bokeh-absolute-url=http://my-jupyterhub-url.com:46249" id="f8fa3bd0-9caf-473d-87a5-6c7b9680648b" data-bokeh-model-id="" data-bokeh-doc-id=""></script>

这不起作用,因为端口46249未在jupyterhub代理上打开。此外,路由到我的 jupyter实例的路径为my-jupyterhub-url.com/user/my-username/,因此my-jupyterhub-url.com/autoload.js不会路由到任何地方。

这个感觉就像它可能是一个常见的要求,但是搜索还没有找到解决方案。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

所以我找到了一个我不满意的解决方案,但只是工作......

首先在Jupyter实例上安装nbserverproxy。这允许您通过JupyterHub(您在其中进行身份验证)代理Jupyter机器/容器上的任意端口。我通过从Jupyter Web前端打开终端并键入:

来安装
pip install git+https://github.com/jupyterhub/nbserverproxy --user
jupyter serverextension enable --py nbserverproxy --user

然后重新启动服务器。对于我安装的JupyterHub,这是control panel - &gt; stop my server等待start my server

最后,我修改了Ipython.display.publish_display_data(因为源代码显示bokeh在笔记本中调用show时使用了这个),就像这样。

from unittest.mock import patch

from IPython.display import publish_display_data
orig = publish_display_data

import re
def proxy_replacer(display_data):
    for key, item in display_data.items():
        if isinstance(item, str):
            item= re.sub(r'(/user/tam203)/?:([0-9]+)', r'\1/proxy/\2', item)
            item = re.sub(r'http:' , 'https:', item)
            display_data[key] = item 
    return display_data


def mock(data, metadata=None, source=None):
    data = proxy_replacer(data) if data else data 
    metadata = proxy_replacer(metadata) if metadata else metadata
    return orig(data, metadata=metadata, source=source)


patcher = patch('IPython.display.publish_display_data', new=mock)
patcher.start()

随着这一切的完成,我可以运行以下内容,看到一个很好的动态更新图。

import random
from bokeh.io import output_notebook 
output_notebook()
from bokeh.io import show
from bokeh.server.server import Server
from bokeh.application import Application
from bokeh.application.handlers.function import FunctionHandler
from bokeh.plotting import figure, ColumnDataSource


def make_document(doc):
    source = ColumnDataSource({'x': [], 'y': [], 'color': []})

    def update():
        new = {'x': [random.random()],
               'y': [random.random()],
               'color': [random.choice(['red', 'blue', 'green'])]}
        source.stream(new)

    doc.add_periodic_callback(update, 100)

    fig = figure(title='Streaming Circle Plot!', sizing_mode='scale_width',
                 x_range=[0, 1], y_range=[0, 1])
    fig.circle(source=source, x='x', y='y', color='color', size=10)

    doc.title = "Now with live updating!"
    doc.add_root(fig)

app =  Application(FunctionHandler(make_document))
show(app, notebook_url="<my-domain>.co.uk/user/tam203/")

因此,虽然我很高兴能找到一份解决方案,但并不是真正的解决方案。我认为散景中的一个微小变化可以解决这个问题(类似于url模板字符串,你可以在其中指定路径和端口)。

答案 1 :(得分:0)

根据官方bokeh documentation show(obj, notebook_url=remote_jupyter_proxy_url)接受notebook_url参数值。显然,这可以是接受端口参数值的函数。

通过在jupyterhub / jupyterlab和代理扩展的上下文中提供功能remote_jupyter_proxy_url的参考实现,文档进一步发展了。