python - matplotlib 将 x 轴与自动缩放的 y 轴链接起来

标签 python matplotlib

如何创建一堆具有链接(共享)x 轴的图,以便在缩放期间自动缩放所有“从属”图的 y 轴?例如:

import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212, sharex=ax1)
ax1.plot([0,1])
ax2.plot([2,1])
plt.show()

当我放大 ax1 时,这也会更新 ax2 的 x 轴(到目前为止一切顺利),但我还希望 ax2 的 y 轴根据现在可见的数据范围自动缩放。所有自动缩放设置均已启用(默认设置)。创建 ax2 后手动设置自动缩放设置没有帮助:

ax2.autoscale(enable=True, axis='y', tight=True)
ax2.autoscale_view(tight=True, scalex=False, scaley=True)

print ax2.get_autoscaley_on()
-> True

我错过了什么吗?

最佳答案

在研究了 matplotlib 的 axes.py 的血淋淋的细节之后,似乎没有根据数据 View 自动缩放轴的规定,因此没有高级方法来实现我想要的。

但是,有“xlim_changed”事件,可以向其附加回调:

import numpy as np

def on_xlim_changed(ax):
    xlim = ax.get_xlim()
    for a in ax.figure.axes:
        # shortcuts: last avoids n**2 behavior when each axis fires event
        if a is ax or len(a.lines) == 0 or getattr(a, 'xlim', None) == xlim:
            continue

        ylim = np.inf, -np.inf
        for l in a.lines:
            x, y = l.get_data()
            # faster, but assumes that x is sorted
            start, stop = np.searchsorted(x, xlim)
            yc = y[max(start-1,0):(stop+1)]
            ylim = min(ylim[0], np.nanmin(yc)), max(ylim[1], np.nanmax(yc))

        # TODO: update limits from Patches, Texts, Collections, ...

        # x axis: emit=False avoids infinite loop
        a.set_xlim(xlim, emit=False)

        # y axis: set dataLim, make sure that autoscale in 'y' is on 
        corners = (xlim[0], ylim[0]), (xlim[1], ylim[1])
        a.dataLim.update_from_data_xy(corners, ignore=True, updatex=False)
        a.autoscale(enable=True, axis='y')
        # cache xlim to mark 'a' as treated
        a.xlim = xlim

for ax in fig.axes:
    ax.callbacks.connect('xlim_changed', on_xlim_changed)

不幸的是,这是一个非常低级的 hack,很容易破坏(除线、反向或对数轴之外的其他对象,...)

似乎无法连接到 axes.py 中的高级功能,因为高级方法不会将 emit=False 参数转发给 set_xlim(),这是避免在 set_xlim( ) 和“xlim_changed”回调。

此外,似乎没有统一的方法来确定水平裁剪对象的垂直范围,因此在 axes.py 中有单独的代码来处理 Lines、Patches、Collections 等,这些都需要复制在回调中。

无论如何,上面的代码对我有用,因为我的情节中只有线条,而且我对 tight=True 布局很满意。似乎只需对 axes.py 进行一些更改,就可以更优雅地容纳此功能。

编辑:

关于无法连接到更高级别的自动缩放功能,我错了。它只需要一组特定的命令来正确分离 x 和 y。我更新了代码以在 y 中使用高级自动缩放,这应该会使其更加健壮。特别是,tight=False 现在可以工作(毕竟看起来好多了),并且反向/对数轴应该不是问题。

剩下的一个问题是确定所有类型对象的数据限制,一旦裁剪到特定的 x 范围。这个功能应该是内置的 matplotlib,因为它可能需要渲染器(例如,如果放大到屏幕上只剩下 0 或 1 个点,上面的代码就会中断)。 Axes.relim() 方法看起来是个不错的选择。如果数据已更改,它应该重新计算数据限制,但目前仅处理线和补丁。 Axes.relim() 可能有可选参数,用于指定 x 或 y 中的窗口。

关于python - matplotlib 将 x 轴与自动缩放的 y 轴链接起来,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11086724/

相关文章:

python - 无法使用 Pandas to_sql() 方法将数据插入到 Snowflake 数据库表中

python-2.7 - 无法将图形另存为 .eps [无法识别 gswin32c]

python - 在Python for循环中,如何为绘图创建图例?

python - Matplotlib:如何将时间戳与 broken_barh 一起使用?

python - Matplotlib 和 Numpy - 创建日历热图

python - pandas numpy matplotlib 溢出错误 : date value out of range

python - 如何从张量中提取子矩阵?

python - 为什么当我执行 'log' 时,我的 matplotlib 条形图会压缩 x 轴

python - 在python中将unicode gif写入文件

python - subprocess.Popen.stdout - 实时读取标准输出(再次)