Quantcast
Channel: 🎛️ Dash - Plotly Community Forum
Viewing all articles
Browse latest Browse all 6271

Circular Dependency message in browser console with Dash 1.11

$
0
0

In one of my applications, I have a feature that allows the use of preset values for different dropdown menus. The users can choose presets from a dropdown which set the values of other “children” dropdown menus to commonly used value combinations. The users still have the option to use custom values in the children dropdown menus, in which case the value of the preset dropdown menu is cleared to avoid the perception that a certain preset is used when the values of the children dropdowns have changed. Also, if the combination of values of the children dropdowns match a preset, the preset dropdown value is set to that preset.

The example app below is an isolated version of that feature:

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate

# Define presets with a name and values for the dropdowns A & B
presets = {"Preset 1 (A1-B3)": ["A1", "B3"], "Preset 2 (A3-B2)": ["A3", "B2"]}

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        html.Label("Presets"),
        dcc.Dropdown(
            id="presets_dropdown",
            options=[dict(label=preset, value=preset) for preset in presets],
        ),
        html.Label("Dropdown A"),
        dcc.Dropdown(
            id="dropdown_a",
            options=[dict(label=option, value=option) for option in ["A1", "A2", "A3"]],
        ),
        html.Label("Dropdown B"),
        dcc.Dropdown(
            id="dropdown_b",
            options=[dict(label=option, value=option) for option in ["B1", "B2", "B3"]],
        ),
    ],
    style={"width": "200px"},
)


@app.callback(
    [Output("dropdown_a", "value"), Output("dropdown_b", "value")],
    [Input("presets_dropdown", "value")],
    [State("dropdown_a", "value"), State("dropdown_b", "value")],
)
def apply_preset(preset, a, b):
    # Apply the preset only if it differs from current values
    if preset is not None and presets[preset] != [a, b]:
        return presets[preset]
    # Otherwise do nothing (avoid circular reference)
    else:
        raise PreventUpdate


@app.callback(
    Output("presets_dropdown", "value"),
    [Input("dropdown_a", "value"), Input("dropdown_b", "value")],
    [State("presets_dropdown", "value")],
)
def clear_or_match_presets_dropdown(a, b, preset):
    if preset is not None:
        # If dropdowns match the current preset, do nothing
        if [a, b] == presets[preset]:
            raise PreventUpdate
        # else clear the preset by returning None (implicit)
    else:
        # If the dropdowns match a preset, set the presets dropdown to that preset
        for preset_name, values in presets.items():
            if [a, b] == values:
                return preset_name
        # If no match, do nothing (i.e. leave the preset to None)
        raise PreventUpdate


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

I use dash.exceptions.PreventUpdate in both callbacks to avoid an actual circular dependencies condition. Up until Dash version 1.10, this was working fine with no errors reported in the browser console. After upgrading to Dash 1.11, the feature still works as expected but I get the following error in the browser console:

{message: "Circular Dependencies", html: "Error: Dependency Cycle Found: dropdown_a.value -> presets_dropdown.value -> dropdown_a.value"}

I don’t know if I should report this as an issue? From the dependencies only, there is technically a condition of circular dependencies. However it is prevented from ever getting in an endless update loop by the use of PreventUpdate at strategic locations. The application and this feature still works correctly which is the most important but the console error that is new with Dash 1.11 is somewhat annoying. This is part of a relatively complex app and I like to keep the console free of errors.

Tested in Chrome Version 81.0.4044.122 on Windows 10 Professional as well as Firefox 75.0 on Ubuntu 18.04.

2 posts - 2 participants

Read full topic


Viewing all articles
Browse latest Browse all 6271

Trending Articles