2016-12-10 60 views
8

我正在研究一个项目,在这个项目中我需要将10行和3列的小区网格放在一起。尽管我已经能够制作情节和安排子情节,但是我无法制作出没有空白的情节,例如gridspec documentatation以下的情节。 image w/o white space如何删除matplotlib.pyplot中的子图之间的空间?

我尝试了以下文章,但仍然无法完全移除示例图像中的空白区域。有人可以给我一些指导吗?谢谢!

这里是我的形象:my image

下面是我的代码。 The full script is here on GitHub。 注意:images_2和images_fool都是具有形状(1032,10)的平展图像的数组,而delta是形状(28,28)的图像数组。

def plot_im(array=None, ind=0): 
    """A function to plot the image given a images matrix, type of the matrix: \ 
    either original or fool, and the order of images in the matrix""" 
    img_reshaped = array[ind, :].reshape((28, 28)) 
    imgplot = plt.imshow(img_reshaped) 

# Output as a grid of 10 rows and 3 cols with first column being original, second being 
# delta and third column being adversaril 
nrow = 10 
ncol = 3 
n = 0 

from matplotlib import gridspec 
fig = plt.figure(figsize=(30, 30)) 
gs = gridspec.GridSpec(nrow, ncol, width_ratios=[1, 1, 1]) 

for row in range(nrow): 
    for col in range(ncol): 
     plt.subplot(gs[n]) 
     if col == 0: 
      #plt.subplot(nrow, ncol, n) 
      plot_im(array=images_2, ind=row) 
     elif col == 1: 
      #plt.subplot(nrow, ncol, n) 
      plt.imshow(w_delta) 
     else: 
      #plt.subplot(nrow, ncol, n) 
      plot_im(array=images_fool, ind=row) 
     n += 1 

plt.tight_layout() 
#plt.show() 
plt.savefig('grid_figure.pdf') 

回答

6

开头的说明:如果你希望能有充分控制间距,避免使用plt.tight_layout(),因为它会尝试将图中的图平均分配好。这大部分都很好,并产生了令人满意的结果,但是可以根据意愿调整间距。

您从Matplotlib示例图库中引用的GridSpec示例运行良好的原因是因为子图的方面未预定义。也就是说,子图会简单地在网格上展开,并保持设定的间距(在这种情况下为wspace=0.0, hspace=0.0),而与图形大小无关。

与此相反,您正在使用imshow绘制图像,并且图像的方面默认设置为相等(相当于ax.set_aspect("equal"))。也就是说,您当然可以将set_aspect("auto")放到每个图(并且另外将wspace=0.0, hspace=0.0作为参数添加到GridSpec中,如在图库示例中),这会产生没有间距的图。

但是,当使用图像时,保持相等的纵横比使得每个像素都像宽一样宽,并且方形阵列显示为方形图像是很有意义的。
然后您需要做的是使用图像大小和图形边距来获得预期结果。图中的参数figsize是以英寸表示的数字(宽度,高度),这里可以使用两个数字的比率。并且可以手动调节子图参数wspace, hspace, top, bottom, left以提供所需的结果。 下面是一个例子:

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib import gridspec 

nrow = 10 
ncol = 3 

fig = plt.figure(figsize=(4, 10)) 

gs = gridspec.GridSpec(nrow, ncol, width_ratios=[1, 1, 1], 
     wspace=0.0, hspace=0.0, top=0.95, bottom=0.05, left=0.17, right=0.845) 

for i in range(10): 
    for j in range(3): 
     im = np.random.rand(28,28) 
     ax= plt.subplot(gs[i,j]) 
     ax.imshow(im) 
     ax.set_xticklabels([]) 
     ax.set_yticklabels([]) 

#plt.tight_layout() # do not use this!! 
plt.show() 

enter image description here

编辑:
当然,desireable不必手动调整的参数。所以可以根据行数和列数计算出一些最优的。

nrow = 7 
ncol = 7 

fig = plt.figure(figsize=(ncol+1, nrow+1)) 

gs = gridspec.GridSpec(nrow, ncol, 
     wspace=0.0, hspace=0.0, 
     top=1.-0.5/(nrow+1), bottom=0.5/(nrow+1), 
     left=0.5/(ncol+1), right=1-0.5/(ncol+1)) 

for i in range(nrow): 
    for j in range(ncol): 
     im = np.random.rand(28,28) 
     ax= plt.subplot(gs[i,j]) 
     ax.imshow(im) 
     ax.set_xticklabels([]) 
     ax.set_yticklabels([]) 

plt.show() 
+0

像魔术一样工作,感谢@ImportanceOfBeingErnest!只是想知道为什么你用figsize =(4,10)而不是figsize =(10,10)......后者立即带回空间。 –

+1

如果您的行数多于列数的3倍,为什么还需要一个方形图大小?您当然可以将它设置为(10,10),然后再次调整“左”和“右”参数。我选择'figsize =(4,10)'的想法更多的是拥有'n'行和'm'列,图形大小为(m + 1,n)可能是合适的。其余的则通过微调子图参数来完成。 – ImportanceOfBeingErnest

+0

我明白了。所以“无花果”真的是指整体图像大小,而不是子图。我迷惑了自己。 –

3

尝试添加到您的代码这一行:

fig.subplots_adjust(wspace=0, hspace=0) 

并为每一个轴对象集:

ax.set_xticklabels([]) 
ax.set_yticklabels([]) 
+1

此解决方案适用于方向设置为auto的子图。对于在这里使用情况下用'imshow'绘制的图像,它会失败。看我的解决方案。 – ImportanceOfBeingErnest

+0

感谢您的回复。这确实删除了垂直空间,但水平空间仍然存在...... –