# Plotly arrow in scattergeo with text on the line

**URL:** <https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060>\
**Category:** 📊 Plotly Python\
**Created:** [January 24, 2020, 4:04am UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060 "2020-01-24T04:04:56Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![tcokyasar](https://avatars.discourse-cdn.com/v4/letter/t/67e7ee/32.png) [@tcokyasar](https://community.plotly.com/u/tcokyasar)\
**Post date:** [January 24, 2020, 4:04am UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/1 "2020-01-24T04:04:56Z")

</div>

I have the following code to generate the plot with Plotly in Python 3.7. I am trying to make the line an arrow instead that is pointing to `Fort Lauderdale`. Also, in the center of the line, I want to have some text. There are many references but no proper answer available.

```
import numpy as np
import pandas as pd
import plotly.graph_objects as go

np.random.seed(1)
I_list = list(np.random.randint(0,3229,10))
skiplist = set(range(1, 3229)) - set(I_list)
locations = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/2014_us_cities.csv', skiprows=skiplist)

scale = 5000
fig = go.Figure()
fig.add_trace(go.Scattergeo(
        locationmode = 'USA-states',
        lon = locations['lon'],
        lat = locations['lat'],
        text = locations['name'],
        textfont = {"color": 'black',
                    "family":'Times New Roman',
                    "size":14},
        textposition="top center",
        name = "Candidate Facility",
        mode ="markers+text",
        marker = dict(
            size = 10,
            color = "black",
            line_color='black',
            line_width=0.5,
            sizemode = 'area')))

fig.add_trace(go.Scattergeo(
    lat = [locations['lat'][5], locations['lat'][0]],
    lon = [locations['lon'][5], locations['lon'][0]],
    mode = 'lines',
    line = dict(width = 2, color = 'blue'),
))

fig.update_layout(
        showlegend = False,
        geo = dict(
            scope = 'usa',
            landcolor = 'rgb(217, 217, 217)'))
fig.show()

```

[![enter image description here](https://i.stack.imgur.com/IpMbY.png)](https://i.stack.imgur.com/IpMbY.png)

---

<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:** [January 24, 2020, 2:14pm UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/2 "2020-01-24T14:14:42Z")

</div>

Hi @tcokyasar,

Plotly does not provide an arrow marker but with a few lines of code we get it:

```auto
import numpy as np
import pandas as pd
import plotly.graph_objects as go

np.random.seed(1)
I_list = list(np.random.randint(0,3229,10))
skiplist = set(range(1, 3229)) - set(I_list)
locations = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/2014_us_cities.csv', skiprows=skiplist)

scale = 5000
fig = go.Figure()
fig.add_trace(go.Scattergeo(
        locationmode = 'USA-states',
        lon = locations['lon'],
        lat = locations['lat'],
        text = locations['name'],
        textfont = {"color": 'black',
                    "family":'Times New Roman',
                    "size":14},
        textposition="top center",
        name = "Candidate Facility",
        mode ="markers+text",
        marker = dict(
            size = 10,
            color = "black",
            line_color='black',
            line_width=0.5,
            sizemode = 'area')))

fig.add_trace(go.Scattergeo(
    lat = [locations['lat'][5], locations['lat'][0]], 
    lon = [locations['lon'][5], locations['lon'][0]],
    mode = 'lines',
    line = dict(width = 1.5, color = 'blue'),
))

#Workaround to get the arrow at the end of an edge AB

l = 1.1 # the arrow length
widh =0.035 #2*widh is the width of the arrow base as triangle

A = np.array([locations['lon'][5], locations['lat'][5]])
B = np.array([locations['lon'][0], locations['lat'][0]])
v = B-A
w = v/np.linalg.norm(v)     
u =np.array([-v[1], v[0]]) #u orthogonal on w
         
P = B-l*w
S = P - widh*u
T = P + widh*u

fig.add_trace(go.Scattergeo(lon = [S[0], T[0], B[0], S[0]], 
                            lat =[S[1], T[1], B[1], S[1]], 
                            mode='lines', 
                            fill='toself', 
                            fillcolor='blue', 
                            line_color='blue'))
#------Display your text at the middle of the segment AB
fig.add_trace(go.Scattergeo(lon =[0.5*(A+B)[0]], lat = [0.5*(A+B)[1]], mode='text', text=' Your text'))

fig.update_layout(width=900, height=750,
        showlegend = False,
        geo = dict(
            scope = 'usa',
            landcolor = 'rgb(217, 217, 217)'))

```

 ![arrow-scattergeo](https://us1.discourse-cdn.com/flex024/uploads/plot/original/2X/0/04d59665d9c241a63a20facc2ab0cbe0b241f741.png)

---

<div class="post-metadata">

**Author:** ![tcokyasar](https://avatars.discourse-cdn.com/v4/letter/t/67e7ee/32.png) [@tcokyasar](https://community.plotly.com/u/tcokyasar)\
**Post date:** [January 24, 2020, 3:40pm UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/3 "2020-01-24T15:40:10Z")

</div>

@empet I really appreciate for this response. I also wonder if there is any way to use self pointing (loop) arrows for some locations, e.g., Hobbs? Should I open a new topic or can you also help me with this problem as well?

---

<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:** [January 24, 2020, 4:14pm UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/4 "2020-01-24T16:14:20Z")

</div>

@tcokyasar I’ll give the answer here, because it is also a graph edge. But let me try first.

---

<div class="post-metadata">

**Author:** ![mpkrass](https://avatars.discourse-cdn.com/v4/letter/m/e47774/32.png) [@mpkrass](https://community.plotly.com/u/mpkrass)\
**Post date:** [September 2, 2021, 8:19pm UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/5 "2021-09-02T20:19:01Z")

</div>

I wanted to note for anyone looking at this that the width of the arrows grow as the distance between points grow with the current solution. Judging from the comments in code I think @empet may have accidentally typed ‘v’ instead of ‘w’ when calculating ‘u’.

Original showing all states ( `u =np.array([-v[1], v[0]])` ):  
 ![screenshot1](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/1/8/18882bbc2a312b3bc77ed8b1ca2c4675e947527e.png)

Version replacing `u = np.array([-v[1], v[0]])` with `u = np.array([-w[1], w[0]])*10 `  
 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/f/7/f75ce59088101eddb579016b17933fd83ac7896b.png)

---

<div class="post-metadata">

**Author:** ![mrv](https://avatars.discourse-cdn.com/v4/letter/m/848f3c/32.png) [@mrv](https://community.plotly.com/u/mrv)\
**Post date:** [October 2, 2022, 7:01pm UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/6 "2022-10-02T19:01:37Z")

</div>

@empet @mpkrass Thanks for this solution…  
I do have an unfortunate artifact… See in the example below. The arrows don’t follow the ‘great circle’ sort of lines instead seems to be pointed at the direct line. So short distances work okay, but longer ones not. (e.g. the red is very obvious, or if you zoom in )

any suggestion how I can have hem point along the line

![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/1/0/1048989411853496fdb0d712d67feddcd43de10f.png)  
 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/8/2/82498e4f84ebf65ff21425be9ec808bad94ddbf0.png)

![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/3/1/310ac03d155469a8eab6255fde5ea6bfc8bbcfe8.png)

note as projection I have:

```auto
fig.update_layout(
    showlegend = True,
    geo = dict(
    #scope = 'world',
    #projection_type = 'azimuthal equal area',
    projection_type="natural earth",
    showland = True,
    landcolor = 'rgb(243, 243, 243)',
    subunitcolor = "rgb(217, 217, 217)",
    countrycolor = "rgb(217, 217, 217)",
    countrywidth = 1,
    subunitwidth = 0.5,
    showcountries=True,  
     ),
)

```

---

<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:** [October 3, 2022, 1:35pm UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/7 "2022-10-03T13:35:02Z")

</div>

@mrv  
Your arrows have a wrong direction because almost surely their end points are not placed on the line giving the corresponding aeeow direction.  
For shortest path between two points on a map it’s a bit more complicated to choose two points on that line (i.e. the curved line on your map).  
Some time ago I explained on this forum how is parameterized the shortest path between two points, by the slerp (spherical linear interpolation). With that parameterization you will be able to select two points on one of its ends to draw the arrow between them.

---

<div class="post-metadata">

**Author:** ![Leov](https://avatars.discourse-cdn.com/v4/letter/l/ed655f/32.png) [@Leov](https://community.plotly.com/u/Leov)\
**Post date:** [November 16, 2022, 10:45am UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/8 "2022-11-16T10:45:29Z")

</div>

@empet Perhaps you have the link for that explanation on the parametrization of the shortest path? I’m doing some work where the arrows are the most important aspect of the world chart!

---

<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 16, 2022, 11:29am UTC](https://community.plotly.com/t/plotly-arrow-in-scattergeo-with-text-on-the-line/34060/9 "2022-11-16T11:29:27Z")

</div>

In this thread [Scattermapbox plot curved lines like Scattergeo](https://community.plotly.com/t/scattermapbox-plot-curved-lines-like-scattergeo/43665) you can find the functions `point_sphere`, and `slerp` that implement the shortest path on maps.  
To get more details on slerp just google for this term.
