在Dash中下载CSV文件

4

我正在使用Dash Plotly构建一个应用程序,该应用程序具有保存csv文件的选项(在运行时创建),但我在保存csv文件时遇到了问题。

我的尝试是使用html.A组件,并使用以下数据设置href属性:

csv_string = df.to_csv(encoding='utf-8', index=True)
csv_string = "data:text/csv;charset=utf-8," + urllib.parse.quote(csv_string)

csv_string是我为href属性分配的数据。 我看到有人推荐这种方法,它似乎确实有效。

当数据框太大时,问题出现了。 当发生这种情况时,尝试保存文件时会出现下载错误。

  1. 您认为我是否正确分类了问题? 大小问题真的可能吗?

  2. 您认为我可以怎样解决这个问题? 是否有其他解决方案可用于保存文件? 我需要说的是,我不想将文件下载到静态文件夹中。 我需要有一种解决方案,可以将文件下载到用户的默认下载文件夹中或启用用户选择要将文件保存到哪个文件夹的选项(也许会弹出窗口)。

编辑: 我找到了这个链接:http://chandrewz.github.io/blog/downloading-large-csv-files-via-href,描述了我遇到的问题。 是否有类似作者在Python中建议的解决方案?

2个回答

15
dash-extensions软件包中的Download组件使用Blob执行下载操作,因此可能会解决您的问题。这是一个小例子,
import dash
import dash_html_components as html
import numpy as np
import pandas as pd

from dash.dependencies import Output, Input
from dash_extensions import Download
from dash_extensions.snippets import send_data_frame

# Generate some example data.
data = np.column_stack((np.arange(10), np.arange(10) * 2))
df = pd.DataFrame(columns=["a column", "another column"], data=data)
# Create app.
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([html.Button("Download csv", id="btn"), Download(id="download")])

@app.callback(Output("download", "data"), [Input("btn", "n_clicks")])
def generate_csv(n_nlicks):
    return send_data_frame(df.to_csv, filename="some_name.csv")

if __name__ == '__main__':
    app.run_server()

如果你决定尝试它,你可以通过pip安装该软件包。

pip install dash-extensions==0.0.18
免责声明:我是Dash扩展的作者。
编辑:根据Dash 1.20.0版本,“Download”组件已经合并到“dash-core-components”中。因此,上述示例可以重新编写而无需使用任何第三方库。
import dash
import dash_html_components as html
import dash_core_components as dcc
import numpy as np
import pandas as pd
from dash.dependencies import Output, Input

# Generate some example data.
data = np.column_stack((np.arange(10), np.arange(10) * 2))
df = pd.DataFrame(columns=["a column", "another column"], data=data)
# Create app.
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([html.Button("Download csv", id="btn"), dcc.Download(id="download")])

@app.callback(Output("download", "data"), [Input("btn", "n_clicks")])
def generate_csv(n_nlicks):
    return dcc.send_data_frame(df.to_csv, filename="some_name.csv")

if __name__ == '__main__':
    app.run_server()

1
不错的功能!有一个问题,当我将其添加到Dash应用程序中时,默认情况下每次回调都会点击按钮,而不仅仅是在我单击它时,因此会下载比所需更多的文件。有没有解决方法? - Tomás Carrera de Souza
谢谢!如果您将按钮设置为回调的唯一输入,并添加prevent_initial_callback标志,则下载应该仅在单击按钮时开始。 - emher

1
以下是我使用Dash框架允许下载CSV文件的方法,无需额外的库:
from flask import request, Response
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd

# This is in the Dash app layout
# Using Bootstrap class for nice styling
html.A(
    "Download CSV",
    id="download_csv",
    href="#",
    className="btn btn-outline-secondary btn-sm"
)


@app.callback(
    Output('download_csv', 'href'),
    [Input('some_input', 'value')]
)
def some_callback(input_value):
    """Some callback that updates the href for the button"""
    
    return f"/download_csv?value={input_value}"


@app.route('/download_csv')
def dash_download_csv():
    """Regular Flask route.
    Download a CSV file from an existing Pandas DataFrame"""

    # Here's the argument passed to the URL in the Dash callback
    value = request.args.get('value')
    df = get_df(value)
    
    # Convert DataFrame to CSV
    csv = df.to_csv(index=False)

    return Response(
        csv,
        mimetype="text/csv",
        headers={
            "Content-disposition": "attachment; filename=rcom_data.csv"
        }
    )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接