How to save current zoom and position after filtering?

Good question. You can pass in the current figure or relayoutData as state and use the range values from that figure in the new figure that you create. Here’s an example: https://plot.ly/dash/gallery/new-york-oil-and-gas/ (see the “Lock camera” checkbox) and here’s the relevant section in the code: https://github.com/plotly/dash-oil-and-gas-demo/blob/d937ebbbf9da244d9832e25c42b46319148d9ef5/app.py#L437-L448

Here’s a simple example that shows the two types of modes with a cartesian plot:

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

import copy

app = dash.Dash()

FIGURE = {
    'data': [{
        'x': [1, 2, 3],
        'y': [4, 3, 6],
        'mode': 'markers',
        'marker': {
            'size': 8
        }
    }],
    'layout': {
        'xaxis': {},
        'yaxis': {},
    }
}

app.layout = html.Div([
    html.H3('Persistent Zoom on Updates'),
    html.Div('''
        Try zooming into the graph (clicking and dragging on the graph),
        then updating the text box. Notice how the graph does not zoom out
        when the graph is updated. Switching to "Refresh View" will
        redraw the graph with auto-range enabled.
    '''),
    dcc.Input(id='my-input'),
    dcc.RadioItems(
        id='lock-zoom',
        options=[{'label': i, 'value': i} for i in ['Lock View', 'Refresh View']],
        value='Lock View'
    ),
    dcc.Graph(
        id='my-graph',
        figure=FIGURE
    )
])

@app.callback(
    Output('my-graph', 'figure'),
    [Input('my-input', 'value'),
     Input('lock-zoom', 'value')],
    [State('my-graph', 'relayoutData')])
def update_graph(value, lock_zoom, relayout_data):
    new_figure = copy.deepcopy(FIGURE)
    new_figure['layout']['title'] = value

    # relayout_data contains data on the zoom and range actions
    print(relayout_data)
    if relayout_data and lock_zoom == 'Lock View':
        if 'xaxis.range[0]' in relayout_data:
            new_figure['layout']['xaxis']['range'] = [
                relayout_data['xaxis.range[0]'],
                relayout_data['xaxis.range[1]']
            ]
        if 'yaxis.range[0]' in relayout_data:
            new_figure['layout']['yaxis']['range'] = [
                relayout_data['yaxis.range[0]'],
                relayout_data['yaxis.range[1]']
            ]

    return new_figure

app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

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

5 Likes