alt planlar için pyplot eksen etiketleri


187

Aşağıdaki komplo var:

import matplotlib.pyplot as plt

fig2 = plt.figure()
ax3 = fig2.add_subplot(2,1,1)
ax4 = fig2.add_subplot(2,1,2)
ax4.loglog(x1, y1)
ax3.loglog(x2, y2)
ax3.set_ylabel('hello')

Sadece iki alt grafiğin her biri için değil, aynı zamanda her iki alt grafiğe yayılan ortak etiketler için eksen etiketleri ve başlıkları oluşturabilmek istiyorum. Örneğin, her iki grafikte de aynı eksenler bulunduğundan, yalnızca bir set x ve y ekseni etiketine ihtiyacım var. Yine de her alt bölüm için farklı başlıklar istiyorum.

Birkaç şey denedim ama hiçbiri işe yaramadı

Yanıtlar:


261

İki alt grafiği kapsayan büyük bir alt grafik oluşturabilir ve sonra ortak etiketleri ayarlayabilirsiniz.

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in xrange(len(x))]
y2 = [random.randint(1, 100) for _ in xrange(len(x))]

fig = plt.figure()
ax = fig.add_subplot(111)    # The big subplot
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

# Turn off axis lines and ticks of the big subplot
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.tick_params(labelcolor='w', top=False, bottom=False, left=False, right=False)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
ax.set_xlabel('common xlabel')
ax.set_ylabel('common ylabel')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels.png', dpi=300)

common_labels.png

Başka bir yol, ortak etiketlerin konumlarını doğrudan ayarlamak için fig.text () yöntemini kullanmaktır.

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in xrange(len(x))]
y2 = [random.randint(1, 100) for _ in xrange(len(x))]

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
fig.text(0.5, 0.04, 'common xlabel', ha='center', va='center')
fig.text(0.06, 0.5, 'common ylabel', ha='center', va='center', rotation='vertical')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels_text.png', dpi=300)

common_labels_text.png


1
Suptitle işlevi fig.text () sürümünü kullanır. Yani bunu yapmanın "resmi" yolu olabilir mi?
PhML

4
It yetmeyecek vurgulayan axönce oluşturulmalıdır ax1ve ax2aksi büyük arsa küçük araziler kadar karşılar.
1 ''

Genel çizim parametreleri (görünür) bir ızgara içeriyorsa ax.grid (False) veya plt.grid (False) de gereklidir.
Næreen

3
Görünüşe göre ilk yaklaşım artık matplotplib'in son sürümleriyle çalışmıyor (2.0.2 kullanıyorum): kapalı baltaya eklenen etiketler görünmüyor.
M.Toya

Her bir alt grafiğe y_labels nasıl eklenir?
Fardin

115

Kullanmanın basit bir yolu subplots:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(3, 4, sharex=True, sharey=True)
# add a big axes, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axes
plt.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')
plt.grid(False)
plt.xlabel("common X")
plt.ylabel("common Y")

1
Genel çizim parametreleri (görünür) bir ızgara içeriyorsa ax.grid (False) veya plt.grid (False) de gereklidir.
Næreen

1
Bunu bir (5, 1) alt grafiği için yapıyorum ve benim ylabel yerine alt grafikleri yakın pencerenin sol kenarında yoludur.
Evidlo

1
Bir oy hakkınız var. ancak lütfen kodun ne yaptığını her zaman açıklayın, bir resim ekleyin veya bir örnek gösterin, çünkü bunu elde etmek biraz zaman aldı.
Kareem Jeiroudi

4
Değişim 'off'için FalseMatplotlib daha yeni sürümleri ile (I 2.2.2 var)
Ted

2
Peki grafikleri nasıl eklersiniz? for ax in axes: ax.plot(x, y)iyi gelmiyor.
usernumber

16

Wen-wei Liao'nun cevabı, vektör grafikleri dışa aktarmaya çalışmıyorsanız veya matplotlib arka uçlarınızı renksiz eksenleri yok saymak için ayarladıysanız iyidir; aksi halde gizli eksenler dışa aktarılan grafikte görünür.

suplabelBurada cevabım işlevi fig.suptitlekullanan ile benzer fig.text. Bu nedenle sanatçıların yaratıldığı ve renksiz hale getirildiği eksenler yoktur. Ancak, birden çok kez çağırmaya çalışırsanız, metnin üst üste eklenmesi sağlanır (olduğu fig.suptitlegibi). Wen-wei Liao'nun cevabı vermez, çünkü fig.add_subplot(111)zaten oluşturulmuşsa aynı Axes nesnesini döndürür.

İşlevlerim, grafikler oluşturulduktan sonra da çağrılabilir.

def suplabel(axis,label,label_prop=None,
             labelpad=5,
             ha='center',va='center'):
    ''' Add super ylabel or xlabel to the figure
    Similar to matplotlib.suptitle
    axis       - string: "x" or "y"
    label      - string
    label_prop - keyword dictionary for Text
    labelpad   - padding from the axis (default: 5)
    ha         - horizontal alignment (default: "center")
    va         - vertical alignment (default: "center")
    '''
    fig = pylab.gcf()
    xmin = []
    ymin = []
    for ax in fig.axes:
        xmin.append(ax.get_position().xmin)
        ymin.append(ax.get_position().ymin)
    xmin,ymin = min(xmin),min(ymin)
    dpi = fig.dpi
    if axis.lower() == "y":
        rotation=90.
        x = xmin-float(labelpad)/dpi
        y = 0.5
    elif axis.lower() == 'x':
        rotation = 0.
        x = 0.5
        y = ymin - float(labelpad)/dpi
    else:
        raise Exception("Unexpected axis: x or y")
    if label_prop is None: 
        label_prop = dict()
    pylab.text(x,y,label,rotation=rotation,
               transform=fig.transFigure,
               ha=ha,va=va,
               **label_prop)

Bu en iyi cevap imo. Uygulaması kolaydır ve labelpad seçeneği nedeniyle etiketler çakışmaz.
Arthur Dent

8

İşte grafiklerden birinin ylabelini ayarladığınız ve konumunu dikey olarak ortalanacak şekilde ayarladığınız bir çözüm. Bu şekilde KYC tarafından bahsedilen sorunlardan kaçınırsınız.

import numpy as np
import matplotlib.pyplot as plt

def set_shared_ylabel(a, ylabel, labelpad = 0.01):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0].get_position().y1
    bottom = a[-1].get_position().y0

    # get the coordinates of the left side of the tick labels 
    x0 = 1
    for at in a:
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
    tick_label_left = x0

    # set position of label
    a[-1].set_ylabel(ylabel)
    a[-1].yaxis.set_label_coords(tick_label_left - labelpad,(bottom + top)/2, transform=f.transFigure)

length = 100
x = np.linspace(0,100, length)
y1 = np.random.random(length) * 1000
y2 = np.random.random(length)

f,a = plt.subplots(2, sharex=True, gridspec_kw={'hspace':0})
a[0].plot(x, y1)
a[1].plot(x, y2)
set_shared_ylabel(a, 'shared y label (a. u.)')

resim açıklamasını buraya girin


7

plt.setp() işi yapacak:

# plot something
fig, axs = plt.subplots(3,3, figsize=(15, 8), sharex=True, sharey=True)
for i, ax in enumerate(axs.flat):
    ax.scatter(*np.random.normal(size=(2,200)))
    ax.set_title(f'Title {i}')

# set labels
plt.setp(axs[-1, :], xlabel='x axis label')
plt.setp(axs[:, 0], ylabel='y axis label')

resim açıklamasını buraya girin


Bu yöntemle yazı tipi boyutunu / ağırlığını ayarlamanın bir yolu var mı?
pfabri

3
# list loss and acc are your data
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

ax1.plot(iteration1, loss)
ax2.plot(iteration2, acc)

ax1.set_title('Training Loss')
ax2.set_title('Training Accuracy')

ax1.set_xlabel('Iteration')
ax1.set_ylabel('Loss')

ax2.set_xlabel('Iteration')
ax2.set_ylabel('Accuracy')

1

Diğer cevaplardaki yöntemler yticks büyük olduğunda düzgün çalışmaz. Ylabel kenelerle kenetlenir, solda kırpılır veya şeklin tamamen görünmez / dışında olur.

Hagne'nin cevabını değiştirdim, böylece hem xlabel hem de ylabel için 1'den fazla alt alan sütunu ile çalışıyor ve ylabel'i şekilde görülebilmesi için çizimi kaydırıyor.

def set_shared_ylabel(a, xlabel, ylabel, labelpad = 0.01, figleftpad=0.05):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0,0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0,0].get_position().y1
    bottom = a[-1,-1].get_position().y0

    # get the coordinates of the left side of the tick labels
    x0 = 1
    x1 = 1
    for at_row in a:
        at = at_row[0]
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
            x1 = bboxes.x1
    tick_label_left = x0

    # shrink plot on left to prevent ylabel clipping
    # (x1 - tick_label_left) is the x coordinate of right end of tick label,
    # basically how much padding is needed to fit tick labels in the figure
    # figleftpad is additional padding to fit the ylabel
    plt.subplots_adjust(left=(x1 - tick_label_left) + figleftpad)

    # set position of label, 
    # note that (figleftpad-labelpad) refers to the middle of the ylabel
    a[-1,-1].set_ylabel(ylabel)
    a[-1,-1].yaxis.set_label_coords(figleftpad-labelpad,(bottom + top)/2, transform=f.transFigure)

    # set xlabel
    y0 = 1
    for at in axes[-1]:
        at.set_xlabel('')  # just to make sure we don't and up with multiple labels
        bboxes, _ = at.xaxis.get_ticklabel_extents(fig.canvas.renderer)
        bboxes = bboxes.inverse_transformed(fig.transFigure)
        yt = bboxes.y0
        if yt < y0:
            y0 = yt
    tick_label_bottom = y0

    axes[-1, -1].set_xlabel(xlabel)
    axes[-1, -1].xaxis.set_label_coords((left + right) / 2, tick_label_bottom - labelpad, transform=fig.transFigure)

Aşağıdaki örnek için çalışır, Hagne'nin yanıtı ylabel çizmez (tuvalin dışında olduğu için) ve KYC'nin ylabel kene etiketleriyle çakışır:

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
set_shared_ylabel(axes, 'common X', 'common Y')
plt.show()

Alternatif olarak, renksiz eksende iyiyseniz, Julian Chen'in çözümünü değiştirdim, böylece ylabel kene etiketleriyle çakışmayacak.

Temel olarak, sadece renksiz ylims'i ayarlamamız gerekiyor, böylece alt parsellerin en büyük ylim'leriyle eşleşiyor, böylece renksiz kene etiketleri ylabel için doğru konumu ayarlıyor.

Kırpmayı önlemek için arsayı daraltmak zorundayız. Burada küçültmek için miktarı kodladım, ancak sizin için çalışan bir sayı bulmak için oynayabilir veya yukarıdaki yöntemdeki gibi hesaplayabilirsiniz.

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
miny = maxy = 0
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
    miny = min(miny, a.get_ylim()[0])
    maxy = max(maxy, a.get_ylim()[1])

# add a big axes, hide frame
# set ylim to match the largest range of any subplot
ax_invis = fig.add_subplot(111, frameon=False)
ax_invis.set_ylim([miny, maxy])

# 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")

# shrink plot to prevent clipping
plt.subplots_adjust(left=0.15)
plt.show()
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.