Announcing Dash Bio 1.0.0 🎉 : a one-stop-shop for bioinformatics and drug development visualizations.

Download component as image using clientside_callback

Hello,

I present a simple example for downloading a component as an image using clientside_callbacks. We achieve this by using the dom-to-image javascript function.

I wanted to display the filters and a message alongside the graph for sharing purposes. Prior to this, I found users were sharing the graphs they created but not including the filters they applied to the data being shown. I initially tried this using html2pdf; however 1) the users prefer images for sharing and 2) the pdf kept cutting off and I couldn’t get it debugged properly. I finally found dom-to-image which made doing this a lot easier.

Here is how I implemented it:

  1. Add the dom-to-image function to our external scripts (link to cdn in code), or download and serve it locally.
  2. Create button with id=download-image
  3. Create a component with `id=‘component-to-save’
  4. Define a clientside_callback when the button is clicked
  5. Call the following function:
function(n_clicks){
    if(n_clicks > 0){
        domtoimage.toBlob(document.getElementById('component-to-save'))
            .then(function (blob) {
                window.saveAs(blob, 'download.png');
            }
        );
    }
}

Full example:

import dash
from dash import html, clientside_callback, Input, Output
import dash_bootstrap_components as dbc

app = dash.Dash(
    __name__,
    external_stylesheets=[dbc.themes.BOOTSTRAP],
    external_scripts=[
        {'src': 'https://cdn.jsdelivr.net/npm/dom-to-image@2.6.0/dist/dom-to-image.min.js'}
    ]
)

app.layout = html.Div(
    [
        html.H1('Title of the page'),
        html.P('The outside of the card is not saved.'),
        dbc.Button(
            'Download as image',
            id='download-image'
        ),
        dbc.Card(
            'Everything in here is downloaded as an image',
            body=True,
            id='component-to-save'
        )
    ]
)


clientside_callback(
    """
    function(n_clicks){
        if(n_clicks > 0){
            domtoimage.toBlob(document.getElementById('component-to-save'))
                .then(function (blob) {
                    window.saveAs(blob, 'download.png');
                }
            );
        }
    }
    """,
    Output('download-image', 'n_clicks'),
    Input('download-image', 'n_clicks')
)

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

I hope this helps!

Brad

5 Likes

HI Brad @raptorbrad
This is amazing. Thank you for sharing with the community. This makes sharing images a lot simpler. And all this will just one clientside_callback :clap:

1 Like

Update: I started running into the following error in the dom-to-image function.
TypeError setting getter-only properly className...

After some digging, I found there is an issue with FontAwesome icons being located on the same page the download is happening (either in or outside of the downloadable content). Bootstrap icons do not raise this error.

1 Like