如何在不破坏现有 enter/exit 绑定的情况下更新整个数据集?
How to update entire dataset without breaking existing enter/exit bindings?
编辑
我创建了一个更简单的示例,几乎完全来自 Mike Bostock 的 Sankey diagram example. You can see a JSFiddle,它演示了同样的事情。这只是加载 Sankey 可视化,然后 re-loads 定期加载完全相同的数据。
这使用了我认为的一般更新模式,因为这只处理具有 entered
的 nodes/edges,所以我希望不会发生任何事情。实际上,SVG 不断地在顶部分层。可以看到更新代码很简单——重新加载原始数据源,这应该意味着没有新输入的数据条目:
// Initial Load
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/D3%20Update/energy.json", function(energy) {
update(energy);
});
// Refresh
setInterval(function() {
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/D3%20Update/energy.json", function(energy) {
update(energy);
})
}, 2000);
在更新函数中,边缘应该简单地为任何新数据条目渲染:
var link = svg.append("g").selectAll(".link")
.data(data.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
然而,当它呈现时,您可以从下面的屏幕截图中看到它是如何错误地不断更新边缘的:
原创
我帮助制作了一个可视化效果,我正在尝试 运行 对其进行更新。我看到的很多示例只是在内存中更新对象数据 - 而我想返回服务器并请求替换 data-set 以查看是否有新项目 introduced/values变了。此可视化效果如下所示:
我最初使用 d3.json
调用加载数据,例如:
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/Sankey/data.json",
function(data) {
sankey.data(data);
sankey.render();
}
);
然后我想做的是加载一个新的 JSON 文件(包含几乎相同的数据 - 有一些小的变化)并更新可视化:
$("#update").click(function() {
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/Sankey/data2.json",
function(data) {
sankey.data(data);
sankey.render();
})
})
然而,数据似乎失去了所有绑定。如果我一直点击更新按钮,那么你会看到半不透明的线条不断地叠加在一起,产生这样的图片:
现在虽然我没有明确删除链接,只是使用以下代码添加新链接,但我没想到在图表本身没有更改的情况下添加任何链接:
// Create new links between nodes
var links = vis.append("g")
.selectAll(".link")
.data(data.links);
links.enter()
.append("path")
.attr("class", "link")
.attr("d", sankey.link())
.style("stroke-width", "6px")
.style("marker-end", "url(#end-arrow)")
.style("stroke", "#fff")
.style("opacity", 0.2)
.style("fill", "none")
.style("hover-opacity", 0.5)
.sort(function (a, b) { return b.dy - a.dy; });
我希望这些行保持原样,并且不会有新链接,而只是更新现有链接。由于我没有明确更新现有链接,因此我不希望它们改变外观。
所以问题是为什么会发生这种情况(我的猜测是由于完整的 re-load 数据)以及如何防止它发生,同时仍然再次加载整个数据集?
这里有一个 JSFiddle 来演示这个问题。有趣的代码在第 #97-#150 行之间的 control.render
函数中。
您的实现中的问题是您在调用 update
函数时不断添加两个新的 g
元素。您可以在您的 JSFiddle 中观察到这一点(一段时间后,您的 svg
元素中有相当多的 g
s)。
如何解决?好吧,有很多方法,这里有一个例子:
首先你添加一些容器来放置你的元素:
var linkContainer = svg.append('g');
var nodeContainer = svg.append('g');
(您在定义 svg
之后立即执行此操作,即 在 更新函数之外。
接下来,在更新函数中将元素添加到这些容器中:
var link = linkContainer.selectAll(".link")....
节点也是如此。
我希望这应该可以解决问题。
另一种方法是将 svg
元素中的组绑定到一些随机固定数据并在其上使用 .enter().append()
(因此确保它只添加一次,因为数据是固定的.. .)
希望对您有所帮助!
编辑
我创建了一个更简单的示例,几乎完全来自 Mike Bostock 的 Sankey diagram example. You can see a JSFiddle,它演示了同样的事情。这只是加载 Sankey 可视化,然后 re-loads 定期加载完全相同的数据。
这使用了我认为的一般更新模式,因为这只处理具有 entered
的 nodes/edges,所以我希望不会发生任何事情。实际上,SVG 不断地在顶部分层。可以看到更新代码很简单——重新加载原始数据源,这应该意味着没有新输入的数据条目:
// Initial Load
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/D3%20Update/energy.json", function(energy) {
update(energy);
});
// Refresh
setInterval(function() {
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/D3%20Update/energy.json", function(energy) {
update(energy);
})
}, 2000);
在更新函数中,边缘应该简单地为任何新数据条目渲染:
var link = svg.append("g").selectAll(".link")
.data(data.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
然而,当它呈现时,您可以从下面的屏幕截图中看到它是如何错误地不断更新边缘的:
原创
我帮助制作了一个可视化效果,我正在尝试 运行 对其进行更新。我看到的很多示例只是在内存中更新对象数据 - 而我想返回服务器并请求替换 data-set 以查看是否有新项目 introduced/values变了。此可视化效果如下所示:
我最初使用 d3.json
调用加载数据,例如:
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/Sankey/data.json",
function(data) {
sankey.data(data);
sankey.render();
}
);
然后我想做的是加载一个新的 JSON 文件(包含几乎相同的数据 - 有一些小的变化)并更新可视化:
$("#update").click(function() {
d3.json("https://dl.dropboxusercontent.com/u/41796243/JSFiddle/Sankey/data2.json",
function(data) {
sankey.data(data);
sankey.render();
})
})
然而,数据似乎失去了所有绑定。如果我一直点击更新按钮,那么你会看到半不透明的线条不断地叠加在一起,产生这样的图片:
现在虽然我没有明确删除链接,只是使用以下代码添加新链接,但我没想到在图表本身没有更改的情况下添加任何链接:
// Create new links between nodes
var links = vis.append("g")
.selectAll(".link")
.data(data.links);
links.enter()
.append("path")
.attr("class", "link")
.attr("d", sankey.link())
.style("stroke-width", "6px")
.style("marker-end", "url(#end-arrow)")
.style("stroke", "#fff")
.style("opacity", 0.2)
.style("fill", "none")
.style("hover-opacity", 0.5)
.sort(function (a, b) { return b.dy - a.dy; });
我希望这些行保持原样,并且不会有新链接,而只是更新现有链接。由于我没有明确更新现有链接,因此我不希望它们改变外观。
所以问题是为什么会发生这种情况(我的猜测是由于完整的 re-load 数据)以及如何防止它发生,同时仍然再次加载整个数据集?
这里有一个 JSFiddle 来演示这个问题。有趣的代码在第 #97-#150 行之间的 control.render
函数中。
您的实现中的问题是您在调用 update
函数时不断添加两个新的 g
元素。您可以在您的 JSFiddle 中观察到这一点(一段时间后,您的 svg
元素中有相当多的 g
s)。
如何解决?好吧,有很多方法,这里有一个例子:
首先你添加一些容器来放置你的元素:
var linkContainer = svg.append('g');
var nodeContainer = svg.append('g');
(您在定义 svg
之后立即执行此操作,即 在 更新函数之外。
接下来,在更新函数中将元素添加到这些容器中:
var link = linkContainer.selectAll(".link")....
节点也是如此。
我希望这应该可以解决问题。
另一种方法是将 svg
元素中的组绑定到一些随机固定数据并在其上使用 .enter().append()
(因此确保它只添加一次,因为数据是固定的.. .)
希望对您有所帮助!