d3-hierarchy

许多数据集本质上是分层的。想想geographic entities(地理实体),如census blocks(人口普查街区),census tracts(人口普查区),counties(县)和states(州);企业和政府的指挥结构;文件系统和软件包。即使是非等级数据也可以根据经验排列成一个层级结构,就像使用k-means clustering(k-均值聚类)phylogenetic trees(系统发生树)一样。

此模块实现了几种用于可视化分层数据的流行技术:

Node-link diagrams(节点链接图)通过为节点和链接使用离散标记来显示拓扑结构,例如每个节点的圆和连接每个父节点和子节点的线。“tidy(整齐)”树是欣然的简化,而dendrogram(系统树图)将所有叶节点放在同一层级。(这些都有极坐标和笛卡尔形式。)缩进树对于交互式浏览很有用。

Adjacency diagrams(邻接图)通过节点的相对位置显示拓扑结构。它们还可以在每个节点的区域中编码定量维度,例如显示收入或文件大小。“icicle(冰柱)”图使用矩形,而“sunburst(旭日)”使用环形节段。

Enclosure diagrams(机箱图)也使用区域编码,但通过包含来显示拓扑结构。一个treemap(树形图)通过递归将区域划分为矩形。Circle-packing紧紧嵌套圆;这不像树形图那样节省空间,但可能更容易显示拓扑结构。

良好的层次可视化有利于快速多尺度推断:个体元素的微观观察和大群体的宏观观察。

Installing

如果你使用npm,请键入npm install d3-hierarchy。否则,请下载最新版本。你也可以直接从d3js.org加载,作为standalone library(独立库)或D3 4.0的一部分来使用。支持AMD,CommonJS和vanilla环境。在vanilla环境下,会输出一个全局的d3

<script src="https://d3js.org/d3-hierarchy.v1.min.js"></script>
<script>

var treemap = d3.treemap();

</script>

API Reference

Hierarchy

在计算hierarchical layout(分层布局)之前,你需要一个根节点。如果你的数据已经是分层格式,例如JSON,则可以直接将其传入 d3.hierarchy ;否则,可以使用d3.stratify将表格数据重新排列为层次结构,如逗号分隔值(CSV)。

d3.hierarchy(data[, children])

从指定的分层data构造一个根节点。指定的data必须是代表根节点的对象。例如:

{
  "name": "Eve",
  "children": [
    {
      "name": "Cain"
    },
    {
      "name": "Seth",
      "children": [
        {
          "name": "Enos"
        },
        {
          "name": "Noam"
        }
      ]
    },
    {
      "name": "Abel"
    },
    {
      "name": "Awan",
      "children": [
        {
          "name": "Enoch"
        }
      ]
    },
    {
      "name": "Azura"
    }
  ]
}

为每个数据调用指定的children _accessor函数,从根_data开始,并且必须返回表示子项的数据数组,如果当前数据没有子项,则返回null。如果不指定children,则默认为:

function children(d) {
  return d.children;
}

返回的节点和每个后代具有以下属性:

  • node.data - 与构造函数指定的关联数据。
  • node.depth - 对于根节点为0,对于每个后代,增加1。
  • node.height - 叶节点为0,并且与内部节​​点的任何后代叶节点的距离最大。
  • node.parent - 父节点,对于根节点为null。
  • node.children - 子节点数组(如果有的话);对于叶节点为undefined。
  • node.value - 节点及其后代的总和值;可选的,另请参阅node.sumnode.count之间。

此方法也可用于测试节点是否为instanceof d3.hierarchy并扩展节点原型。

node.ancestors()

返回祖先节点数组,从此节点开始,然后是每个父节点,直到根节点。

node.descendants()

返回后代节点数组,从此节点开始,然后是按拓扑顺序的每个子节点。

node.leaves()

以遍历顺序返回叶节点数组;叶节点是没有子节点的节点。

node.path(target)

返回从此node到指定target节点的层次结构的最短路径。路径从此node开始,向上到此节点和target节点的最小公共祖先,然后向下到target节点。这对hierarchical edge bundling(分层边绑定)特别有用。

返回此node的链接数组,其中每个link都是定义了source(源)和target(目标)属性的对象。每个链接的来源是父节点,目标是一个子节点。

node.sum(value)

后序遍历中对此node和每个后代的指定value函数求值,并返回此node。每个节点的node.value属性设置为由指定函数返回的数值加上所有后代的组合值。该函数接收传入的节点数据,并且必须返回一个非负数。value accessor用于对节点和每一个后代求值,包括内部节点;如果你只希望叶节点具有内部值,则对于有子节点的任何节点返回0。例如,作为node.count的替代方法:

root.sum(function(d) { return d.value ? 1 : 0; });

你必须在调用需要node.value的分层布局前调用node.sum或node.count,如d3.treemap。由于API支持链式调用,因此可以在计算布局之前调用node.sum和node.sort,然后生成一个包含所有后代节点的数组,如下所示:

var treemap = d3.treemap()
    .size([width, height])
    .padding(2);

var nodes = treemap(root
    .sum(function(d) { return d.value; })
    .sort(function(a, b) { return b.height - a.height || b.value - a.value; }))
  .descendants();

此示例假定节点数据具有值字段。

node.count()

计算此node下叶节点的数量并将其分配给node.value,并且类似地针对node的每个后代。如果此node是一个叶节点,则它的数量为1。返回此node。另请参阅node.sum

node.sort(compare)

前序遍历中使用指定的compare函数对此node的子节点(如果有)以及此节点的每个子节点的子节点进行排序,并返回此node。指定的函数将传入两个节点ab进行比较。如果a应该在b之前,该函数必须返回一个小于0的值;如果b应该在a之前,则该函数必须返回大于0的值;否则,不指定ab的相对顺序。有关更多信息,另请参阅array .sort

node.sum不同,向compare函数传入的是两个节点而不是两个节点的数据。例如,如果数据具有值属性,则通过递减节点及其所有子节点的降序聚合值对节点进行排序,这也是circle-packing的推荐方法:

root
    .sum(function(d) { return d.value; })
    .sort(function(a, b) { return b.value - a.value; });

同样,通过递减高度(与任何后代叶子的最大距离)然后递减值对节点进行排序,这也是treemapicicle的推荐方法:

root
    .sum(function(d) { return d.value; })
    .sort(function(a, b) { return b.height - a.height || b.value - a.value; });

通过递减高度(与任何后代叶子的最大距离)然后递减id对节点进行排序,这也是treedendrogram的推荐方法:

root
    .sum(function(d) { return d.value; })
    .sort(function(a, b) { return b.height - a.height || a.id.localeCompare(b.id); });

如果你希望新排序顺序影响布局,则必须在调用分层布局之前调用node.sort;另请参阅node.sum查看示例。

node.each(function)

广度优先中为node及其每个后代调用指定的function,以便只有在深度较小的所有节点都已访问的情况下才会访问给定node,以及具有相同深度的所有先前节点。向指定的函数传入当前node

node.eachAfter(function)

后序遍历中为node及其每个后代调用的指定function,以便只有在其所有后代已被访问后才访问给定node。向指定的函数传入当前node

node.eachBefore(function)

前序遍历中为node及其每个后代调用指定的function,以便只有在访问完所有祖先节点之后才访问给定node。向指定的函数传入当前node

node.copy()

返回从此node开始的子树的深拷贝。(但是,返回的深拷贝共享相同的数据。)返回的节点是新树的根节点;返回节点的父节点始终为null,并且其深度始终为0。

Stratify

考虑下面的关系表:

Name Parent
Eve
Cain Eve
Seth Eve
Enos Seth
Noam Seth
Abel Eve
Awan Eve
Enoch Awan
Azura Eve

这些名称非常唯一,因此我们可以毫不犹豫地将该层次表示为CSV文件:

name,parent
Eve,
Cain,Eve
Seth,Eve
Enos,Seth
Noam,Seth
Abel,Eve
Awan,Eve
Enoch,Awan
Azura,Eve

使用d3.csvParse解析CSV:

var table = d3.csvParse(text);

这将返回:

[
  {"name": "Eve",   "parent": ""},
  {"name": "Cain",  "parent": "Eve"},
  {"name": "Seth",  "parent": "Eve"},
  {"name": "Enos",  "parent": "Seth"},
  {"name": "Noam",  "parent": "Seth"},
  {"name": "Abel",  "parent": "Eve"},
  {"name": "Awan",  "parent": "Eve"},
  {"name": "Enoch", "parent": "Awan"},
  {"name": "Azura", "parent": "Eve"}
]

转换为层次结构:

var root = d3.stratify()
    .id(function(d) { return d.name; })
    .parentId(function(d) { return d.parent; })
    (table);

这将返回:

现在可以将此层次结构传递给分层布局,例如d3.tree,以进行可视化了。

d3.stratify()

使用默认设置构造一个新的分层运算器。

stratify(data)

根据指定的表格data生成新的层次结构。返回对象中的每个节点都具有相应数据对象的属性的浅拷贝,但不包括以下保留属性:id,parentId,children。

stratify.id([id])

如果指定了id,则设置id accessor为给定函数并返回此分层运算器。否则,返回当前的id accessor,默认为:

function id(d) {
  return d.id;
}

对传递给分层运算器的输入数据中的每个元素调用id accessor,传入当前数据(d)和当前索引(i)。然后使用返回的字符串来识别与父id相关的节点关系。对于叶节点,id可能为undefined;否则,该id必须是唯一的。(Null和空字符串相当于undefined。)

stratify.parentId([parentId])

如果指定了parentId,则将父id accessor设置为给定函数并返回此分层运算器。否则,返回当前的父id accessor,默认为:

function parentId(d) {
  return d.parentId;
}

为传递给分层运算器的输入数据中的每个元素调用父id accessor,并传入当前数据(d)和当前索引(i)。然后使用返回的字符串来识别与id相关的节点关系。对于根节点,父id应该是undefined。(Null和空字符串相当于undefined。)输入数据中必须只有一个根节点,并且没有循环关系。

Cluster

cluster layout(簇布局)生成树状图:在树的的同一深度位置放置叶节点的node-link diagrams(节点链接图)。树状图通常不如tidy tree简洁,但在所有叶子应该处于同一层级时很有用,例如hierarchical clustering(分层群聚)或phylogenetic tree diagrams(系统发生树图)。

d3.cluster()

使用默认设置创建新的簇布局。

cluster(root)

列出指定的root层次结构,在root及其后代上分配以下属性:

  • node.x - 节点的x坐标
  • node.y - 节点的y坐标

坐标xy表示任意坐标系;例如,可以将x视为角度,将y视为半径以生成radial layout(径向布局)。在将层次结构传递给簇布局之前,你可能需要调用root.sort

cluster.size([size])

如果指定了size,则将此簇布局的大小设置为指定的二元数字数组[ widthheight ],并返回此簇布局。如果不指定size,则返回当前布局大小,默认为[1,1]。布局大小为null表示将使用节点大小。坐标xy表示任意坐标系;例如为了产生径向布局,[360,radius] 的大小对应于360°的广度和radius的深度。

cluster.nodeSize([size])

如果指定了size,则将此簇布局的节点大小设置为指定的二元数字数组[ widthheight ],并返回此簇布局。如果不指定size,则返回当前节点大小,默认为null。节点大小为null表示将使用布局大小。当指定了节点大小时,根节点始终位于⟨0,0⟩。

cluster.separation([separation])

如果指定了separation,则设置separation accessor为指定的函数,并返回该簇布局。如果不指定separation,则返回当前separation accessor,默认为:

function separation(a, b) {
  return a.parent == b.parent ? 1 : 2;
}

separation accessor用于分隔相邻的叶节点。分离函数接收传入的两个叶节点ab,并且必须返回所需的分离。节点通常是兄弟节点,但是如果布局决定将这些节点放置在相邻的节点上,那么节点可能关系更远。

Tree

tree(树布局)使用Reingold–Tilford “tidy” algorithm生成整齐的节点链接图,由Buchheim等人改进以在线性时间中运行。整齐的树通常比dendograms(树形图)更紧凑。

d3.tree()

使用默认设置创建新的树布局。

tree(root)

列出指定的root层次结构,在root及其后代上分配以下属性:

  • node.x - 节点的x坐标
  • node.y - 节点的y坐标

坐标xy表示任意坐标系;例如,可以将x视为角度,将y视为半径以生成radial layout(径向布局)。在将层次结构传递给树布局之前,你可能需要调用root.sort

tree.size([size])

如果指定了size,则将此树布局的大小设置为指定的二元数字数组[ widthheight ],并返回此树布局。如果未指定size,则返回当前布局大小,默认为[1,1]。布局大小为null表示将使用节点大小。坐标xy表示任意坐标系;例如为了产生径向布局,[360,radius] 的大小对应于360°的宽度和radius的深度。

tree.nodeSize([size])

如果指定了size,则将此树布局的节点大小设置为指定的二元数字数组[ widthheight ],并返回此树布局。如果不指定size,则返回当前节点大小,默认为null。节点大小为null表示将使用布局大小。当指定了节点大小时,根节点始终位于⟨0,0⟩。

tree.separation([separation])

如果指定了separation,则设置separation accessor为指定的函数,并返回该树布局。如果不指定separation,则返回当前separation accessor,默认为:

function separation(a, b) {
  return a.parent == b.parent ? 1 : 2;
}

一种更适合径向布局的变体,可以按半径比例减小间距:

function separation(a, b) {
  return (a.parent == b.parent ? 1 : 2) / a.depth;
}

separation accessor用于分隔相邻的叶节点。分离函数接收传入的两个叶节点ab,并且必须返回所需的分离。节点通常是兄弟节点,但是如果布局决定将这些节点放置在相邻的节点上,那么节点可能关系更远。

Treemap

Ben Shneiderman于1991年引入,根据每个节点的相关值,treemap(树形图)递归地将区域细分为矩形。D3的树形图实现支持可扩展的tiling method(平铺方法):默认的squarified method(矩形法)试图生成具有黄金分割比的矩形;与slice-and-dice(切片和切块)相比,这提供了更好的可读性和尺寸估计,切片和切块简单地在水平和垂直细分之间交替。

d3.treemap()

使用默认设置创建新的树形图布局。

treemap(root)

列出指定的root层次结构,在root及其后代上分配以下属性:

  • node.x0 - 矩形的左边
  • node.y0 - 矩形的上边
  • node.x1 - 矩形的右边
  • node.y1 - 矩形的底边

在将层次结构传递给树形图布局之前,你必须调用root.sum。在计算布局之前,你可能还想调用root.sort命令来对层次结构排序。

treemap.tile([tile])

如果指定了tile,则将平铺方法设置为指定的函数并返回此树形图布局。如果不指定tile,则返回当前的平铺方法,默认为具有黄金分割比的d3.treemapSquarify

treemap.size([size])

如果指定了size,则将此树形图布局的大小设置为指定的二元数字数组[ widthheight ],并返回此树形图布局。如果不指定size,则返回当前大小,默认为[1,1]。

treemap.round([round])

如果指定了round,则根据给定的布尔值启用或禁用舍入并返回此树形图布局。如果不指定round,则返回当前舍入状态,其默认为false。

treemap.padding([padding])

如果指定了padding,则将内部填充外部填充设置为指定的数字或函数,并返回此树形图布局。如果不指定padding,则返回当前的内部填充函数。

treemap.paddingInner([padding])

如果指定了padding,则设置内部填充为指定的数或函数,并返回该树形图布局。如果不指定padding,则返回当前的内部填充函数,默认为常量0。如果padding是一个函数,则会为每个具有子节点的节点调用它,并传入当前节点。内部填充用于分隔节点的相邻子节点。

treemap.paddingOuter([padding])

如果指定了padding,则将顶部右侧底部左侧填充设置为指定的数字或函数,并返回此树形图布局。如果不指定padding,则返回当前顶部填充函数。

treemap.paddingTop([padding])

如果指定了padding,则设置顶部填充为指定的数或函数,并返回该树形图布局。如果不指定padding,则返回当前顶部填充函数,默认为常量0。如果padding是一个函数,则会为每个具有子节点的节点调用它,并传入当前节点。顶部填充用于将节点的顶边与子节点分开。

treemap.paddingRight([padding])

如果指定了padding,则设置右侧填充为指定的数或函数,并返回该树形图布局。如果不指定padding,则返回当前右侧填充函数,默认为常量0。如果padding是一个函数,则会为每个具有子节点的节点调用它,并传入当前节点。右侧填充用于将节点的右边与子节点分开。

treemap.paddingBottom([padding])

如果指定了padding,则设置底部填充为指定的数或函数,并返回该树形图布局。如果不指定padding,则返回当前底部填充函数,默认为常量0。如果padding是一个函数,则会为每个具有子节点的节点调用它,并传入当前节点。底部填充用于将节点的底边与子节点分开。

treemap.paddingLeft([padding])

如果指定了padding,则设置左侧填充为指定的数或函数,并返回该树形图布局。如果不指定padding,则返回当前左侧填充函数,默认为常量0。如果padding是一个函数,则会为每个具有子节点的节点调用它,并传入当前节点。左侧填充用于将节点的左边与子节点分开。

Treemap Tiling

提供了几种内置的平铺方法,可用于treemap.tile

d3.treemapBinary(node, x0, y0, x1, y1)

递归地将指定的nodes分割成近似均匀的二叉树,为宽矩形选择水平分割,为高矩形选择垂直分割。

d3.treemapDice(node, x0, y0, x1, y1)

根据指定node的每个子节点的值,水平分割由x0y0x1y1指定的矩形区域。从给定矩形的左边(x0)开始,子节点按顺序排列。如果子节点值的总和小于指定node的值(即,如果指定node具有非零内部值),则剩余的空白空间将位于给定矩形的右边(x1)。

d3.treemapSlice(node, x0, y0, x1, y1)

根据指定node的每个子节点的值,垂直分割由x0y0x1y1指定的矩形区域。从给定矩形的顶边(y0)开始,子节点按顺序排列。如果子节点值的总和小于指定node的值(即,如果指定node具有非零内部值),则剩余的空白空间将位于给定矩形的下边(y1)。

d3.treemapSliceDice(node, x0, y0, x1, y1)

如果指定的node具有奇数深度,则委托给treemapSlice;否则委托给treemapDice

d3.treemapSquarify(node, x0, y0, x1, y1)

Bruls等人实现了squarified treemap算法,它试图生成给定宽高比的矩形。

d3.treemapResquarify(node, x0, y0, x1, y1)

d3.treemapSquarify一样,除了保留由d3.treemapResquarify计算的先前布局的拓扑结构(节点邻接)(如果有的话),它使用相同的目标宽高比。这种平铺方法适用于动态更改树形图,因为它只改变节点大小而不改变其相对位置,从而避免分散混乱和遮挡。然而,稳定更新的缺点是后续更新的次优布局:只有第一个布局使用Bruls等人的矩形算法。

squarify.ratio(ratio)

指定生成的矩形的所需宽高比。ratio必须被指定为一个大于或等于1的数字。请注意,生成的矩形的方向(高或宽)不是由比率隐含的;例如,两个的比率将试图生成其矩形的混合物,其width:height比为2:1或1:2。(但是,你可以通过生成不同尺寸的方形树形图,然后将树形图拉伸至所需的宽高比来近似实现此结果。)此外,指定ratio仅仅是平铺算法的一个提示;矩形不保证具有指定的宽高比。如果不指定,宽高比默认为黄金比例,φ=(1 + sqrt(5))/ 2,Kong等人.

Partition

partition layout(分区布局)生成邻接图:节点链接树图的空间填充变体。不是在层次结构中绘制父级和子级之间的链接,而是将节点绘制为solid areas(实体区域)(圆弧或矩形),并且相对于其他节点的位置显示其在层次结构中的位置。节点的大小编码了一个难以在节点链接图中显示的定量维度。

d3.partition()

使用默认设置创建新的分区布局。

partition(root)

列出指定的root层次结构,在root及其后代上分配以下属性:

  • node.x0 - 矩形的左边
  • node.y0 - 矩形的上边
  • node.x1 - 矩形的右边
  • node.y1 - 矩形的底边

在将层次结构传递给分区布局之前,你必须调用root.sum。在计算布局之前,你可能还想调用root.sort命令来对层次结构排序。

partition.size([size])

如果指定了size,则将此分区布局的大小设置为指定的二元数字数组[ widthheight ],并返回此分区图布局。如果不指定size,则返回当前大小,默认为[1,1]。

partition.round([round])

如果指定了round,则根据给定的布尔值启用或禁用舍入并返回此分区布局。如果不指定round,返回当前舍入状态,其默认为false。

partition.padding([padding])

如果指定了padding,则将填充设置为指定的数字或函数,并返回此分区布局。如果不指定padding,则返回当前的填充,默认为0。填充用于分隔节点的相邻子节点。

Pack

机箱图使用包含(嵌套)来表示层次结构。叶圈的大小编码数据的定量维度。封闭的圆显示每个子树的近似累积尺寸,但由于浪费的空间会造成一些失真,只有叶节点可以比较准确。虽然circle packing(圆形打包)不像treemap那样有效地使用空间,但“浪费”的空间更突出地揭示了层次结构。

d3.pack()

使用默认设置创建新的包布局。

pack(root)

列出指定的root层次结构,在root及其后代上分配以下属性:

  • node.x - 圆中心的x坐标
  • node.y - 圆中心的y坐标
  • node.r - 圆的半径

在将层次结构传递给包布局之前,你必须调用root.sum。在计算布局之前,你可能还想调用root.sort命令来对层次结构排序。

pack.radius([radius])

如果指定了radius,则将包布局的radius accessor设置为指定的函数并返回此包布局。如果不指定radius,则返回当前的radius accessor,默认为null。如果radius accessor为null,则每个叶圆的半径由叶node.value 派生(由node.sum计算)得出;然后按比例缩放半径以适应布局尺寸。如果radius accessor不为null,则每个叶圆的半径都由该函数精确指定。

pack.size([size])

如果指定了size,则将此包布局的大小设置为指定的二元数字数组[ widthheight ],并返回此包布局。如果不指定size,则返回当前大小,默认为[1,1]。

pack.padding([padding])

如果指定了padding,则将此包布局的padding accessor设置为指定的数字或函数并返回此包装布局。如果不指定padding,则返回当前padding accessor,默认为常量0。当兄弟节点打包时,切线兄弟节点将被大约指定的填充分开;封闭的父圆也将通过大约指定的填充而与其子节点分开。如果不指定显式半径,则填充是近似值,因为需要使用两遍算法来适应布局大小:首先不使用填充打包这些圆;计算缩放因子并将其应用于指定的填充;最后将这些圆随着填充重新打包。

d3.packSiblings(circles)

打包指定的circles数组,每个circle必须具有指定圆半径的radius.r属性。为每个圆分配以下属性:

  • circle.x - 圆中心的x坐标
  • circle.y - 圆中心的y坐标

根据Wang等人的front-chain packing algorithm(前链打包算法)来定位圆。

d3.packEnclose(circles)

计算包含指定circles数组的最小圆,每个circle必须具有指定圆半径的radius.r属性以及指定圆中心的circle.x和circle.y属性。封闭圆使用Matoušek-Sharir-Welzl algorithm计算。(另请参阅Apollonius’ Problem。)

results matching ""

    No results matching ""