如何使用 jsdom、D3 和 IJavascript 在 Jupyter 笔记本中输出 SVG

Posted

技术标签:

【中文标题】如何使用 jsdom、D3 和 IJavascript 在 Jupyter 笔记本中输出 SVG【英文标题】:How to output SVG in a Jupyter notebook using jsdom, D3 and IJavascript 【发布时间】:2017-09-15 06:06:14 【问题描述】:

我不擅长前端开发,但最近玩弄了很多 javascript 和 D3。习惯于使用 Jupyter Notebooks 在 Python 中进行科学分析,我认为应该可以使用类似的工作流程,使用带有 JS 内核的 Jupiter notebook 中的 JS 代码使用 D3 开发科学可视化。我查看了n-riesco 的IJavascript project,看起来很有希望,但是在尝试导入 D3 时,笔记本会抛出错误:

// npm install d3
var d3 = require('d3');

抛出

ReferenceError: document is not defined

我猜这是因为 Jupyter 环境中没有 DOM (because Mike Bostock says so)。其实如果我导入jsdom,D3也会导入成功。惊人的!但是,现在,我无法选择任何东西,因为……我猜是因为在 Jupyter 环境中没有任何东西可供选择。

我想做的事情是这样的:

$$svg$$ = "<svg><rect width=1000 height=1000/></svg>";
var svg = d3.select("svg")
// Beautiful D3 code

或者(不太酷但也很有利),获取对某个本地服务器的 DOM 的引用,然后我可以通过在笔记本中执行代码来操作它。

更新

随着Observable 的引入,Jupyter 笔记本不再需要使用 JavaScript。 Observable 是一个很棒的 JavaScript 笔记本环境,几乎可以做任何事情。例如,当我问这个问题时我想做的事情,可以简单地做到:

【问题讨论】:

我也喜欢 Observable。我真希望你可以在本地运行它——Jupyter notebooks 仍然可以做到这一点。 【参考方案1】:

让我首先给出一个工作示例(在 ijavascript@5.0.19jsdom@9.12.0d3@4.8.0 上测试),然后进行一些说明:

var jsdom = require("jsdom");
global.document = jsdom.jsdom();

var d3 = require("d3");

var svg = d3.select(document.body).append("svg");

svg.append("rect")
    .attr("width", 80)
    .attr("height", 80)
    .style("fill", "orange");

$$.svg(svg.node().outerhtml);

这个解决方案:

使用jsdom提供的DOM。

使用d3 创建一个&lt;svg&gt; 节点并附加一个&lt;rect&gt;

使用outerHTML获取前面步骤中创建的&lt;svg&gt;节点的字符串表示

最后指示 IJavascript 将此字符串作为 SVG 结果返回到 Jupyter 笔记本。

理论上,IJavascript 可以将 javascript 代码注入 Jupyter 笔记本(以操纵其 DOM),但此代码可能无法运行(取决于 Jupyter 前端的安全策略)。


由于您的兴趣是科学分析,您可能对我最近发布的一个模块感兴趣:ijavascript-plotly。


我知道这个答案略过了许多概念。如果您需要我更新答案并进一步解释,请使用下面的 cmets。

【讨论】:

这很完美!如果我认为,我是否理解正确:$$ 是一个对象,它存储将内容绑定到 Jupyter 输出单元的函数。我们使用 jsdom 创建一个可以写入的 DOM,然后读取(使用outerHTML)并将 html 绑定到输出。我们可以显示整个 DOM 吗? @UlfAslak 是的,我认为你理解正确。 @UlfAslak 还有一件事(可能你已经注意到了),如果你想告诉 IJavascript 发送一个 HTML 结果,你需要使用$$.html 而不是$$.svg 是的,我注意到了。这样就可以将附加到 DOM 的所有内容发送到输出单元格,对吧? @UlfAslak 理论上是的,实际上你可能会遇到一些限制,具体取决于前端。 Hydrogen 例如受 Atom 中的 CSP 策略的限制(这意味着没有注入的 javascript)。如果 Hydrogen 开始使用 webviews,这可能会在未来发生变化。【参考方案2】:

在 Jupyter 中渲染 D3 的类似方法:

var d3 = require("d3");
var jsdom = require("jsdom");

var dom = new jsdom.JSDOM("<svg></svg>",QuerySelector:true);

var svg = dom.window.document.querySelector("svg");

d3.select(svg)
    .append("rect")
    .attr("width", 80)
    .attr("height", 80)
    .style("fill", "orange");

$$.html(dom.serialize());

【讨论】:

以上是关于如何使用 jsdom、D3 和 IJavascript 在 Jupyter 笔记本中输出 SVG的主要内容,如果未能解决你的问题,请参考以下文章

如何使用jsdom和typescript防止“属性'...'在'Global'类型上不存在”?

如何在 JSDOM 中使用 XPath 获取 XML 属性

如何在一个脚本中监视javascript函数,该脚本被注入jsdom用于测试目的?

jsdom:使用 jQuery 将脚本附加到正文

如何配置 jest jsdom 环境?

jsdom应该如何配置NuxtJS?