【问题标题】:Circle packing matrix with consistent scale具有一致比例的圆形填充矩阵
【发布时间】:2020-04-11 14:41:32
【问题描述】:

将 for 循环与 d3 视觉效果相结合时,我得到了不同的结果;在这种情况下,拥有一个圆形包矩阵似乎是最直接的解决方案。但是,一个问题是,如果我以这种方式创建视觉效果,输出可能会有点误导。在下面的 sn-p 中,您会注意到第三个圆包 (152) 中的最大圆看起来与第一个圆包 (200) 中的最大圆一样大。所以在目前的形式中,圆形包只反映了比例,并没有描绘出绝对大小的变化。

var margins = {top:20, bottom:300, left:30, right:100};

var height = 600;
var width = 1080;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);

var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");

  var data = [
[
{'id':'1Q19'},
{'id':'pooled','parentId':'1Q19','size':29.5},
{'id':'spv','parentId':'1Q19', 'size':11},
{'id':'single','parentId':'1Q19', 'size':200}
  ],

  [
  {'id':'2Q19'},
  {'id':'pooled','parentId':'2Q19','size':31},
  {'id':'spv','parentId':'2Q19', 'size':15},
  {'id':'single','parentId':'2Q19', 'size':171}
],

[
{'id':'3Q19'},
{'id':'pooled','parentId':'3Q19','size':28},
{'id':'spv','parentId':'3Q19', 'size':12},
{'id':'single','parentId':'3Q19', 'size':152}
],

[
{'id':'4Q19'},
{'id':'pooled','parentId':'4Q19','size':25},
{'id':'spv','parentId':'4Q19', 'size':214},
{'id':'single','parentId':'4Q19', 'size':101}
],
];

var colorMap = {
  '1Q19':"#e7eef8",
  '2Q19':"#e7eef8",
  '3Q19':"#e7eef8",
  '4Q19':"#e7eef8",
  'pooled':"#f6d18b",
  'spv':"#366092",
  'single':"#95b3d7"
};

var strokeMap = {
  "pooled":"#000",
  "single":"#000",
  "spv":"#fff"
};

for (var j=0; j <(data.length); j++) {

  var vData = d3.stratify()(data[j]);

  var vLayout = d3.pack().size([250, 250]);

  var vRoot = d3.hierarchy(vData).sum(function (d) { return d.data.size; });
  var vNodes = vRoot.descendants();
  vLayout(vRoot);

  var thisClass = "circ"+String(j);

  var vSlices = graphGroup.selectAll('.'+thisClass).data(vNodes).attr('class',thisClass).enter().append('g');

  //console.log(vNodes)

  vSlices.append('circle')
  .attr('cx', function(d, i) {
      return d.x+(j*300)
  })
  .attr('cy', function (d) { return d.y; })
  .attr('r', function (d) { return d.r; })
  .style('fill', function(d) { return colorMap[d.data.id]});

  vSlices.append('text')
  .attr('x', function(d,i) {return d.x+(j*300)})
  .attr('y', function(d) {return d.y+5})
  .attr('text-anchor','middle')
  .style('fill', function(d) {return strokeMap[d.data.id]})
  .text(function(d) {return d.data.data.size ? d.data.data.size : null});

}
&lt;script src="https://d3js.org/d3.v5.min.js"&gt;&lt;/script&gt;

问题

如何为圆形包矩阵中的每个圆形包建立基线/统一比例?我希望背景/整体父圈大小相同,但子圈在打包过程中要考虑绝对值。

注意:我很满意圈包里有更多的空白空间;也许在某些情况下,直径可能不会完全跨越父圆。只要圆圈相切,整体审美主题就应该得到贯彻。

【问题讨论】:

    标签: javascript d3.js svg data-visualization circle-pack


    【解决方案1】:

    您使用循环在 D3 代码中创建元素的事实是非常有问题的,这是真的……但是,这不是问题所在。让我们看看你说的:

    我希望背景/整体父圆的大小相同,但子圆在打包过程中考虑绝对值 [...] 我对圆包中有更多空白空间感到满意。

    好吧,不幸的是,这不是圆形包装的工作方式。您现在拥有的是 正确 数据可视化:叶子会有不同的大小,即使它们具有相同的值,这取决于其他叶子的值。圆形包装是一个动态过程/算法。

    话虽如此,我的建议是:保持原样(但修复那个繁琐的循环)。

    但是,即使我(从数据可视化角度)不同意您的请求,这里有一个解决方案。设置平方根比例:

    var radiusScale = d3.scaleSqrt()
      .domain([0,250])
      .range([0,125]);
    

    并将size 值传递给pack.radius

    var vLayout = d3.pack().size([250, 250])
        .radius(function(d){
            return radiusScale(d.data.data.size)
        });
    

    结果如下:

    var margins = {top:20, bottom:300, left:30, right:100};
    
    var height = 600;
    var width = 1200;
    
    var totalWidth = width+margins.left+margins.right;
    var totalHeight = height+margins.top+margins.bottom;
    
    var svg = d3.select('body')
    .append('svg')
    .attr('width', totalWidth)
    .attr('height', totalHeight);
    
    var graphGroup = svg.append('g')
    .attr('transform', "translate("+margins.left+","+margins.top+")");
    
    const radiusScale = d3.scaleSqrt()
      .domain([0,250])
      .range([0,125]);
    
      var data = [
    [
    {'id':'1Q19'},
    {'id':'pooled','parentId':'1Q19','size':29.5},
    {'id':'spv','parentId':'1Q19', 'size':11},
    {'id':'single','parentId':'1Q19', 'size':200}
      ],
    
      [
      {'id':'2Q19'},
      {'id':'pooled','parentId':'2Q19','size':31},
      {'id':'spv','parentId':'2Q19', 'size':15},
      {'id':'single','parentId':'2Q19', 'size':171}
    ],
    
    [
    {'id':'3Q19'},
    {'id':'pooled','parentId':'3Q19','size':28},
    {'id':'spv','parentId':'3Q19', 'size':12},
    {'id':'single','parentId':'3Q19', 'size':152}
    ],
    
    [
    {'id':'4Q19'},
    {'id':'pooled','parentId':'4Q19','size':25},
    {'id':'spv','parentId':'4Q19', 'size':214},
    {'id':'single','parentId':'4Q19', 'size':101}
    ],
    ];
    
    var colorMap = {
      '1Q19':"#e7eef8",
      '2Q19':"#e7eef8",
      '3Q19':"#e7eef8",
      '4Q19':"#e7eef8",
      'pooled':"#f6d18b",
      'spv':"#366092",
      'single':"#95b3d7"
    };
    
    var strokeMap = {
      "pooled":"#000",
      "single":"#000",
      "spv":"#fff"
    };
    
    for (var j=0; j <(data.length); j++) {
    
      var vData = d3.stratify()(data[j]);
    
      var vLayout = d3.pack().size([250, 250])
      .radius(function(d){
      return radiusScale(d.data.data.size)
      });
    
      var vRoot = d3.hierarchy(vData).sum(function (d) { return d.data.size; });
      var vNodes = vRoot.descendants();
      vLayout(vRoot);
    
      var thisClass = "circ"+String(j);
    
      var vSlices = graphGroup.selectAll('.'+thisClass).data(vNodes).attr('class',thisClass).enter().append('g');
    
      //console.log(vNodes)
    
      vSlices.append('circle')
      .attr('cx', function(d, i) {
          return d.x+(j*(j === 3 ? 320 : 310))
      })
      .attr('cy', function (d) { return d.y; })
      .attr('r', function (d) { return d.r; })
      .style('fill', function(d) { return colorMap[d.data.id]});
    
      vSlices.append('text')
      .attr('x', function(d,i) {return d.x+(j*(j === 3 ? 320 : 310))})
      .attr('y', function(d) {return d.y+5})
      .attr('text-anchor','middle')
      .style('fill', function(d) {return strokeMap[d.data.id]})
      .text(function(d) {return d.data.data.size ? d.data.data.size : null});
    
    }
    &lt;script src="https://d3js.org/d3.v5.min.js"&gt;&lt;/script&gt;

    注意,在最后一包中,整个圆圈的大小不一样(更大)。考虑到包装逻辑,相同的大小是不可能的。

    【讨论】:

      猜你喜欢
      • 2020-01-22
      • 2019-10-11
      • 1970-01-01
      • 1970-01-01
      • 2015-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-29
      相关资源
      最近更新 更多