简体   繁体   中英

D3 Visualization of network data (nodes and links) via json file

I would like to visualize network data that consists nodes and links in json file. I'm looking how D3 could be utilized. I haven't tried D3 but seems its good to visualize network data.

Lot of example visualization of data using D3 but I observed the link in json file example always based on source and target or nodes based on index....

If my json file doesn't have source and target key but instead the key used source and destination or the json nodes and links only content the values...can I still leverage D3..?

I expect I can edit D3 to follow my data or the other way a round?..I'm not sure on how to fit my json data onto D3 structure. I have gone the the D3 documentation and some examples but bit lost where to go... Appreciate someone could advise me further. Thank you

Please find example of data json i have

SAMPLE1 (only values of nodes and links):

{"nodes":["ser1","ser2","ser3","ser4","ser5"],"links":[["ser1","ser3",10], 
["ser1","ser5",30],["ser2","ser3",11],["ser3","ser4",10], 
["ser3","ser5",20],["ser2","ser5",30]]}


{
  "nodes": [
    "ser1",
    "ser2",
    "ser3",
    "ser4",
    "ser5"
  ],
  "links": [
    [
      "ser1",
      "ser3",
      10
    ],
    [
      "ser1",
      "ser5",
      30
    ],
    [
      "ser2",
      "ser3",
      11
    ],
    [
      "ser3",
      "ser4",
      10
    ],
    [
      "ser3",
      "ser5",
      20
    ],
    [
      "ser2",
      "ser5",
      30
    ]
  ]
}

SAMPLE2 (keys and values of nodes and links:

{"nodes":[{"name":"ser1"},{"name":"ser2"},{"name":"ser3"},{"name":"ser4"}, 
{"name":"ser5"}],"links":[{"source":"ser1","dest":"ser3","value":"10"}, 
{"source":"ser1","dest":"ser5","value":"10"}, 
{"source":"ser2","dest":"ser4","value":"30"}, 
{"source":"ser3","dest":"ser4","value":"10"}, 
{"source":"ser3","dest":"ser5","value":"10"}]}

    {
  "nodes": [
    {
      "name": "ser1"
    },
    {
      "name": "ser2"
    },
    {
      "name": "ser3"
    },
    {
      "name": "ser4"
    },
    {
      "name": "ser5"
    }
  ],
  "links": [
    {
      "source": "ser1",
      "dest": "ser3",
      "value": "10"
    },
    {
      "source": "ser1",
      "dest": "ser5",
      "value": "10"
    },
    {
      "source": "ser2",
      "dest": "ser4",
      "value": "30"
    },
    {
      "source": "ser3",
      "dest": "ser4",
      "value": "10"
    },
    {
      "source": "ser3",
      "dest": "ser5",
      "value": "10"
    }
  ]
}

my index.html

 <!DOCTYPE html> <meta charset="utf-8"> <style> .links line { stroke: #999; stroke-opacity: 0.6; } .nodes circle { stroke: #fff; stroke-width: 1.5px; } text { font-family: sans-serif; font-size: 10px; } </style> <svg width="960" height="600"></svg> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script> <script> var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"); var color = d3.scaleOrdinal(d3.schemeCategory20); var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function(d) { return d.name; })) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); var graph = getData(); graph.links = graph.links.map(function(ele) {return { source: ele.source, target: ele.dest, value: +ele.value } }); var link = svg.append("g") .attr("class", "links") .selectAll("line") .data(graph.links) .enter().append("line") .attr("stroke-width", function(d) { return Math.sqrt(d.value); }); var node = svg.append("g") .attr("class", "nodes") .selectAll("g") .data(graph.nodes) .enter().append("g") var circles = node.append("circle") .attr("r", 5) .attr("fill", function(d) { return color(d.name); }) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); var lables = node.append("text") .text(function(d) { return d.name; }) .attr('x', 6) .attr('y', 3); node.append("title") .text(function(d) { return d.name; }); simulation .nodes(graph.nodes) .on("tick", ticked); simulation.force("link") .links(graph.links); function ticked() { 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("transform", function(d) { return "translate(" + dx + "," + dy + ")"; }) } function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d.fx = dx; d.fy = dy; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; } function getData() { let json = {"nodes":[{"name":"ser1"},{"name":"ser2"},{"name":"ser3"},{"name":"ser4"}, {"name":"ser5"}],"links":[{"source":"ser1","dest":"ser3","value":"10"}, {"source":"ser1","dest":"ser5","value":"10"}, {"source":"ser2","dest":"ser4","value":"30"}, {"source":"ser3","dest":"ser4","value":"10"}, {"source":"ser3","dest":"ser5","value":"10"}]}; return json; } </script>

my finding below (1) Only sample2 structure (json data) suitable and can fit onto D3 (Force Directed Graph) (2) To use D3 template, change (i) id=node key (ii) add graph.link = graph.links.map(function(ele) { return { source: ele.source, target: ele.dest, value: +ele.value } }); ( (3) Json data can be internal or external source (4) D3 can provide more values/info based on the data we have

If you want to refer to a property of nodes as opposed to the index (which is the default) you can use the function link.id().

For reference, see: https://github.com/d3/d3-force#link_id

In your case, you can use sample2 and connect the links with the nodes in following way:

d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.name; }))

and you just have to rename "dest" into "target":

graph.links = graph.links.map(function(ele) {
  return {
    source: ele.source, target: ele.dest, value: +ele.value
  }
});

I slightly adjusted an existing block to load your data, see this example block . In addition, I added a code snippet here:

 var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"); var color = d3.scaleOrdinal(d3.schemeCategory20); var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function(d) { return d.name; })) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); var graph = getData(); graph.links = graph.links.map(function(ele) {return { source: ele.source, target: ele.dest, value: +ele.value } }); var link = svg.append("g") .attr("class", "links") .selectAll("line") .data(graph.links) .enter().append("line") .attr("stroke-width", function(d) { return Math.sqrt(d.value); }); var node = svg.append("g") .attr("class", "nodes") .selectAll("g") .data(graph.nodes) .enter().append("g") var circles = node.append("circle") .attr("r", 5) .attr("fill", function(d) { return color(d.name); }) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); var lables = node.append("text") .text(function(d) { return d.name; }) .attr('x', 6) .attr('y', 3); node.append("title") .text(function(d) { return d.name; }); simulation .nodes(graph.nodes) .on("tick", ticked); simulation.force("link") .links(graph.links); function ticked() { 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("transform", function(d) { return "translate(" + dx + "," + dy + ")"; }) } function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d.fx = dx; d.fy = dy; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; } function getData() { let json = {"nodes":[{"name":"ser1"},{"name":"ser2"},{"name":"ser3"},{"name":"ser4"}, {"name":"ser5"}],"links":[{"source":"ser1","dest":"ser3","value":"10"}, {"source":"ser1","dest":"ser5","value":"10"}, {"source":"ser2","dest":"ser4","value":"30"}, {"source":"ser3","dest":"ser4","value":"10"}, {"source":"ser3","dest":"ser5","value":"10"}]}; return json; }
 .links line { stroke: #999; stroke-opacity: 0.6; } .nodes circle { stroke: #fff; stroke-width: 1.5px; } text { font-family: sans-serif; font-size: 10px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script> <svg width="300" height="300"></svg>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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