Hello everyone,
I’m trying to change the projection of a map when the user clicks on a projection. For exemple, I’m trying to change from equirectangular (which is, I believe, the default one) to orthographic but every time I change the projection and move around the chart, the map gets weirder and weirder. The map starts to distort, and the view gets off-center
Here is a minimal reproduction :
import plotly.graph_objects as go
import dash
import dash_mantine_components as dmc
from dash import callback, html, Patch, Output, Input, dcc
from plotly.subplots import make_subplots
app = dash.Dash(__name__)
# Initialize figure with subplots
fig = make_subplots(
rows=1,
cols=2,
column_widths=[0.70, 0.30],
horizontal_spacing=0.020,
specs=[[{"type": "scattergeo"}, {"type": "scatter"}]],
)
# The map
fig.add_trace(go.Scattergeo(), row=1, col=1)
# The main chart
fig.add_trace(go.Scattergl(), row=1, col=2)
fig.update_layout(
height=530,
width=1700,
margin=dict(l=0, r=0, t=20, b=0),
legend=dict(itemwidth=30),
autosize=True,
dragmode="pan",
)
# Update geo subplot properties
fig.update_geos(
patch={
"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,
"center": {"lat": 0, "lon": 0},
"projection_scale": 1,
"projection_type": "equirectangular",
},
overwrite=True,
)
map_projection = html.Div(
[
dmc.SegmentedControl(
id="map_projection",
data=["Equirectangular", "Orthographic"],
value="Equirectangular",
),
]
)
app.layout = dmc.MantineProvider(
html.Div(
[
dcc.Graph(id="graph", figure=fig, clear_on_unhover=True),
map_projection
]
)
)
@callback(
Output("graph", "figure"),
Input("map_projection", "value")
)
def change_map_projection(map_projection: str) -> Patch:
patch = Patch()
patch["layout"]["geo"]["projection"]["type"] = map_projection.lower()
return patch
if __name__ == "__main__":
app.run(debug=True, port=8050)