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

如何用ipywidget按钮下载带样式的Pandas DataFrame Excel文件?

解决带样式Pandas DataFrame的ipywidget按钮下载问题

以下是修正后的完整代码,同时解决你提出的两个疑问:

import ipywidgets
import numpy as np
import pandas as pd
import io
import base64

from IPython.display import HTML, display
from ipywidgets import widgets
from typing import Callable
import pandas.io.formats.style

class DownloadButtonExcel(ipywidgets.Button):
    """
    带动态内容的下载按钮
    点击按钮时通过回调生成带样式的Excel文件并触发下载,无需本地存储文件
    """

    def __init__(self, filename: str, contents: Callable[[], pandas.io.formats.style.Styler], **kwargs):
        super(DownloadButtonExcel, self).__init__(**kwargs)
        self.filename = filename
        self.contents = contents
        self.on_click(self.__on_click)
        self.output = widgets.Output()
        display(self.output)

    def __on_click(self, b):
        # 点击按钮时才获取带样式的DataFrame
        styler = self.contents()
        
        # 使用内存缓冲区存储Excel内容,不写入本地文件
        buffer = io.BytesIO()
        styler.to_excel(buffer, engine='openpyxl')
        buffer.seek(0)
        
        # 将缓冲区内容编码为base64,生成可嵌入HTML的Data URI
        b64 = base64.b64encode(buffer.read()).decode()
        data_uri = f"data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}"
        
        # 生成唯一ID避免浏览器缓存
        digest = pd.util.hash_pandas_object(styler.data).sum()
        id = f"dl_{digest}"

        with self.output:
            # 清空之前的输出,避免重复生成下载链接
            self.output.clear_output(wait=True)
            display(
                HTML(
                    f"""
                    <html>
                    <body>
                    <a id="{id}" download="{self.filename}" href="{data_uri}"></a>
                    <script>
                        document.getElementById('{id}').click();
                    </script>
                    </body>
                    </html>
                    """
                )
            )

# 测试示例
df = pd.DataFrame(
    [[38.0, 2.0, 18.0, 22.0, 21, np.nan],[19, 439, 6, 452, 226,232]],
    index=pd.Index(['Tumour (Positive)', 'Non-Tumour (Negative)'], name='Actual Label:'),
    columns=pd.MultiIndex.from_product(
        [['Decision Tree', 'Regression', 'Random'],['Tumour', 'Non-Tumour']], 
        names=['Model:', 'Predicted:']
    )
)

df_style = df.style.format(precision=2).background_gradient().hide(axis='index')

download_button_excel = DownloadButtonExcel(
    filename="Test.xlsx",
    contents=lambda: df_style,
    description="下载带样式Excel",
    style={"button_color": "#4CAF50"}
)

问题解决说明

1. 实现类似CSV的编解码下载逻辑

  • 不再使用本地文件存储,改用io.BytesIO内存缓冲区暂存Styler生成的Excel内容
  • 通过base64.b64encode将二进制Excel内容编码为字符串,生成符合Data URI规范的链接,直接嵌入到HTML的<a>标签中,浏览器会识别并触发文件下载,完全在内存中完成处理,不会留下本地文件

2. 将Excel生成逻辑移至点击触发函数内

  • 所有Excel文件的生成、编码逻辑都放在按钮的__on_click方法中,只有当用户点击按钮时才会执行styler.to_excel等操作,避免提前生成文件,完全由点击事件触发下载流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 10:11:07