【问题标题】:python matplotlib's gridspec unable to reduce gap between subplotspython matplotlib的gridspec无法减少子图之间的差距
【发布时间】:2020-07-16 21:12:32
【问题描述】:

我正在使用 GridSpec 在子图中绘制子图以显示图像。

在下面的示例代码中,我正在创建一个 1x2 子图,其中每个子图轴包含 3x3 子图(第一个子图中的子图)。

3x3 子图基本上显示了将图像切成 9 块排列成 3x3 格式的图像。我不希望图像片段之间有任何间距,因此我将 wspacehspace 都设置为 0。奇怪的是,生成的输出子图显示了行之间的垂直间隙。

我尝试将hspace 设置为负值以减小行之间的垂直间距,但这会导致行重叠。有没有更方便的方法来实现这一点?

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from PIL import Image
from sklearn.datasets import load_sample_image

flower = load_sample_image('flower.jpg')
img = Image.fromarray(flower)
img = img.crop((100, 100, 325, 325))

# Create tiles - cuts image to 3x3 square tiles
n_tiles = 9
tile_size = float(img.size[0]) / 3 # assumes square tile
tiles = [None] * n_tiles
for n in range(n_tiles):
    row = n // 3 
    col = n % 3

    # compute tile coordinates in term of the image (0,0) is top left corner of the image
    left = col * tile_size
    upper = row * tile_size
    right = left + tile_size
    lower = upper + tile_size
    tile_coord = (int(left), int(upper), int(right), int(lower))
    tile = img.crop(tile_coord)
    tiles[n] = tile
    
# plot subplot of subplot using gridspec
fig = plt.figure(figsize=(7, 3))
outer = gridspec.GridSpec(1, 3, wspace=1)

# image shown as 3x3 grid of image tiles
inner = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=outer[0], wspace=0, hspace=0)
for j in range(len(tiles_tensor)):
    ax1 = plt.Subplot(fig, inner[j], xticks=[], yticks=[])
    ax1.imshow(tiles[j])
    fig.add_subplot(ax1)

# image shown as 3x3 grid of image tiles
inner = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=outer[1], wspace=0, hspace=0)
for j in range(len(data)):
    ax2 = plt.Subplot(fig, inner[j], xticks=[], yticks=[])
    ax2.imshow(tiles[j])
    fig.add_subplot(ax2)

【问题讨论】:

  • 只是把它扔在那里...我更喜欢使用 plt.axes 来制作子图,您可以明确说明大小 plt.axes(left,bottom,width,height)

标签: python matplotlib subplot


【解决方案1】:

主要问题是imshow 默认为aspect='equal'。这迫使小瓷砖是方形的。但是子图不是正方形的,所以 9 个正方形图块并不能很好地填充子图。

一个简单的解决方案是通过imshow(..., aspect='auto') 关闭正方形纵横比。为了更准确地获得子图,可以调整 topbottomleftright 设置。

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from PIL import Image
from sklearn.datasets import load_sample_image

flower = load_sample_image('flower.jpg')
img = Image.fromarray(flower)
img = img.crop((100, 100, 325, 325))

# Create tiles - cuts image to 3x3 square tiles
n_tiles = 9
tile_size = float(img.size[0]) / 3  # assumes square tile
tiles = [None] * n_tiles
for n in range(n_tiles):
    row = n // 3
    col = n % 3

    # compute tile coordinates in term of the image (0,0) is top left corner of the image
    left = col * tile_size
    upper = row * tile_size
    right = left + tile_size
    lower = upper + tile_size
    tile_coord = (int(left), int(upper), int(right), int(lower))
    tile = img.crop(tile_coord)
    tiles[n] = tile

# plot subplot of subplot using gridspec
fig = plt.figure(figsize=(7, 3))
outer = gridspec.GridSpec(1, 2, wspace=1, left=0.1, right=0.9, top=0.9, bottom=0.1)

titles = [f'Subplot {j+1}' for j in range(outer.nrows * outer.ncols) ]
for j in range(len(titles)):
    ax = plt.Subplot(fig, outer[j], xticks=[], yticks=[])
    ax.axis('off')
    ax.set_title(titles[j])
    fig.add_subplot(ax)


# image shown as 3x3 grid of image tiles
inner = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=outer[0], wspace=0, hspace=0)
for j in range(len(tiles)):
    ax1 = plt.Subplot(fig, inner[j], xticks=[], yticks=[])
    ax1.imshow(tiles[j], aspect='auto')
    fig.add_subplot(ax1)

# image shown as 3x3 grid of image tiles
inner = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=outer[1], wspace=0, hspace=0)
for j in range(len(tiles)):
    ax2 = plt.Subplot(fig, inner[j], xticks=[], yticks=[])
    ax2.imshow(tiles[j], aspect='auto')
    fig.add_subplot(ax2)

fig.suptitle('Overall title')

plt.show()

【讨论】:

  • 另请注意,GridSpec(1, 3, wspace=1) 创建了 3 个子图,每个子图之间的间隙很大。 outer[2] 在代码中未使用。
  • 是的,当从 1x3 网格变为 1x2 网格时,我忘记更新了。感谢您指出这一点。
  • 您是否知道我如何为外部网格设置一个标题(一个主要的整体标题),然后为每个内部网格设置一个标题(2 个标题,在本例中每个内部网格上方一个) ?
  • 目前我正在做一些非常hacky的事情,比如fig.suptitle(f"Main Title\n {'Title Image 1':^50} {'Title Image2':^50}", x=0.5, y=1.2)
  • 我用一种添加标题的方式更新了代码,但它也很hacky。如果外部级别不需要多行,那么您的方法肯定是有效的。一般来说,一旦超出plt.subplots 的标准布局,就必须手动控制位置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 2021-08-17
  • 1970-01-01
  • 2021-10-17
  • 2023-03-19
相关资源
最近更新 更多