如何使用 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.19
、jsdom@9.12.0
和 d3@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 创建一个<svg>
节点并附加一个<rect>
使用outerHTML
获取前面步骤中创建的<svg>
节点的字符串表示
最后指示 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'类型上不存在”?