简体   繁体   English

JS / d3.js:为源/目标链接创建组

[英]JS / d3.js: Creating groups for source/target links

I have been trying to colour some nodes based on their links but I am not sure how to do so. 我一直试图根据链接为一些节点着色,但我不知道该怎么做。 Here is my current graph: 这是我目前的图表:

我目前的图表

I have been trying to automatically colour all nodes that are within the same cluster (ie Connected to each other either by being a source or a target to any node within the cluster), but so far all my attempts have been futile.. 我一直在尝试自动为同一个集群内的所有节点着色(即通过作为集群内任何节点的源或目标相互连接),但到目前为止,我的所有尝试都是徒劳的。

I heard that I might need to do a recursive function, but my recursion is self-taught and is fundamentally wrong. 我听说我可能需要做一个递归函数,但我的递归是自学成才的,从根本上说是错误的。 Here is my current code: 这是我目前的代码:

function assignGroup() {
var groupedNodes = [];

for(var i = 0; i < gNodes.length; i++) {
    if(nodes[i].group !== undefined) {
        nodes[i].group = undefined;
    }
}

for(var i = 0; i < nodes.length; i++) {
    if(nodes[i].group === undefined) {
        nodes[i].group = i;
        recursive(nodes[i],i);
    }
}


function recursive(rNode, rGrp) {       
    var tempSrc = hasSrc(rNode);        
    var tempTarg = hasTarg(rNode);

    if(tempSrc == null && tempTarg == null)
        return;

    if(tempSrc != null && tempSrc.group === undefined) {
        tempSrc.group = rGrp;
        recursive(tempSrc, rGrp);
    }

    if(tempTarg != null && tempTarg.group === undefined) {
        tempTarg.group = rGrp;
        recursive(tempTarg, rGrp);
    }
}

function hasTarg(eNode) {
    for(var i = 0; i < edges.length; i++) {
        if(nodes.name == edges[i].source)
            return getNode(nodes, edges[i].target);
        else
            return null;
    }
}

function hasSrc(eNode) {
    for(var i = 0; i < edges.length; i++) {
        if (nodes.name == edges[i].target)
            return getNode(edges[i].source);
        else
            return null;
    }
}

function getNode(id) {
    console.log(id);
    for(var i = 0; i < nodes.length; i++) {
        if(id == nodes[i].name) {
            return nodes[i];
        }
    }
    return null;
}

My approach is to assign a group to each node, and to colour them based on their group, essentially tackling two birds with one stone (Group can be used for future implementations as well). 我的方法是为每个节点分配一个组,并根据他们的组对它们进行着色,基本上是一石二鸟(组也可以用于未来的实现)。

My dataset is: 我的数据集是:

{
"nodes":
[
 {
   "name": "Ben",
},
 {
   "name": "May",
},
 {
   "name": "Jack",
},
 {
   "name": "Francis",
},
 {
   "name": "Owen",
},
 {
   "name": "Blake",
},
 {
   "name": "Julia",
},
 {
   "name": "Liam",
}
],
"edges":
[
    {
        "source":"Ben",
        "target":"May"
    },
    {
        "source":"Ben",
        "target":"Blake"
    },
    {
        "source":"Ben",
        "target":"Owen"
    },
    {
        "source":"Owen",
        "target":"Julia"
    }
]
}

Here is the intended outcome of my dataset for node: 以下是我的节点数据集的预期结果:

"nodes":
[
 {
   "name": "Ben",
   "group": 1
},
 {
   "name": "May",
   "group": 1
},
 {
   "name": "Jack",
   "group": 2 /*Arbitrary group (Ungrouped)*/
},
 {
   "name": "Francis",
   "group": 3 /*Arbitrary group (Ungrouped)*/
},
 {
   "name": "Owen",
   "group": 1
},
 {
   "name": "Blake",
   "group": 1
},
 {
   "name": "Julia",
   "group": 1
},
 {
   "name": "Liam",
   "group": 4 /*Arbitrary group (Ungrouped)*/
}
]

Edit: Here is the jsfiddle: https://jsfiddle.net/ehnf76xg/2/ 编辑:这是jsfiddle: https ://jsfiddle.net/ehnf76xg/2/

This is my solution. 这是我的解决方案。 First, we give each node a different number: 首先,我们给每个节点一个不同的数字:

data.nodes.forEach(function(d, i) {
    d.group = i
});

The numbers themselves don't matter, as you know. 如你所知,数字本身并不重要。

Then we check, for each node, if its name is found at the source or target of each object in the edges array. 然后,我们检查每个节点是否在edges数组中的每个对象的sourcetarget处找到其名称。 If yes, we give its number to both source and target correspondents in the nodes array: 如果是,我们将它的编号分配给nodes数组中的源和目标通讯员:

data.nodes.forEach(function(d) {
    data.edges.forEach(function(e) {
        if (e.source === d.name || e.target === d.name) {
            data.nodes.find(function(f) {
                return f.name === e.source
            }).group = d.group;
            data.nodes.find(function(f) {
                return f.name === e.target
            }).group = d.group;
        }
    })
})

This is just like an infectious process: the first node whose name is found either on source or target spreads its number. 这就像一个传染性过程:在sourcetarget上找到其名称的第一个节点传播其数量。 Again, the number itself doesn't matter. 同样,数字本身并不重要。

Here is a demo: 这是一个演示:

 var data = { "nodes": [{ "name": "Ben", }, { "name": "May", }, { "name": "Jack", }, { "name": "Francis", }, { "name": "Owen", }, { "name": "Blake", }, { "name": "Julia", }, { "name": "Liam", }], "edges": [{ "source": "Ben", "target": "May" }, { "source": "Ben", "target": "Blake" }, { "source": "Ben", "target": "Owen" }, { "source": "Owen", "target": "Julia" }] }; data.nodes.forEach(function(d, i) { d.group = i }); data.nodes.forEach(function(d) { data.edges.forEach(function(e) { if (e.source === d.name || e.target === d.name) { data.nodes.find(function(f) { return f.name === e.source }).group = d.group; data.nodes.find(function(f) { return f.name === e.target }).group = d.group; } }) }) console.log(data) 

Now, let's see it in a real force directed chart: 现在,让我们在一个真实的力量指导图表中看到它:

 var data = { "nodes": [{ "name": "Ben", },{ "name": "May", }, { "name": "Jack", }, { "name": "Liam", },{ "name": "Francis", }, { "name": "Owen", }, { "name": "Blake", }, { "name": "Julia", }], "edges": [{ "source": "Ben", "target": "May" }, { "source": "Ben", "target": "Blake" }, { "source": "Ben", "target": "Owen" }, { "source": "Owen", "target": "Julia" }] }; data.nodes.forEach(function(d, i) { d.group = i }); data.nodes.forEach(function(d) { data.edges.forEach(function(e) { if (e.source === d.name || e.target === d.name) { data.nodes.find(function(f) { return f.name === e.source }).group = d.group; data.nodes.find(function(f) { return f.name === e.target }).group = d.group; } }) }) var svg = d3.select("svg") var force = d3.forceSimulation() .force("link", d3.forceLink() .id(function(d) { return d.name })) .force("charge", d3.forceManyBody().strength(-2)) .force("collide", d3.forceCollide(15)) .force("center", d3.forceCenter(150, 70)); var edges = svg.selectAll("line") .data(data.edges) .enter() .append("line") .style("stroke", "#aaa") .style("stroke-width", 2); var color = d3.scaleOrdinal(d3.schemeCategory10); var nodes = svg.selectAll("circle") .data(data.nodes) .enter() .append("circle") .attr("r", 10) .style("stroke", "#444") .style("stroke-width", 2) .style("fill", function(d) { return color(d.group); }) force.nodes(data.nodes); force.force("link") .links(data.edges); force.on("tick", function() { edges.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; }) nodes.attr("cx", function(d) { return dx; }) .attr("cy", function(d) { return dy; }); }); 
 <script src="https://d3js.org/d3.v4.min.js"></script> <svg></svg> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM