在其他环境而非笔记本中嵌入Jupyter Widgets#

Jupyter 交互式小部件可以被序列化并嵌入到

  • 静态网页

  • sphinx 文档

  • 在nbviewer上的html转换笔记本

这里,我们讨论使用 @jupyter-widgets/html-manager npm 包中的自定义小部件管理器嵌入小部件。提供了两种嵌入器:

  1. 一个基本的嵌入器,仅嵌入标准控件,但可在任何网页上使用

  2. 一个使用RequireJS的嵌入器,能够嵌入标准和自定义的小部件

在HTML网页中嵌入小部件#

经典笔记本界面提供了一个Widgets菜单,用于生成可嵌入任何静态网页的HTML片段:

菜单提供了三组操作

  • 保存Notebook Widget状态与清除Notebook Widget状态

  • 下载小部件状态

  • 嵌入小部件

保存笔记本小部件状态#

一个笔记本文件可以保存当前小部件状态作为元数据。这允许笔记本文件在渲染时包含已渲染的小部件(例如,请参阅下面关于Sphinx的部分)。要保存包含当前小部件状态的笔记本,请使用Save Notebook Widget State菜单项。

为了删除旧的保存状态并将新状态保存到notebook中,请按顺序执行以下操作:

  1. 使用 Clear Notebook Widget State 菜单并保存笔记本。这将清除笔记本文件中的元数据。

  2. 重启内核并刷新页面。这样可以清除页面上来自部件管理器的旧部件状态。

  3. 创建您想要的任意小部件,并使用保存 笔记本 小部件 状态并保存笔记本。这将新的小部件状态保存到笔记本文件中。

可嵌入的HTML片段#

Embed widgets 菜单项提供了一个包含嵌入当前小部件的 HTML 页面对话框。为了支持自定义小部件,它使用了 RequireJS 嵌入器。

这段HTML片段由多个嵌入到HTML文档中的<script>标签组成:

  • 第一个脚本标签从CDN加载RequireJS。如果页面上已有RequireJS,可以删除此脚本标签。

  • 第二个脚本标签加载了 RequireJS 小部件嵌入器。这定义了适当的模块,然后设置了一个函数来渲染页面中包含的所有小部件视图。如果您仅嵌入标准小部件且不想使用 RequireJS,您可以将前两个脚本标签替换为一个加载标准嵌入器的脚本标签。

  • 下一个脚本标签是一个带有MIME类型 application/vnd.jupyter.widget-state+json 的脚本标签,其中包含当前使用的所有 小部件模型的状态。该脚本标签内容的JSON模式可在 @jupyter-widgets/schema npm包中找到。

  • 接下来有一些脚本标签,每个都带有MIME类型 application/vnd.jupyter.widget-view+json,对应于您想要在网页上显示的视图。 这些脚本标签必须位于页面主体中,并将被渲染后的小部件所替换。这些脚本标签内容的JSON模式可以在 @jupyter-widgets/schema npm包中找到。

    嵌入小部件操作当前为笔记本中显示的每个视图创建一个这样的脚本标签。如果您希望布局视图,或者只包含其中一些, 您可以按需删除或包含这些脚本标签。

为了从前端清除小部件状态,使其不会在嵌入中显示,请重启内核然后刷新页面,按此顺序进行。

小部件状态 JSON#

Download Widget State 选项会触发下载一个 JSON 文件,该文件包含当前正在使用的所有 widget 模型的序列化状态,使用在 @jupyter-widgets/schema npm 包中指定的 application/vnd.jupyter.widget-state+json 格式。

Python接口#

小部件的可嵌入代码也可以通过Python生成。 ipywidgets.embed 模块提供了多个函数,用于以编程方式将小部件嵌入到HTML文档中。

使用embed_minimal_html创建一个简单的独立HTML页面:

from ipywidgets import IntSlider
from ipywidgets.embed import embed_minimal_html

slider = IntSlider(value=40)
embed_minimal_html('export.html', views=[slider], title='Widgets export')

这将创建独立的文件 export.html。要查看该文件,可以启动一个HTTP服务器,例如Python标准库中的HTTP server,或者直接在您的网页浏览器中打开它(通过双击文件,或在浏览器搜索栏中输入 file:///path/to/file)。

有时您会需要比embed_minimal_html提供的更精细的控制。通常,您希望控制嵌入小部件的HTML文档结构。为此,使用embed_data获取小部件状态特定部分的JSON导出。您可以将这些嵌入到HTML模板中:

import json

from ipywidgets import IntSlider
from ipywidgets.embed import embed_data

s1 = IntSlider(max=200, value=100)
s2 = IntSlider(value=40)
data = embed_data(views=[s1, s2])

html_template = """
<html>
  <head>

    <title>Widget export</title>

    <!-- Load RequireJS, used by the IPywidgets for dependency management -->
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"
      integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA="
      crossorigin="anonymous">
    </script>

    <!-- Load IPywidgets bundle for embedding. -->
    <script
      data-jupyter-widgets-cdn="https://unpkg.com/"
      data-jupyter-widgets-cdn-only
      src="https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager@*/dist/embed-amd.js"
      crossorigin="anonymous">
    </script>

    <!-- The state of all the widget models on the page -->
    <script type="application/vnd.jupyter.widget-state+json">
      {manager_state}
    </script>
  </head>

  <body>

    <h1>Widget export</h1>

    <div id="first-slider-widget">
      <!-- This script tag will be replaced by the view's DOM tree -->
      <script type="application/vnd.jupyter.widget-view+json">
        {widget_views[0]}
      </script>
    </div>

    <hrule />

    <div id="second-slider-widget">
      <!-- This script tag will be replaced by the view's DOM tree -->
      <script type="application/vnd.jupyter.widget-view+json">
        {widget_views[1]}
      </script>
    </div>

  </body>
</html>
"""

manager_state = json.dumps(data['manager_state'])
widget_views = [json.dumps(view) for view in data['view_specs']]
rendered_template = html_template.format(manager_state=manager_state, widget_views=widget_views)
with open('export.html', 'w') as fp:
    fp.write(rendered_template)

网页需要加载RequireJS和Jupyter小部件HTML管理器。 然后您需要在文档头部的<script>标签中包含类型为 application/vnd.jupyter.widget-state+json的管理器状态。对于每个小部件视图, 在应包含视图的DOM元素中放置一个类型为 application/vnd.jupyter.widget-view+json<script>标签。 小部件管理器将用对应小部件的DOM树替换每个<script>标签。

在此示例中,我们使用了一个Python字符串作为模板,并使用了 format 方法来插入状态。对于嵌入更复杂 文档的情况,您可能希望使用像 Jinja2这样的模板引擎。

我们还将通过设置 data-jupyter-widgets-cdn 属性,将 CDN 从其默认的 jsdelivr 更改为使用 unpkg。

此外,我们仅通过设置data-jupyter-widgets-cdn-only属性从CDN加载模块。

ipywidgets.embed的所有嵌入函数中,默认包含微件管理器已知的所有微件状态。您也可以传递一个精简的状态来替代使用。如果您有许多状态庞大的独立微件,但只想在导出中包含相关的微件,这可能特别相关。要仅包含特定视图及其依赖项的状态,请使用函数dependency_state

from ipywidgets.embed import embed_minimal_html, dependency_state

s1 = IntSlider(max=200, value=100)
s2 = IntSlider(value=40)
embed_minimal_html('export.html', views=[s1, s2], state=dependency_state([s1, s2]))

在Sphinx HTML文档中嵌入小部件#

自 ipywidgets 6.0 起,Sphinx HTML 文档中可以呈现 Jupyter 交互式部件。提供了两种实现方式:

使用Jupyter Sphinx扩展#

jupyter_sphinx 扩展 在 sphinx 中启用了 jupyter 特定功能。它可以通过 pipconda 安装。

conf.py sphinx 配置文件中,将 jupyter_sphinx 添加到启用的扩展列表中。

然后使用jupyter-execute指令将代码执行的输出嵌入到您的文档中

.. jupyter-execute::

  from ipywidgets import VBox, jsdlink, IntSlider, Button
  s1, s2 = IntSlider(max=200, value=100), IntSlider(value=40)
  b = Button(icon='legal')
  jsdlink((s1, 'value'), (s2, 'max'))
  VBox([s1, s2, b])

使用 nbsphinx 项目#

nbsphinx Sphinx 扩展 为 *.ipynb 文件提供了一个源解析器。使用自定义的 Sphinx 指令 在 HTML 和 LaTeX 输出中显示 Jupyter Notebook 代码单元格(当然还有它们的结果)。 对于 HTML 输出,还支持 Jupyter Interactive Widgets。

对于由nbsphinx执行的笔记本,小部件状态会自动生成。 对于其他情况,要求笔记本已通过小部件菜单中的特殊“保存笔记本小部件状态”操作正确保存。

必要的JavaScript代码会自动嵌入到生成的HTML文件中。 可以使用nbsphinx_widgets_path配置选项指定自定义URL或本地JavaScript文件。 有关更多配置选项,请查阅文档

nbviewer#上渲染交互式组件

如果您的笔记本是通过“小部件”菜单中的特殊“保存笔记本小部件状态”操作保存的,那么笔记本中显示的交互式小部件也应当在nbviewer上呈现。

请参阅文档中的Widget List示例。

自定义组件库的情况 #

自定义部件也可以在nbviewer、静态HTML和RTD文档中呈现。一个示例是 http://jupyter.org/widgets 画廊。

小部件嵌入器默认尝试从npm CDN https://cdn.jsdelivr.net/npm 获取自定义小部件的模型和视图实现。例如,对于模块名称 bqplot 和语义化版本范围 ^2.0.0 所请求的URL是

https://cdn.jsdelivr.net/npm/bqplot@^2.0.0/dist/index.js

其中包含 bqplot 库的 webpack 包。

虽然默认的CDN使用https://cdn.jsdelivr.net/npm,但可以通过为加载embed-amd.js的script标签设置可选的data-jupyter-widgets-cdn属性来配置,如上面的示例所示。

虽然默认策略是从同一站点加载模块,然后回退到CDN。这可以通过为加载embed-amd.js的脚本标签设置可选的data-jupyter-widgets-cdn-only属性来配置,如上例所示。

widget-cookiecutter 模板项目包含一个自定义控件库的模板项目 遵循编写控件的最佳实践,确保您的 自定义控件库可以在nbviewer上渲染。

在web环境中使用 jupyter-widgets-controls#

核心的jupyter-widgets-controls库,即ipywidgets的JavaScript包, 与其使用环境无关(Notebook、JupyterLab、静态网页)。 对于每种环境,我们专门定制了在@jupyter-widgets/base中实现的基础小部件管理器,以提供以下逻辑:

  • 部件应显示的位置,

  • 如何检索关于其状态的信息。

具体来说:

  • widgetsnbextension Python 包为经典的 Jupyter notebook 提供了专门的 widget 管理器的实现,以及作为 notebook 扩展的打包逻辑。

  • @jupyter-widgets/jupyterlab-manager npm包提供了在JupyterLab环境下专用的widget管理器的实现,以及作为lab扩展的打包逻辑。

  • @jupyter-widgets/html-manager npm包中实现的嵌入管理器是基础widget管理器的特化版本,用于Sphinx扩展、nbviewer以及上文讨论的“嵌入Widgets”命令中的widget静态嵌入。

我们提供了额外的示例,展示了基础小部件管理器在网页环境中实现Jupyter小部件其他用途的专业化应用。

  1. web1 示例是一个展示在网络环境中使用 Jupyter widgets 的简单示例。

  2. web2示例是一个简单的例子,使用了application/vnd.jupyter.widget-state+json MIME类型。

  3. web3 示例展示了如何在与 Jupyter 内核通信时,在笔记本或 jupyterlab 环境之外的网络上下文中进行。

  4. web4 示例展示了如何使用 HTML 控件管理器将控件嵌入到 HTML 文档中。