如何从 for 循环 matplotlib 中的子图创建单个图形
How to create a single figure from subplots in for loop matplotlib
我有 4 张 numpy 数组格式的图像,其中每张都是 4D(61、73、61、11),最后一个维度对应于图像通道(在我的例子中是 11)。我使用 for 循环迭代通道,在每次迭代时,我为每个图像创建一个包含 4 个图的子图。在 jupyter notebook 中,我可以看到所有的子图,但我想创建一个包含所有子图的图形,这样我就可以创建一个 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();
还有一个打印屏幕,其中前 5 行是 jupyter 的输出。
更新
我尝试使用以下代码根据@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()
虽然图片很小而且中间有很多space
尽管使用紧凑的布局
解决方案
我设法制作了情节并制作了这个辅助函数
# 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)
这可以通过使用 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()
我有 4 张 numpy 数组格式的图像,其中每张都是 4D(61、73、61、11),最后一个维度对应于图像通道(在我的例子中是 11)。我使用 for 循环迭代通道,在每次迭代时,我为每个图像创建一个包含 4 个图的子图。在 jupyter notebook 中,我可以看到所有的子图,但我想创建一个包含所有子图的图形,这样我就可以创建一个 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();
还有一个打印屏幕,其中前 5 行是 jupyter 的输出。
更新 我尝试使用以下代码根据@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()
虽然图片很小而且中间有很多space 尽管使用紧凑的布局
解决方案
我设法制作了情节并制作了这个辅助函数
# 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)
这可以通过使用 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()