Dash Python - using external Javascript to display image

Viewed 1862

Dear readers,

I want to display an image on a Python Dash page that is generated by some JS code. See the description here: https://www.altmetric.com/assets/Getting_Started_Altmetric_Badges.pdf. In a static HTML page one would include this script

<script type='text/javascript' src='https://d1bxh8uas1mnw7.cloudfront.net/assets/embed.js'></script>

and this DIV will show the image:

<div class='altmetric-embed' data-badge-type='donut' data-doi="10.1038/nature.2012.9872"></div>

Im trying to get this working in Dash but not even once the image/badge is shown. I tried several options for injecting te DIV (with dash_dangerously_set_inner_html.DangerouslySetInnerHTML() or with the attributesd of DIV using '**{'), and including the SCRIPT (in the custom HEAD of the var index_string, as Html.Script(), as external_scripts and with options serve_locally = False/True), but none seems to work. Good to mention is that Dash serves me a page with only the "Hello World" string but without any images. But when I locally store the generated HTML code to a HTML file and open it in my browser, the images are shown !

Localhost gives me: this view, whereas the same page gives me locally: this view

See included (minimal) non-working example.

Any suggestions here ?

Kind regards, IvoB

#SEE: https://www.altmetric.com/assets/Getting_Started_Altmetric_Badges.pdf
import dash
import dash_dangerously_set_inner_html
import dash_html_components as html

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
external_scripts = ['https://d1bxh8uas1mnw7.cloudfront.net/assets/embed.js']
app = dash.Dash(__name__, external_scripts=external_scripts, external_stylesheets=external_stylesheets)
app.css.config.serve_locally = False
app.scripts.config.serve_locally = False

app.index_string = '''
<!DOCTYPE html>
<html>
    <head>
        <script type='text/javascript' src='https://d1bxh8uas1mnw7.cloudfront.net/assets/embed.js'></script>
        {%metas%}
        <title>{%title%}</title>
        {%favicon%}
        {%css%}
    </head>
    <body>
        <div>My Custom header</div>
        {%app_entry%}
        <footer>
            {%config%}
            {%scripts%}
            {%renderer%}
        </footer>
        <div>My Custom footer</div>
    </body>
</html>
'''

app.layout = html.Div([
    html.Script(src='https://d1bxh8uas1mnw7.cloudfront.net/assets/embed.js'),
    html.Div('Hello world'),
    html.Div(dash_dangerously_set_inner_html.DangerouslySetInnerHTML("<div class='altmetric-embed' data-badge-type='donut' data-doi='10.1038/nature.2012.9872'></div>")),
    html.Div(className='altmetric-embed', **{'data-badge-type' : 'donut', 'data-doi' : '10.1038/nature.2012.9872'})
])

if __name__ == '__main__':
    app.run_server(debug=True)
1 Answers

The problem is that Dash hasn't finished rendering the altmetric div yet so the script doesn't act on it.

If you put

<div class='altmetric-embed' data-badge-type='donut' data-doi='10.1038/nature.2012.9872'></div>

inside the body of the index_string you will notice that the badge does show up.

If you want the div in the dash layout to work with the script you could use something like dash_defer_js_import to defer execution of the altmetric script.

You can install it with:

pip install dash_defer_js_import

and use it like this:

import dash
import dash_html_components as html
import dash_defer_js_import as dji

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        html.Div(
            className="altmetric-embed",
            **{"data-badge-type": "donut", "data-doi": "10.1038/nature.2012.9872"}
        ),
        dji.Import(src="https://d1bxh8uas1mnw7.cloudfront.net/assets/embed.js"),
    ]
)


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

For better understanding what this Import component is doing you can look at the source code here.

Related