Twinx () ile ikincil eksen: efsaneye nasıl eklenir?


289

Kullanarak, iki y ekseni ile bir komplo var twinx(). Ayrıca satırlara etiketler veriyorum ve bunları göstermek istiyorum legend(), ancak efsanede sadece bir eksenin etiketlerini almayı başardım:

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

Bu yüzden, sadece ikinci eksenin etiketlerini alıyorum, ikinci eksenin 'temp' etiketini değil. Bu üçüncü etiketi efsaneye nasıl ekleyebilirim?

resim açıklamasını buraya girin


4
[ Bunu herhangi bir üretim koduna yakın bir yerde yapmayın ] Tek amacım uygun efsane ASAP ile güzel bir arsa oluşturmak olduğunda, üzerinde axkullandığım stille boş bir dizi çizmek için çirkin bir hack kullanıyorum ax2: senin davanın ax.plot([], [], '-r', label = 'temp').
Neinstein

Yanıtlar:


371

Satırı ekleyerek kolayca ikinci bir gösterge ekleyebilirsiniz:

ax2.legend(loc=0)

Bunu alacaksınız:

resim açıklamasını buraya girin

Ancak tüm etiketlerin bir efsanede olmasını istiyorsanız, böyle bir şey yapmalısınız:

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

Hangi size verecek:

resim açıklamasını buraya girin


2
Bu errorbararazilerle başarısız oluyor . Bunları doğru şekilde işleyen bir çözüm için aşağıya bakın: stackoverflow.com/a/10129461/1319447
Davide

1
İki .legend (loc = 0) belirttiğim durumda olduğu gibi çakışan iki efsaneyi önlemek için, gösterge konumu değeri için iki farklı değer belirtmelisiniz (her ikisi de 0 dışında). Bakınız: matplotlib.org/api/legend_api.html
Roalt

Birden fazla satırlı bazı alt grafiğe tek bir satır eklemekte biraz sorun yaşadım ax1. Bu durumda kullanın lns1=ax1.linesve ardından lns2bu listeye ekleyin .
Küçük Bobby Masaları

Tarafından kullanılan farklı değerler buradaloc açıklanmıştır
Dror

1
Daha otomatik bir yol için aşağıdaki cevaba bakın (matplotlib> = 2.1 ile): stackoverflow.com/a/47370214/653364
joris

183

Bu işlevin yeni olup olmadığından emin değilim, ancak satırları ve etiketleri kendiniz izlemek yerine get_legend_handles_labels () yöntemini de kullanabilirsiniz:

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
Bu, arazilerin efsanelerle örtüştüğü eksenleri işleyebilen tek çözümdür (son eksen, efsaneleri
çizmesi

5
Bu çözüm errorbargrafiklerle de çalışır , kabul edilen başarısız olur (bir satırı ve hata çubuklarını ayrı ayrı gösterir ve hiçbiri doğru etikete sahip değildir). Artı, daha basit.
Davide

hafif yakalama: etiketin üzerine yazmak istiyorsanız işe yaramaz ax2ve başlangıçtan bir seti yoktur
Ciprian Tomoiagă

Not: Klasik grafikler için etiket argümanını belirtmenize gerek yoktur. Ancak diğerleri için, ör. barlar gerekir.
belka

Bu, kaç satırın çizileceğini önceden bilmiyorsanız, her şeyi daha da kolaylaştırır.
Vegard Jervell

77

Matplotlib 2.1 sürümünden itibaren, bir şekil açıklaması kullanabilirsiniz . ax.legend()Eksenlerden kulplarla bir efsane üreten yerine, axbir figür efsanesi yaratılabilir

fig.legend (loc = "sağ üst")

Şekildeki tüm alt grafiklerden tüm tutamaçları toplayacak. Bir figür efsanesi olduğu için, figürün köşesine yerleştirilecek ve locargüman şekle göredir.

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

resim açıklamasını buraya girin

Efsaneyi tekrar eksenlere yerleştirmek için a bbox_to_anchorve a tedarik edilir bbox_transform. İkincisi, göstergenin içinde bulunması gereken eksenlerin eksen dönüşümü olacaktır. Birincisi loc, eksen koordinatlarında verilen kenarın koordinatları olabilir.

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

resim açıklamasını buraya girin


Peki, 2.1 sürümü zaten yayınlanmış mı? Ama Anaconda 3'te conda upgrade matplotlibyeni sürüm bulunamadı denedim , hala v.2.0.2 kullanıyorum
StayFoolish

1
Bu sonuç elde etmenin daha temiz bir yoludur.
Goutham

1
güzel ve
pitonik

1
Birçok alt alanınız olduğunda bu işe yaramıyor gibi görünüyor. Tüm alt grafikler için tek bir gösterge ekler. Birinin tipik olarak her alt grafik için birer göstergeye ihtiyacı vardır ve her göstergede hem birincil hem de ikincil eksenlerde seriler içerir.
sancho.s ReinstateMonicaCellio

@sancho Doğru, bu cevabın üçüncü cümlesinde yazan şey budur, "... şekildeki tüm alt grafiklerden tüm tutamaçları bir araya getirecektir.".
ImportanceOfBeingErnest

38

Çizgiyi balta ekleyerek istediğinizi kolayca elde edebilirsiniz:

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

veya

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

Bu, balta efsanesine bir etiket eklemek dışında hiçbir şey çizmez.

Bence bu çok daha kolay bir yol. Yukarıdaki gibi elle sabitlemek oldukça kolay olacağından, ikinci eksende sadece birkaç çizginiz olduğunda çizgileri otomatik olarak izlemek gerekli değildir. Neyse, neye ihtiyacınız olduğuna bağlı.

Kodun tamamı aşağıdaki gibidir:

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

Arsa aşağıdaki gibidir:

resim açıklamasını buraya girin


Güncelleme: daha iyi bir sürüm ekleyin:

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

plot(0, 0)Eksen aralığını değiştirirken bu hiçbir şey yapmaz .


Saçılma için ekstra bir örnek

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
Bunu severim. Bu sistemi çirkin şekilde çirkin, ama uygulamak çok basit.
Daniel Power

Bunu uygulamak gerçekten çok basit. Ancak bunu saçılma ile kullanırken, efsanede ortaya çıkan saçılma boyutu sadece küçük bir noktadır.
greeeeeeen

@greeeeeeen Sonra dağılım grafiği yaparken işaretleyici boyutunu belirtmelisiniz :-)
Syrtis Major

@SyrtisMajor I, elbette, bunu denedim. Ancak bu, efsanedeki işaretçi boyutunu değiştirmedi.
greeeeeeen

@greeeeeeen Ajan dağılımının işaretçi boyutunu değiştirdiniz mi? Yayına bak, örnek kod parçacığı ekledim.
Syrtis Major

7

İhtiyaçlarınıza uygun hızlı bir saldırı ..

Kutunun çerçevesini çıkarın ve iki efsaneyi yan yana manuel olarak konumlandırın. Böyle bir şey ..

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

Konum grubunun, grafikteki konumu temsil eden soldan sağa ve aşağıdan yukarıya yüzdeleri olduğu yerlerde.


5

Birden fazla y eksenini ve tüm etiketleri tek bir göstergede görüntülemek için host_subplot kullanan aşağıdaki resmi matplotlib örneğini buldum. Geçici çözüm gerekmez. Şimdiye kadar bulduğum en iyi çözüm. 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()

Stack Overflow'a hoş geldiniz! Hedef siteye erişilemiyorsa veya kalıcı olarak çevrimdışı olursa, lütfen bağlantının en alakalı bölümünü belirtin. Bkz . İyi bir cevabı nasıl yazarım . Gelecekte daha güncel sorulara odaklanın, bu yaklaşık 4 yaşında.
ByteHamster

Gerçekten iyi bir keşif ama keşke örnekten öğrendiklerinizi almış olmanız, OP'nin MWE'sine uygulamanız ve bir resim eklemenizi isterdim.
aeroNotAuto
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.