Plotly Dash uses the index_string value to customize the Dash's HTML Index Template as explained here.
To integrate Dash with Flask, one can pass Flask app as Dash server, and get back the Flask app with the Dash app integrated in it, also taking advantage of Jinja. This approach is nicely explained in several tutorial, such as this one.
If you want to add a Jinja template, you can pass the HTML template to the code initializing Dash. The index string shall contain the {%" filed "%} required by Dash, but rendering the template will escape that code.
A trick is nicely explained in an answer here, where the HTML is enriched with comments, which are ignored by Jinja during the rendering, and then replaced in the code with the fields for Dash before setting the index_string upon Dash app initialization. This effectively works, the dash app is well integrated in the Flask server, and the Jinja template is inegrated and rendered.
Here some code to frame this a bit more concretely:
def init_dashboard(server,url):
"""Create a Plotly Dash dashboard."""
dash_app = dash.Dash(
server=server,
routes_pathname_prefix=url,
external_stylesheets=[
"/static/dist/css/styles.css",
"https://fonts.googleapis.com/css?family=Lato",
],
)
# Both app context and a request context to use url_for() in the Jinja2 templates are needed
with server.app_context(), server.test_request_context():
#items = Item.query.all()
html_body = render_template_string(html_layout)
comments_to_replace = ("metas", "title", "favicon", "css", "app_entry", "config", "scripts", "renderer")
for comment in comments_to_replace:
html_body = html_body.replace(f"<!-- {comment} -->", "{%" comment "%}")
dash_app.index_string = html_body
# Load DataFrame
df = create_dataframe()
# Create Layout
dash_app.layout = my_layout
init_callbacks(dash_app)
return dash_app.server
With the layout in HTML:
html_layout = """
{% extends "base.html" %}
{% block title %}
Calculator
{% endblock %}
{% block content %}
<body >
<header>
<div >
<!-- <a href="/">
<img src="/static/img/logo.png" />
<h1>Plotly Dash Flask Tutorial</h1>
</a> -->
<nav>
</nav>
</div>
</header>
<!-- app_entry -->
<footer>
<!-- config -->
<!-- scripts -->
<!-- renderer -->
</footer>
</body>
{% endblock %}
"""
Now, the problem I have is that I would like to update the index_string in the Dash_app during the execution, for example during a callback, and not only on initialization. Upon debug, I can get the dash_app embedded in the Flask app with the dash.get_app() function. There, I can find my index_string nicely set. But I could not find a way to set back that index_string value, effectively updating the dash template. Do you have any idea on how I could achieve this feature?
CodePudding user response:
Any findings on this? I'm also having similar use case.
CodePudding user response:
Ok, I found a solution, but it is super hacky, and I really would like something a bit more robust and elegant, so whoever has an idea, please share it!
The solution is by setting your index_page
like this: your app exists in dash.dcc._dash._get_app.APP
You can modify it from within a dash callback code, from where the variable is visible.
and you can set the index_page
attribute directly in the dash_app
using setattr
like this:
html_body = render_template_string(html_layout, variable_for_jinja=value)
comments_to_replace = ("metas", "title", "favicon", "css", "app_entry", "config", "scripts", "renderer")
for comment in comments_to_replace:
html_body = html_body.replace(f"<!-- {comment} -->", "{%" comment "%}")
setattr(dash.dcc._dash._get_app.APP,"index_string",new_index_page)