Hi guys,
As probably most of you guys know, Dash app scripts, especially with callbacks involved can get a bit messy. I wanted to compartmentalize things into modules, but it still is a bit hard to get right.
My current solution looks somewhat like this:
Where the key lies in the element class:
"""Plotly Dash app layout module."""
import dash_html_components as html
from dash import Dash
class Element:
"""Plotly Dash app element to standardize adding HTML divs and callbacks.
Arguments:
layout: HTML Div describing this element.
"""
def __init__(self, layout: html.Div):
self.layout = layout
def register(self, app: Dash):
"""Register callbacks in app.
Arguments:
app: App to register callbacks in.
Don't forget to add register calls of child elements!
"""
raise NotImplementedError
and a example layout module looks like:
"""Main layout module."""
import dash_html_components as html
from dash import Dash
from dash.dependencies import Input, Output
from dash_project_layout.layout import Element
# Create layout here.
layout = html.Div(
[
html.Button("Click me", id="clickme-button"),
html.Div("Waiting for a click...", id="content-div"),
],
id="main-container",
className="main-container",
)
# Add callbacks in derived class.
class MainElement(Element):
def register(self, app: Dash):
@app.callback(
Output("content-div", "children"), [Input("clickme-button", "n_clicks")]
)
def content_div_children(n_clicks):
if n_clicks < 10:
return "{} clicks".format(n_clicks)
return "Hello world!"
main = MainElement(layout)
This enables you to include the layout of different elements quite easily in other modules, and also gives you the opportunities to include one element’s .register(app)
method in the parent element’s register call.
Just for completeness, the running script looks like:
import dash
from dash_project_layout.layout.main import main
app = dash.Dash(__name__)
app.layout = main.layout
main.register(app)
run = app.run_server
def cli():
"""Dash server command line interface (CLI)."""
import argparse
parser = argparse.ArgumentParser(
prog="Dash Project Layout", description="Example Dash Project Layout."
)
parser.add_argument("-d", "--debug", action="store_true", help="turn on debug mode")
args = parser.parse_args()
run(debug=args.debug)
if __name__ == "__main__":
cli()
What are your thoughts or how do you tackle the complexity of Dash apps?