【问题标题】:Does matplotlib have a function for drawing diagonal lines in axis coordinates?matplotlib 是否具有在轴坐标中绘制对角线的功能?
【发布时间】:2014-04-01 23:48:33
【问题描述】:

Matplotlib 轴具有 axhlineaxvline 函数,用于在给定的 y 或 x 坐标(分别)上绘制水平或垂直线,与轴上的数据比例无关。

是否有用于绘制恒定对角线的类似函数?例如,如果我有一个具有相似域的变量散点图,那么了解它们是位于y = x 的线之上还是之下通常很有用:

mean, cov = [0, 0], [(1, .6), (.6, 1)]
x, y = np.random.multivariate_normal(mean, cov, 100).T
y += x + 1
f, ax = plt.subplots(figsize=(6, 6))
ax.scatter(x, y, c=".3")
ax.plot([-3, 3], [-3, 3], ls="--", c=".3")
ax.set(xlim=(-3, 3), ylim=(-3, 3))

这当然可以通过获取轴限制(ax.get_xlim() 等)以编程方式完成,但是 a) 需要一些额外的步骤,并且 b) 在更多数据可能最终出现在绘图上的情况下很脆弱并改变界限。 (实际上在某些情况下,只需添加常量线本身就会拉伸轴)。

最好只做,例如ax.axdline(ls="--", c=".3"),但不清楚 matplotlib 代码库中是否存在类似的东西。您需要做的就是修改axhline 代码,以便在xy 坐标中从[0, 1] 绘制,我想。

【问题讨论】:

标签: python numpy matplotlib


【解决方案1】:

绘制从屏幕左下角到右上角的对角线非常简单,您只需使用ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3")ax.get_xlim() 方法将简单地返回 x 轴的当前值(对于 y 轴也是如此)。

但是,如果您希望能够使用图表进行缩放,那么它会变得更加棘手,因为您绘制的对角线不会改变以匹配您的新 xlims 和 ylims。

在这种情况下,您可以使用回调来检查 xlims(或 ylims)何时发生变化,并相应地更改对角线上的数据(如下所示)。我在this example 中找到了回调方法。更多信息也可以找到here

import numpy as np
import matplotlib.pyplot as plt

mean, cov = [0, 0], [(1, .6), (.6, 1)]
x, y = np.random.multivariate_normal(mean, cov, 100).T
y += x + 1

f, ax = plt.subplots(figsize=(6, 6))

ax.scatter(x, y, c=".3")
ax.set(xlim=(-3, 3), ylim=(-3, 3))

# Plot your initial diagonal line based on the starting
# xlims and ylims.
diag_line, = ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3")

def on_change(axes):
    # When this function is called it checks the current
    # values of xlim and ylim and modifies diag_line
    # accordingly.
    x_lims = ax.get_xlim()
    y_lims = ax.get_ylim()
    diag_line.set_data(x_lims, y_lims)

# Connect two callbacks to your axis instance.
# These will call the function "on_change" whenever
# xlim or ylim is changed.
ax.callbacks.connect('xlim_changed', on_change)
ax.callbacks.connect('ylim_changed', on_change)

plt.show()

请注意,如果您不希望对角线随着缩放而改变,那么您只需删除diag_line, = ax.plot(...下方的所有内容

【讨论】:

  • 抱歉,我了解如何以编程方式执行此操作,我只是想知道 matplotlib 中是否有一些东西可以省去获取限制等的麻烦,这很脆弱,因为它们可能会改变。我不太担心交互式缩放,一般来说,数据限制会随着数据添加到绘图中而发生变化,或者如果您想添加一条独立于您要绘制的任何其他数据的对角线。我将编辑我的问题以使其更清楚。
  • 只是让您知道对角线不仅会在交互式缩放时发生变化,而且在您将数据添加到绘图并通过例如ax.set_xlim(a, b) 进行更改时也会发生变化。我不明白您所说的“易碎,因为它们可能会改变”是什么意思?我的回答的整个想法是,只要他们确实改变了对角线,就会修改以考虑到这一点。
  • 明白了。回调提示很有用。我的意思是只是在初始绘制时使用get_xlim()get_ylim()
【解决方案2】:

绘制从左下角到右上角的对角线将通过以下方式完成

ax.plot([0, 1], [0, 1], transform=ax.transAxes)

使用transform=ax.transAxes,提供的xy 坐标被解释为axes 坐标而不是data 坐标。

正如@fqq 所指出的,这只是当您的xy 限制相等时的标识线。要绘制线 y=x 使其始终延伸到绘图的范围,类似于@Ffisegydd 给出的方法将起作用,并且可以编写为以下函数。

def add_identity(axes, *line_args, **line_kwargs):
    identity, = axes.plot([], [], *line_args, **line_kwargs)
    def callback(axes):
        low_x, high_x = axes.get_xlim()
        low_y, high_y = axes.get_ylim()
        low = max(low_x, low_y)
        high = min(high_x, high_y)
        identity.set_data([low, high], [low, high])
    callback(axes)
    axes.callbacks.connect('xlim_changed', callback)
    axes.callbacks.connect('ylim_changed', callback)
    return axes

示例用法:

import numpy as np
import matplotlib.pyplot as plt

mean, cov = [0, 0], [(1, .6), (.6, 1)]
x, y = np.random.multivariate_normal(mean, cov, 100).T
y += x + 1

f, ax = plt.subplots(figsize=(6, 6))
ax.scatter(x, y, c=".3")
add_identity(ax, color='r', ls='--')

plt.show()

【讨论】:

  • 这不会画出 y=x 线,这是 OP 要求的。
  • 没错,它在我的回答中从左下角到右上角画了一条线。我在争论是否要包括您仍然必须确保绘图的 x 和 y 限制相等的警告。我认为如果您要绘制标识线,设置相等的 x 和 y 限制通常是一种好习惯。
  • 感谢您的详细说明。在所有这些中还出现了另一件事 - 即使使用您的回调解决方案。就是添加对角线,会改变自动轴限制。为此,我更喜欢访问xlim/ylim,画线,恢复xlim/ylim!
【解决方案3】:

如果坐标轴在[0,1]范围内,可以这样解析:

ident = [0.0, 1.0]
plt.plot(ident,ident)

【讨论】:

    【解决方案4】:

    从 matplotlib 3.3.0 开始,它将:https://matplotlib.org/3.3.0/api/_as_gen/matplotlib.axes.Axes.axline.html

    Axes.axline(self, xy1, xy2=None, *, slope=None, **kwargs) 添加一个 无限长的直线。

    线可以由两个点 xy1 和 xy2 定义,也可以由一个 点 xy1 和一个坡度。

    这会在“屏幕”上绘制一条直线,而不管 x 和 y 尺度,因此也适用于绘制指数衰减 半对数图、对数图中的幂律等。但是,斜率应该 仅与线性刻度一起使用;它对所有其他的没有明确的意义 尺度,因此行为是未定义的。请指定线路 使用点 xy1, xy2 进行非线性尺度。

    【讨论】:

    • 确实,ax.axline((1, 1), slope=1) 应该这样做
    • 对我来说这不起作用。我得到一个attributeError:'AxesSubplot'对象没有属性'axline'。如果我在一些不同的设置中尝试它,我会得到: AttributeError: moule 'matplotlib.pyplot' has no attribute 'axline.我在这两种设置中都使用 hline 和 vline 没有问题。
    • 如果您的 matplotlib 足够新,这显然优于更受欢迎的答案。谢谢!
    【解决方案5】:

    根据https://matplotlib.org/stable/gallery/pyplots/axline.html,您可以使用plt.axline。以及文档中的示例:

    import matplotlib.pyplot as plt
    
    t = np.linspace(-10, 10, 100)
    sig = 1 / (1 + np.exp(-t))
    
    plt.axhline(y=0, color="black", linestyle="--")
    plt.axhline(y=0.5, color="black", linestyle=":")
    plt.axhline(y=1.0, color="black", linestyle="--")
    plt.axvline(color="grey")
    plt.axline((0, 0.5), slope=0.25, color="black", linestyle=(0, (5, 5)))
    plt.plot(t, sig, linewidth=2, label=r"$\sigma(t) = \frac{1}{1 + e^{-t}}$")
    plt.xlim(-10, 10)
    plt.xlabel("t")
    plt.legend(fontsize=14)
    plt.show()```
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多