【问题标题】:get aspect ratio of axes获取轴的纵横比
【发布时间】:2017-01-11 17:32:29
【问题描述】:

axes 的纵横比设置为'auto' 时,是否有一种简单可靠的方法来确定其当前纵横比?

很明显要检查的是ax.get_aspect(),但它只返回'auto'。我可以通过ax.set_aspect(aspect) 将其设置为任意常量值,之后ax.get_aspect() 返回相同的常量。默认情况下(并且非常有用)我们有 aspect = 'auto',在这种情况下,纵横比会自动计算并调整以匹配数据限制和轴大小。
如何获得自动生成的数字纵横比选择了吗?

澄清一下,这既不是ax.get_data_ratio()返回的数据限制的纵横比,也不是返回的图形或子图显示大小的纵横比由fig.get_figheight() / fig.get_figwidth()(如图)。这有点微妙,因为它取决于显示大小和数据限制。 (这可能会导致混淆不同的比率以及我认为易于访问它很重要的原因。)

【问题讨论】:

  • 你指的是什么纵横比?数据还是显示?
  • 根据您对@Frank 回答的评论,我猜想显示或更复杂的东西。
  • 不幸的是,这是“更复杂的东西”,@MadPhysicist。请参阅我编辑的问题。
  • 我几乎得到了你的答案。等一下。
  • 对不起,昨天我太累了,没有意识到我的解决方案只适用于 aspect='equal',但您要求的是其他情况。由于似乎没有一个简单的方法来获得这个,我请求了这个功能:github.com/matplotlib/matplotlib/issues/8013

标签: python matplotlib


【解决方案1】:

docs 开始,纵横比是 x 轴和 y 轴中数据与显示缩放单位的比率。即,如果在 y 方向上每个显示单元有 10 个数据单元,在 x 方向上每个显示单元有 1 个数据单元,则比率将为 1/10。圆的宽度是它的高度的 10 倍。这对应于num 的一个方面执行以下操作的声明:

一个圆将被拉伸,使得高度是宽度的 num 倍。 aspect=1 与 aspect='equal' 相同。

基于您查看的同一段原始代码 (matplotlib.axes._base.adjust_aspect, starting around line 1405),我认为我们可以提出一个简化的公式,只要您只需要线性笛卡尔轴的这个比率即可。极轴和对数轴会使事情变得复杂,所以我将忽略它们。

重申公式:

(x_data_unit / x_display_unit) / (y_data_unit / y_display_unit)

这恰好和

一样
(y_display_unit / x_display_unit) / (y_data_unit / x_data_unit)

最后一个公式只是两个方向上显示尺寸的比率除以 x 和 y 限制的比率。请注意,ax.get_data_ratio NOT 在这里适用,因为它返回的是实际数据边界的结果,而不是轴限制:

from operator import sub
def get_aspect(ax):
    # Total figure size
    figW, figH = ax.get_figure().get_size_inches()
    # Axis size on figure
    _, _, w, h = ax.get_position().bounds
    # Ratio of display units
    disp_ratio = (figH * h) / (figW * w)
    # Ratio of data units
    # Negative over negative because of the order of subtraction
    data_ratio = sub(*ax.get_ylim()) / sub(*ax.get_xlim())

    return disp_ratio / data_ratio

现在让我们测试一下:

from matplotlib import pyplot as plt
fig, ax = plt.subplots()
ax.set_aspect('equal')
print('{} == {}'.format(ax.get_aspect(), get_aspect(ax)))
ax.set_aspect(10)
print('{} == {}'.format(ax.get_aspect(), get_aspect(ax)))

【讨论】:

  • 这行得通。我很惊讶没有更简单的方法可以做到这一点。我想知道为什么matplotlib 不提供get_aspect 功能。
  • @Pygmalion。这是一个非常小众的应用程序。
  • @MadPhysicist 每次画圆时都需要该值。我不知道是不是那个利基市场。
  • @Guimute。这是获得纵横比。你只需要set_aspect('equal') 画一个圆圈。所以我想说我的评论相当不错。
  • 是的,但set_aspect("equal") 不是通用解决方案。在许多情况下,您可能希望在现有画布中以给定且恒定的纵横比处理圆圈。例如,我在这里偶然发现,因为我正在编写一个函数来获取离光标最近的数据点,当然我没有预料到 sqrt(dx² + dy²) 不是可接受的距离定义,因为数据限制和数字不断变化比率。我正在查看显示单元中的一个圆圈,它是数据单元中的省略号。 编辑: 所以您的解决方案非常适合,dx /= get_aspect(ax) 有效。
【解决方案2】:

我能找到的最好的东西是:

def get_aspect(ax=None):
    if ax is None:
        ax = plt.gca()
    fig = ax.figure

    ll, ur = ax.get_position() * fig.get_size_inches()
    width, height = ur - ll
    axes_ratio = height / width
    aspect = axes_ratio / ax.get_data_ratio()

    return aspect

但它出奇地复杂,我不确定它在变换等情况下是否可靠,因为我对 bboxtransform 对象一无所知。

【讨论】:

  • 我觉得您应该将此添加到您的问题中,并询问是否有比这更简单或更可靠的方法
  • 这段代码看起来很像 matplotlib 本身的Axes.apply_aspect 中的代码。
【解决方案3】:

怎么样

import numpy as np
aspect = sum(np.abs(ax.get_xlim())) / sum(np.abs(ax.get_ylim()))

【讨论】:

  • 谢谢@Frank,但我相信这只是给1/ax.get_data_ratio()
  • 哦,没错,甚至比我的建议还要好。我不知道这存在。我以为这就是你要找的东西,但显然是别的东西。对不起。
  • 为什么是np.abs()?如果两个限制具有相同的符号,这将不起作用。
【解决方案4】:

我不确定它是否完全符合您的要求,但请尝试一下

    bbox = axis.get_window_extent().transformed(figure.dpi_scale_trans.inverted())
    aspect_ratio = bbox.width / bbox.height

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-03
    • 2020-06-02
    • 2021-10-29
    • 2019-04-09
    • 2012-07-14
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多