2

I would like to create a plot with 3 subplots. This plot should have a common y and common x label I followed: Common xlabel/ylabel for matplotlib subplots.

I am however changing the aspect ratio aspect=0.5 and this results in the x-label being too far from the plot. Do you know how to fix this?

enter image description here

> Minimal Reproducible Example here:

import numpy as np
import matplotlib.pyplot as plt

# Get Data 
data1 = np.random.rand(100,100)
data2 = np.random.rand(100,100)
data3 = np.random.rand(100,100)
data = [data1,data2,data3]
# Create Figure
fig, axes = plt.subplots(nrows=1, ncols=3, sharex=True, sharey=True)
for i,ax in enumerate(axes.flat):
    im = ax.imshow(data[i], origin="lower", interpolation='quadric', cmap='jet', extent=[50,250,0,400], aspect=0.5, vmin=0, vmax = 1)


cbar_ax = fig.add_axes([1, 0.35, 0.01, 0.3])
fig.colorbar(im, cax=cbar_ax) # orientation='horizontal'
fig.tight_layout(pad=0.7)

## add a big axis, hide frame
fig.add_subplot(111, frameon=False)
## hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")


plt.show()
henry
  • 875
  • 1
  • 18
  • 48
  • 1
    There is of course `plt.xlabel("common X", labelpad=n)`, which takes negative n-values - but it is an absolute value. – Mr. T Oct 24 '20 at 10:46

2 Answers2

3

Here is a solution. The idea is to create a big axis with actual extremal positions of the set of subplots. This should be flexible with different subplot settings.

common label row subplots

import numpy as np
import matplotlib.pyplot as plt

# Get Data
data1 = np.random.rand(100,100)
data2 = np.random.rand(100,100)
data3 = np.random.rand(100,100)
data = [data1,data2,data3]
# Create Figure
fig, axes = plt.subplots(nrows=1, ncols=3, sharex=True, sharey=True)
for i,ax in enumerate(axes.flat):
    im = ax.imshow(data[i], origin="lower", interpolation='quadric', cmap='jet', extent=[50,250,0,400], aspect=0.5, vmin=0, vmax = 1)


cbar_ax = fig.add_axes([1, 0.35, 0.01, 0.3])
fig.colorbar(im, cax=cbar_ax) # orientation='horizontal'
fig.tight_layout(pad=1.5)

# Get extents of subplot
x0 = min([ax.get_position().x0 for ax in axes])
y0 = min([ax.get_position().y0 for ax in axes])
x1 = max([ax.get_position().x1 for ax in axes])
y1 = max([ax.get_position().y1 for ax in axes])

# Hidden axes for common x and y labels
plt.axes([x0, y0, x1 - x0, y1 - y0], frameon=False)
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)

# Labelize
plt.xlabel("common X")
plt.ylabel("common Y")
plt.title('Common Title')

plt.show()
# plt.savefig("example.png", bbox_inches="tight")  # save figure
Leonard
  • 2,510
  • 18
  • 37
  • 1
    Every time I try to export the fig (fig.savefig(...)), the colorbar is not exported. Do you have any idea why? – henry Oct 25 '20 at 10:40
  • Yes, I had to export it with `plt.savefig('figure.png', bbox_inches='tight')` in order to make the colorbar visible. If you want to avoid this issue, you may want to create axes with manual position. This could be also cause by the `tight_layout` function with the `sharex` and `shared` options to `True` at the same time in `subplots`. I added the solution in the answer. – Leonard Oct 25 '20 at 20:32
  • Great ! Thank you so much !! – henry Oct 25 '20 at 20:42
1

Since you already defined a subplot, you can set its ratio as well:

## add a big axis, hide frame
allax = fig.add_subplot(111, frameon=False)
allax.set_aspect(.3) #slightly smaller than 1/3 because of the colorbar
Mr. T
  • 11,960
  • 10
  • 32
  • 54
  • Hey, thanks a lot for your answer. I just have trouble seeing where I should place your code within my code? – henry Oct 25 '20 at 10:14
  • I just copied your code and modified it a bit - I thought your "## add a big axis, hide frame" part gave it away. – Mr. T Oct 25 '20 at 10:37
  • Sorry, just realized that too ! Thanks! :) Another question, every time I try to export the fig (fig.savefig(...)), the colorbar is not exported. Do you have any idea why? – henry Oct 25 '20 at 10:40
  • Independent of the file format? Matplotlib behaves sometimes differently depending on the file format. But sounds like a new question. – Mr. T Oct 25 '20 at 11:02
  • yes, independently of the file format. Okay, I will post a new question this evening. Thanks! – henry Oct 25 '20 at 11:12