Example: Upload and Download Files with Plotly Dash¶
This example demonstrates uploading and downloading files to and from a Plotly
Dash app. This example simply saves the files to disk and serves them back to
user, but if you want to process uploaded files, try adapting the
save_file() function in this example.
Python Source Code¶
import base64
import os
from urllib.parse import quote as urlquote
from flask import Flask, send_from_directory
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
UPLOAD_DIRECTORY = "/project/app_uploaded_files"
if not os.path.exists(UPLOAD_DIRECTORY):
os.makedirs(UPLOAD_DIRECTORY)
# Normally, Dash creates its own Flask server internally. By creating our own,
# we can create a route for downloading files directly:
server = Flask(__name__)
app = dash.Dash(server=server)
@server.route("/download/<path:path>")
def download(path):
"""Serve a file from the upload directory."""
return send_from_directory(UPLOAD_DIRECTORY, path, as_attachment=True)
app.layout = html.Div(
[
html.H1("File Browser"),
html.H2("Upload"),
dcc.Upload(
id="upload-data",
children=html.Div(["Drag and drop or click to select a file to upload."]),
style={
"width": "100%",
"height": "60px",
"lineHeight": "60px",
"borderWidth": "1px",
"borderStyle": "dashed",
"borderRadius": "5px",
"textAlign": "center",
"margin": "10px",
},
multiple=True,
),
html.H2("File List"),
html.Ul(id="file-list"),
],
style={"max-width": "500px"},
)
def save_file(name, content):
"""Decode and store a file uploaded with Plotly Dash."""
data = content.encode("utf8").split(b";base64,")[1]
with open(os.path.join(UPLOAD_DIRECTORY, name), "wb") as fp:
fp.write(base64.decodebytes(data))
def uploaded_files():
"""List the files in the upload directory."""
files = []
for filename in os.listdir(UPLOAD_DIRECTORY):
path = os.path.join(UPLOAD_DIRECTORY, filename)
if os.path.isfile(path):
files.append(filename)
return files
def file_download_link(filename):
"""Create a Plotly Dash 'A' element that downloads a file from the app."""
location = "/download/{}".format(urlquote(filename))
return html.A(filename, href=location)
@app.callback(
Output("file-list", "children"),
[Input("upload-data", "filename"), Input("upload-data", "contents")],
)
def update_output(uploaded_filenames, uploaded_file_contents):
"""Save uploaded files and regenerate the file list."""
if uploaded_filenames is not None and uploaded_file_contents is not None:
for name, data in zip(uploaded_filenames, uploaded_file_contents):
save_file(name, data)
files = uploaded_files()
if len(files) == 0:
return [html.Li("No files yet!")]
else:
return [html.Li(file_download_link(filename)) for filename in files]
if __name__ == "__main__":
app.run_server(debug=True, port=8888)
Deployment¶
Assuming that you store this file as myapp.py to
/project/myappdirectory in your project workspace, the settings you need to
deploy this in Faculty are:
Working Directory:
/project/myappdirectoryPython Module:
myappPython Object:
server(the name of the Flask object used by Dash)
You can also follow the instructions in Developing the application to run the app in development mode.
Usage¶
The app provides a widget to upload files, and maintains a list of download links for previously uploaded files:
Only files that fit in memory on the server you run your app on will work, however for most applications this will not be a problem.