matplotlib ile birçok alt grafik için nasıl tek bir açıklama yaparım?


166

Aynı tür bilgileri planlıyorum, ancak farklı ülkeler için, matplotlib ile birden fazla alt grafik var. Yani, 3x3 ızgara üzerinde 9 satır var, hepsi satırlar için aynı (tabii ki satır başına farklı değerler).

Ancak, tek bir efsane (9 alt grafiğin hepsi aynı çizgilere sahip olduğu için) şekle nasıl bir kez yerleştirileceğini anlayamadım.

Bunu nasıl yaparım?

Yanıtlar:


161

Ayrıca, get_legend_handles_labels()son eksende arayabileceğiniz güzel bir işlev de var (bunlar üzerinde yinelerseniz) label=argümanlardan ihtiyacınız olan her şeyi toplar :

handles, labels = ax.get_legend_handles_labels()
fig.legend(handles, labels, loc='upper center')

13
Bu en iyi cevap olmalı.
naught101

1
Bu gerçekten çok daha faydalı bir cevap! Benim için daha karmaşık bir durumda böyle çalıştı.
gmaravel

1
mükemmel cevap!
Dorgham

4
Alt grafikler için göstergeyi nasıl kaldırabilirim?
BND

5
Sadece bu harika cevaba eklemek için. Arsalarınızda ikincil bir y ekseniniz varsa ve bunları birleştirmeniz gerekiyorsa, her ikisini de kullanın:handles, labels = [(a + b) for a, b in zip(ax1.get_legend_handles_labels(), ax2.get_legend_handles_labels())]
Bill

114

figlegend aradığınız şey olabilir: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.figlegend

Burada örnek: http://matplotlib.org/examples/pylab_examples/figlegend_demo.html

Başka bir örnek:

plt.figlegend( lines, labels, loc = 'lower center', ncol=5, labelspacing=0. )

veya:

fig.legend( lines, labels, loc = (0.5, 0), ncol=5 )

1
Efsaneye koymak istediğim çizgileri biliyorum, ama linesdeğişkeni tartışmaya nasıl sokabilirim legend?
patapouf_ai

1
@patapouf_ai linesdöndürülen sonuçların bir listesidir axes.plot()(yani her bir axes.plotveya benzer rutin bir "satır" döndürür). Bağlantılı örneğe de bakınız.

17

Tek bir efsanenin, figureelde edilenler gibi birçok eksende otomatik olarak konumlandırılması için subplots(), aşağıdaki çözüm gerçekten iyi çalışır:

plt.legend( lines, labels, loc = 'lower center', bbox_to_anchor = (0,-0.1,1,1),
            bbox_transform = plt.gcf().transFigure )

İle bbox_to_anchorve bbox_transform=plt.gcf().transFiguresizin için figurereferans olmak için boyutunda yeni bir sınırlama kutusu tanımlamak loc. (0,-0.1,1,1)Efsanenin diğer sanatçıların üzerine yerleştirilmesini önlemek için, bu övünen kutuyu kullanmak biraz aşağı doğru hareket eder.

OBS: kullandığınız SONRA fig.set_size_inches()ve kullanmadan ÖNCE bu çözümü kullanınfig.tight_layout()


1
Veya basit loc='upper center', bbox_to_anchor=(0.5, 0), bbox_transform=plt.gcf().transFigureve kesin örtüşmez.
Davor Josipovic

2
Neden hala emin değilim, ama Evert'in çözümü benim için işe yaramadı - efsane kesilmeye devam etti. Bu çözüm (davor'un yorumu ile birlikte) çok temiz çalıştı - efsane beklendiği gibi ve tamamen görünür hale getirildi. Teşekkürler!
sudo make install

16

Efsanenizi bir kez, döngünüzün dışında istemelisiniz.

Örneğin, bu durumda, aynı satırlara sahip 4 alt grafiğim ve tek bir efsanem var.

from matplotlib.pyplot import *

ficheiros = ['120318.nc', '120319.nc', '120320.nc', '120321.nc']

fig = figure()
fig.suptitle('concentration profile analysis')

for a in range(len(ficheiros)):
    # dados is here defined
    level = dados.variables['level'][:]

    ax = fig.add_subplot(2,2,a+1)
    xticks(range(8), ['0h','3h','6h','9h','12h','15h','18h','21h']) 
    ax.set_xlabel('time (hours)')
    ax.set_ylabel('CONC ($\mu g. m^{-3}$)')

    for index in range(len(level)):
        conc = dados.variables['CONC'][4:12,index] * 1e9
        ax.plot(conc,label=str(level[index])+'m')

    dados.close()

ax.legend(bbox_to_anchor=(1.05, 0), loc='lower left', borderaxespad=0.)
         # it will place the legend on the outer right-hand side of the last axes

show()

3
figlegend, Evert tarafından istendiği gibi, çok daha iyi bir çözüm gibi görünüyor;)
carla

11
sorun, fig.legend()tüm satırlar (araziler) için tanımlama gerektirir ... her alt grafik için, ben hatları oluşturmak için bir döngü kullanıyorum, bunun üstesinden gelmek için anladım tek çözüm daha önce boş bir liste oluşturmak için İkinci döngü ve sonra oluşturuluyor satırları ekleyin ... Sonra bu listeyi fig.legend()işlev için bir argüman olarak kullanın .
carla

Benzer bir soru burada
emmmphd

dadosOrada ne var?
Shyamkkhadka

1
@Shyamkkhadka, orijinal komut dadosdosyamda bir netCDF4 dosyasından (listede tanımlanan dosyaların her biri için) bir veri kümesi vardı ficheiros. Her döngüde farklı bir dosya okunur ve şekle bir alt grafik eklenir.
carla

14

Hiçbir cevabın, farklı alt grafiklerde birçok eğriye işaret eden tek bir efsaneye sahip bir görüntü göstermediğini fark ettim, bu yüzden size bir şey göstermeliyim ...

resim açıklamasını buraya girin

Şimdi, koda bakmak istiyorsun , değil mi?

from numpy import linspace
import matplotlib.pyplot as plt

# Calling the axes.prop_cycle returns an itertoools.cycle

color_cycle = plt.rcParams['axes.prop_cycle']()

# I need some curves to plot

x = linspace(0, 1, 51)
f1 = x*(1-x)   ; lab1 = 'x - x x'
f2 = 0.25-f1   ; lab2 = '1/4 - x + x x' 
f3 = x*x*(1-x) ; lab3 = 'x x - x x x'
f4 = 0.25-f3   ; lab4 = '1/4 - x x + x x x'

# let's plot our curves (note the use of color cycle, otherwise the curves colors in
# the two subplots will be repeated and a single legend becomes difficult to read)
fig, (a13, a24) = plt.subplots(2)

a13.plot(x, f1, label=lab1, **next(color_cycle))
a13.plot(x, f3, label=lab3, **next(color_cycle))
a24.plot(x, f2, label=lab2, **next(color_cycle))
a24.plot(x, f4, label=lab4, **next(color_cycle))

# so far so good, now the trick

lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]

# finally we invoke the legend (that you probably would like to customize...)

fig.legend(lines, labels)
plt.show()

İki çizgi

lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]

Bir açikIama - bu amaca Ben bir işlev kodu sadece 4 satır zor kısmını kapsüllü ama var ağır yorumladı

def fig_legend(fig, **kwdargs):

    # generate a sequence of tuples, each contains
    #  - a list of handles (lohand) and
    #  - a list of labels (lolbl)
    tuples_lohand_lolbl = (ax.get_legend_handles_labels() for ax in fig.axes)
    # e.g. a figure with two axes, ax0 with two curves, ax1 with one curve
    # yields:   ([ax0h0, ax0h1], [ax0l0, ax0l1]) and ([ax1h0], [ax1l0])

    # legend needs a list of handles and a list of labels, 
    # so our first step is to transpose our data,
    # generating two tuples of lists of homogeneous stuff(tolohs), i.e
    # we yield ([ax0h0, ax0h1], [ax1h0]) and ([ax0l0, ax0l1], [ax1l0])
    tolohs = zip(*tuples_lohand_lolbl)

    # finally we need to concatenate the individual lists in the two
    # lists of lists: [ax0h0, ax0h1, ax1h0] and [ax0l0, ax0l1, ax1l0]
    # a possible solution is to sum the sublists - we use unpacking
    handles, labels = (sum(list_of_lists, []) for list_of_lists in tolohs)

    # call fig.legend with the keyword arguments, return the legend object

    return fig.legend(handles, labels, **kwdargs)

PS Bunun sum(list_of_lists, [])bir liste listesini düzleştirmek için gerçekten verimsiz bir yöntem olduğunu biliyorum ama compact Kompaktlığını seviyorum, ② genellikle birkaç alt grafikte birkaç eğri ve ③ Matplotlib ve verimlilik mi? ;-)


3

Oyuna oldukça geç kalırken, burada başka bir çözüm sunacağım, çünkü bu hala google'da gösterilen ilk bağlantılardan biri. Matplotlib 2.2.2 kullanılarak bu, gridspec özelliği kullanılarak gerçekleştirilebilir. Aşağıdaki örnekte amaç, altta gösterilen gösterge ile 2x2 şeklinde düzenlenmiş dört alt grafiğe sahip olmaktır. Göstergeyi sabit bir noktaya yerleştirmek için altta bir 'sahte' eksen oluşturulur. Daha sonra 'sahte' eksen kapatılır, böylece yalnızca gösterge gösterilir. Sonuç: https://i.stack.imgur.com/5LUWM.png .

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

#Gridspec demo
fig = plt.figure()
fig.set_size_inches(8,9)
fig.set_dpi(100)

rows   = 17 #the larger the number here, the smaller the spacing around the legend
start1 = 0
end1   = int((rows-1)/2)
start2 = end1
end2   = int(rows-1)

gspec = gridspec.GridSpec(ncols=4, nrows=rows)

axes = []
axes.append(fig.add_subplot(gspec[start1:end1,0:2]))
axes.append(fig.add_subplot(gspec[start2:end2,0:2]))
axes.append(fig.add_subplot(gspec[start1:end1,2:4]))
axes.append(fig.add_subplot(gspec[start2:end2,2:4]))
axes.append(fig.add_subplot(gspec[end2,0:4]))

line, = axes[0].plot([0,1],[0,1],'b')           #add some data
axes[-1].legend((line,),('Test',),loc='center') #create legend on bottommost axis
axes[-1].set_axis_off()                         #don't show bottommost axis

fig.tight_layout()
plt.show()

3

çubuk grafikler içeren alt grafikler, her çubuk için farklı renk kullanıyorsanız. kullandığınız eserleri oluşturmak daha hızlı olabilirmpatches

r m c kEfsaneyi aşağıdaki gibi ayarlayabileceğiniz için farklı renklere sahip dört çubuğunuz olduğunu varsayalım

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
labels = ['Red Bar', 'Magenta Bar', 'Cyan Bar', 'Black Bar']


#####################################
# insert code for the subplots here #
#####################################


# now, create an artist for each color
red_patch = mpatches.Patch(facecolor='r', edgecolor='#000000') #this will create a red bar with black borders, you can leave out edgecolor if you do not want the borders
black_patch = mpatches.Patch(facecolor='k', edgecolor='#000000')
magenta_patch = mpatches.Patch(facecolor='m', edgecolor='#000000')
cyan_patch = mpatches.Patch(facecolor='c', edgecolor='#000000')
fig.legend(handles = [red_patch, magenta_patch, cyan_patch, black_patch],labels=labels,
       loc="center right", 
       borderaxespad=0.1)
plt.subplots_adjust(right=0.85) #adjust the subplot to the right for the legend

1
+1 En iyisi! Bu şekilde plt.legendtüm alt grafikleri için bir efsaneye sahip olmak için doğrudan ekleyerek kullandım
Kullanıcı

Otomatik tutamaçları ve el yapımı etiketleri birleştirmek daha hızlıdır handles, _ = plt.gca().get_legend_handles_labels()fig.legend(handles, labels)
:,

1

Bu cevap, @ Evert'in efsane konumunda bir tamamlayıcısıdır.

@ Evert'in çözümü üzerindeki ilk denemem, efsane ve alt bölümün başlığı çakışması nedeniyle başarısız oldu.

Aslında, örtüşmelere fig.tight_layout(), şekil çizimlerini dikkate almadan alt grafiklerin düzenini değiştiren neden olur . Ancak fig.tight_layout()gereklidir.

Çakışmaları önlemek fig.tight_layout()için, figürün efsanesi için boşluk bırakmayı söyleyebiliriz fig.tight_layout(rect=(0,0,1,0.9)).

Tight_layout () parametrelerinin açıklaması .


1

@ Gboffi ve Ben Usman'ın cevabı üzerine inşa etmek için:

Birinin aynı renk ve etikete sahip farklı alt grafiklerde farklı çizgileri olduğu bir durumda,

labels_handles = {
  label: handle for ax in fig.axes for handle, label in zip(*ax.get_legend_handles_labels())
}

fig.legend(
  labels_handles.values(),
  labels_handles.keys(),
  loc="upper center",
  bbox_to_anchor=(0.5, 0),
  bbox_transform=plt.gcf().transFigure,
)
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.