Skip to content
New issue

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

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

Already on GitHub? # 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 ?

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

Successfully merging a pull request may close this issue.

2 participants