I want to set a grid of subplots that should all be the same size and aspect ratio. However, I am mixing pcolor plots and normal plots. The pcolor plots have a fixed aspect ratio, so that pixels are square, and I want the regular plots to conform to that aspect ratio. I am trying to use constrained_layout=True
to enforce the dimensions of the plots, but they are either too wide or too high.
import matplotlib.pyplot as plt
import numpy as np
# Running this in jupyter
%matplotlib inline
# Generating some random data to display
width, height = 265, 200 # dimensions of my "picture"
color_data = np.random.rand(height, width)
plot_data = np.random.rand(40)
# Creating the figure and subplots
fig, axes = plt.subplots(6, 2, figsize=(8,11), constrained_layout=True)
[[ax1, ax2], [ax3, ax4], [ax5, ax6], [ax7, ax8], [ax9, ax10], [ax11, ax12]] = axes
for ax in [ax1, ax2, ax3, ax5, ax7, ax9, ax11]:
art = ax.pcolor(color_data, vmin=0, vmax=1)
# Every plot gets its own color bar, this is intended because I want
# to mix different color plots of the same aspect ratio
plt.colorbar(art, ax=ax, label='z',fraction=0.046, pad=0.04)
ax.grid(False)
ax.set_aspect(height/width)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.invert_yaxis()
for ax in [ax4, ax6, ax8, ax10, ax12]:
ax.plot(np.arange(len(plot_data)), plot_data, color='blue', linewidth=2)
ax.set_xlabel('index')
ax.set_ylabel('value')
Resulting Plot, figsize=(8,11) :
six colorplots mixed with four regular plots, the regular plots are too wide
The same plot, figsize=(10,20):
shows that plot height depends on the color bars
The layout depends heavily on the figure size, which I find weird. I expect the constrained_layout
to recognise that the aspect ratio is fixed by the color plots, then place the regular plots with the same aspect ratio, then add the color bars.
Instead, the plots are wider than the top-right color plot, and as high as the color bars to their left, instead of being as high as the color plots to their left.
I encourage you to play around with the figure size a bit.
What I would like to happen: All plots are the same height and width and arranged in a neat grid, with colorbars of the same height next to those plots that need them.
The loops are simply for brevity. In the final product, I would like to assign each plot's content and/or color map separately, but I want the aspect ratio to stay the same.
Your pcolor plots have a fixed aspect ratio. Use layout='compressed'
to deal with this (https://matplotlib.org/stable/users/explain/axes/constrainedlayout_guide.html#grids-of-fixed-aspect-ratio-axes-compressed-layout)
import matplotlib.pyplot as plt
import numpy as np
# Generating some random data to display
width, height = 265, 200 # dimensions of my "picture"
color_data = np.random.rand(height, width)
plot_data = np.random.rand(40)
# Creating the figure and subplots
fig, axes = plt.subplots(6, 2, figsize=(8,11), layout='compressed')
[[ax1, ax2], [ax3, ax4], [ax5, ax6], [ax7, ax8], [ax9, ax10], [ax11, ax12]] = axes
for ax in [ax1, ax2, ax3, ax5, ax7, ax9, ax11]:
art = ax.pcolor(color_data, vmin=0, vmax=1)
# Every plot gets its own color bar, this is intended because I want
# to mix different color plots of the same aspect ratio
plt.colorbar(art, ax=ax, label='z',fraction=0.046, pad=0.04)
ax.grid(False)
ax.set_aspect(height/width)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.invert_yaxis()
for ax in [ax4, ax6, ax8, ax10, ax12]:
ax.plot(np.arange(len(plot_data)), plot_data, color='blue', linewidth=2)
ax.set_xlabel('index')
ax.set_ylabel('value')
plt.show()