Beeswarm plot with force-directed layout in javascript/d3

Вот статья о создании графиков пчелиного роя в R.

Существует также пакет R для построения графиков пчелиного роя. Следующие два рисунка иллюстрируют некоторые возможности, которые предлагает этот пакет:

enter image description here

enter image description here

Однако сейчас я пытаюсь сделать его, используя принудительную компоновку d3.js.

Мой план состоит в том, чтобы пользовательская гравитация тянула точки к вертикальной линии и их правильному значению y, а обнаружение столкновений удерживало точки друг от друга.

У меня есть полурабочий прототип:

enter image description here

К сожалению, я не могу найти способ обойти две проблемы, которые, как я подозреваю, на самом деле являются одной и той же проблемой:

  1. Мои точки продолжают перекрываться, по крайней мере, немного.

  2. Происходит постоянная "перетасовка" после того, как точки скапливаются в центре расклада, так как силы, препятствующие столкновению, и силы, "пришедшие в центр".

Я бы хотел, чтобы точки довольно быстро пришли к соглашению о том, где они должны жить, и в итоге не пересекались.

Код силы, который я использую (на случай, если вы хотите увидеть его здесь, а не на bl.ocks.org):

force.on("tick", function(e) {
  var q,
    node,
    i = 0,
    n = nodes.length;

  var q = d3.geom.quadtree(nodes);

  while (++i < n) {
    node = nodes[i];
    q.visit(collide(node));
    xerr = node.x - node.true_x;
    yerr = node.y - node.true_y;
    node.x -= xerr*0.005;
    node.y -= yerr*0.9;
  }

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

function collide(node) {
  var r = node.radius,
    nx1,
    nx2,
    ny1,
    ny2,
    xerr,
    yerr;

  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) {
        // we're colliding.
        var xnudge, ynudge, nudge_factor;
        nudge_factor = (l - r) / l * .4;
        xnudge = x*nudge_factor;
        ynudge = y*nudge_factor;
        node.x -= xnudge;
        node.y -= ynudge;
        quad.point.x += xnudge;
        quad.point.y += ynudge;
      }
    }
    return x1 > nx2
        || x2 < nx1
        || y1 > ny2
        || y2 < ny1;
  };
}

Это моя первая вылазка в макеты, ориентированные на силу, так что извините, если это никчемно...

7
задан VividD 2 February 2014 в 02:06
поделиться