Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
423 views
in Technique[技术] by (71.8m points)

python - Using Colormap with Annotate Arrow in Matplotlib

I have seen many examples of using annotate arrows in Matplotlib that have a single color specified. I was wondering if it is possible to instead set the color according to a colormap, so that the whole range of colors from a specified colormap is displayed on a single arrow. I know that it is possible to set the color of an arrow to a single color from a colormap, but I want to have a single arrow displaying all of the colors of a given colormap.

A simple example of using an annotate arrow is shown below. In the documentation, I have not found any method for specifying a colormap. If I naively specify a colormap, I get an error from an invalid RGBA argument.

import matplotlib.pyplot as plt

RdPu = plt.get_cmap('RdPu')

ax = plt.subplot(111)
ax.annotate("Test", xy=(0.2, 0.2), xycoords='data',
    xytext=(0.8, 0.8), textcoords='data',
    size=20, arrowprops=dict(color=RdPu),
)

plt.show()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

Matplotlib rainbow arrow


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

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...