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

时间:2017-05-06 08:29:10

标签: javascript d3.js

我一直在尝试根据链接为某些节点着色,但我不知道该怎么做。这是我目前的图表:

My current Graph

我一直在尝试自动为同一群集内的所有节点着色(即通过作为群集中任何节点的源或目标相互连接),但到目前为止,我的所有尝试都是徒劳的。

我听说我可能需要做一个递归函数,但是我的递归是自学的,从根本上说是错误的。这是我目前的代码:

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;
}

我的方法是为每个节点分配一个组,并根据他们的组对它们进行着色,基本上是一石二鸟(组也可以用于将来的实现)。

我的数据集是:

{
"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"
    }
]
}

以下是我的节点数据集的预期结果:

"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)*/
}
]

编辑:这是jsfiddle:https://jsfiddle.net/ehnf76xg/2/

1 个答案:

答案 0 :(得分:3)

这是我的解决方案。首先,我们给每个节点一个不同的数字:

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

如你所知,数字本身并不重要。

然后,我们针对每个节点检查其名称是否在source数组中每个对象的targetedges处找到。如果是,我们将其编号分配给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;
        }
    })
})

这就像一个传染性过程:在sourcetarget找到其名称的第一个节点传播其编号。同样,这个数字本身并不重要。

这是一个演示:

&#13;
&#13;
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)
&#13;
&#13;
&#13;

现在,让我们在真正的力量指导图表中看到它:

&#13;
&#13;
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 d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    });

});
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
&#13;
&#13;
&#13;