做前端开发也好,数据分析也罢,图表这东西看着简单,真到了生产环境里,坑能把你埋得死死的。很多人(包括我曾经)觉得:“哎呀,Echarts文档那么全,随便拖个type: 'line'或者type: 'scatter'不就完了吗?”
结果呢?线条乱飞、数据看不清、配色像彩虹糖被打翻了,甚至因为坐标轴设置不对,导致业务方拿着数据来质问你“为什么增长率看起来是负的”。
今天咱们不整那些虚头巴脑的理论,直接切入正题。我会把散点图和折线图这两个最常用、也最容易出错的图表类型掰开了揉碎了讲,配上真实的错误案例和正确的代码示范。希望能帮你省下几个加班的夜晚。
一、 为什么大家总是纠结选散点还是选折线?
在深入代码之前,我们先聊点“选型逻辑”。这是很多教程里忽略,但实际上最关键的一步。
折线图(Line Chart)的核心是趋势。它在乎的是“随时间变化”或者“随有序维度变化”的连续性。比如:过去一年的股票价格、气温变化、网站访问量趋势。
散点图(Scatter Plot)的核心是分布和相关性。它在乎的是“这两个变量之间有没有关系”。比如:身高和体重的关系、广告投放量和销售额的相关性。
常见误区:
- 把散点图画成折线图:如果你画的是“身高体重”关系,连起来线不仅没意义,还会让图表看起来像一团乱麻。
- 把折线图画成散点图:如果你看的是“月度销售趋势”,光有点没有线,观众需要自己在脑海里连线,这增加了认知负担。
二、 折线图的那些“隐形坑”
折线图看起来人畜无害,但细节全是魔鬼。
2.1 错误案例:缺失值处理不当导致的“误导性连线”
这是最常见的坑。假设你的数据中有空缺(比如某天服务器宕机,没有数据)。默认情况下,Echarts 会直接把前一个有效点连到后一个有效点,或者断开了。
糟糕的表现:
data: [10, 20, null, 40, 50]
如果直接渲染,null 处可能会出现断点,或者在某些配置下强行连线,导致趋势看起来异常平滑,掩盖了数据的缺失。
正确做法:
你应该明确告诉 Echarts 怎么处理这个 null。通常有两种策略:
- 断开连接:
connectNulls: false(默认),这样趋势更真实。 - 线性插值:
connectNulls: true,如果你认为缺失数据是连续变化的(比如温度),可以用插值填充。
// 实用配置:明确处理空值
series: [{
type: 'line',
data: [120, null, 150, 200],
connectNulls: false, // 断开,不要假装数据存在
lineStyle: {
type: 'dashed' // 虚线提示数据不连续
},
// 重要:加上空值标记,让用户知道这里没数据
markPoint: {
data: [{type: 'average', name: '均值'}] // 或者手动标记空值位置
}
}]
2.2 错误案例:X轴不是时间,却被当成时间轴处理
当你展示“不同城市的人均收入”时,如果你用了 type: 'time' 的 x轴,Echarts 会尝试解析你的城市名(如”Beijing”, “Shanghai”)为时间戳,结果就是——乱码或完全错误的顺序。
避坑指南:
- 分类数据(Categorical):用
type: 'category'。 - 时间数据(Time):用
type: 'time'。 - 数值数据(Value):用
type: 'value'。
很多开发者习惯性地把所有 X 轴都写成 type: 'category',结果当数据量很大(比如几千个时间点)时,标签全部挤在一起,变成一条黑线。
优化方案:自动缩放与间隔控制
xAxis: {
type: 'category',
data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
// 关键配置:防止标签重叠
axisLabel: {
interval: 0, // 0表示全部显示,如果数据太多建议改为 auto 或 1
rotate: 30, // 倾斜 30 度
fontSize: 10
},
// 如果数据极多,启用网格切换
splitLine: {
show: true,
lineStyle: {
color: '#eee',
type: 'dashed'
}
}
}
2.3 错误案例:多条折线颜色混淆,且无法区分
当你有 5 条甚至 10 条折线时,默认的 Echarts 配色循环很快就不够用了,而且颜色过于鲜艳,看起来像儿童画。
专业建议: 使用低饱和度、高对比度的色系,并为每条线添加明确的标识。
// 使用更专业的调色板,比如 Tableau 或 Google 风格
const colorPalette = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de'];
series: [
{
name: '服务器A',
type: 'line',
data: [...],
lineStyle: { width: 3 }, // 加粗线条,更易辨识
smooth: true, // 平滑曲线,适合展示趋势
areaStyle: { opacity: 0.1 } // 轻微填充,增强面积感
},
{
name: '服务器B',
type: 'line',
data: [...],
lineStyle: { width: 3 },
smooth: true,
// 关键点:使用不同的视觉通道,比如虚线
lineStyle: { type: 'dashed' }
}
]
技巧:不要只靠颜色区分,要靠颜色 + 线型(实线/虚线)。这对于色盲用户或黑白打印场景非常友好。
三、 散点图的“高级玩法”与常见陷阱
散点图比折线图更灵活,但也更容易画丑。
3.1 错误案例:点太大,完全遮挡了分布密度
如果你在一个区域有大量重叠的数据点,默认大小的圆点会连成一片,你完全看不出哪里是密集区,哪里是稀疏区。
解决方案:调整透明度(Opacity)
series: [{
type: 'scatter',
symbolSize: 10, // 点的大小
itemStyle: {
opacity: 0.6 // 关键!设置透明度,让重叠区域颜色更深,直观显示密度
},
data: [[10, 8.04], [12, 10.3], ...]
}]
当多个半透明的点重叠时,颜色会变深,这本身就是一种“密度热力图”的雏形,无需额外引入 Heatmap 图表。
3.2 错误案例:忘记使用对数坐标轴(Log Scale)
这是数据分析师的救命稻草。当你的数据跨度极大(比如从 1 到 1,000,000),在对数坐标下,小数值的变化也能被清晰看到,而不会被大数值“压扁”在底部。
很多开发者不知道 Echarts 支持 log 类型!
xAxis: {
type: 'log', // 直接切换为对数坐标
name: '收入 (对数刻度)'
},
yAxis: {
type: 'value',
name: '满意度'
}
何时使用? 当你看到数据集中在左下角,右上角有个别极大值时,首选 log 轴。
3.3 错误案例:用散点图画“时间序列”
这是一个经典的错误。虽然技术上你可以画,但如果你有一年的每秒股价数据(几百万个点),散点图会让屏幕变成一张灰雾,完全看不出趋势。
正确选择:
- 大数据量时间序列:用 折线图 + 采样(Sampling)。
- Echarts 采样策略:
series: [{
type: 'line',
data: largeTimeSeriesData,
sampling: 'lttb', // Last Tritioin Buffering,专业的时序采样算法
itemStyle: { opacity: 0.5 }
}]
LTTE 采样算法能在保持数据主要特征的同时,大幅减少点数,避免性能问题。
3.4 进阶技巧:气泡图(Bubble Chart)——三维信息的四维表达
散点图是二维的(X, Y)。如果你想表达第三个维度(比如市场规模),就用气泡的大小;想表达第四个维度(比如增长率),就用颜色。
代码示例:
series: [{
type: 'scatter', // 注意:虽然叫 scatter,但配置 symbolSize 后就是气泡图
data: [
[10, 8.04, 500], // x, y, z(气泡大小)
[12, 10.3, 1200]
],
symbolSize: function (data) {
return data[2] / 50; // 将 z 值映射为像素大小
},
itemStyle: {
// 根据 z 值映射颜色
color: function (params) {
return params.data[2] > 1000 ? '#ee6666' : '#5470c6';
}
}
}]
警示:气泡图最多建议用 3-4 个维度。超过这个数量,视觉负担会指数级增加,观众会放弃理解。
四、 实用选图决策树
为了让你下次能快速做决定,我整理了一个简单的决策流程:
你想展示什么?
- 趋势/变化 -> 折线图
- 关系/相关性 -> 散点图
- 占比/构成 -> 饼图/堆叠柱状图
- 分布/统计 -> 直方图/箱线图
X轴是什么类型?
- 时间(有序) -> 折线图首选,散点图次选(如果点很少)
- 类别(无序,如城市、产品) -> 柱状图 > 折线图(折线在无序类别中无意义,除非你强行用)
- 数值(连续) -> 散点图
数据量有多大?
- < 100 个点 -> 散点图、折线图都 OK
- 100 - 1000 个点 -> 折线图 + 平滑处理
- > 1000 个点 -> 折线图 + 采样(Sampling),或者改用热力图/密度图
有特殊需求吗?
- 需要对比多条线 -> 折线图 + 不同线型/颜色
- 需要显示精确值 -> 散点图 + Tooltip(鼠标悬停显示数值)
- 需要突出异常值 -> 散点图(异常值很容易在散点图中被发现)
五、 几个提升图表质感的“小心机”
最后,分享几个能让你的图表从“能看”变成“专业”的小技巧。
5.1 Tooltip 的定制化
默认的 tooltip 有时候信息太少。你可以自定义它,展示更丰富的信息。
tooltip: {
trigger: 'axis', // 触发类型为轴,显示该轴上所有数据
backgroundColor: 'rgba(255, 255, 255, 0.9)',
borderColor: '#ccc',
textStyle: { color: '#333' },
formatter: function (params) {
// params 是一个数组
let result = `<strong>${params[0].name}</strong><br/>`;
params.forEach(p => {
result += `${p.marker} ${p.seriesName}: <b>${p.value}</b><br/>`;
});
return result;
}
}
5.2 标签的避让
当数据点很密集时,标签会重叠。Echarts 提供了 labelLayout 来自动避让。
series: [{
type: 'line',
data: [...],
label: {
show: true,
position: 'top'
},
labelLayout: {
hideOverlap: true, // 隐藏重叠的标签
moveOverlap: 'shiftX' // 重叠时沿 X 轴移动
}
}]
5.3 响应式调整
别忘了加这行代码,否则图表在移动端或窗口缩放时会变形。
// 在组件挂载后调用
window.addEventListener('resize', () => {
myChart.resize();
});
结语
图表设计的核心不是“炫技”,而是“降低认知成本”。
从散点图到折线图,每一个选择背后都是对数据本质的理解。折线图讲“故事”,散点图讲“关系”。避开那些常见的坑——空值处理、坐标轴类型、透明度、采样——你的图表就会从“能看”变成“会说”。
希望这篇指南能帮你在下一次画图表时,少掉几根头发。如果有具体的图表场景拿不准,欢迎带着数据来问我,我们一起分析。
