Unexpected behavior while accessing figure properties

Hello,

I am trying to access some properties of a Scattergeo plot called “projection”.
However, if the user hasn’t zoomed or moved the map, no properties are set, which is kind of an unwanted behavior, there should be some default properties.
Plus, if we set fitbounds to True, these properties still aren’t set even though the map was clearly zoomed in and the center was moved, so they are important properties that should be set.
Is this a bug from Plotly or it is just made like that and there is nothing we can do ?

Here is a minimal reproduction of the problem. We can see by clicking the button that even though

import dash
from dash import dcc, html, Input, callback, Output, State
import plotly.graph_objects as go

app = dash.Dash(__name__, assets_folder="assets")

# Coordinates for points over France (example)
france_coords = [
    (48.8566, 2.3522),  # Paris
    (45.7640, 4.8357),  # Lyon
    (43.6047, 1.4442),  # Toulouse
    (50.6292, 3.0573),  # Lille
    (44.8378, -0.5792)  # Bordeaux
]

# Initial figure with an empty Scattergeo trace
fig = go.Figure(go.Scattergeo())
fig.update_geos(
    projection_type="equirectangular",
    showland=True,
    showcountries=True,
    uirevision="Don't change",
    showlakes=True,
    showocean=True,
    landcolor="rgb(204, 204, 204)",
    oceancolor="rgb(145, 191, 219)",
    countrycolor="rgb(128, 128, 128)",
    lakecolor="rgb(145, 191, 219)",
    countrywidth=0.5,
    subunitwidth=0.5,
    coastlinewidth=1,
    resolution=110,
)

app.layout = html.Div([
    dcc.Graph(
        id="map",
        figure=fig,
        config={"scrollZoom": True},
        style={"height": "80vh"}
    ),
    html.Button("Click me", id="button"),
    html.Div("Click the button to show the scale", id="output")
])


@callback(
    Output("map", "figure"),
    Input("button", "n_clicks"),
    prevent_initial_call=True
)
def display_line(n_clicks):
    # Extract latitude and longitude for the points
    latitudes = [coord[0] for coord in france_coords]
    longitudes = [coord[1] for coord in france_coords]

    # Create a new figure with the updated data (including the line)
    new_fig = go.Figure(go.Scattergeo(
        lat=latitudes,
        lon=longitudes,
        mode="lines+markers",  # "lines+markers" will show both points and the connecting line
        line=dict(color="blue", width=4),  # Line style
        marker=dict(size=8, color="red")  # Point style
    ))

    # Update the geographical layout to maintain map features and enable auto-range
    new_fig.update_geos(
        projection_type="equirectangular",
        showland=True,
        showcountries=True,
        uirevision="Don't change",
        showlakes=True,
        showocean=True,
        landcolor="rgb(204, 204, 204)",
        oceancolor="rgb(145, 191, 219)",
        countrycolor="rgb(128, 128, 128)",
        lakecolor="rgb(145, 191, 219)",
        countrywidth=0.5,
        subunitwidth=0.5,
        coastlinewidth=1,
        resolution=110,
        fitbounds="locations"
    )

    return new_fig


@callback(
    Output("output", "children"),
    Input("map", "figure"),
    prevent_initial_call=True
)
def display_scale(figure):
    try:
        out = "Current scale is:" + str(figure["layout"]["geo"]["projection"]["scale"])
    except KeyError:
        out = "Not found"

    return out


if __name__ == "__main__":
    app.run(debug=True)

Hey @Galaktik, just an idea: did you try to zoom via callback and does it populate then?