matplotlib 中曲面图的奇怪边缘行为

Strange edge behaviour of surface plot in matplotlib

我想绘制一个函数的曲面图,该函数在参数 space 的某些值处是不连续的。正是在这些不连续点附近,绘图的颜色变得不正确,如下图所示。我该如何解决这个问题?

我的代码如下:

from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np

def phase(mu_a, mu_b, t, gamma):
    theta = 0.5*np.arctan2(2*gamma, mu_b-mu_a)
    epsilon = 2*gamma**2/np.sqrt((mu_a-mu_b)**2+4*gamma**2)
    y1 = np.arccos(0.5/t*(-mu_a*np.sin(theta)**2 -mu_b*np.cos(theta)**2 - epsilon))
    y2 = np.arccos(0.5/t*(-mu_a*np.cos(theta)**2 -mu_b*np.sin(theta)**2 + epsilon))
    return y1+y2

fig = plt.figure()
ax = fig.gca(projection='3d')

# Make data.
X = np.arange(-2.5, 2.5, 0.01)
Y = np.arange(-2.5, 2.5, 0.01)
X, Y = np.meshgrid(X, Y)
Z = phase(X, Y, 1, 0.6)

# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False)

surf.set_clim(1, 5)
fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

一个想法是将所有数组设为一维,过滤掉 NaN 值,然后调用 ax.plot_trisurf:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np

def phase(mu_a, mu_b, t, gamma):
    theta = 0.5 * np.arctan2(2 * gamma, mu_b - mu_a)
    epsilon = 2 * gamma ** 2 / np.sqrt((mu_a - mu_b) ** 2 + 4 * gamma ** 2)
    with np.errstate(divide='ignore', invalid='ignore'):
        y1 = np.arccos(0.5 / t * (-mu_a * np.sin(theta) ** 2 - mu_b * np.cos(theta) ** 2 - epsilon))
        y2 = np.arccos(0.5 / t * (-mu_a * np.cos(theta) ** 2 - mu_b * np.sin(theta) ** 2 + epsilon))
    return y1 + y2

fig = plt.figure()
ax = fig.add_subplot(projection='3d')

# Make data.
X = np.linspace(-2.5, 2.5, 200)
Y = np.linspace(-2.5, 2.5, 200)
X, Y = np.meshgrid(X, Y)
X = X.ravel() # make the array 1D
Y = Y.ravel()
Z = phase(X, Y, 1, 0.6)
mask = ~np.isnan(Z) # select the indices of the valid values

# Plot the surface.
surf = ax.plot_trisurf(X[mask], Y[mask], Z[mask], cmap=cm.coolwarm, linewidth=0, antialiased=False)

surf.set_clim(1, 5)
fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

一些备注:

  • plot_trisurf 将通过三角形加入 XY-values;这只有在域是凸的时才有效
  • 为了画得更快,可以使用更少的点(原来使用 500x500 点,这里的代码将其减少到 200x200
  • 调用 fig.gca(projection='3d') 已被弃用;相反,您可以调用 fig.add_subplot(projection='3d')
  • 可以暂时抑制除以零或使用超出范围的arccos的警告;这样,当这种情况不是预期的行为时,警告仍然可见