More Elegant way of handling tons of configurations / variables in dash

I’m sure many of you have run into a situation where you have many callback signatures which look like this:

app.callback(
    [
        ServersideOutput(id("compare-view-population-affected"), "data"),
        ServersideOutput(id("model-output-compare-scenario"), "data"),
        ServersideOutput(id("compare-view-execute-button-modal-server"), "data"),
        ServersideOutput(id("compare-view-execute-button-modal-body-server"), "data"),
    ],
    [
        Trigger(id("compare-view-execute-button"), "n_clicks"),
        Trigger(id("flooding-filter-execute-button"), "n_clicks"),
        Input(id("compare-scenario-solutions-shapes"), "data"),
        Input(id("model"), "data"),
    ],
    [
        State(id("compare-view-years-slider"), "value"),
        State(id("compare-view-quantiles-slider"), "value"),
        State(id("compare-view-ssp-dropdown"), "value"),
        State(id("compare-view-return-period-dropdown"), "value"),
        State(id("compare-view-ee-dropdown"), "value"),
        State(id("compare-view-vertical-displacement-button"), "value"),
        State("config", "data"),
        State(id("flooding-filter-button"), "value"),
        State(id("flooding-filter-dropdown"), "value"),
        State(id("flooding-filter-slider"), "value"),
        State(id("compare-view-years-slider"), "id"),
        State(id("slr-filter-button"), "value"),
        State(id("compare-view-execute-button-modal"), "is_open"),
        State(id("compare-view-execute-button-modal-body"), "children"),
    ],
    memoize=True,
    blocking=True,
)

This callback signature is both a beast, hard-to-read, and ugly.

Would be a lot better if I could have an app “state” object that existed in a store which held many of these values. To reduce code and increase readability, and increase elegance.

for example

@app.callback(
    [
        ServersideOutput(id("compare-view-population-affected"), "data"),
        ServersideOutput(id("model-output-compare-scenario"), "data"),
        ServersideOutput(id("compare-view-execute-button-modal-server"), "data"),
        ServersideOutput(id("compare-view-execute-button-modal-body-server"), "data"),
    ],
    [
        Trigger(id("compare-view-execute-button"), "n_clicks"),
        Trigger(id("flooding-filter-execute-button"), "n_clicks"),
        Input(id("compare-scenario-solutions-shapes"), "data"),
        Input(id("model"), "data"),
    ],
    [
        State(id("app-state"), "value"),
        State("config", "data"),
    ],
    memoize=True,
    blocking=True,
)

Where app-state held all those values that I’m taking in. I wonder if this goes against Dash principles, but it seems difficult to update this object since the callbacks are linked.

Is there a good way to do what I’m trying to do?

One solution would be to use pattern matching callbacks and callback context (ctx):

IDS = {'ssp-dropdown': {'ui': 'compare-view', 'control': 'ssp-dropdown'}}

app.layout = html.Div([
     ...
     dcc.Dropdown(id=IDS['ssp-dropdown'])
])

@callback(..., State(dict(IDS['ssp-dropdown'], **{'control': ALL}), value))
def update(...):
    value = ctx.inputs[str(IDS['ssp-dropdown']).replace(' ', '')]
1 Like