matplotlib 设置子图的绝对大小

vlurs2pr  于 2023-06-23  发布在  其他
关注(0)|答案(3)|浏览(129)

我知道如何使用gridspec或subplots_adjust设置图中子图的相对大小,也知道如何使用figsize设置图的大小。我的问题是设置子情节的绝对大小。

**用例:**我正在制作两个单独的图,它们将保存为学术论文的pdf。一个具有两个子图,一个具有三个子图(在两种情况下都在1行中)。我需要的5个子图是完全相同的大小与完全相同的字体大小(轴标签,勾选标签等)在所产生的PDF文件。在下面的示例中,字体大小相同,但子图大小不同。如果我使生成的PDF的高度相同(因此轴相同),则3-subplots.pdf上的字体小于2-subplots.pdf上的字体。
MWE

import matplotlib.pyplot as plt

subplots = [2, 3]
for i, cols in enumerate(subplots):

    fig, ax = plt.subplots(1, cols, sharey=True, subplot_kw=dict(box_aspect=1))

    for j in range(cols):
        ax[j].set_title(f'plot {j*cols}')
        ax[j].set_xlabel('My x label')
    ax[0].set_ylabel('My y label')

    plt.tight_layout()
    plt.savefig(f'{cols}-subplots.pdf', bbox_inches='tight', pad_inches=0)
    plt.show()

输出:x1c 0d1x

x0fgdtte

x0fgdtte1#

我更喜欢使用fig.add_axes([left, bottom, width, height]),它可以让你精确地控制每个子图的大小和位置。leftbottom决定子图的位置,而widthheight决定子图的大小。所有量都是图形宽度和高度的分数,因此它们都在0和1之间浮动。
举个例子:

fig = plt.figure(figsize=(8.3, 11.7))
axs = {
    "ax1": fig.add_axes([0.2, 0.7, 0.6, 0.2], xticklabels=[]),
    "ax2": fig.add_axes([0.2, 0.49, 0.6, 0.2], xticklabels=[]),
    "ax3": fig.add_axes([0.2, 0.28, 0.6, 0.2]),
}

有了这个,我在A4大小的图中创建了3个子图,每个子图的宽度为0.6x8.3,高度为0.2x11.7。它们之间的间距为0.1x11.7。"ax1""ax2"不显示xticklabels,以便我稍后可以为它们设置共享的x刻度。
您可以查看matplotlib API参考以了解更多信息https://matplotlib.org/stable/api/figure_api.html

oyxsuwqo

oyxsuwqo2#

我最终通过以下方式解决了这个问题:
1.为子地块宽度/高度、子地块之间的间隔和子地块外部的间隔设置明确的绝对长度,
1.将它们相加以得到绝对数字大小,
1.将subplot box_aspect设置为1以保持它们的正方形。

import matplotlib.pyplot as plt

num_subplots = [2, 3]

scale = 1 # scaling factor for the plot
subplot_abs_width = 2*scale # Both the width and height of each subplot
subplot_abs_spacing_width = 0.2*scale # The width of the spacing between subplots
subplot_abs_excess_width = 0.3*scale # The width of the excess space on the left and right of the subplots
subplot_abs_excess_height = 0.3*scale # The height of the excess space on the top and bottom of the subplots

for i, cols in enumerate(num_subplots):
    fig_width = (cols * subplot_abs_width) + ((cols-1) * subplot_abs_spacing_width) + subplot_abs_excess_width
    fig_height = subplot_abs_width+subplot_abs_excess_height

    fig, ax = plt.subplots(1, cols, sharey=True, figsize=(fig_width, fig_height), subplot_kw=dict(box_aspect=1))

    for j in range(cols):
        ax[j].set_title(f'plot {j}')
        ax[j].set_xlabel('My x label')
    ax[0].set_ylabel('My y label')

    plt.tight_layout()
    plt.savefig(f'{cols}-subplots.pdf', bbox_inches='tight', pad_inches=0)
    plt.show()

klr1opcd

klr1opcd3#

我创建了一个函数,该函数创建具有绝对大小的轴,并且在大多数方面与plt.subplots(...)类似,例如允许共享y轴或x轴,并将轴作为形状numpy数组返回。它使轴在其栅格区域内居中,使它们与图形的边缘之间具有尽可能多的空间(假设您将figsize设置得足够大)。
参数包括图的绝对高度和宽度(详见matplotlib文档)以及轴的绝对高度和宽度,如原始问题中所要求的。

from typing import Tuple
from matplotlib import pyplot as plt
import numpy as np

def subplots_with_absolute_sized_axes(
        nrows: int, ncols: int,
        figsize: Tuple[float, float],
        axis_width: float, axis_height: float,
        sharex: bool=False, sharey: bool=False) -> Tuple[plt.Figure, numpy.ndarray]:
    ''' Create axes with exact sizes.

    Spaces axes as far from each other and the figure edges as possible
    within the grid defined by nrows, ncols, and figsize.

    Allows you to share y and x axes, if desired.
    '''
    fig = plt.figure(figsize=figsize)
    figwidth, figheight = figsize
    # spacing on each left and right side of the figure
    h_margin = (figwidth - (ncols * axis_width)) / figwidth / ncols / 2
    # spacing on each top and bottom of the figure
    v_margin = (figheight - (nrows * axis_height)) / figheight / nrows / 2
    row_addend = 1 / nrows
    col_addend = 1 / ncols
    inner_ax_width = axis_width / figwidth
    inner_ax_height = axis_height / figheight
    axes = []
    sharex_ax = None
    sharey_ax = None
    for row in range(nrows):
        bottom = (row * row_addend) + v_margin
        for col in range(ncols):
            left = (col * col_addend) + h_margin
            if not axes:
                axes.append(fig.add_axes(
                    [left, bottom, inner_ax_width, inner_ax_height]))
                if sharex:
                    sharex_ax = axes[0]
                if sharey:
                    sharey_ax = axes[0]
            else:
                axes.append(fig.add_axes(
                    [left, bottom, inner_ax_width, inner_ax_height],
                    sharex=sharex_ax, sharey=sharey_ax))
    return fig, np.flip(np.asarray(list(axes)).reshape((nrows, ncols)), axis=0)

相关问题