How to Access Bounding Box Coordinates of Plotly Mapbox figure?

Hello,

I am trying to access the coordinates pertaining to the bounding box of a Plotly Mapbox figure (essentially the min and max latitude and longitude in view at any given time). Does anyone know how such information about the figure might be accessed? I am working in Python + Dash, and am thinking a callback will need to be constructed to retrieve this information when a user either pans or zooms in on the Mapbox figure.

Any help would be greatly appreciated!

Minimal working example (will require a mapbox token)

import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html


fig = go.Figure()
fig.add_trace(go.Scattermapbox(mode = "markers+lines"))

fig.update_layout(
    autosize=True,
    hovermode='closest',
    showlegend=True,
    margin=dict(t=20, b=0, l=0, r=0),
    mapbox=dict(
        # Access token comes from https://docs.mapbox.com/help/glossary/access-token/
        accesstoken= "Insert MapBox Token Key Here",
        bearing=0,
        pitch=0,
        zoom=3,
        style="satellite-streets"
    ),
)

app = JupyterDash(__name__)
app.layout = html.Div([
    dcc.Graph(figure=fig)
])

app.run_server(mode="jupyterlab",debug=True)

I haven’t got much experience with Plotly Mapbox, but in dash leaflet you could use the bounds property,

import json
import dash
import dash_html_components as html
import dash_leaflet as dl
from dash.dependencies import Output, Input

app = dash.Dash()
app.layout = html.Div([
    dl.Map(dl.TileLayer(), id="map", style={'width': '100%', 'height': '50vh'}),
    html.Div(id="log")
])


@app.callback(Output("log", "children"), [Input("map", "bounds")])
def log_bounds(bounds):
    return json.dumps(bounds)


if __name__ == '__main__':
    app.run_server(port=8077)

Thanks Emil for suggesting Dash leaflet! I found a way to do this using Plotly MapBox as well.

For those who may encounter this in the future, this is now possible via relayoutData (https://github.com/plotly/plotly.js/issues/4399) and (https://github.com/plotly/plotly.js/pull/4413).

For reference, I am using dash 1.18.1 and dash_core_components 1.14.1.

Here is a minimal working example that prints the min and max latitude and longitude of Mapbox and writes these values to a hidden Div element.

from jupyter_dash import JupyterDash # replace with dash if not working in a jupyter notebook/lab
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import json

fig = go.Figure()
fig.add_trace(go.Scattermapbox(mode="markers+lines"))

fig.update_layout(
    autosize=True,
    hovermode='closest',
    showlegend=True,
    
    margin=dict(t=20, b=0, l=0, r=0),
    mapbox=dict(
        # Access token comes from https://docs.mapbox.com/help/glossary/access-token/
        accesstoken= "Insert Access Token Here",
        bearing=0,
        pitch=0,
        zoom=3,
        style="satellite-streets"
    ),
)



app = JupyterDash(suppress_callback_exceptions=True)
app.layout = html.Div([
    dcc.Graph(id='Map', figure=fig),
    html.Div(id='Coordinates',style={'display': 'none'})
])

@app.callback(
    Output('Coordinates', 'children'),
    Input('Map', 'relayoutData'))
def display_relayout_data(relayoutData):
    try:
        coords = relayoutData['mapbox._derived']['coordinates']
        lon_min = coords[0][0]
        lon_max = coords[1][0]
        lat_min = coords[2][1]
        lat_max = coords[1][1]
        
        print(f'Min Lat: {lat_min}, Max Lat: {lat_max}, Min Lon:{lon_min}, Max Lon: {lon_max}')
        return [lat_min, lat_max, lon_min, lon_max]
    except:
        return []
    
app.run_server(mode="jupyterlab",debug=True,port=8060)

Thanks for the information @pfussee.
I have tried your method and have a couple of follow-up questions.

  • Do you know how to get the bounding box coordinates initially (i.e. after the mapbox was first rendered and without user interaction (pan or zoom) yet)?

  • Second, upon zooming, relayoutData only contains the new zoom value but does not contain the new mapbox._derived[‘coordinates’] values. Do you know happen to know a way to derive new bounding coordinates using a new zoom value?

1 Like