Best way to generate animation (partial update a scatter plot) with Dash interval of less than 500ms

My goal is to show animation on a page- animation is merely an update of one of the scatterplot point to a new color based on a condition. Every step of the animation is a row in a data set.

Currently the solution i have is to use interval object. and then using the n_interval as the row number to update partial properties of a scatter plot using n_interval property as an input (once i click a button to start the Dash interval object)
n-Interval has to be used as the row index to identify what part of the scatterplot needs to be updated.

For intervals above 1000ms, it works

Anything below that number, what i am noticing is that even though the callback is triggered, and print statements are triggered in the terminal, It does not draw it on the browser. - even tried typograph, doesnt show on the browser

Is this the correct approach to use interval to update the graph or is there a better way to show this animation as i want it be updated fairly quickly (atleast 4 5 times a second)?

** Updated code with client Callback

“”"

@app.callback(
Output(“interval1”,“disabled”),
Output(“play”,“children”),
Input(“play”, “n_clicks”),
State(“play”,“children”)
)
def click_play_button(n_clicks,txt):
if n_clicks is not None:
if txt == “Play”:
txt = “Stop”
state = False
else:
txt = “Play”
state = True
return state,txt
else:
return True,“Play”

@clientside_callback(

"""
function(n_clicks,TraceData,DataRowLookup){
    if n_clicks is not None:
    print(n_clicks)
    dRow = n_clicks-1
    print(dRow)
    patched_figure = Patch()
    #dRow = int(n_clicks)
    print(TraceData[dRow])    
    print(round(float(TraceData[dRow]["3"]),2))   
    # read new record
    if TraceData[dRow]['4'] == "Release":
         
        # some conditions for color


        for r in range(len(route)-1):
            j = DataRowLookup[route[r] + "/" + route[r+1]] 
            patched_figure["data"][j]['line']['color'] = c
            patched_figure["data"][j]['line']['width'] = "5"

    return patched_figure,"Time is " + f'{round(float(TraceData[dRow]["3"]),2):,}'

}
""",
[
Output("animationFig", "figure", allow_duplicate=True),
Output("label1","children", allow_duplicate=True)
],
[Input("interval1", "n_intervals")],
[State("TraceData", "data"),
State("DataRowLookup", "data"),

],prevent_initial_call=True,

)
“”"

Hi @ammarmp and welcome to the Dash community :slightly_smiling_face:

For smooth animations, you can use a clientside callback

Here’s an example:

Thanks for the response ! i am getting this error

" @app.clientside_callback(
^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: ‘NoneType’ object is not callable"

Could this be because the n_interval is only triggered when i press a button? I have updated the original question with the code

Hi, The problem seems to be that your clientside function is writed in python code, and it must be javascript code.

would this be the javascript to use (code at the end) ( used bard… dont know javascript)

gives me this error

Cannot read properties of undefined (reading ‘94c2873d3a8cd702796049c3c204e8fb’)

(This error originated from the built-in JavaScript code that runs Dash apps. Click to see the full stack trace or open your browser’s console.)

TypeError: Cannot read properties of undefined (reading ‘94c2873d3a8cd702796049c3c204e8fb’)

app.clientside_callback(
    
    """
    function updateAnimation(n_clicks, TraceData, DataRowLookup) {
    if (n_clicks !== undefined) {
        const dRow = n_clicks - 1;
        const patched_figure = {
        data: []
        };
        //dRow = int(n_clicks)
        const record = TraceData[dRow];
        const time = parseFloat(record["3"]);
        // read new record
        if (record["4"] === "Release") {
             
     # code for conditions


        for (let r = 0; r < route.length - 1; r++) {
            const j = DataRowLookup[route[r] + "/" + route[r + 1]];
            patched_figure.data.push({
            "line": {
                "color": color,
                "width": "5"
            }
            });
        }
        }
    return patched_figure, "Time is " + f'{round(float(TraceData[dRow]["3"]),2):,}'
  }
}

    """,
    [
    Output("animationFig", "figure", allow_duplicate=True),
    Output("label1","children", allow_duplicate=True)
    ],
    [Input("interval1", "n_intervals")],
    [State("TraceData", "data"),
    State("DataRowLookup", "data"),
    
    ],prevent_initial_call=True,
)

Hello @ammarmp,

For clientside callbacks, you need to put app.clientside_callback not using the @.

i am getting this error afterwards

Cannot read properties of undefined (reading ‘94c2873d3a8cd702796049c3c204e8fb’)

(This error originated from the built-in JavaScript code that runs Dash apps. Click to see the full stack trace or open your browser’s console.)

f' doesnt exist in JS, it needs to be:

app.clientside_callback(
    
    """
    function updateAnimation(n_clicks, TraceData, DataRowLookup) {
    if (n_clicks !== undefined) {
        const dRow = n_clicks - 1;
        const patched_figure = {
        data: []
        };
        //dRow = int(n_clicks)
        const record = TraceData[dRow];
        const time = parseFloat(record["3"]);
        // read new record
        if (record["4"] === "Release") {
             
     # code for conditions


        for (let r = 0; r < route.length - 1; r++) {
            const j = DataRowLookup[route[r] + "/" + route[r + 1]];
            patched_figure.data.push({
            "line": {
                "color": color,
                "width": "5"
            }
            });
        }
        }
    return [patched_figure, `Time is ${round(float(TraceData[dRow]["3"]),2):,}`]
  }
    return window.dash_clientside.no_update, window.dash_clientside.no_update
}

    """,
    [
    Output("animationFig", "figure", allow_duplicate=True),
    Output("label1","children", allow_duplicate=True)
    ],
    [Input("interval1", "n_intervals")],
    [State("TraceData", "data"),
    State("DataRowLookup", "data"),
    
    ],prevent_initial_call=True,
)

Or something similar, sorry, but without the rest of your code I cant help anymore.