【问题标题】:How to create a single figure from subplots in for loop matplotlib如何从 for 循环 matplotlib 中的子图创建单个图形
【发布时间】:2021-01-06 08:31:03
【问题描述】:

我有 4 个 numpy 数组格式的图像,每个图像都是 4D(61、73、61、11),最后一个维度对应于图像通道(在我的情况下为 11)。我使用 for 循环迭代通道,并在每次迭代中为每个图像创建一个包含 4 个图的子图。在 jupyter 笔记本中,我可以看到所有子图,但我想创建一个包含所有子图的单个图形,这样我就可以创建一个 png 而不是 11 个。 这是matplotlib中的代码。

import maplotlib.pyplot as plt

center_slices = [s//2 for s in concat_img.shape[:1]] # take the middle slice
print(np.squeeze(concat_img[center_slices[0], :, :, 5]).shape)

for i in range(10):
    f, axarr = plt.subplots(1, 4, figsize=(20,5),  sharex=True);
    f.suptitle('Different intensity normalisation methods on brain fMRI image dual_regression + ALFF derivatives')

    img = axarr[0].imshow(np.squeeze(concat_img[:, :, center_slices[0], i]), cmap='gray');
    axarr[0].axis('off')
    axarr[0].set_title('Original image')
    f.colorbar(img, ax=axarr[0])

    img = axarr[1].imshow(np.squeeze(concat_img_white[:, :, center_slices[0], i]), cmap='gray');
    axarr[1].axis('off')
    axarr[1].set_title('Zero mean/unit stdev')
    f.colorbar(img, ax=axarr[1])

    img = axarr[2].imshow(np.squeeze(concat_img_zero_one[:, :, center_slices[0], i]), cmap='gray');
    axarr[2].axis('off')
    axarr[2].set_title('[0,1] rescaling')
    f.colorbar(img, ax=axarr[2])

    img = axarr[3].imshow(np.squeeze(concat_img_one_one[:, :, center_slices[0], i]), cmap='gray');
    axarr[3].axis('off')
    axarr[3].set_title('[-1,1] rescaling')
    f.colorbar(img, ax=axarr[3])
    
    f.subplots_adjust(wspace=0.05, hspace=0, top=0.8)
#     plt.savefig('./TTT.{0:07d}.png'.format(i)) # save each subplot in png 
plt.show();
   

还有一个打印屏幕,其中包含 jupyter 前 5 行的输出。

更新 我尝试使用以下代码根据 cmets 中的@Timo 答案调整代码:

center_slices = [s//2 for s in concat_img.shape[:1]]
print(np.squeeze(concat_img[center_slices[0], :, :, 5]).shape)

nrows , ncols = (11, 4)
fig, ax = plt.subplots(nrows=nrows, ncols=ncols,
                       figsize=(140, 120))
fig.suptitle('Different intensity normalisation methods on brain fMRI image dual_regression + ALFF derivatives')

# f.subplots_adjust(wspace=0.05, hspace=0, top=0.8)

zdata = [concat_img, concat_img_white, concat_img_zero_one, concat_img_one_one] 
titles =['Original image', 'Zero mean/unit stdev', '[0,1] rescaling', '[-1,1] rescaling']

for j in range(nrows):
    for i in range(ncols):
        img = zdata[i]
        cbar = ax[j, i].imshow(np.squeeze(img[:, :, center_slices[0], i]), cmap='gray', interpolation='nearest');
        ax[j, i].axis('off')
        ax[j, i].set_title(f'{titles[i]},channel :{j}')
        fig.colorbar(cbar, ax=ax[j, i])
        

fig.tight_layout()

虽然图片非常小,而且之间有很大的空间 尽管使用了紧凑的布局

解决方案

我设法制作了情节并制作了这个辅助函数

# Helper function
def myplot(nrows, ncols, zdata, global_title, title, savefig, name=None):

    center_slices = [s//2 for s in zdata[0].shape[:1]]
    print(np.squeeze(zdata[0][center_slices[0], :, :, 5]).shape)

    fig, ax = plt.subplots(nrows=nrows, ncols=ncols,
                       figsize=(5 * ncols, 4 * nrows))
    
    for j in range(nrows):
        for i in range(ncols):
            img = zdata[i]
            img = img[:, :, center_slices[0], j]
            cbar = ax[j, i].imshow(np.squeeze(img), cmap='gray', interpolation='nearest', aspect='auto');
            ax[j, i].axis('off')
            ax[j, i].set_title(f'{titles[i]},channel :{j}')
            fig.colorbar(cbar, ax=ax[j, i])

    fig.tight_layout()        
    fig.suptitle(global_title, fontsize=16, y=1.005)
    plt.show()
    st = fig.suptitle(global_title,  fontsize=16, y= 1.005)
    if savefig :
        fig.savefig(name, bbox_extra_artists=[st], bbox_inches='tight')

nrows = 11
ncols = 4

global_title ='Different intensity normalisation methods on brain fMRI image '
zdata = [concat_img, concat_img_white, concat_img_zero_one , concat_img_one_one]
titles =['Original image', 'Zero mean/unit stdev', '[0,1] rescaling', '[-1,1] rescaling']

myplot(nrows, ncols, zdata, global_title, titles, False)

【问题讨论】:

  • 仔细看看你的数字,它们大约是 2.4:1.6。理想情况下,您的图形大小应该具有相同的缩放比例。 tight_layout是否运作良好有时是一个试错过程。
  • @Timo 我能够制作我想要的情节并制作了一个函数。谢谢你的代码。
  • 如果对你有用,请接受我的回答。

标签: python matplotlib visualization


【解决方案1】:

这可以通过使用nrows != 1 创建一个坐标区实例来完成。我在下面附上了一个例子。

import matplotlib.pyplot as plt
import numpy as np

nrows = 5
ncols = 4

xdata = np.linspace(-np.pi, np.pi)
ydata = 1 * xdata
X, Y = np.meshgrid(xdata, ydata)
zdata = np.sin(X + Y)

fig, ax = plt.subplots(nrows=nrows, ncols=ncols, sharex=True,
                       figsize=(nrows * 2.2, 2 * ncols))

for j in range(nrows):
    for i in range(ncols):
        cbar = ax[j, i].contourf(zdata)
        fig.colorbar(cbar, ax=ax[j, i])
        
fig.tight_layout()

【讨论】:

  • 我尝试复制您的示例@Timo,但图像非常小。
猜你喜欢
  • 2020-07-23
  • 2022-07-07
  • 2015-08-18
  • 2019-04-09
  • 1970-01-01
  • 2013-09-24
  • 2013-07-08
  • 2021-12-29
  • 2016-06-17
相关资源
最近更新 更多