I build a Streamlit app where the end result is two Pandas dataframes that I want the user to download as separate csv files. However, it seems the Download button in Streamlit only allows the downloading of one file. One way of "combining" them is to put them as separate tabs in an Excel file, but that is unacceptable to the ideal workflow.
I then created two download buttons for them, one for each file. However, clicking on the first Download button will cause the whole application to be rerun. After some Googling, there doesn't seem a way to disable this behavior.
I then looked into creating a Zip file, using the 'zipfile' package:
with zipfile.ZipFile('my_test.zip', 'x') as csv_zip:
csv_zip.writestr("data1.csv", pd.DataFrame(data1).to_csv())
csv_zip.writestr("data2.csv", pd.DataFrame(data2).to_csv())
with open("my_test.zip", "rb") as file:
st.download_button(
label = "Download zip",
data = file,
file_name = "mydownload.zip",
mime = 'application/zip'
)
However, when tested locally, this creates 'my_test.zip' in the same directory where my .py codes are. The file would persist even after I end the app. My question:
If I deploy the Streamlit app by hosting it somewhere, would 'my_test.zip' still be created somewhere? Where?
Is there a way to enable the download of a zip file without first creating a zip file in a directory somewhere?
You can create a .zip
file in-memory without storing it to disk with io.BytesIO()
. Indeed, the data
field from st.download
can take bytes.
import streamlit as st
import io
import zipfile
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
for file_name, data in [
("data1.csv", io.BytesIO(b'a,b,c')),
("data2.csv", io.BytesIO(b'd,e,f'))
]:
zip_file.writestr(file_name, data.getvalue())
st.header("Appname")
st.download_button(
"Download csv",
file_name="data.zip",
mime="application/zip",
data=zip_buffer
)
See Python in-memory zip library for more info on how to create in-memory zipfiles.
Also, see the st.download_button
documentation for more info on the mime
and data
arguments.