You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PyScript在HTML中嵌入Matplotlib财富分布图遇加载问题求助

使用PyScript集成Python财富分布图表到网页(解决本地CSV加载与无限加载问题)

核心问题定位

你遇到的页面无限加载和无内容输出,大概率是因为PyScript运行在浏览器WebAssembly环境中,无法直接读取本地文件系统路径,同时Matplotlib的默认渲染方式不兼容浏览器DOM,导致代码阻塞或无输出。以下是针对性的解决方案:


1. 修正CSV文件加载方式

PyScript不能像本地Python那样用pd.read_csv("local_path.csv")读取文件,必须通过HTTP请求加载静态资源。把你的CSV文件放在网页同目录下(比如wealth_data.csv),用pyfetch异步获取内容:

import pandas as pd
from pyodide.http import pyfetch
import asyncio
from io import StringIO

async def load_data():
    response = await pyfetch("wealth_data.csv")
    if response.status == 200:
        csv_content = await response.text()
        return pd.read_csv(StringIO(csv_content))
    else:
        raise Exception(f"数据加载失败: {response.status}")

# 异步加载数据,避免阻塞页面
df = asyncio.run(load_data())

2. 适配Matplotlib浏览器渲染

Matplotlib默认的后端无法直接在浏览器中输出,需要把图表转为图片插入DOM:

import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
import base64
from js import document

def plot_wealth_distribution(country):
    # 替换为你的原有图表生成逻辑
    country_data = df[df['country'] == country]
    fig, ax = plt.subplots(figsize=(8, 6))
    ax.bar(country_data['percentile'], country_data['wealth'])
    ax.set_title(f"{country} 财富百分位分布")
    ax.set_xlabel("财富百分位")
    ax.set_ylabel("财富值 (USD)")

    # 将图表转为图片并插入网页
    canvas = FigureCanvas(fig)
    canvas.draw()
    img_data = canvas.tostring_rgb()
    width, height = fig.get_size_inches() * fig.dpi
    img = document.createElement("img")
    img.src = f"data:image/png;base64,{base64.b64encode(img_data).decode()}"
    img.width = width
    img.height = height
    
    # 清空旧图表,添加新图表
    chart_container = document.getElementById("chart-container")
    while chart_container.firstChild:
        chart_container.removeChild(chart_container.firstChild)
    chart_container.appendChild(img)
    plt.close(fig) # 释放资源,避免内存泄漏

3. 添加用户交互(国家选择功能)

在HTML中添加交互元素,并用PyScript绑定事件:

HTML部分

<div>
  <label for="country-select">选择国家:</label>
  <select id="country-select"></select>
  <button id="plot-btn">生成图表</button>
</div>
<div id="chart-container"></div>

PyScript部分

# 动态填充国家选项
countries = df['country'].unique()
select = document.getElementById("country-select")
for country in countries:
    option = document.createElement("option")
    option.value = country
    option.textContent = country
    select.appendChild(option)

# 绑定按钮点击事件
def on_plot_click(event):
    selected_country = document.getElementById("country-select").value
    plot_wealth_distribution(selected_country)

document.getElementById("plot-btn").addEventListener("click", on_plot_click)

4. 完整HTML框架示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>国家财富分布对比工具</title>
    <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
    <script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
    <h1>国家财富百分位分布对比</h1>
    <div>
        <label for="country-select">选择国家:</label>
        <select id="country-select"></select>
        <button id="plot-btn">生成图表</button>
    </div>
    <div id="chart-container"></div>

    <py-env>
      - pandas
      - matplotlib
    </py-env>

    <py-script>
      # 这里放入上述所有Python代码
      import pandas as pd
      from pyodide.http import pyfetch
      import asyncio
      from io import StringIO
      import matplotlib.pyplot as plt
      from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
      import base64
      from js import document

      async def load_data():
          response = await pyfetch("wealth_data.csv")
          if response.status == 200:
              csv_content = await response.text()
              return pd.read_csv(StringIO(csv_content))
          else:
              raise Exception(f"数据加载失败: {response.status}")

      df = asyncio.run(load_data())

      def plot_wealth_distribution(country):
          country_data = df[df['country'] == country]
          fig, ax = plt.subplots(figsize=(8, 6))
          ax.bar(country_data['percentile'], country_data['wealth'])
          ax.set_title(f"{country} 财富百分位分布")
          ax.set_xlabel("财富百分位")
          ax.set_ylabel("财富值 (USD)")

          canvas = FigureCanvas(fig)
          canvas.draw()
          img_data = canvas.tostring_rgb()
          width, height = fig.get_size_inches() * fig.dpi
          img = document.createElement("img")
          img.src = f"data:image/png;base64,{base64.b64encode(img_data).decode()}"
          img.width = width
          img.height = height
          
          chart_container = document.getElementById("chart-container")
          while chart_container.firstChild:
              chart_container.removeChild(chart_container.firstChild)
          chart_container.appendChild(img)
          plt.close(fig)

      countries = df['country'].unique()
      select = document.getElementById("country-select")
      for country in countries:
          option = document.createElement("option")
          option.value = country
          option.textContent = country
          select.appendChild(option)

      def on_plot_click(event):
          selected_country = document.getElementById("country-select").value
          plot_wealth_distribution(selected_country)

      document.getElementById("plot-btn").addEventListener("click", on_plot_click)
    </py-script>
</body>
</html>

关键注意事项

  • 确保CSV文件和HTML文件放在同一目录,或在pyfetch中使用正确的相对路径
  • <py-env>必须声明所有依赖包(比如pandas、matplotlib),否则会导致加载失败
  • 所有异步操作必须用async/await处理,避免阻塞页面线程

内容的提问来源于stack exchange,提问作者Leo Wu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 07:15:42