【问题标题】:set matplotlib 3d plot aspect ratio设置 matplotlib 3d 绘图纵横比
【发布时间】:2011-12-29 04:06:45
【问题描述】:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

设置纵横比适用于二维图:

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 case 有不同的语法,还是没有实现?

【问题讨论】:

标签: python matplotlib


【解决方案1】:

从 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)

【讨论】:

  • 这真的很有帮助,只是提到在 ax.set_box_aspect 行的末尾缺少一个右括号“)”..
  • 这是唯一对我有用的解决方案。其他人都没有。对于我的程序,我对其进行了修改以自动选择参数。 limits = np.array([getattr(self.ax, f'get_{axis}lim')() for axis in 'xyz']); ax.set_box_aspect(np.ptp(limits, axis = 1))
  • 可能使用xs[~np.isnan(xs)]等来避免nans。
【解决方案2】:

我没有尝试所有这些答案,但是这个 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)

【讨论】:

  • 我认为这是对 SO 提出的各种解决方案中最优雅的解决方案。
  • 更容易ax.auto_scale_xyz(*np.column_stack((centers - r, centers + r)))
  • 虽然这会将每个轴的限制设置为相同的值,但不幸的是,此解决方案不能修复不同的轴刻度。球体仍然显示为椭球体(至少在默认的 MacOSX 后端上)。
【解决方案3】:

看起来这个功能已经被添加了,所以我想我会像我一样为将来来这个帖子的人添加一个答案:

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 增加了图形的大小。标签等不会增加,因此这是一种使图表看起来不那么被标签混乱的方法。

【讨论】:

  • 您使用哪个版本?我正在使用 1.3.1,但它不起作用。
  • 这不会设置实际绘图的纵横比。只是封闭的数字。
  • 这是唯一适合我在 Windows 上正常工作的解决方案。
  • @PrasadRaghavendra 您使用了哪些版本的 python 和 matplotlib?最好知道这何时有效。另外,您能否验证一下 Jacob Jones 上面所说的内容?
  • Python 3.7.6(默认,2020 年 1 月 8 日,20:23:39)[MSC v.1916 64 位(AMD64)] :: Ana conda, Inc. on win32 键入“帮助”, “版权”、“学分”或“许可”以获取更多信息。 >>> 导入 matplotlib >>> matplotlib.__version__ '3.1.2'
【解决方案4】:

如果您知道界限,例如。 +-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')

【讨论】:

  • 这是一个很好的技巧,直到 matplotlib 支持方面锁定。为我工作。
  • 好主意 - 为我工作。只是我的意见,但这似乎不是纵横比问题,这是一个边界框问题。有什么方法可以简单地设置范围吗?
【解决方案5】:

如果你知道边界,你也可以这样设置纵横比:

ax.auto_scale_xyz([minbound, maxbound], [minbound, maxbound], [minbound, maxbound])

【讨论】:

  • 或者,自动执行:scaling = np.array([getattr(ax, 'get_{}lim'.format(dim))() for dim in 'xyz']); ax.auto_scale_xyz(*[[np.min(scaling), np.max(scaling)]]*3)
  • @sebix 这真的很有帮助。这应该是答案
【解决方案6】:

我认为设置正确的“盒子方面”是一个很好的解决方案:

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)

https://matplotlib.org/stable/api/_as_gen/mpl_toolkits.mplot3d.axes3d.Axes3D.html?highlight=3d%20set_box_aspect#mpl_toolkits.mplot3d.axes3d.Axes3D.set_box_aspect

【讨论】:

  • 这个答案是错误的。 set_box_aspect 只是改变 x,y,z 轴的长度在显示中。它不会改变轴的比例。 OP 正在询问如何将所有三个轴设置为具有相同的比例在数据空间中,就像set_aspect('equal') 在二维图中的工作方式一样。
【解决方案7】:

我的理解基本上是这还没有实现(见this bug in GitHub)。我也希望它尽快实施。请参阅This link 了解可能的解决方案(我自己没有测试过)。

【讨论】:

  • 链接已损坏,但可以通过Wayback Machine 检索。但是,最好在答案中包含相关代码,而不是要求未来的人搜索邮件列表存档。
【解决方案8】:

另一个有用的(希望是)解决方案,例如,当需要更新已经存在的图形时:

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]))

get_w_lims()

set_box_aspect()

【讨论】:

  • 它适用于 matplotlib 3.4.3。谢谢
【解决方案9】:

我尝试了几种方法,例如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))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-06
    • 1970-01-01
    • 2021-10-29
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    相关资源
    最近更新 更多