D3气泡图/包布局 - 如何使气泡从最大的气泡向最小的气泡辐射?

8


我正在使用与此D3画廊示例相同的代码(使用自己的数据):

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

我希望能够得到一个气泡图,其中圆圈按照从中心到最小的顺序排列。以下是我在Photoshop中创建的模拟图:

What I actually want



这是我使用示例(默认的圆形打包算法和默认排序)得到的结果:

Default packing

我尝试调整排序(包括尝试d3.ascending和d3.descending)。我能想到的最好方法只是通过一个常量来破坏排序,但仍然远远不符合我的要求:
//...
.sort( function(a, b) { return -1;} )
//...

Best I could get by tweaking sort



好的,那么有没有可能在不改变实际的D3包布局算法的情况下完成这个任务?如果不行,也许有人已经扩展或修改了包布局,并且可以告诉我在D3源中可以更改的5行代码。



提前感谢!


编辑:

如请求所示,这是我正在使用的代码。基本上与上面链接的示例相同,只有一些表面上的更改,如注释行所示:

var diameter = 960,
format = d3.format(",d"),
color = d3.scale.category20c();

var bubble = d3.layout.pack()
//  .sort(null)
//  .sort(d3.ascending)
//  .sort(d3.descending)
    .sort( function(a, b) { return  -1;} ) // basically a < b always
    .size([diameter, diameter])
    .padding(1.5);

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

d3.json("data.json", function(error, root) 
{
  var node = svg.selectAll(".node")
        .data(bubble.nodes(classes(root))
        .filter(function(d) { return !d.children; }))
        .enter().append("g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

  node.append("title")
      .text(function(d) { return d.className + ": " + format(d.value); });

  node.append("circle")
      .attr("r", function(d) { return d.r; })
      .style("fill", function(d) 
            { 
                // return color(d.packageName); 
                return color(d.value); // this gives a different color for every leaf node
            });

  node.append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
     // .text(function(d) { return d.className.substring(0, d.r / 3); });
});

// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root) 
{
  var classes = [];

  function recurse(name, node) {
    if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
    else classes.push({packageName: name, className: node.name, value: node.size});
  }

  recurse(null, root);
  return {children: classes};
}

d3.select(self.frameElement).style("height", diameter + "px");

还有我的 data.json 文件:

{
    "name": "Root",
    "children": [
        {
            "name": "Leaf",
            "children": null,
            "size": 2098629
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 104720
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 5430
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 102096
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 986974
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 59735
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 1902
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 120
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 870751
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 36672
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 274338
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 517693
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 145807
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 476178
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 11771
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 153
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 2138
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 8436
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 3572
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 120235
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 210945
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 56033
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 358704
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 295736
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 26087
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 33110
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 3828
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 1105544
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 98740
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 80723
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 5766
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 1453
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 10443176
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 14055
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 1890127
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 404575
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 272777
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 1269763
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 5081
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 3168510
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 717031
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 88418
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 762084
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 255055
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 535
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 81238
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 17075
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 5331
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 74834
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 110359
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 27333
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 143
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 12721
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 529
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 115684
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 3990850
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 6045060
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 2445766
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 479865
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 105743
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 183750
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 661
        },
        {
            "name": "Leaf",
            "children": null,
            "size": 11181
        }
    ],
    "size": 41103329
}

你需要一个自定义布局——pack布局总是将小圆圈放在大圆圈之间,以减少浪费的空间。哦,而且没有必要将所有内容都加粗。 - Lars Kotthoff
当然有道理,只是希望有人遇到过类似的用例并已经找到了解决方案。是的,不需要所有的粗体;这主要是一个复制和粘贴的错误。现在只有图像标题是粗体 :) - SoldierOfFortran
@SoldierOfFortran,你能否附上你的示例数据?代码(至少是关键部分)也是可取的。 - VividD
@VividD - 完成。希望对您有所帮助。 - SoldierOfFortran
1个回答

16

你所需要做的就是指定:

.sort(function(a, b) {
    return -(a.value - b.value);
})

这与指定 .sort(d3.ascending).sort(d3.descending) 不同,因为 d3.ascendingd3.descending 都被定义为

function(a, b) {
  return a < b ? -1 : a > b ? 1 : 0;
}

function(a, b) {
  return b < a ? -1 : b > a ? 1 : 0;
}

相应地,打包布局受到其对数据点差异的“不敏感性”的影响。

这是我的测试示例:(使用您的数据)jsfiddle

enter image description here


实验中,我还应用了以下排序函数:(它是一种混合类型)

.sort( function(a, b) {
    var threshold = 10000000;
    if ((a.value > threshold) && (b.value > threshold)) {
        return -(a.value - b.value);
    } else {
        return -1;
    }
})

对于阈值分别为10000000、3000000、1000000、300000、100000、30000的值,我得到了:jsfiddle

图片描述

图片描述

图片描述

图片描述

图片描述

图片描述


你好 @VividD!这些气泡之间是否可以获得间隙? - Sandesh Sapkota

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接