Scattermapbox plot curved lines like Scattergeo


In this tutorial (, the lines connecting the points are curved. However I can’t seem to recreate this behavior when using mapbox, i.e. go.Scattermapbox. With Scattermapbox the lines created are straight as shown on this page Are there any options or workarounds to join points using curved lines when using mapbox?

Thanks in advance!

Hi @dee214 did you find any solution for this?

Those curved lines on maps are shortest paths on the shere, representing the Earth, projected on a flat map.
Here is defined the function slerp which returns such a path, and must work on mapbox, too::

Thanks for your response @empet, I’ll try out the function.

@dee214 @dataturnsmeon

Curved lines representing shortest path between two locations on a mapbox, can be plotted using spherical liniar interpolation, slerp:

import numpy as np
from numpy import pi, sin, cos
import plotly.graph_objects as go
def point_sphere(lon, lat):
    #associate the cartesian coords (x, y, z) to a point on the  globe of given lon and lat
    #lon longitude
    #lat latitude
    lon = lon*pi/180
    lat = lat*pi/180
    x = cos(lon) * cos(lat) 
    y = sin(lon) * cos(lat) 
    z = sin(lat) 
    return np.array([x, y, z])

def slerp(A=[100, 45], B=[-50, -25], dir=-1, n=100):
    #Spherical "linear" interpolation
    A=[lonA, latA] lon lat given in degrees; lon in  (-180, 180], lat in ([-90, 90])
    B=[lonB, latB]
    returns n points on the great circle of the globe that passes through the  points A, B
    #represented by lon and lat
    #if dir=1 it returns the shortest path; for dir=-1 the complement of the shortest path
    As = point_sphere(A[0], A[1])
    Bs = point_sphere(B[0], B[1])
    alpha = np.arccos(,Bs)) if dir==1 else  2*pi-np.arccos(,Bs))
    if abs(alpha) < 1e-6 or abs(alpha-2*pi)<1e-6:
        return A
        t = np.linspace(0, 1, n)
        P = sin((1 - t)*alpha) 
        Q = sin(t*alpha)
        #pts records the cartesian coordinates of the points on the chosen path
        pts =  np.array([a*As + b*Bs for (a, b) in zip(P,Q)])/sin(alpha)
        #convert cartesian coords to lons and lats to be recognized by go.Scattergeo
        lons = 180*np.arctan2(pts[:, 1], pts[:, 0])/pi
        lats = 180*np.arctan(pts[:, 2]/np.sqrt(pts[:, 0]**2+pts[:,1]**2))/pi
        return lons, lats

lons, lats = slerp(A=[-111.5, 25], B=[-56, 49], dir=1)
fig = go.Figure(go.Scattermapbox(lon=lons, lat=lats, mode="lines", line_color="red"))
fig.update_layout(mapbox= dict(accesstoken=open(".mapbox_token").read().rstrip(),
                  center_lat= 37.72199960022625, center_lon= -94.65000604447964,
                  style="basic" ))

1 Like