python - legends - Parcela 3D con Matplotlib
matplotlib text box (1)
Simplemente estoy tratando de trazar una superficie y su contorno en 3D, exactamente como en this ejemplo.
Este es el código que estoy usando para hacerlo:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm
import numpy
def plot_3d_contour(x_dim, y_dim, x_steps, y_steps, scalar_field, file_path):
fig = plt.figure()
x, y = numpy.mgrid[-x_dim/2:x_dim/2:x_steps*1j, -y_dim/2:y_dim/2:y_steps*1j]
v_min = numpy.min(scalar_field)
v_max = nupmy.max(scalar_field)
ax = fig.gca(projection=''3d'')
cset = ax.contourf(x, y, scalar_field, zdir=''z'', offset=v_min, cmap=cm.coolwarm)
cset = ax.contourf(x, y, scalar_field, zdir=''x'', offset=-x_dim/2-1, cmap=cm.coolwarm)
cset = ax.contourf(x, y, scalar_field, zdir=''y'', offset=y_dim/2+1, cmap=cm.coolwarm)
ax.plot_surface(x, y, scalar_field, rstride=10, cstride=10, alpha=0.3)
ax.set_xlabel(''X'')
ax.set_xlim(-x_dim/2-1, x_dim/2+1)
ax.set_ylabel(''Y'')
ax.set_ylim(-y_dim/2-1, y_dim/2+1)
ax.set_zlabel(''Z'')
ax.set_zlim(v_min, v_max)
plt.savefig(file_path + ''.jpg'')
plt.close()
scalar_field = numpy.loadtxt(''../scalar_field'', delimiter=",")
plot_3d_contour(12, 12, 100, 100, scalar_field, ''scalar_field3D'')
Sin embargo, estoy zdir=y
un comportamiento extraño en el que el contorno a ( zdir=y
) está sobre la superficie. Además, z_dir=z
un contorno extraño en z_dir=z
(con una sección que falta):
Me pregunto qué me falta. El campo escalar se puede encontrar here .
Estoy de acuerdo con Ajean. Creo que el problema surge porque cada artista de matplotlib (es decir, PolygonCollection
) se procesa por separado. No hay manera de que diferentes caras del mismo objeto sean renderizadas en diferentes lados de otro objeto en la escena.
Aquí hay una pieza de código útil:
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)
que da la siguiente imagen:
Las primeras dos filas son producidas por un código similar al tuyo. Puede notar que establecer la elevación con view_init
en un valor más alto resuelve el problema. Pero no es satisfactorio. También he determinado la influencia del rango de los valores z (que no se muestra aquí), el error parece aparecer solo cuando este rango es pequeño (se puede usar el parámetro f
para probarlo) que explica por qué el this no sufre de eso.
La solución que propongo es reemplazar:
ax.contourf(x, y, scalar_field, zdir=''y'', offset=y_dim/2+1, cmap=cm.coolwarm)
por:
ax.contourf(x, y, scalar_field, zdir=''y'', offset=-y_dim/2-1, cmap=cm.coolwarm)
en su código y agregue esta línea adicional:
ax.view_init(azim=60, elev=30)
Como se muestra en las dos últimas filas de la imagen anterior, de esta manera podrás evitar los caprichos de matplotlib.