pg2455
pg2455

Reputation: 5178

How to position legend in a matploltib figure easily?

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 - enter image description here

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

Answers (1)

pg2455
pg2455

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

Related Questions