python - real - pyplot combina varias etiquetas de líneas en la leyenda
matplotlib python 3 (4)
Tengo datos que dan como resultado el trazado de múltiples líneas, quiero dar a estas líneas una sola etiqueta en mi leyenda. Creo que esto se puede demostrar mejor usando el siguiente ejemplo,
a = np.array([[ 3.57, 1.76, 7.42, 6.52],
[ 1.57, 1.2 , 3.02, 6.88],
[ 2.23, 4.86, 5.12, 2.81],
[ 4.48, 1.38, 2.14, 0.86],
[ 6.68, 1.72, 8.56, 3.23]])
plt.plot(a[:,::2].T, a[:, 1::2].T, ''r'', label=''data_a'')
plt.legend(loc=''best'')
Como se puede ver en Out [23] la trama resultó en 5 líneas distintas. La trama resultante se ve así
¿Hay alguna manera de que pueda decir el método de trazado para evitar etiquetas múltiples? No deseo utilizar la leyenda personalizada (donde especifica la etiqueta y la forma de la línea, todo a la vez) tanto como pueda.
Haría una pequeña función de ayudante personalmente, si planeaba hacerlo a menudo;
from matplotlib import pyplot
import numpy
a = numpy.array([[ 3.57, 1.76, 7.42, 6.52],
[ 1.57, 1.2 , 3.02, 6.88],
[ 2.23, 4.86, 5.12, 2.81],
[ 4.48, 1.38, 2.14, 0.86],
[ 6.68, 1.72, 8.56, 3.23]])
def plotCollection(ax, xs, ys, *args, **kwargs):
ax.plot(xs,ys, *args, **kwargs)
if "label" in kwargs.keys():
#remove duplicates
handles, labels = pyplot.gca().get_legend_handles_labels()
newLabels, newHandles = [], []
for handle, label in zip(handles, labels):
if label not in newLabels:
newLabels.append(label)
newHandles.append(handle)
pyplot.legend(newHandles, newLabels)
ax = pyplot.subplot(1,1,1)
plotCollection(ax, a[:,::2].T, a[:, 1::2].T, ''r'', label=''data_a'')
plotCollection(ax, a[:,1::2].T, a[:, ::2].T, ''b'', label=''data_b'')
pyplot.show()
Una forma más fácil (y más clara de IMO) de eliminar duplicados (que los que tiene) de los handles
y labels
de la leyenda es esta:
handles, labels = pyplot.gca().get_legend_handles_labels()
newLabels, newHandles = [], []
for handle, label in zip(handles, labels):
if label not in newLabels:
newLabels.append(label)
newHandles.append(handle)
pyplot.legend(newHandles, newLabels)
Numpy solución basada en la respuesta de voluntad anterior.
import numpy as np
import matplotlib.pylab as plt
a = np.array([[3.57, 1.76, 7.42, 6.52],
[1.57, 1.20, 3.02, 6.88],
[2.23, 4.86, 5.12, 2.81],
[4.48, 1.38, 2.14, 0.86],
[6.68, 1.72, 8.56, 3.23]])
plt.plot(a[:,::2].T, a[:, 1::2].T, ''r'', label=''data_a'')
handles, labels = plt.gca().get_legend_handles_labels()
Suponiendo que las etiquetas iguales tengan los mismos identificadores, obtenga etiquetas únicas y sus respectivos índices, que corresponden a los índices de control.
labels, ids = np.unique(labels, return_index=True)
handles = [handles[i] for i in ids]
plt.legend(handles, labels, loc=''best'')
plt.show()
Matplotlib le ofrece una interfaz agradable para colecciones de líneas, LineCollection . El código es directo
import numpy
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
a = numpy.array([[ 3.57, 1.76, 7.42, 6.52],
[ 1.57, 1.2 , 3.02, 6.88],
[ 2.23, 4.86, 5.12, 2.81],
[ 4.48, 1.38, 2.14, 0.86],
[ 6.68, 1.72, 8.56, 3.23]])
xs = a[:,::2]
ys = a[:, 1::2]
lines = LineCollection([list(zip(x,y)) for x,y in zip(xs, ys)], label=''data_a'')
f, ax = plt.subplots(1, 1)
ax.add_collection(lines)
ax.legend()
ax.set_xlim([xs.min(), xs.max()]) # have to set manually
ax.set_ylim([ys.min(), ys.max()])
plt.show()
Entonces, usando la sugerencia de Will y otra pregunta aquí , dejo mi remedio aquí
handles, labels = plt.gca().get_legend_handles_labels()
i =1
while i<len(labels):
if labels[i] in labels[:i]:
del(labels[i])
del(handles[i])
else:
i +=1
plt.legend(handles, labels)
Y la nueva trama parece,