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.

2 Likes

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

2 Likes