logo

G2

  • 图表介绍
  • 文档
  • 图表示例
  • 主题
  • 周边生态
  • 所有产品antv logo arrow
  • 5.3.3
  • 快速上手
  • 简介
    • 什么是 G2
    • 在前端框架中使用
    • Spec 和 API
  • 图表 API
  • 核心概念
    • 图表(Chart)
      • G2 图表组成
      • 如何使用图表
    • 标记(Mark)
      • 概览
      • area
      • box
      • boxplot
      • cell
      • chord
      • density
      • gauge
      • heatmap
      • image
      • interval
      • line
      • lineX
      • lineY
      • link
      • liquid
      • sunburst
      • point
      • polygon
      • range
      • rangeX
      • rangeY
      • rect
      • shape
      • text
      • vector
      • connector
      • wordCloud
    • 视图(View)
    • 数据(Data)
      • 概览
      • custom
      • ema
      • fetch
      • filter
      • fold
      • inline
      • join
      • kde
      • log
      • map
      • pick
      • rename
      • slice
      • sort
      • sortBy
    • 编码(Encode)
    • 比例尺(Scale)
      • 概览
      • band
      • linear
      • log
      • ordinal
      • point
      • quantile
      • quantize
      • sqrt
      • threshold
      • time
      • pow
    • 转换(Transform)
      • 概览
      • bin
      • binX
      • diffY
      • dodgeX
      • flexX
      • group
      • groupColor
      • groupX
      • groupY
      • jitter
      • jitterX
      • jitterY
      • normalizeY
      • pack
      • sample
      • select
      • selectX
      • selectY
      • sortColor
      • sortX
      • sortY
      • stackEnter
      • stackY
      • symmetryY
    • 坐标系(Coordinate)
      • 概览
      • fisheye
      • parallel
      • polar
      • theta
      • transpose
      • radial
      • cartesian3D
      • helix
    • 样式(Style)
    • 动画(Animate)
      • 概览
      • fadeIn
      • fadeOut
      • growInX
      • growInY
      • morphing
      • pathIn
      • scaleInX
      • scaleInY
      • scaleOutX
      • scaleOutY
      • waveIn
      • zoomIn
      • zoomOut
    • 状态(State)
    • 交互(Interaction)
      • 概览
      • brushAxisHighlight
      • brushHighlight
      • brushXHighlight
      • brushYHighlight
      • brushFilter
      • brushXFilter
      • brushYFilter
      • chartIndex
      • elementHighlight
      • elementHighlightByColor
      • elementHighlightByX
      • elementSelect
      • elementSelectByColor
      • elementSelectByX
      • fisheye
      • legendFilter
      • legendHighlight
      • poptip
      • scrollbarFilter
      • sliderFilter
    • 复合(Composition)
      • 概览
      • facetCircle
      • facetRect
      • repeatMatrix
      • spaceFlex
      • spaceLayer
      • timingKeyframe
    • 主题(Theme)
      • 概览
      • academy
      • classic
      • classicDark
    • 事件(Event)
    • 颜色映射(Color)
  • 图表组件
    • 标题(Title)
    • 坐标轴(Axis)
    • 图例(Legend)
    • 滚动条(Scrollbar)
    • 缩略轴(Slider)
    • 提示信息(Tooltip)
    • 数据标签(Label)
  • 进阶主题
    • 关系图(Graph)
      • forceGraph
      • pack
      • sankey
      • tree
      • treemap
    • 地图(Geo)
      • geoPath
      • geoView
    • 3D 图表(3D Chart)
      • 绘制 3D 图表
      • point3D
      • line3D
      • interval3D
      • surface3D
    • 插件扩展(Plugin)
      • renderer
      • rough
      • lottie
      • a11y
    • 按需打包
    • 设置纹理
    • 服务端渲染(SSR)
    • Spec 函数表达式支持 (5.3.0 支持)
  • 版本特性
    • 新版本特性
    • v4 升级 v5 指南
  • 常见问题 FAQ

band

上一篇
概览
下一篇
linear

资源

Ant Design
Galacea Effects
Umi-React 应用开发框架
Dumi-组件/文档研发工具
ahooks-React Hooks 库

社区

体验科技专栏
seeconfSEE Conf-蚂蚁体验科技大会

帮助

GitHub
StackOverflow

more products更多产品

Ant DesignAnt Design-企业级 UI 设计语言
yuque语雀-知识创作与分享工具
EggEgg-企业级 Node 开发框架
kitchenKitchen-Sketch 工具集
GalaceanGalacean-互动图形解决方案
xtech蚂蚁体验科技
© Copyright 2025 Ant Group Co., Ltd..备案号:京ICP备15032932号-38

Loading...

概述

band 比例尺是一种特殊的分类比例尺,它将离散的定义域(如类别、名称等)映射到连续的数值范围,并为每个类别分配相等宽度的区间(band)。与普通的 ordinal 比例尺不同,band 比例尺不仅关注点的位置,还关注每个类别占据的区间宽度。

band 比例尺的主要特点:

  • 将离散数据(如类别)映射到连续区间
  • 为每个类别分配等宽的区间(band)
  • 支持设置类别之间的内部间距(paddingInner)和外部间距(paddingOuter)
  • 常用于柱状图、条形图等需要表示类别数据的可视化中

在 G2 中,band 比例尺是柱状图(interval 标记)的默认 x 轴比例尺,它能够自动处理类别数据的映射和布局。

配置项

属性描述类型默认值必选
domain设置定义域数组,即输入数据的可能值number[] | string[] | Date[][]
range设置数据映射的值域范围,即输出的范围number[] | string[][0, 1]
unknown对于 undefined, NaN,null 空值,返回的数据anyundefined
round输出值是否进行四舍五入booleanfalse
paddingInner设置类别之间的内部间距,在 [0, 1] 范围内,值越大间距越大number0
paddingOuter设置两端的外部间距,在 [0, 1] 范围内,值越大间距越大number0
padding同时设置 paddingInner 和 paddingOuter 的快捷方式number0
align对齐方式,在 [0, 1] 范围内,0 表示左对齐,0.5 表示居中,1 表示右对齐number0.5
compare对定义域进行映射前的排序函数(a: string or number, b: string or number) => numberundefined
flex设置各类别的宽度分配比例number[][]

band 比例尺的布局原理

band 比例尺将连续的值域范围(range)划分为等宽的区间,每个区间对应定义域中的一个离散值。下图展示了 band 比例尺的布局原理:

|<------------------------------------------- range ------------------------------------------->|
| | | | | | |
|<--step*PO-->|<----bandWidth---->|<--step*PI-->|<----bandWidth---->|<--step*PI-->|<--step*PO-->|
| | ***************** | | ***************** | | |
| | ******* A ******* | | ******* B ******* | | |
| | ***************** | | ***************** | | |
| |<--------------step------------->| |
|-----------------------------------------------------------------------------------------------|

其中:

  • range: 整个比例尺的值域范围
  • bandWidth: 每个类别占据的宽度
  • step: 相邻类别中心点之间的距离
  • step*PI (paddingInner): 类别之间的内部间距
  • step*PO (paddingOuter): 两端的外部间距

带宽概念详解

什么是带宽(bandWidth)

带宽(bandWidth)是 band 比例尺中每个类别实际占据的宽度,它决定了柱状图中每个柱子的宽度、条形图中每个条的高度等。带宽是 band 比例尺区别于其他比例尺的核心概念。

带宽的计算公式

带宽的计算涉及多个参数,具体公式如下:

step = rangeLength / (domain.length - paddingInner + paddingOuter * 2)
bandWidth = step * (1 - paddingInner)

其中:

  • rangeLength: 值域的长度(range[1] - range[0])
  • domain.length: 定义域中类别的数量
  • paddingInner: 内部间距比例 [0, 1]
  • paddingOuter: 外部间距比例 [0, 1]

参数对带宽的影响

1. paddingInner 的影响

paddingInner 控制类别之间的间距,直接影响带宽大小:

import { Chart } from '@antv/g2';
const data = [
{ category: 'A', value: 100 },
{ category: 'B', value: 80 },
{ category: 'C', value: 120 },
{ category: 'D', value: 90 },
];
// 创建三个图表展示不同 paddingInner 的效果
const charts = [
{ paddingInner: 0, title: 'paddingInner: 0 (带宽最大)' },
{ paddingInner: 0.3, title: 'paddingInner: 0.3 (中等带宽)' },
{ paddingInner: 0.8, title: 'paddingInner: 0.8 (带宽最小)' },
];
charts.forEach((config, index) => {
const container = document.createElement('div');
container.style.width = '300px';
container.style.height = '200px';
container.style.display = 'inline-block';
container.style.margin = '10px';
document.getElementById('container').appendChild(container);
const chart = new Chart({
container,
autoFit: true,
});
chart.options({
type: 'interval',
data,
encode: {
x: 'category',
y: 'value',
color: 'category',
},
scale: {
x: {
type: 'band',
paddingInner: config.paddingInner,
paddingOuter: 0.1,
},
},
axis: {
x: { title: config.title },
y: { title: null },
},
});
chart.render();
});

2. paddingOuter 的影响

paddingOuter 控制两端的间距,间接影响带宽:

import { Chart } from '@antv/g2';
const data = [
{ category: 'A', value: 100 },
{ category: 'B', value: 80 },
{ category: 'C', value: 120 },
{ category: 'D', value: 90 },
];
const charts = [
{ paddingOuter: 0, title: 'paddingOuter: 0' },
{ paddingOuter: 0.3, title: 'paddingOuter: 0.3' },
{ paddingOuter: 0.6, title: 'paddingOuter: 0.6' },
];
charts.forEach((config, index) => {
const container = document.createElement('div');
container.style.width = '300px';
container.style.height = '200px';
container.style.display = 'inline-block';
container.style.margin = '10px';
document.getElementById('container').appendChild(container);
const chart = new Chart({
container,
autoFit: true,
});
chart.options({
type: 'interval',
data,
encode: {
x: 'category',
y: 'value',
color: 'category',
},
scale: {
x: {
type: 'band',
paddingInner: 0.2,
paddingOuter: config.paddingOuter,
},
},
axis: {
x: { title: config.title },
y: { title: null },
},
});
chart.render();
});

3. 类别数量的影响

类别数量越多,每个类别的带宽越小:

import { Chart } from '@antv/g2';
const datasets = [
{
data: [
{ category: 'A', value: 100 },
{ category: 'B', value: 80 },
],
title: '2个类别',
},
{
data: [
{ category: 'A', value: 100 },
{ category: 'B', value: 80 },
{ category: 'C', value: 120 },
{ category: 'D', value: 90 },
],
title: '4个类别',
},
{
data: [
{ category: 'A', value: 100 },
{ category: 'B', value: 80 },
{ category: 'C', value: 120 },
{ category: 'D', value: 90 },
{ category: 'E', value: 110 },
{ category: 'F', value: 95 },
],
title: '6个类别',
},
];
datasets.forEach((dataset, index) => {
const container = document.createElement('div');
container.style.width = '300px';
container.style.height = '200px';
container.style.display = 'inline-block';
container.style.margin = '10px';
document.getElementById('container').appendChild(container);
const chart = new Chart({
container,
autoFit: true,
});
chart.options({
type: 'interval',
data: dataset.data,
encode: {
x: 'category',
y: 'value',
color: 'category',
},
scale: {
x: {
type: 'band',
padding: 0.3, // 固定间距比例
},
},
axis: {
x: { title: dataset.title },
y: { title: null },
},
});
chart.render();
});

如何获取带宽值

在实际开发中,有时需要获取计算后的带宽值,可以通过以下方式:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ category: 'A', value: 100 },
{ category: 'B', value: 80 },
{ category: 'C', value: 120 },
{ category: 'D', value: 90 },
],
encode: {
x: 'category',
y: 'value',
color: 'category',
},
scale: {
x: {
type: 'band',
padding: 0.3,
},
},
});
chart.render().then(() => {
// 获取 x 轴的比例尺
const xScale = chart.getScale().x;
// 获取带宽值 - 使用无参数调用
const bandWidth = xScale.getBandWidth?.() ?? 0;
console.log('当前带宽值:', bandWidth);
// 也可以获取特定类别的带宽(如果需要)
const categoryABandWidth = xScale.getBandWidth?.(xScale.invert('A')) ?? 0;
console.log('类别A的带宽值:', categoryABandWidth);
// 计算步长值(相邻类别中心点的距离)
const domain = xScale.getOptions()?.domain || [];
const range = xScale.getOptions()?.range || [0, 1];
const rangeLength = range[1] - range[0];
const paddingInner = xScale.getOptions()?.paddingInner || 0;
const paddingOuter = xScale.getOptions()?.paddingOuter || 0;
const step = rangeLength / (domain.length - paddingInner + paddingOuter * 2);
console.log('当前步长值:', step);
// 在图表上显示带宽信息
const container = chart.getContainer();
const info = document.createElement('div');
info.style.position = 'absolute';
info.style.top = '10px';
info.style.left = '10px';
info.style.background = 'rgba(0,0,0,0.8)';
info.style.color = 'white';
info.style.padding = '5px 10px';
info.style.borderRadius = '4px';
info.style.fontSize = '12px';
info.innerHTML = `带宽: ${bandWidth.toFixed(2)}<br>步长: ${step.toFixed(2)}`;
container.appendChild(info);
});

带宽在不同图表类型中的应用

1. 柱状图中的带宽

在柱状图中,带宽直接决定柱子的宽度:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ month: '1月', sales: 1200 },
{ month: '2月', sales: 1100 },
{ month: '3月', sales: 1350 },
{ month: '4月', sales: 1280 },
],
encode: {
x: 'month',
y: 'sales',
color: 'month',
},
scale: {
x: {
type: 'band',
padding: 0.2, // 较小的间距,柱子较宽
},
},
style: {
stroke: '#fff',
strokeWidth: 2,
},
});
chart.render();

2. 条形图中的带宽

在条形图中,带宽决定条的高度:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
coordinate: { transform: [{ type: 'transpose' }] },
data: [
{ department: '销售部', count: 45 },
{ department: '市场部', count: 32 },
{ department: '技术部', count: 28 },
{ department: '人事部', count: 15 },
],
encode: {
x: 'department',
y: 'count',
color: 'department',
},
scale: {
x: {
type: 'band',
padding: 0.4, // 条之间有较大间距
},
},
});
chart.render();

3. 分组柱状图中的带宽

在分组柱状图中,整体的带宽会被子组的数量平分:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ quarter: 'Q1', type: '实际', value: 120 },
{ quarter: 'Q1', type: '预算', value: 100 },
{ quarter: 'Q2', type: '实际', value: 140 },
{ quarter: 'Q2', type: '预算', value: 130 },
{ quarter: 'Q3', type: '实际', value: 160 },
{ quarter: 'Q3', type: '预算', value: 150 },
],
encode: {
x: 'quarter',
y: 'value',
color: 'type',
},
transform: [{ type: 'dodgeX' }],
scale: {
x: {
type: 'band',
padding: 0.3, // 每个季度的整体带宽
},
},
});
chart.render();

带宽优化建议

1. 根据数据量调整间距

  • 少量数据(< 5 个类别):可以使用较小的 padding(0.1-0.3),让柱子更宽更突出
  • 中等数据(5-10 个类别):建议使用中等 padding(0.3-0.5),平衡可读性和视觉效果
  • 大量数据(> 10 个类别):可以使用较大的 padding(0.5-0.8),或考虑分页展示

2. 考虑图表容器大小

import { Chart } from '@antv/g2';
// 模拟不同容器宽度下的带宽效果
const widths = [300, 600, 900];
const data = Array.from({ length: 8 }, (_, i) => ({
category: `类别${String.fromCharCode(65 + i)}`,
value: Math.random() * 100 + 50,
}));
widths.forEach((width, index) => {
const container = document.createElement('div');
container.style.width = `${width}px`;
container.style.height = '200px';
container.style.display = 'inline-block';
container.style.margin = '10px';
container.style.border = '1px solid #ccc';
document.getElementById('container').appendChild(container);
const chart = new Chart({
container,
width,
height: 200,
});
chart.options({
type: 'interval',
data,
encode: {
x: 'category',
y: 'value',
color: 'category',
},
scale: {
x: {
type: 'band',
padding: 0.2, // 固定间距比例
},
},
axis: {
x: { title: `容器宽度: ${width}px` },
y: { title: null },
},
});
chart.render();
});

3. 响应式带宽设计

对于需要适配不同屏幕尺寸的图表,可以动态调整 padding:

// 根据容器宽度动态调整 padding
function getResponsivePadding(containerWidth, dataLength) {
const baseWidth = containerWidth / dataLength;
if (baseWidth > 100) {
return 0.6; // 容器很宽时,增加间距
} else if (baseWidth > 50) {
return 0.4; // 中等宽度
} else {
return 0.2; // 容器较窄时,减少间距
}
}

通过深入理解带宽概念,你可以更好地控制图表的视觉效果,创建出既美观又实用的数据可视化作品。

使用示例

基础柱状图

band 比例尺最常见的应用是柱状图,通过设置 padding 可以控制柱子之间的间距:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
],
encode: {
x: 'genre',
y: 'sold',
color: 'genre',
},
scale: {
x: {
type: 'band',
padding: 0.5, // 设置柱子之间的间距
},
},
});
chart.render();

分组柱状图

在分组柱状图中,band 比例尺与 dodgeX 转换一起使用,可以创建分组效果:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ month: '1月', value: 86.5, type: '降水量' },
{ month: '2月', value: 86.5, type: '降水量' },
{ month: '3月', value: 86.5, type: '降水量' },
{ month: '4月', value: 86.5, type: '降水量' },
{ month: '5月', value: 86.5, type: '降水量' },
{ month: '6月', value: 86.5, type: '降水量' },
{ month: '1月', value: 30.5, type: '蒸发量' },
{ month: '2月', value: 30.5, type: '蒸发量' },
{ month: '3月', value: 30.5, type: '蒸发量' },
{ month: '4月', value: 30.5, type: '蒸发量' },
{ month: '5月', value: 30.5, type: '蒸发量' },
{ month: '6月', value: 30.5, type: '蒸发量' },
],
encode: {
x: 'month',
y: 'value',
color: 'type',
},
transform: [{ type: 'dodgeX' }],
scale: {
x: {
type: 'band',
padding: 0.2, // 设置组间距
},
},
});
chart.render();

自定义柱宽

使用 flex 属性可以为不同类别设置不同的宽度比例:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ country: 'USA', value: 12394, gdp: 21.4 },
{ country: 'China', value: 9608, gdp: 14.7 },
{ country: 'Japan', value: 4731, gdp: 5.0 },
{ country: 'Germany', value: 3861, gdp: 4.2 },
{ country: 'UK', value: 2678, gdp: 2.9 },
],
encode: {
x: 'country',
y: 'value',
color: 'country',
},
scale: {
x: {
type: 'band',
padding: 0.4,
flex: [2.14, 1.47, 0.5, 0.42, 0.29], // 根据 GDP 设置不同宽度
},
},
});
chart.render();

条形图(横向柱状图)

通过坐标系转置,可以创建条形图,band 比例尺同样适用:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
coordinate: { transform: [{ type: 'transpose' }] },
data: [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
],
encode: {
x: 'genre',
y: 'sold',
color: 'genre',
},
scale: {
x: {
type: 'band',
padding: 0.5,
},
},
});
chart.render();

堆叠柱状图

使用 stackY 转换可以创建堆叠柱状图,展示各部分的累积效果:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ quarter: 'Q1', department: '销售部', value: 120 },
{ quarter: 'Q1', department: '市场部', value: 100 },
{ quarter: 'Q1', department: '技术部', value: 80 },
{ quarter: 'Q2', department: '销售部', value: 140 },
{ quarter: 'Q2', department: '市场部', value: 110 },
{ quarter: 'Q2', department: '技术部', value: 90 },
{ quarter: 'Q3', department: '销售部', value: 160 },
{ quarter: 'Q3', department: '市场部', value: 95 },
{ quarter: 'Q3', department: '技术部', value: 120 },
{ quarter: 'Q4', department: '销售部', value: 180 },
{ quarter: 'Q4', department: '市场部', value: 100 },
{ quarter: 'Q4', department: '技术部', value: 130 },
],
encode: {
x: 'quarter',
y: 'value',
color: 'department',
},
transform: [{ type: 'stackY' }],
scale: {
x: {
type: 'band',
padding: 0.3,
},
},
});
chart.render();

不等宽柱状图(使用 flexX 转换)

根据指定字段的值自动调整柱子宽度,适合表示权重或比例关系:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ region: '华东', sales: 8500, population: 2.4 },
{ region: '华南', sales: 6200, population: 1.8 },
{ region: '华北', sales: 7800, population: 2.1 },
{ region: '西南', sales: 4500, population: 1.2 },
{ region: '东北', sales: 3200, population: 0.9 },
{ region: '西北', sales: 2800, population: 0.7 },
],
encode: {
x: 'region',
y: 'sales',
color: 'region',
},
transform: [{ type: 'flexX', field: 'population' }], // 根据人口数据调整柱宽
scale: {
x: {
type: 'band',
padding: 0.2,
},
},
});
chart.render();

时间序列柱状图

处理时间数据时,band 比例尺能很好地处理时间间隔的可视化:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ month: '2024-01', sales: 1200 },
{ month: '2024-02', sales: 1100 },
{ month: '2024-03', sales: 1350 },
{ month: '2024-04', sales: 1280 },
{ month: '2024-05', sales: 1400 },
{ month: '2024-06', sales: 1520 },
{ month: '2024-07', sales: 1680 },
{ month: '2024-08', sales: 1590 },
{ month: '2024-09', sales: 1450 },
{ month: '2024-10', sales: 1380 },
{ month: '2024-11', sales: 1250 },
{ month: '2024-12', sales: 1600 },
],
encode: {
x: 'month',
y: 'sales',
color: (d) => (d.sales > 1500 ? 'high' : d.sales > 1300 ? 'medium' : 'low'),
},
scale: {
x: {
type: 'band',
padding: 0.1,
},
color: {
domain: ['low', 'medium', 'high'],
range: ['#faad14', '#1890ff', '#52c41a'],
},
},
});
chart.render();

多级分类柱状图

展示具有层次结构的分类数据:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ category: '服装-男装', subcategory: '衬衫', value: 850 },
{ category: '服装-男装', subcategory: '裤子', value: 750 },
{ category: '服装-男装', subcategory: '外套', value: 650 },
{ category: '服装-女装', subcategory: '连衣裙', value: 950 },
{ category: '服装-女装', subcategory: '上衣', value: 800 },
{ category: '服装-女装', subcategory: '裙子', value: 700 },
{ category: '电子-手机', subcategory: 'iPhone', value: 1200 },
{ category: '电子-手机', subcategory: '华为', value: 1100 },
{ category: '电子-手机', subcategory: '小米', value: 900 },
{ category: '电子-电脑', subcategory: '笔记本', value: 1500 },
{ category: '电子-电脑', subcategory: '台式机', value: 800 },
{ category: '电子-电脑', subcategory: '平板', value: 600 },
],
encode: {
x: 'category',
y: 'value',
color: 'subcategory',
},
transform: [{ type: 'dodgeX' }],
scale: {
x: {
type: 'band',
padding: 0.4, // 较大的间距区分不同主类别
paddingInner: 0.3, // 内部间距
paddingOuter: 0.1, // 外部间距
},
},
});
chart.render();

对比分析柱状图

使用 paddingInner 和 paddingOuter 精确控制间距,适合对比分析:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: [
{ product: '产品A', current: 320, target: 400 },
{ product: '产品B', current: 280, target: 350 },
{ product: '产品C', current: 410, target: 450 },
{ product: '产品D', current: 180, target: 250 },
{ product: '产品E', current: 350, target: 380 },
].flatMap((d) => [
{ product: d.product, type: '当前销量', value: d.current },
{ product: d.product, type: '目标销量', value: d.target },
]),
encode: {
x: 'product',
y: 'value',
color: 'type',
},
transform: [{ type: 'dodgeX' }],
scale: {
x: {
type: 'band',
paddingInner: 0.2, // 组内间距较小
paddingOuter: 0.3, // 组间间距较大
},
color: {
domain: ['当前销量', '目标销量'],
range: ['#1890ff', '#52c41a'],
},
},
});
chart.render();

动态柱宽柱状图

结合 compare 函数对数据进行排序,并使用不同的柱宽策略:

import { Chart } from '@antv/g2';
const data = [
{ brand: '苹果', market_share: 23.4, revenue: 365 },
{ brand: '三星', market_share: 20.1, revenue: 220 },
{ brand: '华为', market_share: 15.8, revenue: 180 },
{ brand: '小米', market_share: 12.3, revenue: 120 },
{ brand: 'OPPO', market_share: 8.9, revenue: 95 },
{ brand: 'vivo', market_share: 7.2, revenue: 85 },
{ brand: '其他', market_share: 12.3, revenue: 150 },
];
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data,
encode: {
x: 'brand',
y: 'market_share',
color: 'brand',
},
scale: {
x: {
type: 'band',
padding: 0.2,
compare: (a, b) => {
// 按市场份额降序排列
const dataA = data.find((d) => d.brand === a);
const dataB = data.find((d) => d.brand === b);
return (dataB?.market_share || 0) - (dataA?.market_share || 0);
},
flex: [2.34, 2.01, 1.58, 1.23, 0.89, 0.72, 1.23], // 根据市场份额设置宽度
},
},
});
chart.render();

高级应用场景

瀑布图(使用 band 比例尺)

展示数值的逐步累积变化过程:

import { Chart } from '@antv/g2';
// 瀑布图数据处理
const rawData = [
{ name: '期初余额', value: 1000, type: 'start' },
{ name: '收入增加', value: 500, type: 'positive' },
{ name: '成本支出', value: -200, type: 'negative' },
{ name: '税费支出', value: -150, type: 'negative' },
{ name: '其他收入', value: 100, type: 'positive' },
{ name: '期末余额', value: 1250, type: 'end' },
];
// 计算累积值
let cumulative = 0;
const data = rawData.map((d, i) => {
if (d.type === 'start' || d.type === 'end') {
const result = { ...d, start: 0, end: d.value };
cumulative = d.value;
return result;
} else {
const start = cumulative;
cumulative += d.value;
return { ...d, start, end: cumulative };
}
});
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'interval',
data: data.flatMap((d) => [
{ name: d.name, value: d.end - d.start, position: d.start, type: d.type },
]),
encode: {
x: 'name',
y: ['position', (d) => d.position + d.value],
color: 'type',
},
scale: {
x: {
type: 'band',
padding: 0.4,
},
color: {
domain: ['start', 'positive', 'negative', 'end'],
range: ['#722ed1', '#52c41a', '#ff4d4f', '#1890ff'],
},
},
});
chart.render();

分面柱状图

使用 band 比例尺结合分面布局展示多维数据:

import { Chart } from '@antv/g2';
const chart = new Chart({
container: 'container',
autoFit: true,
});
chart.options({
type: 'facetRect',
data: [
{ region: '北区', quarter: 'Q1', product: '产品A', sales: 120 },
{ region: '北区', quarter: 'Q1', product: '产品B', sales: 100 },
{ region: '北区', quarter: 'Q1', product: '产品C', sales: 80 },
{ region: '北区', quarter: 'Q2', product: '产品A', sales: 140 },
{ region: '北区', quarter: 'Q2', product: '产品B', sales: 110 },
{ region: '北区', quarter: 'Q2', product: '产品C', sales: 90 },
{ region: '南区', quarter: 'Q1', product: '产品A', sales: 150 },
{ region: '南区', quarter: 'Q1', product: '产品B', sales: 130 },
{ region: '南区', quarter: 'Q1', product: '产品C', sales: 110 },
{ region: '南区', quarter: 'Q2', product: '产品A', sales: 170 },
{ region: '南区', quarter: 'Q2', product: '产品B', sales: 140 },
{ region: '南区', quarter: 'Q2', product: '产品C', sales: 120 },
],
encode: { x: 'region', y: 'quarter' },
children: [
{
type: 'interval',
encode: {
x: 'product',
y: 'sales',
color: 'product',
},
scale: {
x: {
type: 'band',
padding: 0.3,
},
},
},
],
});
chart.render();

常见问题

如何调整柱子的宽度?

可以通过设置 padding 属性来调整柱子之间的间距,从而间接调整柱子的宽度。padding 值越大,柱子越窄;值越小,柱子越宽。

chart.interval().encode('x', 'type').encode('y', 'sale').scale('x', {
type: 'band',
padding: 0.5, // 值范围在 [0, 1] 之间
});

band 比例尺与 point 比例尺的区别是什么?

  • band 比例尺:为每个类别分配一个区间(带宽),适合柱状图等需要占据宽度的图表
  • point 比例尺:为每个类别分配一个点,相当于 bandWidth = 0 的 band 比例尺,适合散点图等只需要点位置的图表

如何设置不同宽度的柱子?

有两种方法:

  1. 使用 flex 属性为不同类别设置不同的宽度比例
  2. 使用 flexX 转换,根据指定字段的值自动设置柱宽
// 方法1:使用 flex 属性
chart
.interval()
.encode('x', 'country')
.encode('y', 'value')
.scale('x', {
type: 'band',
flex: [2, 1, 3, 1.5], // 手动设置宽度比例
});
// 方法2:使用 flexX 转换
chart
.interval()
.encode('x', 'country')
.encode('y', 'value')
.transform({ type: 'flexX', field: 'gdp' }); // 根据 gdp 字段自动设置宽度