📣 Preserving UI State, like Zoom, in dcc.Graph with uirevision with Dash

UPDATE: Solved this with different syntax for map figure.

hi @chriddyp
I was looking for this functionality but I’m not sure if I understand the syntax. I have a map with points on it. These points are filtered based on three dropdown filters. Each time I apply filtering, the map centers to initial position. I’m attaching part of the code that shows dropdown items, map, and callback. I’m wondering where I should have uirevision in the code.

html.Div([
            dcc.Dropdown(
                df['country'].unique().tolist(),
                placeholder='Country',
                id='country-filter',
                multi=True,
            ),
        ],
        style={'width': '15%','float': 'left', 'display': 'inline-block'}),

        html.Div([
            dcc.Dropdown(
                df['partner'].unique().tolist(),
                placeholder='Partner',
                id='partner-filter',
                multi=True,
            ),
        ], style={'width': '15%', 'float': 'left', 'display': 'inline-block'}),

        html.Div([
            dcc.Dropdown(
                df['product'].unique().tolist(),
                placeholder='Product',
                id='product-filter',
                multi=True,
            ),
        ], style={'width': '15%', 'float': 'left', 'display': 'inline-block'})

    ], style={
        'padding-bottom' : '2.5%'
    })

html.Div([
        dcc.Graph(
            id='map',
            
            
        )
    ], style={'width': '75%', 'display': 'inline-block','flex':'1'})

#callback

@app.callback(
    Output('map', 'figure'),
    Input('country-filter', 'value'),
    Input('partner-filter', 'value'),
    Input('product-filter', 'value'))
def update_main_map(country,partner,product):

    input_list = []
    # Callback triggers when app is running. it returns callback error
    # if the function is not receiving any input from the beginning.
    # The checks below avoid callback errors.
    if country is not None:
        a = "`country` == " + "'" + country + "'"
        input_list.append(a)
    if partner is not None:
        b = "`partner` == " + "'" + partner + "'"
        input_list.append(b)
    if product is not None:
        c = "`product` == " + "'" + product + "'"
        input_list.append(c)
    
    
    delimeter = " and "

    if len(input_list)>0:
        query_string = delimeter.join(input_list)  
        dff = df.query(query_string) #query method in pandas allows to enter complex row filtering with one string.
    else:
        dff=df.copy()

    map_fig = px.scatter_mapbox(df, lat="latitude", lon="longitude", hover_data=["age", "income"],
                        color_discrete_sequence=["fuchsia"], zoom=6, height=780, center={'lat':57.67, 'lon':12.00})
    map_fig.update_layout(mapbox_style="open-street-map",
                          margin={"r":0,"t":0,"l":0,"b":0},
                          )

    return map_fig

Dash app screenshot:

I have

dash=2.8.1
dash-core-components=2.0.0

Hello, I have the same small issues using uirevision on scatter3d plots, such as the camera returning to the initial position after the first update (only the first time) and the zoom changing a bit when the camera readjusts. Any suggestion on how to fix them?

Hey @alexcjohnson i’ve been unable to make uirevision to work while using the orthographic projection on 3D scatter plot using graph object.
here’s a simplified example :

import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import pandas as pd
from numpy.random import randn
# Sample data
data = {
    'sepal_width': [3.5, 3.0, 3.2, 3.1, 3.6],
    'sepal_length': [5.1, 4.9, 4.7, 4.6, 5.0],
    'petal_length': [1.4, 1.4, 1.3, 1.5, 1.4],
}
data2 = {
    'sepal_width': [3.5, 3.0, 3.2, 3.1, 3.6]*3,
    'sepal_length': [5.1, 4.9, 4.7, 4.6, 5.0]*2,
    'petal_length': [1.4, 1.4, 1.3, 1.5, 1.4]*1,
}
df = pd.DataFrame(data)

# Initial Figure
scatter_figure = go.Figure()
scatter_figure.layout.uirevision = True
scatter_figure.layout.scene.camera.projection.type = 'orthographic'
# Add 3D Scatter Plot Trace
scatter_figure.add_trace(
    go.Scatter3d(
        x=df['sepal_width'],
        y=df['sepal_length'],
        z=df['petal_length'],
        mode='markers',
        marker=dict(
            size=12,
            opacity=0.7,
        ),
        scene='scene',
    )
)

# Dash app
app = dash.Dash(__name__)

# Layout
app.layout = html.Div([
    dcc.Graph(
        id='scatter-plot',
        figure=scatter_figure,
    ),
    dcc.Checklist(
        id='toggle-checklist',
        options=[
            {'label': 'Toggle Plot', 'value': 'toggle'}
        ],
        value=['toggle'],
    ),
])

# Callback to toggle plot visibility
@app.callback(
    Output('scatter-plot', 'figure'),
    [Input('toggle-checklist', 'value')]
)
def toggle_plot(value):
    if 'toggle' in value:
        # If 'toggle' is in the value, show the plot
        return scatter_figure
    else:
        df = data2
        scatter_figure.add_trace(
            go.Scatter3d(
                x=df['sepal_width'],
                y=df['sepal_length'],
                z=df['petal_length'],
                mode='markers',
                marker=dict(
                    size=12,
                    opacity=0.7,
                ),
                scene='scene',
            )
        )
        return scatter_figure

# Run the app
if __name__ == '__main__':
    app.run_server(debug=True,port = 8078)

every time im toggling the check box the view completely reversed to its original position, and only when im specifing projection to be orthographic , works perfectly on perspective, am i missing something?
thanks in advance

(Sorry, lost track of this during the holidays - Happy New Year!)

That sure sounds like a bug to me, would you mind creating a new plotly.js issue and including the app you posted above? We’ll try to take a look.

hey , I’m not really familiar with plotly.js.
I will add the app and open an issue under the link you shared , Happy New Year !