关于python:matplotlib的子图中的行和列标题

Row and column headers in matplotlib's subplots

将行和列标题添加到在matplotlib中的循环中生成的子图网格中的最佳实践是什么? 我能想到几个,但并不是特别整洁:

  • 对于具有循环计数器的列,您只能将set_title()用于第一行。 对于行,这不起作用。 您将不得不在绘图之外绘制text
  • 您在顶部添加了一排子图,在左侧添加了一列子图,并在该子图的中间绘制了文本。
  • 您能提出更好的选择吗?

    enter image description here


    有几种方法可以做到这一点。 最简单的方法是利用图的y标签和标题,然后使用fig.tight_layout()为标签腾出空间。 或者,您可以使用annotate将其他文本放置在正确的位置,然后以半手动方式为其留出空间。

    如果轴上没有y标签,则很容易利用第一行和第一列的标题和y标签。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import matplotlib.pyplot as plt

    cols = ['Column {}'.format(col) for col in range(1, 4)]
    rows = ['Row {}'.format(row) for row in ['A', 'B', 'C', 'D']]

    fig, axes = plt.subplots(nrows=4, ncols=3, figsize=(12, 8))

    for ax, col in zip(axes[0], cols):
        ax.set_title(col)

    for ax, row in zip(axes[:,0], rows):
        ax.set_ylabel(row, rotation=0, size='large')

    fig.tight_layout()
    plt.show()

    enter image description here

    如果您确实有y标签,或者您希望有更多的灵活性,则可以使用annotate放置标签。 这比较复杂,但是除了行和列标签外,还允许您具有单独的打印标题,ylabel等。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import matplotlib.pyplot as plt
    from matplotlib.transforms import offset_copy


    cols = ['Column {}'.format(col) for col in range(1, 4)]
    rows = ['Row {}'.format(row) for row in ['A', 'B', 'C', 'D']]

    fig, axes = plt.subplots(nrows=4, ncols=3, figsize=(12, 8))
    plt.setp(axes.flat, xlabel='X-label', ylabel='Y-label')

    pad = 5 # in points

    for ax, col in zip(axes[0], cols):
        ax.annotate(col, xy=(0.5, 1), xytext=(0, pad),
                    xycoords='axes fraction', textcoords='offset points',
                    size='large', ha='center', va='baseline')

    for ax, row in zip(axes[:,0], rows):
        ax.annotate(row, xy=(0, 0.5), xytext=(-ax.yaxis.labelpad - pad, 0),
                    xycoords=ax.yaxis.label, textcoords='offset points',
                    size='large', ha='right', va='center')

    fig.tight_layout()
    # tight_layout doesn't take these labels into account. We'll need
    # to make some room. These numbers are are manually tweaked.
    # You could automatically calculate them, but it's a pain.
    fig.subplots_adjust(left=0.15, top=0.95)

    plt.show()

    enter image description here


    上面的答案有效。 只是在第二版答案中您没有:

    1
    2
    3
    4
    for ax, row in zip(axes[:,0], rows):
        ax.annotate(col, xy=(0, 0.5), xytext=(-ax.yaxis.labelpad-pad,0),
                    xycoords=ax.yaxis.label, textcoords='offset points',
                    size='large', ha='right', va='center')

    代替:

    1
    2
    3
    4
    for ax, row in zip(axes[:,0], rows):
        ax.annotate(row,xy=(0, 0.5), xytext=(-ax.yaxis.labelpad-pad,0),                    
                    xycoords=ax.yaxis.label, textcoords='offset points',
                    size='large', ha='right', va='center')