我正在尝试在 D3 上进行强制布局,以使用节点和链接进行网络可视化。我曾经使用过一点 v3,但我切换到 v5,以便能够使用节点属性而不是节点索引来链接节点(这需要 d3 v3 中的额外步骤)。
我得到了这个代码
https://jsfiddle.net/lioneluranl/4fxpp2co/1/
var linkpath = ("links.csv");
var nodepath = ("nodes.csv");
var svg = d3.select("svg");
var width = svg.attr("width");
var height = svg.attr("height");
var simulation = d3.forceSimulation();
var nodes = [];
var links = [];
d3.csv(nodepath, function(d){
node = {
id: d.node,
group: d.group,
node: d.node
};
nodes.push(node);
d3.csv(linkpath, function(d){
link = {
source: d.source,
target: d.target,
type: d.type
};
links.push(link);
});
}).then( function() {
//console.log(links);
//console.log(nodes);
simulation
.force("link", d3.forceLink().id(function(d) { /*console.log(d);*/ return d.id; }))
.nodes(nodes)
.force("collide", d3.forceCollide().radius(10))
.force("r", d3.forceRadial(function(d) {
if(d.group === "compound"){
return 240;
} else { return d.group === "annotation" ? 0 : 100; }}))
// Create the link lines.
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke", "black")
.attr("stroke-width", 4)
.attr("class", function(d) { return "link " + d.type; });
// Create the node circles.
var node = svg.append("g")
.attr("class", "node")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 8)
.attr("class", function (d){
return d.group;
});
simulation.on("tick", ticked);
simulation.force("link").links(links);
function ticked() {
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
}
});
改编自此
https://bl.ocks.org/mbostock/cd98bf52e9067e26945edd95e8cf6ef9
绘制节点没有问题,但无法绘制链接。相关文档表明,正如我认为我正在做的那样,节点属性必须传递到力模拟上的链接,但我收到此错误:
类型错误:无法分配给“PF05257”上的属性“vx”:不是对象
此外,执行此操作时,节点在布局上的行为不会按预期运行(径向力集不起作用,请参见附图),这表明此按节点链接属性扰乱了我的模拟。
CSV 包含以下数据:
节点.csv:
node,group
C236103,compound
C327961,compound
C337527,compound
C376038,compound
C543486,compound
T24871,target
T27222,target
T33516,target
T33937,target
OG5_135897,annotation
PF01529,annotation
PF05257,annotation
PF11669,annotation
...
链接.csv
source,target,type
T24871,PF05257,annotation
T27222,PF05257,annotation
T33516,PF01529,annotation
T33516,PF05257,annotation
T33516,PF11669,annotation
T33937,PF05257,annotation
T24871,C561727,bioactivity
T24871,C337527,bioactivity
T24871,C585910,bioactivity
...
仅供引用和数据完整性健全性检查,我在 d3 v3 上得到了这个工作。
有什么想法吗?
最佳答案
这里是一个建设性的批评:正确缩进你的代码1。
我第一次阅读它时,由于缩进不正确,我错过了这个问题。但是,有了正确的缩进,问题就清楚了,看看这个:
d3.csv(nodepath, function(d) {
node = {
id: d.node,
group: d.group,
node: d.node
};
nodes.push(node);
d3.csv(linkpath, function(d) {
link = {
source: d.source,
target: d.target,
type: d.type
};
links.push(link);
});
})
您不能像这样嵌套d3.csv
。您的代码现在的方式是第二个 d3.csv
是第一个 d3.csv
的行函数的一部分,这显然是行不通的。
这里正确的方法是嵌套 promise (这对某些人来说是反模式),或者更好的是,使用 Promise.all
(因为没有 d3.queue
在 v5 中):
var promises = [d3.csv("nodes.csv"), d3.csv("links.csv")];
Promise.all(promises).then(function(data) {
var links = data[1];
var nodes = data[0];
//rest of the code here
});
作为一个额外的提示,您不需要将对象推送到外部作用域中的数组:只需处理 then
内的参数即可。
此外,您不需要两个 CSV 的行函数,因为您的行函数现在没有执行任何操作(除了将 node
复制为 id
之外,它们只是返回与没有它们时相同的对象)。
这是一个包含您的代码和数据的 bl.ocks,使用 Promise.all
:
1 大多数文本编辑器,如 Sublime Text,都有缩进插件。网上也可以找到几个不错的工具,like this one例如。
关于javascript - 无法使用 D3 强制布局按节点属性绘制链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50184951/