secondary pyplot legends python matplotlib axis legend

python - pyplot - matplotlib secondary y axis



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

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

Para volver a colocar la leyenda en los ejes, se debería proporcionar un bbox_to_anchor y un bbox_transform . El último sería la transformación de los ejes de los ejes en los que debería residir la leyenda. El primero 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)

Tengo una trama con dos ejes y, utilizando twinx() . También asigno 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()

Así que solo obtengo las etiquetas 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?


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


No estoy seguro de si esta funcionalidad es nueva, pero también puede usar el método get_legend_handles_labels () en lugar de mantener un seguimiento de las líneas y las etiquetas 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 agregar fácilmente una segunda leyenda agregando la línea:

ax2.legend(loc=0)

Obtendrás esto:

Pero si quieres todas las etiquetas 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:


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 añadir 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 trama es la siguiente:

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.


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.