Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ G2Plot v3 covers 36+ common chart types. PRs for more types are welcome:
|---|---|---|---|---|
| line | column | pie | scatter | dual-axes |
| area | bar | | heatmap | funnel |
| | | | | radar |
| | | | beeswarm | radar |


## 🏗️ How It Works
Expand Down
162 changes: 162 additions & 0 deletions charts/beeswarm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Beeswarm 熊蜂图

> 组件用途:展示分类类别下数值的分布情况,通过点的位置和密度直观展示数据分布,适合小到中等规模的分类数据集。

## 何时使用

- **分类分布展示**:查看不同类别下数值的分布情况,如不同实验组的基因表达量、不同处理方案的效果分布
- **小规模数据可视化**:数据点 ≤ 200 条,希望展示每个数据点的具体位置和分布密度
- **替代箱线图**:当需要展示具体数据点而非五数概括时,或当数据量适中不想丢失个体信息时
- **多类别比较**:比较多个类别的数值分布差异

## 何时不用

- 大规模数据(> 500 条):点会重叠过多,视觉效果差 → 使用 violin 小提琴图 或 histogram 直方图
- 连续二维空间的点密度分布:用 `type: 'heatmap'` 渐变热力图
- 时间序列趋势:用 `type: 'line'` 折线图
- 类别间纯数值大小对比:用 `type: 'column'` 柱状图

## 数据要求

- **长表数据**,每行一个数据点,包含类别字段和数值字段
- `category` 字段:类别标识符(字符串),表示数据属于哪个分组
- `value` 字段:数值(number),表示要展示的测量值
- **建议**:每个类别建议 5-50 个数据点,点过多时建议抽样或使用抖动策略

```ts
const data = [
{ category: 'Control', value: 12.5 },
{ category: 'Control', value: 15.3 },
{ category: 'Control', value: 11.8 },
{ category: 'Treatment', value: 22.1 },
{ category: 'Treatment', value: 19.7 },
{ category: 'Treatment', value: 23.4 },
];
```

## 基础实现(G2 v5)

Beeswarm 图通过 `type: 'point'` 标记展示个体数据点,类别通过 x 轴编码,数值通过 y 轴编码。点在类别内部通过轻微抖动(x jitter)防止重叠。

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

const data = [
{ category: 'Control', value: 12.5 },
{ category: 'Control', value: 15.3 },
{ category: 'Control', value: 11.8 },
{ category: 'Treatment', value: 22.1 },
{ category: 'Treatment', value: 19.7 },
{ category: 'Treatment', value: 23.4 },
{ category: 'Treatment', value: 21.0 },
{ category: 'Treatment', value: 24.5 },
];

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

chart.options({
type: 'point',
data,
encode: {
x: 'category',
y: 'value',
},
// 点的样式自定义
style: {
fill: '#5B8FF9',
stroke: '#1890FF',
lineWidth: 2,
},
// 坐标轴配置
axis: {
x: { title: '实验组' },
y: { title: '数值', min: 0 },
},
// 图例配置
legend: false,
});

chart.render();
```

## 常见变体

| 变体 | 关键改动 | 完整案例 |
|---|---|---|
| 带数据标签 | `labels: [{ text: 'value', position: 'top' }]` | [with-label.ts](../examples/beeswarm/with-label.ts) |
| 多系列分组 | `encode.color: 'group'`,通过颜色分组不同实验 | [multi-group.ts](../examples/beeswarm/multi-group.ts) |
| 自定义点大小 | `encode.size: 'value'`,根据数值大小变点大小 | [size-variable.ts](../examples/beeswarm/size-variable.ts) |
| 水平展示 | `coordinate: { type: 'rect' }` 或交换 x/y 字段 | [horizontal.ts](../examples/beeswarm/horizontal.ts) |

### 带数据标签核心差异

```ts-snippet
chart.options({
type: 'point',
data,
encode: { x: 'category', y: 'value' },
labels: [{ text: 'value', position: 'top', style: { fontSize: 10 } }],
});
```

### 多系列分组核心差异(数据需含 `group` 字段)

```ts-snippet
chart.options({
type: 'point',
data,
encode: { x: 'category', y: 'value', color: 'group' },
});
```

## 样式自定义

常用视觉定制项(以下写法均经 `@antv/g2` ^5 类型校验),完整示例见 [with-label.ts](../examples/beeswarm/with-label.ts):

| 定制项 | 写法 | 说明 |
|---|---|---|
| 点的颜色 | `style: { fill: '#5B8FF9' }` | 固定点颜色 |
| 点的颜色 scales | `scale: { color: { range: ['#5B8FF9', '#5AD8A6'] } }` | 多系列按序着色 |
| 点的大小 | `style: { size: 6 }` | 固定点大小 |
| 点的大小 scales | `encode.size: 'value'` | 根据数值大小变点大小 |
| 透明度 | `style: { opacity: 0.7 }` | 整体透明度 |
| 坐标轴标题 | `axis: { x: { title: '类别' } }` | x/y 轴标题 |
| 刻度标签字体 | `axis.x.labelFontSize: 10` | x 轴刻度字体大小 |
| 关闭坐标轴 | `axis: { x: false }` | 关闭 x 轴 |
| 关闭图例 | `legend: false` | 关闭图例 |

### 图表标题与组件文字样式

`title: { title: '...', subtitle: '...', align: 'left' }`,一行切换整体配色。暗色场景用 `theme: 'classicDark'`。

### 内置主题

`theme: 'light' | 'dark' | 'classic' | 'classicDark' | 'academy'`,一行切换整体配色。

## 易错点(v4 → v5)

| ❌ 错误(幻觉高发) | ✅ 正确 |
|---|---|
| `.position('category*value')` | `.encode('x', 'category').encode('y', 'value')` |
| `import { BeeSwarm } from '@antv/g2plot'` | `import { Chart } from '@antv/g2'` + `type: 'point'` |
| `new BeeSwarm('container', {...})`(不存在的组件) | `new Chart({ container })` + `chart.options({ type: 'point', ... })` |
| `size: 'value'`(未编码) | `encode.size: 'value'` 或 `style: { size: number }` |
| 点重叠严重未抖动 | 需要配合数据预处理或 `transform` 进行抖动处理 |
| `chart.source(data)`(v4) | `chart.options({ data })` |

更多对照见 [v4-to-v5-migration.md](../references/v4-to-v5-migration.md)。

## 完整案例

每个案例的元信息(场景与关键配置),代码均通过 `npm run validate` 校验:

| 案例 | 场景 | 关键配置 |
|---|---|---|
| [basic.ts](../examples/beeswarm/basic.ts) | 最简 beeswarm 图,单类别分布 | `type: 'point'` + `encode: { x, y }` |
| [with-label.ts](../examples/beeswarm/with-label.ts) | 点旁标注数值 | `labels` + `encode x/y` |
| [multi-group.ts](../examples/beeswarm/multi-group.ts) | 多组别对比(颜色分组) | `encode.color: 'group'` |
| [size-variable.ts](../examples/beeswarm/size-variable.ts) | 点大小反映数值大小 | `encode.size: 'value'` |
| [horizontal.ts](../examples/beeswarm/horizontal.ts) | 水平展示形式 | 坐标轴互换 |
10 changes: 10 additions & 0 deletions evals/cases/beeswarm.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{"id": "beeswarm-basic", "prompt": "展示三个不同年龄组的血压分布数据,每个组别约 8-10 个测量值,希望看到每个数据点的具体位置", "groundTruth": "使用 type: 'point';x 轴编码 category 字段,y 轴编码 value 字段;每个类别展示 8-10 个数据点,展示分布情况而非仅显示均值"}
{"id": "beeswarm-labels", "prompt": "神经科学实验中需要展示不同刺激条件下的反应时间分布,并要求每个数据点都标出具体毫秒数", "groundTruth": "包含 labels 配置,text 指向 value 字段,position 为 'top';type: 'point' + encode x/y,确保数据点数量适中(≤ 40 个)以免标签重叠"}
{"id": "beeswarm-multi-group", "prompt": "对比四种不同药物治疗方案的有效性,每种方案有 6-8 名患者的有效性评分数据", "groundTruth": "encode.color映射group字段展示四个治疗组,type: 'point'配合色彩分组, legend.position设为'top'以便对比"}
{"id": "beeswarm-horizontal", "prompt": "类别名称较长(如‘北京市、上海市、广州市、深圳市'),希望水平展示以节省垂直空间", "groundTruth": "交换x/y字段编码,或使用 coordinate 配置实现横向展示,类别标签位于左侧 y 轴"}
{"id": "beeswarm-size-variable", "prompt": "气候数据可视化,想让点的大小反映降水量的大小,大点表示雨水多,小点表示雨水少", "groundTruth": "encode.size映射value字段,根据数值大小自动调整点的尺寸,配合说明文字说明‘点大=雨水多’"}
{"id": "beeswarm-color-scale", "prompt": "展示五个不同城市的空气质量指数分布,想要颜色深浅反映AQI数值的高低", "groundTruth": "encode.color映射value字段,配合scale.color.type: 'sequential'和palette设置发散/顺序色阶,颜色深浅反映AQI数值"}
{"id": "beeswarm-axis-custom", "prompt": "需要自定义坐标轴标题,x轴写‘处理方案’,y轴写‘反应时间(ms)’,并希望y轴从0开始固定刻度", "groundTruth": "axis.x.title设为'处理方案',axis.y.title设为'反应时间(ms)',axis.y.min设为0确保从0开始"}
{"id": "beeswarm-theme-dark", "prompt": "深色模式下的科研数据展示,需要在背景深色的环境下清晰展示数据分布", "groundTruth": "设置theme: 'classicDark'或'dark',坐标轴、图例、标题文字颜色会自动适配暗色背景"}
{"id": "beeswarm-tooltip", "prompt": "医学会议海报展示,tooltip需要显示类别名称和具体的数值分数", "groundTruth": "tooltip.title设为类别字段名,tooltip.items包含channel: 'y'的name: '数值'配置,悬停显示具体分数"}
{"id": "beeswarm-null-handle", "prompt": "有些数据点缺失或测量失败,希望缺失的数据点不显示或以不同方式标记", "groundTruth": "数据中对应行的value字段传null,或使用transform过滤掉null行;line mark默认遇null断开,point mark视渲染表现而定"}
44 changes: 44 additions & 0 deletions examples/beeswarm/basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Chart } from '@antv/g2';

/**
* 基础熊蜂图
* 场景:展示不同实验组的数值分布,每个数据点均可见
*/
const data = [
{ category: 'Control', value: 12.5 },
{ category: 'Control', value: 15.3 },
{ category: 'Control', value: 11.8 },
{ category: 'Control', value: 13.2 },
{ category: 'Treatment', value: 22.1 },
{ category: 'Treatment', value: 19.7 },
{ category: 'Treatment', value: 23.4 },
{ category: 'Treatment', value: 21.0 },
{ category: 'Treatment', value: 24.5 },
{ category: 'Treatment', value: 18.8 },
];

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

chart.options({
type: 'point',
data,
encode: {
x: 'category',
y: 'value',
},
style: {
fill: '#5B8FF9',
stroke: '#1890FF',
lineWidth: 2,
},
axis: {
x: { title: '实验组' },
y: { title: '数值', min: 0 },
},
legend: false,
});

chart.render();
52 changes: 52 additions & 0 deletions examples/beeswarm/multi-group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Chart } from '@antv/g2';

/**
* 多组别对比的熊蜂图
* 场景:通过颜色分组展示多个实验/处理方案的数值分布差异
*/
const data = [
{ category: 'Control', value: 12.5, group: 'A' },
{ category: 'Control', value: 15.3, group: 'A' },
{ category: 'Control', value: 11.8, group: 'B' },
{ category: 'Control', value: 13.2, group: 'B' },
{ category: 'Treatment', value: 22.1, group: 'A' },
{ category: 'Treatment', value: 19.7, group: 'A' },
{ category: 'Treatment', value: 23.4, group: 'B' },
{ category: 'Treatment', value: 21.0, group: 'B' },
{ category: 'Treatment', value: 24.5, group: 'A' },
{ category: 'Treatment', value: 18.8, group: 'B' },
];

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

chart.options({
type: 'point',
data,
encode: {
x: 'category',
y: 'value',
color: 'group',
},
style: {
strokeWidth: 2,
},
axis: {
x: { title: '实验组' },
y: { title: '数值', min: 0 },
},
legend: {
color: { position: 'top' },
},
tooltip: {
title: '类别',
items: [
{ channel: 'color', name: '组别' },
{ channel: 'y', name: '数值' },
],
},
});

chart.render();
51 changes: 51 additions & 0 deletions examples/beeswarm/with-label.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Chart } from '@antv/g2';

/**
* 带数据标签的熊蜂图
* 场景:每个数据点旁标注具体数值,适合数据量适中(≤ 50 个点)的分布展示
*/
const data = [
{ category: 'Control', value: 12.5 },
{ category: 'Control', value: 15.3 },
{ category: 'Control', value: 11.8 },
{ category: 'Control', value: 13.2 },
{ category: 'Treatment', value: 22.1 },
{ category: 'Treatment', value: 19.7 },
{ category: 'Treatment', value: 23.4 },
{ category: 'Treatment', value: 21.0 },
{ category: 'Treatment', value: 24.5 },
{ category: 'Treatment', value: 18.8 },
];

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

chart.options({
type: 'point',
data,
encode: {
x: 'category',
y: 'value',
},
style: {
fill: '#5B8FF9',
stroke: '#1890FF',
lineWidth: 2,
},
labels: [
{ text: 'value', position: 'top', style: { fontSize: 10 } },
],
axis: {
x: { title: '实验组' },
y: { title: '数值', min: 0 },
},
legend: false,
tooltip: {
title: '类别',
items: [{ channel: 'y', name: '数值' }],
},
});

chart.render();
1 change: 1 addition & 0 deletions skills/g2plot-v3/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ description: G2Plot v3 可视化组件库,提示词即组件。当用户需要
| 两个量级不同的指标 | 时间 x + 双数值 y | dual-axes 双轴图 | [charts/dual-axes.md](../../charts/dual-axes.md) |
| 多维能力对比 | 多维度数值 | radar 雷达图 | [charts/radar.md](../../charts/radar.md) |
| 密度/频率分布 | 两个类别 + 数值 | heatmap 热力图 | [charts/heatmap.md](../../charts/heatmap.md) |
| 分类分布展示 | 单类别数值分布 | beeswarm 熊蜂图 | [charts/beeswarm.md](../../charts/beeswarm.md) |
| 流程转化 | 阶段 + 数值 | funnel 漏斗图 | [charts/funnel.md](../../charts/funnel.md) |

选型拿不准时,读对应 `charts/<chart>.md` 的「何时使用 / 何时不用」小节。
Expand Down