python - matplotlib 相邻子图 : adding colorbar changes size of a subplot

标签 python matplotlib colorbar

我正在尝试绘制一个由 5 x 6 个子图组成的图形,所有这些子图我都希望相邻,即共享它们的 x 轴和 y 轴。

我还想向每行最右边的图添加一个颜色条,该颜色条针对该行中的所有子图进行标准化。

我使用以下方法添加颜色条:

   divider = make_axes_locatable(ax)
   cax = divider.append_axes("right", size="5%", pad=0.15)
   fig.colorbar(im, cax=cax)

但是,添加颜色条会更改子图的大小,并且它不再粘在其他子图上。这是一个示例输出: sample output, generated with the program below 添加颜色条时如何使其不改变尺寸?

以下是生成上面图像的代码示例:

#!/usr/bin/env python3

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size 

# border limits for plots
lowlim = 0.43
uplim = 0.52
nx = 10


kernels = ['cubic_spline', 'quintic_spline',
        'wendland_C2', 'wendland_C4', 'wendland_C6']




#========================
def main():
#========================


    eta_facts = [ 0, 1, 2, 3, 4, 5 ]

    nrows = len(eta_facts)
    ncols = len(kernels)

    Ay_list = [[None for c in range(ncols)] for r in range(nrows)]



    #--------------------------------
    # Loop and compute As
    #--------------------------------
    dx = (uplim - lowlim)/nx

    for row, eta in enumerate(eta_facts):

        for col, kernel in enumerate(kernels):

            A = np.zeros((nx, nx), dtype=np.float)

            for i in range(nx):
                for j in range(nx):
                    A[j,i] = row + np.random.random()/10 # not a typo: need A[j,i] for imshow

            Ay_list[row][col] = A




    #------------------------------------
    # Now plot it
    #------------------------------------

    fig = plt.figure(figsize=(3.5*ncols, 3.5*nrows))

    axrows = []
    i = 1
    for r in range(nrows):
        axcols = []
        for c in range(ncols):
            if r > 0:
                if c > 0:
                    axcols.append(fig.add_subplot(nrows, ncols, i, 
                            aspect='equal', sharex=axrows[r-1][c], sharey=axcols[c-1]))
                else:
                    axcols.append(fig.add_subplot(nrows, ncols, i, 
                            aspect='equal', sharex=axrows[r-1][c]))
            else:
                if c > 0:
                    axcols.append(fig.add_subplot(nrows, ncols, i, 
                            aspect='equal', sharey=axcols[c-1]))
                else:
                    axcols.append(fig.add_subplot(nrows, ncols, i, aspect='equal'))
            i+=1
        axrows.append(axcols)



    cmap = 'YlGnBu_r'

    lw = 2


    for row in range(nrows):
        axcols = axrows[row]

        minval = min([np.min(Ay_list[row][c]) for c in range(ncols)])
        maxval = max([np.max(Ay_list[row][c]) for c in range(ncols)])


        for col, ax in enumerate(axcols):

            im = ax.imshow(Ay_list[row][col], origin='lower', 
                vmin=minval, vmax=maxval, cmap=cmap,
                extent=(lowlim, uplim, lowlim, uplim),
                #  norm=matplotlib.colors.SymLogNorm(1e-3),
                zorder=1)

            # only plot colorbar for last column

            if col==len(kernels)-1:
                divider = make_axes_locatable(ax)
                cax = divider.append_axes("right", size="5%", pad=0.15)
                fig.colorbar(im, cax=cax)


            ax.set_xlim((lowlim,uplim))
            ax.set_ylim((lowlim,uplim))


            # cosmetics
            if col > 0:
                left = False
            else:
                left = True
            if row == len(eta_facts)-1 :
                bottom = True
            else:
                bottom = False

            ax.tick_params(
                axis='both',        # changes apply to the x-axis
                which='both',       # both major and minor ticks are affected
                bottom=bottom,      # ticks along the bottom edge are off
                top=False,          # ticks along the top edge are off
                left=left,          # ticks along the left edge are off
                right=False,        # ticks along the rigt edge are off
                labelbottom=bottom, # labels along the bottom edge are off
                labeltop=False,     # labels along the top edge are off
                labelleft=left,     # labels along the left edge are off
                labelright=False)   # labels along the right edge are off


            if row==0:
                ax.set_title(kernels[col] + ' kernel', fontsize=14)
            if col==0:
                ax.set_ylabel(r"$\eta = $ "+str(eta_facts[row])+r"$\eta_0$")


    fig.suptitle(r"Some title", fontsize=18)
    plt.tight_layout(rect=(0, 0, 1, 0.97))
    plt.subplots_adjust(wspace=0, hspace=0)
    plt.savefig('for_stackexchange.png', dpi=150)
    plt.close()

    print('finished.')

    return





if __name__ == '__main__':
    main()

最佳答案

事实上,根据用户 ImportanceOfBeingErnest 的评论并使用axes_grid1,我可以让它工作。

主要区别:对于每一行,我定义一个 ImageGrid 对象:

    axrows = [[] for r in range(nrows)]
    i = 0
    for r in range(nrows):
        axcols = [None for c in range(ncols)]

        axcols = ImageGrid(fig, (nrows, 1, r+1),
                    nrows_ncols=(1, ncols), 
                    axes_pad = 0.0,
                    share_all = True,
                    label_mode = 'L',
                    cbar_mode = 'edge',
                    cbar_location = 'right',
                    cbar_size = "7%",
                    cbar_pad = "2%")
        axrows[r] = axcols

然后,在代码中的正确位置,我添加颜色条

axcols.cbar_axes[0].colorbar(im)

完整代码如下:

#!/usr/bin/env python3

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size 
from mpl_toolkits.axes_grid1 import ImageGrid

# border limits for plots
lowlim = 0.43
uplim = 0.52
nx = 10


kernels = ['cubic_spline', 'quintic_spline',
        'wendland_C2', 'wendland_C4', 'wendland_C6']




#========================
def main():
#========================


    eta_facts = [ 0, 1, 2, 3, 4, 5 ]

    nrows = len(eta_facts)
    ncols = len(kernels)

    Ay_list = [[None for c in range(ncols)] for r in range(nrows)]



    #--------------------------------
    # Loop and compute As
    #--------------------------------
    dx = (uplim - lowlim)/nx

    for row, eta in enumerate(eta_facts):

        for col, kernel in enumerate(kernels):

            A = np.zeros((nx, nx), dtype=np.float)

            for i in range(nx):
                for j in range(nx):
                    A[j,i] = row + np.random.random()/10 # not a typo: need A[j,i] for imshow

            Ay_list[row][col] = A




    #------------------------------------
    # Now plot it
    #------------------------------------

    fig = plt.figure(figsize=(3.5*ncols+1, 3.5*nrows))



    axrows = [[] for r in range(nrows)]
    i = 0
    for r in range(nrows):
        axcols = [None for c in range(ncols)]

        axcols = ImageGrid(fig, (nrows, 1, r+1),
                    nrows_ncols=(1, ncols), 
                    axes_pad = 0.0,
                    share_all = True,
                    label_mode = 'L',
                    cbar_mode = 'edge',
                    cbar_location = 'right',
                    cbar_size = "7%",
                    cbar_pad = "2%")
        axrows[r] = axcols



    cmap = 'YlGnBu_r'

    lw = 2


    for row in range(nrows):
        axcols = axrows[row]

        minval = min([np.min(Ay_list[row][c]) for c in range(ncols)])
        maxval = max([np.max(Ay_list[row][c]) for c in range(ncols)])


        for col, ax in enumerate(axcols):

            im = ax.imshow(Ay_list[row][col], origin='lower', 
                vmin=minval, vmax=maxval, cmap=cmap,
                extent=(lowlim, uplim, lowlim, uplim),
                #  norm=matplotlib.colors.SymLogNorm(1e-3),
                zorder=1)

            ax.set_xlim((lowlim,uplim))
            ax.set_ylim((lowlim,uplim))


            # cosmetics
            if col > 0:
                left = False
            else:
                left = True
            if row == len(eta_facts)-1 :
                bottom = True
            else:
                bottom = False

            ax.tick_params(
                axis='both',        # changes apply to the x-axis
                which='both',       # both major and minor ticks are affected
                bottom=bottom,      # ticks along the bottom edge are off
                top=False,          # ticks along the top edge are off
                left=left,          # ticks along the left edge are off
                right=False,        # ticks along the rigt edge are off
                labelbottom=bottom, # labels along the bottom edge are off
                labeltop=False,     # labels along the top edge are off
                labelleft=left,     # labels along the left edge are off
                labelright=False)   # labels along the right edge are off


            if row==0:
                ax.set_title(kernels[col] + ' kernel', fontsize=14)
            if col==0:
                ax.set_ylabel(r"$\eta = $ "+str(eta_facts[row])+r"$\eta_0$")
        axcols.cbar_axes[0].colorbar(im)


    fig.suptitle(r"Some title", fontsize=18)
    plt.tight_layout(rect=(0, 0, 1, 0.97))
    plt.subplots_adjust(wspace=0.0, hspace=0.0)
    plt.savefig('for_stackexchange.png', dpi=150)
    plt.close()

    print('finished.')

    return





if __name__ == '__main__':
    main()

生成此图像:

results

关于python - matplotlib 相邻子图 : adding colorbar changes size of a subplot,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56257524/

相关文章:

python - matplotlib 等高线图 : proportional colorbar levels in logarithmic scale

python - 配置 matplotlib colorbar 以匹配 3D 表面值

python - 初学者 Python 键盘 GUI 设置

python - 如何使用css选择器获取跨度数据?

python - 更改 Python 交互提示 ">>>"

python - 如何获取每行的百分比并可视化分类数据

python - 如何在 Matplotlib 中的 x 轴上分配相等的比例?

python - 如何在 scikit 中使用外部数据来执行 PCA/LDA?

python - 使用 Anytree 和 graphviz 在 python 中渲染树。无法打开文件

matlab - 模糊颜色图的一部分