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)