Plotly Dash Table 如何导出带自定义格式的Excel文件
Dash Table导出带格式Excel的实现方案
问题原因
你之前的写法无法生效的核心原因有两点:
dcc.send_data_frame()的第一个入参要求是DataFrame自带的导出方法(例如df.to_excel),它会自动封装DataFrame的转换逻辑。而writer.save()执行后返回值为None,作用是直接将生成的Excel写入本地磁盘,无法传递给Download组件触发下载。- 带自定义格式的Excel无法仅通过
df.to_excel生成,需要用XlsxWriter完成格式配置后,将完整的Excel字节流传给下载组件。
可行实现方案
不需要将Excel文件存储到本地磁盘,直接在内存中生成带格式的Excel文件,再传递给dcc.Download触发下载即可,完整示例代码如下:
import dash from dash.dependencies import Output, Input import dash_html_components as html import dash_core_components as dcc import pandas as pd import numpy as np from io import BytesIO from xlsxwriter.utility import xl_rowcol_to_cell app = dash.Dash(__name__) app.layout = html.Div([ html.Button("下载带格式Excel", id="btn_xlsx"), dcc.Download(id="download-dataframe-xlsx"), ]) # 这里替换为你自己的DataFrame数据 df = pd.read_excel("../in/excel-comp-datav2.xlsx") @app.callback( Output("download-dataframe-xlsx", "data"), Input("btn_xlsx", "n_clicks"), prevent_initial_call=True, ) def generate_formatted_excel(n_clicks): # 在内存中创建BytesIO对象,替代本地文件路径 output = BytesIO() # 以下是你原有的带格式Excel生成逻辑,输出到内存的output对象 number_rows = len(df.index) df = df.assign(total=(df['Jan'] + df['Feb'] + df['Mar'])) df = df.assign(quota_pct=(1+(df['total'] - df['quota'])/df['quota'])) # 把ExcelWriter的输出指定为内存的BytesIO对象 writer = pd.ExcelWriter(output, engine='xlsxwriter') df.to_excel(writer, index=False, sheet_name='report') workbook = writer.book worksheet = writer.sheets['report'] # 原有格式配置逻辑 worksheet.set_zoom(90) money_fmt = workbook.add_format({'num_format': '$#,##0', 'bold': True}) percent_fmt = workbook.add_format({'num_format': '0.0%', 'bold': True}) total_fmt = workbook.add_format({'align': 'right', 'num_format': '$#,##0', 'bold': True, 'bottom':6}) total_percent_fmt = workbook.add_format({'align': 'right', 'num_format': '0.0%', 'bold': True, 'bottom':6}) worksheet.set_column('B:D', 20) worksheet.set_column('E:E', 5) worksheet.set_column('F:F', 10) worksheet.set_column('G:K', 12, money_fmt) worksheet.set_column('L:L', 12, percent_fmt) for column in range(6, 11): cell_location = xl_rowcol_to_cell(number_rows+1, column) start_range = xl_rowcol_to_cell(1, column) end_range = xl_rowcol_to_cell(number_rows, column) formula = "=SUM({:s}:{:s})".format(start_range, end_range) worksheet.write_formula(cell_location, formula, total_fmt) worksheet.write_string(number_rows+1, 5, "Total",total_fmt) percent_formula = "=1+(K{0}-G{0})/G{0}".format(number_rows+2) worksheet.write_formula(number_rows+1, 11, percent_formula, total_percent_fmt) color_range = "L2:L{}".format(number_rows+1) format1 = workbook.add_format({'bg_color': '#FFC7CE', 'font_color': '#9C0006'}) format2 = workbook.add_format({'bg_color': '#C6EFCE', 'font_color': '#006100'}) worksheet.conditional_format(color_range, {'type': 'top', 'value': '5', 'format': format2}) worksheet.conditional_format(color_range, {'type': 'bottom', 'value': '5', 'format': format1}) # 关闭writer,把所有内容写入BytesIO writer.close() # 把BytesIO的指针移到文件开头,读取完整字节流 output.seek(0) # 用dcc.send_bytes返回内存中的Excel文件,指定文件名 return dcc.send_bytes(output.read(), "带格式导出结果.xlsx") if __name__ == "__main__": app.run_server(debug=True)
注意事项
- 如果你使用的pandas版本低于1.3.0,
writer.close()可以替换为writer.save(),两者功能一致。 - 整个生成过程不会在本地磁盘产生临时文件,所有操作都在内存中完成,性能更高。
内容的提问来源于stack exchange,提问作者Galat
相关产品推荐
相关产品推荐

