使用 imshow 将空格添加到 Matplotlib 热图中

Adding whitespace to Matplotlib heatmap using imshow

我正在使用 Matplotlib 的 imshow 将数据绘制为两个变量的函数,其中之一是时间。在许多情况下,数据收集存在重大中断,我想指出的是,在图表上使用空格(或类似的东西)分隔它们之间有失误的数据。但是,我很难将其付诸实践。我插入了一个由 NaN 值组成的虚拟数据行,在彩色地图上绘制为白色。问题在于视觉外观。我正在使用 catrom 插值来创建热图,这会导致比我想要的更宽的空白。使用其他插值方案不会产生我满意的图。

我无法提供 MWE,因为我的数据足够大,我无法提供它,而且我没有时间创建可以充分显示这一点的虚拟数据集。但是,我可以提供我用来创建图表本身及其输出的代码。这是生成类似于我希望看到的内容的代码:

# Plot the time and phase difference as a color map showing variation over both domains.
img = ax2D.imshow(variance_array, extent=[-0.5, 0.5, float(period_numbers[-1]), 0.0], aspect="auto",
                  interpolation="nearest")
plt.colorbar(img, ax=ax2D, label="Variance", spacing="proportional")
ax2D.minorticks_on()
ax2D.invert_yaxis()

这导致:

然而,它太像素化了!这不是我想在论文中发表的东西的质量,更不用说我的论文了。我以前用来生成这些图像的代码是:

# Plot the time and phase difference as a color map showing variation over both domains.
img = ax2D.imshow(variance_array, extent=[-0.5, 0.5, float(period_numbers[-1]), 0.0], aspect="auto",
                  interpolation="catrom")
plt.colorbar(img, ax=ax2D, label="Variance", spacing="proportional")
ax2D.minorticks_on()
ax2D.invert_yaxis()

这导致:

顺畅多了,但是看看留白多宽啊!它使判断失效数据发生的任何趋势变得更加困难,并且它实际上删除了一些有用的数据。

指示这种数据中断的最佳方式是什么?我是在用最好的方式去做,还是有什么更好的我没有考虑过?如果这是最好的方法,我该如何确定空格的宽度?

对于 matplotlib >= 3.5.0

如果你有 matplotlib 3.5.0 或更高版本,你可以使用 imshow 参数 interpolation_stage 并将其设置为 "rgba" 而不是 "data" 以实现你想要的。

import matplotlib
import matplotlib.pyplot as plt

# Plot the time and phase difference as a color map showing variation over both domains.
fig, (ax2D, ax2D2) = plt.subplots(figsize=plt.figaspect(1.5), ncols=2)
variance_array = np.random.rand(180, 20)

## Mask broken timepoints
# (generate random broken_timepoints)
broken_timepoints = [40, 50, 51, 100, *list(range(160, 163))]
mask = np.full_like(variance_array, 0)
mask[broken_timepoints, :] = 1

variance_array_masked = np.ma.masked_where(mask == 1, variance_array)

img = ax2D.imshow(
    variance_array_masked,
    extent=[-0.5, 0.5, 200, 0.0],
    aspect="auto",
    interpolation="catrom",
    interpolation_stage="data",
)

img2 = ax2D2.imshow(
    variance_array_masked,
    extent=[-0.5, 0.5, 200, 0.0],
    aspect="auto",
    interpolation="catrom",
    interpolation_stage="rgba",
)

ax2D.minorticks_on()
ax2D.axis("off")
ax2D.invert_yaxis()
ax2D2.minorticks_on()
ax2D2.invert_yaxis()
ax2D2.axis("off")
fig.suptitle("DATA vs RGBA")

对于 matplotlib < 3.5.0

您可以尝试的一种技巧是在插值后通过使用 1. 对 imshow 的第二次调用和 2. 仅包含白色值的颜色图在数据上应用伪掩码。

这是一个例子:

import matplotlib
import matplotlib.pyplot as plt

# Plot the time and phase difference as a color map showing variation over both domains.
fig, ax2D = plt.subplots(figsize=plt.figaspect(1.3))
variance_array = np.random.rand(180, 20)

img = ax2D.imshow(variance_array, extent=[-0.5, 0.5, 200, 0.0], aspect="auto",
                  interpolation="catrom", alpha=1)

## Mask broken timepoints
# (generate random broken_timepoints)
broken_timepoints = [40, 50, 51, 100, *list(range(160, 163))]
mask = np.full_like(variance_array, np.nan)
mask[broken_timepoints, :] = 0

# (apply white mask)
white_only_cmap = matplotlib.colors.ListedColormap(["white"])
_ = ax2D.imshow(mask, extent=[-0.5, 0.5, 200, 0.0], aspect="auto",
                interpolation="nearest", alpha=1, cmap=white_only_cmap)

plt.colorbar(img, ax=ax2D, label="Variance", spacing="proportional")
ax2D.minorticks_on()
ax2D.invert_yaxis()