Axe secondaire avec twinx (): comment ajouter à la légende?

j'ai un tracé avec deux axes en y, en utilisant twinx() . Je donne aussi des étiquettes aux lignes, et je veux les montrer avec legend() , mais je ne réussis à obtenir les étiquettes d'un axe dans la légende:

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

donc je n'obtiens que les étiquettes du premier axe dans la légende, et pas l'étiquette 'temp' du deuxième axe. Comment pourrais-je ajouter cette troisième étiquette de la légende?

enter image description here

192
demandé sur joris 2011-03-30 14:10:56

6 réponses

Vous pouvez facilement ajouter une deuxième légende en ajoutant la ligne:

ax2.legend(loc=0)

, Vous obtiendrez ceci:

enter image description here

mais si vous voulez toutes les étiquettes sur une légende, alors vous devriez faire quelque chose comme ceci:

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

qui vous donnera ceci:

enter image description here

240
répondu Paul 2011-03-30 13:32:09

Je ne suis pas sûr que cette fonctionnalité soit nouvelle, mais vous pouvez également utiliser la méthode get_legend_handles_labels() plutôt que de garder une trace des lignes et des étiquettes vous-même:

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()
123
répondu zgana 2012-04-12 18:21:22

, Vous pouvez facilement obtenir ce que vous voulez en ajoutant la ligne ax:

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

ou

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

cela ne ferait qu'ajouter une étiquette à la légende de la hache.

je pense que c'est un moyen beaucoup plus facile. Il n'est pas nécessaire de suivre les lignes automatiquement lorsque vous avez seulement quelques lignes dans les second axes, car la fixation à la main comme ci-dessus serait assez facile. De toute façon, ça dépend de ce dont tu as besoin.

le le code entier est comme ci-dessous:

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 parcelle est comme suit:

enter image description here


mise à jour: ajouter une meilleure version:

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

cela ne fera rien alors que plot(0, 0) peut changer la plage des axes.

27
répondu Syrtis Major 2017-05-08 12:28:36

à partir de la version 2.1 de matplotlib, vous pouvez utiliser une légende . Au lieu de ax.legend() , qui produit une légende avec les poignées des axes ax , on peut créer une légende de figure

fig.legend(loc=1)

qui rassemblera toutes les poignées de tous les sous-lots de la figure. Comme il s'agit d'une légende de figure, elle sera placée au coin de la figure, et l'argument loc est relatif à la figure.

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

pour replacer la légende dans les axes, on fournit un bbox_to_anchor et un bbox_transform . Ce dernier serait la transformation des axes des axes dans lesquels la légende devrait résider. La première peut être les coordonnées du bord défini par loc données en coordonnées d'axes.

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

enter image description here

20
répondu ImportanceOfBeingErnest 2017-11-18 21:01:28

un piratage rapide qui pourrait convenir à vos besoins..

enlevez le cadre de la boîte et placez manuellement les deux légendes l'une à côté de l'autre. Quelque chose comme cela..

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

où le N-UPL est le pourcentage de gauche à droite et le pourcentage de bas en haut qui représentent l'emplacement dans le graphique.

6
répondu user2105997 2015-10-05 20:28:51

j'ai trouvé un exemple de matplotlib officiel suivant qui utilise host_subplot pour afficher plusieurs axes y et toutes les différentes étiquettes dans une légende. Pas de contournement nécessaire. La meilleure solution que j'ai trouvé jusqu'à présent. 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()
5
répondu gerrit 2015-03-17 14:15:53