Is it possible to update just `layout`, not whole `figure` of Graph in callback?

Very interesting topic!
I have quite a few issues with slow response in Dash when updating minor figure layout elements or using events, probably caused by re-loading the entire data on each callback.

I have looked a bit into “build your own dash component”, thinking that some of these tasks could be transferred “back” to the faster JS side (such as updating a color, height, get hover information etc) without invoking a “costly” Dash callback (and leave those for more data related, Python-based stuff).

Now I understand (sorry, I’m new to React as well as relatively new to JS…) that I could build sort of custom-made graph components using Plotly.js and Plotly.newPlot(); (as done here: and work for example with Plotly.restyle or Plotly.relayout (as shown here:

However - here comes Plotly.react (as @chriddyp posted:, which sounds to be faster and may work better/cleaner(?) together with React. BUT on the main plotly.react page it says that “This component currently creates a new plot every time the input changes” (

So, my question is - what do you think is the way forward? After all Plotly.js is the base library, which ultimately should allow most customisation - yet Plotly.react seems really attractive. In terms of building a custom-made Dash component, what would be the most sensible approach?

Thanks for shedding some light onto my current Plotly confusion…!

I am also interested in what will be the way forward here. Right now in my app i have a figure where I am animating a moving vertical line along the time axis. I am returning the entire figure each time, which works ok as long as the figure stays simple. However as figure get more complex the animation delay gets longer and longer.

Also mydcc.relayout works well for a simple example, but when I tried to use it in my case i get into some sort of infinite loop of callbacks, because I also i have callbacks that listen to chart relayout data and then update the chart to zoom in/out. Which leaves me not sure if the issue is with my callbacks or with mydcc.relayout and I don’t know to debug it.

this also seems ideal to me:

Allow the developer to update nested properties in callbacks with something like
@app.callback(Output(‘my-graph’, ‘figure.layout.range’))

For now it seems like I am stuck with “returning the entire figure each time”, until solution 1 or 2 is created (not soon?) or I learn more React/JS and custom components and can make some sort of custom hack.

1 Like

Is there any update on this issue?

Your first soluction would be perfect.



No updates. This is actually quite a bit project and we’d likely need commercial sponsorship of the feature in order to move it forward

Sorry I can not help with that. I don´t belong to any company.

1 Like

I believe this is now possible to some extent thanks to State callback.

@app.callback(Output('graph', 'figure'),
             [Input('graph', 'relayoutData')], # this triggers the event
             [State('graph', 'figure')])
def graph_event(select_data,  fig):
    fig['layout'] = [YOUR STUFF]
    return fig

This is sorely needed for large plots e.g. choropleths that have megabytes of data to be overlaid on the map, which at the present need to be sent repeatedly when a layout change such as zoom level is made to the figure via callback.

After facing a similar issue it seems like client side callbacks are the best way to step around this issue!

1 Like

Would love to see your solution @sjtrny

Simplified Example

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, ClientsideFunction

app = dash.Dash(__name__)

fig_data = {
    "data": [{"type": "bar", "x": [1, 2, 3], "y": [1, 3, 2]}],
    "layout": {"title": {"text": ""}}

app.layout = html.Div([
    dcc.Store("fig-data", data=fig_data),
        options=[ {'label': z, "value": z} for z in ["Sydney", "Montreal"] ],

    ClientsideFunction("clientside", "figure"),
    Output(component_id="graph", component_property="figure"),
    [Input("fig-data", "data"), Input("city", "value")],

app.run_server(host="", debug=True)


if (!window.dash_clientside) {
     window.dash_clientside = {}

window.dash_clientside.clientside = {

    figure: function (fig_dict, title) {

        if (!fig_dict) {
            throw "Figure data not loaded, aborting update."

        // Copy the fig_data so we can modify it
        // Is this required? Not sure if fig_data is passed by reference or value
        fig_dict_copy = {...fig_dict};

        fig_dict_copy["layout"]["title"] = title;

        return fig_dict_copy



Choropleth Example

This example is a bit more involved so I put it in a

1 Like

I am still new to Dash Plotly. I do not know any Javascript. The solution proposed by tracek works (without external script).

This is what I have in my script. I can update the title of the graph. Hopefully this can help anyone who is struggling with this aspect.

    Output(component_id='my-div', component_property='figure'),
    [Input(component_id='variable', component_property='value')],
    [State('my-div', 'figure')]
def update_output_div(input_value, fig):
    fig['layout'] = {"title": input_value}
    return fig

I’m wondering how @tracek solution improve performance compared to reloading at each call back. Does changing the state only reload the changed attribute or it reloads the whole figure?
Thank you

1 Like

Any Update here ? I’m trying to update the annotation text of my Graph , is that possible?


The best workaround right now is to use a clientside callback to add or change the smaller pieces of the figure. See the example here:

1 Like

Just a minor addition to your great example: You have to make a deep copy of the figure object. Otherwise you might run into issues when adding elements to an existing list, e.g. such as traces.

I was able to completely decouple any figure modification (e.g. adding descriptive shapes, traces, annotations etc.) while keeping the original (large) figure data in a dcc.Store object and not resend it on every update (of the auxiliary data).

1 Like

Would you mind sharing code on your example? I am facing a similar issue.

1 Like

Yes, can you show us your example, please?

I’m trying to make a choropleth with ~40k polygons that gets recolored depending on the value of a dropdown menu.
I want to the menu choice to trigger a server-side recomputation of the choropleth values, colors, and legend, then send only that info to the client and not the large amount of geodata again.
Any suggestions?

I haven’t tied with Plotly Choropleth, but it should be possible with the GeJSON component in Dash leaflet. If you color the polygons based on data from the hideout prop (via a custom JS function), you can update this prop only without changing the data prop (which holds the polygons).

Hi @chriddyp , I also wanted to update plots in a Dash applications, and I was tempted to use figure updates as documented at Creating and Updating Figures | Python | Plotly. Do we agree that at the moment I can’t use that in the context of a dash application? Thanks!