Matplotlib alt grafikleri için ortak xlabel / ylabel


144

Şu arsam var:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

ve şimdi bu grafiğe ortak x ekseni etiketleri ve y ekseni etiketleri vermek istiyorum. "Ortak" ile, tüm alt noktalar ızgarasının altında büyük bir x ekseni etiketi ve sağda büyük bir y ekseni etiketi olması gerektiğini kastediyorum. Dokümantasyonunda bununla ilgili hiçbir şey bulamıyorum plt.subplotsve googlinglerim plt.subplot(111)başlamak için büyük bir şey yapmam gerektiğini öneriyor - ama sonra 5 * 2 alt plaklarımı bunun içine nasıl yerleştirebilirim plt.subplots?


2
Soruya yapılan güncelleme ve aşağıdaki yanıtlarda bırakılan yorumlarla birlikte bu, stackoverflow.com/questions/6963035/… '
Hooked

Pek sayılmaz, sorum plt.subplots () için olduğundan ve bağladığınız soru add_subplot kullandığından - kaçınmak istediğim add_subplot'a geçmediğim sürece bu yöntemi kullanamam. Ben olabilir bağlantınızda alternatif bir çözüm olarak verilir plt.text çözümünü kullanabilir, ancak en zarif çözüm değildir.
jolindbe

Detaylandırmak gerekirse, anladığım kadarıyla, plt.subplots, mevcut bir eksen ortamında bir alt grafik kümesi oluşturamaz, ancak her zaman yeni bir şekil oluşturur. Sağ?
jolindbe

En zarif çözümü burada bulabilirsiniz: stackoverflow.com/questions/6963035/…
Bay H

Bağlantınız, 4 yıldan daha uzun bir süre önce Hooked kullanıcısı tarafından sağlandı (sizinkinin üzerinde sadece birkaç yorum var). Daha önce de söylediğim gibi, bu çözüm plt.subplots () değil, add_subplot ile ilgilidir.
jolindbe

Yanıtlar:


207

Bu gerçekten istediğiniz şeye benziyor. Bu cevaba aynı yaklaşımı sizin özel durumunuza da uygular :

import matplotlib.pyplot as plt

fig, ax = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6, 6))

fig.text(0.5, 0.04, 'common X', ha='center')
fig.text(0.04, 0.5, 'common Y', va='center', rotation='vertical')

Ortak eksen etiketli çoklu grafikler


4
x etiketinin x koordinatı için 0.5'in, etiketi merkez alt grafiğin merkezine koymadığını unutmayın. yticklabels'ı hesaba katmak için bundan biraz daha büyük yapmanız gerekir.
dbliss

2
Kullanmayan bir yöntem için bu yanıta bir göz atın plt.text. Alt çizimlerinizi yaratırsınız, ancak sonra bir bitlik grafik eklersiniz, onu görünmez yapar ve x ve y'yi etiketlersiniz.
James Owers

Teşekkürler, genel olarak çalıştı. Kullanırken kırılmaya yönelik herhangi bir çözüm var tight_layoutmı?
serv-inc

3
@ serv-inc ile tight_layoutdeğiştirerek 0.04çalışıyor 0gibi görünüyor.
divenex

3
Kullanmak fig.textiyi bir fikir değil. Bu durum gibi şeyleri berbat ediyorplt.tight_layout()
Peaceful

55

Bunu yeterince alakalı ve zarif bulduğum için (metni yerleştirmek için koordinatları belirtmeye gerek yok), ilgili başka bir soruya bir cevabı (küçük bir uyarlamayla) kopyalıyorum .

import matplotlib.pyplot as plt
fig, axes = plt.subplots(5, 2, sharex=True, sharey=True, figsize=(6,15))
# add a big axis, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")

Bu, aşağıdakilerle sonuçlanır (matplotlib sürüm 2.2.0 ile):

Ortak x ve y ekseni etiketlerine sahip 5 satır ve 2 sütun alt çizim


4
Basitlik nedeniyle bu kabul edilen cevap olmalıdır. Çok basit. Matplotlib v3.x için hala geçerli.
Kyle Swanson

Birden çok figür nesnesi ile nasıl kullanılabileceğini bilmek isterim? fig.xlabel ("foo") çalışmıyor.
Horror Vacui

Bilginize: Artık insanlar StackOverflow'da karanlık temalar kullandıklarından, etiketler zar zor okunabilir, bu nedenle
png'lerinizi

@xyzzyqed Stackoverflow'da "temalar" diye bir şey olduğunu bilmiyordum ve rakamı nasıl dışa aktardığımı bile hatırlamıyorum. Dışa aktarırken arka planı nasıl kontrol edebilirim?
bli

2
Bu çözümün tek sorunu, constrained_layout=Trueüst üste binen etiketler oluşturduğu için kullanıldığında çalışmamasıdır . Bu durumda, alt alanların sınırlarını manuel olarak ayarlamanız gerekir.
baccandr

35

sharex=True, sharey=TrueSen olmadan :

görüntü açıklamasını buraya girin

Bununla onu daha güzel hale getirmelisin:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))

plt.tight_layout()

görüntü açıklamasını buraya girin

Ancak ek etiketler eklemek isterseniz, bunları yalnızca kenar grafiklerine eklemelisiniz:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))
        if i == len(axes2d) - 1:
            cell.set_xlabel("noise column: {0:d}".format(j + 1))
        if j == 0:
            cell.set_ylabel("noise row: {0:d}".format(i + 1))

plt.tight_layout()

görüntü açıklamasını buraya girin

Her arsa için etiket eklemek onu bozacaktır (belki tekrarlanan etiketleri otomatik olarak algılamanın bir yolu vardır, ancak ben farkında değilim).


Örneğin grafiklerin sayısı bilinmiyorsa bu çok daha zordur (örneğin, herhangi bir sayıda alt grafik için çalışan bir genelleştirilmiş grafik fonksiyonuna sahipseniz).
naught101

15

Komuttan beri:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

Eğer (ben değiştim akılda böyle bir şey yapmak zaten yeterlidir, tuple şekil ve eksenler örneklerinin bir listeden oluşan getiri kullanılan fig,axiçin fig,axes):

fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

for ax in axes:
    ax.set_xlabel('Common x-label')
    ax.set_ylabel('Common y-label')

Belirli bir subplot bazı ayrıntılarını değiştirmek istediğiniz ne varsa, üzerinden erişebilirsiniz axes[i]nerede isenin subplots üzerinde dolaşır.

Eklemek de çok yararlı olabilir.

fig.tight_layout()

plt.show()üst üste binen etiketleri önlemek için dosyanın sonunda .


5
Üzgünüm yukarıda biraz belirsizdim. "Ortak" ile, tüm grafiklerin altında tek bir x etiketi ve grafiklerin solundaki tek bir y etiketini kastetmiştim, soruyu bunu yansıtacak şekilde güncelledim.
jolindbe

2
@JohanLindberg: Buradaki ve yukarıdaki yorumlarınızla ilgili olarak: Indeed plt.subplots()yeni bir figür örneği yaratacaktır. Bu komuta bağlı kalmak istiyorsanız, big_ax = fig.add_subplot(111)zaten bir şekle sahip olduğunuz ve başka bir eksen ekleyebildiğiniz için kolayca a ekleyebilirsiniz. Bundan sonra, big_axHooked'dan bağlantıda gösterilme şeklini değiştirebilirsiniz .
Marius

Önerileriniz için teşekkürler, ancak bunu yaparsam, big_ax'ı plt.subplots () 'dan sonra eklemem gerekir ve bu alt grafiği her şeyin üstüne alırım - onu şeffaf yapabilir miyim veya bir şekilde arka tarafa gönderebilir miyim? Hooked'ın bağlantısındaki gibi tüm renkleri sıfıra ayarlasam bile, bu hala tüm alt noktalarımı kaplayan beyaz bir kutu.
jolindbe

2
@JohanLindberg, haklısın, bunu kontrol etmemiştim. Ancak aşağıdakileri noneyaparak büyük eksenin arka plan rengini kolayca ayarlayabilirsiniz : big_ax.set_axis_bgcolor('none')Ayrıca etiket rengini de yapmalısınız none(Hooked tarafından bağlanan örneğin aksine):big_ax.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')
Marius

2
Bir hata alıyorum: AttributeError: 'numpy.ndarray' object has no attribute 'set_xlabel'ifadede ax.set_xlabel('Common x-label'). Çözebilir misin?
hengxin

5

Sol alt köşedeki alt alan için görünmez etiketler yaparak ortak etiketler için yer ayırırsanız daha iyi görünecektir. Ayrıca rcParams'dan yazı tipi boyutunu aktarmak da iyidir. Bu şekilde, ortak etiketlerin boyutu rc kurulumunuzla değişecek ve eksenler de ortak etiketler için yer bırakacak şekilde ayarlanacaktır.

fig_size = [8, 6]
fig, ax = plt.subplots(5, 2, sharex=True, sharey=True, figsize=fig_size)
# Reserve space for axis labels
ax[-1, 0].set_xlabel('.', color=(0, 0, 0, 0))
ax[-1, 0].set_ylabel('.', color=(0, 0, 0, 0))
# Make common axis labels
fig.text(0.5, 0.04, 'common X', va='center', ha='center', fontsize=rcParams['axes.labelsize'])
fig.text(0.04, 0.5, 'common Y', va='center', ha='center', rotation='vertical', fontsize=rcParams['axes.labelsize'])

görüntü açıklamasını buraya girin görüntü açıklamasını buraya girin


1
Görünmez etiketin güzel kullanımı! Teşekkür ederim
colelemonz

3

Bir grafik ızgarası çizerken benzer bir problemle karşılaştım. Grafikler iki bölümden oluşuyordu (üst ve alt). Y etiketinin her iki parçanın da ortalanması gerekiyordu.

Dış şekildeki konumu bilmeye bağlı bir çözüm kullanmak istemedim (fig.text () gibi), bu yüzden set_ylabel () işlevinin y konumunu değiştirdim. Genellikle eklendiği arsanın ortası 0,5'tir. Kodumdaki bölümler (hspace) arasındaki dolgu sıfır olduğundan, iki bölümün ortasını üst bölüme göre hesaplayabildim.

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

# Create outer and inner grid
outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1])
somePlot = gridspec.GridSpecFromSubplotSpec(2, 1,
               subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0)

# Add two partial plots
partA = plt.subplot(somePlot[0])
partB = plt.subplot(somePlot[1])

# No x-ticks for the upper plot
plt.setp(partA.get_xticklabels(), visible=False)

# The center is (height(top)-height(bottom))/(2*height(top))
# Simplified to 0.5 - height(bottom)/(2*height(top))
mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0])
# Place the y-label
partA.set_ylabel('shared label', y = mid)

plt.show()

resim

Downsides:

  • Grafiğe olan yatay mesafe üst kısma bağlıdır, alt keneler etiketin içine uzanabilir.

  • Formül, parçalar arasında dikkate alınmaz.

  • Üst kısmın yüksekliği 0 olduğunda bir istisna atar.

Muhtemelen rakamlar arasındaki dolguyu dikkate alan genel bir çözüm vardır.


Hey, cevabınız doğrultusunda bunu yapmanın bir yolunu çok buldum, ama bu sorunlardan bazılarını çözebilir; bakınız stackoverflow.com/a/44020303/4970632 (aşağıda)
Luke Davis

2

Güncelleme:

Bu özellik artık yakın zamanda pypi'de yayınladığım proplot matplotlib paketinin bir parçası . Varsayılan olarak, şekiller oluşturduğunuzda etiketler eksenler arasında "paylaşılır".


Orijinal cevap:

Daha sağlam bir yöntem keşfettim:

Bir başlatmaya giden bottomve topkwarg'ları biliyorsanız GridSpecveya eksenlerinizin Figurekoordinatlarındaki kenar konumlarını biliyorsanız , ilabel konumunu Figurebazı süslü "dönüştürme" sihriyle koordinatlarda da belirtebilirsiniz . Örneğin:

import matplotlib.transforms as mtransforms
bottom, top = .1, .9
f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top)
avepos = (bottom+top)/2
a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory(
       mtransforms.IdentityTransform(), f.transFigure # specify x, y transform
       )) # changed from default blend (IdentityTransform(), a[0].transAxes)
a[0].yaxis.label.set_position((0, avepos))
a[0].set_ylabel('Hello, world!')

... ve etiketin , tıpkı normal gibi, onay etiketleriyle örtüşmesini önlemek için sol-sağa uygun şekilde ayarlandığını görmelisiniz - ama şimdi her zaman tam olarak istenen alt noktalar arasında olacak şekilde ayarlanacaktır .

Dahası, kullanmazsanız bile set_position, ilabel varsayılan olarak tam olarak rakamın yarısında görünecektir . Tahminimce bunun nedeni, etiket sonunda çizildiğinde, temel koordinat dönüşümünün değişip değişmediğini kontrol etmeden-koordinat matplotlibiçin 0.5 kullanmasıdır y.

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.