在Matplotlib子图中删除多余的图表

53
我想在2行3列的布局中绘制5个数据框。这是我的代码:但第6个位置(第二行第三列)多了一个空图,我想去掉它。我想知道如何移除它,以便第一行有三个图,第二行有两个图。
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2, ncols=3)

fig.set_figheight(8)
fig.set_figwidth(15)



df[2].plot(kind='bar',ax=axes[0,0]); axes[0,0].set_title('2')

df[4].plot(kind='bar',ax=axes[0,1]); axes[0,1].set_title('4')

df[6].plot(kind='bar',ax=axes[0,2]); axes[0,2].set_title('6')

df[8].plot(kind='bar',ax=axes[1,0]); axes[1,0].set_title('8')

df[10].plot(kind='bar',ax=axes[1,1]); axes[1,1].set_title('10')

plt.setp(axes, xticks=np.arange(len(observations)), xticklabels=map(str,observations),
        yticks=[0,1])

fig.tight_layout()

Plots

6个回答

90

试一下这个:

fig.delaxes(axes[1][2])

创建子图的更加灵活的方式是使用fig.add_axes()方法。参数是一个矩形坐标列表:fig.add_axes([x,y,xsize,ysize])。这些值是相对于画布大小的,因此 xsize0.5 表示子图的宽度为窗口的一半。


谢谢,它起作用了。你知道如何将这两个图形移动到中心吗? - HimanAB
如果您想要一个不同于常规网格的子图布局,通常更容易使用 fig.add_axes() 方法。它接受一个矩形的坐标(作为列表)并返回一个单个轴对象。这些坐标是相对于窗口大小的。我会在我的答案中放一个例子。 - Johannes
3
使用 add_axes 并不是生成子图的最好或推荐的方式。使用 plt.subplots 或者 Gridspec 是更好的选择,而 delaxesax.axis("off") 可以用来删除或隐藏子图。 - ImportanceOfBeingErnest
请问您能解释一下为什么吗?我知道在大多数情况下,plt.subplots已经足够了,并且这也是推荐的方式。但是在像这样的情况下或者如果您想要重叠的子图,我认为这是正确的方式。 - Johannes
嗨,约翰内斯,如果我这样定义我的轴:f,((ax1,ax2),(ax3,ax4),(ax5,ax6),(ax7,ax8)) = plt.subplots(4,2,sharex = True,sharey = True,figsize =(10,20)),而我不需要我的ax8怎么办? - Ash
显示剩余2条评论

42

或者,使用 axes 方法的 set_axis_off():

axes[1,2].set_axis_off()

1
当我不知道行/列数时,我发现这比@Johannes的建议更容易实现。 - Addison Klinke
我似乎无法让这个与第一行的图表一起工作,即axes [0,2] .set_axis_off()。它会抛出一个“IndexError:数组的索引太多”。子图是1行4列。有关如何在第一行上实现此操作的任何指针吗? - 3kstc
在您的情况下,axes不再是一个二维网格,而是一个子图对象的一维数组。因此,您需要设置axes[2].set_axis_off() - ksha
[p.set_axis_off() for p in [i for i in axes.flatten() if len(i.get_title()) < 1]] [p.set_axis_off() for p in [i for i in axes.flatten() if len(i.get_title()) < 1]] - DJV

16
如果您知道要删除的情节,请给出索引并像这样删除:
axes.flat[-1].set_visible(False) # to remove last plot

9

关闭所有轴,只有在绘制它们时才一个一个地打开它们。这样你就不需要事先知道索引,例如:

import matplotlib.pyplot as plt

columns = ["a", "b", "c", "d"]
fig, axes = plt.subplots(nrows=len(columns))

for ax in axes:
    ax.set_axis_off()

for c, ax in zip(columns, axes):
    if c == "d":
        print("I didn't actually need 'd'")
        continue

    ax.set_axis_on()
    ax.set_title(c)

plt.tight_layout()
plt.show()

enter image description here


4
当我写一个通用的绘图程序而又不知道需要有多少子图时,+1 是最好的选择。虽然其他答案在回答问题时也是正确的,但这个回答更具普适性。 - Julian Moore
如果您在subplots调用中添加了sharex=True,则会返回-1,这样将无法正常工作,也不适用于其他解决方案,例如delaxesset_axis_off - snail123815

3
Johannes的回答中更懒的方法是删除掉没有添加数据的坐标轴。这样就避免了维护需要删除哪些坐标轴的规范。
[fig.delaxes(ax) for ax in axes.flatten() if not ax.has_data()]

2

之前的解决方案不适用于 sharex=True。如果你使用了这个参数,请考虑以下解决方案,它也适用于二维子图布局。

import matplotlib.pyplot as plt


columns = ["a", "b", "c", "d"]
fig, axes = plt.subplots(4,1, sharex=True)


plotted = {}
for c, ax in zip(columns, axes.ravel()):
    plotted[ax] = 0
    if c == "d":
        print("I didn't actually need 'd'")
        continue
    ax.plot([1,2,3,4,5,6,5,4,6,7])
    ax.set_title(c)
    plotted[ax] = 1

if axes.ndim == 2:
    for a, axs in enumerate(reversed(axes)):
        for b, ax in enumerate(reversed(axs)):
            if plotted[ax] == 0:
                # one can use get_lines(), get_images(), findobj() for the propose
                ax.set_axis_off()
                # now find the plot above
                axes[-2-a][-1-b].xaxis.set_tick_params(which='both', labelbottom=True)
            else:
                break # usually only the last few plots are empty, but delete this line if not the case
else:
    for i, ax in enumerate(reversed(axes)):
        if plotted[ax] == 0:
            ax.set_axis_off()
            axes[-2-i].xaxis.set_tick_params(which='both', labelbottom=True)
            # should also work with horizontal subplots
            # all modifications to the tick params should happen after this
        else:
            break

plt.show()

示例运行结果

创建2维图表:fig, axes = plot.subplots(2,2, sharex=True)

使用2,2时


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