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

组合图表组件

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

在前面的章节中,我们已经掌握了如何使用 pyecharts 绘制各种独立的图表,如折线图、柱状图、散点图等。然而,在实际的数据分析报告或数据大屏项目中,我们常常需要将多个图表组合在一起,形成对比、关联或互补的视图,以更全面地呈现数据故事。本节将介绍 pyecharts 中用于组合图表的三大核心组件:Grid、Page 和 Tab,帮助你掌握将多个图表整合到一个可视化区域或页面中的方法。

💡 核心导读

  • Grid 组件:将画布划分为网格,通过 GridOpts 精确控制每个子图的位置和大小,实现灵活的图表布局。
  • Grid 的数据关联:在 Grid 中,不同子图内具有相同 series_name 的数据系列会自动关联,支持联动高亮与隐藏。
  • Page 组件:无需指定位置,只需设定子图大小,可根据页面宽度自动调整布局,并支持可拖拽的布局方式。
  • Tab 组件:以标签页的形式组织图表,节省空间,用户可通过点击标签在不同图表间切换。

1. Grid:精确布局的组合组件

Grid 组件是构建组合图表的基础。它的核心思想是将整个可视化区域(画布)视为一个网格系统,你可以将不同的图表(子图)放置在这个网格的指定位置。

1.1 准备子图数据与图表

在组合之前,我们需要先创建好要组合的独立图表。这里我们使用一组相同的数据,分别创建一个散点图和一个折线图。

# 导入必要的库
from pyecharts import options as opts
from pyecharts.charts import Grid, Line, Scatter

# 准备示例数据
x_data = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
y_data_a = [820, 932, 901, 934, 1290, 1330, 1320]
y_data_b = [620, 732, 701, 734, 1090, 1130, 1120]

def make_scatter(title):
    return (
        Scatter(init_opts=opts.InitOpts(width='500px', height='400px'))
        .add_xaxis(x_data)
        .add_yaxis("组A", y_data_a, symbol_size=10)
        .add_yaxis("组B", y_data_b, symbol_size=10)
        .set_global_opts(
            title_opts=opts.TitleOpts(title=title),
            legend_opts=opts.LegendOpts(pos_left="20%"),
        )
    )

def make_line(title):
    return (
        Line(init_opts=opts.InitOpts(width='500px', height='400px'))
        .add_xaxis(x_data)
        .add_yaxis("组A", y_data_a, is_smooth=True)
        .add_yaxis("组B", y_data_b, is_smooth=True)
        .set_global_opts(
            title_opts=opts.TitleOpts(title=title),
            legend_opts=opts.LegendOpts(pos_right="20%"),
        )
    )

# 水平布局:左侧散点图,右侧折线图
horizontal_grid = (
    Grid(init_opts=opts.InitOpts(width='1000px', height='450px'))
    .add(make_scatter("散点图 - 左侧"), grid_opts=opts.GridOpts(pos_right="55%"))
    .add(make_line("折线图 - 右侧"), grid_opts=opts.GridOpts(pos_left="55%"))
)

# 垂直布局:上方散点图,下方折线图
vertical_grid = (
    Grid(init_opts=opts.InitOpts(width='600px', height='800px'))
    .add(make_scatter("散点图 - 上方"), grid_opts=opts.GridOpts(pos_bottom="55%"))
    .add(make_line("折线图 - 下方"), grid_opts=opts.GridOpts(pos_top="55%"))
)

# 任意布局:两个子图分别占据不同区域
free_grid = (
    Grid(init_opts=opts.InitOpts(width='1000px', height='600px'))
    .add(make_scatter("散点图 - 左上"), grid_opts=opts.GridOpts(pos_right="50%", pos_bottom="50%"))
    .add(make_line("折线图 - 右下"), grid_opts=opts.GridOpts(pos_left="50%", pos_top="50%"))
)

print("已创建 3 种 Grid 布局:水平、垂直、任意位置")
print("每个 Grid 均包含 2 个子图")
已创建 3 种 Grid 布局:水平、垂直、任意位置
每个 Grid 均包含 2 个子图
Grid 组合图,左侧散点图、右侧折线图并排
图:Grid 左右布局:散点图占左半、折线图占右半,两块子图共享同一张画布。手机端可左右滑动查看,点击图片可看全图。

1.2 理解 GridOpts 的位置参数

Grid 布局的核心在于 GridOpts 中的 pos_top、pos_bottom、pos_left、pos_right 四个参数。初学者最容易混淆的是:这些参数并非定义子图“位于”哪个方向,而是定义子图“距离”画布对应边界的距离(百分比或像素)。

  • pos_right="55%":表示子图的右边界距离画布右边界有 55% 的空白。因此,子图实际占据的是画布左侧 45% 的宽度。
  • pos_left="55%":表示子图的左边界距离画布左边界有 55% 的空白。因此,子图实际占据的是画布右侧 45% 的宽度。

1.3 实现水平布局

让我们将散点图放在左侧,折线图放在右侧。

上面代码的第一个 Grid 使用 pos_right="55%" 和 pos_left="55%",将两个子图左右分开:散点图占左侧区域,折线图占右侧区域。

1.4 实现垂直与任意布局

同理,我们可以实现垂直布局(上下排列)或更复杂的任意布局。

vertical_grid 用 pos_bottom 和 pos_top 实现上下排列;free_grid 同时组合左右与上下偏移,让两个子图落入不同象限。调整这四个参数时,始终把它们理解为“子图边界到画布对应边界的留白”,布局结果会更直观。

1.5 Grid 中的数据关联特性

Grid 组件一个非常强大的特性是数据关联。当不同子图中的数据系列具有相同的 series_name(如我们都使用了“组A”和“组B”)时,它们在交互上是联动的。

  • 效果:在最终生成的 HTML 页面中,当你用鼠标点击或悬停图例中的“组A”时,两个图表中属于“组A”的数据点会同时高亮或隐藏。这使得对比分析变得非常直观。
  • 原理:pyecharts 在底层生成 ECharts 配置时,会识别相同的系列名,并配置相应的 legend 联动。
  • 控制:如果你不希望图表间联动,只需为不同图表中的系列设置不同的名称即可。

2. Page:自适应与可拖拽的页面组件

Page 组件提供了一种更简单的多图表组织方式。你无需关心每个图表的具体位置,只需将它们添加到 Page 中,并指定一个布局策略,Page 会自动排列它们。

2.1 SimplePageLayout:简单自适应布局

SimplePageLayout 会根据你为每个子图设置的宽度 (width) 和页面容器的实际宽度,自动决定是水平排列(并排)还是垂直排列(换行)。注意:Page 的完整布局效果需要在保存为 HTML 文件并在浏览器中打开后才能完全呈现。

from pyecharts import options as opts
from pyecharts.charts import Line, Page, Scatter

x_data = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
y_data_a = [820, 932, 901, 934, 1290, 1330, 1320]

# 每个子图都重新创建,避免依赖上一个代码块中的局部变量
scatter_small = (
    Scatter(init_opts=opts.InitOpts(width='400px', height='300px'))
    .add_xaxis(x_data)
    .add_yaxis("组A", y_data_a)
    .set_global_opts(title_opts=opts.TitleOpts(title="散点图"))
)
line_small = (
    Line(init_opts=opts.InitOpts(width='400px', height='300px'))
    .add_xaxis(x_data)
    .add_yaxis("组A", y_data_a, is_smooth=True)
    .set_global_opts(title_opts=opts.TitleOpts(title="折线图"))
)

# 方式一:SimplePageLayout 自适应排列
simple_page = Page(layout=Page.SimplePageLayout)
simple_page.add(scatter_small, line_small)
simple_page.render("simple_page_layout.html")

# 方式二:DraggablePageLayout 可拖拽排列
draggable_page = Page(layout=Page.DraggablePageLayout)
draggable_page.add(scatter_small, line_small)
draggable_page.render("draggable_page_layout.html")

print("已生成两种 Page 页面:simple_page_layout.html 与 draggable_page_layout.html")
print("SimplePageLayout 会按容器宽度自动换行;DraggablePageLayout 可在浏览器中拖动图表")
已生成两种 Page 页面:simple_page_layout.html 与 draggable_page_layout.html
SimplePageLayout 会按容器宽度自动换行;DraggablePageLayout 可在浏览器中拖动图表

2.2 DraggablePageLayout:可拖拽布局

DraggablePageLayout 提供了一个交互性更强的功能:允许用户在浏览器中自由拖拽图表来调整布局,并且可以将最终的布局保存下来。

上面的同一个代码块已经同时生成 draggable_page_layout.html。在浏览器中打开后,你可以拖动图表调整位置;点击页面上的“保存配置”会下载布局 JSON(默认文件名为 chart_config.json)。

将该 JSON 与 HTML 放在同一工作目录后,可使用 pyecharts 2.1.0 的实际接口恢复布局:

Page.save_resize_html(
    source="draggable_page_layout.html",
    cfg_file="chart_config.json",
    dest="fixed_layout.html"
)

这会生成应用固定布局的新文件 fixed_layout.html;Page 类没有 load_resize_json() 方法。

3. Tab:节省空间的分页组件

Tab 组件通过标签页的形式来组织多个图表。它非常节省空间,因为同一时间只显示一个图表,用户通过点击标签来切换。这适用于图表数量较多,且不需要同时对比查看的场景。

from pyecharts import options as opts
from pyecharts.charts import Line, Scatter, Tab

x_data = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
y_data_a = [820, 932, 901, 934, 1290, 1330, 1320]

scatter_tab = (
    Scatter(init_opts=opts.InitOpts(width='500px', height='350px'))
    .add_xaxis(x_data)
    .add_yaxis("组A", y_data_a)
    .set_global_opts(title_opts=opts.TitleOpts(title="散点图"))
)
line_tab = (
    Line(init_opts=opts.InitOpts(width='500px', height='350px'))
    .add_xaxis(x_data)
    .add_yaxis("组A", y_data_a, is_smooth=True)
    .set_global_opts(title_opts=opts.TitleOpts(title="折线图"))
)

# 创建 Tab 组件
tab = Tab()

# 向 Tab 中添加图表,并指定标签页的名称
tab.add(scatter_tab, "散点图")
tab.add(line_tab, "折线图")

print("Tab 组件已创建,包含 2 个标签页。")
print("标签页名称: '散点图', '折线图'")
print("在渲染出的页面中,可通过点击顶部标签进行切换。")
Tab 组件已创建,包含 2 个标签页。
标签页名称: '散点图', '折线图'
在渲染出的页面中,可通过点击顶部标签进行切换。

📝 动手练一练

  1. 布局挑战:使用 Grid 组件,尝试将三个不同的图表(例如,一个柱状图、一个折线图、一个饼图)布局成一个“品”字形(上面一个,下面两个并排)。请写出关键的 GridOpts 参数设置思路。
点击查看参考答案

思路:

  • 假设画布总宽度为 100%,高度为 100%。
  • 顶部图表:占据上半部分,例如设置 pos_bottom="55%"(图表下边界距画布底55%),即图表高度约占45%。同时,为了居中,可以设置 pos_left="20%", pos_right="20%",使其宽度占60%。
  • 左下图表:占据左下角。设置 pos_top="55%"(图表上边界距画布顶55%,即从45%高度处开始),pos_right="55%"(图表右边界距画布右55%,即宽度占左45%)。
  • 右下图表:占据右下角。设置 pos_top="55%", pos_left="55%"(图表左边界距画布左55%,即宽度占右45%)。

关键参数示例:

# 伪代码示意
grid = Grid()
grid.add(bar_chart, grid_opts=opts.GridOpts(pos_bottom="55%", pos_left="20%", pos_right="20%"))
grid.add(line_chart, grid_opts=opts.GridOpts(pos_top="55%", pos_right="55%"))
grid.add(pie_chart, grid_opts=opts.GridOpts(pos_top="55%", pos_left="55%"))
  1. 数据关联实验:创建两个 Line 图表,第一个图表包含系列“销售额”和“成本”,第二个图表包含系列“销售额”和“利润率”。将它们用 Grid 组合后,在交互时观察哪个系列会联动?为什么?
点击查看参考答案

答案:只有“销售额”这个系列会联动。

原因:Grid 的数据关联是基于相同的 series_name。在这个例子中:

  • 图表1的系列名:"销售额", "成本"
  • 图表2的系列名:"销售额", "利润率" 只有 "销售额" 这个名称在两个图表中都存在。因此,当点击图例操作“销售额”时,两个图表中对应的“销售额”线条会同时高亮或隐藏。而“成本”和“利润率”因为名称唯一,只影响其所在的图表。

本章小结

本节我们学习了 pyecharts 中用于构建组合图表的三个核心组件,它们各有其适用的场景:

  • Grid:当你需要对图表位置进行像素级精确控制,或者需要图表间数据联动时,它是首选。适用于制作严谨的分析报告或数据大屏中的固定布局模块。
  • Page:当你需要快速生成一个包含多个图表的自适应页面,或者希望提供交互式布局能力(如让用户自行拖拽排列)时,它非常方便。常用于生成可分享的数据看板。
  • Tab:当图表数量较多,且屏幕空间有限,不需要同时展示所有图表时,使用 Tab 可以保持界面整洁,用户按需切换查看。

📋 行动清单

  • 使用 Grid 组件,将你之前项目中生成的至少两个关联图表组合在一起,并调整到一个合理的布局。
  • 尝试使用 Page 组件的 DraggablePageLayout,创建一个包含3-4个图表的小型看板,并在浏览器中体验拖拽布局功能。
  • 思考你的某个数据分析结果,如果图表超过5个,考虑如何使用 Tab 组件来组织它们,并写出大致的代码结构。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 11_组合图表及仪表盘制作.ipynb · ECharts 课程配套资源
    IPYNB · 章级代码与输出
    下载
  • simple_page.html · ECharts 课程配套资源
    课程配套文件
    下载