D3.js 创建节点集群';在d3中按数据属性设置的焦点?

D3.js 创建节点集群';在d3中按数据属性设置的焦点?,d3.js,cluster-computing,nodes,force-layout,D3.js,Cluster Computing,Nodes,Force Layout,我试图根据数据中的某个属性(如“组”)在force布局中强制节点进入不同的集群。我正在修改Mike Bostock的多焦点force布局示例(,)中的代码我已经成功地添加了我自己的数据,但我无法指定有多少个集群,以及如何将节点分配给集群 我对d3和JavaScript比较陌生,我还没有找到很多多焦点应用程序的例子。这是我的d3代码,任何帮助或输入都非常感谢: var width = 960, height = 500; var fill = d3.scale.categ

我试图根据数据中的某个属性(如“组”)在force布局中强制节点进入不同的集群。我正在修改Mike Bostock的多焦点force布局示例(,)中的代码我已经成功地添加了我自己的数据,但我无法指定有多少个集群,以及如何将节点分配给集群

我对d3和JavaScript比较陌生,我还没有找到很多多焦点应用程序的例子。这是我的d3代码,任何帮助或输入都非常感谢:

    var width = 960,
    height = 500;

    var fill = d3.scale.category10();


    d3.json("test.json" , function(error, json){

       var root = json.nodes[0];

       root.radius = 0;
       root.fixed = true;  

      var force = d3.layout.force()
         .nodes(json.nodes)
         .size([width, height])
         .gravity(0.06)
         .charge(function(d, i) { return i ? 0 : -2000; })
         .on("tick", tick)
         .start();

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

      var elem = svg.selectAll(".elem")
         .data(json.nodes)
         .enter()
         .append("g")
         .attr("class", "elem");

  elem.append("circle")
  .attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; })
  .attr("r", 40)
  .style("fill", function(d, i) { return fill(i & 3); })
  .style("stroke", function(d, i) { return d3.rgb(fill(i & 3)).darker(2); })
  .call(force.drag)
  .on("mousedown", function() { d3.event.stopPropagation(); });

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

  svg.style("opacity", 1e-6)
    .transition()
    .duration(1000)
    .style("opacity", 1);

  d3.select("body")
    .on("mousedown", mousedown);
我一直在努力弄清楚这个勾号函数是如何工作的。我做了一些研究,发现“&”是一个位运算符,我注意到在它之后改变数字就是改变有多少个集群以及每个集群中有哪些节点。但最好我能在这里指向类似于d.group的东西来指定集群

 function tick(e) {

    // Push different nodes in different directions for clustering.
    var k = 6 * e.alpha;
    json.nodes.forEach(function(o, i) {

        o.y += i & 3 ? k : -k;
        o.x += i & 2 ? k : -k;      
    });

 var q = d3.geom.quadtree(json.nodes),
      i = 0,
      n = json.nodes.length;

 while (++i < n) q.visit(collide(json.nodes[i]));

 svg.selectAll("circle")
     .attr("cx", function(d) { return d.x; })
     .attr("cy", function(d) { return d.y; });

 svg.selectAll("text")
     .attr("x", function(d) { return d.x; })
     .attr("y", function(d) { return d.y; });
 }

  function collide(node) {
  var r = node.radius + 16,
      nx1 = node.x - r,
      nx2 = node.x + r,
      ny1 = node.y - r,
      ny2 = node.y + r;
  return function(quad, x1, y1, x2, y2) {
    if (quad.point && (quad.point !== node)) {
      var x = node.x - quad.point.x,
          y = node.y - quad.point.y,
          l = Math.sqrt(x * x + y * y),
          r = node.radius + quad.point.radius;
      if (l < r) {
        l = (l - r) / l * .5;
        node.x -= x *= l;
        node.y -= y *= l;
        quad.point.x += x;
        quad.point.y += y;
      }
    }
    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
  };
}

svg.on("mousemove", function() {
  var p1 = d3.mouse(this);
  root.px = p1[0];
  root.py = p1[1];
  force.resume();
}); 

function mousedown() {
  json.nodes.forEach(function(o, i) {
  o.x += (Math.random() - .5) * 40;
  o.y += (Math.random() - .5) * 40;
});

force.resume();
}
});

所有集群工作都在这里进行:

// Push different nodes in different directions for clustering.
var k = 6 * e.alpha;
json.nodes.forEach(function(o, i) {
    o.y += i & 3 ? k : -k;
    o.x += i & 2 ? k : -k;      
});
诚然,我不知道在这个特定的例子中它是如何工作的。这似乎是间接的,很难理解。更一般地说,这是您要执行的操作,以便进行群集:

force.on("tick", function(e) {
  var k = e.alpha * .1;
  nodes.forEach(function(node) {
    var center = ...; // here you want to set center to the appropriate [x,y] coords
    node.x += (center.x - node.x) * k;
    node.y += (center.y - node.y) * k;
  });
它直接从中取出,您可以查看源代码以查看代码

在这段代码中,更容易理解如何在滴答声时将节点推近所需的焦点。因此,现在需要根据节点的
参数,找到一种将节点映射到焦点的方法,以便填充
变量中心=

首先,您需要获取
json.nodes
中所有组的清单
d3.nest()
非常适合:

var groups = d3.nest()
  .key(function(d) { return d.group; })
  .map(json.nodes)
这将为您提供组到节点的映射。由于您的示例json中只有两个组(
“1”
“6”
),它将如下所示:

{
  "1": [
    {
      "name": "Null",
      "radius": 40,
      "color": "#ff0000",
      "gravity": 0.05,
      "group": 1
    },
    {
      "name": "One",
      "radius": 40,
      "color": "#ffff00",
      "gravity": 0.05,
      "group": 1
    },
    {
      "name": "Two",
      "radius": 40,
      "color": "#33cc33",
      "gravity": 0.2,
      "group": 1
    },
    {
      "name": "Three",
      "radius": 40,
      "color": "#3399ff",
      "gravity": 0.9,
      "group": 1
    }
  ],
  "6": [
    {
      "name": "Four",
      "radius": 40,
      "color": "#ffff00",
      "gravity": 0.05,
      "group": 6
    },
    {
      "name": "Five",
      "radius": 40,
      "color": "#33cc33",
      "gravity": 0.2,
      "group": 6
    },
    {
      "name": "Six",
      "radius": 40,
      "color": "#3399ff",
      "gravity": 0.9,
      "group": 6
    }
  ]
}
然后,您可以在
组上循环,并根据需要为每个组指定一个中心点。你如何做到这一点取决于你努力实现的目标。也许您希望将焦点分布在屏幕中心周围的一个圆圈中。这取决于你。。。但目标是最终得到
组[“1”]的结果。中心
等于
{x:123,y:456}
,因为这样您就可以从上面将其插入勾号处理程序:

force.on("tick", function(e) {
  var k = e.alpha * .1;
  nodes.forEach(function(node) {
    var center = groups[node.group].center;
    node.x += (center.x - node.x) * k;
    node.y += (center.y - node.y) * k;
  });

(希望如此)瞧

所有聚类工作都在这里进行:

// Push different nodes in different directions for clustering.
var k = 6 * e.alpha;
json.nodes.forEach(function(o, i) {
    o.y += i & 3 ? k : -k;
    o.x += i & 2 ? k : -k;      
});
诚然,我不知道在这个特定的例子中它是如何工作的。这似乎是间接的,很难理解。更一般地说,这是您要执行的操作,以便进行群集:

force.on("tick", function(e) {
  var k = e.alpha * .1;
  nodes.forEach(function(node) {
    var center = ...; // here you want to set center to the appropriate [x,y] coords
    node.x += (center.x - node.x) * k;
    node.y += (center.y - node.y) * k;
  });
它直接从中取出,您可以查看源代码以查看代码

在这段代码中,更容易理解如何在滴答声时将节点推近所需的焦点。因此,现在需要根据节点的
参数,找到一种将节点映射到焦点的方法,以便填充
变量中心=

首先,您需要获取
json.nodes
中所有组的清单
d3.nest()
非常适合:

var groups = d3.nest()
  .key(function(d) { return d.group; })
  .map(json.nodes)
这将为您提供组到节点的映射。由于您的示例json中只有两个组(
“1”
“6”
),它将如下所示:

{
  "1": [
    {
      "name": "Null",
      "radius": 40,
      "color": "#ff0000",
      "gravity": 0.05,
      "group": 1
    },
    {
      "name": "One",
      "radius": 40,
      "color": "#ffff00",
      "gravity": 0.05,
      "group": 1
    },
    {
      "name": "Two",
      "radius": 40,
      "color": "#33cc33",
      "gravity": 0.2,
      "group": 1
    },
    {
      "name": "Three",
      "radius": 40,
      "color": "#3399ff",
      "gravity": 0.9,
      "group": 1
    }
  ],
  "6": [
    {
      "name": "Four",
      "radius": 40,
      "color": "#ffff00",
      "gravity": 0.05,
      "group": 6
    },
    {
      "name": "Five",
      "radius": 40,
      "color": "#33cc33",
      "gravity": 0.2,
      "group": 6
    },
    {
      "name": "Six",
      "radius": 40,
      "color": "#3399ff",
      "gravity": 0.9,
      "group": 6
    }
  ]
}
然后,您可以在
组上循环,并根据需要为每个组指定一个中心点。你如何做到这一点取决于你努力实现的目标。也许您希望将焦点分布在屏幕中心周围的一个圆圈中。这取决于你。。。但目标是最终得到
组[“1”]的结果。中心
等于
{x:123,y:456}
,因为这样您就可以从上面将其插入勾号处理程序:

force.on("tick", function(e) {
  var k = e.alpha * .1;
  nodes.forEach(function(node) {
    var center = groups[node.group].center;
    node.x += (center.x - node.x) * k;
    node.y += (center.y - node.y) * k;
  });

(希望如此)瞧

嘿@codonnell我的答案对你来说怎么样?嘿,很抱歉回复太晚,但这正是我需要的。关键是将节点嵌套到组中,然后我可以使用诸如组[6].x=540和组[6].y=750这样的语句为每个组指定x和y值。嘿@codonnell我的答案对你来说如何?嘿,很抱歉回复太晚,但这正是我需要的。关键是将节点嵌套到组中,然后我可以使用groups[6].x=540和groups[6].y=750这样的语句为每个组指定x和y值。