Ответ 1
Я согласен с Ajean. Я считаю, что проблема возникает из-за того, что каждый художник matplotlib (т.е. PolygonCollection
) визуализируется отдельно. Нет разных сторон от одного и того же объекта, которые будут отображаться по разные стороны другого объекта в сцене.
Вот полезный фрагмент кода:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
file_path = "./3D_surface_and_contour.jpg"
p = 0.05
f = -0.01
def get_data(p):
x, y, z = axes3d.get_test_data(p)
z = f * z
return x, y, z
def plot_3d_contour(p, f):
nrows = 4
ncols = 5
x, y, z = get_data(p)
x_min, x_max = np.min(x), np.max(x)
y_min, y_max = np.min(y), np.max(y)
z_min, z_max = np.min(z), np.max(z)
fig = plt.figure(figsize=(15, 10))
for n in range(nrows * ncols):
i = n % ncols
j = n / ncols
k = n + 1
if j == 0:
azim = -60 + (i - 2) * 15
elev = 30
elif j == 1:
azim = -60
elev = 30 + (i - 2) * 5
elif j == 2:
azim = 60 + (i - 2) * 10
elev = 30
elif j == 3:
azim = 60
elev = 30 + (i - 2) * 5
ax = fig.add_subplot(nrows, ncols, k, projection='3d')
ax.set_title("azim=" + str(azim) + " elev=" + str(elev))
ax.tick_params(labelsize=8)
ax.view_init(azim=azim, elev=elev)
ax.plot_surface(x, y, z, rstride=10, cstride=10, alpha=0.3)
ax.contourf(x, y, z, zdir='z', offset=z_min, cmap=cm.coolwarm)
ax.contourf(x, y, z, zdir='x', offset=x_min, cmap=cm.coolwarm)
if j == 0 or j == 1:
ax.contourf(x, y, z, zdir='y', offset=y_max, cmap=cm.coolwarm)
elif j == 2 or j == 3:
ax.contourf(x, y, z, zdir='y', offset=y_min, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(x_min, x_max)
ax.set_ylabel('Y')
ax.set_ylim(y_min, y_max)
ax.set_zlabel('Z')
ax.set_zlim(z_min, z_max)
plt.savefig(file_path, dpi=80)
plt.close()
plot_3d_contour(p, f)
который дает следующее изображение:
Первые две строки создаются кодом, похожим на ваш. Вы можете заметить, что установка высоты с помощью view_init
на большее значение решает проблему. Но это неудовлетворительно. Я также определил влияние диапазона значений z (не показано здесь), ошибка появляется только тогда, когда этот диапазон мал (вы можете использовать параметр f
для его проверки), которые объясняют, почему example не страдает от этого.
Решение, которое я предлагаю, заключается в замене:
ax.contourf(x, y, scalar_field, zdir='y', offset=y_dim/2+1, cmap=cm.coolwarm)
:
ax.contourf(x, y, scalar_field, zdir='y', offset=-y_dim/2-1, cmap=cm.coolwarm)
в вашем коде и добавьте дополнительную строку:
ax.view_init(azim=60, elev=30)
Как показано в последних двух строках предыдущего изображения, таким образом вы сможете избежать прихотей matplotlib.