I meant to come back to this thread based on the comment from @stu. Definitely caused some alarm discussing authentication/routing permissions. Our apps implement OAuth directly using flask-dance (instead of dash-auth), so it didn’t end up being a problem.
However, the thought about WYSIWYG, and link validity/server pressure/storage space stuck with me, along with the obvious desire to have filterable downloads (seems like people have been creating pretty complex routes!). I’ve come up with an alternative client-based solution that addresses those problems. I use it now when handling large real-time IoT data streams. I put together a basic working demo this holiday weekend, which is now running off of a free heroku instance: https://dash-clientside-demo.herokuapp.com
Repository is on github.
Summary: the app uses FileSaverJS to create a blob out of data accessible in the browser application. It’s implemented with clientside callbacks so large data overhead doesn’t need to pass between the server and client an extra time. Particularly important when talking about large sets of processed data that might cause your worker threads to time out. Note that FileSaverJS also eliminates the browser download caps discussed in this thread.
NOTE: … older browsers may not be compatible. FileSaver requires browsers to support the Blob structure. Here’s the project’s Supported Browsers list.
In the example, data comes directly from figure.data (so… not exactly the same as saving a pandas df). It’s just grabbing the trace data from a time series scattergl trace. There’s no reason you can’t generate a blob/file directly from any object that could be passed in via callback. In some cases the data doesn’t even need to be passed in. Some examples:
- save selected data from a figure by callback:
Input('figure-id', 'selectedData')
@rccg - directly access session storage via
window.sessionStorage.getItem(..)
instead of sending the contents ofdcc.Store
in a callback @praetor - If a static file really needs to be served, you could place it in a web-accessible path (e.g. /assets) and access them through an
await fetch()
call (warning: not secure)
...
# FileSaverJS supports 500MB downloads from the browser!
app.clientside_callback(
ClientsideFunction('download', 'csvDownload'),
Output('button-csv-target', 'children'),
[Input('button-csv-download', 'n_clicks')],
[State('btc-signal', 'figure')]
)