Reputation: 459
I am running Folium 0.2.1' with Python 2.7.11 on Jupyter Notebook Server 4.2.1
I am trying to plot lines on a map, which have a arrowhead to convey direction
import folium
#DFW, LGA coordinates
coordinates=[(32.900908, -97.040335),(40.768571, -73.861603)]
m = folium.Map(location=[32.900908, -97.040335], zoom_start=4)
#line going from dfw to lga
aline=folium.PolyLine(locations=coordinates,weight=2,color = 'blue')
m.add_children(aline)
Is there a way to add an arrowhead to the line?
Upvotes: 11
Views: 14705
Reputation: 11
I found a solution for this issue: I calculate my own arrow points with trigonometry and then I call polyline function using that points.
def arrow_points_calculate(self, ini_lat, ini_long, heading):
lenght_scale = 0.00012
sides_scale = 0.000025
sides_angle = 25
latA= ini_lat
longA = ini_long
latB = lenght_scale * math.cos(math.radians(heading)) + latA
longB = lenght_scale * math.sin(math.radians(heading)) + longA
latC = sides_scale * math.cos(math.radians(heading + 180 - sides_angle)) + latB
longC = sides_scale * math.sin(math.radians(heading + 180 - sides_angle)) + longB
latD = sides_scale * math.cos(math.radians(heading + 180 + sides_angle)) + latB
longD = sides_scale * math.sin(math.radians(heading + 180 + sides_angle)) + longB
pointA = (latA, longA)
pointB = (latB, longB)
pointC = (latC, longC)
pointD = (latD, longD)
point = [pointA, pointB, pointC, pointD, pointB]
return point
folium.PolyLine(locations=points, color="purple").add_to(
position_plot)
Lenght_scale and Side_scale variables must be modified depends of the arrow size you want. If you have the coords of start and finish of the arrow, just use the final coords as point B and calculate Side Scale relative to the length between that points (20% of the length between points is a correct scale on my opinion).
Example of the result: Position plot + heading arrows
Hope it could help
Upvotes: 1
Reputation: 162
I may be a little late to the party, but I have another suggestions for other people bothered by this problem. I would suggest to use the pyproj package's Geod class, which can do geodetic and great circle calculations. We can use it to get forward and backward azimuth of a piece of a LineString. Then for each piece we add a small polygon marker(or something similar) on one end.
from pyproj import Geod
# loop your lines
for line in lines.itertuples():
# format coordinates and draw line
loc = [[j for j in reversed(i)] for i in line.geometry.coords]
folium.PolyLine(loc, color="red").add_to(m)
# get pieces of the line
pairs = [(loc[idx], loc[idx-1]) for idx, val in enumerate(loc) if idx != 0]
# get rotations from forward azimuth of the line pieces and add an offset of 90°
geodesic = Geod(ellps='WGS84')
rotations = [geodesic.inv(pair[0][1], pair[0][0], pair[1][1], pair[1][0])[0]+90 for pair in pairs]
# create your arrow
for pair, rot in zip(pairs, rotations):
folium.RegularPolygonMarker(location=pair[0], color='red', fill=True, fill_color='red', fill_opacity=1,
number_of_sides=3, rotation=rot).add_to(m)
I hope someone will find this snippet helpful. Have a great day! =)
Upvotes: 6
Reputation: 116
You could use a regular polygon marker to draw a triangle at the end point...
folium.RegularPolygonMarker(location=(32.900908, -97.040335), fill_color='blue', number_of_sides=3, radius=10, rotation=???).add_to(m)
You'll have to use some trigonometry to calculate the angle of rotation for the triangle to point in the correct direction. The initial point of any such marker points due east.
Upvotes: 9