python - mpl_toolkits - Establecer la relación de aspecto de la trama 3D
plot_wireframe python (3)
Agregue el siguiente código antes de guardar:
ax.auto_scale_xyz([0, 500], [0, 500], [0, 0.15])
Si no quieres un eje cuadrado:
edite la función get_proj
dentro de site-packages / mpl_toolkits / mplot3d / axes3d.py:
xmin, xmax = np.divide(self.get_xlim3d(), self.pbaspect[0])
ymin, ymax = np.divide(self.get_ylim3d(), self.pbaspect[1])
zmin, zmax = np.divide(self.get_zlim3d(), self.pbaspect[2])
luego agrega una línea para establecer pbaspect:
ax = fig.gca(projection = ''3d'')
ax.pbaspect = [2.0, 0.6, 0.25]
Intento trazar una imagen en 3D del lecho marino a partir de los datos de un sonar que recorre una porción de 500m por 40m del fondo marino. Estoy usando matplotlib / mplot3d con Axes3D y quiero poder cambiar la relación de aspecto de los ejes para que los ejes xey estén a escala. Un script de ejemplo con datos generados en lugar de los datos reales es:
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# Create figure.
fig = plt.figure()
ax = fig.gca(projection = ''3d'')
# Generate example data.
R, Y = np.meshgrid(np.arange(0, 500, 0.5), np.arange(0, 40, 0.5))
z = 0.1 * np.abs(np.sin(R/40) * np.sin(Y/6))
# Plot the data.
surf = ax.plot_surface(R, Y, z, cmap=cm.jet, linewidth=0)
fig.colorbar(surf)
# Set viewpoint.
ax.azim = -160
ax.elev = 30
# Label axes.
ax.set_xlabel(''Along track (m)'')
ax.set_ylabel(''Range (m)'')
ax.set_zlabel(''Height (m)'')
# Save image.
fig.savefig(''data.png'')
Y la imagen de salida de este script:
Ahora me gustaría cambiarlo de modo que 1 metro en el eje de la trayectoria (x) sea igual a 1 metro en el eje del rango (y) (o tal vez una relación diferente dependiendo de los tamaños relativos involucrados). También me gustaría establecer la relación del eje z, de nuevo innecesariamente a 1: 1 debido a los tamaños relativos en los datos, pero el eje es más pequeño que el gráfico actual.
Intenté construir y usar esta rama de matplotlib , siguiendo el script de ejemplo en este mensaje de la lista de correo , pero agregando la línea ax.pbaspect = [1.0, 1.0, 0.25]
a mi script (habiendo desinstalado la versión ''estándar'' de matplotlib para garantizar que se utilizara la versión personalizada) no hizo ninguna diferencia en la imagen generada.
Editar: De modo que la salida deseada sería algo así como la siguiente imagen (crudamente editada con Inkscape). En este caso, no he establecido una relación 1: 1 en los ejes x / y porque parece ridículamente delgada, pero la he extendido para que no esté cuadrada como en la salida original.
Así cómo resolví el problema del espacio desperdiciado:
try:
self.localPbAspect=self.pbaspect
zoom_out = (self.localPbAspect[0]+self.localPbAspect[1]+self.localPbAspect[2])
except AttributeError:
self.localPbAspect=[1,1,1]
zoom_out = 0
xmin, xmax = self.get_xlim3d() / self.localPbAspect[0]
ymin, ymax = self.get_ylim3d() / self.localPbAspect[1]
zmin, zmax = self.get_zlim3d() / self.localPbAspect[2]
# transform to uniform world coordinates 0-1.0,0-1.0,0-1.0
worldM = proj3d.world_transformation(xmin, xmax,
ymin, ymax,
zmin, zmax)
# look into the middle of the new coordinates
R = np.array([0.5*self.localPbAspect[0], 0.5*self.localPbAspect[1], 0.5*self.localPbAspect[2]])
xp = R[0] + np.cos(razim) * np.cos(relev) * (self.dist+zoom_out)
yp = R[1] + np.sin(razim) * np.cos(relev) * (self.dist+zoom_out)
zp = R[2] + np.sin(relev) * (self.dist+zoom_out)
E = np.array((xp, yp, zp))
La respuesta a esta pregunta funciona perfectamente para mí. Y no necesita configurar ninguna proporción, hace todo automáticamente.