Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib - add titles to the legend rows

I created a legend which contains two rows, as below:

enter image description here

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!

like image 462
Ziva Avatar asked May 19 '17 13:05

Ziva


1 Answers

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()

enter image description here

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:

enter image description here

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

enter image description here


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)

matplotlib legend column titles

like image 172
ImportanceOfBeingErnest Avatar answered Sep 16 '22 15:09

ImportanceOfBeingErnest