无法使用多个子图修复图像中颜色条的位置

时间:2014-03-14 18:41:12

标签: python matplotlib plot colorbar

我有一个非常大的代码输出几个图,每个图运行一个函数。我将所有这些图保存在单个输出.png文件中。根据具体情况,有时代码会保存来自所有函数的图表,有时只会保存其中的一些。

其中一个图包括一个颜色条,我想放在同一个地方里面所说的情节,无论是否所有的功能都被处理过,或者只有少数功能被处理过。

我已经尝试了我能想到的一切,但是我只是在.png最终输出文件只包含几个图(更确切地说:不会生成包含颜色条的图下面的图。)

这是一张显示我的意思的图片:

enter image description here

MWE如下。为了生成第一个文件,我绘制了所有内容,而对于第二个文件,我只是注释掉了最后八个ax*块。

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

# Generate random data.
x = np.random.randn(60)
y = np.random.randn(60)
z = [np.random.random() for _ in range(60)]

fig = plt.figure(figsize=(20, 35))  # create the top-level container
gs = gridspec.GridSpec(14, 8)  # create a GridSpec object

ax0 = plt.subplot(gs[0:2, 0:2])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax1 = plt.subplot(gs[0:2, 2:4])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax2 = plt.subplot(gs[0:2, 4:6])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax3 = plt.subplot(gs[0:2, 6:8])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax4 = plt.subplot(gs[2:4, 0:2])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax5 = plt.subplot(gs[2:4, 2:4])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax6 = plt.subplot(gs[2:4, 4:6])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax7 = plt.subplot(gs[2:4, 6:8])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax8 = plt.subplot(gs[4:6, 0:2])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax9 = plt.subplot(gs[4:6, 2:4])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax10 = plt.subplot(gs[4:6, 4:6])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax11 = plt.subplot(gs[4:6, 6:8])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax12 = plt.subplot(gs[6:8, 0:2])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax13 = plt.subplot(gs[6:8, 2:4])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax14 = plt.subplot(gs[6:8, 4:6])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax15 = plt.subplot(gs[6:8, 6:8])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax16 = plt.subplot(gs[8:10, 0:2])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax17 = plt.subplot(gs[8:10, 2:4])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax18 = plt.subplot(gs[8:10, 4:6])
cm = plt.cm.get_cmap('RdYlBu_r')
plt.scatter(x, y, s=20, c=z, cmap=cm, vmin=0, vmax=1)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)
# Plot colorbar.
box = ax18.get_position()
cbar_posit = [box.x1 * 0.93, box.y1 * 0.94, 0.04, 0.005]
cbaxes = fig.add_axes(cbar_posit)
cbar = plt.colorbar(cax=cbaxes, ticks=[0, 1], orientation='horizontal')
cbar.ax.tick_params(labelsize=9)

ax19 = plt.subplot(gs[8:10, 6:8])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax20 = plt.subplot(gs[10:12, 0:2])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax21 = plt.subplot(gs[10:12, 2:4])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax22 = plt.subplot(gs[10:12, 4:6])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax23 = plt.subplot(gs[10:12, 6:8])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax24 = plt.subplot(gs[12:14, 0:2])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax25 = plt.subplot(gs[12:14, 2:4])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax26 = plt.subplot(gs[12:14, 4:6])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

ax27 = plt.subplot(gs[12:14, 6:8])
plt.scatter(x, y, s=20)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)

fig.tight_layout()

out_png = 'colorbar.png'
plt.savefig(out_png, dpi=150)
plt.close()

这个MWE再现了我在实际代码中生成输出.png文件的方式,因此显然是不必要的大代码。

由于颜色条根据ax18图的位置定位,我希望它始终正确定位在其中的正确位置,但显然不是我&# 39;得到。

我只是希望在ax18图中 fixed ,无论我在其周围生成多少个图。这可能吗?


添加

好的,我已将问题缩小到fig.tight_layout()电话。当这被注释掉时,无论生成多少个图,颜色条都保持完美的位置。这样做的缺点是最终的图像看起来更糟糕,相邻的情节'轴重叠。

有没有办法让fig.tight_layout()开启并仍能正确获取色条位置?

1 个答案:

答案 0 :(得分:3)

我认为有几个问题。

如果我理解正确,您希望颜色条相对于嵌入的轴处于固定位置

fig.tight_layout()移动常规'轴绕。通过'定期'我的意思是颜色条是您手动创建的轴,会受此功能的影响。 AFAIK,没有任何方法可以将一个轴固定到另一个轴上,这样如果移动第一个轴,第二个也会移动以保持其相对位置。这需要我指出您需要在调用tight_layout 后设置颜色条的位置。

然而,您仍然会遇到问题,因为您需要以绝对值设置色条的位置,而您需要相对于轴的固定位置。 您需要指定轴的实际位置。

你会怎么做:

## ...
## ...
## Your MWE starts up there...

ax18 = plt.subplot(gs[8:10, 4:6])
cm = plt.cm.get_cmap('RdYlBu_r')
sca = plt.scatter(x, y, s=20, c=z, cmap=cm, vmin=0, vmax=1)
plt.ylabel('$L$', fontsize=16)
plt.xlabel('$E$', fontsize=16)
# Plot colorbar.
#box = ax18.get_position()
#cbar_posit = [box.x1 * 0.93, box.y1 * 0.94, 0.04, 0.005]
#cbaxes = fig.add_axes(cbar_posit)
#cbar = plt.colorbar(cax=cbaxes, ticks=[0, 1], orientation='horizontal')
#cbar.ax.tick_params(labelsize=9)

## You keep creating and filling axes...
## ...
## ...

请注意,我在sca中保存了散点图的返回值。我们需要它用于颜色条。此外,您可以删除评论的行,只是为了表明您不再需要它们。

然后,在您的脚本结束时,您可以创建de colorbar,指定其在轴内的位置和大小

## ...
## ...
## All the plots are created above...

fig.tight_layout()  # You call fig.tight_layout BEFORE creating the colorbar

import matplotlib
# You input the POSITION AND DIMENSIONS RELATIVE TO THE AXES
x0, y0, width, height = [0.6, 0.9, 0.2, 0.04]

# and transform them after to get the ABSOLUTE POSITION AND DIMENSIONS
Bbox = matplotlib.transforms.Bbox.from_bounds(x0, y0, width, height)
trans = ax18.transAxes + fig.transFigure.inverted()
l, b, w, h = matplotlib.transforms.TransformedBbox(Bbox, trans).bounds

# Now just create the axes and the colorbar
cbaxes = fig.add_axes([l, b, w, h])
cbar = plt.colorbar(sca, cax=cbaxes, ticks=[0, 1], orientation='horizontal')
cbar.ax.tick_params(labelsize=9)

out_png = 'colorbar.png'
plt.savefig(out_png, dpi=150)
plt.close()

我很久以前从SO的答案中得到了坐标转换的代码,并将其保存在一些脚本中。我试着相信这个答案,但我再也找不到了,抱歉。