I created a legend which contains two rows, as below:
Is it possible to add a label/title to each row, that when I show the plot the legend appears as:
Title1: One One One
Title2: Two Two Two
Many thanks for any suggestions!
There is no built-in option to set row titles in legends.
As a workaround you may preprend a first column to the legend, which has no handles, but only labels.
import matplotlib.pyplot as plt
import numpy as np
y = np.exp(-np.arange(5))
markers=["s", "o", ""]
labels =["one", "two"]
fig, ax = plt.subplots()
for i in range(6):
ax.plot(y*i+i/2., marker=markers[i//2], label=labels[i%2])
h, l = ax.get_legend_handles_labels()
ph = [plt.plot([],marker="", ls="")[0]]*2
handles = ph + h
labels = ["Title 1:", "Title 2:"] + l
plt.legend(handles, labels, ncol=4)
plt.show()
The main drawback here is that there is a lot of whitespace at the positions where the handles of the row titles would sit.
Setting markerfirst=False
would make this less apparent:
If all of those are not an option one needs to dive a little deeper into the legend. The legend consists of Packer
objects. It is then possible to identify those two packers from the first column that take up the space and set their width to zero
leg = plt.legend(handles, labels, ncol=4)
for vpack in leg._legend_handle_box.get_children()[:1]:
for hpack in vpack.get_children():
hpack.get_children()[0].set_width(0)
This should now pretty much give the desired row titles
The equivalent thing for column titles can be achieved by swapping the [:1]
like this:
handles = ph[:1] + h[::2] + ph[1:] + h[1::2]
labels = ["Title 1:"] + l[::2] + ["Title 2:"] + l[1::2]
leg = plt.legend(handles, labels, ncol=2)
for vpack in leg._legend_handle_box.get_children():
for hpack in vpack.get_children()[:1]:
hpack.get_children()[0].set_width(0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With