Eje secundario con twinx(): cómo agregar a la leyenda
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?
Puedes agregar fácilmente una segunda leyenda agregando la línea:
ax2.legend(loc=0)
Obtendrás esto:
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:
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()
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 loc
argumento 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()
Para volver a colocar la leyenda en los ejes, se proporcionarían a bbox_to_anchor
y 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 loc
coordenadas dadas en los ejes.
fig.legend(loc="upper right", bbox_to_anchor=(1,1), bbox_transform=ax.transAxes)