Update axis range

Hi! I’m trying to update the range of a graph’s x-axis but having some trouble understanding why the following code doesn’t work:

n = 1000
x = np.linspace(0, n, n)

app.layout = html.Div([
    html.Button('Button', id='button'),
    dcc.Graph(id='graph', figure=px.line(x=x, y=x ** 2)),
])


@app.callback(
    Output('graph', 'figure'),
    Input('button', 'n_clicks'),
    State('graph', 'figure')
)
def update(button, figure):
    if button is None:
        raise PreventUpdate

    f = go.Figure(figure)
    f.update_xaxes({'range': (50, 100)})
    return f

Interestingly, the below code does work:

app.layout = html.Div([
    html.Button('Button', id='button'),
    dcc.Graph(id='graph', figure=px.line(x=x, y=x ** 2)),
])


@app.callback(
    Output('graph', 'figure'),
    Input('button', 'n_clicks'),
    State('graph', 'figure')
)
def update(button, figure):
    if button is None:
        raise PreventUpdate

    figure['layout']['xaxis'] = {'range': (50, 100)}
    f = go.Figure(figure)
    return f

So what am I missing? And is there a better way to achieve this?

Thank you!

Hi,

Your first approach should work and maybe I am overlooking something…

Regardless, here is a better way:

@app.callback(
    Output('graph', 'figure'),
    Input('button', 'n_clicks'),
    State('graph', 'figure')
)
def update(button, figure):
    if button is None:
        raise PreventUpdate

    figure['layout']['xaxis'] = {'range': (50, 100)}
    return figure

You can simply return the dictionary instead of creating the figure. This is much faster.

First way is not working because you are simply updating the xaxis. And autorange is set to True.

The second way works because you re-write the xaxis as

{'range': (50, 100)}

To get the first way to work, you need to make it:

f.update_xaxes({'range': (50, 100), 'autorange': False})

Setting the autorange to False does the trick