17

我正在研究标签可视化,其中标签在不同的力导向布局之间转换。

我在弄清楚如何从气泡图过渡到节点图时遇到了一些问题,但我对如何让图表过渡到词云有点困惑。我的困难主要源于我在编写自定义聚类/碰撞检测函数方面缺乏经验。

我将力声明为全局变量,然后在用户单击按钮时停止并启动它们:

var force1 = d3.layout.force()
    .size([width, height])
    .charge(0)
    .gravity(0.02)
    .on("tick", ticka);

//layout for node chart
var force2 = d3.layout.force()
    .size([width, height])
    .charge(-50)
    .gravity(0.005)
    .linkDistance(120)
    .on("tick", tickb);

//layout for bubble chart
var force3 = d3.layout.force()
    .size([width, height])
    .charge(0)
    .gravity(0.02)
    .on("tick", tickc);

当绘制节点的函数被调用时,相关的节点/链接函数被添加到力中(因为数据根据滑块值发生变化)。

创建节点数据的代码如下:

nodes = splicedCounts.map(function(d, e) {
    var choice;
    var i = 0,
    r = d[1],
    d = { count: d[1],
          sentiment: d[2]/d[1],
          cluster: i,
          radius: radScale(r),
          name: d[0],
          index: e,
          x: Math.cos(i / m * 2 * Math.PI) * 200 + width / 2 + Math.random(),
          y: Math.sin(i / m * 2 * Math.PI) * 200 + height / 2 + Math.random()
    };
    if (!clusters[i] || (r > clusters[i].radius))
        clusters[i] = d;
    return d;
});

为了使这个问题相对简短,我用于绘制气泡图的代码是此示例的衍生代码:http: //bl.ocks.org/mbostock/7881887并且用于绘制节点图的代码同样通用(我如果它有助于解决我的问题,我很乐意提供此代码)。

这就是我的问题所在:

我发现了这个用于矩形之间碰撞检测的好例子,并将其合并到我的代码中。但是,由于我使用的是 SVG 文本并且字体大小在过渡时会发生变化,因此我选择根据文本长度和半径来估计文本大小/边界框大小。

单词图表的整个“刻度”功能如下。

function tickc(e) {
    node = nodeGroup.selectAll(".node");
    var nodeText = nodeGroup.selectAll(".node text");
    node.each(cluster(5 * e.alpha * e.alpha));
    var k = e.alpha;
    nodeText.each(function(a, i) {
        var compWidth = d3.select(this).attr("bWidth");
        var compHeight = d3.select(this).attr("bHeight");
        nodes.slice(i + 1).forEach(function(b) {
          // console.log(a);
          var lineWidthA = a["name"].length * a["radius"]/2.5;
          var lineHeightA = a["radius"]/0.9;

          var lineWidthB = b["name"].length * b["radius"]/2.5;
          var lineHeightB = b["radius"]/0.9;
          dx =  (a.x - b.x)
          dy =  (a.y - b.y)    
          adx = Math.abs(dx)
          ady = Math.abs(dy)
          mdx = (1 + 0.07) * (lineWidthA + lineWidthB)/2
          mdy = (1 + 0.07) * (lineHeightA + lineHeightB)/2
          if (adx < mdx  &&  ady < mdy) {          
            l = Math.sqrt(dx * dx + dy * dy)

            lx = (adx - mdx) / l * k
            ly = (ady - mdy) / l * k

            // choose the direction with less overlap
            if (lx > ly  &&  ly > 0)
                 lx = 0;
            else if (ly > lx  &&  lx > 0)
                 ly = 0;

            dx *= lx
            dy *= ly
            a.x -= dx
            a.y -= dy
            b.x += dx
            b.y += dy
          }
        });
  });
node.select("circle")
    .attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; });
node.select("text")
    .attr("x", function(d) { return d.x; })
    .attr("y", function(d) { return d.y; });
}
// Move d to be adjacent to the cluster node.
function cluster2(alpha) {
  return function(d) {
    var cluster = clusters[d.cluster];
    if (cluster === d) return;
    var x = d.x - cluster.x,
    y = d.y - cluster.y,
    l = Math.sqrt(x * x + y * y),
    r = (d["name"].length * d["radius"]) + (cluster["name"].length * cluster["radius"]);

  };
}

我不确定如何结束聚类功能以便适当地移动节点。我试图适应标准的集群功能,即

// Move d to be adjacent to the cluster node.
function cluster(alpha) {
  return function(d) {
    var cluster = clusters[d.cluster];
    if (cluster === d) return;
    var x = d.x - cluster.x,
        y = d.y - cluster.y,
        l = Math.sqrt(x * x + y * y),
        r = d.radius + cluster.radius;
    if (l != r) {
      l = (l - r) / l * alpha;
      d.x -= x *= l;
      d.y -= y *= l;
      cluster.x += x;
      cluster.y += y;
    }
  };
} 

更类似于前面提到的矩形集群力布局,但没有运气(恐怕我不再有我的确切尝试的副本)。

由于缺乏声誉,我担心我无法附上图片,但如果有帮助,我可以尝试找到一种方法来提供它们。词云的重叠问题很小(大多数词分解为相邻但不接触的位置),但如果可能的话,我希望它像气泡图一样完美地解决。我很确定这些问题源于 a.) 未完成的集群函数和 b.) 我在使用文本长度和半径来估计文本大小而不是正确的边界框坐标方面的技巧,但我不确定如何修复这些东西。

4

1 回答 1

1

我建议使用d3-cloud应该做很多你需要的包。如果没有,那么至少这是一个很好的起点https://github.com/jasondavies/d3-cloud

它的工作方式似乎是计算每个单词的边界,然后解决这些边界之间的冲突。你可以在这里看到

于 2017-07-19T10:46:05.677 回答