在Matplotlib中归一化颜色

6

我正在尝试使用以下代码在matplotlib中绘制表面:

from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p

vima=0.5

fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)

Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))

surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, alpha=1,cmap=cm.jet,  linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

如果您运行它,您将看到一个蓝色的表面,但我想使用jet的整个颜色范围... 我知道有一个类“matplotlib.colors.Normalize”,但我不知道如何使用它。您能否添加必要的代码以实现此目的?


当我按原样运行此代码时,我没有得到蓝色表面。你使用的matplotlib版本是什么? - Paul
我正在使用1.0.1版本。 - Stelios
5
在我删除由于除以零而导致 Z 中的 NaN 值后,看起来对我来说很好。 - JoshAdel
我不明白接下来发生了什么...... 我知道matplotlib的版本之间存在差异,但如果你在1.0.1版本中运行它并且没有问题,那么这不仅是我的问题。 - Stelios
1
似乎就是这样,Josh。在具有NaN的数组的颜色映射缩放中似乎存在一个错误。您应该发布“nan_to_num”或您用于解决NaN的任何内容作为解决方法。 - Paul
你可以使用掩码数组来忽略NaN值:http://docs.scipy.org/doc/numpy/reference/maskedarray.html - arboc7
3个回答

18

我意识到发布者的问题已经得到解决,但是对于颜色规范化的问题从未得到解决。由于我已经理清了思路,我在这里为任何需要的人提供一下解决方案。

首先,创建一个norm并将其传递给绘图函数,我尝试将此添加到发布者的代码中。

from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p
import matplotlib

vima=0.5

fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)

Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))
Z = np.nan_to_num(Z)

# Make the norm
norm = matplotlib.colors.Normalize(vmin = np.min(Z), vmax = np.max(Z), clip = False)

# Plot with the norm
surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, norm=norm, alpha=1,cmap=cm.jet,     linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

"imshow"命令的规则与此相同。


Normalize() 在这里是不必要的,而且会产生不想要的结果。正确答案确实是 Paul 所接受的答案。 - divenex

5

正如JoshAdel在评论中指出的(应归功于他),当Z数组中存在NaN时,表面绘图似乎未正确设置颜色映射范围。一个简单的解决方法是将NaN转换为零或非常大或非常小的数字,以便可以将颜色映射归一化到z轴范围。

from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p

vima=0.5

fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)

Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))
Z = np.nan_to_num(Z) # added this line

surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, alpha=1,cmap=cm.jet,  linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

2
感谢您的归属。只需记得在其他时间为我点赞 :-) - JoshAdel
非常感谢Peter和Josh的帮助。我已将其标记为正确答案,但我更喜欢将“X = np.arange(0,16.67,vima)”改为“X = np.arange(0.000001,16.67,vima)”,而不是添加“Z = np.nan_to_num(Z)”。这样,Z中就不会有任何NaN值……您可以尝试一下,在(X,Y)=(0,0)附近看到差异。 - Stelios
然而,这会禁用使用 nan 来隐藏(而不是绘制)数据的一部分。那么怎样才能仍然使用 nan 来隐藏某些点,同时具有适当的颜色规范化呢?也许可以使用自定义 Normalize?请参见 https://dev59.com/iZXfa4cB1Zd3GeqPcD1j - Hanan Shteingart

4

回答一个老问题,我知道,但是在我的情况下,发布的答案有些令人不满意。对于那些仍然在这里摸索的人,我给出了一个对我有效的解决方案。

首先,我不想使用零来替换NaN,因为对我来说它们代表着具有缺失或未定义数据的点。我宁愿在这些点上没有任何绘图。其次,我的整个数据的z范围远高于零,所以用零点缀绘图会导致一个丑陋和缩放不良的绘图。

leifdenby提供的解决方案非常接近,所以+1(尽管如指出的,显式规范化并没有增加早期的解决方案)。我只是放弃了NaN-to-zero替换,并在颜色比例尺规范化中使用了函数nanmin和nanmax,而不是min和max。这些函数给出数组的最小值和最大值,但是简单地忽略所有NaN。现在的代码如下:

# Added colors to the matplotlib import list
from matplotlib import cm, colors
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import axes3d, Axes3D
import pylab as p


vima=0.5

fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 16.67, vima)
Y = np.arange(0, 12.5, vima)
X, Y = np.meshgrid(X, Y)

Z = np.sqrt(((1.2*Y+0.6*X)**2+(0.2*Y+1.6*X)**2)/(0.64*Y**2+0.36*X**2))

# MAIN IDEA: Added normalisation using nanmin and nanmax functions
norm = colors.Normalize(vmin = np.nanmin(Z), 
                        vmax = np.nanmax(Z))

# Added the norm=norm parameter
surf = ax.plot_surface(X, Y, Z,rstride=1, cstride=1, alpha=1, norm=norm, cmap=cm.jet,  linewidth=0)
fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

运行此代码,我得到了一个正确缩放的图表,但是(0,0)数据点被省略了。这也是我认为最好的行为方式,因为所讨论的函数在(x,y)趋近于(0,0)时并不存在极限值。
这是我在StackOverflow上的第一次贡献,希望它是一个好的开始(眨眼)。

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