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

Tengo una ttwig con dos ejes y, utilizando twinx() . También asigno tags a las líneas y quiero mostrarlas con legend() , pero solo logro obtener las tags 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() 

Así que solo obtengo las tags del primer eje en la leyenda, y no la etiqueta ‘temp’ del segundo eje. ¿Cómo podría añadir esta tercera etiqueta a la leyenda?

introduzca la descripción de la imagen aquí

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

 ax2.legend(loc=0) 

Obtendrás esto:

introduzca la descripción de la imagen aquí

Pero si quieres todas las tags en una leyenda, debes 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() 

Lo que te dará esto:

introduzca la descripción de la imagen aquí

No estoy seguro de si esta funcionalidad es nueva, pero también puede usar el método get_legend_handles_labels () en lugar de seguir las líneas y las tags usted 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() 

Puede obtener fácilmente lo que desea al agregar la línea en el hacha:

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

o

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

Esto no trazaría nada más que agregar una etiqueta a la leyenda del hacha.

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

El código completo es el 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 ttwig es la siguiente:

introduzca la descripción de la imagen aquí


Actualización: agregar una mejor versión:

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

Esto no hará nada mientras que la plot(0, 0) puede cambiar el rango del eje.

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

  fig.legend (loc = 1) 

que reunirá todos los manejadores de todas las subplots en la figura. Dado que es una leyenda de la figura, se colocará en la esquina de la figura y el argumento loc será 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() 

introduzca la descripción de la imagen aquí

Para volver a colocar la leyenda en los ejes, se debería proporcionar un bbox_to_anchor y un bbox_transform . La última sería la transformación de los ejes de los ejes en los que debería residir la leyenda. La primera puede ser las coordenadas del borde definido por el lugar dado en las coordenadas de los ejes.

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

introduzca la descripción de la imagen aquí

Un truco rápido que puede satisfacer sus necesidades.

Quite el marco de la caja y coloque manualmente las dos leyendas una al lado de la otra. Algo como esto..

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

Donde la tupla de locación es de izquierda a derecha y los porcentajes de abajo a arriba que representan la ubicación en el gráfico.

Encontré un siguiente ejemplo oficial de matplotlib que usa host_subplot para mostrar varios ejes y y todas las diferentes tags 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()