Подтвердить что ты не робот

Остановить matplotlib, повторяя метки в легенде

Вот очень упрощенный пример:

xvalues = [2,3,4,6]

for x in xvalues:
    plt.axvline(x,color='b',label='xvalues')

plt.legend()

В легенде теперь будет отображаться "xvalues" как синяя линия 4 раза. Есть ли более элегантный способ исправить это, чем следующее?

for i,x in enumerate(xvalues):
    if not i:
        plt.axvline(x,color='b',label='xvalues')
    else:
        plt.axvline(x,color='b')
4b9b3361

Ответ 1

legend принимает в качестве аргументов список осей-дескрипторов и меток, по умолчанию plt.gca().get_legend_handles_labels(). Вы можете удалить дубликаты меток при вызове legend, например:

from collections import OrderedDict
import matplotlib.pyplot as plt

handles, labels = plt.gca().get_legend_handles_labels()
by_label = OrderedDict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())

Ответ 2

handles, labels = ax.get_legend_handles_labels()
handle_list, label_list = [], []
for handle, label in zip(handles, labels):
    if label not in label_list:
        handle_list.append(handle)
        label_list.append(label)
plt.legend(handle_list, label_list)

Ответ 3

Эти фрагменты кода не работали для меня лично. Я писал две разные группы в двух разных цветах. В легенде будут показаны два красных маркера и два синих маркера, когда я только хочу увидеть один цвет. Я вставлю упрощенную версию того, что для меня работало:

Операторы импорта

import matplotlib.pyplot as plt

from matplotlib.legend_handler import HandlerLine2D

Данные графика

points_grp, = plt.plot(x[grp_idx], y[grp_idx], color=c.c[1], marker=m, ms=4, lw=0, label=leglab[1])        
points_ctrl, = plt.plot(x[ctrl_idx], y[ctrl_idx], color=c.c[0], marker=m, ms=4, lw=0, label=leglab[0])

Добавить легенду

points_dict = {points_grp: HandlerLine2D(numpoints=1),points_ctrl: HandlerLine2D(numpoints=1)}
leg = ax.legend(fontsize=12, loc='upper left', bbox_to_anchor=(1, 1.03),handler_map=points_dict)

Ответ 4

Я не знаю, можно ли считать это "элегантным", но вы можете присвоить своей метке переменную, которая после первого использования получает значение "_nolegend_":

my_label = "xvalues"
xvalues = [2,3,4,6]

for x in xvalues:
    plt.axvline(x, color='b', label=my_label)
    my_label = "_nolegend_"

plt.legend()

Это можно обобщить, используя словарь ярлыков, если вам нужно поместить несколько меток:

my_labels = {"x1" : "x1values", "x2" : "x2values"}
x1values = [1, 3, 5]
x2values = [2, 4, 6]

for x in x1values:
    plt.axvline(x, color='b', label=my_labels["x1"])
    my_labels["x1"] = "_nolegend_"
for x in x2values:
    plt.axvline(x, color='r', label=my_labels["x2"])
    my_labels["x2"] = "_nolegend_"

plt.legend()

Рисунок с двумя разными метками

(Ответ вдохновлен fooobar.com/questions/187172/...)

Ответ 5

На основе ответа fooobar.com/questions/187171/... и fooobar.com/questions/187172/... plt.gca().get_legend_handles_labels()[1] дает список имен, можно проверить, находится ли метка уже в списке при построении цикла (label= name[i] if name[i] not in plt.gca().get_legend_handles_labels()[1] else ''). Для данного примера это решение будет выглядеть так:

import matplotlib.pyplot as plt

xvalues = [2,3,4,6]

for x in xvalues:
    plt.axvline(x,color='b',\
    label= 'xvalues' if 'xvalues' \
            not in plt.gca().get_legend_handles_labels()[1] else '')

plt.legend()

Которая намного короче fooobar.com/questions/187171/... и более гибкая, чем fooobar.com/questions/187172/..., поскольку это может быть использовать для любого вида петлю любую функцию графика в цикле по отдельности. Однако для многих циклов он, вероятно, медленнее, чем fooobar.com/questions/187171/....

Ответ 6

Проблема - 3D-массив

Вопросы: ноябрь 2012 г., октябрь 2013 г.

import numpy as np
a = np.random.random((2, 100, 4))
b = np.random.random((2, 100, 4))
c = np.random.random((2, 100, 4))

Решение - продиктовать уникальность

Для моего случая _nolegend_ (bli и DSM) не будет работать, как и label if i==0. ecatmur ответ использует get_legend_handles_labels и уменьшает легенду до collections.OrderedDict. Fons демонстрирует, что это возможно без импорта.

В соответствии с этими ответами я предлагаю использовать dict для уникальных ярлыков.

# Step-by-step
ax = plt.gca()                      # Get the axes you need
a = ax.get_legend_handles_labels()  # a = [(h1 ... h2) (l1 ... l2)]  non unique
b = {l:h for h,l in zip(*a)}        # b = {l1:h1, l2:h2}             unique
c = [*zip(*b.items())]              # c = [(l1 l2) (h1 h2)]
d = c[::-1]                         # d = [(h1 h2) (l1 l2)]
plt.legend(*d)

Или

plt.legend(*[*zip(*{l:h for h,l in zip(*ax.get_legend_handles_labels())}.items())][::-1])

Возможно, менее разборчивый и запоминающийся, чем Мэттью Бурк. Код гольф приветствуется.

Пример

import numpy as np
a = np.random.random((2, 100, 4))
b = np.random.random((2, 100, 4))

import matplotlib.pyplot as plt
fig, ax = plt.subplots(1)
ax.plot(*a, 'C0', label='a')
ax.plot(*b, 'C1', label='b')

ax.legend(*[*zip(*{l:h for h,l in zip(*ax.get_legend_handles_labels())}.items())][::-1])
# ax.legend()   # Old,  ^ New

plt.show()