There are some files generate by my program, I need a button when I press files will be download by my browser, but I don’t know how to do that. could streamlit provide this function?
not directly, but there is a workaround. Its discussed in the following contribution: File Download Workaround added to awesome-streamlit.org.
I have created the following function for myself and use it frequently. It works fine for bigger files too, my files often have thousands of rows and so far I haven’t hit a limit yet.
st.markdown(get_table_download_link(df), unsafe_allow_html=True)
def get_table_download_link(df):
"""Generates a link allowing the data in a given panda dataframe to be downloaded
in: dataframe
out: href string
"""
csv = df.to_csv(index=False)
b64 = base64.b64encode(csv.encode()).decode() # some strings <-> bytes conversions necessary here
href = f'<a href="data:file/csv;base64,{b64}">Download csv file</a>'
Thanks!! Can’t imagine I missed this post ,I should search more carefully before I post next time
hey using that opens a new tab with title about:blank#blocked
and nothing happens
please help
This works for me, just make sure to return href at the bottom of the get_table_download_link function
Heya, this works for me, but the files download without the .csv extension. Is there a way to make sure that the .csv extension occurs or specify the name of the csv file?
Thank you!
I haven’t found a way to do that automatically, but one can always edit the filename to filename.csv when saving the link with the right mouse click.
@marciorpcoelho I see, thank you for putting this workaround together it is very useful!
Why did U say that the file is downloaded without the .csv, it’s not true if you have converted your dataframe with the to_csv() method. It’s works like a charm
Adding the ‘download’ tag attribute as shown below allows you to provide a file name and extension.
f'<a href="data:file/csv;base64,{b64}" download="myfilename.csv">Download csv file</a>'
Welcome to the community @dplutchok, and thanks for pointing out the download
argument!
I’ve been searching for a while, a way to do same thing with excel xlsx file. I finally found
a way to make it work, so I decide to share my code here. I hope it will help someone.
python 3, pandas '0.23.4'
import streamlit as st
import base64
from io import BytesIO
def to_excel(df):
output = BytesIO()
writer = pd.ExcelWriter(output, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
processed_data = output.getvalue()
return processed_data
def get_table_download_link(df):
"""Generates a link allowing the data in a given panda dataframe to be downloaded
in: dataframe
out: href string
"""
val = to_excel(df)
b64 = base64.b64encode(val) # val looks like b'...'
return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="extract.xlsx">Download csv file</a>' # decode b'abc' => abc
df = ... # your dataframe
st.markdown(get_table_download_link(df), unsafe_allow_html=True)
# PS: pip install xlsxwriter # pandas need this
This is a great answer for csv files or excel files.
However does it work on midi (*.mid) files? midi files are binary. like the excel files.
Now I dont think i need to encode/decode to b64. what do you think? if i do use the b64 enc/decoding i get
TypeError: a bytes-like object is required, not '_io.BufferedReader’
if i dont it still doesnt work.
you can find an example midi file here example_midi
example:
import base64
def get_midi_download_link(mid):
"""Generates a link allowing the data in a given midi file to be downloaded
in: midi file
out: href string
"""
# val looks like b'...'
return f'<a href="data:application/octet-stream;{mid}" download="example.mid">Download midi file with save as</a>'
with open("105027.mid", 'rb') as inmidi:
st.markdown(get_midi_download_link(inmidi), unsafe_allow_html=True)
Whenever you download the .xlsx file, index column will come in the sheet1. How we can make index = False? Could you please help me out in this?
Hello @goutamborthakur555, welcome to the community !
I believe from the to_excel docs that index=False
should be added to the to_excel
function so :
def to_excel(df):
output = BytesIO()
writer = pd.ExcelWriter(output, engine='xlsxwriter')
df.to_excel(writer, index=False, sheet_name='Sheet1') # <--- here
writer.save()
processed_data = output.getvalue()
return processed_data
Fanilo
Thank you!
Hi, if I make an excel file downloadable and if my excel downloadable file values are in float of 4 decimal place, how to make it to 2 decimal place? i.e while download the file values should come with 2 decimal places.
import streamlit as st
import base64
from io import BytesIO
def to_excel(df):
output = BytesIO()
writer = pd.ExcelWriter(output, engine='xlsxwriter')
df.to_excel(writer, index = False, sheet_name='Sheet1')
workbook = writer.book
worksheet = writer.sheets['Sheet1']
format1 = workbook.add_format({'num_format': '0.00'}) # Tried with '0%' and '#,##0.00' also.
worksheet.set_column('A:A', None, format1) # Say Data are in column A
writer.save()
processed_data = output.getvalue()
return processed_data
def get_table_download_link(df):
"""Generates a link allowing the data in a given panda dataframe to be downloaded
in: dataframe
out: href string
"""
val = to_excel(df)
b64 = base64.b64encode(val) # val looks like b'...'
return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="Your_File.xlsx">Download Excel file</a>' # decode b'abc' => abc
st.markdown(get_table_download_link(df), unsafe_allow_html=True)
df = my dataframe
Position
5.7680
2.7680
5.7680
5.7680
7.2680
5.7680
5.7680
5.7680
5.7680
5.7680
5.7680
5.7680
5.9680
5.7680
2.7680
5.7680
5.7680
5.7680
5.7680
5.7680
Thank, I got the answer. Was supposed this: float_format="%.2f"
import streamlit as st
import base64
from io import BytesIO
def to_excel(df):
output = BytesIO()
writer = pd.ExcelWriter(output, engine='xlsxwriter')
df.to_excel(writer, index = False, sheet_name='Sheet1',float_format="%.2f")
writer.save()
processed_data = output.getvalue()
return processed_data
def get_table_download_link(df):
"""Generates a link allowing the data in a given panda dataframe to be downloaded
in: dataframe
out: href string
"""
val = to_excel(df)
b64 = base64.b64encode(val) # val looks like b'...'
return f'<a href="data:application/octet-stream;base64,{b64.decode()}" download="Your_File.xlsx">Download Excel file</a>' # decode b'abc' => abc
st.markdown(get_table_download_link(df), unsafe_allow_html=True)
In case if you need to download image:
result = Image.fromarray(predicted_img)
def get_image_download_link(img):
"""Generates a link allowing the PIL image to be downloaded
in: PIL image
out: href string
"""
buffered = BytesIO()
img.save(buffered, format="JPEG")
img_str = base64.b64encode(buffered.getvalue()).decode()
href = f'<a href="data:file/jpg;base64,{img_str}">Download result</a>'
return href
st.markdown(get_image_download_link(result), unsafe_allow_html=True)
This code assumes that you convert you image to PIL format from the numpy array.
If it helps anyone, I posted a version of the function that can handle both dataframes and text: Here's a download function that works for dataframes and txt (posted below for reference)
Also, curious if anyone has any ideas about how to generalize file downloads in Streamlit. For example: CSV, Excel, img, txt, midi, pdf, video formats, etc.
It would also be neat to auto download on button click - or interaction with another Streamlit component - rather than a link being returned. I’ve started researching ways to achieve this, but it’s admittedly not my specialty area. Any thoughts on how to achieve this?
import base64
import streamlit as st
import pandas as pd
def download_link(object_to_download, download_filename, download_link_text):
"""
Generates a link to download the given object_to_download.
object_to_download (str, pd.DataFrame): The object to be downloaded.
download_filename (str): filename and extension of file. e.g. mydata.csv, some_txt_output.txt
download_link_text (str): Text to display for download link.
Examples:
download_link(YOUR_DF, 'YOUR_DF.csv', 'Click here to download data!')
download_link(YOUR_STRING, 'YOUR_STRING.txt', 'Click here to download your text!')
"""
if isinstance(object_to_download,pd.DataFrame):
object_to_download = object_to_download.to_csv(index=False)
# some strings <-> bytes conversions necessary here
b64 = base64.b64encode(object_to_download.encode()).decode()