I have a very large code which outputs several plots, one for each function it runs. I save all these plots in a single output .png
file. Depending on the situation, sometimes the code will save plots from all functions and other times just a few of them.
One of these plots includes a colorbar which I want positioned in the same place inside said plot no matter if all the functions were processed or if only a few of them were.
I've tried everything I could think of but I just can't stop the colorbar from moving around in the .png
final output file when it contains only a few plots (more precisely: when the plots below the one that contains the colorbar are not generated).
Here's a picture to show what I mean:
The MWE
is below. To generate the first file I plotted everything and for the second one I just commented out the last eight ax*
blocks.
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()
This MWE
reproduces the way I generate the output .png
file in my actual code, hence the apparently unnecessarily large code.
Since the colorbar is positioned according to the position of the ax18
plot, I'd expect it to always be correctly positioned in the right place inside it but clearly that's not what I'm getting.
I just want that colorbar to be fixed inside the ax18
plot no matter how many other plots I generate around it. Is this possible?
Add
Ok, so I've narrowed down the issue to the fig.tight_layout()
call. When this is commented out the colorbar stays perfectly in position no matter how many plots are produced. The downside of this is that the final image looks that much worse, with adjacent plots' axes overlapping.
Is there a way to keep fig.tight_layout()
on and still get the colorbar position correctly?