I want a grid figure with m rows and n columns to be displayed sharing both x and y axis between subplots, and no whitespace between them. This is easy to achieve with simple plot in matplotlib, as with this code
def plot_me():
n = 4
m = 5
f, axs = plt.subplots(m,n, sharex=True, sharey=True, gridspec_kw=dict(hspace=0, wspace=0))
x = np.arange(44)
for i in range(m):
for j in range(n):
axs[i,j].plot(np.sin(x*(i*j+1)))
but when I change axs[i,j].plot()
to axs[i,j].imshow()
then there is a vertical whitespace between the columns, but not a horizontal one! Why is that?
def imshow_me():
n = 4
m = 5
f, axs = plt.subplots(m,n, sharex=True, sharey=True, gridspec_kw=dict(hspace=0, wspace=0))
for i in range(m):
for j in range(n):
axs[i, j].imshow(np.random.random((100, 100)))
I also tried with f.subplots_adjust(wspace=0, hspace=0)
but with the same result.
And also with mosaic plot, and again in one axis there is no whitespace, while in the other is.
I'm using Python 3.11.2 in visual studio code 1.78.2, matplotlib 3.7.1
Thanks in advance.
EDIT, as with @jared linked thread Matplotlib adjust image subplots hspace and wspace does not raise the specific issue of imshow
compared to simple plot
, nor are the answerd there satisfactory solving the issue.
What solved the issue for me is using pcolormesh
, as per @jared comment. Alternatively, as explained by @gboffi one can force the plot h/w ratio to be exactly 1.5 to avoid whitespaces
imshow
is for images, and images usually are represented in terms of SQUARE pixels.
If an image is 200 px wide and 300 px high, Matplotlib places, let's say, on the screen a rectangle with an aspect ratio of 1.5 (the actual pixel count not being 200x300), and later draws the axes frame, complete with spines, labels etc, fitting the displayed image or, in your case, just the frame.
If so it happens that the aspect ratio (h/w) of the subplots is exactly 1.5, and I mean exactly 1.5 after the figure size, the axes ticks, the tick labels, the titles, etc are taken into account, then everything fits, otherwise...
Ultimately, the unwanted white space is added horizontally if the figsize
is too wide or horizontally if the figsize
is too tall, as shown in the following example:
import matplotlib.pyplot as plt
mat = [[i for i in range(j, j+10)] for j in range(10)]
fig0, axs0 = plt.subplots(2, 2, edgecolor='k', linewidth=1,
figsize=(6,2), gridspec_kw=dict(hspace=0, wspace=0))
for ax in axs0.flatten(): ax.imshow(mat)
fig1, axs1 = plt.subplots(2, 2, edgecolor='k', linewidth=1,
figsize=(4,6), gridspec_kw=dict(hspace=0, wspace=0))
for ax in axs1.flatten(): ax.imshow(mat)
plt.show()
PS In a comment Jared correctly suggested the use of pcolormesh
. pcolormesh
has a different approach and treats the not-an-image as stretchable, hence it can make it fit inside the elements of the grid.
PS2 In other words, when you use imshow
matplotlib fits the subplot around a fixed shape image, when you use pcolormesh
Matplotlib distorts the image to fit inside a fixed shape subplot.