【问题标题】:D3 Visualization of network data (nodes and links) via json fileD3 通过 json 文件可视化网络数据(节点和链接)
【发布时间】:2019-08-14 06:02:39
【问题描述】:

我想可视化包含 json 文件中的节点和链接的网络数据。我正在研究如何使用 D3。我没有尝试过 D3,但它似乎可以很好地可视化网络数据。

很多使用 D3 的数据可视化示例,但我观察到 json 文件示例中的链接始终基于源和目标或基于索引的节点......

如果我的 json 文件没有源和目标键,而是使用源和目标的键或 json 节点和链接只包含值...我还能利用 D3..?

我希望我可以编辑 D3 以跟随我的数据或以其他方式循环?..我不确定如何将我的 json 数据适合 D3 结构。我已经查看了 D3 文档和一些示例,但有点迷失了去哪里......感谢有人可以进一步建议我。谢谢你

请查找我拥有的数据 json 示例

SAMPLE1(仅节点和链接的值):

{"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(节点和链接的键和值:

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

我的 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(" + d.x + "," + d.y + ")";
        })
  }

function dragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

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>

我在下面的发现 (1) 只有 sample2 结构 (json 数据) 适合并且可以适合 D3 (Force Directed Graph) (2) 要使用 D3 模板,更改 (i) id=node key (ii) add graph.link = graph.links.map (函数(ele){返回{源:ele.source,目标:ele.dest,值:+ele.value}}); ( (3) Json 数据可以是内部或外部来源 (4) D3 可以根据我们拥有的数据提供更多的值/信息

【问题讨论】:

    标签: javascript python json d3.js data-visualization


    【解决方案1】:

    如果你想引用节点的属性而不是索引 (这是默认设置)您可以使用函数 link.id()。

    参考见:https://github.com/d3/d3-force#link_id

    在您的情况下,您可以使用 sample2 并通过以下方式将链接与节点连接:

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

    您只需将“dest”重命名为“target”:

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

    我稍微调整了现有块以加载您的数据,see this example block。 另外,我这里加了一个代码sn -p:

    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(" + d.x + "," + d.y + ")";
            })
      }
    
    function dragstarted(d) {
      if (!d3.event.active) simulation.alphaTarget(0.3).restart();
      d.fx = d.x;
      d.fy = d.y;
    }
    
    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>

    【讨论】:

    • 我上面的 json 链接使用 source、dest 和 value 作为键,如何将它与 index.html 中所述的源和目标映射?我需要根据我的链接键更改源/目标吗?这部分我仍然难以理解...欣赏一些可以基于我的simple2 json应用的sn-p...谢谢
    • 我用你的 sample2 数据添加了一个例子
    • 我按照上面的示例进行操作,但浏览器上没有出现任何内容...我在上面提供了我的 index.html...
    • 这很奇怪——当你在我的回答中运行代码 sn-p 按钮时,它应该会显示图表。它是否给出错误消息?
    • 是不是因为我都是在html文件里做的?
    猜你喜欢
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 2020-03-25
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 2014-03-06
    • 2017-01-15
    相关资源
    最近更新 更多