在matplotlib中为三维箭袋图添加颜色

时间:2015-02-09 22:18:11

标签: python numpy matplotlib mplot3d

我希望在我的3D箭袋图中找到与颜色图相对应的颜色。 2d版本的绘图有一个可选的数组,用于将颜色映射到箭头。如何在3d版本中创建相同的效果?

4 个答案:

答案 0 :(得分:6)

3D箭头图是1.4中的一个全新功能(它的文档)可能仍然有点粗糙的边缘。在这种情况下,我们可以尝试使用这样一个事实:箭头被实现为LineCollection,它最终继承自ScalarMappable,这意味着它知道什么是色彩图,而返回的艺术家有方法{{ 1}}。

以文档here

为基础
set_array

enter image description here

但是,您会注意到 head shaft 的颜色不同,这是由于其实现方式的实现细节,每个部分被绘制为这是自己的路线。

直接使用from mpl_toolkits.mplot3d import axes3d import matplotlib.pyplot as plt import numpy as np fig = plt.figure() ax = fig.gca(projection='3d') x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2), np.arange(-0.8, 1, 0.2), np.arange(-0.8, 1, 0.8)) u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z) v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z) w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)) q = ax.quiver(x, y, z, u, v, w, length=0.1, cmap='Reds', lw=2) q.set_array(np.random.rand(np.prod(x.shape))) plt.show() 和色彩映射函数并将结果传递给Norm可能是更好的方法。

答案 1 :(得分:2)

可以使用colors参数为每个箭头指定自定义颜色,虽然这样做的方式根本不是直截了当的(对于 matplotlib 2.0.0) )。我在this issue中指定了实际绘制箭袋图的逻辑以及指定着色的解决方法。您可以查看this gist以获取一个简单示例,该示例可以生成与此类似的图表: custom coloring of matplotlib 3D quiver

总结一下,以下是要遵循的步骤:

  1. 假设您有一个3元组(或RGBA的4元组)的列表(大小为x * y * z),指定要绘制的每个向量的RGB值(在0~1之间)。
  2. 过滤掉与长度为0的向量对应的RGB(或RGBA)元组,因为它们实际上不会被绘制。
  3. [color_1, color_2, ..., color_n]成为您在第2步之后获得的列表,您应该指定colors=[color_1, color_2, ..., color_n, color_1, color_1, color_2, color_2, ..., color_n, color_n],因为实际上是" - "所有非零箭头的部分(由1行组成)" - >"首先绘制,然后是">"部分(由2行组成)。
  4. 希望这有帮助。

答案 2 :(得分:0)

在@tacaswell和@sytrus答案的基础上,这是一个着色3d箭袋图的例子

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np

# Make the grid
x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.8))

# Make the direction data for the arrows
u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)
v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)
w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) *
     np.sin(np.pi * z))

# Color by azimuthal angle
c = np.arctan2(v, u)
# Flatten and normalize
c = (c.ravel() - c.min()) / c.ptp()
# Repeat for each body line and two head lines
c = np.concatenate((c, np.repeat(c, 2)))
# Colormap
c = plt.cm.hsv(c)

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.quiver(x, y, z, u, v, w, colors=c, length=0.1, normalize=True)
plt.show()

enter image description here

答案 3 :(得分:0)

扩展@ slek120的答案。我有一个问题,其中存在长度为零的向量。这些弄乱了箭头提示颜色之间的对应关系。我的解决方案是给它们一个非零的长度并使它们透明。由于某些我不了解的原因,仅仅丢弃它们是行不通的。在最后一部分上添加一个小的更改,还可以包括一个颜色栏。彩条明确要求q.set_array()。这会更改颜色,但是q.set_edgecolor(c); q.set_facecolor(c)允许您插入自定义颜色图。

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np

cmap = 'hsv'

# Make the grid
x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.2),
                      np.arange(-0.8, 1, 0.8))

# Make the direction data for the arrows
u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)
v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)
w = np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z)

# check what happens if all values are zero
# no quivers are plotted, colors don't match anymore
u[:,2:4] = v[:,2:4] = w[:,2:4] = 0
# change values that are zero to something close to zero
uvw = np.vstack((u[np.newaxis],v[np.newaxis],w[np.newaxis]))
norm = np.linalg.norm(uvw, axis = 0)
max_norm = np.max(norm)
mask = norm == 0
min_norm = 0.3  # you want every arrow to be longer than this fraction of max_norm
# rescale vs for illustrative purposes, so small vectors become visible
# and zero vectors become nonzero so colors of the arrow shaft and head correspond. Later these are made transparent
uvw = uvw + min_norm * np.tile(mask[np.newaxis], (3, 1, 1, 1)) / max_norm
# recalculate norms so you don't divide by zero
norm = np.linalg.norm(uvw, axis=0)
uvw = min_norm * uvw / norm + (1 - min_norm) * uvw / max_norm
u, v, w = uvw

# Color by azimuthal angle
c = np.arctan2(v, u)
# Flatten and normalize
c = (c.ravel() - c.min()) / c.ptp()
# Adjust for missing quivers
# c = c[np.nonzero((u.ravel() != 0) * (v.ravel() != 0) * (w.ravel() != 0))]
# Repeat for each body line and two head lines
c = np.concatenate((c, np.repeat(c, 2)))
repeated_mask = np.concatenate((mask.ravel(), np.repeat(mask.ravel(), 2)))
# Colormap
c = getattr(plt.cm, cmap)(c)
# set zero values transparent, you made them nonzero not to mess up the tip colors
c[repeated_mask, 3] = 0.1

fig = plt.figure()
ax = fig.gca(projection='3d')
q = ax.quiver(x, y, z, u, v, w, cmap = cmap, length=0.1)
q.set_array(np.linspace(0,max_norm,10))
fig.colorbar(q)
q.set_edgecolor(c)
q.set_facecolor(c)

plt.show()

Colored quivers with colorbar, zeros are made transparent.