Subplots with common x and y labels and a common legend under the x-axis
Question:
I am trying to plot a subplot with a common legend displayed at the bottom of the figure below a common x axis label, and with a common y-axis label. I have two ways of almost getting it working, except the first has the common y-axis label overlapping the axis tick labels, while with the second I can’t figure out how to get the legend to show on the plot (it hangs off the page).
Option 2, using the newer supx/ylabel, puts too much space between the subplots and the labels as well – but I think that is fixable (quite a few questions on that one).
These are just example plots, actual plots use more decimals places in the labels, so the overlap is considerable. I will likely also be setting the figure sizes to print (and save) the plots was well.
MWE
import numpy as np
import matplotlib.pyplot as plt
# Some points to plot
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
z = np.sin((1.03* x) ** 2)
#option 1 - problem is with my real data the common y label is over the labels of the left hand plot
fig, axs = plt.subplots(2, 2)
axs[0, 0].plot(x, y)
axs[0, 0].plot(x, z, '--')
axs[0, 1].plot(x, y)
axs[0, 1].plot(x, z, '--')
axs[1, 0].plot(x, -y)
axs[1, 0].plot(x, -z, '--')
axs[1, 1].plot(x, -y)
axs[1, 1].plot(x, -z, '--')
fig.add_subplot(111, frameon=False)
plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
plt.xlabel("The X label")
plt.ylabel("The Y label")
fig.subplots_adjust(bottom=0.2)
labels = ["A","B"]
fig.legend(labels,loc='lower center', ncol=len(labels), bbox_to_anchor=(0.55, 0))
fig.tight_layout()
# Option 2 - problem is I can't get the legend to show (it is off the page)
fig, axs = plt.subplots(2, 2)
axs[0, 0].plot(x, y)
axs[0, 0].plot(x, z, '--')
axs[0, 1].plot(x, y)
axs[0, 1].plot(x, z, '--')
axs[1, 0].plot(x, -y)
axs[1, 0].plot(x, -z, '--')
axs[1, 1].plot(x, -y)
axs[1, 1].plot(x, -z, '--')
fig.supxlabel("The X label")
fig.supylabel("The Y label")
fig.subplots_adjust(bottom=0.2)
labels = ["A","B"]
fig.legend(labels,loc='lower center', ncol=len(labels), bbox_to_anchor=(0.55, 0))
fig.tight_layout()
Answers:
You were almost there with your first option, adding labelpad
to the ax.set_xlabel()
and ax.set_ylabel()
calls should fix your issue.
Here is an updated version.
# [...]
fig, axs = plt.subplots(2, 2, figsize=(16, 8), tight_layout=True)
# [...]
# Create the new axis for marginal X and Y labels
ax = fig.add_subplot(111, frameon=False)
# Disable ticks. using ax.tick_params() works as well
ax.set_xticks([])
ax.set_yticks([])
# Set X and Y label. Add labelpad so that the text does not overlap the ticks
ax.set_xlabel("The X label", labelpad=20, fontsize=12)
ax.set_ylabel("The Y label", labelpad=40, fontsize=12)
# Set fig legend as you did
labels = ["A","B"]
fig.legend(labels, loc='lower center', ncol=len(labels), bbox_to_anchor=(0.55, 0))
I am trying to plot a subplot with a common legend displayed at the bottom of the figure below a common x axis label, and with a common y-axis label. I have two ways of almost getting it working, except the first has the common y-axis label overlapping the axis tick labels, while with the second I can’t figure out how to get the legend to show on the plot (it hangs off the page).
Option 2, using the newer supx/ylabel, puts too much space between the subplots and the labels as well – but I think that is fixable (quite a few questions on that one).
These are just example plots, actual plots use more decimals places in the labels, so the overlap is considerable. I will likely also be setting the figure sizes to print (and save) the plots was well.
MWE
import numpy as np
import matplotlib.pyplot as plt
# Some points to plot
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
z = np.sin((1.03* x) ** 2)
#option 1 - problem is with my real data the common y label is over the labels of the left hand plot
fig, axs = plt.subplots(2, 2)
axs[0, 0].plot(x, y)
axs[0, 0].plot(x, z, '--')
axs[0, 1].plot(x, y)
axs[0, 1].plot(x, z, '--')
axs[1, 0].plot(x, -y)
axs[1, 0].plot(x, -z, '--')
axs[1, 1].plot(x, -y)
axs[1, 1].plot(x, -z, '--')
fig.add_subplot(111, frameon=False)
plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
plt.xlabel("The X label")
plt.ylabel("The Y label")
fig.subplots_adjust(bottom=0.2)
labels = ["A","B"]
fig.legend(labels,loc='lower center', ncol=len(labels), bbox_to_anchor=(0.55, 0))
fig.tight_layout()
# Option 2 - problem is I can't get the legend to show (it is off the page)
fig, axs = plt.subplots(2, 2)
axs[0, 0].plot(x, y)
axs[0, 0].plot(x, z, '--')
axs[0, 1].plot(x, y)
axs[0, 1].plot(x, z, '--')
axs[1, 0].plot(x, -y)
axs[1, 0].plot(x, -z, '--')
axs[1, 1].plot(x, -y)
axs[1, 1].plot(x, -z, '--')
fig.supxlabel("The X label")
fig.supylabel("The Y label")
fig.subplots_adjust(bottom=0.2)
labels = ["A","B"]
fig.legend(labels,loc='lower center', ncol=len(labels), bbox_to_anchor=(0.55, 0))
fig.tight_layout()
You were almost there with your first option, adding labelpad
to the ax.set_xlabel()
and ax.set_ylabel()
calls should fix your issue.
Here is an updated version.
# [...]
fig, axs = plt.subplots(2, 2, figsize=(16, 8), tight_layout=True)
# [...]
# Create the new axis for marginal X and Y labels
ax = fig.add_subplot(111, frameon=False)
# Disable ticks. using ax.tick_params() works as well
ax.set_xticks([])
ax.set_yticks([])
# Set X and Y label. Add labelpad so that the text does not overlap the ticks
ax.set_xlabel("The X label", labelpad=20, fontsize=12)
ax.set_ylabel("The Y label", labelpad=40, fontsize=12)
# Set fig legend as you did
labels = ["A","B"]
fig.legend(labels, loc='lower center', ncol=len(labels), bbox_to_anchor=(0.55, 0))