Skip to main content
 首页 » 编程设计

python之根据大小和方向为 matplotlib quiver field 上色

2025年05月04日22qq78292959

我正在尝试实现与 this function in Matlab 相同的行为,其中每个箭头的颜色对应于它的大小和方向,本质上是从轮子中绘制它的颜色。我看到了this question ,但它似乎只适用于 倒钩。我也看到了这个答案,但是 quiver 提示颜色数组必须是二维的。

为 matplotlib.pyplot.quiver 计算 C 的最佳方法是什么? ,同时考虑幅度和方向?

请您参考如下方法:

尽管这已经很老了,但我也遇到过同样的问题。基于matplotlibs quiver demo和 my own answer to this post ,我创建了以下示例。这个想法是使用 HSV colors 将矢量的角度转换为颜色色调值。向量的绝对值作为饱和度和值。

import numpy as np 
import matplotlib.colors 
import matplotlib.pyplot as plt 
 
def vector_to_rgb(angle, absolute): 
    """Get the rgb value for the given `angle` and the `absolute` value 
 
    Parameters 
    ---------- 
    angle : float 
        The angle in radians 
    absolute : float 
        The absolute value of the gradient 
     
    Returns 
    ------- 
    array_like 
        The rgb value as a tuple with values [0..1] 
    """ 
    global max_abs 
 
    # normalize angle 
    angle = angle % (2 * np.pi) 
    if angle < 0: 
        angle += 2 * np.pi 
 
    return matplotlib.colors.hsv_to_rgb((angle / 2 / np.pi,  
                                         absolute / max_abs,  
                                         absolute / max_abs)) 
 
X = np.arange(-10, 10, 1) 
Y = np.arange(-10, 10, 1) 
U, V = np.meshgrid(X, Y) 
 
angles = np.arctan2(V, U) 
lengths = np.sqrt(np.square(U) + np.square(V)) 
 
max_abs = np.max(lengths) 
c = np.array(list(map(vector_to_rgb, angles.flatten(), lengths.flatten()))) 
 
fig, ax = plt.subplots() 
q = ax.quiver(X, Y, U, V, color=c) 
 
plt.show() 

色轮如下。编辑中提到了生成它的代码。


编辑

我刚刚注意到,链接的 matlab 函数“将矢量场渲染为单位长度箭头的网格。箭头方向表示矢量场方向,颜色表示大小”。所以我上面的例子并不是问题所在。这里有一些修改。

左图同上。右边的是引用的 matlab 函数的作用:一个单位长度的箭头图,颜色表示大小。中间的一个不使用大小,只使用颜色中的方向,这也可能有用。我希望从这个例子中可以清楚地看出其他组合。

import numpy as np 
import matplotlib.colors 
import matplotlib.pyplot as plt 
 
def vector_to_rgb(angle, absolute): 
    """Get the rgb value for the given `angle` and the `absolute` value 
 
    Parameters 
    ---------- 
    angle : float 
        The angle in radians 
    absolute : float 
        The absolute value of the gradient 
     
    Returns 
    ------- 
    array_like 
        The rgb value as a tuple with values [0..1] 
    """ 
    global max_abs 
 
    # normalize angle 
    angle = angle % (2 * np.pi) 
    if angle < 0: 
        angle += 2 * np.pi 
 
    return matplotlib.colors.hsv_to_rgb((angle / 2 / np.pi,  
                                         absolute / max_abs,  
                                         absolute / max_abs)) 
 
X = np.arange(-10, 10, 1) 
Y = np.arange(-10, 10, 1) 
U, V = np.meshgrid(X, Y) 
 
angles = np.arctan2(V, U) 
lengths = np.sqrt(np.square(U) + np.square(V)) 
max_abs = np.max(lengths) 
 
# color is direction, hue and value are magnitude 
c1 = np.array(list(map(vector_to_rgb, angles.flatten(), lengths.flatten()))) 
 
ax = plt.subplot(131) 
ax.set_title("Color is lenth,\nhue and value are magnitude") 
q = ax.quiver(X, Y, U, V, color=c1) 
 
# color is length only 
c2 = np.array(list(map(vector_to_rgb, angles.flatten(),  
                                      np.ones_like(lengths.flatten()) * max_abs))) 
 
ax = plt.subplot(132) 
ax.set_title("Color is direction only") 
q = ax.quiver(X, Y, U, V, color=c2) 
 
# color is direction only 
c3 = np.array(list(map(vector_to_rgb, 2 * np.pi * lengths.flatten() / max_abs,  
                                      max_abs * np.ones_like(lengths.flatten())))) 
 
# create one-length vectors 
U_ddash = np.ones_like(U) 
V_ddash = np.zeros_like(V) 
# now rotate them 
U_dash = U_ddash * np.cos(angles) - V_ddash * np.sin(angles) 
V_dash = U_ddash * np.sin(angles) + V_ddash * np.cos(angles) 
 
ax = plt.subplot(133) 
ax.set_title("Uniform length,\nColor is magnitude only") 
q = ax.quiver(X, Y, U_dash, V_dash, color=c3) 
 
plt.show() 

要绘制色轮,请使用以下代码。请注意,这使用了上面的 max_abs 值,它是色调和值可以达到的最大值。 vector_to_rgb() 函数也在这里被重新使用。

ax = plt.subplot(236, projection='polar') 
 
n = 200 
t = np.linspace(0, 2 * np.pi, n) 
r = np.linspace(0, max_abs, n) 
rg, tg = np.meshgrid(r, t) 
 
c = np.array(list(map(vector_to_rgb, tg.T.flatten(), rg.T.flatten()))) 
cv = c.reshape((n, n, 3)) 
 
m = ax.pcolormesh(t, r, cv[:,:,1], color=c, shading='auto') 
m.set_array(None) 
ax.set_yticklabels([])