堆叠柱状图

stacked-bar

堆叠柱状图的简介

堆叠柱状图是柱状图的扩展,通过在单个柱子中堆叠多个数据系列来显示分类数据。每个柱子代表一个类别的总数,而柱子内的不同颜色段代表各个子类别的数值。堆叠柱状图不仅能够展示每个类别的总量,还能显示各个子类别对总量的贡献。

堆叠柱状图特别适合于比较多个类别的组成结构,以及观察各子类别在不同类别中的分布情况。通过颜色编码,用户可以轻松识别不同的子类别,并比较它们在各个主类别中的占比。

当需要同时展示总量和构成时,堆叠柱状图是一个很好的选择。可以进一步扩展为百分比堆叠柱状图来显示各部分的相对比例。

英文名:Stacked Bar Chart, Stacked Column Chart

堆叠柱状图的构成

垂直堆叠柱状图

stacked-bar-vertical
图表类型 垂直堆叠柱状图
适合的数据 多系列分类数据:一个分类数据字段、一个连续数据字段、一个系列分类字段
功能 对比不同类别的总量以及各子类别的构成
数据与图形的映射 分类字段映射到横轴位置
数值字段映射到柱子高度
系列字段映射到颜色,通过堆叠显示在同一柱子中
适合的数据条数 主类别不超过 12 条,子类别不超过 8 条

水平堆叠柱状图

stacked-bar-horizontal
图表类型 水平堆叠柱状图
适合的数据 多系列分类数据:一个分类数据字段、一个连续数据字段、一个系列分类字段
功能 对比不同类别的总量以及各子类别的构成
数据与图形的映射 分类字段映射到纵轴位置
数值字段映射到柱子宽度
系列字段映射到颜色
适合的数据条数 主类别不超过 30 条,子类别不超过 8 条

堆叠柱状图的应用场景

适合的场景

例子 1: 适合展示多城市降雨量的月度构成

下图展示了伦敦和柏林两个城市在不同月份的降雨量分布,能够清楚地看出每个月的总降雨量以及两个城市各自的贡献。

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

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

chart.options({
  type: 'interval',
  autoFit: true,
  data: [
    { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 },
    { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 },
    { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 },
    { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 },
    { name: 'London', 月份: 'May', 月均降雨量: 47 },
    { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 },
    { name: 'London', 月份: 'Jul.', 月均降雨量: 24 },
    { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 },
    { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 },
    { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 },
    { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 },
    { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 },
    { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 },
    { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 },
    { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 },
    { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 },
  ],
  encode: { x: '月份', y: '月均降雨量', color: 'name' },
  transform: [{ type: 'stackY' }],
  interaction: [
    {
      type: 'elementHighlight',
      background: true,
      region: true,
    },
  ],
});

chart.render();

说明

  • 月份 字段映射到横轴位置,表示时间维度
  • 月均降雨量 字段映射到柱子高度,通过 stackY 变换进行堆叠
  • name 字段映射到颜色,区分不同城市
  • 可以同时比较每个月的总降雨量和各城市的贡献

例子 2: 适合展示人口年龄结构的地区对比

堆叠柱状图非常适合展示不同地区的人口年龄结构分布,既能看出各地区的总人口,又能分析年龄构成。

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

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

chart.options({
  type: 'interval',
  autoFit: true,
  data: {
    type: 'fetch',
    value:
      'https://gw.alipayobjects.com/os/bmw-prod/f129b517-158d-41a9-83a3-3294d639b39e.csv',
    format: 'csv',
  },
  encode: { x: 'state', y: 'population', color: 'age' },
  transform: [{ type: 'stackY' }, { type: 'sortX', by: 'y', reverse: true }],
  axis: {
    x: {
      labelSpacing: 4,
      labelTransform: 'rotate(90)',
    },
    y: {
      labelFormatter: '~s',
      title: null,
    },
  },
  legend: {
    color: {
      position: 'right',
      title: '年龄段',
    },
  },
  interaction: [
    {
      type: 'elementHighlight',
      background: true,
    },
  ],
});

chart.render();

说明

  • 使用 sortX 变换按总人口数量排序,便于比较
  • labelFormatter: '~s' 格式化数值显示(如 1M 表示 1 百万)
  • 旋转 x 轴标签以避免重叠

例子 3: 水平堆叠柱状图适合类别较多的情况

当分类较多时,水平堆叠柱状图能够更好地展示标签,避免文字重叠。

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

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  width: 800,
  height: 600,
});

chart.options({
  type: 'interval',
  autoFit: true,
  data: {
    type: 'fetch',
    value:
      'https://gw.alipayobjects.com/os/bmw-prod/f129b517-158d-41a9-83a3-3294d639b39e.csv',
    format: 'csv',
  },
  coordinate: { transform: [{ type: 'transpose' }] },
  encode: { x: 'state', y: 'population', color: 'age' },
  transform: [{ type: 'stackY' }, { type: 'sortX', by: 'y', reverse: true }],
  axis: {
    y: {
      labelFormatter: '~s',
      title: null,
    },
    x: {
      title: null,
    },
  },
  legend: {
    color: {
      position: 'bottom',
      title: '年龄段',
    },
  },
});

chart.render();

说明

  • 使用 coordinate: { transform: [{ type: 'transpose' }] } 实现水平方向
  • 标签可以水平排列,提高可读性
  • 适合有较多分类的数据

例子 4: 百分比堆叠柱状图展示比例关系

当重点关注各部分占比而非绝对数值时,百分比堆叠柱状图是更好的选择。

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

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  width: 800,
  height: 600,
});

chart.options({
  type: 'interval',
  autoFit: true,
  data: {
    type: 'fetch',
    value:
      'https://gw.alipayobjects.com/os/bmw-prod/f129b517-158d-41a9-83a3-3294d639b39e.csv',
    format: 'csv',
  },
  coordinate: { transform: [{ type: 'transpose' }] },
  encode: { x: 'state', y: 'population', color: 'age' },
  transform: [
    { type: 'stackY' },
    { type: 'normalizeY' },
    { type: 'sortX', by: 'y', reverse: true },
  ],
  axis: {
    y: {
      labelFormatter: '.0%',
      title: null,
    },
    x: {
      title: null,
    },
  },
  legend: {
    color: {
      position: 'bottom',
      title: '年龄段',
    },
  },
  tooltip: {
    channel: 'y0',
    valueFormatter: '.0%',
  },
});

chart.render();

说明

  • 结合 stackYnormalizeY 变换实现百分比堆叠
  • labelFormatter: '.0%' 将 y 轴标签格式化为百分比
  • 便于比较各州的年龄结构比例

不适合的场景

例子 1: 不适合展示负值数据的简单堆叠

传统的堆叠柱状图不适合包含负值的数据,因为堆叠逻辑会导致视觉混乱。

例子 2: 子类别过多时视觉效果差

当子类别数量超过 8-10 个时,颜色区分度下降,用户难以有效区分和比较。

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

// 模拟过多子类别的数据
const chart = new Chart({
  container: 'container',
  theme: 'classic',
});

chart.options({
  type: 'interval',
  autoFit: true,
  data: [
    { category: 'A', type: 'Type1', value: 10 },
    { category: 'A', type: 'Type2', value: 8 },
    { category: 'A', type: 'Type3', value: 6 },
    { category: 'A', type: 'Type4', value: 4 },
    { category: 'A', type: 'Type5', value: 3 },
    { category: 'A', type: 'Type6', value: 2 },
    { category: 'A', type: 'Type7', value: 2 },
    { category: 'A', type: 'Type8', value: 1 },
    { category: 'A', type: 'Type9', value: 1 },
    { category: 'A', type: 'Type10', value: 1 },
    { category: 'A', type: 'Type11', value: 1 },
    { category: 'A', type: 'Type12', value: 1 },
    { category: 'B', type: 'Type1', value: 12 },
    { category: 'B', type: 'Type2', value: 9 },
    { category: 'B', type: 'Type3', value: 7 },
    { category: 'B', type: 'Type4', value: 5 },
    { category: 'B', type: 'Type5', value: 4 },
    { category: 'B', type: 'Type6', value: 3 },
    { category: 'B', type: 'Type7', value: 2 },
    { category: 'B', type: 'Type8', value: 2 },
    { category: 'B', type: 'Type9', value: 1 },
    { category: 'B', type: 'Type10', value: 1 },
    { category: 'B', type: 'Type11', value: 1 },
    { category: 'B', type: 'Type12', value: 1 },
  ],
  encode: { x: 'category', y: 'value', color: 'type' },
  transform: [{ type: 'stackY' }],
});

chart.render();

在这种情况下,建议将较小的类别合并为“其他”类别,或者使用其他图表类型。

堆叠柱状图的扩展

分散堆叠柱状图

分散堆叠柱状图可以展示正负值的对比,特别适合展示盈亏、增减等对比数据。

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

const chart = new Chart({ container: 'container' });

const fields = [
  'lost > 100$',
  'lost <= 100$',
  'gained <= 100$',
  'gained > 100$',
];

chart.options({
  type: 'view',
  paddingLeft: 25,
  children: [
    {
      type: 'interval',
      data: {
        type: 'fetch',
        value: 'https://assets.antv.antgroup.com/g2/nivo-gain-lost.json',
        transform: [
          {
            type: 'fold',
            fields,
          },
        ],
      },
      encode: { x: 'user', y: 'value', color: 'key' },
      transform: [{ type: 'stackY' }],
      scale: {
        x: { padding: 0.2 },
        y: { domainMin: -100, domainMax: 100 },
        color: {
          domain: fields,
          range: ['#97e3d5', '#61cdbb', '#e25c3b', '#f47560'],
        },
      },
      style: { radius: 10 },
      axis: {
        y: { position: 'right', title: false, labelFormatter: (v) => `${v}%` },
      },
      legend: { color: { title: false } },
      labels: [
        {
          text: 'value',
          position: 'inside',
          formatter: (v) => (v ? `${v}%` : ''),
          transform: [{ type: 'overlapDodgeY' }],
          fill: '#000',
          fontSize: 10,
        },
      ],
    },
    {
      type: 'lineY',
      data: [0],
      style: { lineWidth: 2, stroke: '#e25c3b', strokeOpacity: 1 },
    },
    {
      type: 'text',
      style: {
        x: -10,
        y: '75%',
        text: 'lost',
        fontWeight: 'bold',
        dy: -10,
        transform: 'rotate(-90)',
        fill: '#61cdbb',
      },
    },
    {
      type: 'text',
      style: {
        x: -10,
        y: '20%',
        text: 'gain',
        fontWeight: 'bold',
        dy: -10,
        transform: 'rotate(-90)',
        fill: '#e25c3b',
      },
    },
  ],
});

chart.render();

说明

  • 使用正负值数据展示盈亏对比
  • 设置 domainMindomainMax 控制坐标轴范围
  • 添加分界线突出正负值的分界
  • 使用圆角样式增强视觉效果

堆叠柱状图与其他图表的对比

堆叠柱状图和柱状图

  • 堆叠柱状图展示多个子类别的构成关系和总量
  • 普通柱状图主要用于比较不同类别的单一数值
  • 堆叠柱状图能同时显示部分和整体的关系

堆叠柱状图和堆叠面积图

  • 堆叠柱状图适合离散的分类数据比较
  • 堆叠面积图适合连续的时间序列数据趋势展示
  • 堆叠柱状图更便于精确数值比较

堆叠柱状图和饼图

  • 堆叠柱状图可以同时比较多个类别的构成
  • 饼图只能展示单个整体的构成比例
  • 堆叠柱状图在比较多个类别时更有优势

相似图表

分类

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

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

选择打开Esc关闭