twinx ()가있는 보조 축 : 범례에 추가하는 방법?


288

를 사용하여 두 개의 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'라는 레이블은 얻지 못합니다. 범례에이 세 번째 레이블을 어떻게 추가 할 수 있습니까?

여기에 이미지 설명을 입력하십시오


4
[ 제작 코드와 가까운 곳에서이 작업을 수행하지 마십시오. ] 내 유일한 목표는 적절한 범례를 최대한 사용하여 아름다운 줄거리를 생성하는 ax것입니다 ax2. 당신의 경우 ax.plot([], [], '-r', label = 'temp'). 제대로하는 것보다 훨씬 빠르고 간단합니다.
— Neinstein

답변:


370

다음 줄을 추가하여 두 번째 범례를 쉽게 추가 할 수 있습니다.

ax2.legend(loc=0)

당신은 이것을 얻을 것입니다 :

여기에 이미지 설명을 입력하십시오

그러나 하나의 범례에 모든 레이블을 원하면 다음과 같이해야합니다.

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

이것은 당신에게 이것을 줄 것입니다 :

여기에 이미지 설명을 입력하십시오


2
이것은 errorbar플롯 과 함께 실패 합니다. 올바르게 처리하는 솔루션은 아래를 참조하십시오. stackoverflow.com/a/10129461/1319447
— Davide

1
두 개의 .legend (loc = 0)을 지정한 경우와 같이 두 개의 겹치는 범례를 방지하려면 범례 위치 값 (0 이외의 값)에 서로 다른 두 개의 값을 지정해야합니다. 참조 : matplotlib.org/api/legend_api.html
— Roalt

여러 줄의 일부 줄거리에 단일 줄을 추가하는 데 문제가있었습니다 ax1. 이 경우이 목록을 사용 lns1=ax1.lines하여 추가 lns2하십시오.
— 작은 바비 테이블

사용 된 다른 값 loc들은 여기
— Dror

1
보다 자동적 인 방법은 아래의 답변을 참조하십시오 (matplotlib> = 2.1) : stackoverflow.com/a/47370214/653364
— joris

183

이 기능이 새로운 것인지 확실하지 않지만, 선과 레이블을 직접 추적하는 대신 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()

1
이것은 플롯이 범례와 겹치는 축을 처리 할 수있는 유일한 솔루션입니다 (마지막 축은 범례를 플롯해야하는 축입니다)
— Amelio Vazquez-Reina

5
이 솔루션은 errorbar플롯 과도 작동 하지만 허용 된 것은 실패합니다 (줄과 오류 표시 줄을 개별적으로 표시하고 올바른 레이블이없는 것은 없음). 게다가 더 간단합니다.
— Davide

약간의 캐치 : 레이블을 덮어 쓰려고 할 ax2때 작동하지 않으며 처음부터 설정하지 않은 것
— Ciprian Tomoiagă

참고 : 클래식 플롯의 경우 레이블 인수를 지정할 필요가 없습니다. 그러나 다른 사람들에게는, 예를 들어. 당신이 필요로하는 바.
— belka

이것은 얼마나 많은 선이 그려 질지 미리 알지 못하는 경우 모든 것을 훨씬 쉽게 만듭니다.
— Vegard Jervell

77

matplotlib 버전 2.1부터는 그림 범례를 사용할 수 있습니다 . 대신 ax.legend()축의 핸들로 범례를 생성하는 대신 ax피겨 범례를 만들 수 있습니다.

fig.legend (loc = "오른쪽 위")

그림의 모든 하위 그림에서 모든 핸들을 수집합니다. 그림 범례이므로 그림의 모퉁이에 배치되며 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="upper right")

ax.set_xlabel("x [units]")
ax.set_ylabel(r"Quantity 1")
ax2.set_ylabel(r"Quantity 2")

plt.show()

여기에 이미지 설명을 입력하십시오

범례를 다시 축에 배치하기 위해 a bbox_to_anchor와 a를 제공 bbox_transform합니다. 후자는 범례가 상주해야하는 축의 축 변환입니다. 전자는 loc축 좌표 로 지정된 가장자리의 좌표 일 수 있습니다 .

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

여기에 이미지 설명을 입력하십시오


그렇다면 2.1 버전이 이미 출시 되었습니까? 그러나 Anaconda 3에서는 conda upgrade matplotlib최신 버전을 찾지 못했습니다. v.2.0.2를 사용하고 있습니다.
— StayFoolish

1
이것은 최종 결과를 얻는 더 확실한 방법입니다.
— Goutham

1
아름답고 pythonic
— DanGoodrick

1
하위 그림이 많은 경우에는 작동하지 않는 것 같습니다. 모든 하위 그림에 대해 단일 범례를 추가합니다. 일반적으로 각 범례의 기본 축과 보조 축 모두에 시리즈를 포함하는 각 서브 플롯에 대해 하나의 범례가 필요합니다.
— sancho.s ReinstateMonicaCellio

@sancho 맞습니다. 이것이이 답변의 세 번째 문장에 쓰여진 것입니다.
— ImportanceOfBeingErnest

38

ax에 줄을 추가하여 원하는 것을 쉽게 얻을 수 있습니다.

ax.plot([], [], '-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()

줄거리는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오


업데이트 : 더 나은 버전을 추가하십시오.

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

이것은 plot(0, 0)축 범위를 변경할 수있는 동안 아무 것도하지 않습니다 .


산포에 대한 추가 예

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)

3
나는 이것을 좋아한다. 그것은 시스템을 "트릭"하는 방식에있어서 추악하지만 구현하기가 너무 간단합니다.
— Daniel Power

이것은 실제로 구현하기가 간단합니다. 그러나 이것을 스 캐터와 함께 사용할 때 범례의 결과 스 캐터 크기는 아주 작은 지점입니다.
— greeeeeeen

@greeeeeeen 그럼 당신은 산점도를 만들 때 마커 크기를 지정해야합니다 :-)
— Syrtis Major

물론 @SyrtisMajor I도 시도했습니다. 그러나 이것은 범례에서 마커 크기를 변경하지 않았습니다.
— greeeeeeen

@greeeeeeen 에이전트 스 캐터의 마커 크기를 변경 했습니까? 내 게시물을 참조하십시오. 예제 코드 스 니펫을 추가했습니다.
— 시르 티스 메이저

7

필요에 맞는 빠른 해킹 ..

상자의 프레임을 벗고 두 범례를 서로 옆에 수동으로 배치하십시오. 이 같은..

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

위치 튜플이 차트에서 위치를 나타내는 왼쪽에서 오른쪽 및 아래쪽에서 위쪽 비율입니다.


5

host_subplot을 사용하여 하나의 범례에 여러 개의 y 축과 모든 다른 레이블을 표시하는 다음 공식 matplotlib 예제를 찾았습니다. 해결 방법이 필요하지 않습니다. 내가 지금까지 찾은 최고의 솔루션. 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()

스택 오버플로에 오신 것을 환영합니다! 대상 사이트에 연결할 수 없거나 영구적으로 오프라인 상태가되는 경우 링크에서 가장 관련성이 높은 부분을 인용하십시오. 좋은 답변을 작성하려면 어떻게합니까?를 참조하십시오 . 앞으로 더 많은 현재 질문에 중점을 둔이 질문은 거의 4 살입니다.
— ByteHamster

실제로 좋은 발견이지만 예제에서 배운 것을 OP의 MWE에 적용하고 이미지를 포함 시키길 바랍니다.
— aeroNotAuto
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.