D3 强制布局,根据大小聚集到顶部

D3 force layout with clustering to the top based on size

我想基于强制布局图创建一个 d3 图,但较大的节点聚集在顶部。我从外部 json 获得了 mbostocks 示例 here 所需格式的节点,即

{
  "nodes":[
    {"name":"Myriel","group":1},
    {"name":"Child2","group":10},
    {"name":"Brujon","group":4},
    {"name":"Mme.Hucheloup","group":8}
  ],
  "links":[
    {"source":76,"target":62,"value":1},
    {"source":76,"target":48,"value":1},
    {"source":76,"target":58,"value":1}
  ]
}

我已经将图创建为力导向图,但我真的很苦恼如何根据组值聚类到顶部。到目前为止,这是我的代码:

var width = 1400,
    height = 500

var color = d3.scale.category20()
            .domain(d3.range(10));

var y = d3.scale.ordinal()
  .domain(d3.range(10))
  .rangePoints([height, 0], 1);


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

var svg = d3.select("#chart").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
    .append("g");


function zoom() {
  svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}

var endpoint = window.location.href+".json"


d3.json(endpoint, function(graph) {
  force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();

  var link = svg.selectAll(".link")
      .data(graph.links)
      .enter().append("line")
      .attr("class", "link")
      .style("marker-end",  "url(#suit)");

  var node = svg.selectAll(".node")
      .data(graph.nodes)
      .enter().append("circle")
      .attr("class", "node")
      .attr("r", function(d) { return d.group * 3; })
      .attr("cy", function(d) { return d.group; })
      .style("fill", function(d) { return color(d.group); })
      .call(force.drag)
      .on('mouseover', connectedNodes)
      .on('mouseout', UnconnectedNodes)
      .on("click",  function(d) { getprofile2(d); });
      node.each(function(d, i) {d.cy = y(d.size)})


      function getprofile2(d){

        $.ajax({
          url: "/graph/show", 
          type: "GET", 
          dataType: 'html',
          data: {name: d.name},
          success: function(result) {
            $('.bchart-content').html(result);
            //Need to parse into html here before included in .bchart-content
            addGraph(result);
          }
        });
      }


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

      node.append("circle")
  .attr("r", function(d) { return d.group * 3; });

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




  //Toggle stores whether the highlighting is on
var toggle = 0;
//Create an array logging what is connected to what
var linkedByIndex = {};
for (i = 0; i < graph.nodes.length; i++) {
    linkedByIndex[i + "," + i] = 1;
};
graph.links.forEach(function (d) {
    linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

//This function looks up whether a pair are neighbours
function neighboring(a, b) {
    return linkedByIndex[a.index + "," + b.index];
}



function connectedNodes() {
    if (toggle == 0) {
        //Reduce the opacity of all but the neighbouring nodes
        d = d3.select(this).node().__data__;
        node.style("opacity", function (o) {
            return neighboring(d, o) | neighboring(o, d) ? 1 : 0.1;
        });
        link.style("opacity", function (o) {
            return d.index==o.source.index | d.index==o.target.index ? 1 : 0.1;
        });
        //Reduce the op
        toggle = 1;
    } else {
        //Put them back to opacity=1
        node.style("opacity", 1);
        link.style("opacity", 1);
        toggle = 0;
    }
}


function UnconnectedNodes() {
node.style("opacity", 1);
        link.style("opacity", 1);
        toggle = 0;
}





graphRec=JSON.parse(JSON.stringify(graph));
function threshold(thresh) {
    graph.links.splice(0, graph.links.length);
        for (var i = 0; i < graphRec.links.length; i++) {
            if (graphRec.links[i].value > thresh) {graph.links.push(graphRec.links[i]);}
        }
    restart();
}
//Restart the visualisation after any node and link changes
function restart() {
    link = link.data(graph.links);
    link.exit().remove();
    link.enter().insert("line", ".node").attr("class", "link");
    node = node.data(graph.nodes);
    node.enter().insert("circle", ".cursor").attr("class", "node").attr("r", 5).call(force.drag);
    force.start();
}
});

理想情况下,我正在寻找与 here 类似的东西,但连接的链接仍然附加在源节点和目标节点之间。我知道这会因为相反的力量而改变图表的外观,但我希望在以后的阶段利用它来发挥我的优势

我认为我遇到的主要问题是如何将 json 字段附加到所需的元素以使每个节点基于 'group' 值

向上集群

解决方案

var width = 500,
  height = 280;

var color = d3.scale.category20();

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

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

var graph = getData();

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("title")
  .text(function(d) {
    return d.name;
  });

force.on("tick", function(e) {

  var ky = e.alpha;
  graph.nodes.forEach(function(d, i) {
      d.x -= (d.x - width/2) * 8 * ky;
      d.y -= (d.y - (d.group + 1) * 25) * 8 * ky;
  });

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


function getData() {
  return {
    "nodes": [{
      "name": "Myriel",
      "group": 1
    }, {
      "name": "Napoleon",
      "group": 1
    }, {
      "name": "Mlle.Baptistine",
      "group": 1
    }, {
      "name": "Mme.Magloire",
      "group": 1
    }, {
      "name": "CountessdeLo",
      "group": 1
    }, {
      "name": "Geborand",
      "group": 1
    }, {
      "name": "Champtercier",
      "group": 1
    }, {
      "name": "Cravatte",
      "group": 1
    }, {
      "name": "Count",
      "group": 1
    }, {
      "name": "OldMan",
      "group": 1
    }, {
      "name": "Labarre",
      "group": 2
    }, {
      "name": "Valjean",
      "group": 2
    }, {
      "name": "Marguerite",
      "group": 3
    }, {
      "name": "Mme.deR",
      "group": 2
    }, {
      "name": "Isabeau",
      "group": 2
    }, {
      "name": "Gervais",
      "group": 2
    }, {
      "name": "Tholomyes",
      "group": 3
    }, {
      "name": "Listolier",
      "group": 3
    }, {
      "name": "Fameuil",
      "group": 3
    }, {
      "name": "Blacheville",
      "group": 3
    }, {
      "name": "Favourite",
      "group": 3
    }, {
      "name": "Dahlia",
      "group": 3
    }, {
      "name": "Zephine",
      "group": 3
    }, {
      "name": "Fantine",
      "group": 3
    }, {
      "name": "Mme.Thenardier",
      "group": 4
    }, {
      "name": "Thenardier",
      "group": 4
    }, {
      "name": "Cosette",
      "group": 5
    }, {
      "name": "Javert",
      "group": 4
    }, {
      "name": "Fauchelevent",
      "group": 0
    }, {
      "name": "Bamatabois",
      "group": 2
    }, {
      "name": "Perpetue",
      "group": 3
    }, {
      "name": "Simplice",
      "group": 2
    }, {
      "name": "Scaufflaire",
      "group": 2
    }, {
      "name": "Woman1",
      "group": 2
    }, {
      "name": "Judge",
      "group": 2
    }, {
      "name": "Champmathieu",
      "group": 2
    }, {
      "name": "Brevet",
      "group": 2
    }, {
      "name": "Chenildieu",
      "group": 2
    }, {
      "name": "Cochepaille",
      "group": 2
    }, {
      "name": "Pontmercy",
      "group": 4
    }, {
      "name": "Boulatruelle",
      "group": 6
    }, {
      "name": "Eponine",
      "group": 4
    }, {
      "name": "Anzelma",
      "group": 4
    }, {
      "name": "Woman2",
      "group": 5
    }, {
      "name": "MotherInnocent",
      "group": 0
    }, {
      "name": "Gribier",
      "group": 0
    }, {
      "name": "Jondrette",
      "group": 7
    }, {
      "name": "Mme.Burgon",
      "group": 7
    }, {
      "name": "Gavroche",
      "group": 8
    }, {
      "name": "Gillenormand",
      "group": 5
    }, {
      "name": "Magnon",
      "group": 5
    }, {
      "name": "Mlle.Gillenormand",
      "group": 5
    }, {
      "name": "Mme.Pontmercy",
      "group": 5
    }, {
      "name": "Mlle.Vaubois",
      "group": 5
    }, {
      "name": "Lt.Gillenormand",
      "group": 5
    }, {
      "name": "Marius",
      "group": 8
    }, {
      "name": "BaronessT",
      "group": 5
    }, {
      "name": "Mabeuf",
      "group": 8
    }, {
      "name": "Enjolras",
      "group": 8
    }, {
      "name": "Combeferre",
      "group": 8
    }, {
      "name": "Prouvaire",
      "group": 8
    }, {
      "name": "Feuilly",
      "group": 8
    }, {
      "name": "Courfeyrac",
      "group": 8
    }, {
      "name": "Bahorel",
      "group": 8
    }, {
      "name": "Bossuet",
      "group": 8
    }, {
      "name": "Joly",
      "group": 8
    }, {
      "name": "Grantaire",
      "group": 8
    }, {
      "name": "MotherPlutarch",
      "group": 9
    }, {
      "name": "Gueulemer",
      "group": 4
    }, {
      "name": "Babet",
      "group": 4
    }, {
      "name": "Claquesous",
      "group": 4
    }, {
      "name": "Montparnasse",
      "group": 4
    }, {
      "name": "Toussaint",
      "group": 5
    }, {
      "name": "Child1",
      "group": 10
    }, {
      "name": "Child2",
      "group": 10
    }, {
      "name": "Brujon",
      "group": 4
    }, {
      "name": "Mme.Hucheloup",
      "group": 8
    }],
    "links": [{
      "source": 1,
      "target": 0,
      "value": 1
    }, {
      "source": 2,
      "target": 0,
      "value": 8
    }, {
      "source": 3,
      "target": 0,
      "value": 10
    }, {
      "source": 3,
      "target": 2,
      "value": 6
    }, {
      "source": 4,
      "target": 0,
      "value": 1
    }, {
      "source": 5,
      "target": 0,
      "value": 1
    }, {
      "source": 6,
      "target": 0,
      "value": 1
    }, {
      "source": 7,
      "target": 0,
      "value": 1
    }, {
      "source": 8,
      "target": 0,
      "value": 2
    }, {
      "source": 9,
      "target": 0,
      "value": 1
    }, {
      "source": 11,
      "target": 10,
      "value": 1
    }, {
      "source": 11,
      "target": 3,
      "value": 3
    }, {
      "source": 11,
      "target": 2,
      "value": 3
    }, {
      "source": 11,
      "target": 0,
      "value": 5
    }, {
      "source": 12,
      "target": 11,
      "value": 1
    }, {
      "source": 13,
      "target": 11,
      "value": 1
    }, {
      "source": 14,
      "target": 11,
      "value": 1
    }, {
      "source": 15,
      "target": 11,
      "value": 1
    }, {
      "source": 17,
      "target": 16,
      "value": 4
    }, {
      "source": 18,
      "target": 16,
      "value": 4
    }, {
      "source": 18,
      "target": 17,
      "value": 4
    }, {
      "source": 19,
      "target": 16,
      "value": 4
    }, {
      "source": 19,
      "target": 17,
      "value": 4
    }, {
      "source": 19,
      "target": 18,
      "value": 4
    }, {
      "source": 20,
      "target": 16,
      "value": 3
    }, {
      "source": 20,
      "target": 17,
      "value": 3
    }, {
      "source": 20,
      "target": 18,
      "value": 3
    }, {
      "source": 20,
      "target": 19,
      "value": 4
    }, {
      "source": 21,
      "target": 16,
      "value": 3
    }, {
      "source": 21,
      "target": 17,
      "value": 3
    }, {
      "source": 21,
      "target": 18,
      "value": 3
    }, {
      "source": 21,
      "target": 19,
      "value": 3
    }, {
      "source": 21,
      "target": 20,
      "value": 5
    }, {
      "source": 22,
      "target": 16,
      "value": 3
    }, {
      "source": 22,
      "target": 17,
      "value": 3
    }, {
      "source": 22,
      "target": 18,
      "value": 3
    }, {
      "source": 22,
      "target": 19,
      "value": 3
    }, {
      "source": 22,
      "target": 20,
      "value": 4
    }, {
      "source": 22,
      "target": 21,
      "value": 4
    }, {
      "source": 23,
      "target": 16,
      "value": 3
    }, {
      "source": 23,
      "target": 17,
      "value": 3
    }, {
      "source": 23,
      "target": 18,
      "value": 3
    }, {
      "source": 23,
      "target": 19,
      "value": 3
    }, {
      "source": 23,
      "target": 20,
      "value": 4
    }, {
      "source": 23,
      "target": 21,
      "value": 4
    }, {
      "source": 23,
      "target": 22,
      "value": 4
    }, {
      "source": 23,
      "target": 12,
      "value": 2
    }, {
      "source": 23,
      "target": 11,
      "value": 9
    }, {
      "source": 24,
      "target": 23,
      "value": 2
    }, {
      "source": 24,
      "target": 11,
      "value": 7
    }, {
      "source": 25,
      "target": 24,
      "value": 13
    }, {
      "source": 25,
      "target": 23,
      "value": 1
    }, {
      "source": 25,
      "target": 11,
      "value": 12
    }, {
      "source": 26,
      "target": 24,
      "value": 4
    }, {
      "source": 26,
      "target": 11,
      "value": 31
    }, {
      "source": 26,
      "target": 16,
      "value": 1
    }, {
      "source": 26,
      "target": 25,
      "value": 1
    }, {
      "source": 27,
      "target": 11,
      "value": 17
    }, {
      "source": 27,
      "target": 23,
      "value": 5
    }, {
      "source": 27,
      "target": 25,
      "value": 5
    }, {
      "source": 27,
      "target": 24,
      "value": 1
    }, {
      "source": 27,
      "target": 26,
      "value": 1
    }, {
      "source": 28,
      "target": 11,
      "value": 8
    }, {
      "source": 28,
      "target": 27,
      "value": 1
    }, {
      "source": 29,
      "target": 23,
      "value": 1
    }, {
      "source": 29,
      "target": 27,
      "value": 1
    }, {
      "source": 29,
      "target": 11,
      "value": 2
    }, {
      "source": 30,
      "target": 23,
      "value": 1
    }, {
      "source": 31,
      "target": 30,
      "value": 2
    }, {
      "source": 31,
      "target": 11,
      "value": 3
    }, {
      "source": 31,
      "target": 23,
      "value": 2
    }, {
      "source": 31,
      "target": 27,
      "value": 1
    }, {
      "source": 32,
      "target": 11,
      "value": 1
    }, {
      "source": 33,
      "target": 11,
      "value": 2
    }, {
      "source": 33,
      "target": 27,
      "value": 1
    }, {
      "source": 34,
      "target": 11,
      "value": 3
    }, {
      "source": 34,
      "target": 29,
      "value": 2
    }, {
      "source": 35,
      "target": 11,
      "value": 3
    }, {
      "source": 35,
      "target": 34,
      "value": 3
    }, {
      "source": 35,
      "target": 29,
      "value": 2
    }, {
      "source": 36,
      "target": 34,
      "value": 2
    }, {
      "source": 36,
      "target": 35,
      "value": 2
    }, {
      "source": 36,
      "target": 11,
      "value": 2
    }, {
      "source": 36,
      "target": 29,
      "value": 1
    }, {
      "source": 37,
      "target": 34,
      "value": 2
    }, {
      "source": 37,
      "target": 35,
      "value": 2
    }, {
      "source": 37,
      "target": 36,
      "value": 2
    }, {
      "source": 37,
      "target": 11,
      "value": 2
    }, {
      "source": 37,
      "target": 29,
      "value": 1
    }, {
      "source": 38,
      "target": 34,
      "value": 2
    }, {
      "source": 38,
      "target": 35,
      "value": 2
    }, {
      "source": 38,
      "target": 36,
      "value": 2
    }, {
      "source": 38,
      "target": 37,
      "value": 2
    }, {
      "source": 38,
      "target": 11,
      "value": 2
    }, {
      "source": 38,
      "target": 29,
      "value": 1
    }, {
      "source": 39,
      "target": 25,
      "value": 1
    }, {
      "source": 40,
      "target": 25,
      "value": 1
    }, {
      "source": 41,
      "target": 24,
      "value": 2
    }, {
      "source": 41,
      "target": 25,
      "value": 3
    }, {
      "source": 42,
      "target": 41,
      "value": 2
    }, {
      "source": 42,
      "target": 25,
      "value": 2
    }, {
      "source": 42,
      "target": 24,
      "value": 1
    }, {
      "source": 43,
      "target": 11,
      "value": 3
    }, {
      "source": 43,
      "target": 26,
      "value": 1
    }, {
      "source": 43,
      "target": 27,
      "value": 1
    }, {
      "source": 44,
      "target": 28,
      "value": 3
    }, {
      "source": 44,
      "target": 11,
      "value": 1
    }, {
      "source": 45,
      "target": 28,
      "value": 2
    }, {
      "source": 47,
      "target": 46,
      "value": 1
    }, {
      "source": 48,
      "target": 47,
      "value": 2
    }, {
      "source": 48,
      "target": 25,
      "value": 1
    }, {
      "source": 48,
      "target": 27,
      "value": 1
    }, {
      "source": 48,
      "target": 11,
      "value": 1
    }, {
      "source": 49,
      "target": 26,
      "value": 3
    }, {
      "source": 49,
      "target": 11,
      "value": 2
    }, {
      "source": 50,
      "target": 49,
      "value": 1
    }, {
      "source": 50,
      "target": 24,
      "value": 1
    }, {
      "source": 51,
      "target": 49,
      "value": 9
    }, {
      "source": 51,
      "target": 26,
      "value": 2
    }, {
      "source": 51,
      "target": 11,
      "value": 2
    }, {
      "source": 52,
      "target": 51,
      "value": 1
    }, {
      "source": 52,
      "target": 39,
      "value": 1
    }, {
      "source": 53,
      "target": 51,
      "value": 1
    }, {
      "source": 54,
      "target": 51,
      "value": 2
    }, {
      "source": 54,
      "target": 49,
      "value": 1
    }, {
      "source": 54,
      "target": 26,
      "value": 1
    }, {
      "source": 55,
      "target": 51,
      "value": 6
    }, {
      "source": 55,
      "target": 49,
      "value": 12
    }, {
      "source": 55,
      "target": 39,
      "value": 1
    }, {
      "source": 55,
      "target": 54,
      "value": 1
    }, {
      "source": 55,
      "target": 26,
      "value": 21
    }, {
      "source": 55,
      "target": 11,
      "value": 19
    }, {
      "source": 55,
      "target": 16,
      "value": 1
    }, {
      "source": 55,
      "target": 25,
      "value": 2
    }, {
      "source": 55,
      "target": 41,
      "value": 5
    }, {
      "source": 55,
      "target": 48,
      "value": 4
    }, {
      "source": 56,
      "target": 49,
      "value": 1
    }, {
      "source": 56,
      "target": 55,
      "value": 1
    }, {
      "source": 57,
      "target": 55,
      "value": 1
    }, {
      "source": 57,
      "target": 41,
      "value": 1
    }, {
      "source": 57,
      "target": 48,
      "value": 1
    }, {
      "source": 58,
      "target": 55,
      "value": 7
    }, {
      "source": 58,
      "target": 48,
      "value": 7
    }, {
      "source": 58,
      "target": 27,
      "value": 6
    }, {
      "source": 58,
      "target": 57,
      "value": 1
    }, {
      "source": 58,
      "target": 11,
      "value": 4
    }, {
      "source": 59,
      "target": 58,
      "value": 15
    }, {
      "source": 59,
      "target": 55,
      "value": 5
    }, {
      "source": 59,
      "target": 48,
      "value": 6
    }, {
      "source": 59,
      "target": 57,
      "value": 2
    }, {
      "source": 60,
      "target": 48,
      "value": 1
    }, {
      "source": 60,
      "target": 58,
      "value": 4
    }, {
      "source": 60,
      "target": 59,
      "value": 2
    }, {
      "source": 61,
      "target": 48,
      "value": 2
    }, {
      "source": 61,
      "target": 58,
      "value": 6
    }, {
      "source": 61,
      "target": 60,
      "value": 2
    }, {
      "source": 61,
      "target": 59,
      "value": 5
    }, {
      "source": 61,
      "target": 57,
      "value": 1
    }, {
      "source": 61,
      "target": 55,
      "value": 1
    }, {
      "source": 62,
      "target": 55,
      "value": 9
    }, {
      "source": 62,
      "target": 58,
      "value": 17
    }, {
      "source": 62,
      "target": 59,
      "value": 13
    }, {
      "source": 62,
      "target": 48,
      "value": 7
    }, {
      "source": 62,
      "target": 57,
      "value": 2
    }, {
      "source": 62,
      "target": 41,
      "value": 1
    }, {
      "source": 62,
      "target": 61,
      "value": 6
    }, {
      "source": 62,
      "target": 60,
      "value": 3
    }, {
      "source": 63,
      "target": 59,
      "value": 5
    }, {
      "source": 63,
      "target": 48,
      "value": 5
    }, {
      "source": 63,
      "target": 62,
      "value": 6
    }, {
      "source": 63,
      "target": 57,
      "value": 2
    }, {
      "source": 63,
      "target": 58,
      "value": 4
    }, {
      "source": 63,
      "target": 61,
      "value": 3
    }, {
      "source": 63,
      "target": 60,
      "value": 2
    }, {
      "source": 63,
      "target": 55,
      "value": 1
    }, {
      "source": 64,
      "target": 55,
      "value": 5
    }, {
      "source": 64,
      "target": 62,
      "value": 12
    }, {
      "source": 64,
      "target": 48,
      "value": 5
    }, {
      "source": 64,
      "target": 63,
      "value": 4
    }, {
      "source": 64,
      "target": 58,
      "value": 10
    }, {
      "source": 64,
      "target": 61,
      "value": 6
    }, {
      "source": 64,
      "target": 60,
      "value": 2
    }, {
      "source": 64,
      "target": 59,
      "value": 9
    }, {
      "source": 64,
      "target": 57,
      "value": 1
    }, {
      "source": 64,
      "target": 11,
      "value": 1
    }, {
      "source": 65,
      "target": 63,
      "value": 5
    }, {
      "source": 65,
      "target": 64,
      "value": 7
    }, {
      "source": 65,
      "target": 48,
      "value": 3
    }, {
      "source": 65,
      "target": 62,
      "value": 5
    }, {
      "source": 65,
      "target": 58,
      "value": 5
    }, {
      "source": 65,
      "target": 61,
      "value": 5
    }, {
      "source": 65,
      "target": 60,
      "value": 2
    }, {
      "source": 65,
      "target": 59,
      "value": 5
    }, {
      "source": 65,
      "target": 57,
      "value": 1
    }, {
      "source": 65,
      "target": 55,
      "value": 2
    }, {
      "source": 66,
      "target": 64,
      "value": 3
    }, {
      "source": 66,
      "target": 58,
      "value": 3
    }, {
      "source": 66,
      "target": 59,
      "value": 1
    }, {
      "source": 66,
      "target": 62,
      "value": 2
    }, {
      "source": 66,
      "target": 65,
      "value": 2
    }, {
      "source": 66,
      "target": 48,
      "value": 1
    }, {
      "source": 66,
      "target": 63,
      "value": 1
    }, {
      "source": 66,
      "target": 61,
      "value": 1
    }, {
      "source": 66,
      "target": 60,
      "value": 1
    }, {
      "source": 67,
      "target": 57,
      "value": 3
    }, {
      "source": 68,
      "target": 25,
      "value": 5
    }, {
      "source": 68,
      "target": 11,
      "value": 1
    }, {
      "source": 68,
      "target": 24,
      "value": 1
    }, {
      "source": 68,
      "target": 27,
      "value": 1
    }, {
      "source": 68,
      "target": 48,
      "value": 1
    }, {
      "source": 68,
      "target": 41,
      "value": 1
    }, {
      "source": 69,
      "target": 25,
      "value": 6
    }, {
      "source": 69,
      "target": 68,
      "value": 6
    }, {
      "source": 69,
      "target": 11,
      "value": 1
    }, {
      "source": 69,
      "target": 24,
      "value": 1
    }, {
      "source": 69,
      "target": 27,
      "value": 2
    }, {
      "source": 69,
      "target": 48,
      "value": 1
    }, {
      "source": 69,
      "target": 41,
      "value": 1
    }, {
      "source": 70,
      "target": 25,
      "value": 4
    }, {
      "source": 70,
      "target": 69,
      "value": 4
    }, {
      "source": 70,
      "target": 68,
      "value": 4
    }, {
      "source": 70,
      "target": 11,
      "value": 1
    }, {
      "source": 70,
      "target": 24,
      "value": 1
    }, {
      "source": 70,
      "target": 27,
      "value": 1
    }, {
      "source": 70,
      "target": 41,
      "value": 1
    }, {
      "source": 70,
      "target": 58,
      "value": 1
    }, {
      "source": 71,
      "target": 27,
      "value": 1
    }, {
      "source": 71,
      "target": 69,
      "value": 2
    }, {
      "source": 71,
      "target": 68,
      "value": 2
    }, {
      "source": 71,
      "target": 70,
      "value": 2
    }, {
      "source": 71,
      "target": 11,
      "value": 1
    }, {
      "source": 71,
      "target": 48,
      "value": 1
    }, {
      "source": 71,
      "target": 41,
      "value": 1
    }, {
      "source": 71,
      "target": 25,
      "value": 1
    }, {
      "source": 72,
      "target": 26,
      "value": 2
    }, {
      "source": 72,
      "target": 27,
      "value": 1
    }, {
      "source": 72,
      "target": 11,
      "value": 1
    }, {
      "source": 73,
      "target": 48,
      "value": 2
    }, {
      "source": 74,
      "target": 48,
      "value": 2
    }, {
      "source": 74,
      "target": 73,
      "value": 3
    }, {
      "source": 75,
      "target": 69,
      "value": 3
    }, {
      "source": 75,
      "target": 68,
      "value": 3
    }, {
      "source": 75,
      "target": 25,
      "value": 3
    }, {
      "source": 75,
      "target": 48,
      "value": 1
    }, {
      "source": 75,
      "target": 41,
      "value": 1
    }, {
      "source": 75,
      "target": 70,
      "value": 1
    }, {
      "source": 75,
      "target": 71,
      "value": 1
    }, {
      "source": 76,
      "target": 64,
      "value": 1
    }, {
      "source": 76,
      "target": 65,
      "value": 1
    }, {
      "source": 76,
      "target": 66,
      "value": 1
    }, {
      "source": 76,
      "target": 63,
      "value": 1
    }, {
      "source": 76,
      "target": 62,
      "value": 1
    }, {
      "source": 76,
      "target": 48,
      "value": 1
    }, {
      "source": 76,
      "target": 58,
      "value": 1
    }]

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

.link {
  stroke: #999;
  stroke-opacity: .6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

说明

解决方案的出发点是您在问题中链接到的示例,只是稍作调整以适应 SO 代码片段格式。

解决方案的关键部分是定义自定义力,在这部分代码中:

force.on("tick", function(e) {

  var ky = e.alpha;
  graph.nodes.forEach(function(d, i) {
      d.x -= (d.x - width/2) * 8 * ky;
      d.y -= (d.y - (d.group + 1) * 25) * 8 * ky;
  });

  ...

};

d.y -= (d.y - (d.group + 1) * 25) * 8 * ky; 使节点看起来接近于每个节点对应字段定义的水平水平 group