matplotlib子图的行标题

时间:2014-12-11 15:39:31

标签: python matplotlib subplot

在matplotlib中,除了整个图的标题集和每个单独的图的标题集之外,是否可以为每行子图设置一个单独的标题?这将对应于下图中的橙色文本。 enter image description here

如果没有,你会如何解决这个问题?在左侧创建一个单独的空子图列,并用橙色文本填充它们?

我知道可以使用text()annotate()手动定位每个单独的标题,但这通常需要大量调整,我有很多子图。有更顺畅的解决方案吗?

4 个答案:

答案 0 :(得分:8)

一个想法是创建三个"大的子图",给每个人一个标题,并使它们不可见。最重要的是,您可以创建较小的子图的矩阵。

此解决方案完全基于this post,但已经更加注意实际删除背景子图。

enter image description here

import matplotlib.pyplot as plt

fig, big_axes = plt.subplots( figsize=(15.0, 15.0) , nrows=3, ncols=1, sharey=True) 

for row, big_ax in enumerate(big_axes, start=1):
    big_ax.set_title("Subplot row %s \n" % row, fontsize=16)

    # Turn off axis lines and ticks of the big subplot 
    # obs alpha is 0 in RGBA string!
    big_ax.tick_params(labelcolor=(1.,1.,1., 0.0), top='off', bottom='off', left='off', right='off')
    # removes the white frame
    big_ax._frameon = False


for i in range(1,10):
    ax = fig.add_subplot(3,3,i)
    ax.set_title('Plot title ' + str(i))

fig.set_facecolor('w')
plt.tight_layout()
plt.show()

答案 1 :(得分:1)

另一种简单的作弊方式是将中间列的标题命名为subplot row XX\n\nPlot title No.YY

答案 2 :(得分:1)

最好先绘制真正的子图,然后在它们上方绘制空的子图,这样标题对齐会更精确。为了准确地做到这一点,我们需要 plt.GridSpec() (link)。

最好在栏目字幕中看到:

# modified code of @snake_chrmer
fig, big_axes = plt.subplots(figsize=(9, 3) , nrows=1, ncols=3, sharey=True) 

for title, big_ax in zip(['First', 'Second', 'Third'], big_axes):
    big_ax.set_title(f'{title}\n', fontweight='semibold')
    big_ax.set_frame_on(False)
    big_ax.axis('off')


for i in range(1, 7):
    ax = fig.add_subplot(1,6,i)
    ax.set_title('Plot title ' + str(i))

fig.set_facecolor('w')
plt.tight_layout()
plt.show()

enter image description here

# my solition
import matplotlib.pyplot as plt
from matplotlib.gridspec import SubplotSpec

def create_subtitle(fig: plt.Figure, grid: SubplotSpec, title: str):
    "Sign sets of subplots with title"
    row = fig.add_subplot(grid)
    # the '\n' is important
    row.set_title(f'{title}\n', fontweight='semibold')
    # hide subplot
    row.set_frame_on(False)
    row.axis('off')


rows = 1 
cols = 6
fig, axs = plt.subplots(rows, cols, figsize=(9, 3))
for i, ax in enumerate(axs.flatten()):
    ax.set_title(f'Plot title {i}')
grid = plt.GridSpec(rows, cols)
create_subtitle(fig, grid[0, 0:2], 'First')
create_subtitle(fig, grid[0, 2:4], 'Second')
create_subtitle(fig, grid[0, 4:6], 'Third')
fig.tight_layout()
fig.set_facecolor('w')

enter image description here

# original problem
rows = 3
cols = 3
fig, axs = plt.subplots(rows, cols, figsize=(9, 9))
for i, ax in enumerate(axs.flatten()):
    ax.set_title(f'Plot title {i}')
grid = plt.GridSpec(rows, cols)
create_subtitle(fig, grid[0, ::], 'First')
create_subtitle(fig, grid[1, ::], 'Second')
create_subtitle(fig, grid[2, ::], 'Third')
fig.tight_layout()
fig.set_facecolor('w')

enter image description here

更新

为一组子图创建子网格只是为了给它们命名更合乎逻辑和易于理解。 subgrig 为修改提供了浪费空间:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

rows = 1
cols = 3

fig = plt.figure(figsize=(9, 3))
# grid for pairs of subplots
grid = plt.GridSpec(rows, cols)

for i in range(rows * cols):
    # create fake subplot just to title pair of subplots
    fake = fig.add_subplot(grid[i])
    #  '\n' is important
    fake.set_title(f'Fake #{i}\n', fontweight='semibold', size=14)
    fake.set_axis_off()

    # create subgrid for two subplots without space between them
    # <https://matplotlib.org/2.0.2/users/gridspec.html>
    gs = gridspec.GridSpecFromSubplotSpec(1, 2, subplot_spec=grid[i], wspace=0)

    # real subplot #1
    ax = fig.add_subplot(gs[0])
    ax.set_title(f'Real {i}1')
    # hide ticks and labels
    ax.tick_params(left=False, labelleft=False, labelbottom=False, bottom=False)

    # real subplot #2
    ax = fig.add_subplot(gs[1], sharey=ax)
    ax.set_title(f'Real {i}2')
    # hide ticks and labels
    ax.tick_params(left=False, labelleft=False, labelbottom=False, bottom=False)

fig.patch.set_facecolor('white')
fig.suptitle('SUPERTITLE', fontweight='bold', size=16)
fig.tight_layout()

enter image description here

原问题:

rows = 3
cols = 1

fig = plt.figure(figsize=(9, 9))
# grid for pairs of subplots
grid = plt.GridSpec(rows, cols)

for i in range(rows * cols):
    # create fake subplot just to title set of subplots
    fake = fig.add_subplot(grid[i])
    # '\n' is important
    fake.set_title(f'Fake #{i}\n', fontweight='semibold', size=14)
    fake.set_axis_off()

    # create subgrid for two subplots without space between them
    # <https://matplotlib.org/2.0.2/users/gridspec.html>
    gs = gridspec.GridSpecFromSubplotSpec(1, 3, subplot_spec=grid[i])

    # real subplot #1
    ax = fig.add_subplot(gs[0])
    ax.set_title(f'Real {i}1')

    # real subplot #2
    ax = fig.add_subplot(gs[1], sharey=ax)
    ax.set_title(f'Real {i}2')
    
    # real subplot #3
    ax = fig.add_subplot(gs[2], sharey=ax)
    ax.set_title(f'Real {i}3')

fig.patch.set_facecolor('white')
fig.suptitle('SUPERTITLE', fontweight='bold', size=16)
fig.tight_layout()

enter image description here

答案 3 :(得分:1)

从 matplotlib 3.4.0 开始,行标题现在可以实现为 subfigure suptitles

<块引用>

新的 Figure.subfiguresFigure.add_subfigure 允许在图形中创建虚拟图形[使用]本地化图形艺术家(例如,颜色条和字幕),仅与每个子图形相关。 >

matplotlib 库包括 how to plot subfigures 上的演示。


复制OP的参考图:

  • 使用 Figure.subfigures(更直接)

    创建 fig.subfigures (3x1),其中每个 subfig 都有自己的 subfig.subplots (1x3) 和 subfig.suptitle

    fig = plt.figure(constrained_layout=True)
    fig.suptitle('Figure title')
    
    # create 3x1 subfigs
    subfigs = fig.subfigures(nrows=3, ncols=1)
    for row, subfig in enumerate(subfigs):
        subfig.suptitle(f'Subplot row title {row}')
    
        # create 1x3 subplots per subfig
        axs = subfig.subplots(nrows=1, ncols=3)
        for col, ax in enumerate(axs):
            ax.plot()
            ax.set_title(f'Plot title {col}')
    
  • 或使用 Figure.add_subfigure(在现有的 pyplot.subplots 上)

    如果您已经有了 plt.subplots 图形 (3x1),则将 add_subfigures 插入底层 gridspec。同样,每个 subfig 都会得到自己的 subfig.subplots (1x3) 和 subfig.suptitle

    # create 3x1 subplots
    fig, axs = plt.subplots(nrows=3, ncols=1, constrained_layout=True)
    fig.suptitle('Figure title')
    
    # clear subplots
    for ax in axs:
        ax.remove()
    
    # add subfigure per subplot
    gridspec = axs[0].get_subplotspec().get_gridspec()
    subfigs = [fig.add_subfigure(gs) for gs in gridspec]
    
    for row, subfig in enumerate(subfigs):
        subfig.suptitle(f'Subplot row title {row}')
    
        # create 1x3 subplots per subfig
        axs = subfig.subplots(nrows=1, ncols=3)
        for col, ax in enumerate(axs):
            ax.plot()
            ax.set_title(f'Plot title {col}')
    

任一示例的输出(经过一些样式/格式设置后):

subfigures with localized suptitles