← 首页 / 把权重铺满一块矩形 待审核
treemap · 面积编码

把权重铺满一块矩形

一组带权重的项(各部门人数、各文件大小、各品类销售额),如何在一块矩形里一眼看出占比?treemap 用面积编码数量:每项分到的矩形面积正比于权重,互不重叠、铺满整块。难点不在「能不能铺满」(切条即可),而在切成什么形状——细长条难以辨识,近正方形才好比较。

1 · 为什么用面积编码

motivation · 面积编码

treemap 要解决的问题:一组带权重的项,如何在有限的矩形空间里一眼看出谁大谁小、占比几何。答案是用面积编码数量——每项分到的矩形面积正比于它的权重,且无重叠、铺满整块。下面直接调权重,看矩形如何随之重排。

1.1 · 三条约束

一个合格的 treemap 布局必须同时满足:

  1. 面积 ∝ 权重——这是「用面积比大小」能成立的前提,比例一旦失真,就会产生误导;
  2. 无重叠——每块矩形互不覆盖,否则面积无法读;
  3. 铺满——不留空隙(层级 treemap 的留白是刻意用来区分层级的,见下方层级嵌套 treemap)。

满足这三条的布局有无穷多种,区别只在矩形的形状: 同样的面积,可以切成细长条,也可以切成近正方形。形状直接决定可读性——这就是 slice-and-dice 与 squarify 两套算法的分野。把同一组权重在上方两种布局间切换,面积始终不变,变的只是长宽比。

2 · Slice-and-Dice

slice-and-dice · 切条

把权重映射成面积,最朴素的做法:沿单一方向把矩形按权重占比切成一排条。实现只有几行,缺点也很直接——权重悬殊时切出的是又细又长的条,面积虽对、却难以辨识与比较。下面单步逐条切分,右侧报出每条的长宽比。

2.1 · 为什么会退化

沿固定方向切,每条的厚度正比于权重,而长度恒等于矩形的另一条边。当某项权重很小,它分到的厚度极薄,长度却仍是满边长——长宽比随之爆炸。经典的 slice-and-dice 会逐层交替横竖切(本节演示单层),但只要某层内权重悬殊,细长条就难以避免。

面积编码的本意是「让人一眼比较大小」,细长条恰恰破坏了这一点——这正是 squarify 要解决的问题:通过换行让每块尽量方正。

3 · Squarified Treemap

squarify · worst aspect ratio

slice-and-dice 沿单一方向切条,权重悬殊时退化成难以辨识的细长条。Bruls、Huizing、van Wijk (2000) 的 squarify 换一种贪心策略:逐项累积成「行」,用 worst aspect ratio 判断何时该收尾换行,使每块矩形尽量接近正方形。下面单步观察这个累积与 flush 的决策过程。

3.1 · 核心:worst aspect ratio

把一组面积 {a₁ … aₙ} 铺在长度为 w 的短边上,这一行所有矩形里最差的那个长宽比记作 worst。设行内面积之和为 s,则 worst=max(w2max(ai)/s2,s2/(w2min(ai)))worst = \max ( w^2\cdot \max (a_i)/s^2 , s^2/(w^2\cdot \min (a_i)) )。贪心准则:把下一项加入当前行,若 worst 不增大就继续累积;一旦会变差,就 flush 当前行(沿短边定型并从剩余区域挖走),再用新的短边开启下一行。

每次都沿较短的边铺行,是 squarify 接近正方形的关键——这与 slice-and-dice 固定方向恰好相反。它是贪心而非全局最优,但实践中已足够好,D3 treemapSquarify、各类磁盘占用可视化都用它。

4 · 层级嵌套 Treemap

nesting · 层级递归

真实数据大多是: 部门下有小组、小组下有人;目录下有子目录、子目录下有文件。treemap 的层级版很直接——内部节点的权重是其所有叶子的权重之和,先把它当一块矩形布局,再在这块矩形内部递归地对它的子节点布局。层与层之间留一点 padding表头来区分。

4.1 · 权重的自底向上聚合

叶子节点自带权重,内部节点的权重是递归求和得到的——这保证了「父块面积 = 子块面积之和」,层级因此在面积上自洽:看一眼最外层就知道各大类占比,钻进去又能看到内部细分。

padding 与表头不是装饰: 没有它们,父子矩形边界重合,根本看不出层级结构;但它们会占用面积,使叶子矩形之和略小于整块——这是层级可读性与面积保真度之间的取舍。调大上方两个滑块,留白增多、层级更清晰,但叶子被挤得更小。

每一层内部的布局仍由 squarify 完成,所以每块叶子也尽量方正。

相关链接

  • Squarified Treemaps Bruls, Huizing, van Wijk (2000) 「squarify」一节的原始论文: 提出用 worst aspect ratio 贪心换行, 使矩形尽量方正, 附完整伪代码与对比图。
  • Treemaps for space-constrained visualization Ben Shneiderman treemap 的发明者讲述其缘起 —— 1990 年代初为在有限屏幕上可视化文件系统占用而提出 slice-and-dice。
  • d3-hierarchy · treemap D3 对应本系列各节的工程实现: d3.treemap() 与可替换的 tiling 策略 (treemapSquarify / treemapSlice / treemapBinary) 及 padding API。
  • Treemapping Wikipedia treemap 各类 tiling 算法 (slice-and-dice / squarified / strip / Voronoi) 的总览与长宽比、稳定性权衡。