放置图像,保持相对大小#

默认情况下,Matplotlib 会对使用 imshow 创建的图像进行重采样,以使其适应父 Axes。这意味着原始尺寸差异很大的图像最终可能看起来大小相似。

本示例展示了如何保持图像的相对大小,或如何使图像保留与原始数据完全相同的像素。

保持相对大小#

默认情况下,尽管其中一张图像的宽度是另一张的 1.5 倍,但两张图像被调整为相似的大小。

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.patches as mpatches

# make the data:
N = 450
x = np.arange(N) / N
y = np.arange(N) / N

X, Y = np.meshgrid(x, y)
R = np.sqrt(X**2 + Y**2)
f0 = 5
k = 100
a = np.sin(np.pi * 2 * (f0 * R + k * R**2 / 2))
A = a[:100, :300]
B = A[:40, :200]

# default layout: both axes have the same size
fig, axs = plt.subplots(1, 2, facecolor='aliceblue')

axs[0].imshow(A, vmin=-1, vmax=1)
axs[1].imshow(B, vmin=-1, vmax=1)


def annotate_rect(ax):
    # add a rectangle that is the size of the B matrix
    rect = mpatches.Rectangle((0, 0), 200, 40, linewidth=1,
                              edgecolor='r', facecolor='none')
    ax.add_patch(rect)
    return rect

annotate_rect(axs[0])
image exact placement

请注意,两张图像的长宽比均为 1(即像素为正方形),但由于图像被缩放到相同的宽度,它们的像素大小有所不同。

如果图像尺寸适宜,我们可以通过使用子图的 width_ratio(宽度比)或 height_ratio(高度比)来保持两张图像的相对大小。具体使用哪一个取决于图像的形状和图形的尺寸。如果图像的宽度大于高度且并排显示(如本例所示),我们可以通过 width_ratios 参数来控制相对大小。

在进行更改的同时,让我们使用 figsize 使图形的长宽比更接近坐标轴的长宽比,从而减少图形中多余的空白空间。请注意,保存图形时,您也可以通过向 savefig 传递 bbox_inches="tight" 来修剪多余的空白空间。

fig, axs = plt.subplots(1, 2, width_ratios=[300/200, 1],
                        figsize=(6.4, 2), facecolor='aliceblue')

axs[0].imshow(A, vmin=-1, vmax=1)
annotate_rect(axs[0])

axs[1].imshow(B, vmin=-1, vmax=1)
image exact placement

考虑到数据子样本位于较大图像的左上角,如果较小 Axes 的顶部与较大 Axes 的顶部对齐,可能会更合理。这可以通过使用 set_anchor 并设置 "NW"(西北,即左上)来手动实现。

fig, axs = plt.subplots(1, 2, width_ratios=[300/200, 1],
                        figsize=(6.4, 2), facecolor='aliceblue')

axs[0].imshow(A, vmin=-1, vmax=1)
annotate_rect(axs[0])

axs[0].set_anchor('NW')
axs[1].imshow(B, vmin=-1, vmax=1)
axs[1].set_anchor('NW')
image exact placement

显式放置#

上述调整 figsizewidth_ratios 的方法通用性不强,因为它需要手动调整参数,甚至可能需要根据图像的比例和布局将代码改为使用 height_ratios 而非 width_ratios

我们可以选择显式计算位置,并使用 add_axes 将 Axes 放置在绝对坐标处。这采用 [左 高] 格式的位置参数,并使用 图形坐标。在下文中,我们确定了图形尺寸和 Axes 位置,以便一个图像数据点正好渲染为一个图形像素。

dpi = 100  # 100 pixels is one inch

# All variables from here are in pixels:
buffer = 0.35 * dpi  # pixels

# Get the position of A axes
left = buffer
bottom = buffer
ny, nx = np.shape(A)
posA = [left, bottom, nx, ny]
# we know this is tallest, so we can already get the fig height (in pixels)
fig_height = bottom + ny + buffer

# place the B axes to the right of the A axes
left = left + nx + buffer

ny, nx = np.shape(B)
# align the bottom so that the top lines up with the top of the A axes:
bottom = fig_height - buffer - ny
posB = [left, bottom, nx, ny]

# now we can get the fig width (in pixels)
fig_width = left + nx + buffer

# figsize must be in inches:
fig = plt.figure(figsize=(fig_width / dpi, fig_height / dpi), facecolor='aliceblue')

# the position posA must be normalized by the figure width and height:
ax = fig.add_axes((posA[0] / fig_width, posA[1] / fig_height,
                   posA[2] / fig_width, posA[3] / fig_height))
ax.imshow(A, vmin=-1, vmax=1)
annotate_rect(ax)

ax = fig.add_axes((posB[0] / fig_width, posB[1] / fig_height,
                   posB[2] / fig_width, posB[3] / fig_height))
ax.imshow(B, vmin=-1, vmax=1)
plt.show()
image exact placement

检查该图像会发现它正好是 3* 35 + 300 + 200 = 605 像素宽,170 像素高(如果浏览器使用了 2 倍版本,则为该值的两倍)。图像应以每个数据点正好 1 个像素(如果为 2 倍,则为 4 个)的比例进行渲染。

参考

本示例展示了以下函数、方法、类和模块的使用

标签:组件:图形 组件:坐标轴 样式:位置 绘图类型:图像

脚本总运行时间:(0 分 1.013 秒)

由 Sphinx-Gallery 生成的画廊