Hi,
Welcome to the community!
Please make sure to format your post next time, so the code is more readable. Here is a great guideline, which includes an explanation about preformatted text for code.
The problem is that you are trying to pass a list of fig
directly to the data
of dcc.Download
, and this is not possible. You can find the specs for the “data” dict and some examples in the documentation below:
Your question asks about downloading multiple plots with one button, and that is in my opinion slightly more advanced than a single file download. Therefore I am providing you a simple example of how to do it below:
from dash import Dash, callback, Input, Output, State, dcc, html, ALL
import plotly.express as px
import plotly.graph_objects as go
import io
from base64 import standard_b64decode, b64decode, b64encode
def fig_to_data(fig: go.Figure, filename: str="plot.html") -> dict:
buffer = io.StringIO()
fig.write_html(buffer)
html_bytes = buffer.getvalue().encode()
content = b64encode(html_bytes).decode()
return {
"base64": True,
"content": content,
"type": "text/html",
"filename": filename
}
app = Dash(__name__)
app.layout = html.Div([
dcc.Graph(id={"type": 'graph', "index": 0}, figure=px.scatter(px.data.iris(), x='sepal_width', y='sepal_length', color='species')),
dcc.Graph(id={"type": 'graph', "index": 1}, figure=px.scatter(px.data.iris(), x='petal_length', y='petal_width', color='species')),
html.Button('Download All', id='download-button'),
*[
dcc.Download(id={"type": 'download', "index": i}) for i in range(2)
]
])
@callback(
Output({"type": "download", "index": ALL}, "data"),
[
Input("download-button", "n_clicks"),
State({"type": "graph", "index": ALL}, "figure")
],
prevent_initial_call=True
)
def download_figure(n_clicks, figs):
return [
fig_to_data(go.Figure(fig), filename=f"plot_{idx}.html") for idx, fig in enumerate(figs)
]
if __name__ == '__main__':
app.run_server(debug=True)
Some observations about the example:
- I used the pattern matching callback to simplify a bit, but the idea is quite general: you need N
dcc.Download
components if you intend to download N figures fromdcc.Graph
. There might be ways to do it with a simple component. but I don’t see it being simpler than this approach. -
fig_to_data
exports a html figure, which is interactive just like in the application itself (of course, without the dynamic aspects of re-writing figures with callbacks). You can use other formats and there are examples around. - The example above is heavily inspired by [this part of the documentation]
Hope this helps!