Вторичная ось с twinx (): как добавить в легенду? - PullRequest
238 голосов
/ 30 марта 2011

У меня есть график с двумя осями Y, используя twinx(). Я также даю метки линиям и хочу показать их с помощью legend(), но мне удалось получить метки только одной оси в легенде:

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

Таким образом, я получаю только метки первой оси в легенде, а не метку 'temp' второй оси. Как я могу добавить этот третий ярлык к легенде?

enter image description here

Ответы [ 6 ]

292 голосов
/ 30 марта 2011

Вы можете легко добавить вторую легенду, добавив строку:

ax2.legend(loc=0)

Вы получите это:

enter image description here

Но если вы хотите, чтобы всенадписей на одной легенде, тогда вы должны сделать что-то вроде этого:

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

Что даст вам это:

enter image description here

150 голосов
/ 12 апреля 2012

Я не уверен, что эта функция является новой, но вы также можете использовать метод get_legend_handles_labels () вместо того, чтобы отслеживать строки и метки самостоятельно:

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()
42 голосов
/ 18 ноября 2017

Начиная с версии 2.1 для matplotlib, вы можете использовать рисунок с легендой .Вместо ax.legend(), который создает легенду с ручками от осей ax, можно создать легенду фигуры

<b>fig.legend(loc=1)</b>

, которая соберет все маркеры из всех вспомогательных участков на рисунке.Поскольку это легенда фигуры, она будет размещена в углу фигуры, а аргумент loc относится к фигуре.

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

Чтобы поместить легенду обратно в оси, нужно указать bbox_to_anchor и bbox_transform.Последним будет преобразование осей осей, в которых должна находиться легенда. Первым могут быть координаты ребра, определенные как loc, заданные в координатах осей.

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

enter image description here

35 голосов
/ 14 мая 2014

Вы можете легко получить то, что хотите, добавив строку в топоре:

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

или

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

Это ничего не изменит, кроме добавления метки к легенде об топоре.

Я думаю, что это намного проще. Нет необходимости автоматически отслеживать линии, когда у вас есть только несколько линий на вторых осях, так как ручная фиксация, как описано выше, будет довольно простой. Во всяком случае, это зависит от того, что вам нужно.

Весь код как показано ниже:

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

Сюжет как ниже:

enter image description here


Обновление: добавить лучшую версию:

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

Это ничего не даст, пока plot(0, 0) может изменить диапазон оси.

6 голосов
/ 05 октября 2015

Быстрый взлом, который может удовлетворить ваши потребности ..

Снимите рамку коробки и вручную расположите две легенды рядом друг с другом. Как то так ..

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

Где кортеж loc - это проценты слева направо и снизу вверх, которые представляют местоположение на диаграмме.

5 голосов
/ 05 марта 2015

Я нашел следующий официальный пример matplotlib, который использует host_subplot для отображения нескольких осей y и всех различных меток в одной легенде.Обходной путь не требуется.Лучшее решение, которое я нашел до сих пор.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()
...