# Scattermapbox plot curved lines like Scattergeo

**URL:** <https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665>\
**Category:** 📊 Plotly Python\
**Created:** [August 11, 2020, 11:17am UTC](https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665 "2020-08-11T11:17:10Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dee214](https://avatars.discourse-cdn.com/v4/letter/d/34f0e0/32.png) [@dee214](https://community.plotly.com/u/dee214)\
**Post date:** [August 11, 2020, 11:17am UTC](https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665/1 "2020-08-11T11:17:10Z")

</div>

Hi,

In this tutorial ([https://plotly.com/python/lines-on-maps/](https://plotly.com/python/lines-on-maps/)), 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 [https://plotly.com/python/lines-on-mapbox/](https://plotly.com/python/lines-on-mapbox/). Are there any options or workarounds to join points using curved lines when using mapbox?

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![dataturnsmeon](https://avatars.discourse-cdn.com/v4/letter/d/4af34b/32.png) [@dataturnsmeon](https://community.plotly.com/u/dataturnsmeon)\
**Post date:** [November 7, 2022, 9:13am UTC](https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665/2 "2022-11-07T09:13:15Z")

</div>

Hi @dee214 did you find any solution for this?

---

<div class="post-metadata">

**Author:** ![empet](https://avatars.discourse-cdn.com/v4/letter/e/977dab/32.png) [@empet](https://community.plotly.com/u/empet)\
**Post date:** [November 7, 2022, 6:21pm UTC](https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665/3 "2022-11-07T18:21:47Z")

</div>

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::  
[https://community.plotly.com/t/prevent-lines-in-scattergeo-plot-to-be-drawn-over-pacific/59196/2](https://community.plotly.com/t/prevent-lines-in-scattergeo-plot-to-be-drawn-over-pacific/59196/2)

---

<div class="post-metadata">

**Author:** ![dataturnsmeon](https://avatars.discourse-cdn.com/v4/letter/d/4af34b/32.png) [@dataturnsmeon](https://community.plotly.com/u/dataturnsmeon)\
**Post date:** [November 7, 2022, 7:18pm UTC](https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665/4 "2022-11-07T19:18:31Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![empet](https://avatars.discourse-cdn.com/v4/letter/e/977dab/32.png) [@empet](https://community.plotly.com/u/empet)\
**Post date:** [November 8, 2022, 1:37pm UTC](https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665/5 "2022-11-08T13:37:25Z")

</div>

@dee214@dataturnsmeon

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

```auto
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(np.dot(As,Bs)) if dir==1 else 2*pi-np.arccos(np.dot(As,Bs))
    if abs(alpha) < 1e-6 or abs(alpha-2*pi)<1e-6:
        return A
    else:
        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,
                  zoom=2.5,
                  style="basic" ))

```

 ![shortestpath-mbx](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/a/0/a077d4ac69945c616990dffcd84c602870fc9074.png)
