Usage of Plotly.relayout function in Dash

Dear all,

I’m trying to update a line shape of figure (dcc.Graph) directly with javascript. My idea is to incorporate this Plotly.relayout function into clientside callback. I have an example below (normal clientside callkback is in blocked comment).
However, there is an error (Cannot read properties of undefined (reading ‘_guiEditing’))
What would be the issue and how to use the Plotly.relayout function normally in Dash?

Regards,

import dash
from dash import Input, Output, State, dcc, html
import plotly.graph_objects as go
from numpy import random

app = dash.Dash(__name__)

x = [1, 2, 3, 4, 5]
y = random.randint(20, size=5)

fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, mode="lines+markers"))
fig.layout.shapes = [
    {
        "visible": True,
        "x0": 2,
        "x1": 2,
        "yref": "paper",
        "y0": 0,
        "y1": 1,
        "type": "line",
    }
]

app.layout = html.Div(
    [
        dcc.Graph(id="main_figure", figure=fig),
        html.Div(
            html.Button("Display Spike Line", id="line_shape", n_clicks=0),
            style={"display": "flex", "justify-content": "center"}
        ),
    ]
)

app.clientside_callback(
    """
    function(n_clicks, fig) {
        var graphDiv = document.getElementById("main_figure");
        update_shape = {shapes: [{"visible": true}]};
        if (n_clicks % 2 === 0) {
            update_shape = {shapes: [{"visible": false}]};
        }
        Plotly.relayout(graphDiv, update_shape)
        return figure;
    }
    """,
    Output("main_figure", "figure"),
    Input("line_shape", "n_clicks"),
    State("main_figure", "figure"),
)

# app.clientside_callback(
#     """
#     function(n_clicks, fig) {
#         var figure = JSON.parse(JSON.stringify(fig));
#
#         if (n_clicks % 2 === 0) {
#             figure.layout.shapes[0]["visible"] = false;
#             return figure;
#         }
#         figure.layout.shapes[0]["visible"] = true;
#         return figure;
#     }
#     """,
#     Output("main_figure", "figure"),
#     Input("line_shape", "n_clicks"),
#     State("main_figure", "figure"),
# )


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


I think I have a similar problem:
I use Plotly.relayout to sync the zoom of multiple plots. It works in pure Plotly, but not with Dash. Not even changing the title works there. Do I have to do something differently when using Dash?

Here’s a screenshot of me playing with that in the browser JS console:

I get the same results when trying in this in any Plotly or Dash demo apps: works in Plotly, doesn’t in Dash.

Any idea?

Indeed, this is something uncovered.
There is another question of using Plotly.restyle (below) but hasn’t addressed yet. Perhaps, we need expert here…

I had the same problem and found a solution.

The Plotly.restyle function takes as a first argument either a string ID or a DOM node. The plotly.js figure does not seem to have an ID, but it is possible to get the element itself and passing it to the restyle function. Here is an example to change the colorscale limits of a go.Heatmap in a dcc.Graph with id=dccGraphID:

clientside_callback(
    """
    function updateHeatmapColorscale(value) {
        var dccGraph = document.getElementById('dccGraphID');
        var jsFigure = dccGraph.querySelector('.js-plotly-plot');
        var update = {zmin: value[0], zmax: value[1]};
        Plotly.restyle(jsFigure, update, []);
        return window.dash_clientside.no_update;
    }
    """
    Output('dccGraphID', 'figure'),
    Input('dccRangeSliderID', 'value'),
)