Skip to content

dbc.Progress: value/label sometimes not updated properly by callback Output #1161

@jouvin

Description

@jouvin
  • dash version: 4.0.0
  • dash-bootstrap-components version: 2.0.4
  • components affected by bug: dbc.Progress

What is happening?

I have an application using a progress bar during some actions. It can be used several times, without being recreated. It is created hidden (managed by the Div containing the Progress) and made visible by some callbacks that want them to be visible, updating the Div style attribute in the Running() parameter of these callbacks.

Generally it works well but from time to time, the progress no longer updates its value and label or update it with a long delay compared to Interval interval parameter, despite the associate dcc.Interval (and related callback) working properly (see below). I have the feeling that the problem happens when the progress bar has been updating during 10s or more : next time the progress bar value and label are reset to 0 by a callback Output(), the Progress doesn't update internally and remains stuck at the 0 position during a few seconds. In the callback managing the Interval n_intervals, I added as State() Progress value and label and print the value each time the callback is entered : I can see that when the Progress no longer updates value equals 0 and label is an empty string.

The problem seems to be browser dependent. With Opera (my usual browser) and Chrome (same engine), value and label stay stuck for ever (at least longer than the workload execution). With Firefox (used in the output below), the delay is a matter of a few seconds (4-5 iterations, with 0.5s between iterations). In both cases, running a shorter workload with the progress bar enabled or even disabling/enabling the Progress and Interval (Interval called once with n=0 is enough to restore a normal behaviour.

What should be happening?

Should work properly all the time! I;e. the Progress should properly display any change to its value and label.

Code

It's difficult to build a minimal code to reproduce the problem. I put here the 2 callbacks that manage the Progress and Interval. These callbacks print some information about their input each time they are entered. update_progress_bar_visibility is called when the Progress (associated Div) visibility is changed. update_progress is called each time the Interval n_intervals is updated. I also put a typical output when the problem happens:

@app.callback(
    [
        Output(LOAD_PROGRESS_BAR_ID, "style"),
        Output(LOAD_PROGRESS_INTERVAL_ID, "n_intervals"),
        Output(LOAD_PROGRESS_INTERVAL_ID, "disabled"),
    ],
    Input(LOAD_PROGRESS_BAR_ID, "disabled"),
    prevent_initial_call=True,
)
def update_progress_bar_visibilty(disabled):
    """
    This callback is called when the progress bar is disabled or enabled. It takes
    care of changing the visibility and resetting the associated dcc.Interval visibility
    and n_intervals. n_intervals is reset to 0 at every state transition.

    :param disabled: progress bar state (True=disabled)
    :return: progress bar style, dcc.Interval n_intervals and state
    """
    if disabled:
        style = {'visibility': 'hidden'}
        msg = "disabled"
    else:
        style = {'visibility': 'visible'}
        msg = "enabled"

    n_intervals = 0

    print(f"update_progress_bar_visibilty: {msg}")

    return style, n_intervals, disabled


@app.callback(
    [
        Output("progress", "value"),
        Output("progress", "label"),
    ],
    [Input(LOAD_PROGRESS_INTERVAL_ID, "n_intervals")],
    [
        State(LOAD_PROGRESS_INTERVAL_ID, "max_intervals"),
        State(LOAD_PROGRESS_INTERVAL_ID, "interval"),
        State("progress", "value"),
        State("progress", "label"),
        State("progress", "min"),
        State("progress", "max"),
        State(LOAD_PROGRESS_INTERVAL_ID, "disabled"),
    ],
    prevent_initial_call=True,
)
def update_progress(n, max_intervals, interval, value, label, min, max, disabled):
    # Protect against n=None, despite it should not happen
    if n is None:
        return PreventUpdate
    else:
        duration = int(max_intervals * interval / 1000)
        # only add text after 5% progress to ensure text isn't squashed too much
        progress = int(round(n / duration * 100))
        print(f"update progress: n={n}, value={value}, label={label}, min={min}, "
              f"max={max}, interval_disabled={disabled}, progress={progress}")
        return progress, f"{progress} %" if progress >= 5 else ""

Output of the callbacks before and after the problem happens (update_progress is called every 0.5s), using Firefox as a browser (see description of the problem above). The workload executed at each atttempt is the same and massaging some pandas (filled from a database) and building a table. The pandas has roughly the same number of rows in all the attempts below. In update_progress:

  • n is the value of n_intervals input
  • progress is the value propagated to value and label output, except if value is less than 5, label is kept as an empty string (should happen for n=0 and n=1 in the examples below)
  • other parameters reflect the value of the corresponding input (State()) at the beginning of the callback. value and label should be value of progress in the previous call
# Initialisation

* Serving Flask app 'ositah.app'
 * Debug mode: on
create_progress_bar: duration=30, interval=500, max_intervals=60
update_progress_bar_visibilty: enabled
update_progress_bar_visibilty: disabled
update progress: n=0, value=None, label=None, min=None, max=None, interval_disabled=True, progress=0
update_progress_bar_visibilty: enabled
update_progress_bar_visibilty: disabled
update progress: n=0, value=0, label=, min=None, max=None, interval_disabled=True, progress=0

# 1st execution of the workload: ok (value properly updated at each call)
update_progress_bar_visibilty: enabled
update progress: n=0, value=0, label=, min=None, max=None, interval_disabled=False, progress=0
update progress: n=1, value=0, label=, min=None, max=None, interval_disabled=False, progress=3
update progress: n=2, value=3, label=, min=None, max=None, interval_disabled=False, progress=7
update progress: n=3, value=7, label=7 %, min=None, max=None, interval_disabled=False, progress=10
update progress: n=4, value=10, label=10 %, min=None, max=None, interval_disabled=False, progress=13
update progress: n=5, value=13, label=13 %, min=None, max=None, interval_disabled=False, progress=17
update progress: n=6, value=17, label=17 %, min=None, max=None, interval_disabled=False, progress=20
update progress: n=7, value=20, label=20 %, min=None, max=None, interval_disabled=False, progress=23
update progress: n=8, value=23, label=23 %, min=None, max=None, interval_disabled=False, progress=27
update progress: n=9, value=27, label=27 %, min=None, max=None, interval_disabled=False, progress=30
update progress: n=10, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=33
update progress: n=11, value=33, label=33 %, min=None, max=None, interval_disabled=False, progress=37
update progress: n=12, value=37, label=37 %, min=None, max=None, interval_disabled=False, progress=40
update progress: n=13, value=40, label=40 %, min=None, max=None, interval_disabled=False, progress=43
update progress: n=14, value=43, label=43 %, min=None, max=None, interval_disabled=False, progress=47
update progress: n=15, value=47, label=47 %, min=None, max=None, interval_disabled=False, progress=50
update progress: n=16, value=50, label=50 %, min=None, max=None, interval_disabled=False, progress=53
update progress: n=17, value=53, label=53 %, min=None, max=None, interval_disabled=False, progress=57
update progress: n=18, value=57, label=57 %, min=None, max=None, interval_disabled=False, progress=60
update progress: n=19, value=60, label=60 %, min=None, max=None, interval_disabled=False, progress=63
update progress: n=20, value=63, label=63 %, min=None, max=None, interval_disabled=False, progress=67
update_progress_bar_visibilty: disabled
update progress: n=0, value=67, label=67 %, min=None, max=None, interval_disabled=True, progress=0

# 2nd execution of the workload: not ok until n=4 (n=5 sees the n=4 output) and some latency in further updates (values identical for several `update_progress` calls). Final value (seen after the progress bar has been disabled is correct).
update_progress_bar_visibilty: enabled
update progress: n=0, value=0, label=, min=None, max=None, interval_disabled=False, progress=0
update progress: n=1, value=0, label=, min=None, max=None, interval_disabled=False, progress=3
update progress: n=2, value=0, label=, min=None, max=None, interval_disabled=False, progress=7
update progress: n=3, value=0, label=, min=None, max=None, interval_disabled=False, progress=10
update progress: n=4, value=0, label=, min=None, max=None, interval_disabled=False, progress=13
update progress: n=5, value=13, label=13 %, min=None, max=None, interval_disabled=False, progress=17
update progress: n=6, value=17, label=17 %, min=None, max=None, interval_disabled=False, progress=20
update progress: n=7, value=20, label=20 %, min=None, max=None, interval_disabled=False, progress=23
update progress: n=8, value=23, label=23 %, min=None, max=None, interval_disabled=False, progress=27
update progress: n=9, value=27, label=27 %, min=None, max=None, interval_disabled=False, progress=30
update progress: n=10, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=33
update progress: n=11, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=37
update progress: n=12, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=40
update progress: n=13, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=43
update progress: n=14, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=47
update progress: n=15, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=50
update progress: n=16, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=53
update_progress_bar_visibilty: disabled
update progress: n=0, value=53, label=53 %, min=None, max=None, interval_disabled=True, progress=0

# 3d execution of the workload: not ok until n=5 (n=6 sees the n=5 output) and some latency in further updates (values identical for several `update_progress` calls). Final value (seen after the progress bar has been disabled is correct).
update_progress_bar_visibilty: enabled
update progress: n=0, value=0, label=, min=None, max=None, interval_disabled=False, progress=0
update progress: n=1, value=0, label=, min=None, max=None, interval_disabled=False, progress=3
update progress: n=2, value=0, label=, min=None, max=None, interval_disabled=False, progress=7
update progress: n=3, value=0, label=, min=None, max=None, interval_disabled=False, progress=10
update progress: n=4, value=0, label=, min=None, max=None, interval_disabled=False, progress=13
update progress: n=5, value=0, label=, min=None, max=None, interval_disabled=False, progress=17
update progress: n=6, value=17, label=17 %, min=None, max=None, interval_disabled=False, progress=20
update progress: n=7, value=17, label=17 %, min=None, max=None, interval_disabled=False, progress=23
update progress: n=8, value=23, label=23 %, min=None, max=None, interval_disabled=False, progress=27
update progress: n=9, value=27, label=27 %, min=None, max=None, interval_disabled=False, progress=30
update progress: n=10, value=27, label=27 %, min=None, max=None, interval_disabled=False, progress=33
update progress: n=11, value=33, label=33 %, min=None, max=None, interval_disabled=False, progress=37
update progress: n=12, value=37, label=37 %, min=None, max=None, interval_disabled=False, progress=40
update progress: n=13, value=40, label=40 %, min=None, max=None, interval_disabled=False, progress=43
update_progress_bar_visibilty: disabled
update progress: n=0, value=43, label=43 %, min=None, max=None, interval_disabled=True, progress=0

# Action enabling/disabling the progress bar and associate Interval without executing any workload
update_progress_bar_visibilty: enabled
update_progress_bar_visibilty: disabled
update progress: n=0, value=0, label=, min=None, max=None, interval_disabled=True, progress=0

# 4th execution of the workload: ok
update_progress_bar_visibilty: enabled
update progress: n=0, value=0, label=, min=None, max=None, interval_disabled=False, progress=0
update progress: n=1, value=0, label=, min=None, max=None, interval_disabled=False, progress=3
update progress: n=2, value=3, label=, min=None, max=None, interval_disabled=False, progress=7
update progress: n=3, value=7, label=7 %, min=None, max=None, interval_disabled=False, progress=10
update progress: n=4, value=10, label=10 %, min=None, max=None, interval_disabled=False, progress=13
update progress: n=5, value=13, label=13 %, min=None, max=None, interval_disabled=False, progress=17
update progress: n=6, value=17, label=17 %, min=None, max=None, interval_disabled=False, progress=20
update progress: n=7, value=20, label=20 %, min=None, max=None, interval_disabled=False, progress=23
update progress: n=8, value=23, label=23 %, min=None, max=None, interval_disabled=False, progress=27
update progress: n=9, value=27, label=27 %, min=None, max=None, interval_disabled=False, progress=30
update progress: n=10, value=30, label=30 %, min=None, max=None, interval_disabled=False, progress=33
update progress: n=11, value=33, label=33 %, min=None, max=None, interval_disabled=False, progress=37
update progress: n=12, value=37, label=37 %, min=None, max=None, interval_disabled=False, progress=40
update progress: n=13, value=40, label=40 %, min=None, max=None, interval_disabled=False, progress=43
update progress: n=14, value=43, label=43 %, min=None, max=None, interval_disabled=False, progress=47
update progress: n=15, value=47, label=47 %, min=None, max=None, interval_disabled=False, progress=50
update progress: n=16, value=50, label=50 %, min=None, max=None, interval_disabled=False, progress=53
update progress: n=17, value=53, label=53 %, min=None, max=None, interval_disabled=False, progress=57
update progress: n=18, value=57, label=57 %, min=None, max=None, interval_disabled=False, progress=60
update progress: n=19, value=60, label=60 %, min=None, max=None, interval_disabled=False, progress=63
update progress: n=20, value=63, label=63 %, min=None, max=None, interval_disabled=False, progress=67
update progress: n=21, value=67, label=67 %, min=None, max=None, interval_disabled=False, progress=70
update progress: n=22, value=70, label=70 %, min=None, max=None, interval_disabled=False, progress=73
update_progress_bar_visibilty: disabled
update progress: n=0, value=73, label=73 %, min=None, max=None, interval_disabled=True, progress=0```

### Error messages

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions