matplotlib 子图最后一个图扰乱了对数比例

matplotlib subplots last plot disturbs log scale

我正在制作一个 matplotlib 尺寸为 2x2 的图形,其中共享 x 轴和 y 轴,然后循环遍历不同的轴以在其中绘制。我正在绘制每个样本的变体数据,样本可能没有变体数据,所以我希望绘图在中间显示“NA”。

import matplotlib.pyplot as plt

n_plots_per_fig = 4
nrows = 2
ncols = 2

fig, axs = plt.subplots(nrows, ncols, sharex="all", sharey="all", figsize=(8, 6))
axs = axs.ravel()

for i, ax in enumerate(axs):
    x = [1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]  # example values, but this list CAN be empty
    bins = 3  # example bins
    if x: 
        ax.hist(x, bins=bins)  # plot the hist
        ax.set_yscale("log")
        ax.set_title(str(i), fontsize="medium")
    else:
        ax.set_title(str(i), fontsize="medium")
        ax.text(0.5, 0.5, 'NA', ha='center', va='center', transform=ax.transAxes)

fig.show()

这几乎适用于所有情况;想要的输出示例:

但是,只有当图中的最后一个图没有任何数据时,才会扰乱对数刻度。触发此操作的示例代码:

import matplotlib.pyplot as plt

n_plots_per_fig = 4
nrows = 2
ncols = 2

fig, axs = plt.subplots(nrows, ncols, sharex="all", sharey="all", figsize=(8, 6))
axs = axs.ravel()

for i, ax in enumerate(axs):
    x = [1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
    bins = 3

    if i == n_plots_per_fig-1:  # this will distort the log scale
        ax.set_title(str(i), fontsize="medium")
        ax.text(0.5, 0.5, 'NA', ha='center', va='center', transform=ax.transAxes)
    elif x:
        ax.hist(x, bins=bins)  # plot the hist
        ax.set_yscale("log")
        ax.set_title(str(i), fontsize="medium")
    else:
        ax.set_title(str(i), fontsize="medium")
        ax.text(0.5, 0.5, 'NA', ha='center', va='center', transform=ax.transAxes)

fig.show()

对数刻度现在设置为非常低的值,这不是我想要的。我已经尝试了几种方法来解决这个问题,比如取消共享没有任何数据的图的 y 轴 [ax.get_shared_y_axes().remove(axis) for axis in axs] 或隐藏图 ax.set_visible(False),但是 none 这个作品. 的一件事是使用 ax.remove() 从绘图中删除轴,但由于这是最底部的样本,这也删除了 x 刻度的值柱子:

除此之外,我仍然希望没有任何数据的样本的名称在轴(和“NA”文本)中可见,并且删除轴不允许这样做。

关于修复的任何想法?

编辑:我简化了示例。

您可以使用 ax.set_xlim() / ax.set_ylim() 手动设置限制。 请注意,如果您共享轴,则在哪个子图中调用这些函数并不重要。例如:

axs[-1][-1].set_ylim(1e0, 1e2)

如果你之前不知道极限,你可以从其他图中推断出来:

x = np.random.random(100)
bins = 10
if bins != 0:
    ...
    yy, xx = np.histogram(x, bins=bins)
    ylim = yy.min(), yy.max()
    xlim = xx.min(), xx.max()
else:
   ax.set_xlim(xlim)
   ax.set_ylim(ylim)