The above solutions did not work for me. But I finally found a way to do this using dash_core_components.Download
and dash_html_components.Button
along with the normal Dash callbacks
Here is a reproducible example that downloads a zip folder with some dummy csv
files in it.
import dash
from dash.dependencies import Output, Input
import dash_html_components as html
import dash_core_components as dcc
import os
import zipfile
import tempfile
# helper function for closing temporary files
def close_tmp_file(tf):
try:
os.unlink(tf.name)
tf.close()
except:
pass
# app layout
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div(
[
html.Button("Download ZIP folder with dummy csv", id="btn_zip"),
dcc.Download(id="download-dataframe-zip"),
]
)
# sample dataframes for zipping
import pandas as pd
df1 = pd.DataFrame({"a": [1, 2, 3, 4], "b": [2, 1, 5, 6], "c": ["x", "x", "y", "y"]})
df2 = pd.DataFrame({"d": [6, 2, 3, 9], "e": [3, 2, 7, 8], "f": ["t", "v", "s", "b"]})
df_dict = {"df1":df1,"df2":df2}
# app callbacks
@app.callback(
Output("download-dataframe-zip", "data"),
Input("btn_zip", "n_clicks"),
prevent_initial_call=True,
)
def func(n_clicks):
zip_dict = {}
# add dataframes to zip file using temporary files
for name,df in df_dict.items():
df_temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.csv')
df.to_csv(df_temp_file.name)
df_temp_file.flush()
zip_dict[name] = df_temp_file.name
zip_tf = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
zf = zipfile.ZipFile(zip_tf, mode='w', compression=zipfile.ZIP_DEFLATED)
for name,fn in zip_dict.items():
zf.write(fn,f"{name}.csv")
# close uploaded temporary files
zf.close()
zip_tf.flush()
zip_tf.seek(0)
[close_tmp_file(_tf) for _tf in zip_dict]
close_tmp_file(zip_tf)
return dcc.send_file(zip_tf.name,filename="mydfs.zip")
if __name__ == "__main__":
app.run_server(debug=True)