2011-03-30 16 views
155

Tengo un diagrama con dos ejes y, usando twinx(). También doy las etiquetas para las líneas, y quiero mostrar con legend(), pero sólo tienen éxito para obtener las etiquetas de un eje en la leyenda:Eje secundario con twinx(): cómo agregar a 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() 

Así que solo me dan las etiquetas del primer eje en el leyenda, y no la etiqueta 'temp' del segundo eje. ¿Cómo podría agregar esta tercera etiqueta a la leyenda?

enter image description here

Respuesta

204

Usted puede agregar fácilmente una segunda leyenda añadiendo la línea:

ax2.legend(loc=0) 

que obtendrá esto:

enter image description here

Pero si desea que todas las etiquetas de 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 le dará la siguiente:

enter image description here

+15

Gracias! Esto ciertamente lo hará. Solo encuentro que es un poco desafortunado que matplotlib no tenga más solución automática. – joris

+0

Esto falla con los diagramas 'errorbar'. Para una solución que los maneje correctamente, consulte a continuación: http://stackoverflow.com/a/10129461/1319447 – Davide

+0

Para evitar dos leyendas superpuestas, como en mi caso donde especifiqué dos .legend (loc = 0), debe especificar dos valores diferentes para el valor de ubicación de la leyenda (ambos distintos de 0). Ver: http://matplotlib.org/api/legend_api.html – Roalt

99

No estoy seguro de si esta funcionalidad es nueva, pero también se puede utilizar el get_legend_handles_labels() método en lugar de hacer el seguimiento de líneas y etiquetas a sí 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() 
+1

Este es el único solución que puede manejar ejes donde las tramas se superponen con las leyendas (los últimos ejes es el que debe trazar las leyendas) –

+2

Esta solución también funciona con diagramas 'errorbar', mientras que la aceptada falla (mostrando una línea y sus barras de error por separado, y ninguno de ellos con la etiqueta correcta). Además, es más simple. – Davide

+0

captura ligera: no funciona si desea sobrescribir la etiqueta para 'ax2' y no tiene un juego desde el principio –

23

usted puede conseguir fácilmente lo que quiere mediante la adición de la línea de hacha:

ax.plot(0, 0, '-r', label = 'temp') 

o

ax.plot(np.nan, '-r', label = 'temp') 

Esto trazar nada más que añadir una etiqueta con la leyenda del hacha.

Creo que esta es una manera mucho más fácil. No es necesario rastrear líneas automáticamente cuando tiene solo unas pocas líneas en el segundo eje, ya que la fijación a mano como la anterior sería bastante fácil. De todos modos, depende de lo que necesites.

Todo el código es la siguiente:

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

time = np.arange(22.) 
temp = 20*np.random.rand(22) 
Swdown = 10*np.random.randn(22)+40 
Rn = 40*np.random.rand(22) 

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

#---------- look at below ----------- 

ax.plot(time, Swdown, '-', label = 'Swdown') 
ax.plot(time, Rn, '-', label = 'Rn') 

ax2.plot(time, temp, '-r') # The true line in ax2 
ax.plot(np.nan, '-r', label = 'temp') # Make an agent in ax 

ax.legend(loc=0) 

#---------------done----------------- 

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() 

La trama es la siguiente:

enter image description here


Actualización: añadir una versión mejor:

ax.plot(np.nan, '-r', label = 'temp') 

Esto wil No hago nada, mientras que plot(0, 0) puede cambiar el rango del eje.

+2

Me gusta esto. Es un poco feo en la forma en que "engaña" al sistema, pero es tan simple de implementar. –

4

Encontré el siguiente ejemplo oficial de matplotlib que usa host_subplot para mostrar múltiples ejes y y todas las diferentes etiquetas en una leyenda. No hay solución necesaria. La mejor solución que encontré hasta ahora. http://matplotlib.org/examples/axes_grid/demo_parasite_axes2.html

from mpl_toolkits.axes_grid1 import host_subplot 
import mpl_toolkits.axisartist as AA 
import matplotlib.pyplot as plt 

host = host_subplot(111, axes_class=AA.Axes) 
plt.subplots_adjust(right=0.75) 

par1 = host.twinx() 
par2 = host.twinx() 

offset = 60 
new_fixed_axis = par2.get_grid_helper().new_fixed_axis 
par2.axis["right"] = new_fixed_axis(loc="right", 
            axes=par2, 
            offset=(offset, 0)) 

par2.axis["right"].toggle(all=True) 

host.set_xlim(0, 2) 
host.set_ylim(0, 2) 

host.set_xlabel("Distance") 
host.set_ylabel("Density") 
par1.set_ylabel("Temperature") 
par2.set_ylabel("Velocity") 

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density") 
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature") 
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity") 

par1.set_ylim(0, 4) 
par2.set_ylim(1, 65) 

host.legend() 

plt.draw() 
plt.show() 
+0

¡Bienvenido a Stack Overflow!Indique la parte más relevante del enlace, en caso de que el sitio objetivo no esté disponible o esté permanentemente fuera de línea. Consulte [Cómo escribo una buena respuesta] (http://stackoverflow.com/help/how-to-answer). Concéntrese en preguntas más actuales en el futuro, esta tiene casi 4 años. – ByteHamster

+0

De hecho, es un buen hallazgo, pero desearía que hubieras tomado lo que aprendiste del ejemplo, lo aplicaras al MWE del OP e incluyeras una imagen. – aeroNotAuto

3

Un truco rápido que pueden satisfacer sus necesidades ..

quitarse el marco de la caja y la posición manualmente las dos leyendas junto a la otra. Algo como esto ..

ax1.legend(loc = (.75,.1), frameon = False) 
ax2.legend(loc = (.75, .05), frameon = False) 

Cuando la tupla loc es de izquierda a derecha y porcentajes de abajo hacia arriba que representan la ubicación en la tabla.

4

Desde matplotlib versión 2.1 en adelante, puede usar una leyenda de la figura . En lugar de ax.legend(), que produce una leyenda con los mangos de los ejes ax, se puede crear una leyenda de la figura

fig.legend(loc=1)

que reunirá a todos los mangos de todas las subtramas en la figura. Como es una leyenda de figura, se colocará en la esquina de la figura y el argumento loc 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=1) 

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

plt.show() 

enter image description here

Para colocar la leyenda de nuevo en los ejes, uno podría suministrar una bbox_to_anchor y una bbox_transform. Esta última sería la transformación de los ejes en los ejes en los que debería residir la leyenda. Los primeros pueden ser las coordenadas del borde definidas por loc indicadas en las coordenadas de los ejes.

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

enter image description here

+0

¿Ya se lanzó la versión 2.1? Pero en Anaconda 3, probé 'conda upgrade matplotlib' no se encontraron versiones más nuevas, todavía estoy usando v.2.0.2 – StayFoolish

Cuestiones relacionadas