はじめに
Pythonのみで記述できるお手軽webフレームワークであるstreamlitはHTMLやCSSの勉強の必要がなくちょっとしたものを作るには非常に便利です。しかしその反面で標準搭載されている機能も少なく、場合によっては自作する必要があります。
今回、結果を出力する際にexcel形式(.xlsx)を利用しようとしたのですが、少々つまずいたので備忘録として残しておきます。
2023/02/15追記
@SaitoTsutomoさんより良い方法を教えていただきました。
記事の下に追記したのでそちらをご参照ください。
ありがとうございます。
内容
from io import BytesIO
import pandas as pd
import streamlit as st
def df_to_xlsx(df):
byte_xlsx = BytesIO()
writer_xlsx = pd.ExcelWriter(byte_xlsx, engine="xlsxwriter")
df.to_excel(writer_xlsx, index=False, sheet_name="Sheet1")
##-----必要に応じてexcelのフォーマット等を設定-----##
workbook = writer_xlsx.book
worksheet = writer_xlsx.sheets["Sheet1"]
format1 = workbook.add_format({"num_format": "0.00"})
worksheet.set_column("A:A", None, format1)
writer_xlsx.save()
##---------------------------------------------##
workbook = writer_xlsx.book
out_xlsx = byte_xlsx.getvalue()
return out_xlsx
df_test = pd.read_excel("test.xlsx")
xlsx_test = df_to_xlsx(df_test)
st.download_button(label="Download", data=xlsx_test, file_name="_test.xlsx")
上記のコードを使うことでDataFrameをcsvではなくxlsxの形式でダウンロードすることが可能になります。
xlsxのエンジンとしてxlsxwriter
を利用するのでこちらのライブラリのインストールを忘れないでください。
xlsxを用いる利点としては
・日本語が入っていても文字化けしない
・画像やグラフの挿入ができる
・非プログラマーにとってはcsvより使いやすい
といった点が挙げられます。
特に日本語を含むcsvを扱いたい場合、デフォルトのst.download_button
では文字化けしてしまいます。
そのため別途ダウンロードリンクを作成する必要があり厄介です。
ダウンロードリンクの例も示しておきます(こちらから流用)。
import base64
import streamlit as st
csv = df.to_csv(index=False)
b64 = base64.b64encode(csv.encode('utf-8-sig')).decode()
href = f'<a href="data:application/octet-stream;base64,{b64}" download="result_utf-8-sig.csv">Download Link</a>'
st.markdown(f"CSVファイルのダウンロード(utf-8 BOM): {href}", unsafe_allow_html=True)
またアプリ画面の見栄えも標準搭載されているst.download_button
の方が綺麗だと思います(好みですが...)。
最後に
streamlitでDataFrameをxlsx形式で出力する方法について記しました。
webフレームワークとしてはほかにFastAPIやDjangoなどもあるので、必要に応じて使い分けたいと思います。
2023/02/15追記
@SaitoTsutomoさんに以下の方法を教えていただきました。
from io import BytesIO
import pandas as pd
import streamlit as st
df = pd.DataFrame(["テスト"], columns=["列A"])
df.to_excel(buf := BytesIO(), index=False)
st.download_button(
"Download",
buf.getvalue(),
"sample.xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
こちらの方がコンパクトに書けるので良いと思います。