【问题标题】:Hierarchical JSON into flare.json format for use in Bilevel Partition将分层 JSON 转换为flare.json 格式,用于双级分区
【发布时间】:2014-11-11 13:46:43
【问题描述】:

我有一个 CSV,我想将其转换为分层 JSON,以便与 Bilevel Partition 一起使用。

Bilevel 分区希望其 JSON 数据的格式类似于 flare.json file。基本上,叶节点具有namesize 属性,而介于两者之间的所有内容都具有namechildren 属性。

这是我尝试将 CSV 文件转换为分层 JSON 的代码。

代码

var root = { "key": "Leeds CCGs", "values": d3.nest()
    .key(function(d) { return d.ccgname; })
    .key(function(d) { return d.practicename; })
    .key(function(d) { return d.diagnosisname; })
    .rollup(function(leaves) { return d3.sum(leaves, function(d) { return d.numpatientswithdiagnosis; }) })
    .entries(data)
}

上面的代码可以为数据提供所需的层次结构,但标签是错误的。而不是namechildrensize它给了我key并且只有values,一直到叶子节点,类似于this file

所以我四处阅读,发现 SO 上的 this questionBilevel Partition 无关,但我认为同样的原则也适用,因为两种布局都需要分层 JSON 数据。

所以我开始做同样的事情,但我无法让它发挥作用。首先,在我的代码中,我没有 SO 问题中提到的 size() 函数。这是我的整个代码,几乎是从official example复制而来的:

代码

d3.csv('data/partition.csv', function (data) {

  var root = { "key": "Leeds CCGs", "values": d3.nest()
    .key(function(d) { return d.ccgname; })
    .key(function(d) { return d.practicename; })
    .key(function(d) { return d.diagnosisname; })
    .rollup(function(leaves) { return d3.sum(leaves, function(d) { return d.numpatientswithdiagnosis; }) })
    .entries(data)
  }

  // Compute the initial layout on the entire tree to sum sizes.
  // Also compute the full name and fill color for each node,
  // and stash the children so they can be restored as we descend.
  partition
    .value(function(d) { return d.values; })
    .nodes(root)
    .forEach(function(d) {
      d._children = d.values;
      d.sum       = d.value;
      d.key       = key(d);
      d.fill      = fill(d);
    });

  // Now redefine the value function to use the previously-computed sum.
  partition.children(function(d, depth) {
    return depth < 2 ? d._children : null;
  }).value(function(d) {
    return d.sum;
  });

  var center = svg.append("circle")
    .attr("r", radius / 4)
    .style('fill-opacity', '.2')
    .style('cursor', 'pointer')
    .on("click", zoomOut);

  center.append("title")
    .text("zoom out");

  var path = svg.selectAll("path")
    .data(partition.nodes(root).slice(1))
  .enter().append("path")
    .attr("d", arc)
    .style("fill", function(d) { return d.fill; })
    .style('cursor', 'help')
    .each(function(d) { this._current = updateArc(d); })
    .on("mouseover", update_legend)
    .on("mouseout", remove_legend)
    .on("click", zoomIn);

  function zoomIn(p) {
    if (p.depth > 1) p = p.parent;
    if (!p.children) return;
    zoom(p, p);
  }

  function zoomOut(p) {
    if (!p.parent) return;
    zoom(p.parent, p);
  }

  // Zoom to the specified new root.
  function zoom(root, p) {
    if (document.documentElement.__transition__) return;

    // Rescale outside angles to match the new layout.
    var enterArc,
        exitArc,
        outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]);

    function insideArc(d) {
      return p.key > d.key
          ? {depth: d.depth - 1, x: 0, dx: 0} : p.key < d.key
          ? {depth: d.depth - 1, x: 2 * Math.PI, dx: 0}
          : {depth: 0, x: 0, dx: 2 * Math.PI};
    }

    function outsideArc(d) {
      return {depth: d.depth + 1, x: outsideAngle(d.x), dx: outsideAngle(d.x + d.dx) - outsideAngle(d.x)};
    }

    center.datum(root);

    // When zooming in, arcs enter from the outside and exit to the inside.
    // Entering outside arcs start from the old layout.
    if (root === p) enterArc = outsideArc, exitArc = insideArc, outsideAngle.range([p.x, p.x + p.dx]);

    path = path.data(partition.nodes(root).slice(1), function(d) { return d.key; });

    // When zooming out, arcs enter from the inside and exit to the outside.
    // Exiting outside arcs transition to the new layout.
    if (root !== p) enterArc = insideArc, exitArc = outsideArc, outsideAngle.range([p.x, p.x + p.dx]);

    d3.transition().duration(d3.event.altKey ? 7500 : 750).each(function() {
      path.exit().transition()
          .style("fill-opacity", function(d) { return d.depth === 1 + (root === p) ? 1 : 0; })
          .attrTween("d", function(d) { return arcTween.call(this, exitArc(d)); })
          .remove();

      path.enter().append("path")
          .style("fill-opacity", function(d) { return d.depth === 2 - (root === p) ? 1 : 0; })
          .style("fill", function(d) { return d.fill; })
          .style('cursor', 'help')
          .on("mouseover",update_legend)
          .on("mouseout",remove_legend)
          .on("click", zoomIn)
          .each(function(d) { this._current = enterArc(d); });

      path.transition()
          .style("fill-opacity", 1)
          .attrTween("d", function(d) { return arcTween.call(this, updateArc(d)); });
    });
  }
});

function key(d) {
  var k = [];
  var p = d;
  while (p.depth) k.push(p.key), p = p.parent;
  return k.reverse().join(".");
}

function fill(d) {
  var p = d;
  while (p.depth > 1) p = p.parent;
  var c = d3.lab(hue(p.key));
  c.l = luminance(d.sum);
  return c;
}

function arcTween(b) {
  var i = d3.interpolate(this._current, b);
  this._current = i(0);
  return function(t) {
    return arc(i(t));
  };
}

function updateArc(d) {
  return {depth: d.depth, x: d.x, dx: d.dx};
}

以上所有内容都在我的浏览器中为我提供了这个:

【问题讨论】:

  • 你能发布你的源数据集吗?

标签: javascript json csv d3.js hierarchy


【解决方案1】:

您应该能够通过简单地将 d3.nest() 的分层输出转换为与flare.json 数据集相同的格式来完全重用其余代码,如下所示:

(应该在root的定义之后立即运行)

  //rename object keys generated from d3.nest() to match flare.json format
  renameStuff(root);
  function renameStuff(d) {
    d.name = d.key; delete d.key;
    if (typeof d.values === "number") d.size = d.values;
    else d.values.forEach(renameStuff), d.children = d.values;
    delete d.values;
  }

您也可以将访问器函数更改为d3.layout.partition() 对象以匹配新对象,但您至少需要更改原始对象的结构,以便叶节点不会将值存储在同一字段中以孩子的名字命名。上面的解决方案可能是让事情快速运行的最简单方法。

【讨论】:

  • 谢谢@Josh。我希望能够理解d3.js 以及它如何剖析其数据以用于双层分区。我不想总是重组我的数据以完全匹配示例的方式。我想了解.children() 函数以及如何让它工作。
  • 我认为最好的参考是文档:github.com/mbostock/d3/wiki/Partition-Layout#children
  • 我在上面尝试过,但没有让我去哪里:(你理解它(文档)更好吗?
  • 顺便说一句,Josh,您的代码会使浏览器崩溃!没有它,chrome 可以正常加载页面,有了它,chrome 就会崩溃。
  • 我会尝试以不同的方式描述 .children() 访问器函数,但我不确定您到底在理解什么方面有困难
猜你喜欢
  • 2013-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
  • 2019-05-21
相关资源
最近更新 更多