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

其他对比图表

堆叠柱状图与漏斗图

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

在上一节掌握了基础的柱状图和条形图后,你是否想过如何同时展示一个分类的总量及其内部各子项的构成?或者如何直观地分析一个多环节业务流程中的转化情况?本节将介绍两种功能强大的对比图表:堆叠柱状图和漏斗图。通过学习,你将能利用堆叠柱状图清晰地呈现“部分与整体”的关系,并运用漏斗图分析流程中的关键环节,为你的数据分析报告增添深度和洞察力。

💡 核心导读

  • 堆叠柱状图:用于展示每个分类的总量,以及该分类内部各子项的构成与占比,非常适合分析部分与整体的关系。
  • 堆叠的实现:在 add_yaxis() 方法中使用 stack 参数,相同 stack 名称的数据系列会堆叠在一起,可实现“全部堆叠”或“部分堆叠”。
  • 漏斗图:适用于业务流程规范、环节多的单流程分析,能直观展示各环节的转化情况,帮助定位问题环节。
  • 数据准备:漏斗图的数据需要准备成 [ [环节名, 数值], ... ] 的列表形式,pyecharts 会自动按数值从大到小排序展示。

堆叠柱状图:展示部分与整体

堆叠柱状图(Stacked Bar Chart)是柱状图的扩展。与普通柱状图(或称分组柱状图)将不同系列的数据并行排列不同,堆叠柱状图将同一分类下的不同系列数据垂直堆叠起来。

它的核心价值在于:

  1. 展示总量:每个柱子的总高度代表该分类的合计值。
  2. 展示构成:柱子内部不同颜色的分段代表了各子分类的大小及其在总量中的占比。
  3. 对比关系:既能横向对比不同分类的总量,也能纵向(在单个柱子内)分析其内部构成。

例如,比较不同手机品牌(苹果、小米、OPPO)的总销量时,可以用普通柱状图。但如果还想知道每个品牌内部,手机、耳机、可穿戴设备各自的销量贡献,堆叠柱状图就是最佳选择。它能立刻告诉你,小米的总销量虽不及苹果,但其耳机产品线可能是销量主力。

在 pyecharts 中创建堆叠柱状图

实现堆叠效果的关键在于 add_yaxis() 方法中的 stack 参数。所有指定了相同 stack 名称的数据系列,将会在同一个柱子上堆叠。

首先,我们导入必要的库并准备示例数据。

# 导入必要的库
from pyecharts import options as opts
from pyecharts.charts import Bar
import pandas as pd

# 准备示例数据:模拟三个品牌在三种产品上的销量
brands = ['苹果', '小米', 'OPPO', '三星', '华为']
products = {
    '手机': [120, 80, 150, 90, 110],
    '耳机': [200, 150, 180, 120, 160],
    '穿戴设备': [80, 100, 70, 60, 90]
}

print("X轴分类(品牌):", brands)
print("产品系列数据:")
for product, values in products.items():
    print(f"  {product}: {values}")
X轴分类(品牌): ['苹果', '小米', 'OPPO', '三星', '华为']
产品系列数据:
  手机: [120, 80, 150, 90, 110]
  耳机: [200, 150, 180, 120, 160]
  穿戴设备: [80, 100, 70, 60, 90]

接下来,我们创建第一个图表:全部堆叠。将三个产品系列都堆叠到同一个柱子上,以展示每个品牌的总销量及构成。

# 创建全部堆叠的柱状图
stacked_bar_all = (
    Bar()
    .add_xaxis(brands)
    .add_yaxis("手机", products['手机'], stack="total")  # 指定 stack 名称
    .add_yaxis("耳机", products['耳机'], stack="total")  # 相同的 stack 名称
    .add_yaxis("穿戴设备", products['穿戴设备'], stack="total") # 相同的 stack 名称
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) # 隐藏柱内数值标签,避免拥挤
    .set_global_opts(title_opts=opts.TitleOpts(title="各品牌产品销量(全部堆叠)"))
)

# 生成HTML文件,并打印图表类型作为摘要
stacked_bar_all.render("stacked_bar_all.html")
print(f"已生成图表: {type(stacked_bar_all).__name__}")
print(f"堆叠系列数: 3 (stack='total')")
已生成图表: Bar
堆叠系列数: 3 (stack='total')

运行后,打开生成的 stacked_bar_all.html 文件,你会看到每个品牌对应一个柱子,柱子由三段不同颜色的部分堆叠而成,总高度代表了该品牌三种产品的总销量。你可以清晰地比较各品牌总销量(苹果最高),同时观察每个品牌内部哪种产品销量最多(例如小米的耳机部分最厚)。

部分堆叠

有时,我们只需要将部分有关联的系列堆叠在一起,而其他系列保持并列。这可以通过分配不同的 stack 名称来实现。

# 创建部分堆叠的柱状图:将"手机"和"耳机"堆叠, "穿戴设备"独立
stacked_bar_partial = (
    Bar()
    .add_xaxis(brands)
    .add_yaxis("手机", products['手机'], stack="stack1")  # 堆叠组1
    .add_yaxis("耳机", products['耳机'], stack="stack1")  # 堆叠组1
    .add_yaxis("穿戴设备", products['穿戴设备'], stack="stack2") # 独立组2
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(title_opts=opts.TitleOpts(title="各品牌产品销量(部分堆叠)"))
)

stacked_bar_partial.render("stacked_bar_partial.html")
print(f"已生成图表: {type(stacked_bar_partial).__name__}")
print(f"堆叠组 'stack1' 包含系列: ['手机', '耳机']")
print(f"独立组 'stack2' 包含系列: ['穿戴设备']")
已生成图表: Bar
堆叠组 'stack1' 包含系列: ['手机', '耳机']
独立组 'stack2' 包含系列: ['穿戴设备']

查看 stacked_bar_partial.html,你会发现每个品牌下有两个柱子:一个是由手机和耳机构成的堆叠柱(总高为两者之和),另一个是独立的穿戴设备柱。这种形式便于我们单独对比穿戴设备在各品牌间的销量,同时又能看到手机和耳机的合并销量及内部构成。

堆叠柱状图的使用建议

  1. 避免过多颜色:堆叠部分过多会导致难以区分。建议每个堆叠柱包含2-4个子项,最多不超过6个。
  2. 谨慎进行跨组细分对比:堆叠柱状图不擅长直接对比不同柱子(分类)中间一颜色部分(子分类)的大小。例如,比较“苹果”和“小米”的“耳机”销量,因为它们的基线不同(苹果的基线在手机销量之上,小米的基线也在手机销量之上),直观比较高度容易产生误导。如需精确对比,应考虑使用分组柱状图。
  3. 避免使用负值:堆叠逻辑基于加法,包含负值会使图表解读变得极其困难,且可能破坏“部分构成整体”的视觉隐喻。
  4. 考虑水平布局:当分类标签文字较长时,可以使用水平堆叠条形图来提升可读性(通过 .reversal_axis() 实现)。

漏斗图:分析业务流程转化

漏斗图(Funnel Chart)因其形状类似漏斗而得名,它适用于分析具有固定流程、环节较多且单向发展的业务场景,如营销转化、用户注册、购物流程等。

它的核心价值在于:

  1. 可视化转化过程:从上到下,展示流程中各个环节的绝对数量。
  2. 定位流失环节:通过相邻环节面积的显著收缩(斜率变化),可以直观发现用户流失严重的环节。
  3. 支持决策:帮助业务人员聚焦问题环节,深入分析流失原因。

一个典型的例子是广告投放转化漏斗:展现 → 点击 → 访问 → 咨询 → 订单。通过漏斗图,我们可以一眼看出从“点击”到“访问”的转化率是否正常,哪个环节是转化的瓶颈。

在 pyecharts 中创建漏斗图

漏斗图的数据需要特殊格式:一个由 [环节名称, 数值] 对组成的列表。我们可以使用 zip 函数和列表推导式来方便地构造。

# 导入漏斗图类
from pyecharts.charts import Funnel

# 准备业务流程数据
steps = ["展现", "点击", "访问", "咨询", "订单"]
values = [10000, 3000, 1200, 300, 150]

# 使用 zip 和列表推导式构造数据对
data_pair = [list(z) for z in zip(steps, values)]
print("漏斗图数据对:")
for item in data_pair:
    print(f"  {item}")
漏斗图数据对:
  ['展现', 10000]
  ['点击', 3000]
  ['访问', 1200]
  ['咨询', 300]
  ['订单', 150]

现在,我们使用链式调用的方式创建漏斗图。注意,pyecharts 的 Funnel 图表会自动根据数值从大到小进行排序和展示,这与漏斗从上到下逐渐减小的视觉逻辑一致。因此,即使你的原始数据顺序是乱的,最终呈现的也是正确的漏斗形状。

# 创建并渲染漏斗图
funnel_chart = (
    Funnel()
    .add(
        series_name="转化漏斗",  # 系列名称
        data_pair=data_pair,     # 传入数据对
        gap=2,                   # 各漏斗层之间的间隙
        label_opts=opts.LabelOpts(position="inside") # 标签显示在内部
    )
    .set_global_opts(title_opts=opts.TitleOpts(title="广告投放转化漏斗"))
)

funnel_chart.render("funnel_chart.html")
print(f"已生成图表: {type(funnel_chart).__name__}")
print(f"漏斗环节数: {len(data_pair)}")
print("注意:图表已自动按数值降序排列环节。")
已生成图表: Funnel
漏斗环节数: 5
注意:图表已自动按数值降序排列环节。

打开 funnel_chart.html,你将看到一个标准的漏斗。最宽的顶层是“展现”(10000),最窄的底层是“订单”(150)。每个梯形的倾斜程度直观反映了该环节的转化率(流失率)。例如,“点击”到“访问”的梯形边如果非常陡峭,说明这个环节流失了大量用户,值得深入分析。

📝 动手练一练

  1. 水平堆叠条形图:将“全部堆叠”示例中的垂直堆叠柱状图,改造成水平的堆叠条形图。提示:回忆如何将普通柱状图转换为条形图,并将此逻辑应用到堆叠图表上。
点击查看参考答案
from pyecharts import options as opts
from pyecharts.charts import Bar

brands = ['苹果', '小米', 'OPPO', '三星', '华为']
products = {
    '手机': [120, 80, 150, 90, 110],
    '耳机': [200, 150, 180, 120, 160],
    '穿戴设备': [80, 100, 70, 60, 90]
}

# 创建水平堆叠条形图
horizontal_stacked_bar = (
    Bar()
    .add_xaxis(brands)
    .add_yaxis("手机", products['手机'], stack="total")
    .add_yaxis("耳机", products['耳机'], stack="total")
    .add_yaxis("穿戴设备", products['穿戴设备'], stack="total")
    .reversal_axis()  # 翻转坐标轴,变成条形图
    .set_series_opts(label_opts=opts.LabelOpts(position="right", is_show=False)) # 标签在右侧
    .set_global_opts(title_opts=opts.TitleOpts(title="各品牌产品销量(水平堆叠)"))
)

horizontal_stacked_bar.render("horizontal_stacked_bar.html")
print("水平堆叠条形图已生成。")
水平堆叠条形图已生成。
五个品牌三种产品系列的手机耳机穿戴设备水平堆叠条形图
图:水平堆叠条形图:三个产品系列在同一根条上累加,条的总长度表示各品牌的合计销量。手机端自动使用简化视图,点击图片可看大图。
  1. 自定义漏斗图数据:假设你有一个用户注册流程的数据:[‘访问首页’, ‘开始注册’, ‘填写信息’, ‘提交验证’, ‘注册成功’],对应的用户数分别为 [5000, 3500, 2000, 1200, 800]。请用漏斗图可视化这个过程,并指出哪个环节的流失率看起来最高(仅从图形斜率判断)。
点击查看参考答案
from pyecharts.charts import Funnel
from pyecharts import options as opts

steps = ['访问首页', '开始注册', '填写信息', '提交验证', '注册成功']
values = [5000, 3500, 2000, 1200, 800]

data_pair = [list(z) for z in zip(steps, values)]

funnel_chart_custom = (
    Funnel()
    .add(
        series_name="用户注册漏斗",
        data_pair=data_pair,
        gap=2,
        label_opts=opts.LabelOpts(position="inside")
    )
    .set_global_opts(title_opts=opts.TitleOpts(title="用户注册流程转化漏斗"))
)

funnel_chart_custom.render("funnel_registration.html")
print(f"注册漏斗环节数: {len(data_pair)}")
print("观察图形,从'填写信息'到'提交验证'的梯形边可能最陡峭,表明该环节流失率较高。")
注册漏斗环节数: 5
观察图形,从'填写信息'到'提交验证'的梯形边可能最陡峭,表明该环节流失率较高。

本章小结

本节深入探讨了两种用于项目对比和流程分析的高级图表。堆叠柱状图通过将数据系列垂直堆叠,巧妙地在同一图表中展示了总量与构成的双重信息,是分析部分与整体关系的利器。漏斗图则以其独特的形状,清晰地描绘了多环节业务流程中的转化与流失情况,是流程优化的可视化助手。

📋 行动清单

  • 实践堆叠:在你的项目中,找一个包含分类和子分类的数据集,用 stack 参数创建全部堆叠和部分堆叠的柱状图,体会其异同。
  • 分析流程:梳理一个你熟悉的业务流程(如工作流、产品使用路径),收集各环节数据,用漏斗图进行可视化,并尝试从图中发现可以优化的环节。
  • 规避误区:回顾堆叠柱状图的使用建议,确保在未来的使用中避免颜色过多、进行无效的跨组细分对比等常见问题。

—— 小象教研组