python - matrices - matplotlib.pyplot install
matplotlib(longitud de unidad igual): con relaciĆ³n de aspecto ''igual'' eje z no es igual a x- y y- (5)
Cuando configuro una relación de aspecto igual para un gráfico en 3D, el eje z no cambia a ''igual''. Así que esto:
fig = pylab.figure()
mesFig = fig.gca(projection=''3d'', adjustable=''box'')
mesFig.axis(''equal'')
mesFig.plot(xC, yC, zC, ''r.'')
mesFig.plot(xO, yO, zO, ''b.'')
pyplot.show()
me da lo siguiente:
donde obviamente la longitud de la unidad del eje z no es igual a las unidades x e y.
¿Cómo puedo hacer que la longitud de la unidad de los tres ejes sea igual? Todas las soluciones que pude encontrar no funcionaron. Gracias.
Adaptado de @ karlo''s answer para hacer las cosas aún más limpias:
def set_axes_radius(ax, origin, radius):
ax.set_xlim3d([origin[0] - radius, origin[0] + radius])
ax.set_ylim3d([origin[1] - radius, origin[1] + radius])
ax.set_zlim3d([origin[2] - radius, origin[2] + radius])
def set_axes_equal(ax):
''''''Make axes of 3D plot have equal scale so that spheres appear as spheres,
cubes as cubes, etc.. This is one possible solution to Matplotlib''s
ax.set_aspect(''equal'') and ax.axis(''equal'') not working for 3D.
Input
ax: a matplotlib axis, e.g., as output from plt.gca().
''''''
limits = np.array([
ax.get_xlim3d(),
ax.get_ylim3d(),
ax.get_zlim3d(),
])
origin = np.mean(limits, axis=1)
radius = 0.5 * np.max(np.abs(limits[:, 1] - limits[:, 0]))
set_axes_radius(ax, origin, radius)
Uso:
fig = plt.figure()
ax = fig.gca(projection=''3d'')
ax.set_aspect(''equal'') # important!
# ...draw here...
set_axes_equal(ax) # important!
plt.show()
Creo que matplotlib aún no establece correctamente el eje equidistante en 3D ... Pero hace un tiempo encontré un truco (no recuerdo dónde) que he adaptado para usarlo. El concepto es crear un cuadro de límite cúbico falso alrededor de sus datos. Puedes probarlo con el siguiente código:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection=''3d'')
ax.set_aspect(''equal'')
X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25
scat = ax.scatter(X, Y, Z)
# Create cubic bounding box to simulate equal aspect ratio
max_range = np.array([X.max()-X.min(), Y.max()-Y.min(), Z.max()-Z.min()]).max()
Xb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][0].flatten() + 0.5*(X.max()+X.min())
Yb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][1].flatten() + 0.5*(Y.max()+Y.min())
Zb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][2].flatten() + 0.5*(Z.max()+Z.min())
# Comment or uncomment following both lines to test the fake bounding box:
for xb, yb, zb in zip(Xb, Yb, Zb):
ax.plot([xb], [yb], [zb], ''w'')
plt.grid()
plt.show()
z los datos son de un orden de magnitud mayor que xey, pero incluso con la opción de eje igual, matplotlib autoscale z axis:
Pero si agrega el cuadro delimitador, obtiene una escala correcta:
Me gustan las soluciones anteriores, pero tienen el inconveniente de que necesita realizar un seguimiento de los rangos y significa más que todos sus datos. Esto podría ser engorroso si tiene múltiples conjuntos de datos que se trazarán juntos. Para solucionarlo, utilicé los métodos ax.get_ [xyz] lim3d () y puse todo en una función independiente que se puede llamar solo una vez antes de llamar a plt.show (). Aquí está la nueva versión:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
def set_axes_equal(ax):
''''''Make axes of 3D plot have equal scale so that spheres appear as spheres,
cubes as cubes, etc.. This is one possible solution to Matplotlib''s
ax.set_aspect(''equal'') and ax.axis(''equal'') not working for 3D.
Input
ax: a matplotlib axis, e.g., as output from plt.gca().
''''''
x_limits = ax.get_xlim3d()
y_limits = ax.get_ylim3d()
z_limits = ax.get_zlim3d()
x_range = abs(x_limits[1] - x_limits[0])
x_middle = np.mean(x_limits)
y_range = abs(y_limits[1] - y_limits[0])
y_middle = np.mean(y_limits)
z_range = abs(z_limits[1] - z_limits[0])
z_middle = np.mean(z_limits)
# The plot bounding box is a sphere in the sense of the infinity
# norm, hence I call half the max range the plot radius.
plot_radius = 0.5*max([x_range, y_range, z_range])
ax.set_xlim3d([x_middle - plot_radius, x_middle + plot_radius])
ax.set_ylim3d([y_middle - plot_radius, y_middle + plot_radius])
ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])
fig = plt.figure()
ax = fig.gca(projection=''3d'')
ax.set_aspect(''equal'')
X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25
scat = ax.scatter(X, Y, Z)
set_axes_equal(ax)
plt.show()
Simplifiqué la solución de Remy F usando las set_x/y/zlim
.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection=''3d'')
ax.set_aspect(''equal'')
X = np.random.rand(100)*10+5
Y = np.random.rand(100)*5+2.5
Z = np.random.rand(100)*50+25
scat = ax.scatter(X, Y, Z)
max_range = np.array([X.max()-X.min(), Y.max()-Y.min(), Z.max()-Z.min()]).max() / 2.0
mid_x = (X.max()+X.min()) * 0.5
mid_y = (Y.max()+Y.min()) * 0.5
mid_z = (Z.max()+Z.min()) * 0.5
ax.set_xlim(mid_x - max_range, mid_x + max_range)
ax.set_ylim(mid_y - max_range, mid_y + max_range)
ax.set_zlim(mid_z - max_range, mid_z + max_range)
plt.show()
EDITAR: el código del usuario2525140 debería funcionar perfectamente bien, aunque supuestamente esta respuesta intentó corregir un error inexistente. La respuesta a continuación es solo una implementación duplicada (alternativa):
def set_aspect_equal_3d(ax):
"""Fix equal aspect bug for 3D plots."""
xlim = ax.get_xlim3d()
ylim = ax.get_ylim3d()
zlim = ax.get_zlim3d()
from numpy import mean
xmean = mean(xlim)
ymean = mean(ylim)
zmean = mean(zlim)
plot_radius = max([abs(lim - mean_)
for lims, mean_ in ((xlim, xmean),
(ylim, ymean),
(zlim, zmean))
for lim in lims])
ax.set_xlim3d([xmean - plot_radius, xmean + plot_radius])
ax.set_ylim3d([ymean - plot_radius, ymean + plot_radius])
ax.set_zlim3d([zmean - plot_radius, zmean + plot_radius])