1

我正在创建一些子图,每个子图的底部都有自己的颜色条。使用以下命令添加颜色条:

cax, kw = mcbar.make_axes_gridspec(ax, orientation='horizontal',
                                   pad=pad,
                                   fraction=0.07, shrink=0.85, aspect=35)
figure.colorbar(cs, cax=cax, orientation='horizontal')

调整参数,pad使得如果没有 xticklabels,则值更小,以避免浪费空间。

完整的脚本:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colorbar as mcbar

x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 50)
X, Y = np.meshgrid(x, y)
Z = X**2+np.sin(Y)

figure = plt.figure(figsize=(12, 10))
nrow = 3
ncol = 2

for ii in range(nrow*ncol):
    ax = figure.add_subplot(nrow, ncol, ii+1)
    row, col = np.unravel_index(ii, (nrow, ncol))

    cs = ax.contourf(X, Y, Z)
    if row == nrow-1:
        # larger padding to make room for xticklabels
        pad = 0.15
    else:
        # smaller padding otherwise
        pad = 0.05
        ax.tick_params(labelbottom=False)

    if row == 1 and col == 1:
        # add xlabel would need more padding
        ax.set_xlabel('X')

    cax, kw = mcbar.make_axes_gridspec(ax, orientation='horizontal',
                                       pad=pad,
                                       fraction=0.07, shrink=0.85, aspect=35)
    figure.colorbar(cs, cax=cax, orientation='horizontal')
    ax.set_title(str(ii+1))

figure.tight_layout()
figure.show()

输出图:

在此处输入图像描述

但是当前的解决方案是使用硬编码的填充值(0.15如果使用xticklabels0.05否则),并且它不能很好地适应存在xlabels(参见子图 4)或改变图形大小。

有没有办法以编程方式计算出合适的填充值来放置颜色条?也许通过调整父轴对象的边界框,如果没有xlabelsor xticklabels,则它的 bbox 更小,或者通过找出父轴的坐标并以某种方式计算填充?

4

1 回答 1

0

您可以通过比较整个轴和y轴的边界框来获得刻度标签和轴标签所需的空间。要获得这些边界框,我们需要一个渲染器。为了使它可用,我们首先需要绘制画布。边界框以显示坐标返回,因此我们使用反转轴变换将它们转换为轴坐标。它们 y 坐标的差异给出了所需的额外填充:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colorbar as mcbar
from matplotlib.transforms import Bbox

x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 50)
X, Y = np.meshgrid(x, y)
Z = X**2+np.sin(Y)

figure = plt.figure(figsize=(12, 10))
figure.canvas.draw()  # to get renderer
nrow = 3
ncol = 2

for ii in range(nrow*ncol):
    ax = figure.add_subplot(nrow, ncol, ii+1)
    row, col = np.unravel_index(ii, (nrow, ncol))

    cs = ax.contourf(X, Y, Z)
    if row != nrow-1:
        ax.tick_params(labelbottom=False)

    if row == 1 and col == 1:
        # add xlabel would need more padding
        ax.set_xlabel('X')

    # get height of ticklabels and label
    b = ax.transAxes.inverted().transform(
        [ax.yaxis.get_tightbbox(figure.canvas.renderer).p0,
        ax.get_tightbbox(figure.canvas.renderer).p0]
    )
    pad = 0.05 + (b[0]-b[1])[1]

    cax, kw = mcbar.make_axes_gridspec(ax, orientation='horizontal',
                                       pad=pad,
                                       fraction=0.07, shrink=0.85, aspect=35)
    figure.colorbar(cs, cax=cax, orientation='horizontal')
    ax.set_title(str(ii+1))

在此处输入图像描述

该解决方案存在轴 3 和轴 4 具有不同高度的缺陷。您可以通过将ymin一行中的所有轴调整为行最大值来解决此问题:

figure.tight_layout()
for i in range(0, 2*ncol*nrow, 2*ncol):
    ymin = 0
    for j in range(0, 2*ncol, 2):
        ymin = max(ymin, figure.axes[i+j].get_position().ymin)
    for j in range(0, 2*ncol, 2):
        b = figure.axes[i+j].get_position()
        figure.axes[i+j].set_position(Bbox([[b.xmin,ymin],[b.xmax,b.ymax]]))

请注意,此调整必须在申请前完成tight_layout在此处输入图像描述

于 2021-01-12T16:19:25.857 回答