Ok, let's produce The Rainbow Arrow. ;-)
There is of course no built-in way to colorize an arrow with a color gradient. Instead one needs to build the arrow manually. I can think of two options. (1) Create a color gradient and clip it with the circonference path of an arrow. (2) Produce a LineCollection
with a colorgradient and then add an arrow head to it.
The following is the second option:
import matplotlib.pyplot as plt
import matplotlib.transforms
import matplotlib.path
import numpy as np
from matplotlib.collections import LineCollection
def rainbowarrow(ax, start, end, cmap="viridis", n=50,lw=3):
cmap = plt.get_cmap(cmap,n)
# Arrow shaft: LineCollection
x = np.linspace(start[0],end[0],n)
y = np.linspace(start[1],end[1],n)
points = np.array([x,y]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, cmap=cmap, linewidth=lw)
lc.set_array(np.linspace(0,1,n))
ax.add_collection(lc)
# Arrow head: Triangle
tricoords = [(0,-0.4),(0.5,0),(0,0.4),(0,-0.4)]
angle = np.arctan2(end[1]-start[1],end[0]-start[0])
rot = matplotlib.transforms.Affine2D().rotate(angle)
tricoords2 = rot.transform(tricoords)
tri = matplotlib.path.Path(tricoords2, closed=True)
ax.scatter(end[0],end[1], c=1, s=(2*lw)**2, marker=tri, cmap=cmap,vmin=0)
ax.autoscale_view()
fig,ax = plt.subplots()
ax.axis([0,5,0,4])
ax.set_aspect("equal")
rainbowarrow(ax, (3,3), (2,2.5), cmap="viridis", n=100,lw=3)
rainbowarrow(ax, (1,1), (1.5,1.5), cmap="jet", n=50,lw=7)
rainbowarrow(ax, (4,1.3), (2.7,1.0), cmap="RdYlBu", n=23,lw=5)
plt.show()
The following is the old solution, caused by a misunderstanding
An annotation arrow is a single arrow. Hence you would need to draw any number of arrows individually. In order for each arrow to then obtain a color, you may use the arrowprops=dict(color="<some color>")
argument.
To get colors from a colormap, you can call the colormap with a value. Here the length of the arrow can be taken as the quantity to encode as color.
import matplotlib.pyplot as plt
import numpy as np
RdPu = plt.get_cmap('RdPu')
ax = plt.subplot(111)
ax.axis([-6,2,-4.5,3.2])
ax.set_aspect("equal")
X = np.linspace(0,1,17, endpoint=False)
Xt =np.sin(2.5*X+3)
Yt = 3*np.cos(2.6*X+3.4)
Xh = np.linspace(-0.5,-5,17)
Yh = -1.3*Xh-5
#Distance
D = np.sqrt((Xh-Xt)**2+(Yh-Yt)**2)
norm = plt.Normalize(D.min(), D.max())
for xt, yt, xh, yh, d in zip(Xt,Yt,Xh,Yh,D):
ax.annotate("Test", xy=(xh,yh), xycoords='data',
xytext=(xt,yt), textcoords='data',
size=10, arrowprops=dict(color=RdPu(norm(d))))
plt.show()