@t1ch4n
go.Scattergeo
with mode="lines"
, and lon
, lat
lists of only two entries each, dispalys exclusively the shortest path between the points on the globe of given lon and lat. (in fact the projection of the shortest path onto a planar map).
The shortest path is the arc of minimum length on the big circle of the globe passing through the two points.
To plot the complement of the shortest path we have to define a few functions as below:
import plotly.graph_objects as go
import numpy as np
from numpy import pi, sin, cos
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
#############################
fig = go.Figure()
#Define the map:
fig.add_trace(go.Scattergeo(
locationmode = 'USA-states',
lon =[-74, 151.2093], #New York
lat = [40.71, -33.86],#Sydney
hoverinfo = 'text',
text = ["New-York", "Sydney"],
mode = 'markers+text',
marker_size=3,
line = dict(
width = 3,
color = 'rgb(68, 68, 68)'
)
)))
##Draw in red the shortest path between two cities (i.e. the path that is plotted when tou give only the lon and lat for New York and Sydney)
lons, lats = slerp(A= [151.2093, -33.8688], B = [-74, 40.7128], dir=1)
fig.add_trace(
go.Scattergeo(
locationmode = 'USA-states',
lon = lons,
lat = lats,
mode = 'lines',
line = dict(width = 1,color = 'red')))
#Draw the complement of the shortest path
lons, lats = slerp(A= [151.2093, -33.8688], B = [-74, 40.7128], dir=-1)
fig.add_trace(
go.Scattergeo(
locationmode = 'USA-states',
lon = lons,
lat = lats,
mode = 'lines',
line = dict(width = 2,color = 'green')))
Shortest path:
Complement of the shortest path:
If you want to go on a particular path, between two points, not on the shortest path or its complement,
then you must define effectively that path
t\in [a, b]->(lon(t), lat(t))
on the sphere (of radius 1).