Eje secundario con twinx(): cómo agregar a la leyenda

Resuelto joris asked hace 13 años • 11 respuestas

Tengo una gráfica con dos ejes y, usando twinx(). También le doy etiquetas a las líneas y quiero mostrarlas con legend(), pero solo logro obtener las etiquetas de un eje en la leyenda:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
rc('mathtext', default='regular')

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(time, Swdown, '-', label = 'Swdown')
ax.plot(time, Rn, '-', label = 'Rn')
ax2 = ax.twinx()
ax2.plot(time, temp, '-r', label = 'temp')
ax.legend(loc=0)
ax.grid()
ax.set_xlabel("Time (h)")
ax.set_ylabel(r"Radiation ($MJ\,m^{-2}\,d^{-1}$)")
ax2.set_ylabel(r"Temperature ($^\circ$C)")
ax2.set_ylim(0, 35)
ax.set_ylim(-20,100)
plt.show()

Entonces solo obtengo las etiquetas del primer eje en la leyenda, y no la etiqueta "temperatura" del segundo eje. ¿Cómo podría agregar esta tercera etiqueta a la leyenda?

ingrese la descripción de la imagen aquí

joris avatar Mar 30 '11 17:03 joris
Aceptado

Puedes agregar fácilmente una segunda leyenda agregando la línea:

ax2.legend(loc=0)

Obtendrás esto:

ingrese la descripción de la imagen aquí

Pero si quieres que todas las etiquetas estén en una leyenda, entonces deberías hacer algo como esto:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
rc('mathtext', default='regular')

time = np.arange(10)
temp = np.random.random(10)*30
Swdown = np.random.random(10)*100-10
Rn = np.random.random(10)*100-10

fig = plt.figure()
ax = fig.add_subplot(111)

lns1 = ax.plot(time, Swdown, '-', label = 'Swdown')
lns2 = ax.plot(time, Rn, '-', label = 'Rn')
ax2 = ax.twinx()
lns3 = ax2.plot(time, temp, '-r', label = 'temp')

# added these three lines
lns = lns1+lns2+lns3
labs = [l.get_label() for l in lns]
ax.legend(lns, labs, loc=0)

ax.grid()
ax.set_xlabel("Time (h)")
ax.set_ylabel(r"Radiation ($MJ\,m^{-2}\,d^{-1}$)")
ax2.set_ylabel(r"Temperature ($^\circ$C)")
ax2.set_ylim(0, 35)
ax.set_ylim(-20,100)
plt.show()

Que te dará esto:

ingrese la descripción de la imagen aquí

Paul avatar Mar 30 '2011 13:03 Paul

No estoy seguro de si esta funcionalidad es nueva, pero también puedes usar el método get_legend_handles_labels() en lugar de realizar un seguimiento de las líneas y etiquetas tú mismo:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
rc('mathtext', default='regular')

pi = np.pi

# fake data
time = np.linspace (0, 25, 50)
temp = 50 / np.sqrt (2 * pi * 3**2) \
        * np.exp (-((time - 13)**2 / (3**2))**2) + 15
Swdown = 400 / np.sqrt (2 * pi * 3**2) * np.exp (-((time - 13)**2 / (3**2))**2)
Rn = Swdown - 10

fig = plt.figure()
ax = fig.add_subplot(111)

ax.plot(time, Swdown, '-', label = 'Swdown')
ax.plot(time, Rn, '-', label = 'Rn')
ax2 = ax.twinx()
ax2.plot(time, temp, '-r', label = 'temp')

# ask matplotlib for the plotted objects and their labels
lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax2.legend(lines + lines2, labels + labels2, loc=0)

ax.grid()
ax.set_xlabel("Time (h)")
ax.set_ylabel(r"Radiation ($MJ\,m^{-2}\,d^{-1}$)")
ax2.set_ylabel(r"Temperature ($^\circ$C)")
ax2.set_ylim(0, 35)
ax.set_ylim(-20,100)
plt.show()

ingrese la descripción de la imagen aquí

zgana avatar Apr 12 '2012 18:04 zgana

A partir de la versión 2.1 de matplotlib, puede utilizar una leyenda de figura . En lugar de lo ax.legend()que produce una leyenda con los identificadores de los ejes ax, se puede crear una leyenda de figura.

fig.legend(loc="arriba derecha")

que reunirá todos los identificadores de todas las subtramas de la figura. Dado que es una leyenda de figura, se colocará en la esquina de la figura y el locargumento es relativo a la figura.

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,10)
y = np.linspace(0,10)
z = np.sin(x/3)**2*98

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,y, '-', label = 'Quantity 1')

ax2 = ax.twinx()
ax2.plot(x,z, '-r', label = 'Quantity 2')
fig.legend(loc="upper right")

ax.set_xlabel("x [units]")
ax.set_ylabel(r"Quantity 1")
ax2.set_ylabel(r"Quantity 2")

plt.show()

ingrese la descripción de la imagen aquí

Para volver a colocar la leyenda en los ejes, se proporcionarían a bbox_to_anchory a bbox_transform. Esta última sería la transformación de los ejes en los que debe residir la leyenda. La primera puede ser las coordenadas del borde definido por las loccoordenadas dadas en los ejes.

fig.legend(loc="upper right", bbox_to_anchor=(1,1), bbox_transform=ax.transAxes)

ingrese la descripción de la imagen aquí

ImportanceOfBeingErnest avatar Nov 18 '2017 19:11 ImportanceOfBeingErnest