HConBike
HConBike

Reputation: 99

plotly dash download bytes stream

I have an app that produces a zip file that I want to download using dcc.download. I think the zip-creation works fine (I tested it by downloading it directly using "with"). But how its possible to download the stream archive using dcc.download? How do I have to hand it over the correct way?

My code below:

import io
from os import close
import dash
from dash.dependencies import Output, Input
from dash_extensions.snippets import send_bytes
import dash_html_components as html
import dash_core_components as dcc
import base64

import matplotlib.pyplot as plt
import zipfile
from io import BytesIO

app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([html.Button("Download zip", id="btn_txt"), 
                       dcc.Download(id="download-text")]
                     )

@app.callback(
    Output("download-text", "data"),
    Input("btn_txt", "n_clicks"),
    prevent_initial_call=True,
)
def func(n_clicks):
    archive = BytesIO()
    
    with zipfile.ZipFile(archive, mode="w") as zf:
        for i in range(3):
            plt.plot([i, i])
            buf = io.BytesIO()
            plt.savefig(buf)
            plt.close()
            img_name = "fig_{:02d}.png".format(i)
            zf.writestr(img_name, buf.getvalue())
    
    return send_bytes(archive.read(), "some_name.zip")



if __name__ == "__main__":
    app.run_server(debug=False)

Upvotes: 2

Views: 3785

Answers (1)

emher
emher

Reputation: 6024

The first argument of send_bytes should be a function handle that writes content to BytesIO. Adopting your example, the code would be

import io
import dash
import dash_html_components as html
import dash_core_components as dcc
import matplotlib.pyplot as plt
import zipfile

from dash.dependencies import Output, Input

app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([html.Button("Download zip", id="btn_txt"), dcc.Download(id="download-text")])

@app.callback(Output("download-text", "data"), Input("btn_txt", "n_clicks"))
def func(n_clicks):
    def write_archive(bytes_io):
        with zipfile.ZipFile(bytes_io, mode="w") as zf:
            for i in range(3):
                plt.plot([i, i])
                buf = io.BytesIO()
                plt.savefig(buf)
                plt.close()
                img_name = "fig_{:02d}.png".format(i)
                zf.writestr(img_name, buf.getvalue())
    return dcc.send_bytes(write_archive, "some_name.zip")

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

Upvotes: 4

Related Questions