来自 CSV 的 d3 可缩放树状图

d3 Zoomable Treemap from CSV

本文关键字:缩放 CSV d3 来自      更新时间:2023-09-26

我是使用D3的新手,我发现它非常谦卑。

我的目标是从CSV文件制作树状图。 我想使用 CSV 格式,因为我将在电子表格中使用值,并且以这种方式保存文件很容易。

我正在尝试以分层格式存储数据,如下所示(hier.csv):

parent,child,value
Homer Simpson,Bart,20
Homer Simpson,Lisa,14
Homer Simpson,Maggie,6
Peter Griffin,Chris,19
Peter Griffin,Meg,12
Peter Griffin,Stewie,9

我正在使用这个可缩放树状图示例。

我希望树可以任意深入,即如果 Bart 在我的示例中有孩子,并根据名称相应地积累父子关系。

我在桑基图中找到了一个很好的例子,但我还没有找到可缩放树状图的等效项。

有没有办法在 Bostock 示例的第 124 行和第 126 行之间插入一些代码,以使我的数据正确格式化为可缩放树状图?(我可以更改 CSV 的布局,但希望保留 CSV 格式)。 类似于这种方法使用 nest() ,但显然这不起作用:

d3.csv("./hier.csv", function(hier) {
  var root = { 
    "name": "myrootnode",
    "children": d3.nest()
        .key(function (d) { return d.parent; })
        .key(function (d) { return d.child; })
        .entries(hier)
  };
  initialize(root);
  accumulate(root);
  layout(root);
  display(root);
  //etc...

我看到了一些例子和StackOverflow问题,这些问题解决了这个问题的点点滴滴,但无法端到端地将它们放在一起。 我一直在研究和黑客攻击,但无济于事。 我欢迎一些帮助。 谢谢!

在这里摆弄

http://jsfiddle.net/KXuWD/

小提琴笔记:

  • 我正在评论显示的 #90 行附近寻求帮助
  • 我设置了一个内联变量来保存 flare.json 的精简副本
  • 我计划在现实生活中将数据保存在一个单独的文件中,但对于 JSFiddle,它必须内联拉取;当然,如果我能弄清楚主要逻辑,这将很容易适应回单独的数据文件。
  • 此示例似乎不适用于 D3 版本 3.0.4,这是 JSFiddle 的当前内置版本。 我为示例导入了 v2.x,因为这是适用于 Bostock 的示例。 这是一个潜在的单独问题...

更新

我克服了部分问题。 我认为nest()是必要的,但我没有正确更新我的访问器。 以下是对大多数有效内容的一个非常草率的看法:http://bl.ocks.org/maw246/7303963

我的例子和博斯托克的例子之间的主要区别:

  • CSV 在加载后使用 d3.nest() 进行嵌套。 这会将其强制转换为分层 JSON 对象格式
  • 许多(如果不是全部)对"子项"的引用已被"值"替换,因为d3.nest()使用keyvalues属性而不是树状图的预期namechildren属性生成树。 用于块大小调整的 value 属性保持不变。

剩余问题

  • 它不会任意深入。 我正在考虑一种重新组织数据以更好地利用d3.nest()功能的方法,但尚未尝试。
  • 孩子的名字出现在undefined. 我确定我只是忽略了一些简单的东西,但我主要关心的是让核心功能正常工作,所以我会在一分钟的时候稍微破解一下这篇文章。

注意:我仍在寻求有关干净和惯用方法的帮助,包括有关如何最好地组织 CSV 以分层嵌套到任意深度的建议!

我在调查树状图的使用时也遇到了类似的挫折。来自服务器的数据是平面表格样式的数据,例如:

var myData = [{ "thedad": "Homer Simpson", "name": "Bart", "value": 20 },
{ "thedad": "Homer Simpson", "name": "Lisa", "value": 14 },
{ "thedad": "Homer Simpson", "name": "Maggie", "value": 6 },
{ "thedad": "Peter Griffin", "name": "Chris", "value": 19 },
{ "thedad": "Peter Griffin", "name": "Meg", "value": 12 },
{ "thedad": "Peter Griffin", "name": "Stewie", "value": 16 },
{ "thedad": "Bart", "name": "Bart Junior A", "value": 77 },
{ "thedad": "Bart", "name": "Bart Junior B", "value": 32 }];

然而,d3 树状图需要它处理的 javascript 对象采用分层格式。经过繁琐的搜索,我在d3 google群组中看到了underscore.nest的提及。https://github.com/iros/underscore.nest

"Underscore.Nest 是 [underscore js 库] 的扩展 将平面数据转换为嵌套树结构"。

使用此库(同样,依赖于下划线.js)意味着您没有诉诸 d3.nest 并担心它产生的键/值数据格式。

工作示例
下面是树状图采用对象平面列表的工作示例已由 Underscore.nest 转换为 D3 树状图所需的分层格式。(没有 underscore.nest 的原始树状图来自 mbostock 的示例:http://bost.ocks.org/mike/treemap/)

http://jsbin.com/aGIvOnEH/3

root = _.nest( myData, "thedad");
root.name = "TV Dads";

希望这是有用的。

未经测试,可能不是很惯用(javascript不是我的菜),但可能会让你走上正确的轨道。我使用underscore.js是因为我很懒,如果你关心,请使用本机循环来做。

d3.csv(csv_url, function(error, data) {
    var root = {
        name: "Everybody",
        value: 0,
        children: []
    };
    var parents = {};
    _.each(data, function(row) {
        var child = {
            name: row.child,
            value: row.value,
            children: []
        };
        if(parents[row.parent]) {  // parent seen already
            parents[row.parent]['children'].push(child);
            parents[row.parent]['value'] += row.value;
        } else {                   // new parent
            parents[row.parent] = {  
                name: row.parent,
                children: [child],
                value: row.value
            }
        }
        root.value += row.value;
    });
    root.children = _.values(parents);
    ...

从 mg1075 的答案中,我看到myData是自引用数据,这意味着一行中的子项成为另一行中的父项,并拥有自己的子项。这导致了一个可变深度的层次结构,并且无法仅通过查看一行来计算深度;程序需要遍历整个事情并建立关系。 d3.nest()对此不起作用..它需要整个祖先一直到每一行本身的顶部。

我仍然需要探索underscore.js,但是mg1075的jsbin工作示例表明它实际上并没有解决问题:巴特在树状图中排在荷马辛普森旁边,尽管是荷马辛普森的孩子,但他的孩子在那里; 他也在荷马辛普森手下(让他成为自己的叔叔:P),但在那里没有任何孩子(所以巴特的克隆叔叔偷了他的孩子, 可怜的荷马辛普森没有孙子孙女)。所以基本上孙子是不被承认的。

我发布了一个问题,然后使用一个名为DataStructures.Tree的库在这里找到了这种可变深度分层数据的可视化解决方案。我认为这可能会有所帮助:

https://stackoverflow.com/a/27756744/4355695