Matplotlib:隐藏子图并用其他子图填充空间

10

我有一个包含三个垂直排列的子图的图表。一旦我点击这个图表,我希望第二个子图 ax2 被隐藏,并且其他的子图填充空间。再次点击图表应该还原原始的图和布局。

隐藏子图 ax2 并不是问题,但我如何重新排列其他子图的位置呢?

我尝试创建一个新的 GridSpec,使用 set_positionset_subplotspec 方法,但什么都没有起作用。我确定我在这里漏掉了些什么,任何帮助将不胜感激。

这是我的代码:

import matplotlib.pyplot as plt
from matplotlib import gridspec

fig = plt.figure()

gs = gridspec.GridSpec(3, 1, height_ratios=[5, 2, 1])
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharex=ax1)
ax3 = fig.add_subplot(gs[2], sharex=ax2)

visible = True

def toggle_ax2(event):
    global visible
    visible = not visible
    ax2.set_visible(visible)
    plt.draw()

fig.canvas.mpl_connect('button_press_event', toggle_ax2)
plt.show()
2个回答

13
您可以定义两个不同的GridSpec,其中一个将具有3个子图,另一个将具有2个子图。根据中间轴的可见性,您可以更改其他两个轴的位置,以遵从第一个或第二个GridSpec。(不需要任何虚拟图形或其他答案可能建议的东西。)
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

fig = plt.figure()

gs = gridspec.GridSpec(3, 1, height_ratios=[5, 2, 1], hspace=0.3)
gs2 = gridspec.GridSpec(2,1, height_ratios=[5,3])

ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharex=ax1)
ax3 = fig.add_subplot(gs[2], sharex=ax2)

ax1.plot([1,2,3], [1,2,3], color="crimson")
ax2.plot([1,2,3], [2,3,1], color="darkorange")
ax3.plot([1,2,3], [3,2,1], color="limegreen")

visible = True

def toggle_ax2(event):
    global visible
    visible = not visible
    ax2.set_visible(visible)
    if visible:
        ax1.set_position(gs[0].get_position(fig))
        ax3.set_position(gs[2].get_position(fig))
    else:
        ax1.set_position(gs2[0].get_position(fig))
        ax3.set_position(gs2[1].get_position(fig))

    plt.draw()

fig.canvas.mpl_connect('button_press_event', toggle_ax2)
plt.show()

左侧是原始图像;右侧是点击后的效果。

在此输入图片描述


如果您有五个轴,会发生什么?... 您需要为显示1、2、3、4和5个轴使用不同的“gridspec”吗?更复杂的是,其中一些轴必须比其他轴大... - Sardathrion - against SE abuse
1
@Sardathrion 这完全取决于您想做什么。如果只有五个轴,但仍然只想切换其中一个,您仍然只需要两个网格规范。但是,如果希望能够切换它们所有,可能需要大量的网格规范,以便在所有可能的组合中都具有不同的高度比例。然而,我建议最好采用单个网格规范,并在运行时操作其属性。 - ImportanceOfBeingErnest
1
@Sardathrion 抱歉,那不是我的意思。如果你有5个子图并且想要能够切换它们所有,你仍然需要5个gridspecs,一个有5行,一个有4行等等。但是你可以动态更新height_ratios来为每个子图产生所需的布局。 - ImportanceOfBeingErnest
好的,我现在明白了。谢谢。☺ - Sardathrion - against SE abuse

1
你可以创建一个新的gridspec实例,并使用它在第二个图中创建一些虚拟图形(在plt.show之前可以关闭它,因此您实际上从未看到它,我们只想从这里获取一些轴的位置)。
通过从该虚拟图和原始图中存储ax1ax3的两个可能位置,然后您可以在toggle_ax2函数中使用ax.set_position()更改其余两个轴的位置。
import matplotlib.pyplot as plt
from matplotlib import gridspec

fig = plt.figure()

gs = gridspec.GridSpec(3, 1, height_ratios=[5, 2, 1])
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharex=ax1)
ax3 = fig.add_subplot(gs[2], sharex=ax2)

# Store the original positions of ax1 and ax3
pos1_1 = ax1.get_position()
pos3_1 = ax3.get_position()

# Create a second gridspec for when ax2 is hidden. Keep 5:1 ratio
gs2 = gridspec.GridSpec(2, 1, height_ratios=[5, 1])
fig2 = plt.figure()
ax1_2 = fig2.add_subplot(gs2[0])
ax3_2 = fig2.add_subplot(gs2[1])

# Store the positions of ax1 and ax3 in the new gridspec
pos1_2 = ax1_2.get_position()
pos3_2 = ax3_2.get_position()

# Close the dummy figure2
plt.close(fig2)

visible = True

def toggle_ax2(event):
    global visible

    visible = not visible
    ax2.set_visible(visible)

    # Use the stored positions to switch between 
    # different arrangements of ax1 and ax3
    if visible:
        ax1.set_position(pos1_1)
        ax3.set_position(pos3_1)
    else:
        ax1.set_position(pos1_2)
        ax3.set_position(pos3_2)
    plt.draw()

fig.canvas.mpl_connect('button_press_event', toggle_ax2)
plt.show()

原始配置: 输入图像描述

删除 ax2 后: 输入图像描述


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