modifying the d3 force-directed graph example

Deadly 提交于 2019-12-04 23:40:14

问题


I'm new to javascript and D3.js, and I am trying to understand how it all works. I have been playing with the force-directed graph example here: http://bl.ocks.org/mbostock/4062045

What I want to do, is to change the JSON links from being array numbers to node names. I'm trying to visualize a small network topology, and I have the node neighbors all set up. Here is the JSON data I would like to use:

{
  "nodes":[
    {"name":"stkbl0001","group":1},
    {"name":"stkbl0002","group":1},
    {"name":"stkbl0003","group":1},
    {"name":"stkbl0004","group":1},
    {"name":"stkbl0005","group":1}
  ],
  "links":[
    {"source":"stkbl0001","target":"stkbl0005","value":3},
    {"source":"stkbl0002","target":"stkbl0005","value":3},
    {"source":"stkbl0003","target":"stkbl0005","value":3},
    {"source":"stkbl0004","target":"stkbl0005","value":3}
  ]

I really don't know how to alter the D3 code to tie all this together. I fail to see the section where the array numbers is fetched and glued together as links. This is probably a stupid question, but it will help me a lot!

EDIT:

Here is the javascript code I have so far based on the input from Lars Kotthoff:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.node {
  stroke: #fff;
  stroke-width: 1.5px;
}

.link {
  stroke: #999;
  stroke-opacity: .6;
}

</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var width = 960,
    height = 500;

var color = d3.scale.category20();

var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

d3.json("mini.json", function(error, graph) {
  force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();

  var link = svg.selectAll(".link")
      .data(graph.links)
      .enter().append("line")
      .attr("class", "link")
      .style("stroke-width", function(d) { return Math.sqrt(d.value); });

  var node = svg.selectAll(".node")
      .data(graph.nodes)
      .enter().append("circle")
      .attr("class", "node")
      .attr("r", 5)
      .style("fill", function(d) { return color(d.group); })
      .call(force.drag);

  var nodeMap = {};
  nodes.forEach(function(d) { nodeMap[d.name] = d; });

  links.forEach(function(l) {
      l.source = nodeMap[l.source];
      l.target = nodeMap[l.target];
  })

  node.append("title")
      .text(function(d) { return d.name; });

  force.on("tick", function() {
    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; });

    node.attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  });
});
</script>

This fails at line 55 (nodes.forEach(function(d) { nodeMap[d.name] = d; });) with the error:

Uncaught ReferenceError: nodes is not defined

回答1:


This link links to a working example based on the your example.

The critical code is placed just before initialization of force layout:

var nodeMap = {};

graph.nodes.forEach(function(d) { nodeMap[d.name] = d; });

graph.links.forEach(function(l) {
    l.source = nodeMap[l.source];
    l.target = nodeMap[l.target];
})

force.nodes(graph.nodes)
    .links(graph.links)
    .start();

That way you will be able to use your data format in the same fashion as the original format is used (and many examples on the net follow that original format, so you will be able to adapt many of them to your format without problems).

(json file is not used in my example, due to restrictions of jsfiddle; instead, function getData() is made to return the data; but this is not essential to your question; you can use this solution with json files too)

Hope this helps.




回答2:


D3 provides two ways of specifying link source and target for the force layout. The first, used in the example you've linked to, is to provide the index of the node in the array of nodes. When the force layout is started, this is replaced with the reference to the actual node. The second is to provide the reference to the actual node explicitly.

To reference a node by name, you need something that allows you to resolve that reference. For example:

var nodeMap = {};
graph.nodes.forEach(function(d) { nodeMap[d.name] = d; });

Then you can do

graph.links.forEach(function(l) {
  l.source = nodeMap[l.source];
  l.target = nodeMap[l.target];
})

You can of course also use this to define links to start with:

"links":[
 {"source":nodeMap["stkbl0001"],"target":nodeMap["stkbl0005"],"value":3}
]


来源:https://stackoverflow.com/questions/24015930/modifying-the-d3-force-directed-graph-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!