查看全课大纲(第 21 / 45 节)

其他时间图表

小象实战讲义 · ECharts 数据可视化

在掌握了基础的折线图和面积图后,我们常常需要根据不同的数据特性和分析目的,选择更合适的图表变体来传达信息。本节将介绍几种基于折线图的“变种”图表:阶梯图、平滑曲线图、堆叠折线图与堆叠面积图。它们通过改变线条的连接方式或增加视觉元素,能更精准地表达阶跃变化、整体趋势以及部分与整体的关系。学完本节,你将能根据业务场景,灵活选用并绘制这些进阶的时间趋势图表。

💡 核心导读

  • 阶梯图:通过水平与垂直的“阶跃”线段连接数据点,适用于表示累积量(如用电量、用水量)的突变过程。
  • 平滑曲线图:使用平滑的贝塞尔曲线连接数据点,弱化局部波动,更清晰地展示数据的整体趋势。
  • 堆叠折线图:将多条折线在垂直方向堆叠,用于展示多个数据系列的总和趋势及各部分的贡献。
  • 堆叠面积图:在堆叠折线图的基础上填充颜色区域,视觉上更直观地展示部分与整体的占比关系,减少解读混淆。

一、阶梯图:表达阶跃变化

阶梯图(Step Line Chart)不以斜线直接连接相邻的数据点,而是采用一种“阶跃”的方式:从一个数据点垂直移动到下一个数据点的Y轴数值,再水平移动到该点的X轴位置。这种连接方式使得图表呈现出台阶状的视觉效果。

适用场景:阶梯图非常适合表示累积量或消耗量在特定时间点发生突变的数据,例如每日的用电量、用水量记录。在这些场景中,数值在某个时刻(如下一个读数点)突然变化到一个新水平,并保持到下一次变化,阶梯图能准确反映这种“跳变”特性。

在 pyecharts 中,绘制阶梯图非常简单,只需在 add_yaxis() 方法中设置参数 is_step=True 即可。默认值为 False,即普通折线图。

下面我们通过一个模拟每日消耗量的例子来对比阶梯图与普通折线图。

# 示例:阶梯图 vs 普通折线图
from pyecharts import options as opts
from pyecharts.charts import Line
import pandas as pd

# 创建模拟数据:假设为30天的每日消耗量
days = [f'Day {i+1}' for i in range(30)]
# 使用一个简单的函数生成有起伏的模拟数据
values = [10, 12, 8, 15, 18, 14, 20, 22, 19, 25, 23, 28, 26, 30, 27, 32, 35, 31, 34, 38, 36, 40, 39, 42, 45, 41, 44, 48, 46, 50]

# 1. 绘制阶梯图
chart_step = (
    Line()
    .add_xaxis(days)
    .add_yaxis(series_name='日消耗量', y_axis=values, is_step=True)
    .set_global_opts(title_opts=opts.TitleOpts(title='日消耗量趋势(阶梯图)'),
                     xaxis_opts=opts.AxisOpts(name='日期'),
                     yaxis_opts=opts.AxisOpts(name='消耗量'))
)
print(f"已创建图表:{type(chart_step).__name__},系列名:'日消耗量',数据点:{len(values)}个")
# 按本次显式传入的配置输出摘要,避免依赖内部 options 结构
print("阶梯图模式 (is_step): True")

# 2. 绘制普通折线图(对比)
chart_line = (
    Line()
    .add_xaxis(days)
    .add_yaxis(series_name='日消耗量', y_axis=values, is_step=False) # 显式设置为False,与默认一致
    .set_global_opts(title_opts=opts.TitleOpts(title='日消耗量趋势(普通折线图)'))
)
print(f"\n已创建对比图表:{type(chart_line).__name__}")
print("普通折线图模式 (is_step): False")
已创建图表:Line,系列名:'日消耗量',数据点:30个
阶梯图模式 (is_step): True

已创建对比图表:Line
普通折线图模式 (is_step): False
日消耗量阶梯折线图,数值在相邻时间点之间保持水平
图:阶梯图:日消耗量在两个时间点之间保持水平,数值变化时垂直跳变,适合表达离散事件后的稳定状态。手机端自动使用简化视图,点击图片可看大图。

通过输出可以看到,is_step 参数被成功设置。在实际渲染的图表中,chart_step 将显示为台阶状,清晰地表明消耗量在每一天读数点“跳变”到新值并保持;而 chart_line 则是点与点之间用直线连接,更强调连续的变化过程。你可以根据数据是“阶跃”变化还是“连续”变化来选择合适的图表类型。

二、平滑曲线图:突出整体趋势

平滑曲线图(Smooth Line Chart)使用平滑的贝塞尔曲线来连接数据点,而不是生硬的直线段。这种处理方式可以弱化数据中短期的、局部的波动,让观察者的注意力更容易集中在数据长期的、整体的变化趋势上。

适用场景:当你希望展示数据的宏观走向,而不被细微的上下起伏所干扰时,平滑曲线图是很好的选择。例如,展示公司年度营收的整体增长趋势、用户活跃度的长期变化等。

在 pyecharts 中,启用平滑曲线只需在 add_yaxis() 方法中设置参数 is_smooth=True。

# 示例:平滑曲线图
from pyecharts import options as opts
from pyecharts.charts import Line

# 使用与上文相同的数据,以便对比
days = [f'Day {i+1}' for i in range(30)]
values = [10, 12, 8, 15, 18, 14, 20, 22, 19, 25, 23, 28, 26, 30, 27, 32, 35, 31, 34, 38, 36, 40, 39, 42, 45, 41, 44, 48, 46, 50]

chart_smooth = (
    Line()
    .add_xaxis(days)
    .add_yaxis(series_name='趋势线', y_axis=values, is_smooth=True)
    .set_global_opts(title_opts=opts.TitleOpts(title='数据整体趋势(平滑曲线图)'))
)
print(f"已创建图表:{type(chart_smooth).__name__}")
print("平滑模式 (smooth): True")
已创建图表:Line
平滑模式 (smooth): True

启用平滑后,图表中的连线将变得圆滑。与普通折线图相比,平滑曲线图能更柔和地反映数据上升的大方向,减少了每日波动带来的视觉“锯齿感”,更适合用于汇报和展示整体趋势。

三、堆叠折线图:展示部分与整体

堆叠折线图(Stacked Line Chart)是堆叠柱状图在折线图领域的对应物。它将多个数据系列(series)的折线在垂直方向上进行堆叠,最上方的折线代表所有系列数值的累计总和,而任意两条折线之间的垂直距离则代表对应数据系列在该点的具体数值。

核心价值:

  1. 观察整体趋势:最上方的折线展示了总量的变化。
  2. 分析部分贡献:可以同时看到每个组成部分(数据系列)随时间变化的趋势。
  3. 对比部分大小:在任何一个时间点上,不同折线之间的间距宽度直观反映了该组成部分数值的大小。

一个重要的解读提示:在堆叠折线图中,数据值由折线之间的垂直距离表示,而非折线到X轴的绝对高度。例如,最上面的折线是“搜索引擎”的访问量线,但它到X轴的高度是总访问量。真正代表“搜索引擎”访问量的是这条线与它下面那条线(“直接访问”)之间的间距。

下面我们模拟一份一周内不同渠道网站访问量的数据,来绘制堆叠折线图。

# 示例:堆叠折线图
import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import Line

# 模拟一周各渠道访问量数据
data_dict = {
    '日期': ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
    '邮件营销': [120, 132, 101, 134, 90, 230, 210],
    '联盟广告': [220, 182, 191, 234, 290, 330, 310],
    '视频广告': [150, 232, 201, 154, 190, 330, 410],
    '直接访问': [320, 332, 301, 334, 390, 330, 320],
    '搜索引擎': [820, 932, 901, 934, 1290, 1330, 1320]
}
pv_data = pd.DataFrame(data_dict)

# 绘制堆叠折线图
chart_stacked_line = (
    Line()
    .add_xaxis(xaxis_data=pv_data['日期'].tolist())
    .add_yaxis(
        series_name='邮件营销',
        stack='Total',  # 关键参数:所有需要堆叠的系列使用相同的stack名称
        y_axis=pv_data['邮件营销'].tolist(),
        label_opts=opts.LabelOpts(is_show=False), # 默认不显示数据标签,避免杂乱
    )
    .add_yaxis(series_name='联盟广告', stack='Total', y_axis=pv_data['联盟广告'].tolist(),
               label_opts=opts.LabelOpts(is_show=False))
    .add_yaxis(series_name='视频广告', stack='Total', y_axis=pv_data['视频广告'].tolist(),
               label_opts=opts.LabelOpts(is_show=False))
    .add_yaxis(series_name='直接访问', stack='Total', y_axis=pv_data['直接访问'].tolist(),
               label_opts=opts.LabelOpts(is_show=False))
    .add_yaxis(series_name='搜索引擎', stack='Total', y_axis=pv_data['搜索引擎'].tolist(),
               label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title='网站周访问量趋势(堆叠折线图)'),
        # 关键配置:将提示框触发器设为'axis',鼠标悬停时显示该X轴位置所有系列的数据
        tooltip_opts=opts.TooltipOpts(trigger="axis"),
        # 添加横向网格线,便于阅读数值
        yaxis_opts=opts.AxisOpts(
            splitline_opts=opts.SplitLineOpts(is_show=True),
        ),
        # 将X轴类型设为'category',并关闭boundary_gap让折线与坐标轴标签对齐
        xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
    )
)

print(f"已创建图表:{type(chart_stacked_line).__name__}")
print(f"X轴数据:{pv_data['日期'].tolist()}")
print("包含的数据系列:['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']")
print("提示框触发模式:axis")
已创建图表:Line
X轴数据:['周一', '周二', '周三', '周四', '周五', '周六', '周日']
包含的数据系列:['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
提示框触发模式:axis
五个流量来源堆叠的网站周访问量折线图
图:堆叠折线图:五个流量来源堆叠成总量曲线,既能看总量变化,也能看各来源的占比结构。手机端可左右滑动查看,点击图片可看全图。

代码中的两个关键点:

  1. stack='Total':这是实现堆叠的核心。所有需要参与堆叠的 yaxis 系列必须设置相同的 stack 字符串值。
  2. tooltip_opts=opts.TooltipOpts(trigger="axis"):此配置将鼠标悬停提示框的触发方式从默认的“数据项”(item)改为“坐标轴”(axis)。这意味着当鼠标悬停在图表的某个X轴位置时,会一次性展示该位置下所有堆叠系列的数据,方便对比和查看总和。

四、堆叠面积图:更直观的占比表达

堆叠面积图(Stacked Area Chart)在堆叠折线图的基础上,对折线之间的区域进行颜色填充。这种填充使得每个组成部分的数值大小和占比变得更加直观和醒目。

优势:相比于堆叠折线图,堆叠面积图通过色块面积来表征数据,减少了将“线间距”误解为“值”的可能性,视觉冲击力更强,更易于理解部分与整体的关系。

实现堆叠面积图只需在堆叠折线图的代码基础上,为每个 add_yaxis() 添加 areastyle_opts 参数,通常用于设置填充区域的透明度。

# 示例:堆叠面积图(基于上一示例的数据和配置)
chart_stacked_area = (
    Line()
    .add_xaxis(xaxis_data=pv_data['日期'].tolist())
    .add_yaxis(
        series_name='邮件营销',
        stack='Total',
        y_axis=pv_data['邮件营销'].tolist(),
        areastyle_opts=opts.AreaStyleOpts(opacity=0.5), # 关键:设置区域填充样式,透明度50%
        label_opts=opts.LabelOpts(is_show=False),
    )
    .add_yaxis(series_name='联盟广告', stack='Total', y_axis=pv_data['联盟广告'].tolist(),
               areastyle_opts=opts.AreaStyleOpts(opacity=0.5),
               label_opts=opts.LabelOpts(is_show=False))
    .add_yaxis(series_name='视频广告', stack='Total', y_axis=pv_data['视频广告'].tolist(),
               areastyle_opts=opts.AreaStyleOpts(opacity=0.5),
               label_opts=opts.LabelOpts(is_show=False))
    .add_yaxis(series_name='直接访问', stack='Total', y_axis=pv_data['直接访问'].tolist(),
               areastyle_opts=opts.AreaStyleOpts(opacity=0.5),
               label_opts=opts.LabelOpts(is_show=False))
    .add_yaxis(series_name='搜索引擎', stack='Total', y_axis=pv_data['搜索引擎'].tolist(),
               areastyle_opts=opts.AreaStyleOpts(opacity=0.5),
               label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title='网站周访问量趋势(堆叠面积图)'),
        tooltip_opts=opts.TooltipOpts(trigger="axis"),
        yaxis_opts=opts.AxisOpts(splitline_opts=opts.SplitLineOpts(is_show=True)),
        xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
    )
)

print(f"已创建图表:{type(chart_stacked_area).__name__}")
print("第一个系列是否配置了区域样式:True")
已创建图表:Line
第一个系列是否配置了区域样式:True

添加 areastyle_opts 后,图表中每个系列对应的区域会被填充颜色。通过设置 opacity(透明度),可以实现层叠区域的视觉混合,使图表层次分明且美观。在进行部分与整体关系的可视化时,堆叠面积图通常是比堆叠折线图更推荐的选择。

📝 动手练一练

  1. 场景选择:假设你有一份记录某个APP“每日新增用户”、“每日活跃用户”和“每日总用户数”的数据。如果你想展示“每日总用户数”的增长趋势,并且同时了解“新增”和“活跃”用户对总用户数的贡献变化,应该使用本节介绍的哪种图表?为什么?
点击查看参考答案

应使用堆叠面积图或堆叠折线图。

  • 为什么:因为“每日总用户数”可以理解为由“每日新增用户”和“每日活跃用户”(以及其他可能的组成部分)累积而成。堆叠图表能同时展示总量的变化趋势(最上方的线/面积边缘)以及各组成部分的贡献趋势和大小(线间距/色块面积)。其中,堆叠面积图通过色块表达占比更为直观,是更优的选择。
  • 注意:这需要确保你的数据定义在逻辑上是可堆叠的,即各组成部分之和等于总量。
  1. 代码实践:请使用 pyecharts,为一组表示“服务器每小时CPU使用率(%)”的模拟数据绘制一张平滑曲线图。数据要求:X轴为 [‘00:00’, ‘01:00’, …, ‘23:00’],Y轴为包含24个在 [20, 80] 区间内随机整数的列表。请固定随机种子,确保输出可复现。
点击查看参考答案
from pyecharts import options as opts
from pyecharts.charts import Line
import random

# 固定随机种子以确保结果可复现
random.seed(2026)

# 生成X轴标签(24小时)
hours = [f'{i:02d}:00' for i in range(24)]
# 生成模拟的CPU使用率数据(20-80之间的整数)
cpu_usage = [random.randint(20, 80) for _ in range(24)]

# 绘制平滑曲线图
chart = (
    Line()
    .add_xaxis(hours)
    .add_yaxis(series_name='CPU使用率', y_axis=cpu_usage, is_smooth=True)
    .set_global_opts(
        title_opts=opts.TitleOpts(title='服务器24小时CPU使用率趋势'),
        xaxis_opts=opts.AxisOpts(name='时间'),
        yaxis_opts=opts.AxisOpts(name='使用率(%)')
    )
)

print(f"图表类型:{type(chart).__name__}")
print(f"X轴数据点:前3个为 {hours[:3]} ... 共{len(hours)}个")
print(f"Y轴数据示例(前5个):{cpu_usage[:5]}")
print("平滑配置已启用:True")
图表类型:Line
X轴数据点:前3个为 ['00:00', '01:00', '02:00'] ... 共24个
Y轴数据示例(前5个):[27, 40, 52, 80, 52]
平滑配置已启用:True

本章小结

本节深入探讨了折线图的四种实用变体,它们扩展了我们在表达时间序列数据时的工具箱。记住选择图表的核心原则:让图表形式服务于数据内涵和解读目的。阶梯图对应阶跃变化,平滑曲线图强调整体趋势,而堆叠折线/面积图则擅长解构总量与部分的关系。

📋 行动清单

  • 尝试转换:将你手头的一份用普通折线图表示的数据,分别用阶梯图和平滑曲线图重新绘制,体会三者视觉传达的差异。
  • 检查逻辑:在决定使用堆叠图表前,务必确认你的多个数据系列在逻辑上是可加和的,并且你关注的是总量趋势及各部分的贡献。
  • 配置优化:使用堆叠图表时,记得设置 tooltip_opts=opts.TooltipOpts(trigger="axis") 和 xaxis_opts=opts.AxisOpts(boundary_gap=False),以获得更好的交互和布局体验。

—— 小象教研组