根据大小和方向,为matplotlib quiver字段着色

3

我正在尝试实现与Matlab中此功能相同的行为,即每个箭头的颜色均对应其大小和方向,基本上从一个色轮中绘制其颜色。我看到了这个问题,但它似乎只适用于barbs。我还看到了这篇答案,但是quiver抱怨颜色数组必须是二维的。

计算C以考虑大小和方向的最佳方法是什么,用于matplotlib.pyplot.quiver


我发现这个帖子回答了一个类似的问题。https://dev59.com/E2ct5IYBdhLWcg3wmOhO - Alex Messina
计算C的方式完全取决于您的需求。您问题中提到的Matlab文件仅使用方向来计算颜色。您能准确地说明您想要的效果吗?也许这个问题本身已经不重要了,因为它已经过去很久了。但它可能会帮助其他可能遇到类似问题的人。 - pyan
2个回答

1
我不知道你是否已经发现,matplotlib 1.4.x中的箭头具有3D功能。但是,在尝试为箭头着色时,这种功能是有限的。我和一个朋友花了半个小时左右编写了以下脚本(用于我的论文实验数据的绘制),使用电子表格中的十六进制值。我们将在学期结束后使其更加自动化,但是将颜色映射传递给quiver的问题在于,由于某种原因,它无法接受向量形式。 此链接 是我的git存储库,其中托管了我使用的代码,由另一个朋友稍微整理。 我希望我能节省某人所花费的时间。

1
尽管这篇文章现在已经相当老了,但我遇到了同样的问题。基于matplotlibs quiver demo我对这篇文章的回答,我创建了以下示例。其思路是将向量的角度转换为颜色,使用HSV 颜色的 Hue 值。向量的绝对值用作饱和度和值。
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()

Result plot

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

编辑

我刚刚注意到,链接的Matlab函数“将矢量场呈网格状的单位长度箭头。箭头方向表示矢量场方向,颜色表示大小”。所以我上面的示例并不是问题中的内容。以下是一些修改。

左图与上图相同。右图执行引用的Matlab函数:颜色表示大小的单位长度箭头图。中间的图仅使用方向而不是大小来表示颜色,这也可能很有用。我希望其他组合从这个示例中也很清楚。

Result plot

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接