472 Stimmen

Sekundäre Achse mit twinx(): wie zur Legende hinzufügen?

Ich habe ein Diagramm mit zwei Y-Achsen, das twinx() . Ich beschrifte auch die Linien und möchte sie mit legend() , aber es gelingt mir nur, die Beschriftungen einer Achse in der Legende zu erhalten:

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

Ich erhalte also nur die Beschriftungen der ersten Achse in der Legende, aber nicht die Beschriftung "temp" der zweiten Achse. Wie kann ich diese dritte Beschriftung in die Legende einfügen?

enter image description here

573voto

Paul Punkte 39492

Sie können ganz einfach eine zweite Legende hinzufügen, indem Sie die Zeile hinzufügen:

ax2.legend(loc=0)

Das werden Sie bekommen:

enter image description here

Wenn Sie aber alle Beschriftungen in einer Legende haben wollen, sollten Sie so vorgehen:

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

Daraus ergibt sich Folgendes:

enter image description here

306voto

zgana Punkte 2642

Ich bin mir nicht sicher, ob diese Funktionalität neu ist, aber Sie können auch die Methode get_legend_handles_labels() verwenden, anstatt selbst die Zeilen und Beschriftungen zu verfolgen:

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

180voto

Ab matplotlib Version 2.1 können Sie eine Abbildungslegende . Anstelle von ax.legend() die eine Legende mit den Griffen der Achsen erzeugt ax kann man eine Figurenlegende erstellen

fig.legend(loc="upper right")

die alle Griffe von allen Teilflächen in der Abbildung sammelt. Da es sich um eine Abbildungslegende handelt, wird sie in der Ecke der Abbildung platziert, und die loc ist relativ zur Abbildung.

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

enter image description here

Um die Legende wieder in die Achsen zu setzen, würde man eine bbox_to_anchor und eine bbox_transform . Letzteres wäre die Achsentransformation der Achsen, in denen sich die Legende befinden soll. Ersteres können die Koordinaten der Kante sein, die durch loc in Achsenkoordinaten angegeben.

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

enter image description here

57voto

Syrtis Major Punkte 3423

Sie können das Gewünschte leicht erreichen, indem Sie die Zeile in ax hinzufügen:

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

または

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

Dies würde nichts anderes tun, als die Legende der Axt mit einem Etikett zu versehen.

Ich denke, das ist eine viel einfachere Methode. Es ist nicht notwendig, Linien automatisch zu verfolgen, wenn man nur ein paar Linien in der zweiten Achse hat, da die Fixierung von Hand wie oben ziemlich einfach wäre. Jedenfalls hängt es davon ab, was Sie brauchen.

Der gesamte Code lautet wie folgt:

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

Die Handlung ist wie folgt:

enter image description here


Update: eine bessere Version hinzugefügt:

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

Dies wird nichts bewirken, solange plot(0, 0) kann sich der Achsenbereich ändern.


Ein zusätzliches Beispiel für Streuung

ax.scatter([], [], s=100, label = 'temp')  # Make an agent in ax
ax2.scatter(time, temp, s=10)  # The true scatter in ax2

ax.legend(loc=1, framealpha=1)

19voto

Suuuehgi Punkte 3458

Vorbereitung

import numpy as np
from matplotlib import pyplot as plt

fig, ax1 = plt.subplots( figsize=(15,6) )

Y1, Y2 = np.random.random((2,100))

ax2 = ax1.twinx()

Inhalt

Ich bin überrascht, dass es bisher nicht aufgetaucht ist, aber der einfachste Weg ist, sie entweder manuell in einem der Achsen-Objs (die übereinander liegen) zu sammeln

l1 = ax1.plot( range(len(Y1)), Y1, label='Label 1' )
l2 = ax2.plot( range(len(Y2)), Y2, label='Label 2', color='orange' )

ax1.legend( handles=l1+l2 )

Plot_axes

oder lassen Sie sie automatisch in die umgebende Figur einsammeln, indem Sie fig.legend() und fummeln Sie an der bbox_to_anchor Parameter:

ax1.plot( range(len(Y1)), Y1, label='Label 1' )
ax2.plot( range(len(Y2)), Y2, label='Label 2', color='orange' )

fig.legend( bbox_to_anchor=(.97, .97) )

Plot_figlegend

Fertigstellung

fig.tight_layout()
fig.savefig('stackoverflow.png', bbox_inches='tight')

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X