矩形树图

treemap

矩形树图的简介

矩形树图是一种用于展示层次化数据的可视化图表,通过一系列嵌套的矩形来表示树状结构的数据。每个矩形的面积大小与其对应的数值成正比,颜色通常用来区分不同的类别或层级。矩形树图将树形数据结构转化为平面空间的矩形填充,能够直观地展示数据的层次关系和数值比例。

矩形树图特别适合展示具有层级关系的大量数据,如文件系统、组织架构、预算分配、股票市场等。相比传统的树形结构图,矩形树图能更有效地利用空间,并且具有展示占比功能,使得用户能够快速理解数据的分布和重要性。

矩形树图还支持交互式下钻功能,用户可以点击某个矩形区域来查看该层级的详细子项,这使得它成为数据探索和分析的强大工具。

英文名:Treemap

矩形树图的构成

basic-treemap
图表类型 矩形树图
适合的数据 层次化数据:具有树状结构的嵌套数据,包含分类字段和数值字段
功能 展示层次化数据的比例关系和分布情况
数据与图形的映射 层级关系映射到嵌套矩形
数值大小映射到矩形面积
不同类别通过颜色和位置进行区分
适合的场景 文件系统、组织架构、预算分配、股票组合等具有清晰层次关系的数据展示

矩形树图的应用场景

适合的场景

例子 1: 展示文件系统结构

下图展示了软件项目文件系统的层次结构,通过矩形树图可以清晰地看到各个模块和文件的大小分布,帮助开发者了解代码结构。

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

chart.options({
  type: 'treemap',
  data: {
    type: 'fetch',
    value: 'https://assets.antv.antgroup.com/g2/flare-treemap.json',
  },
  layout: {
    path: (d) => d.name.replace(/\./g, '/'),
    tile: 'treemapBinary',
    paddingInner: 1,
  },
  encode: {
    value: 'size',
    color: (d) => d.parent?.data.name.split('.')[1] || 'root',
  },
  style: {
    labelText: (d) => {
      const name = d.data.name
        .split('.')
        .pop()
        .split(/(?=[A-Z][a-z])/g)[0];
      return name;
    },
    labelFill: '#000',
    labelPosition: 'top-left',
    labelDx: 3,
    labelDy: 3,
    fillOpacity: 0.7,
  },
  tooltip: {
    title: (d) => d.path?.join?.('.') || d.data.name,
    items: [{ field: 'value', name: '大小' }],
  },
});

chart.render();

说明

  • 使用 path 配置将扁平化数据转换为层次结构
  • layout.tile 设置为 treemapBinary 使用二分布局算法
  • paddingInner 设置矩形间的内边距,增强视觉分离效果

例子 2: 展示预算分配情况

矩形树图非常适合展示预算在不同项目和子项目之间的分配情况,帮助管理者快速了解资源配置。

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const budgetData = {
  name: '年度预算',
  children: [
    {
      name: '研发部门',
      children: [
        { name: '前端开发', value: 1200 },
        { name: '后端开发', value: 1500 },
        { name: '测试', value: 800 },
        { name: '设计', value: 600 },
      ],
    },
    {
      name: '市场部门',
      children: [
        { name: '广告投放', value: 2000 },
        { name: '活动策划', value: 800 },
        { name: '内容营销', value: 500 },
      ],
    },
    {
      name: '运营部门',
      children: [
        { name: '客户服务', value: 700 },
        { name: '数据分析', value: 400 },
        { name: '运营支持', value: 300 },
      ],
    },
    { name: '其他支出', value: 1200 },
  ],
};

chart.options({
  type: 'treemap',
  data: { value: budgetData },
  layout: {
    tile: 'treemapSquarify',
    paddingInner: 2,
  },
  encode: {
    value: 'value',
    color: (d) => d.path[1] || d.data.name,
  },
  style: {
    labelText: (d) => d.data.name,
    labelFill: '#fff',
    labelStroke: '#000',
    labelLineWidth: 0.5,
    labelFontSize: 12,
  },
  tooltip: {
    title: (d) => d.data.name,
    items: [
      { field: 'value', name: '预算', valueFormatter: (v) => `${v}万元` },
    ],
  },
});

chart.render();

说明

  • 使用层级结构数据,不需要配置 path
  • tile: 'treemapSquarify' 使用黄金比例算法,产生更接近正方形的矩形
  • 通过 labelPosition: 'center' 将标签居中显示

例子 3: 展示销售数据层次

矩形树图可以有效展示销售数据的多层级结构,从地区到产品类别再到具体产品。

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const salesData = {
  name: '全国销售',
  children: [
    {
      name: '华东地区',
      children: [
        {
          name: '数码产品',
          children: [
            { name: '手机', value: 3200 },
            { name: '电脑', value: 2800 },
            { name: '平板', value: 1500 },
          ],
        },
        {
          name: '家电',
          children: [
            { name: '冰箱', value: 2100 },
            { name: '洗衣机', value: 1800 },
            { name: '空调', value: 2500 },
          ],
        },
      ],
    },
    {
      name: '华北地区',
      children: [
        {
          name: '数码产品',
          children: [
            { name: '手机', value: 2800 },
            { name: '电脑', value: 2400 },
            { name: '平板', value: 1200 },
          ],
        },
        {
          name: '家电',
          children: [
            { name: '冰箱', value: 1900 },
            { name: '洗衣机', value: 1600 },
            { name: '空调', value: 2200 },
          ],
        },
      ],
    },
    {
      name: '华南地区',
      children: [
        { name: '数码产品', value: 2200 },
        { name: '家电', value: 1800 },
      ],
    },
  ],
};

chart.options({
  type: 'treemap',
  data: { value: salesData },
  layout: {
    tile: 'treemapSliceDice',
    paddingInner: 3,
    layer: 2, // 只显示前两层
  },
  encode: {
    value: 'value',
    color: (d) => d.path[1] || 'default',
  },
  style: {
    labelText: (d) => {
      const name = d.data.name;
      const value = d.value;
      return d.depth <= 1 ? `${name}\n${Math.round(value)}万` : name;
    },
    labelFill: '#000',
    labelFontSize: (d) =>
      Math.max(10, Math.min(16, Math.sqrt(d.x1 - d.x0) * 2)),
    stroke: '#fff',
    lineWidth: 2,
  },
  interaction: {
    treemapDrillDown: {
      breadCrumbY: 12,
      activeFill: '#873bf4',
      breadCrumbFill: 'rgba(0, 0, 0, 0.85)',
      breadCrumbFontSize: 12,
    },
  },
  legend: false,
});

chart.render();

不适合的场景

例子 1: 数值差异极小的数据对比

当数据中各项目的数值差异很小时,矩形树图的面积差异不明显,用户难以感知到数值的细微差别。

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

// 数值差异很小的数据
const similarData = {
  name: '地区销售(相似数值)',
  children: [
    { name: '北京', value: 9995 },
    { name: '上海', value: 10001 },
    { name: '广州', value: 9999 },
    { name: '深圳', value: 10003 },
    { name: '杭州', value: 9997 },
    { name: '南京', value: 10002 },
  ],
};

chart.options({
  type: 'treemap',
  data: { value: similarData },
  encode: { value: 'value' },
  style: {
    labelText: (d) => `${d.data.name}\n${d.value}`,
    labelFill: '#000',
  },
});

chart.render();

柱状图(推荐)

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const similarDataFlat = [
  { name: '北京', value: 9995 },
  { name: '上海', value: 10001 },
  { name: '广州', value: 9999 },
  { name: '深圳', value: 10003 },
  { name: '杭州', value: 9997 },
  { name: '南京', value: 10002 },
];

chart.options({
  type: 'interval',
  data: similarDataFlat,
  encode: { x: 'name', y: 'value', color: 'name' },
  axis: {
    y: { nice: false, domain: [9990, 10010] }, // 缩小Y轴范围突出差异
  },
});

chart.render();

说明:当数据值差异小于 5% 时,矩形树图的面积差异几乎不可感知,此时建议使用柱状图并调整 Y 轴范围来突出差异。

例子 2: 非层次化的简单分类数据

对于没有层次关系的简单分类数据,矩形树图会显得过于复杂,不如饼图或柱状图直观。

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

// 简单的分类数据,没有层次关系
const simpleData = {
  name: '产品销量',
  children: [
    { name: '产品A', value: 230 },
    { name: '产品B', value: 180 },
    { name: '产品C', value: 150 },
    { name: '产品D', value: 120 },
  ],
};

chart.options({
  type: 'treemap',
  data: { value: simpleData },
  encode: { value: 'value' },
  style: {
    labelText: (d) => d.data.name,
    labelFill: '#000',
  },
});

chart.render();

饼图(推荐)

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const simpleDataFlat = [
  { name: '产品A', value: 230 },
  { name: '产品B', value: 180 },
  { name: '产品C', value: 150 },
  { name: '产品D', value: 120 },
];

chart.options({
  type: 'interval',
  data: simpleDataFlat,
  encode: { y: 'value', color: 'name' },
  transform: [{ type: 'stackY' }],
  coordinate: { type: 'theta' },
  legend: {
    color: { position: 'right' },
  },
});

chart.render();

说明:对于简单的分类占比数据,饼图能更直观地展示各部分在整体中的比例关系。

矩形树图的扩展用法

带下钻交互的矩形树图

矩形树图最强大的功能之一是支持下钻交互,用户可以点击某个区域来深入查看该层级的详细信息:

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const drillDownData = {
  name: '商品',
  children: [
    {
      name: '文具',
      children: [
        {
          name: '笔类',
          children: [
            { name: '铅笔', value: 430 },
            { name: '圆珠笔', value: 530 },
            { name: '钢笔', value: 80 },
            { name: '水彩笔', value: 130 },
          ],
        },
        { name: '笔记本', value: 160 },
        { name: '文件夹', value: 90 },
        { name: '其他', value: 80 },
      ],
    },
    {
      name: '零食',
      children: [
        { name: '饼干', value: 280 },
        { name: '辣条', value: 150 },
        { name: '糖果', value: 210 },
        {
          name: '饮品',
          children: [
            { name: '可乐', value: 122 },
            { name: '矿泉水', value: 244 },
            { name: '果汁', value: 49 },
            { name: '牛奶', value: 82 },
          ],
        },
        { name: '其他', value: 40 },
      ],
    },
    { name: '其他商品', value: 450 },
  ],
};

chart.options({
  type: 'treemap',
  data: { value: drillDownData },
  layout: {
    tile: 'treemapBinary',
    paddingInner: 5,
  },
  encode: { value: 'value' },
  style: {
    labelFill: '#000',
    labelStroke: '#fff',
    labelLineWidth: 1.5,
    labelFontSize: 14,
    labelPosition: 'top-left',
    labelDx: 5,
    labelDy: 5,
  },
  interaction: {
    treemapDrillDown: {
      breadCrumbY: 12,
      activeFill: '#873bf4',
      breadCrumbFill: 'rgba(0, 0, 0, 0.85)',
      breadCrumbFontSize: 12,
    },
  },
  tooltip: {
    title: (d) => d.data.name,
    items: [{ field: 'value', name: '数量' }],
  },
});

chart.render();

自定义样式的矩形树图

通过丰富的样式配置,可以创建个性化的矩形树图:

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const customData = {
  name: '技术栈',
  children: [
    {
      name: '前端',
      children: [
        { name: 'React', value: 45 },
        { name: 'Vue', value: 35 },
        { name: 'Angular', value: 20 },
      ],
    },
    {
      name: '后端',
      children: [
        { name: 'Node.js', value: 40 },
        { name: 'Python', value: 35 },
        { name: 'Java', value: 25 },
      ],
    },
    {
      name: '数据库',
      children: [
        { name: 'MySQL', value: 50 },
        { name: 'MongoDB', value: 30 },
        { name: 'Redis', value: 20 },
      ],
    },
  ],
};

chart.options({
  type: 'treemap',
  data: { value: customData },
  layout: {
    tile: 'treemapResquarify',
    paddingInner: 4,
    paddingOuter: 2,
  },
  encode: {
    value: 'value',
    color: (d) => d.path[1] || 'default',
  },
  scale: {
    color: {
      range: ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD'],
    },
  },
  style: {
    labelText: (d) => d.data.name,
    labelFill: '#fff',
    labelStroke: '#000',
    labelLineWidth: 1,
    labelFontSize: (d) => Math.max(10, Math.min(18, (d.x1 - d.x0) * 0.1)),
    labelFontWeight: 'bold',
    stroke: '#fff',
    lineWidth: 3,
    radius: 4, // 圆角
    fillOpacity: 0.9,
    shadowColor: 'rgba(0, 0, 0, 0.1)',
    shadowBlur: 4,
    shadowOffsetX: 2,
    shadowOffsetY: 2,
  },
  interaction: [
    {
      type: 'elementHighlight',
    },
  ],
});

chart.render();

带渐变色的矩形树图

通过渐变色可以增强矩形树图的视觉效果:

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const gradientData = {
  name: '市场份额',
  children: [
    { name: '阿里巴巴', value: 28 },
    { name: '腾讯', value: 25 },
    { name: '字节跳动', value: 18 },
    { name: '美团', value: 15 },
    { name: '京东', value: 12 },
    { name: '百度', value: 10 },
    { name: '网易', value: 8 },
    { name: '小米', value: 7 },
    { name: '滴滴', value: 6 },
    { name: '拼多多', value: 5 },
    { name: '新浪', value: 4 },
    { name: '搜狐', value: 3 },
    { name: '360', value: 2 },
    { name: '其他', value: 7 },
  ],
};

chart.options({
  type: 'treemap',
  data: { value: gradientData },
  layout: {
    tile: 'treemapSquarify',
    paddingInner: 3,
  },
  encode: {
    value: 'value',
    color: 'value',
  },
  scale: {
    color: {
      type: 'sequential',
      range: ['#E8F4FD', '#1890FF'],
    },
  },
  style: {
    labelText: (d) => `${d.data.name}\n${d.value}%`,
    labelFill: (d) => (d.value > 20 ? '#fff' : '#000'),
    labelFontSize: 14,
    labelFontWeight: 'bold',
    stroke: '#fff',
    lineWidth: 2,
  },
  tooltip: {
    title: (d) => d.data.name,
    items: [
      { field: 'value', name: '市场份额', valueFormatter: (v) => `${v}%` },
    ],
  },
});

chart.render();

矩形树图与其他图表的对比

矩形树图和旭日图

矩形树图和旭日图都可以展示层次化数据,但有不同的特点:

对比维度 矩形树图 旭日图
视觉形式 矩形布局 圆形布局
空间利用 矩形填充,利用率高 圆形边界,利用率较低
比例感知 面积比较,更准确 角度比较,适中
层次展示 嵌套矩形,包含关系明确 同心圆,层次关系清晰
适用场景 强调精确的比例对比 强调层次关系和整体结构

矩形树图和饼图

矩形树图相比饼图的优势:

  • 层次化数据:矩形树图可以展示多层级数据,而饼图只能展示单层级
  • 空间利用:矩形树图能更有效利用空间,展示更多信息
  • 精确比较:矩形面积比角度更容易进行精确比较
  • 交互性:支持下钻交互,可以逐层探索数据

饼图的优势:

  • 整体感知:更好地展示各部分与整体的关系
  • 简洁性:对于简单分类数据更清晰易懂

相似图表

分类

全站搜索
文档与示例输入关键词开始搜索

输入关键词,查找文档、API 与示例

选择打开Esc关闭