跳到主要内容

环图

donut

环图的简介

环图(又叫做甜甜圈图),其本质是饼图将中间区域挖空。环图采用了让我们更关注长度而不是面积的做法,这样我们就能相对简单的对比不同的环图。

虽然环图和饼图在数据表达上很相似,但环图还是有它独特的优点:

  • 更好的对比性:饼图的整体性太强,我们会将注意力集中在比较饼图内各个扇形之间占整体比重的关系。但如果我们将两个饼图放在一起,饼图很难同时对比两个图。环图解决了这个问题。
  • 空间利用率更高:环图可以使用它的空心区域显示文本信息,比如标题、总数等。

英文名:Donut Chart

环图的构成

donut-structure
图表类型 环图
适合的数据 列表:一个分类数据字段、一个连续数据字段
功能 对比分类数据的数值大小
数据与图形的映射 分类数据字段映射到环形的颜色
连续数据字段映射到环形的角度
适合的数据条数 不超过 9 条数据

环图的应用场景

适合的场景

例子 1: 展示分类的占比情况

这种用法与饼图类似,下图是一个游戏公司的销售情况:

genre(游戏类型) sold(销售量)
Sports 27,500
Strategy 11,500
Action 6,000
Shooter 3,500
Other 1,500
import { Chart } from '@antv/g2';

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

chart.options({
  type: 'interval',
  autoFit: true,
  transform: [{ type: 'stackY' }], // 添加堆叠转换
  data: [
    { genre: 'Sports', sold: 27500 },
    { genre: 'Strategy', sold: 11500 },
    { genre: 'Action', sold: 6000 },
    { genre: 'Shooter', sold: 3500 },
    { genre: 'Other', sold: 1500 },
  ],
  coordinate: { type: 'theta', innerRadius: 0.5 },
  encode: { y: 'sold', color: 'genre' },
  legend: {
    color: { position: 'bottom', layout: { justifyContent: 'center' } },
  },
  labels: [
    {
      text: 'genre',
      style: {
        fontWeight: 'bold',
      },
    },
    {
      text: (d, i, data) => {
        const total = data.reduce((acc, curr) => acc + curr.sold, 0);
        const percent = ((d.sold / total) * 100).toFixed(2);
        return `${percent}%`;
      },
      style: {
        fontSize: 10,
        dy: 12,
      },
    },
  ],
});

chart.render();

说明:

  • genre 字段映射到颜色,用于区分不同的游戏类型
  • sold 字段映射到角度,表示销售量占比的大小
  • 使用 coordinate: { type: 'theta', innerRadius: 0.5 } 创建环图效果

例子 2: 在中心区域显示额外信息

环图的空心区域可以用来显示总数、标题或其他重要信息:

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

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

const data = [
  { type: '移动端', value: 54.2 },
  { type: '桌面端', value: 32.1 },
  { type: '平板端', value: 13.7 },
];

const total = data.reduce((acc, curr) => acc + curr.value, 0);

chart.options({
  type: 'interval',
  autoFit: true,
  transform: [{ type: 'stackY' }], // 添加堆叠转换
  data,
  coordinate: { type: 'theta', innerRadius: 0.6 },
  encode: { y: 'value', color: 'type' },
  style: { stroke: '#fff', lineWidth: 2 },
  legend: {
    color: { position: 'bottom', layout: { justifyContent: 'center' } },
  },
  labels: [
    {
      text: (d) => `${d.value}%`,
      style: {
        fontWeight: 'bold',
        fontSize: 12,
      },
    },
  ],
});

chart.render();

不适合的场景

例子 1: 分类过多的场景

下图是各个省的人口的占比情况,因为这张图上包含的分类过多,很难清晰对比各个省份的人口数据占比情况,所以这种情况下,我们推荐使用柱状图。

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

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

chart.options({
  type: 'interval',
  autoFit: true,
  transform: [{ type: 'stackY' }], // 添加堆叠转换
  data: [
    { province: '北京市', population: 19612368 },
    { province: '天津市', population: 12938693 },
    { province: '河北省', population: 71854210 },
    { province: '山西省', population: 27500000 },
    { province: '内蒙古自治区', population: 24706291 },
    { province: '辽宁省', population: 43746323 },
    { province: '吉林省', population: 27452815 },
    { province: '黑龙江省', population: 38313991 },
    { province: '上海市', population: 23019196 },
    { province: '江苏省', population: 78660941 },
    { province: '浙江省', population: 54426891 },
    { province: '安徽省', population: 59500468 },
    { province: '福建省', population: 36894217 },
    { province: '江西省', population: 44567797 },
    { province: '山东省', population: 95792719 },
    { province: '河南省', population: 94029939 },
    { province: '湖北省', population: 57237727 },
    { province: '湖南省', population: 65700762 },
    { province: '广东省', population: 104320459 },
    { province: '广西壮族自治区', population: 46023761 },
    { province: '海南省', population: 8671485 },
    { province: '重庆市', population: 28846170 },
    { province: '四川省', population: 80417528 },
    { province: '贵州省', population: 34748556 },
    { province: '云南省', population: 45966766 },
    { province: '西藏自治区', population: 3002165 },
    { province: '陕西省', population: 37327379 },
    { province: '甘肃省', population: 25575263 },
    { province: '青海省', population: 5626723 },
  ],
  coordinate: { type: 'theta', innerRadius: 0.4 },
  encode: { y: 'population', color: 'province' },
  legend: false, // 分类太多,关闭图例
  labels: false, // 分类太多,关闭标签
});

chart.render();

说明:上图中分类过多,颜色难以区分,标签重叠严重,不适合使用环图。

例子 2: 分类占比差别不明显的场景

下图中游戏公司的不同种类游戏的销售量相近,角度差异很小,不太适合使用环图,此时可以使用柱状图。

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

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

chart.options({
  type: 'interval',
  autoFit: true,
  transform: [{ type: 'stackY' }], // 添加堆叠转换
  data: [
    { genre: 'Sports', sold: 15000 },
    { genre: 'Strategy', sold: 14900 },
    { genre: 'Action', sold: 15050 },
    { genre: 'Shooter', sold: 13000 },
    { genre: 'Other', sold: 13900 },
  ],
  coordinate: { type: 'theta', innerRadius: 0.5 },
  encode: { y: 'sold', color: 'genre' },
  legend: {
    color: { position: 'bottom', layout: { justifyContent: 'center' } },
  },
  labels: [
    {
      text: (d, i, data) => {
        const total = data.reduce((acc, curr) => acc + curr.sold, 0);
        const percent = ((d.sold / total) * 100).toFixed(2);
        return `${percent}%`;
      },
      style: {
        fontSize: 10,
      },
    },
  ],
});

chart.render();

说明:上图中各个分类的占比都接近 20%,差异很小,难以通过角度清晰地对比数值大小。

环图的扩展

分面环图

使用 G2 的分面功能,可以将分组数据绘制成多个环图。下图展示了全球最大 1000 家银行所在地区在 2007 年和 2011 年的利润总额占比情况:

年份 地区 利润总额(亿美金)
2007 亚太地区 1485.54
2007 非洲及中东 330.12
2007 拉丁美洲 196.5
…… …… ……
2011 亚太地区 4107.18
2011 非洲及中东 495.3
2011 拉丁美洲 495.3
…… …… ……
import { Chart } from '@antv/g2';

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

chart.options({
  type: 'facetRect',
  autoFit: true,
  data: [
    { year: '2007', area: '亚太地区', profit: 1485.54 },
    { year: '2007', area: '西欧', profit: 3631.32 },
    { year: '2007', area: '北美', profit: 2083.9 },
    { year: '2007', area: '非洲及中东', profit: 330.12 },
    { year: '2007', area: '中欧和东欧', profit: 141.48 },
    { year: '2007', area: '拉丁美洲', profit: 196.5 },
    { year: '2011', area: '亚太地区', profit: 4107.18 },
    { year: '2011', area: '西欧', profit: 480.06 },
    { year: '2011', area: '北美', profit: 1783.08 },
    { year: '2011', area: '非洲及中东', profit: 495.3 },
    { year: '2011', area: '中欧和东欧', profit: 259.08 },
    { year: '2011', area: '拉丁美洲', profit: 495.3 },
  ],
  encode: { x: 'year' },
  children: [
    {
      type: 'interval',
      transform: [{ type: 'stackY' }], // 添加堆叠转换
      coordinate: { type: 'theta', innerRadius: 0.5 },
      encode: { y: 'profit', color: 'area' },
      legend: {
        color: { position: 'bottom', layout: { justifyContent: 'center' } },
      },
      labels: [
        {
          text: (d, i, data) => {
            const total = data.reduce((acc, curr) => acc + curr.profit, 0);
            const percent = ((d.profit / total) * 100).toFixed(1);
            return `${percent}%`;
          },
          style: {
            fontSize: 10,
          },
        },
      ],
    },
  ],
});

chart.render();

环图与其他图表的对比

环图和饼图

  • 相似性:都用于展示分类数据的占比关系
  • 区别:
    • 环图中心留空,可以放置额外信息
    • 环图更强调弧长(周长),饼图更强调面积
    • 环图在多图对比时效果更好

环图和柱状图

  • 环图:更适合展示占比关系,强调部分与整体的关系
  • 柱状图:更适合展示精确的数值对比,特别是数值差异较小的情况

环图和南丁格尔玫瑰图

  • 环图:通过角度表示数值,内径固定
  • 南丁格尔玫瑰图:通过半径表示数值,更容易区分数值差异

相似图表

分类

© Copyright 2026 Ant Group Co., Ltd..备案号:京ICP备15032932号-38
全站搜索
文档与示例输入关键词开始搜索

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

↑↓选择↵打开Esc关闭