d3.js 中的堆积圆散点图?

Scatterplot of packed circles in d3.js?

有没有办法创建稀疏散点图可视化,其中每个 "point" 是一个 one-level packed circle?我一直在尝试用 d3 来做这个,但我不知道是否有可能在同一个 svg 中制作多个不同的包布局......(或者我是否应该这样做)。任何帮助将不胜感激!

我希望它最终看起来像下面的草图:

这是您要实现的目标的示例:

http://bl.ocks.org/donaldh/2920551

只是把它放在一起。它需要 d3 耀斑数据并将 scatter-plot 输出第一级 children 和它们的 children.

数据结构:

var flareData = {
  "name": "root",
  "children": [{
    "name": "pointOne",
    "scatX": 10,
    "scatY": 20,
    "children": [{
      "name": "pointOneA",
      "children": [{
        "name": "A",
        "size": 40
      }, {
        "name": "B",
        "size": 50
      }]
    }, {
      "name": "pointOneB",
      "children": [{
        "name": "C",
        "size": 10
      }, {
        "name": "D",
        "size": 23
      }]
    }]
  }, {
    "name": "pointTwo",
...

创建绘图和轴的典型 d3 代码:

var
 WIDTH = 600,
  HEIGHT = 600,
  DIAMETER = 200;

var vis = d3.select('body')
  .append('svg')
  .attr('width', WIDTH)
  .attr('height', HEIGHT);

var MARGINS = {
  top: 20,
  right: 20,
  bottom: 20,
  left: 50
},
  xRange = d3.scale
    .linear()
    .range([MARGINS.left, WIDTH - MARGINS.right])
    .domain([d3.min(flareData.children, function(d) {
      return d.scatX;
    }) - 10, d3.max(flareData.children, function(d) {
      return d.scatX;
    }) + 10]),
  yRange = d3.scale
    .linear()
    .range([HEIGHT - MARGINS.top, MARGINS.bottom])
    .domain([d3.min(flareData.children, function(d) {
      return d.scatY;
    }) - 10, d3.max(flareData.children, function(d) {
      return d.scatY;
    }) + 10]),
  xAxis = d3.svg.axis()
    .scale(xRange)
    .tickSize(5)
    .tickSubdivide(true),
  yAxis = d3.svg.axis()
    .scale(yRange)
    .tickSize(5)
    .orient('left')
    .tickSubdivide(true);

vis.append('svg:g')
  .attr('class', 'x axis')
  .attr('transform', 'translate(0,' + (HEIGHT - MARGINS.bottom) + ')')
  .call(xAxis);

vis.append('svg:g')
  .attr('class', 'y axis')
  .attr('transform', 'translate(' + (MARGINS.left) + ',0)')
  .call(yAxis);

让打包布局的滥用开始:

// normal packed layout
var pack = d3.layout.pack()
  .size([DIAMETER - 4, DIAMETER - 4])
  .value(function(d) {
    return d.size;
  });

// classify each level
var node = vis.datum(flareData).selectAll(".node")
  .data(pack.nodes)
  .enter().append("g")
  .attr("class", function(d) {        
    // root level
    if (!d.parent) {
      return "node rootNode";
    // first level children, these are our scatter points
    } else if (d.children && !d.parent.parent) {
      return "node pointNode";
    // an intermediate circle
    } else if (d.children) {
      return "node innerNode";
    // last level packing
    } else {
      return "node innerNode packedNode";
    }
  });

// use calculated radius
node.append("circle")
  .attr("r", function(d) {
    return d.r;
  });

// we don't care about root circle, move off page
node.filter(".rootNode")
  .attr("transform", "translate(" + -100 + "," + -100 + ")");

// this is our scatter point
node.filter(".pointNode")
  .attr("transform", function(d) {
    return "translate(" + xRange(d.scatX) + "," + yRange(d.scatY) + ")";
  });

// any circle in a scatter point
node.filter(".innerNode")
  .attr("transform", function(d) {
    var iter = d;
    while(!iter.scatX){
      iter = iter.parent;
    }
    // diff from scatter point...
    var difX = iter.x - d.x,
        difY = iter.y - d.y;
    return "translate(" + (xRange(iter.scatX) + difX) + "," + (yRange(iter.scatY) + difY) + ")";
  })

// finally label our last level
node.filter(".packedNode")
  .append("text")
  .attr("dy", ".3em")
  .style("text-anchor", "middle")
  .text(function(d) {
    return d.name;
  });

例子here.

产生: