【问题标题】:How to configure secondary axis in matplotlib plot when the axis relation is derived empirically?凭经验得出轴关系时,如何在matplotlib图中配置次轴?
【发布时间】:2020-03-19 17:07:08
【问题描述】:

我试图遵循这个文档

https://matplotlib.org/3.1.0/gallery/subplots_axes_and_figures/secondary_axis.html

在辅助轴变换的第三种情况下,即,当“我们想要在一个变换中关联轴时,该变换是从数据中临时得出的,并且是根据经验得出的”,因此,设置“正向和反向变换函数是从一个数据集到另一个数据集的线性插值。”。但我无法达到令人满意的结果。

以本文档第一个示例的简单绘图为例:具有两个水平轴的正弦波,其中一个是同一绘图上的弧度到度数的转换。

下面的代码给出了正确的结果,其中底轴以弧度为单位,顶轴以度为单位

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(constrained_layout=True)
x = np.linspace(0, 2*np.pi, 1000)
y = np.sin(x)
ax.plot(x, y)

def deg2rad(x):
    return x * np.pi / 180

def rad2deg(x):
    return x * 180 / np.pi

secax = ax.secondary_xaxis('top', functions=(rad2deg,deg2rad))

plt.show()

但是,下面的代码旨在模拟“度数轴”将来自经验数据(数组变量xnew,可能是其他值),但它没有给出正确的结果(遵循插值函数文档)。

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(constrained_layout=True)
x = np.linspace(0, 2*np.pi, 1000)
y = np.sin(x)
ax.plot(x, y)

xold = x
xnew = x * 180 / np.pi

def forward(x):
    return np.interp(x, xold, xnew)

def inverse(x):
    return np.interp(x, xnew, xold)

secax = ax.secondary_xaxis('top', functions=(forward,inverse))

plt.show()

我错过了什么?

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    问题在于,对于稍微超出给定 x 值范围的值,会同时调用正向和逆向函数。例如,它们用于 xlims。 (可以在这些函数中添加print(x) 以查看它们是如何被调用的。)

    如果将这些函数写成简单的线性变换,例如deg2rad 示例,则没有问题。该函数在其范围之外同样有效。但是np.interp 在它的范围之外没有很好的线索,所以它返回它的下限或上限。这种截断会导致不希望的刻度标记。

    对于一部分,这可以通过设置一个紧密的 x 轴来解决,所以没有默认发生的填充:

    plt.autoscale(enable=True, axis='x', tight=True)
    

    但即便如此,400 处的不受欢迎的滴答声也会弹出。

    更好的解决方案是使这两个函数的范围比旧 x 轴上显示的限制宽一些,包括填充。比如设置

    xold = np.linspace(x[0]-0.5, x[-1]+0.5, 100)
    xnew = xold * 180 / np.pi
    

    请注意,在linked example 中,他们设置了xold = np.arange(0, 11, 0.2),但随后只从第三个索引开始绘制,以便为填充创建足够的空间:ax.plot(xold[3:], xnew[3:])

    完整的示例如下所示:

    import matplotlib.pyplot as plt
    import numpy as np
    
    fig, ax = plt.subplots(constrained_layout=True)
    x = np.linspace(0, 2*np.pi, 1000)
    y = np.sin(x)
    ax.plot(x, y)
    
    xold = np.linspace(x[0]-0.5, x[-1]+0.5, 100)
    xnew = xold * 180 / np.pi
    
    def forward(x):
        return np.interp(x, xold, xnew)
    
    def inverse(x):
        return np.interp(x, xnew, xold)
    
    secax = ax.secondary_xaxis('top', functions=(forward,inverse))
    
    plt.show()
    

    【讨论】:

    • 谢谢,这确实回答了这个问题。对不起,我之前忘记互动了。我真的很怀念这个例子是从第三个索引(xold[3:])开始的。我应该注意到它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    • 1970-01-01
    相关资源
    最近更新 更多