Announcing Dash Bio 1.0.0 🎉 : a one-stop-shop for bioinformatics and drug development visualizations.

# Prevent lines in Scattergeo-Plot to be drawn over Pacific

Hey there I ran into a problem while using the Scattergeo Plot.
Everything works fine except of changing the orientation lines take from e.g. Australia to the United States. I don’t want them to go straight over the pacific, but over the other continents. Following picture shows the current state:

My intention is to draw the lines from Asia, Australia, etc. in the opposite direction and not over the pacific.

Is there anyone who could help with that issue?

Cheers!

@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:
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)

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)
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).

Wow, wonderful! Thanks a lot! That solved my problem!