Matplotlib中如何为部分子图共享坐标轴

72

我有一个大的情节,我开始时是这样的:

import numpy as np
import matplotlib.pyplot as plt

fig, axs = plt.subplots(5, 4)

我想让第1和2列共享X轴,第3和4列也一样,但是第1和2列与第3和4列没有共享相同的坐标轴。

我想知道是否有任何方法可以做到这一点,而不需要在所有图中都使用 sharex=Truesharey=True

PS:这个教程并没有太大帮助,因为它只是关于在每个行/列之间共享x/y;除非共享所有轴,否则它们无法在不同的行/列之间共享轴。

4个回答

72

我不确定您想从问题中获得什么样的结果。不过,在向图形添加子图时,您可以针对每个子图指定它应与哪个子图共享轴。

该操作可以通过以下方式完成:

import matplotlib.pylab as plt

fig = plt.figure()

ax1 = fig.add_subplot(5, 4, 1)
ax2 = fig.add_subplot(5, 4, 2, sharex = ax1)
ax3 = fig.add_subplot(5, 4, 3, sharex = ax1, sharey = ax1)

1
谢谢!那真的很有帮助。我查了一下,似乎没有一个可以设置sharex/sharey属性的轴对象方法。你觉得是这样吗? - Yuxiang Wang
我还没有找到相关的东西,所以我认为是这样。需要注意的是,我的搜索技能不错,但也不是最好的。 - The Dude
3
如何使用轴数组?ax[1,0] = plot(x,y) ax[1,1] = plot(x,y,sharey=ax[1,0])。但是这样不起作用。 - AAI
1
那应该是被接受的答案。不明白为什么它排在这么靠后的位置。(我猜是因为按活跃度排序的缘故)。 - Fabian Ying
它也适用于轴数组 - 确保您对数组使用np.empty(),例如: ax = np.empty((4, 2), dtype=object); fig = plt.figure(); ax[0][0] = fig.add_subplot(4, 2, 1, sharex=ax[0][0]); ax[0][1] = fig.add_subplot(4, 2, 2, sharex=ax[0][0]) - Balint Pato

68

子图的一个略微受限但更简单的选项可用。该限制适用于完整的子图行或列。 例如,如果想为所有子图设置共同的y轴,但仅为3x2子图中各个列设置共同的x轴,则可以指定为:

一个稍微受限但更简单的子图选项可用,在完整的一行或一列子图上有限制。例如,在3x2的子图中,如果想要为所有子图使用相同的y轴,但只希望各个列之间共享相同的x轴,那么可以进行如下设置:

import matplotlib.pyplot as plt
fig, ax = plt.subplots(3, 2, sharey=True, sharex='col')

2
这太棒了!谢谢!! - raulindo
3
确实太完美了!直到现在我都不知道这是真的存在! - Mad Physicist
真是个很棒的功能! - fokkerplanck
1
完美!而等价的sharey='row'。 - undefined

18
可以使用Grouper对象手动管理轴的共享,可以通过ax._shared_axes['x']ax._shared_axes['y']访问。例如,
import matplotlib.pyplot as plt

def set_share_axes(axs, target=None, sharex=False, sharey=False):
    if target is None:
        target = axs.flat[0]
    # Manage share using grouper objects
    for ax in axs.flat:
        if sharex:
            target._shared_axes['x'].join(target, ax)
        if sharey:
            target._shared_axes['y'].join(target, ax)
    # Turn off x tick labels and offset text for all but the bottom row
    if sharex and axs.ndim > 1:
        for ax in axs[:-1,:].flat:
            ax.xaxis.set_tick_params(which='both', labelbottom=False, labeltop=False)
            ax.xaxis.offsetText.set_visible(False)
    # Turn off y tick labels and offset text for all but the left most column
    if sharey and axs.ndim > 1:
        for ax in axs[:,1:].flat:
            ax.yaxis.set_tick_params(which='both', labelleft=False, labelright=False)
            ax.yaxis.offsetText.set_visible(False)

fig, axs = plt.subplots(5, 4)
set_share_axes(axs[:,:2], sharex=True)
set_share_axes(axs[:,2:], sharex=True)

要以分组方式调整子图之间的间距,请参考this question
编辑:根据最新的matplotlib API更新修改了代码。感谢@Jonvdrdo的建议!

对于我的用例来说并不直接适用(在一个8行2列的图中,将第2n行和第2n+1行之间的x轴共享,并将所有偶数行的y轴与另一侧的所有奇数行的y轴共享),但我可以进行调整。我之前不知道有“Grouper”,很好! - Aubergine
2
Matplotlib API已经更新,请参见此链接。因此,您需要将if sharex更改为target._shared_axes['x'].join(target, ax),将if sharey更改为target._shared_axes['y'].join(target, ax)。然后它就可以在较新的Matplotlib版本中使用(在Matplotlib==3.5.1上测试过)。 - Jonvdrdo
注意:在过去的版本(<3.8)中,可以通过get_shared_x_axes()get_shared_y_axes()方法访问target._shared_axes['x']target._shared_axes['y'],在我看来,这样做比使用“私有”方法更好。但是现在这些方法返回不可变的GrouperView对象。所以你要么使用target._shared_axes,要么使用target.get_shared_x_axes()._grouper。我不确定他们(在mpl中)在这里是怎么想的。 - undefined

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接