在代理/jupyterhub 后面的 jupyter notebook 中使用散景服务器
Using bokeh server in jupyter notebook behind proxy / jupyterhub
我想在 jupyter notebook 实例上开发 bokeh 应用程序,该实例在 jupyterhub(也称为身份验证代理)后面运行。我想让交互式散景应用程序回调到笔记本内核。我不想使用笔记本小部件等,因为我希望能够将笔记本导出为 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&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 代理上未打开。另外路由到 my jupyter 实例的路径是 my-jupyterhub-url.com/user/my-username/
所以 my-jupyterhub-url.com/autoload.js
不会路由到任何地方。
感觉这可能是一个常见的要求,但搜索尚未显示解决方案。
有什么想法吗?
所以我找到了一个我不满意但有效的解决方案..差不多。
首先在您的 Jupyter 实例上安装 nbserverproxy
。这允许您通过 JupyterHub(您经过身份验证的地方)代理到 Jupyter machine/container 上的任意端口。我通过从 Jupyter Web 前端打开终端并输入:
来安装
pip install git+https://github.com/jupyterhub/nbserverproxy --user
jupyter serverextension enable --py nbserverproxy --user
然后重启你的服务器。对于我安装的 JupyterHub,这是 control panel
-> 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'/proxy/', 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/")
因此,虽然我很高兴找到了解决方法,但它并不是真正的解决方案。我认为 bokeh 的微小变化可以解决这个问题(类似于 url 模板字符串,您可以在其中指定路径和端口)。
根据官方散景 documentation show(obj, notebook_url=remote_jupyter_proxy_url)
接受 notebook_url 参数值。显然这可以是一个接受端口参数值的函数。
文档更进一步,在 jupyterhub/jupyterlab 和代理扩展的上下文中提供了函数 remote_jupyter_proxy_url
的参考实现。
我想在 jupyter notebook 实例上开发 bokeh 应用程序,该实例在 jupyterhub(也称为身份验证代理)后面运行。我想让交互式散景应用程序回调到笔记本内核。我不想使用笔记本小部件等,因为我希望能够将笔记本导出为 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&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 代理上未打开。另外路由到 my jupyter 实例的路径是 my-jupyterhub-url.com/user/my-username/
所以 my-jupyterhub-url.com/autoload.js
不会路由到任何地方。
感觉这可能是一个常见的要求,但搜索尚未显示解决方案。
有什么想法吗?
所以我找到了一个我不满意但有效的解决方案..差不多。
首先在您的 Jupyter 实例上安装 nbserverproxy
。这允许您通过 JupyterHub(您经过身份验证的地方)代理到 Jupyter machine/container 上的任意端口。我通过从 Jupyter Web 前端打开终端并输入:
pip install git+https://github.com/jupyterhub/nbserverproxy --user
jupyter serverextension enable --py nbserverproxy --user
然后重启你的服务器。对于我安装的 JupyterHub,这是 control panel
-> 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'/proxy/', 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/")
因此,虽然我很高兴找到了解决方法,但它并不是真正的解决方案。我认为 bokeh 的微小变化可以解决这个问题(类似于 url 模板字符串,您可以在其中指定路径和端口)。
根据官方散景 documentation show(obj, notebook_url=remote_jupyter_proxy_url)
接受 notebook_url 参数值。显然这可以是一个接受端口参数值的函数。
文档更进一步,在 jupyterhub/jupyterlab 和代理扩展的上下文中提供了函数 remote_jupyter_proxy_url
的参考实现。