frixhax
frixhax

Reputation: 1395

matplotlib make selected legend entry invisible

I want to plot two lines, which both have a label, several times in a for loop yielding several plots. In some of those I want the legend to hold both line entries, in some only the handle and label of the first line, leaving the entry for the second line blank. In all cases I need the legend frame to have the exact same size, leaving a blank space in cases where I don't want the second entry.

In theory I just need to turn the second handle and label invisible. I found some solutions with Rectangle() or Circle() dummy entries set invisible. However, they don't have the same size as the real legend entry resulting in differing legend frame hight depending on whether I use both lines in the legend or just one line and the dummy. Is there a solution for that?

Here is an example which comes close to what it looks like (despite generating values, of course). Say, in every second iteration I need the lower legend entry to disappear without the legend frame changing its size or shape. How can I do that?

import numpy as np
import matplotlib.pyplot as plt

for i in range(10):
    x1 = x2 = y1 = y2 = np.random.rand(5)
    yerr1 = yerr2 = .1

    plt.figure()
    plt.errorbar(x1, y1, yerr=yerr1, c='r', ls='-', marker='.', label='set1')
    plt.errorbar(x2, y2, yerr=yerr2, c='k', ls='-', marker='.', label='set2')

    # Get rid of error bars in legend
    ax.gca()
    handles, labels = ax.get_legend_handles_labels()
    handles = [n[0:1] for n in handles]

    plt.legend(handles, labels, bbox_to_anchor=(0.,1.,1.,0.), loc=3, numpoints=2, ncol=1 ,borderaxespad=0., mode='expand', labelspacing=0.5, borderpad=0.2, handletextpad=0.05)
    plt.savefig('test_%d' % i)
    plt.close()

Upvotes: 0

Views: 2811

Answers (1)

Marcin
Marcin

Reputation: 238497

Thanks for the example.

What about something like that:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.lines as mlines

dummy_white_line = mlines.Line2D([], [], color='white')

for i in range(10):
    x1 = x2 = y1 = y2 = np.random.rand(5)
    yerr1 = yerr2 = .1

    plt.figure()
    plt.errorbar(x1, y1, yerr=yerr1, c='r', ls='-', marker='.', label='set1')
    plt.errorbar(x2, y2, yerr=yerr2, c='k', ls='-', marker='.', label='set2')

    # Get rid of error bars in legend
    ax = plt.gca()
    handles, labels = ax.get_legend_handles_labels()

    if i % 2 == 0:

        handles[1] = dummy_white_line
        labels[1]  = ''

    plt.legend(handles, labels, bbox_to_anchor=(0.,1.,1.,0.), 
                loc=3, numpoints=2, ncol=1 ,borderaxespad=0.,
                 mode='expand', labelspacing=0.5, borderpad=0.2, handletextpad=0.05)
    plt.savefig('test_%d' % i)
    #plt.show()
    plt.close()

In here I used dummy_white_line to "erase" the line in label (you have white line on white background) and used empty string for a label.

Normal plot:

enter image description here

Plot without (i.e. empty dummy) second label:

file:///home/marcin/workspace2/mypython/test/test_2.png

Upvotes: 1

Related Questions