[英]Hierarchical JSON into flare.json format for use in Bilevel Partition
我有一个CSV文件,我想将其转换为可与Bilevel分区一起使用的分层JSON。
Bilevel分区希望其JSON数据的格式与此flare.json文件类似。 基本上,叶节点具有name
和size
属性,而介于两者之间的所有内容都具有name
和children
属性。
这是我的尝试将CSV文件转换为Hierarchical 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)
}
上面的代码可以为数据提供所需的层次结构, 但是标签是错误的。 类似于name
, children
和size
它仅给我key
和values
,一直到叶节点,类似于此文件 。
因此,我四处阅读,并在SO上发现了这个问题 ,这与Bilevel分区无关,但我认为将应用相同的原理,因为两种布局都需要分层JSON数据。
所以我开始做同样的事情,但是我只是无法使它工作。 首先,在我的代码中,我没有SO问题中提到的size()
函数。 这是我的完整代码,几乎是从官方示例中复制的:
码
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};
}
以上所有内容都在浏览器中为我提供了这一点:
您只需将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()
对象以匹配新对象,但是您至少需要更改原始对象的结构,以便叶节点不会在同一对象中存储值字段名称为孩子。 上面的解决方案可能是使事情快速运行的最简单方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.