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

如何在Shiny for Python中为Pandas DataFrame添加下载按钮并解决报错

解决Shiny for Python中Pandas DataFrame导出下载的问题

核心问题分析

你的代码存在几个关键问题导致下载报错:

  • 下载按钮ID download_new_df 和装饰器绑定的函数名不匹配
  • 下载函数直接返回DataFrame,不符合Shiny要求——需要将DataFrame内容写入输出流
  • new_df 定义在reactive.Effect内部,作用域受限,下载时无法正确获取最新的DataFrame

修正后的完整代码

import pandas as pd
from shiny import ui, reactive, session, App

# A card component wrapper.
def ui_card(title, *args):
    return (
        ui.div(
            {"class": "card mb-4"},
            ui.div(title, class_="card-header"),
            ui.div({"class": "card-body"}, *args),
        ),
    )
    
app_ui = ui.page_fluid(
    ui.panel_title("pyPARAGON network inference and analysis tool"),

    ### PANEL 1 Gene list
    ui.panel_well(
        ui.tags.h4("Choose a file to upload"),
        ui.row(       
            ui.input_file(
                "initial_file", "", multiple=True
            )
        ),
        ui.row(
            ui.column(
                4,
                ui.input_select(
                    "Column1", "Select input column", {})
            ),
            ui.column(
                4,
                ui.input_select(
                    "Column2", "Select weight column", {})
            )
        )
    ),

    # download panel
    ui_card(
        ui.download_button("download_new_df", "Download_selected_tsv"),
    ),

    ui.output_text_verbatim("txt")
)
            
def server(input, output, session):
    # 用响应式变量存储处理后的DataFrame和输出文件名
    processed_df = reactive.Value(None)
    output_filename = reactive.Value("output.tab")

    @reactive.Effect
    def _():
        file_infos = input.initial_file()   
        Column1 = input.Column1()
        Column2 = input.Column2()
        
        if not file_infos:
            processed_df.set(None)
            return
        
        # 处理上传文件(取最后一个上传的文件)
        file_info = file_infos[-1]
        input_df = pd.read_csv(file_info["datapath"], sep="\t")   
        input_name = ".".join(file_info["name"].split(".")[:-1])       
        columns = input_df.columns.to_list()

        # 更新下拉选择框选项与选中状态
        ui.update_select(
            id="Column1", 
            label="Select input column", 
            choices=[""] + columns,
            selected=Column1 if Column1 in columns else ""
        )
                
        ui.update_select(
            id="Column2", 
            label="Select weight column", 
            choices=[""] + columns,
            selected=Column2 if Column2 in columns else ""
        )

        # 生成并存储处理后的DataFrame
        if Column1 and Column2 and Column1 in columns and Column2 in columns:
            new_df = input_df[[Column1, Column2]]
            processed_df.set(new_df)
            output_filename.set(f"{input_name}.tab")
        else:
            processed_df.set(None)

    # 绑定下载按钮对应的处理函数
    @session.download(id="download_new_df", filename=lambda: output_filename())
    def download_new_df():
        df = processed_df()
        if df is not None:
            # 将DataFrame转为TSV格式字节流返回
            yield df.to_csv(sep="\t", index=False).encode("utf-8")

app = App(app_ui, server, debug=True)

关键修改点说明

  • 匹配下载按钮ID:@session.download的id参数设置为download_new_df,与UI中下载按钮的ID完全对应
  • 响应式变量存储数据:用reactive.Value保存处理后的DataFrame和输出文件名,确保下载时能获取最新的处理结果
  • 正确生成下载流:通过df.to_csv(sep="\t", index=False).encode("utf-8")生成TSV格式的字节流,再通过yield返回给下载组件,实现类似pd.DataFrame.to_csv()的导出效果
  • 完善边界检查:增加列存在性验证,避免无效列选择导致的报错;多文件上传时默认取最后一个文件处理
  • 优化下拉框选中逻辑:确保选中的列在当前文件的列列表中,避免无效选中状态

内容的提问来源于stack exchange,提问作者M. Kaan ARICI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:40:30