【问题标题】:Can't add labels to d3js force layout network visualization无法将标签添加到 d3js 强制布局网络可视化
【发布时间】:2014-05-13 18:26:56
【问题描述】:

我一直在努力尝试使用 d3js 在强制导向布局网络可视化中实现标签(我正在使用 Python 和 Flask 从 API 生成 JSON 文件并在网页中呈现可视化。

我看过很多例子,比如...

http://bl.ocks.org/mbostock/2706022

http://bl.ocks.org/mbostock/1153292

http://bl.ocks.org/MoritzStefaner/1377729

...但我对 Javascript 还很陌生,所以我很难将这些代码重新实现到我当前的代码中:

我一直使用的 JSON 文件是:

{"directed": true, "graph": [], "nodes": [{"id": "user1"}, {"id": "user2"}, {"id": "user3"}, {"id": "user4"}, {"id": "user5"}, {"id": "user6"}, {"id": "user7"}, {"id": "user8"}, {"id": "user9"}, {"id": "user10"}, {"id": "user11"}, {"id": "user12"}, {"id": "user13"}, {"id": "user14"}, {"id": "user15"}, {"id": "user16"}, {"id": "user17"}, {"id": "user18"}, {"id": "user19"}, {"id": "user20"}, {"id": "user21"}, {"id": "user22"}, {"id": "myaccount"}, {"id": "user23"}, {"id": "user24"}, {"id": "user25"}, {"id": "user26"}, {"id": "user27"}, {"id": "user28"}, {"id": "user29"}, {"id": "user30"}, {"id": "user31"}, {"id": "user32"}, {"id": "user33"}, {"id": "user34"}, {"id": "user35"}, {"id": "user36"}, {"id": "user37"}, {"id": "user38"}, {"id": "user39"}, {"id": "user40"}, {"id": "user41"}, {"id": "user42"}, {"id": "user43"}, {"id": "user44"}, {"id": "user45"}, {"id": "user46"}, {"id": "user47"}, {"id": "user48"}, {"id": "user49"}, {"id": "user50"}, {"id": "user51"}, {"id": "user52"}, {"id": "user53"}, {"id": "user54"}, {"id": "user55"}, {"id": "user56"}, {"id": "user57"}, {"id": "user58"}, {"id": "user59"}, {"id": "user60"}, {"id": "user61"}, {"id": "user62"}, {"id": "user63"}, {"id": "user64"}, {"id": "user65"}, {"id": "user66"}, {"id": "user67"}, {"id": "user68"}, {"id": "user69"}, {"id": "user70"}, {"id": "user71"}, {"id": "user72"}, {"id": "user73"}, {"id": "user74"}, {"id": "user75"}, {"id": "user76"}, {"id": "user77"}, {"id": "user78"}, {"id": "user79"}, {"id": "user80"}, {"id": "user81"}, {"id": "user82"}, {"id": "user83"}, {"id": "user84"}, {"id": "user85"}, {"id": "user86"}, {"id": "user87"}, {"id": "user88"}, {"id": "user89"}, {"id": "user90"}, {"id": "user91"}, {"id": "user92"}, {"id": "user93"}, {"id": "user94"}, {"id": "user95"}, {"id": "user96"}, {"id": "user97"}, {"id": "user98"}, {"id": "user99"}, {"id": "user100"}, {"id": "user101"}, {"id": "user102"}, {"id": "cuser103"}, {"id": "user104"}, {"id": "user105"}, {"id": "user106"}, {"id": "user107"}, {"id": "user108"}, {"id": "user109"}, {"id": "user110"}, {"id": "user111"}, {"id": "user112"}, {"id": "user113"}, {"id": "user114"}, {"id": "user115"}, {"id": "user116"}, {"id": "user117"}, {"id": "user118"}, {"id": "user119"}, {"id": "user120"}, {"id": "user121"}, {"id": "user122"}, {"id": "user123"}, {"id": "user124"}, {"id": "user125"}, {"id": "user126"}, {"id": "user127"}, {"id": "user128"}, {"id": "user129"}, {"id": "user130"}, {"id": "user131"}], "links": [{"source": 22, "target": 72, "weight": 1}, {"source": 22, "target": 65, "weight": 3}, {"source": 22, "target": 115, "weight": 1}, {"source": 22, "target": 56, "weight": 1}, {"source": 22, "target": 106, "weight": 1}, {"source": 22, "target": 124, "weight": 3}, {"source": 22, "target": 48, "weight": 1}, {"source": 22, "target": 101, "weight": 1}, {"source": 22, "target": 111, "weight": 1}, {"source": 22, "target": 64, "weight": 4}, {"source": 22, "target": 112, "weight": 1}, {"source": 22, "target": 71, "weight": 1}, {"source": 48, "target": 121, "weight": 1}, {"source": 48, "target": 114, "weight": 1}, {"source": 48, "target": 34, "weight": 1}, {"source": 48, "target": 28, "weight": 1}, {"source": 48, "target": 43, "weight": 1}, {"source": 48, "target": 52, "weight": 1}, {"source": 48, "target": 64, "weight": 1}, {"source": 56, "target": 101, "weight": 1}, {"source": 56, "target": 9, "weight": 1}, {"source": 56, "target": 50, "weight": 1}, {"source": 56, "target": 85, "weight": 1}, {"source": 64, "target": 51, "weight": 1}, {"source": 64, "target": 46, "weight": 1}, {"source": 64, "target": 104, "weight": 1}, {"source": 64, "target": 122, "weight": 1}, {"source": 64, "target": 20, "weight": 2}, {"source": 64, "target": 2, "weight": 1}, {"source": 64, "target": 23, "weight": 1}, {"source": 64, "target": 94, "weight": 1}, {"source": 64, "target": 60, "weight": 1}, {"source": 64, "target": 6, "weight": 1}, {"source": 64, "target": 89, "weight": 1}, {"source": 64, "target": 96, "weight": 1}, {"source": 64, "target": 131, "weight": 3}, {"source": 64, "target": 50, "weight": 1}, {"source": 65, "target": 73, "weight": 2}, {"source": 65, "target": 90, "weight": 1}, {"source": 65, "target": 11, "weight": 3}, {"source": 65, "target": 1, "weight": 3}, {"source": 65, "target": 29, "weight": 4}, {"source": 65, "target": 13, "weight": 1}, {"source": 65, "target": 83, "weight": 1}, {"source": 65, "target": 78, "weight": 1}, {"source": 65, "target": 88, "weight": 1}, {"source": 65, "target": 113, "weight": 2}, {"source": 65, "target": 63, "weight": 1}, {"source": 71, "target": 10, "weight": 1}, {"source": 72, "target": 98, "weight": 3}, {"source": 72, "target": 123, "weight": 1}, {"source": 72, "target": 91, "weight": 1}, {"source": 72, "target": 12, "weight": 1}, {"source": 72, "target": 107, "weight": 1}, {"source": 72, "target": 7, "weight": 2}, {"source": 72, "target": 36, "weight": 4}, {"source": 72, "target": 128, "weight": 4}, {"source": 72, "target": 129, "weight": 1}, {"source": 72, "target": 38, "weight": 2}, {"source": 101, "target": 69, "weight": 1}, {"source": 101, "target": 119, "weight": 1}, {"source": 101, "target": 82, "weight": 1}, {"source": 101, "target": 21, "weight": 1}, {"source": 101, "target": 116, "weight": 1}, {"source": 101, "target": 125, "weight": 1}, {"source": 101, "target": 4, "weight": 1}, {"source": 101, "target": 109, "weight": 1}, {"source": 101, "target": 64, "weight": 2}, {"source": 101, "target": 53, "weight": 1}, {"source": 101, "target": 130, "weight": 1}, {"source": 101, "target": 102, "weight": 1}, {"source": 101, "target": 32, "weight": 1}, {"source": 101, "target": 80, "weight": 1}, {"source": 101, "target": 62, "weight": 1}, {"source": 106, "target": 103, "weight": 1}, {"source": 106, "target": 84, "weight": 1}, {"source": 106, "target": 66, "weight": 1}, {"source": 106, "target": 67, "weight": 1}, {"source": 106, "target": 87, "weight": 1}, {"source": 106, "target": 15, "weight": 1}, {"source": 106, "target": 126, "weight": 2}, {"source": 106, "target": 74, "weight": 1}, {"source": 106, "target": 127, "weight": 1}, {"source": 106, "target": 42, "weight": 4}, {"source": 106, "target": 5, "weight": 1}, {"source": 106, "target": 77, "weight": 2}, {"source": 106, "target": 79, "weight": 1}, {"source": 106, "target": 118, "weight": 1}, {"source": 111, "target": 92, "weight": 1}, {"source": 111, "target": 54, "weight": 1}, {"source": 111, "target": 55, "weight": 1}, {"source": 111, "target": 95, "weight": 1}, {"source": 111, "target": 41, "weight": 2}, {"source": 111, "target": 3, "weight": 1}, {"source": 111, "target": 93, "weight": 3}, {"source": 111, "target": 76, "weight": 1}, {"source": 111, "target": 49, "weight": 1}, {"source": 111, "target": 99, "weight": 1}, {"source": 111, "target": 44, "weight": 1}, {"source": 111, "target": 61, "weight": 1}, {"source": 111, "target": 117, "weight": 2}, {"source": 111, "target": 81, "weight": 1}, {"source": 111, "target": 97, "weight": 1}, {"source": 112, "target": 26, "weight": 1}, {"source": 112, "target": 8, "weight": 1}, {"source": 112, "target": 39, "weight": 1}, {"source": 112, "target": 45, "weight": 1}, {"source": 112, "target": 57, "weight": 1}, {"source": 112, "target": 47, "weight": 1}, {"source": 112, "target": 108, "weight": 1}, {"source": 112, "target": 37, "weight": 5}, {"source": 112, "target": 17, "weight": 1}, {"source": 112, "target": 31, "weight": 1}, {"source": 112, "target": 131, "weight": 4}, {"source": 112, "target": 94, "weight": 1}, {"source": 115, "target": 18, "weight": 3}, {"source": 115, "target": 19, "weight": 1}, {"source": 115, "target": 33, "weight": 1}, {"source": 115, "target": 30, "weight": 1}, {"source": 115, "target": 110, "weight": 1}, {"source": 115, "target": 70, "weight": 1}, {"source": 124, "target": 120, "weight": 1}, {"source": 124, "target": 0, "weight": 1}, {"source": 124, "target": 40, "weight": 1}, {"source": 124, "target": 105, "weight": 1}, {"source": 124, "target": 35, "weight": 1}, {"source": 124, "target": 27, "weight": 1}, {"source": 124, "target": 86, "weight": 3}, {"source": 124, "target": 68, "weight": 1}, {"source": 124, "target": 14, "weight": 1}, {"source": 124, "target": 58, "weight": 1}, {"source": 124, "target": 24, "weight": 1}, {"source": 124, "target": 25, "weight": 1}, {"source": 124, "target": 100, "weight": 1}, {"source": 124, "target": 59, "weight": 1}, {"source": 124, "target": 75, "weight": 2}, {"source": 124, "target": 16, "weight": 2}], "multigraph": false}

而当前生成不带标签的可视化的代码是:

var width = 600,
    height = 500;

var color = d3.scale.category20();

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

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

d3.json("static/reblognetwork_{{ session_username }}.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);

  node.append("text")
    // .attr("x", 12)
    // .attr("dy", ".35em")
    .text(function(d) { return d.id; });

  // var text = svg.append("g").selectAll("text")
  //   .data(graph.nodes)
  // .enter().append("text")
  //   // .attr("x", ".5em")
  //   // .attr("y", ".31em")
  //   .text(function(d) { return d.id; });

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

  });
});

您也可以看到一些我尝试过但没有成功的(注释掉的)代码,这些代码基于之前的问题,例如D3.js, force-graph, cannot display text/label of nodes

任何帮助表示赞赏!


解决方案:下面的最终代码有效。

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

<script>
var width = 500, height = 450;

var svg = d3.select("div").append("svg");

var color = d3.scale.category20();

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

svg.attr("width", width)
    .attr("height", height);

d3.json("static/reblognetwork_{{ session_username }}.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("g.node")
      .data(graph.nodes);
  var nodeEnter = node.enter()
      .append("g")
      .attr("class", "node")
      .call(force.drag);
  nodeEnter.append("circle")
      .attr("r", 5)
      .style("fill", function(d) { return color(d.group); })
      .call(force.drag);

  nodeEnter.append("text")
     .attr("dx", 5)
     .style("text-anchor", "start")
     .text(function(d) { return d.id; });

  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("transform", function(d) {
      return "translate(" + [d.x, d.y] + ")";
    });
  });
};


</script>

<div id="networkgraph"></div>

【问题讨论】:

    标签: javascript python json d3.js force-layout


    【解决方案1】:

    我不擅长故障排除,但我将您的代码插入到 JSFiddle 中,并且节点似乎呈现(虽然不是链接)。

    也许它与您传入的数据有关?在这种情况下,我插入 Les Miserables 数据进行测试(所以我所做的唯一更改是删除 d3.json 调用并缩小节点文本的大小)。

    http://jsfiddle.net/JA4kD/1/

    var width = 500,
        height = 450;
    
    var svg = d3.select("#networkgraph").append("svg");
    
    var color = d3.scale.category20();
    
    var force = d3.layout.force()
        .charge(-120)
        .linkDistance(30)
        .size([width, height]);
    
    svg.attr("width", width)
        .attr("height", height);
    
    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("g.node")
        .data(graph.nodes);
    
    var nodeEnter = node.enter()
        .append("g")
        .attr("class", "node")
        .call(force.drag);
    
    nodeEnter.append("circle")
        .attr("r", 5)
        .style("fill", function (d) { return color(d.group); })
        .call(force.drag);
    
    nodeEnter.append("text")
        .attr("dx", 5)
        .style("text-anchor", "start")
        .style("font-size", "8px")
        .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("transform", function (d) { return "translate(" + [d.x, d.y] + ")"; });
    });
    

    【讨论】:

      【解决方案2】:

      当为一个节点添加多个元素时,通常最好有一个 g 元素,其位置由您设置并包含所有其他元素,就像您链接到的第一个示例一样。在您的情况下,这可能如下所示。

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

      完整的演示here

      【讨论】:

      • 尝试添加上面的代码,但我在之前的一些代码中遇到了同样的问题,标签(这次还有圆圈)悬停在左上角。 screenshot
      • 你看过完整的演示了吗?
      • 是的。划掉最后一条评论;我重新实现了整个代码,只更改了第 25 行 –– d3.json("static/reblognetwork_{{ session_username }}.json", function(error, graph) { –– 现在甚至没有生成可视化。不确定如果我调用 JSON 的方式有问题,或者...?
      • 好的,您仍然收到该错误吗?恐怕没有看到您的代码,我无法帮助您。
      • 听起来像是加载 JSON 的问题。你检查它是否加载正确。
      猜你喜欢
      • 1970-01-01
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 2020-02-05
      • 2019-08-10
      • 2019-09-02
      • 2018-12-26
      • 1970-01-01
      相关资源
      最近更新 更多