Matplotlib tight_layout () şekil üstyazısını dikkate almaz


211

Matplotlib şeklime bir altyazı eklersem, alt grafiğin başlıkları üzerine bindirilir. Bununla nasıl ilgileneceğini bilen var mı? tight_layout()İşlevi denedim , ama sadece işleri daha da kötüleştiriyor.

Misal:

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.tight_layout()
plt.show()

Yanıtlar:


185

tight_layoutAşağıdaki çağrıda alt grafik geometrisini aşağıdaki gibi ayarlayabilirsiniz :

fig.tight_layout(rect=[0, 0.03, 1, 0.95])

Belgelerde belirtildiği gibi ( https://matplotlib.org/users/tight_layout_guide.html ):

tight_layout()yalnızca işaret etiketlerini, eksen etiketlerini ve başlıkları dikkate alır. Böylece, diğer sanatçılar kırpılabilir ve üst üste gelebilir.


1
Cazibe gibi çalıştı, ancak sınırlama kutusunu belirlerken değişiklik nasıl olur? Dokümanı okudum ama bana pek açık değildi. Bana açıklayabilirsen harika olur! Teşekkürler.
thepunitsingh

2
rektteki her sayının anlamını açıklar mısınız? Onları doktorda görmedim.
steven

6
@steven bkz. tight_layoutdokümanlar:[left, bottom, right, top] in normalized (0, 1) figure coordinates
soupault

2
: Hatta daha en doğru değerinin düşürülmesiyle suptitle ve eksenler arasındaki boşluğu artırabilir tight_layout(rect=[0, 0.03, 1, 0.9])yerine 0.95cevap olarak.
ComFreek

1
Jupyter içinde çalışmadı. Sayılar için farklı değerler denedim, hiçbir etkisi olmadı
Aleksejs Fomins

114

Boşluğu manuel olarak aşağıdakileri kullanarak ayarlayabilirsiniz plt.subplots_adjust(top=0.85):

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.subplots_adjust(top=0.85)
plt.show()

5
Aradığınızda top için varsayılan değerin 0.9 olduğunu unutmayınsubplots_adjust
Brian Burns

73
Lordumuzun 2017 yılında bu hala bir matplotlib hatası olduğuna inanamıyorum.
wordsforthewise

29
Bunun herhangi bir çağrıdan sonrasubplots_adjust çağrılması gerektiğini veya çağrının herhangi bir etkisi olmayacağını unutmayın . tight_layoutsubplots_adjust
Achal Dave

7
@wordsforthewise 2018'i şimdi yapın
vlsd

6
@vlsd Merhaba 2019
Xiaoyu Lu

55

Kodunuzda kolayca değiştirebileceğiniz bir şey fontsize, başlıklar için kullanmanızdır. Ancak, sadece bunu yapmak istemediğinizi varsayacağım!

Kullanmanın bazı alternatifleri fig.subplots_adjust(top=0.85):

Genellikle tight_layout(), üst üste binmemek için her şeyi iyi konumlara yerleştirmede oldukça iyi bir iş çıkarır. Nedeni tight_layout()bu durumda yardımcı olmaz çünkü tight_layout()fig.suptitle () dikkate almaz. GitHub'da bununla ilgili açık bir sorun var: https://github.com/matplotlib/matplotlib/issues/829 [tam bir geometri yöneticisi gerektirdiği için 2014'te kapatıldı - https://github.com/matplotlib/matplotlib adresine kaydırıldı / konular / 1109 ].

Konuyu okursanız, sorununuzu içeren bir çözüm var GridSpec. Anahtar, kwarg'u tight_layoutkullanarak arama yaparken şeklin üstünde biraz boşluk bırakmaktır rect. Sorununuz için kod şöyle olur:

GridSpec kullanma

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

f = np.random.random(100)
g = np.random.random(100)

fig = plt.figure(1)
gs1 = gridspec.GridSpec(1, 2)
ax_list = [fig.add_subplot(ss) for ss in gs1]

ax_list[0].plot(f)
ax_list[0].set_title('Very Long Title 1', fontsize=20)

ax_list[1].plot(g)
ax_list[1].set_title('Very Long Title 2', fontsize=20)

fig.suptitle('Long Suptitle', fontsize=24)    

gs1.tight_layout(fig, rect=[0, 0.03, 1, 0.95])  

plt.show()

Sonuç:

gridspec kullanma

Belki GridSpecsizin için biraz abartıyor, ya da gerçek probleminiz çok daha büyük bir tuval ya da diğer komplikasyonlarda daha fazla alt grafik içerecektir. Basit bir kesmek sadece taklit annotate()etmek için koordinatları kullanmak ve kilitlemektir . Yine de, çıktıya bir göz attığınızda bazı daha ince ayarlamalar yapmanız gerekebilir. Bu ikinci çözüm olmadığını Not değil kullanın .'figure fraction'suptitletight_layout()

Daha basit çözüm (yine de ince ayar yapılması gerekebilir)

fig = plt.figure(2)

ax1 = plt.subplot(121)
ax1.plot(f)
ax1.set_title('Very Long Title 1', fontsize=20)

ax2 = plt.subplot(122)
ax2.plot(g)
ax2.set_title('Very Long Title 2', fontsize=20)

# fig.suptitle('Long Suptitle', fontsize=24)
# Instead, do a hack by annotating the first axes with the desired 
# string and set the positioning to 'figure fraction'.
fig.get_axes()[0].annotate('Long Suptitle', (0.5, 0.95), 
                            xycoords='figure fraction', ha='center', 
                            fontsize=24
                            )
plt.show()

Sonuç:

basit

[ Python2.7.3 (64 bit) ve matplotlib1.2.0 kullanarak]


1
Teşekkürler, önerdiğiniz ilk çözümü kullanırsam (kullanarak GridSpec) eksenleri paylaşan alt grafikleri nasıl oluşturabilirim? Genellikle plt.subplots(N,1, sharex=<>, sharey=<>)alt grafikler oluştururken kullanıyorum , ancak yayınladığınız kod add_subplotbunun yerine kullanıyor
Amelio Vazquez-Reina

10
Döküm fig.tight_layout(rect=[0, 0.03, 1, 0.95])de işe yarıyor.
soupault

1
İkinci çözüm benim için çalışan tek çözüm. Teşekkür ederim!
Hagbard

19

Alternatif ve kullanımı kolay bir çözüm, altyazı çağrısındaki y bağımsız değişkenini kullanarak şekilde üstyazı metninin koordinatlarını ayarlamaktır (bkz. Dokümanlar ):

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', y=1.05, fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.show()

8
Bu bir not defterinde harika bir yoldur, ancak plt.savefig () komutuna uymaz. Bu çözüm hala bir savefig komutunda başlığı keser.
Süper kahraman

11

Sıkı düzen, suptitle ile çalışmaz, ancak çalışır constrained_layout. Bu soruya bakın matplotlib'deki birçok alt grafikle alt grafik boyutunu / aralığını geliştirin

Alt grafikleri eklemeyi bir kerede daha iyi görünüyordu, yani

fig, axs = plt.subplots(rows, cols, constrained_layout=True)

# then iterating over the axes to fill in the plots

Ancak, figürün oluşturulduğu noktada da eklenebilir:

fig = plt.figure(constrained_layout=True)

ax1 = fig.add_subplot(cols, rows, 1)
# etc

Not: Alt grafiklerimı birbirine daha yakın hale getirmek için

fig.subplots_adjust(wspace=0.05)

ve constrained_layout bununla çalışmaz :(


4

Ben şimdi sadece bir ile bunu yapma bir işlev yaptık yüzden yöntemler kırparak matplotlib ile mücadele bashetmek çağrısı ImageMagickbireyin mogrify komuta iyi çalışıyor ve Heykelcigin kenarından tüm ekstra boşluk alır. Bunun için UNIX / Linux kullanmanız, bashkabuğu kullanmanız ve ImageMagickyüklemiş olmanız gerekir.

Aramanızdan sonra savefig()buna bir çağrı yapın.

def autocrop_img(filename):
    '''Call ImageMagick mogrify from bash to autocrop image'''
    import subprocess
    import os

    cwd, img_name = os.path.split(filename)

    bashcmd = 'mogrify -trim %s' % img_name
    process = subprocess.Popen(bashcmd.split(), stdout=subprocess.PIPE, cwd=cwd)

4

Başkaları tarafından belirtildiği gibi, sıkı düzen varsayılan olarak altyazıyı dikkate almaz. Ancak, bbox_extra_artistsdikkate alınması gereken bir sınırlama kutusu olarak altyazı geçmek için argümanı kullanmak mümkün bulduk :

st = fig.suptitle("My Super Title")
plt.savefig("figure.png", bbox_extra_artists=[st], bbox_inches='tight')

Bu, sıkı düzen hesaplamasını dikkate almaya zorlar ve suptitlebeklediğiniz gibi görünür.


Benim için işe yarayan tek seçenek bu. Rakamlar yapmak ve kaydetmek için Jupyter defterlerini kullanıyorum. Bir Linux makinesinde python 3.6'da çalışıyorum.
GRquanti

2

Benim için işe yarayan tek şey, suptitle çağrısını değiştirmekti:

fig.suptitle("title", y=.995)

1

tight_layoutArsalar (200'den fazla alt grafik) çok büyük bir ızgara için kullanırken ve bir jupyter defter render sırasında kırpılmış benzer bir sorun vardı . Her zaman suptitleüst alt grafiğinizin üzerinde belirli bir mesafeye yerleştiren hızlı bir çözüm yaptım :

import matplotlib.pyplot as plt

n_rows = 50
n_col = 4
fig, axs = plt.subplots(n_rows, n_cols)

#make plots ...

# define y position of suptitle to be ~20% of a row above the top row
y_title_pos = axs[0][0].get_position().get_points()[1][1]+(1/n_rows)*0.2
fig.suptitle('My Sup Title', y=y_title_pos)

Değişken boyutlu alt grafikler için, yine de en üstteki alt grafiğin en üstünü almak için bu yöntemi kullanabilirsiniz, ardından altyazıya eklemek için manuel olarak ek bir miktar tanımlayabilirsiniz.

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.