Дублировать предметы в легенде в matplotlib?
Я пытаюсь добавить легенду к моему сюжету с помощью этого фрагмента:
import matplotlib.pylab as plt
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # left, bottom, width, height (range 0 to 1)
axes.set_xlabel('x (m)')
axes.set_ylabel('y (m)')
for i, representative in enumerate(representatives):
axes.plot([e[0] for e in representative], [e[1] for e in representative], color='b', label='Representatives')
axes.scatter([e[0] for e in intersections], [e[1] for e in intersections], color='r', label='Intersections')
axes.legend()
Я заканчиваю этот сюжет
![enter image description here]()
Очевидно, элементы дублируются в сюжете. Как я могу исправить эту ошибку?
Ответы
Ответ 1
Как говорится в docs, хотя легко пропустить:
Если атрибут метки пустой строки или начинается с "_", те художники будут проигнорированы.
Итак, если я рисую похожие строки в цикле, и мне нужна только одна строка примера в легенде, я обычно делаю что-то вроде
ax.plot(x, y, label="Representatives" if i == 0 else "")
где i
- мой индекс цикла.
Не так приятно смотреть, как создавать их отдельно, но часто я хочу, чтобы логика ярлыков была как можно ближе к чертежу линии.
(Обратите внимание, что сами разработчики matplotlib
используют "_nolegend_"
для явного.)
Ответ 2
Вот способ удаления дублированных записей легенды после того, как обычно уже назначены метки:
representatives=[[[-100,40],[-50,20],[0,0],[75,-5],[100,5]], #made up some data
[[-60,80],[0,85],[100,90]],
[[-60,15],[-50,90]],
[[-2,-2],[5,95]]]
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # left, bottom, width, height (range 0 to 1)
axes.set_xlabel('x (m)')
axes.set_ylabel('y (m)')
for i, representative in enumerate(representatives):
axes.plot([e[0] for e in representative], [e[1] for e in representative],color='b', label='Representatives')
#make sure only unique labels show up (no repeats)
handles,labels=axes.get_legend_handles_labels() #get existing legend item handles and labels
i=arange(len(labels)) #make an index for later
filter=array([]) #set up a filter (empty for now)
unique_labels=tolist(set(labels)) #find unique labels
for ul in unique_labels: #loop through unique labels
filter=np.append(filter,[i[array(labels)==ul][0]]) #find the first instance of this label and add its index to the filter
handles=[handles[int(f)] for f in filter] #filter out legend items to keep only the first instance of each repeated label
labels=[labels[int(f)] for f in filter]
axes.legend(handles,labels) #draw the legend with the filtered handles and labels lists
И вот результаты:
Слева - результат сценария выше. Справа, вызов легенды был заменен на axes.legend()
.
Преимущество заключается в том, что вы можете просматривать большую часть кода и просто назначать метки в обычном режиме, не беспокоясь о встроенных циклах или, if
. Вы также можете встроить это в обертку вокруг легенды или что-то в этом роде.
Ответ 3
Это не ошибка. Ваша метка внутри цикла for
добавляет к вашей легенде len(representatives)-1
повторяющиеся ярлыки. Что, если вместо этого вы сделали что-то вроде
for i, representative in enumerate(representatives):
rep, = axes.plot([e[0] for e in representative], [e[1] for e in representative], color='b')
inter = axes.scatter([e[0] for e in intersections], [e[1] for e in intersections], color='r')
axes.legend((rep, inter), ("Representatives", "Intersections"))
Изменить: формат приведенного ниже кода использует формат, размещенный в учебнике легенд matplotlib. Причина, по которой вышеуказанный код не была выполнена, состоит в том, что после rep, =
отсутствовала запятая. Каждая итерация rep
перезаписывается, и когда она используется для вызова legend
, в rep
сохраняется только последний график представителей.
fig = plt.figure()
ax = fig.add_subplot(111)
for i, representative in enumerate(representatives):
rep, = ax.plot([e[0] for e in representative], [e[1] for e in representative], color='b')
inter = ax.scatter([e[0] for e in intersections], [e[1] for e in intersections], color='r')
ax.legend((rep, inter), ("Representatives", "Intersections"))
Вы также можете попытаться построить ваши данные так, как вы делаете в своем OP, но сделайте легенду, используя
handles, labels = ax.get_legend_handles_labels()
и редактирование содержимого handles
и labels
.
Ответ 4
Основываясь на ответе EL_DON, вот общий метод рисования легенды без дублирующих меток:
def legend_without_duplicate_labels(ax):
handles, labels = ax.get_legend_handles_labels()
unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels)) if l not in labels[:i]]
ax.legend(*zip(*unique))
Пример использования: (открыть в repl.it
)
fig, ax = plt.subplots()
ax.plot([0,1], [0,1], c="y", label="my lines")
ax.plot([0,1], [0,2], c="y", label="my lines")
legend_without_duplicate_labels(ax)
plt.show()
![enter image description here]()