Reputation: 5178
I have the following script to do what I want -
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
TITLEPAD = 25
LABELSIZE = 24
SCENARIO_LABELSIZE=25
SCENARIO_LABELPAD=85
LABELPAD = 30
LINESTYLES = ["-", "--"]
COLUMN_NAMES = ["A", "B", "C", "D"]
ROW_NAMES = ["I", "II", "III"]
ALL_METHODS = ["X", "Y", "Z"]
fig, axs = plt.subplots(nrows=len(ROW_NAMES), ncols=len(COLUMN_NAMES), figsize=(27, 18), sharex='col', sharey=True, dpi=100)
# set row and column headers
for col, name in enumerate(COLUMN_NAMES):
tmp_ax = axs[0, col].twiny()
tmp_ax.set_xticks([])
tmp_ax.set_xlabel(name, labelpad=LABELPAD, fontsize=LABELSIZE)
for row, name in enumerate(ROW_NAMES):
axs[row, 0].set_ylabel("Y", labelpad=LABELPAD, fontsize=LABELSIZE, rotation=0)
tmp_ax = axs[row, -1].twinx()
tmp_ax.set_ylabel(name+"\nCase", fontsize=LABELSIZE, fontweight="bold", rotation=0, labelpad=LABELPAD )
tmp_ax.set_yticks([])
# bunch of plots
plt.subplots_adjust(left=0.125, wspace=0.2, hspace=0.2, bottom=0.15)
# legends
legends = []
for method in ALL_METHODS:
legends.append(Line2D([0, 1], [0, 0], linestyle="-", label=method, linewidth=3))
lgd = fig.legend(handles=legends, ncol=len(legends), fontsize=30, loc="lower center", fancybox=True, bbox_to_anchor=(0.5, -0.0275))
fig.tight_layout()
fig.savefig("tmp.png", bbox_inches='tight', bbox_extra_artists=(lgd,))
It yields the image like this -
Notice the busy and butchered legend at the bottom. I have tried several things like playing with bbox
dimensions or figure size to make it look less busy and full. Nothing worked!
Question: Is there an easy and structured way to control the legend positioning in a figure? I know this is much easy when we have a single plot. Ideally, I would like to position the legend such that there is enough space between the ticks at the bottom and the top line of the legend without cutting it out from the figure.
Upvotes: 0
Views: 74
Reputation: 5178
As pointed by @Asmus this detailed answer has the answer to what I was looking for.
For the sake of completeness, here is what I did -
# no need for subplots_adjust
# plt.subplots_adjust(left=0.125, wspace=0.2, hspace=0.2, bottom=0.25)
# added reference for bbox_to_anchor as the coordinates of figure using bbox_transform
lgd = fig.legend(handles=legends, ncol=len(legends), fontsize=30, loc="lower center", fancybox=True, bbox_to_anchor=(0.5, 0), bbox_transform=fig.transFigure)
# pushed the entire subplot withing a rectangle as specified in rect argument to tight_layout
fig.tight_layout(rect=[0, 0.05, 1, 1])
Upvotes: 1