Matplotlib标题跨越两个(或任意数量的)子图列

28
由于我正在绘制的内容的特性,我希望子图类似于嵌套表格。我不确定如何清楚地提问,所以我添加了一些图片来说明问题。 我拥有的是: Matplotlib graphs with title and axes titles 我想要的是: Matplotlib graphs with title and axes titles AND wanted sub-titles 当前(简化后)代码看起来像这样:
fig, axes = plt.subplots(nrows=5, ncols=4) 
fig.suptitle(title, fontsize='x-large')
data0.plot(x=data0.x, y=data0.y, ax=axes[0,0],kind='scatter')
data1.plot(x=data1.x, y=data1.y, ax=axes[0,1],kind='scatter')
axes[0,0].set_title('title 0')
axes[0,1].set_title('title 1')

我无法弄清如何同时为axes [0,0][0,1]设置标题。 我在文档中也找不到任何信息。 我不喜欢在Latex中围绕表格忙来实现这一点。 有什么建议吗?


你的图片中没有表格。表格应该放在哪里? - ImportanceOfBeingErnest
https://dev59.com/Nl8e5IYBdhLWcg3w6N2W - Dadep
@ImportanceOfBeingErnest 这不是关于表格的问题。我只是用表格比较来展示嵌套的概念。感谢你让我的图片可见! - user6870124
@Dadep 这是关于字幕和轴标题的问题,我已经在使用了。 - user6870124
2个回答

25

使用fig.suptitle()来设置图表标题,使用ax.set_title()来设置子图标题相对简单。要设置一个跨列的中间标题,确实没有内置选项。

解决这个问题的一种方法是在适当的位置使用plt.figtext()。需要考虑到该标题的额外空间,例如通过使用fig.subplots_adjust并找到该figtext的合适位置。

在下面的示例中,我们使用子图标题框架来找到标题所跨越的框架的中心水平位置,垂直位置则是最佳猜测。

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)
y = np.random.rand(10,8)

colors=["b", "g", "r", "violet"]
fig, axes = plt.subplots(nrows=2, ncols=4, sharex=True, sharey=True, figsize=(8,5)) 
#set a figure title on top
fig.suptitle("Very long figure title over the whole figure extent", fontsize='x-large')
# adjust the subplots, i.e. leave more space at the top to accomodate the additional titles
fig.subplots_adjust(top=0.78)     

ext = []
#loop over the columns (j) and rows(i) to populate subplots
for j in range(4):
    for i in range(2):
        axes[i,j].scatter(x, y[:,4*i+j], c=colors[j], s=25) 
    # each axes in the top row gets its own axes title
    axes[0,j].set_title('title {}'.format(j+1))
    # save the axes bounding boxes for later use
    ext.append([axes[0,j].get_window_extent().x0, axes[0,j].get_window_extent().width ])

# this is optional
# from the axes bounding boxes calculate the optimal position of the column spanning title
inv = fig.transFigure.inverted()
width_left = ext[0][0]+(ext[1][0]+ext[1][1]-ext[0][0])/2.
left_center = inv.transform( (width_left, 1) )
width_right = ext[2][0]+(ext[3][0]+ext[3][1]-ext[2][0])/2.
right_center = inv.transform( (width_right, 1) )

# set column spanning title 
# the first two arguments to figtext are x and y coordinates in the figure system (0 to 1)
plt.figtext(left_center[0],0.88,"Left column spanning title", va="center", ha="center", size=15)
plt.figtext(right_center[0],0.88,"Right column spanning title", va="center", ha="center", size=15)
axes[0,0].set_ylim([0,1])
axes[0,0].set_xlim([0,10])

plt.show()

在此输入图片说明


2
这个问题有一个新的解决方案,使用从matplotlib 3.4.0开始的subfigs 链接 - ra0

9

matplotlib 3.4.0的新功能

如果您使用的是matplotlib版本>=3.4.0(如@ra0的评论中所述),则可以使用子图。

创建子图后,您可以像处理普通图形一样处理它们,创建子图和添加子标题。

有关子图的文档示例

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)
y = np.random.rand(10, 8)

colors = ["b", "g", "r", "violet"]

fig = plt.figure(figsize=(8, 5), constrained_layout=True)
subfigs = fig.subfigures(1, 2)
titles = ["Left spanning title", "Right spanning title"]
for i, subfig in enumerate(subfigs):
    axes = subfig.subplots(2, 2)
    for j, row in enumerate(axes):
        for k, ax in enumerate(row):
            ax.scatter(x, y[:, i*4 + j*2 + k], color=colors[i*2 + k], s=25)
            ax.set_xlim([0, 10])
            ax.set_ylim([0, 1])
            if j == 0:
                ax.set_title(f"fig{i}, row{j}, col{k}")
    subfig.suptitle(titles[i])
fig.suptitle("Very long figure title over the whole figure extent", fontsize='x-large')
plt.show()

Code output


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