[英]set matplotlib 3d plot aspect ratio
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
设置纵横比适用于 2d 图:
ax = plt.axes()
ax.plot([0,1],[0,10])
ax.set_aspect('equal','box')
但不适用于 3d:
ax = plt.axes(projection='3d')
ax.plot([0,1],[0,1],[0,10])
ax.set_aspect('equal','box')
3d 案例是否有不同的语法,或者它没有实现?
从 matplotlib 3.3.0 开始, Axes3D.set_box_aspect似乎是推荐的方法。
import numpy as np
import matplotlib.pyplot as plt
xs, ys, zs = ...
ax = plt.axes(projection='3d')
ax.set_box_aspect((np.ptp(xs), np.ptp(ys), np.ptp(zs))) # aspect ratio is 1:1:1 in data space
ax.plot(xs, ys, zs)
我没有尝试所有这些答案,但是这个 kludge 为我做到了:
def axisEqual3D(ax):
extents = np.array([getattr(ax, 'get_{}lim'.format(dim))() for dim in 'xyz'])
sz = extents[:,1] - extents[:,0]
centers = np.mean(extents, axis=1)
maxsize = max(abs(sz))
r = maxsize/2
for ctr, dim in zip(centers, 'xyz'):
getattr(ax, 'set_{}lim'.format(dim))(ctr - r, ctr + r)
看起来这个功能已经被添加了,所以我想我会像我一样为将来通过这个线程的人添加一个答案:
fig = plt.figure(figsize=plt.figaspect(0.5)*1.5) #Adjusts the aspect ratio and enlarges the figure (text does not enlarge)
ax = fig.add_subplot(projection='3d')
figaspect(0.5)
使图形宽是高的两倍。 然后*1.5
增加了图形的大小。 标签等不会增加,因此这是一种使图表看起来不那么被标签混乱的方法。
如果你知道界限,例如。 +-3 以 (0,0,0) 为中心,您可以像这样添加不可见点:
import numpy as np
import pylab as pl
from mpl_toolkits.mplot3d import Axes3D
fig = pl.figure()
ax = fig.add_subplot(projection='3d')
ax.set_aspect('equal')
MAX = 3
for direction in (-1, 1):
for point in np.diag(direction * MAX * np.array([1,1,1])):
ax.plot([point[0]], [point[1]], [point[2]], 'w')
我认为设置正确的“盒子方面”是一个很好的解决方案:
ax.set_box_aspect(aspect = (1,1,1))
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.set_box_aspect(aspect = (1,1,1))
ax.plot(dataX,dataY,dataZ)
如果您知道边界,您还可以通过以下方式设置纵横比:
ax.auto_scale_xyz([minbound, maxbound], [minbound, maxbound], [minbound, maxbound])
另一个有用的(希望是)解决方案,例如,当需要更新已经存在的图形时:
world_limits = ax.get_w_lims()
ax.set_box_aspect((world_limits[1]-world_limits[0],world_limits[3]-world_limits[2],world_limits[5]-world_limits[4]))
我的理解基本上是这还没有实现(参见GitHub 中的这个错误)。 我也希望它尽快实施。 有关可能的解决方案,请参阅此链接(我自己没有测试过)。
Matt Panzer 回答的后续行动。
limits = np.array([getattr(ax, f'get_{axis}lim')() for axis in 'xyz'])
ax.set_box_aspect(np.ptp(limits, axis=1))
这可能很快就会变得不必要,因为正在进行拉取请求以使ax.set_aspect('equal')
工作。
Matt Panzer 的回答对我有用,但我花了一段时间才弄清楚我遇到的问题。 如果您将多个数据集绘制到同一张图中,则必须计算整个数据点范围的峰峰值。
我使用以下代码来解决我的问题:
x1, y1, z1 = ..., ..., ...
x2, y2, z2 = ..., ..., ...
ax.set_box_aspect((
max(np.ptp(x1), np.ptp(x2)),
max(np.ptp(y1), np.ptp(y2)),
max(np.ptp(z1), np.ptp(y2))
))
ax.plot(x1, y1, z1)
ax.scatter(x2, y2, z2)
请注意,此解决方案并不完美。 如果 x1 包含最大的负数而 x2 包含最大的正数,它将不起作用。 仅当 x1 或 x2 包含最大峰峰值范围时。
如果您比我更了解 numpy,请随时编辑此答案,使其适用于更一般的情况。
我尝试了几种方法,例如ax.set_box_aspect(aspect = (1,1,1))
并不起作用。 我希望一个球体显示为一个球体——而不是椭球体。 我编写了这个函数并在各种数据上进行了尝试。 这是一个 hack,它并不完美,但非常接近。
def set_aspect_equal(ax):
"""
Fix the 3D graph to have similar scale on all the axes.
Call this after you do all the plot3D, but before show
"""
X = ax.get_xlim3d()
Y = ax.get_ylim3d()
Z = ax.get_zlim3d()
a = [X[1]-X[0],Y[1]-Y[0],Z[1]-Z[0]]
b = np.amax(a)
ax.set_xlim3d(X[0]-(b-a[0])/2,X[1]+(b-a[0])/2)
ax.set_ylim3d(Y[0]-(b-a[1])/2,Y[1]+(b-a[1])/2)
ax.set_zlim3d(Z[0]-(b-a[2])/2,Z[1]+(b-a[2])/2)
ax.set_box_aspect(aspect = (1,1,1))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.