如何实现Matplotlib 3D绘图的坐标轴等比例显示
First, let's spot a critical issue in your code: your zlim setting doesn't match your data. Looking at your vertices, the z-values range from ~1681 up to 22508, but you've set ax.set_zlim(1000., 2500.)—this truncates most of your triangle, which is already contributing to the distorted appearance. Let's fix that first, then address the equal scaling problem.
Matplotlib's 3D axes don't support plt.axis('equal') (as you've seen from the error), but there are reliable workarounds:
Method 1: Use set_box_aspect() (Matplotlib 3.3+)
This is the simplest approach for newer Matplotlib versions. You calculate the range of each axis, then set the box aspect ratio to match those ranges (so each unit of length is visually consistent across axes).
Here's your corrected code with this method:
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection vertices = np.array([ [ 2.5800e+06, 1.1090e+06, 1.6817e+03], [ 2.5300e+06, 1.1370e+06, 1.0996e+04], [ 2.5300e+06, 1.1350e+06, 2.2508e+04]]) fig = plt.figure(figsize=(4,4)) ax = fig.add_subplot(111, projection='3d') # Calculate axis ranges from your data x_range = np.max(vertices[:,0]) - np.min(vertices[:,0]) y_range = np.max(vertices[:,1]) - np.min(vertices[:,1]) z_range = np.max(vertices[:,2]) - np.min(vertices[:,2]) # Set equal aspect ratio based on actual data ranges ax.set_box_aspect([x_range, y_range, z_range]) # Set axis limits to fully contain your data (fixed the zlim issue) ax.set_xlim(np.min(vertices[:,0]), np.max(vertices[:,0])) ax.set_ylim(np.min(vertices[:,1]), np.max(vertices[:,1])) ax.set_zlim(np.min(vertices[:,2]), np.max(vertices[:,2])) # Add the triangle once (no need for a loop here) ax.add_collection3d(Poly3DCollection([vertices], facecolor='lightblue', edgecolor='black')) plt.show()
Method 2: Manual Aspect Adjustment (Older Matplotlib Versions)
If you're using a version before 3.3, you can manually adjust the axis scaling by normalizing all axes to the largest range in your data:
# After setting your initial axis limits x_lim = ax.get_xlim() y_lim = ax.get_ylim() z_lim = ax.get_zlim() x_range = x_lim[1] - x_lim[0] y_range = y_lim[1] - y_lim[0] z_range = z_lim[1] - z_lim[0] # Find the maximum range to normalize against max_range = np.max([x_range, y_range, z_range]) # Adjust each axis to span the same total length for consistent scaling ax.set_xlim(x_lim[0], x_lim[0] + max_range) ax.set_ylim(y_lim[0], y_lim[0] + max_range) ax.set_zlim(z_lim[0], z_lim[0] + max_range)
This forces all axes to have the same visual span, making units of length look equal across x, y, and z.
A quick side note: your original loop adding the same Poly3DCollection four times is unnecessary—adding it once is enough to display the triangle correctly.
内容的提问来源于stack exchange,提问作者swiss_knight

