如何在使用pandas plot创建的图表中添加共享的x轴标签和y轴标签

17

使用Pandas可以轻松地从数据框创建子图:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'A': [0.3, 0.2, 0.5, 0.2], 'B': [0.1, 0.0, 0.3, 0.1], 'C': [0.2, 0.5, 0.0, 0.7], 'D': [0.6, 0.3, 0.4, 0.6]}, index=list('abcd'))

ax = df.plot(kind="bar", subplots=True, layout=(2, 2), sharey=True, sharex=True, rot=0, fontsize=20)

如何在生成的图中添加x和y标签?这里解释了如何为单个图添加标签。所以如果我想要为特定子图添加标签,我可以执行以下操作:

ax[1][0].set_xlabel('my_general_xlabel')
ax[0][0].set_ylabel('my_general_ylabel')
plt.show()

那么得到:

输入图像描述

如何添加标签,使它们居中且不仅仅是指一行/列?

4个回答

19

在matplotlib中,x和y标签是绑定到坐标轴上的。因此,对于用于标记多个子图的目的,使用xlabelylabel命令几乎没有意义。

不过,可以创建一个简单的文本并将其放置在所需位置。fig.text(x,y, text)将一些文本放置在图形坐标系中的坐标xy处,即图形的左下角具有坐标(0,0),右上角具有坐标(1,1)

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'A': [0.3, 0.2, 0.5, 0.2], 'B': [0.1, 0.0, 0.3, 0.1], 'C': [0.2, 0.5, 0.0, 0.7], 'D': [0.6, 0.3, 0.4, 0.6]}, index=list('abcd'))
axes = df.plot(kind="bar", subplots=True, layout=(2,2), sharey=True, sharex=True)

fig=axes[0,0].figure
fig.text(0.5,0.04, "Some very long and even longer xlabel", ha="center", va="center")
fig.text(0.05,0.5, "Some quite extensive ylabel", ha="center", va="center", rotation=90)

plt.show()

在此输入图片描述

这种解决方案的缺点是需要手动设置文本放置的坐标,而且可能取决于图形的大小。


原问题中没有提到,但您是否知道如何更改各个子图(在本例中为 ABCD)的标题字体大小? - Cleb
2
@Cleb:它们需要有不同的大小吗?如果不需要,最简单的方法是在脚本顶部使用plt.rcParams["axes.titlesize"] = 20(这将为所有标题设置字体大小为20)。 - ImportanceOfBeingErnest

10

另一个解决方案是创建一个大的子图,然后设置共同的标签。以下是我得到的结果。

输入图片描述

以下是源代码。

import pandas as pd
import matplotlib.pyplot as plt

fig = plt.figure()
axarr = fig.add_subplot(221)   

df = pd.DataFrame({'A': [0.3, 0.2, 0.5, 0.2], 'B': [0.1, 0.0, 0.3, 0.1], 'C': [0.2, 0.5, 0.0, 0.7], 'D': [0.6, 0.3, 0.4, 0.6]}, index=list('abcd'))
axes = df.plot(kind="bar", ax=axarr, subplots=True, layout=(2, 2), sharey=True, sharex=True, rot=0, fontsize=20)

# Create a big subplot
ax = fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axes
plt.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')

ax.set_xlabel('my_general_xlabel', labelpad=10) # Use argument `labelpad` to move label downwards.
ax.set_ylabel('my_general_ylabel', labelpad=20)

plt.show()

原问题中没有提到,但您是否知道如何更改各个子图(在本例中为 ABCD)标题的字体大小? - Cleb
@Cleb,您可以使用参数“labelpad”调整标签的位置,请查看我的编辑答案。 - SparkAndShine
我指的是子图上方的字母(也出现在图例中的字母)。 - Cleb

9

新特性:最近的matplotlib(v3.4+;使用pip --upgrade matplotlib)也具备了图形级别的x和y标签:

fig.supxlabel('my general x-label')
fig.supylabel('my general y-label')

虽然这是一个重要的选项,但默认情况下与字体大小和位置匹配并不完全相同,就好像它适合其中一个子图一样。请查看文档:https://matplotlib.org/devdocs/api/figure_api.html#matplotlib.figure.FigureBase.supxlabel,以了解其有很多选项可以满足原问题的要求。


1
我们如何调整supxlabel和xticks标签之间的间距?我找不到labelpad选项。谢谢。 - Basilique

8
这将创建一个不可见的111轴,您可以在其中设置通用的x和y标签:
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'A': [0.3, 0.2, 0.5, 0.2], 'B': [0.1, 0.0, 0.3, 0.1],
                   'C': [0.2, 0.5, 0.0, 0.7], 'D': [0.6, 0.3, 0.4, 0.6]},
                  index=list('abcd'))
ax = df.plot(kind="bar", subplots=True, layout=(2, 2), sharey=True,
             sharex=True, rot=0, fontsize=12)

fig = ax[0][0].get_figure()  # getting the figure
ax0 = fig.add_subplot(111, frame_on=False)   # creating a single axes
ax0.set_xticks([])
ax0.set_yticks([])
ax0.set_xlabel('my_general_xlabel', labelpad=25)
ax0.set_ylabel('my_general_ylabel', labelpad=45)

# Part of a follow up question: Modifying the fontsize of the titles:
for i,axi in np.ndenumerate(ax):
    axi.set_title(axi.get_title(),{'size' : 16})

enter image description here


不完全是我想要的:我希望在两个图之间有一个居中的公共 x 轴标签,y 轴也一样。 - Cleb
我明白了,您想要类似于suptitle的东西。 - Pablo Reyes
那不会对你有帮助,那只是放置一个通用的居中标题而不是x和y标签。我正在做一些可能会对你有帮助的事情:添加一个111子图。 - Pablo Reyes
2
更新了。这与@sparkandshine发布的内容类似,但不同之处在于此解决方案使用已生成的图形,但需要微调标签间距。 - Pablo Reyes
运行良好,也已点赞。虽然这不是原始问题的一部分,但您是否看到了更改各个子图标题字体大小的方法(在此示例中为“A”,“B”,“C”和“D”)? - Cleb
2
我刚刚更新了我的解决方案末尾的代码,以修改单个标题的字体大小。 - Pablo Reyes

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