Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Pattern-Matching Callbacks ALL inconsistent order in dash 2.7.1 #2368

Closed
CNFeffery opened this issue Dec 18, 2022 · 1 comment · Fixed by #2388
Closed

[BUG] Pattern-Matching Callbacks ALL inconsistent order in dash 2.7.1 #2368

CNFeffery opened this issue Dec 18, 2022 · 1 comment · Fixed by #2388

Comments

@CNFeffery
Copy link
Contributor

Describe your context
Please provide us your environment, so we can easily reproduce the issue.

  • replace the result of pip list | grep dash below
dash                        2.7.1
dash-core-components        2.0.0
dash-html-components        2.0.0

Describe the bug

In Dash 2.7.1, the order of Pattern-Matching ALL Inputs will be inconsistent with the order of the elements in the web page, here's how the same code behaves differently in versions 2.7.0 and 2.7.1:

2.7.1

2 7 1

2.7.0

2 7 0

The source code for this example is as follows:

import dash
from dash import html, dcc
from dash.dependencies import Input, Output, State, ALL

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        html.Button(
            'refresh options',
            id='refresh-options'
        ),
        html.Br(),
        html.Div(
            [
                *[
                    dcc.Dropdown(
                        id={
                            'type': 'demo-options',
                            'index': i
                        },
                        placeholder=f'dropdown-{i}',
                        style={
                            'width': '200px'
                        }
                    )
                    for i in range(2)
                ],
                dcc.Dropdown(
                    id={
                        'type': 'demo-options',
                        'index': 2
                    },
                    options=[f'option2-{i}' for i in range(3)],
                    placeholder='dropdown-2',
                    style={
                        'width': '200px'
                    }
                )
            ]
        ),
        html.Br(),
        html.Pre(
            id='selected-values'
        )
    ],
    style={
        'padding': '50px'
    }
)


@app.callback(
    [
        Output(
            {
                'type': 'demo-options',
                'index': 0
            },
            'options'
        ),
        Output(
            {
                'type': 'demo-options',
                'index': 1
            },
            'options'
        )
    ],
    Input('refresh-options', 'n_clicks'),
    prevent_initial_call=True
)
def refresh_options(n_clicks):

    return [
        [f'option0-{i}' for i in range(3)],
        [f'option1-{i}' for i in range(3)]
    ]


@app.callback(
    Output('selected-values', 'children'),
    Input(
        {
            'type': 'demo-options',
            'index': ALL
        },
        'value'
    )
)
def update_selected_values(values):

    return str(values)


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

@T4rk1n @alexcjohnson

@T4rk1n T4rk1n changed the title Pattern-Matching Callbacks ALL inconsistent order in dash 2.7.1 [BUG] [BUG] Pattern-Matching Callbacks ALL inconsistent order in dash 2.7.1 Jan 9, 2023
@luewh
Copy link

luewh commented Nov 6, 2024

BUG reappear in some circumstances | dash 2.18.1

Image

code :

from dash import Dash, dcc, html
from dash import callback, ALL
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc

ip = "localhost"
port = "8848"

processes = ["optimize", "resize", "upscale"]

videoSizesDict = [
    {"label":"480p/SD", "width":854, "height":480},
    {"label":"720p/HD", "width":1280, "height":720},
    {"label":"1080p/FHD", "width":1920, "height":1080},
    {"label":"1440p/2K", "width":2560, "height":1440},
    {"label":"2160p/4K", "width":3840, "height":2160},
    {"label":"4320p/8K", "width":7680, "height":4320},
]

upscaleFactor = [2, 3, 4]

app = Dash(__name__)

app.layout = html.Div([
    dcc.Dropdown(
        processes,
        value=processes[0],
        id="dropdown_processes",
        style={"color": "black"},
    ),
    html.Div(id="div_processParamUI"),
    html.Div(id="text"),
])

def qualityInputUI():
    return [
        html.Div("Div"),
        dcc.Input(
            id={"type": "input", "id": "videoQuality"},
            type="number",
            value=3.0,
        ),
    ]

def sizeInputUI():
    global videoSizesDict
    return [
        html.Div("Div"),
        dbc.Row(
            [
                dbc.Col(
                    dcc.Input(
                        id={"type": "input", "id": "videoWidth"},
                        type="number",
                        value=1920,
                    ),
                    width=3,
                ),
                dbc.Col(
                    html.Button(
                        "X",
                        id="button_sizeSwitch",
                        n_clicks=0,
                    ),
                    width=1,
                ),
                dbc.Col(
                    dcc.Input(
                        id={"type": "input", "id": "videoHeight"},
                        type="number",
                        value=1080,
                    ),
                    width=3,
                ),
                dbc.Col(
                    dcc.Dropdown(
                        [videoSizes["label"] for videoSizes in videoSizesDict],
                        value=[videoSizes["label"] for videoSizes in videoSizesDict][2],
                        id="dropdown_videoSize",
                    ),
                    width=5,
                ),
            ],
            className="g-0",
        ),
    ]

def upscaleInputUI():
    global upscaleFactor
    return [
        html.Div("Div"),
        dcc.Dropdown(
            upscaleFactor,
            upscaleFactor[0],
            id={"type": "input", "id": "upscaleFactor"},
        ),
    ]

@callback(
    Output('div_processParamUI', 'children'),
    Input('dropdown_processes', 'value'),
)
def update_div_processParamUI(selectedProcess):
    if selectedProcess == "optimize":
        return [
            html.H6("H6"),
            *qualityInputUI(),
        ]
    elif selectedProcess == "resize":
        return [
            html.H6("H6"), # comment this line to remove the bug
            *sizeInputUI(),
            *qualityInputUI(),
        ]
    elif selectedProcess == "upscale":
        return [
            html.H6("H6"), # or this
            *upscaleInputUI(),
            *qualityInputUI(),
        ]

@callback(
    Output('text', 'children'),
    Input('div_processParamUI', 'children'),
    State({'type':'input','id': ALL}, 'value'),
)
def show(_, values):
    return str(values)



if __name__ == '__main__':

    app.run(
        host=ip,
        port=port,
        debug=True,
    )
    

can we have [ {'id':'id1, 'value':3} ] in this format when State({'type':'input','id': ALL}, 'value') like this ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants