matplotlib子图的行标题

joe*_*lom 8 python matplotlib subplot

在matplotlib中,除了整个图的标题集和每个单独的图的标题集之外,是否可以为每行子图设置一个单独的标题?这将对应于下图中的橙色文本. 在此输入图像描述

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

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

ban*_*013 17

最好先绘制真实的子图,然后在其上方绘制空的子图,这样您将获得更精确的标题对齐。为了准确地做到这一点,我们需要plt.GridSpec()链接)。

最好在栏目副标题中看到:

# 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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

# 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')

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

# 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')
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

UPD

为一组子图创建子网格只是为了给它们添加标题,这样更合逻辑、更容易理解。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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

原来的问题:

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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


sna*_*mer 9

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

这个解决方案完全基于这篇文章,除了更多关注实际删除背景子图.

在此输入图像描述

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()
Run Code Online (Sandbox Code Playgroud)

  • 这很好,但打破了 sharex 和 sharey 选项。 (4认同)
  • 不幸的是,大多数 matplotlib 格式化方法看起来都像 hack... (2认同)
  • 伙计们,观看“big_ax.set_title()”中的“\n”,我花了一个小时试图理解为什么我将所有标题都写在一行上 (2认同)

tdy*_*tdy 7

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

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

matplotlib 库包括有关如何绘制子图的演示。


要重现 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}')
    
    Run Code Online (Sandbox Code Playgroud)
  • 或使用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}')
    
    Run Code Online (Sandbox Code Playgroud)

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

带有本地化字幕的子图


小智 6

另一个简单的作弊是将中间列的标题设为 subplot row XX\n\nPlot title No.YY

  • 它不适用于偶数列 (3认同)