-1

enter image description hereI am trying to plot the legend outside a 2 columns 5 rows, but in this MWE 2 rows example in matplotlib. Turns out the legend to "lower center" puts the space between the two plots as well, which is undesirable. Would anyone have any suggestions to correct this? Ideally default space between the two columns is desired. (have looked at various examples which are a single plot exmamples, moving around bbox_to_anchor, none exists for 2 column ones, atleast to the best of my knowledge)

import numpy as np
import matplotlib.pyplot as plt
[![enter image description here][2]][2]
r2x =np.arange(1,10,1)
rmx =np.arange(1,10,1)

a0_r2_gp = np.random.rand(9)
a0_r2_mf = np.random.rand(9)
a0_r2_mo = np.random.rand(9)

a0_rmse_gp = np.random.randint(0, 60, 9)
a0_rmse_mf = np.random.randint(0, 50, 9)
a0_rmse_mo = np.random.randint(0, 40, 9)

a1_r2_gp = np.random.rand(9)
a1_r2_mf = np.random.rand(9)
a1_r2_mo = np.random.rand(9)

a1_rmse_gp = np.random.randint(0, 30, 9)
a1_rmse_mf =np.random.randint(0, 20, 9)
a1_rmse_mo =np.random.randint(0, 15, 9)

fig, axs = plt.subplots(2, 2, figsize=(8, 12) )
axs[0,0].plot(r2x, np.asarray(a0_r2_gp), marker='o', c = gp_color, label='GP')
axs[0,0].plot(r2x, np.asarray(a0_r2_mf), marker='o', c = mf_color, label='MF')
axs[0,0].plot(r2x, np.asarray(a0_r2_mo), marker='o', c = mo_color, label='MO')
axs[0,0].set_xticks(r2x)
axs[0,0].set_yticks(np.linspace(0,1,11))
axs[0,0].set_ylim(0, 1)
axs[0,0].set_ylabel("r\u00b2, 1st case", fontsize=textfs)

axs[0,1].plot(rmx, np.asarray(a0_rmse_gp), marker='o', c = gp_color, label='GP')
axs[0,1].plot(rmx, np.asarray(a0_rmse_mf), marker='o', c = mf_color, label='MF')
axs[0,1].plot(rmx, np.asarray(a0_rmse_mo), marker='o', c = mo_color, label='MO')
axs[0,1].set_yticks(np.arange(10, 65, 5))
axs[0,1].set_xticks(rmx)
axs[0,1].set_ylim(10, 65)
axs[0,1].set_ylabel("%rmse", fontsize=textfs)
fig.suptitle("r\u00b2 and %rmse averages for Tubes", fontsize=textfs)

axs[1,0].plot(r2x, np.asarray(a1_r2_gp), marker='o', c = gp_color, label='GP')
axs[1,0].plot(r2x, np.asarray(a1_r2_mf), marker='o', c = mf_color, label='MF')
axs[1,0].plot(r2x, np.asarray(a1_r2_mo), marker='o', c = mo_color, label='MO')
axs[1,0].set_xticks(r2x)
axs[1,0].set_yticks(np.linspace(0,1,11))
axs[1,0].set_ylim(0, 1)
axs[1,0].set_ylabel("r\u00b2, 2nd case", fontsize=textfs)

axs[1,1].plot(rmx, np.asarray(a1_rmse_gp), marker='o', c = gp_color, label='GP')
axs[1,1].plot(rmx, np.asarray(a1_rmse_mf), marker='o', c = mf_color, label='MF')
axs[1,1].plot(rmx, np.asarray(a1_rmse_mo), marker='o', c = mo_color, label='MO')
axs[1,1].set_yticks(np.arange(6, 30, 2))
axs[1,1].set_xticks(rmx)
axs[1,1].set_ylim(6, 30)
axs[1,1].set_ylabel("%rmse", fontsize=textfs)

plt.legend(bbox_to_anchor=(0.5, 0), loc="lower center", bbox_transform=fig.transFigure, ncol=3)
plt.tight_layout()
plt.show()
2
  • 1
    Try this: fig.tight_layout();fig.subplots_adjust(bottom=0.05);fig.legend(labels=['GP','MF','MO'], loc="lower center", ncol=3) I think you will find this response helpful. Commented Sep 7, 2023 at 14:18
  • 1
    I removed the numpy tag since your question is about matplotlib and has nothing to do with numpy. Please remember that tags should indicate what the question is about, not what it contains.
    – pho
    Commented Sep 7, 2023 at 15:47

2 Answers 2

0
  1. Use constrained layout rather than tight_layout.
  2. Use a figure legend rather than plt.legend (which is a wrapper to ax.legend) and set the loc to "outside lower center".
  3. Only set the labels within one of the axes, otherwise the legend entries will be repeated.

See also https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html#figure-legends

import numpy as np
import matplotlib.pyplot as plt

r2x =np.arange(1,10,1)
rmx =np.arange(1,10,1)

a0_r2_gp = np.random.rand(9)
a0_r2_mf = np.random.rand(9)
a0_r2_mo = np.random.rand(9)

a0_rmse_gp = np.random.randint(0, 60, 9)
a0_rmse_mf = np.random.randint(0, 50, 9)
a0_rmse_mo = np.random.randint(0, 40, 9)

a1_r2_gp = np.random.rand(9)
a1_r2_mf = np.random.rand(9)
a1_r2_mo = np.random.rand(9)

a1_rmse_gp = np.random.randint(0, 30, 9)
a1_rmse_mf =np.random.randint(0, 20, 9)
a1_rmse_mo =np.random.randint(0, 15, 9)

fig, axs = plt.subplots(2, 2, figsize=(8, 12), layout='constrained' )
axs[0,0].plot(r2x, np.asarray(a0_r2_gp), marker='o', label='GP')
axs[0,0].plot(r2x, np.asarray(a0_r2_mf), marker='o', label='MF')
axs[0,0].plot(r2x, np.asarray(a0_r2_mo), marker='o', label='MO')
axs[0,0].set_xticks(r2x)
axs[0,0].set_yticks(np.linspace(0,1,11))
axs[0,0].set_ylim(0, 1)
axs[0,0].set_ylabel("r\u00b2, 1st case")

axs[0,1].plot(rmx, np.asarray(a0_rmse_gp), marker='o')
axs[0,1].plot(rmx, np.asarray(a0_rmse_mf), marker='o')
axs[0,1].plot(rmx, np.asarray(a0_rmse_mo), marker='o')
axs[0,1].set_yticks(np.arange(10, 65, 5))
axs[0,1].set_xticks(rmx)
axs[0,1].set_ylim(10, 65)
axs[0,1].set_ylabel("%rmse")
fig.suptitle("r\u00b2 and %rmse averages for Tubes")

axs[1,0].plot(r2x, np.asarray(a1_r2_gp), marker='o')
axs[1,0].plot(r2x, np.asarray(a1_r2_mf), marker='o')
axs[1,0].plot(r2x, np.asarray(a1_r2_mo), marker='o')
axs[1,0].set_xticks(r2x)
axs[1,0].set_yticks(np.linspace(0,1,11))
axs[1,0].set_ylim(0, 1)
axs[1,0].set_ylabel("r\u00b2, 2nd case")

axs[1,1].plot(rmx, np.asarray(a1_rmse_gp), marker='o')
axs[1,1].plot(rmx, np.asarray(a1_rmse_mf), marker='o')
axs[1,1].plot(rmx, np.asarray(a1_rmse_mo), marker='o')
axs[1,1].set_yticks(np.arange(6, 30, 2))
axs[1,1].set_xticks(rmx)
axs[1,1].set_ylim(6, 30)
axs[1,1].set_ylabel("%rmse")

fig.legend(loc="outside lower center", ncol=3)
plt.show()

enter image description here

0

There is no need to use subplots_adjust with modern Matplotlib: https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html#figure-legends. Use 'outside lower center' with layout='constrained' instead.

EDIT (sorry, cross post with @RuthC below).

import matplotlib.pyplot as plt
import numpy as np

fig, axs = plt.subplots(2, 2, layout='constrained', sharex=True, sharey=True)
np.random.seed(12345)
for n in range(4):
    ax = axs.flat[n]
    ll = []
    for i in range(3):
        l, = ax.plot(np.random.randn(5), label=f'Line {i}')
        ll += [l]

fig.legend(handles=ll, loc='outside lower center', ncol=1, fontsize=8, labelspacing=0.5)

plt.show()

enter image description here

Not the answer you're looking for? Browse other questions tagged or ask your own question.