杰瑞科技汇

Python与PyEcharts如何实现数据通信?

这里的“通信”可以从两个层面来理解:

Python与PyEcharts如何实现数据通信?-图1
(图片来源网络,侵删)
  1. 后端 Python 与前端 JavaScript 的通信:这是 Pyecharts 的核心工作机制,理解它对于深入使用 Pyecharts 至关重要。
  2. Pyecharts 生成的图表与外部数据源的通信:这是指如何在用户与图表交互时,让图表与后端服务器进行数据请求和更新,实现动态效果。

我会分两部分来详细解释。


第一部分:Pyecharts 的核心通信机制 (Python ↔ JavaScript)

Pyecharts 本身是一个纯 Python 库,但它最终生成的是标准的 HTML 文件,这个 HTML 文件包含了 HTML、CSS 和 JavaScript 代码,Pyecharts 的“魔法”就在于它如何将 Python 中的图表配置,无缝地转换成 JavaScript 中 ECharts 库能够理解的配置。

基本原理:生成一个独立的 HTML 文件

这是最基础、最常用的方式,当你调用 chart.render() 方法时,Pyecharts 会做以下事情:

  • 收集配置:将你在 Python 代码中设置的所有图表组件(如标题 Title、图例 Legend、X轴 XAxis、Y轴 YAxis、系列 Series 等)收集起来。
  • 序列化:将这些 Python 对象序列化为一个 JSON 字符串。
  • 生成 HTML 模板:Pyecharts 内置了一个 HTML 模板,这个模板引入了 ECharts 的 JavaScript 库,并预留了一个 <div> 容器来放置图表。
  • 注入配置:将上一步生成的 JSON 字符串注入到 HTML 模板的 <script> 标签中。
  • 写入文件:将最终生成的完整 HTML 字符串写入到一个 .html 文件中。

示例代码:

Python与PyEcharts如何实现数据通信?-图2
(图片来源网络,侵删)
from pyecharts.charts import Bar
from pyecharts import options as opts
# 1. 准备数据
x_data = ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
y_data = [5, 20, 36, 10, 75, 90]
# 2. 创建图表实例并配置
bar = (
    Bar()
    .add_xaxis(x_data)
    .add_yaxis("商家A", y_data)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="Pyecharts 示例"),
        xaxis_opts=opts.AxisOpts(name="商品"),
        yaxis_opts=opts.AxisOpts(name="销量"),
    )
)
# 3. 渲染图表到 HTML 文件
# 这一步就是“通信”发生的地方
bar.render("my_first_chart.html")
print("图表已生成 my_first_chart.html")

生成的 my_first_chart.html 文件内容(简化版):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">Pyecharts 示例</title>
    <!-- 1. 引入 ECharts JavaScript 库 -->
    <script src="https://assets.pyecharts.org/assets/v5/echarts.min.js"></script>
</head>
<body>
    <!-- 2. 图表容器 -->
    <div id="chart_id" style="width:900px;height:500px;"></div>
    <script>
        // 3. Python 中的配置被转换成了这里的 JavaScript 对象
        var chart_id = echarts.init(document.getElementById('chart_id'));
        var option_id = {
            "title": {"text": "Pyecharts 示例"},
            "xAxis": {"type": "category", "data": ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"], "name": "商品"},
            "yAxis": {"type": "value", "name": "销量"},
            "series": [
                {
                    "name": "商家A",
                    "type": "bar",
                    "data": [5, 20, 36, 10, 75, 90]
                }
            ]
        };
        chart_id.setOption(option_id);
    </script>
</body>
</html>

小结:在这种模式下,Python 脚本只在运行时与 Pyecharts 库进行“通信”,生成一个静态的 HTML 文件,一旦文件生成,Python 脚本就结束了后续工作,图表的渲染和交互完全由浏览器中的 JavaScript 完成。

在 Jupyter Notebook/Lab 中内嵌显示

在 Jupyter 环境中,Pyecharts 使用了 IPythondisplay 机制,流程类似,但它不是生成文件,而是将最终的 HTML 字符串直接返回给 Jupyter 内核,Jupyter 再将其渲染成交互式组件显示在单元格中。


第二部分:实现动态数据通信 (图表 ↔ 后端服务器)

这才是现代 Web 应用的核心,当用户点击图表上的某个元素(比如一个柱状图的柱子)时,我们希望图表能向后端发送一个请求,获取新的数据并更新自身。

Python与PyEcharts如何实现数据通信?-图3
(图片来源网络,侵删)

这需要 前后端配合 完成。

场景:点击柱状图的柱子,加载该商品的详细销售数据

技术栈:

  • 前端:Pyecharts (ECharts) + JavaScript (用于监听事件和发送请求)
  • 后端:Python (使用 Flask 或 FastAPI 等框架) + 数据库 (或模拟数据)

步骤分解:

第 1 步:后端 API 准备 (使用 Flask)

后端需要提供一个 API 接口,当收到特定商品的请求时,返回该商品的详细数据。

# app.py
from flask import Flask, jsonify, request
app = Flask(__name__)
# 模拟一个数据库
product_details_db = {
    "衬衫": {"一月": 10, "二月": 20, "三月": 15},
    "羊毛衫": {"一月": 25, "二月": 18, "三月": 30},
    "雪纺衫": {"一月": 15, "二月": 22, "三月": 28},
    "裤子": {"一月": 12, "二月": 15, "三月": 18},
    "高跟鞋": {"一月": 30, "二月": 45, "三月": 50},
    "袜子": {"一月": 40, "二月": 35, "三月": 42},
}
@app.route('/api/product_details', methods=['GET'])
def get_product_details():
    # 从请求的 URL 参数中获取商品名
    product_name = request.args.get('name')
    if product_name and product_name in product_details_db:
        # 返回 JSON 格式的详细数据
        return jsonify(product_details_db[product_name])
    else:
        # 如果商品不存在,返回错误
        return jsonify({"error": "Product not found"}), 404
if __name__ == '__main__':
    app.run(debug=True)

启动后端服务:python app.py,它会在 http://127.0.0.1:5000 上运行。

第 2 步:前端 Pyecharts 图表配置 (关键)

我们需要在 Pyecharts 中添加 JavaScript 代码,用于监听图表的点击事件,并在事件触发时调用我们刚刚创建的后端 API。

注意:Pyecharts 从 V1.x 版本开始,推荐使用 JsCode 来嵌入自定义的 JavaScript 代码。

# frontend_chart.py
from pyecharts.charts import Bar
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
# 1. 准备初始数据
x_data = ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
y_data = [5, 20, 36, 10, 75, 90]
# 2. 定义 JavaScript 回调函数
# 这段代码将在浏览器中执行
on_js_click = """
    function(params) {
        // params 是被点击元素的数据信息
        // params.name 是被点击的柱子的名称(即商品名)
        const productName = params.name;
        // 使用 fetch API 向后端发送 GET 请求
        fetch(`/api/product_details?name=${productName}`)
          .then(response => {
            if (!response.ok) {
              throw new Error('Network response was not ok');
            }
            return response.json(); // 解析 JSON 响应
          })
          .then(data => {
            // 我们得到了后端返回的详细数据
            console.log('Received data:', data);
            // 获取图表实例
            const myChart = echarts.getInstanceByDom(document.getElementById('chart_id'));
            // 准备新的图表配置
            const newOption = {
                title: { text: `${productName} - 月度销量详情` },
                tooltip: { trigger: 'axis' },
                xAxis: { type: 'category', data: Object.keys(data) },
                yAxis: { type: 'value' },
                series: [{ 
                    type: 'bar', 
                    name: '月度销量',
                    data: Object.values(data) 
                }]
            };
            // 使用新的配置更新图表
            myChart.setOption(newOption, true); // true 表示不合并,而是替换全部选项
          })
          .catch(error => {
            console.error('Error fetching data:', error);
          });
    }
"""
# 3. 创建图表实例
bar = (
    Bar()
    .add_xaxis(x_data)
    .add_yaxis("商家A", y_data)
    .set_global_opts(
        title_opts=opts.TitleOpts(title="点击柱子查看详情"),
        # 4. 绑定点击事件处理器
        # 使用 JsCode 将我们写的 Python 字符串包裹起来
        tooltip_opts=opts.TooltipOpts(
            trigger="axis",
            formatter=JsCode("""
                function(params) {
                    return params[0].name + ': ' + params[0].data;
                }
            """)
        )
    )
    # 5. 在 series 中绑定点击事件
    .set_series_opts(
        label_opts=opts.LabelOpts(is_show=False),
        # on_click 是 ECharts 提供的事件
        # 我们将自定义的 on_js_click 函数赋给它
        emphasis_opts=opts.EmphasisOpts(
            scale=True,
            item_style={"shadowBlur": 10, "shadowColor": "rgba(0,0,0,0.3)"}
        ),
        # 这是关键!将 Python 函数传递给 on_click
        on_click=JsCode(on_js_click)
    )
)
# 6. 渲染图表
# 为了让 JavaScript 中的 'chart_id' 能找到对应的 div,我们需要确保 render 的 id 一致
# 默认情况下,render 会生成一个随机 id,所以最好手动指定
bar.render("interactive_chart.html", page_title="交互式图表")
print("交互式图表已生成 interactive_chart.html")

代码解释:

  1. on_js_click 字符串:我们在这里写了一段标准的 JavaScript 代码,它定义了一个函数,这个函数就是 ECharts 的点击事件回调函数。
  2. fetch(...):这是现代浏览器中用于发起网络请求的 API,它向我们的 Flask 后端 (/api/product_details) 发送一个 GET 请求,并将商品名作为查询参数。
  3. .then(...)fetch 返回一个 Promise,我们使用 .then 来处理成功响应(解析 JSON 数据)和后续操作。
  4. echarts.getInstanceByDom(...):这是 ECharts 提供的一个关键方法,它允许我们通过 DOM 元素的 ID 来获取已初始化的图表实例。
  5. myChart.setOption(newOption, true):获取到图表实例后,我们调用 setOption 方法来更新图表,传入 true 作为第二个参数,会清空之前的所有配置,并用新的 newOption 完全替换,实现图表的“刷新”。
  6. JsCode(on_js_click):这是 Pyecharts 提供的桥梁,它告诉 Pyecharts:“on_js_click 这个字符串不是普通的文本,它需要在最终的 HTML 中作为原生 JavaScript 代码执行。” 我们通过 on_click=JsCode(on_js_click) 将这个函数绑定到图表的系列上。

最终效果:

  1. 运行 python app.py 启动后端服务。
  2. 运行 python frontend_chart.py 生成 interactive_chart.html 文件。
  3. 用浏览器打开 interactive_chart.html
  4. 你会看到一个初始的柱状图,点击任意一个柱子(羊毛衫”),浏览器会立即向后端发送请求。
  5. 后端返回 {"一月": 25, "二月": 18, "三月": 30}
  6. 前端 JavaScript 收到数据后,图表会自动更新,显示“羊毛衫”的月度销量详情。
通信类型 机制 关键技术/方法 适用场景
Python ↔ JS (核心机制) Pyecharts 将 Python 对象序列化为 JSON,并注入到 HTML 模板中。 chart.render(), JsCode 生成静态报告、数据看板、在 Jupyter 中展示。
图表 ↔ 后端 (动态交互) 在 Pyecharts 图表中嵌入 JavaScript 事件监听器,通过 fetch/axios 等库与后端 API 通信,然后用返回的数据更新图表。 JsCode, echarts.getInstanceByDom(), fetch(), Flask/FastAPI 需要用户交互来动态加载数据的 Web 应用,如实时监控、数据探索工具。

理解这两个层次的“通信”,你就能从简单地使用 Pyecharts 到灵活地构建复杂的交互式数据可视化应用。

分享:
扫描分享到社交APP
上一篇
下一篇