ECharts encode映射机制完全指南
文档类型: 深度技术文档
难度等级: ⭐⭐⭐⭐
源码版本: ECharts 5.x
本文行数: 约600行
📋 目录
🎯 encode基础概念
什么是encode?
encode是ECharts 5引入的数据映射机制,用于明确指定数据的哪个维度映射到哪个视觉通道。
typescript
// 传统方式 - 隐式映射
series: {
type: 'scatter',
data: [[10, 20], [30, 40]] // 默认[0]→x, [1]→y
}
// encode方式 - 显式映射
series: {
type: 'scatter',
data: [[10, 20, 30], [40, 50, 60]],
encode: {
x: 0, // 第0维 → x轴
y: 1, // 第1维 → y轴
value: 2 // 第2维 → tooltip显示
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
优势:
- ✅ 清晰表达数据映射关系
- ✅ 支持高维数据可视化
- ✅ 灵活控制视觉编码
📊 维度映射详解
坐标系通道
x / y - 直角坐标系
typescript
const option = {
dataset: {
source: [
['日期', '销量', '利润', '地区'],
['2024-01', 100, 30, '华东'],
['2024-02', 120, 35, '华北']
]
},
xAxis: { type: 'category' },
yAxis: {},
series: [{
type: 'bar',
encode: {
x: '日期', // 使用'日期'列作为x轴
y: '销量' // 使用'销量'列作为y轴
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
angle / radius - 极坐标系
typescript
const option = {
polar: {},
angleAxis: {},
radiusAxis: {},
series: [{
type: 'scatter',
coordinateSystem: 'polar',
data: [[30, 5], [60, 8], [90, 12]],
encode: {
angle: 0, // 第0维 → 角度
radius: 1 // 第1维 → 半径
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
视觉通道
color - 颜色映射
typescript
const option = {
visualMap: {
min: 0,
max: 100,
inRange: {
color: ['#313695', '#4575b4', '#74add1', '#fdae61', '#d73027']
}
},
series: [{
type: 'scatter',
data: [
[10, 20, 85],
[30, 40, 92],
[50, 60, 78]
],
encode: {
x: 0,
y: 1,
color: 2 // 第2维映射到颜色
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
symbolSize - 符号大小
typescript
const option = {
series: [{
type: 'scatter',
data: [
[10, 20, 30], // [x, y, 气泡大小]
[40, 50, 80],
[70, 80, 120]
],
encode: {
x: 0,
y: 1,
symbolSize: 2 // 第2维控制气泡大小
},
symbolSize: (value: number) => {
return value / 5; // 缩放因子
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
tooltip - 自定义tooltip内容
typescript
const option = {
series: [{
type: 'scatter',
data: [
[10, 20, '产品A', 85],
[30, 40, '产品B', 92],
[50, 60, '产品C', 78]
],
encode: {
x: 0,
y: 1,
tooltip: [2, 3] // tooltip显示产品名称和分数
}
}]
};
// tooltip显示:
// 产品A: 85
// 产品B: 921
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
🎨 特殊通道用法
itemName - 数据项名称
typescript
const option = {
dataset: {
source: [
['姓名', '数学', '英语'],
['张三', 90, 85],
['李四', 88, 92]
]
},
series: [{
type: 'bar',
encode: {
x: '姓名', // 使用姓名列作为x轴
y: '数学', // 使用数学成绩作为y轴
itemName: 0 // 数据项名称也是姓名
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
groupId - 分组ID (用于graph、sankey)
typescript
const option = {
series: [{
type: 'graph',
data: [
{ name: '节点1', groupId: 0 },
{ name: '节点2', groupId: 0 },
{ name: '节点3', groupId: 1 }
],
links: [],
encode: {
groupId: 'groupId' // 按groupId分组着色
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
latitude / longitude - 地理坐标
typescript
const option = {
geo: {
map: 'china'
},
series: [{
type: 'effectScatter',
coordinateSystem: 'geo',
data: [
{ name: '北京', value: [116.4074, 39.9042, 100] },
{ name: '上海', value: [121.4737, 31.2304, 120] }
],
encode: {
longitude: 0, // 经度
latitude: 1, // 纬度
value: 2 // 数值
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
📦 dataset配合使用
基础映射
typescript
const option = {
dataset: {
source: [
['月份', '销售额', '利润', '增长率'],
['1月', 100, 30, 5],
['2月', 120, 35, 8],
['3月', 150, 45, 12]
]
},
xAxis: { type: 'category' },
yAxis: {},
series: [
{
type: 'bar',
encode: {
x: '月份',
y: '销售额'
}
},
{
type: 'line',
yAxisIndex: 1, // 使用第二个y轴
encode: {
x: '月份',
y: '增长率'
}
}
]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
多系列共享数据
typescript
const option = {
legend: {},
dataset: {
source: [
['季度', 'Q1', 'Q2', 'Q3', 'Q4'],
['产品A', 100, 120, 150, 180],
['产品B', 80, 95, 110, 130],
['产品C', 120, 140, 160, 190]
]
},
xAxis: { type: 'category' },
yAxis: {},
series: [
{
type: 'bar',
name: '产品A',
encode: {
x: '季度',
y: 'Q1'
}
},
{
type: 'bar',
name: '产品B',
encode: {
x: '季度',
y: 'Q2'
}
},
{
type: 'bar',
name: '产品C',
encode: {
x: '季度',
y: 'Q3'
}
}
]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
动态列映射
typescript
interface ChartConfig {
xColumn: string;
yColumn: string;
chartType: 'bar' | 'line';
}
function createChart(config: ChartConfig) {
return {
dataset: {
source: fetchData() // 从API获取
},
xAxis: { type: 'category' },
yAxis: {},
series: [{
type: config.chartType,
encode: {
x: config.xColumn,
y: config.yColumn
}
}]
};
}
// 用户可配置
const userConfig: ChartConfig = {
xColumn: '日期',
yColumn: '访问量',
chartType: 'line'
};
chart.setOption(createChart(userConfig));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
💻 实战案例
案例1: 五维数据可视化
typescript
// 数据集: [年份, GDP, 人口, 面积, 大洲]
const data = [
[2020, 147000, 140000, 960, '亚洲'],
[2020, 21400, 330, 983, '北美洲'],
[2020, 5100, 67, 242, '欧洲']
];
const option = {
tooltip: {},
visualMap: {
dimension: 4, // 按大洲着色
categories: ['亚洲', '北美洲', '欧洲'],
inRange: {
color: ['#5470c6', '#91cc75', '#fac858']
}
},
xAxis: {
name: 'GDP(亿美元)',
type: 'value'
},
yAxis: {
name: '人口(万人)',
type: 'value'
},
series: [{
type: 'scatter',
data: data,
encode: {
x: 1, // GDP → x轴
y: 2, // 人口 → y轴
symbolSize: 3, // 面积 → 气泡大小
color: 4, // 大洲 → 颜色
tooltip: [0, 1, 2, 3, 4] // 显示所有维度
},
label: {
show: true,
formatter: (params: any) => {
const data = params.data;
return `${data[0]}年`;
}
}
}]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
可视化效果:
- X轴: GDP
- Y轴: 人口
- 气泡大小: 面积
- 颜色: 大洲
- Tooltip: 完整信息
案例2: 股票K线+成交量组合图
typescript
const option = {
dataset: {
source: stockData // [日期, 开盘, 收盘, 最低, 最高, 成交量]
},
grid: [
{ left: '10%', right: '8%', height: '50%' },
{ left: '10%', right: '8%', top: '63%', height: '16%' }
],
xAxis: [
{ gridIndex: 0, type: 'category' },
{ gridIndex: 1, type: 'category', gridIndex: 1 }
],
yAxis: [
{ gridIndex: 0, scale: true },
{ gridIndex: 1, scale: true }
],
series: [
{
name: 'K线',
type: 'candlestick',
xAxisIndex: 0,
yAxisIndex: 0,
encode: {
x: '日期',
open: '开盘',
close: '收盘',
low: '最低',
high: '最高'
}
},
{
name: '成交量',
type: 'bar',
xAxisIndex: 1,
yAxisIndex: 1,
encode: {
x: '日期',
y: '成交量'
}
}
]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
案例3: 动态数据透视表
typescript
class PivotTableChart {
private rawData: any[] = [];
setData(data: any[]) {
this.rawData = data;
this.render();
}
// 动态切换行列映射
pivot(rowField: string, colField: string, valueField: string) {
const pivoted = this.transformPivot(rowField, colField, valueField);
chart.setOption({
dataset: {
source: pivoted
},
xAxis: { type: 'category' },
yAxis: {},
series: pivoted[0].slice(1).map((col: string, index: number) => ({
type: 'bar',
name: col,
encode: {
x: 0,
y: index + 1
}
}))
});
}
private transformPivot(row: string, col: string, val: string): any[][] {
// 数据透视转换逻辑
const headers = [row, ...new Set(this.rawData.map(d => d[col]))];
const grouped: any = {};
this.rawData.forEach(item => {
if (!grouped[item[row]]) {
grouped[item[row]] = {};
}
grouped[item[row]][item[col]] = item[val];
});
const rows = Object.entries(grouped).map(([key, values]: any) => {
return [key, ...headers.slice(1).map(h => values[h] || 0)];
});
return [headers, ...rows];
}
}
// 使用
const pivot = new PivotTableChart();
pivot.setData(salesData);
// 动态切换
pivot.pivot('地区', '产品', '销售额');
// 或
pivot.pivot('产品', '季度', '利润');1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
🎯 encode选择决策树
📊 性能对比
| 映射方式 | 可读性 | 灵活性 | 性能 |
|---|---|---|---|
| 隐式(无encode) | 低 | 低 | 快 |
| 数字索引 | 中 | 中 | 快 |
| 列名(dataset) | 高 | 高 | 中 |
建议:
- 简单场景: 无需encode
- 多维数据: 使用数字索引
- 复杂业务: 使用dataset+列名
🔗 相关资源
上一篇: 数据格式规范
✅ 数据与系列模块完成!
