Melhore o tamanho / espaçamento das subparcelas com muitas subparcelas no matplotlib

313

Muito parecido com essa pergunta, mas com a diferença de que minha figura pode ser tão grande quanto precisa.

Preciso gerar um monte de gráficos empilhados verticalmente no matplotlib. O resultado será salvo usando figsave e visualizado em uma página da web. Portanto, não me importo com a altura da imagem final, contanto que as subparcelas sejam espaçadas para que não se sobreponham.

Por maior que eu permita que a figura seja, as subparcelas sempre parecem se sobrepor.

Meu código atualmente parece

import matplotlib.pyplot as plt
import my_other_module

titles, x_lists, y_lists = my_other_module.get_data()

fig = plt.figure(figsize=(10,60))
for i, y_list in enumerate(y_lists):
    plt.subplot(len(titles), 1, i)
    plt.xlabel("Some X label")
    plt.ylabel("Some Y label")
    plt.title(titles[i])
    plt.plot(x_lists[i],y_list)
fig.savefig('out.png', dpi=100)
Mcstrother
fonte

Respostas:

413

Tente usar plt.tight_layout

Como um exemplo rápido:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=4, ncols=4)
fig.tight_layout() # Or equivalently,  "plt.tight_layout()"

plt.show()

Sem layout apertado

insira a descrição da imagem aqui


Com layout apertado insira a descrição da imagem aqui

Joe Kington
fonte
21
Seria um pouco mais claro, se você mostrar que você deve executar este após o seu código de enredo, mas logo antes de show ()
PYJ
5
tight_layout()é um sucesso e um erro. Eu tenho tentado entender o que é diferente quando ele não tem efeito (grandes margens inter-enredo permanecem) - que muitas vezes é
javadba
3
Isso funcionou muito bem para mim, exceto que sobrepôs meu título da figura ( suptitle) ao título da subtrama. Caso alguém encontre um problema semelhante, eis o que ajudou no meu caso stackoverflow.com/a/45161551/11740420 . Ou seja, o rectparâmetro detight_layout()
Siyana Pavlova 28/10/19
284

Você pode usar plt.subplots_adjustpara alterar o espaçamento entre as subparcelas (origem)

assinatura de chamada:

subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)

Os significados dos parâmetros (e padrões sugeridos) são:

left  = 0.125  # the left side of the subplots of the figure
right = 0.9    # the right side of the subplots of the figure
bottom = 0.1   # the bottom of the subplots of the figure
top = 0.9      # the top of the subplots of the figure
wspace = 0.2   # the amount of width reserved for blank space between subplots
hspace = 0.2   # the amount of height reserved for white space between subplots

Os padrões reais são controlados pelo arquivo rc

CyanRook
fonte
3
Tentei mexer com o hspace, mas aumentá-lo apenas parece diminuir todos os gráficos sem resolver o problema de sobreposição. Tentei brincar com os outros parâmetros também, mas não sei o que esquerdo, direito, baixo e topo estão realmente especificando lá.
Mcstrother 01/07
52
@mcstrother, você pode alterar interativamente todos os 6 desses parâmetros se clicar no botão 'ajuste' depois de mostrar um gráfico e copiá-los no código assim que encontrar o que funciona.
Nick T
1
Não vejo um botão de ajuste. Embora eu esteja em um caderno Jupyter. Tentei o% matplotlib inline e o% matplotlib notebook.
22618 Matt Mattinsins
1
@MattKleinsmith: O botão de ajuste tem o texto suspenso "Configurar subtramas" e aparece nos usos regulares do Matplotlib que não são de notebook. É o botão à esquerda do botão de salvar "disquete" aqui: pythonspot-9329.kxcdn.com/wp-content/uploads/2016/07/… - observe que o botão parece diferente dependendo do sistema de janelas que você está usando, mas sempre à esquerda do botão Salvar.
John Zwinck
@JohnZwinck, o link no seu comentário está morto agora.
user4015990
56

Eu descobri que subplots_adjust (hspace = 0.001) é o que acabou funcionando para mim. Quando eu uso space = None, ainda há espaço em branco entre cada plot. Configurá-lo para algo muito próximo de zero, no entanto, parece forçá-los a alinhar. O que eu enviei aqui não é o código mais elegante, mas você pode ver como o hspace funciona.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tic

fig = plt.figure()

x = np.arange(100)
y = 3.*np.sin(x*2.*np.pi/100.)

for i in range(5):
    temp = 510 + i
    ax = plt.subplot(temp)
    plt.plot(x,y)
    plt.subplots_adjust(hspace = .001)
    temp = tic.MaxNLocator(3)
    ax.yaxis.set_major_locator(temp)
    ax.set_xticklabels(())
    ax.title.set_visible(False)

plt.show()

insira a descrição da imagem aqui

Alexa Halford
fonte
31
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,60))
plt.subplots_adjust( ... )

O método plt.subplots_adjust :

def subplots_adjust(*args, **kwargs):
    """
    call signature::

      subplots_adjust(left=None, bottom=None, right=None, top=None,
                      wspace=None, hspace=None)

    Tune the subplot layout via the
    :class:`matplotlib.figure.SubplotParams` mechanism.  The parameter
    meanings (and suggested defaults) are::

      left  = 0.125  # the left side of the subplots of the figure
      right = 0.9    # the right side of the subplots of the figure
      bottom = 0.1   # the bottom of the subplots of the figure
      top = 0.9      # the top of the subplots of the figure
      wspace = 0.2   # the amount of width reserved for blank space between subplots
      hspace = 0.2   # the amount of height reserved for white space between subplots

    The actual defaults are controlled by the rc file
    """
    fig = gcf()
    fig.subplots_adjust(*args, **kwargs)
    draw_if_interactive()

ou

fig = plt.figure(figsize=(10,60))
fig.subplots_adjust( ... )

O tamanho da imagem é importante.

"Tentei mexer com o hspace, mas aumentá-lo apenas parece diminuir todos os gráficos sem resolver o problema de sobreposição".

Assim, para criar mais espaço em branco e manter o tamanho da subparcela, a imagem total precisa ser maior.

The Demz
fonte
2
O tamanho da imagem é importante, um tamanho maior pode resolver esse problema! conjunto plt.figure(figsize=(10, 7)), o tamanho do quadro seria 2000 x 1400pix
Belter
20

Semelhante ao tight_layoutmatplotlib agora (a partir da versão 2.2) fornece constrained_layout. Por outro lado tight_layout, que pode ser chamado a qualquer momento no código para um único layout otimizado, constrained_layouté uma propriedade que pode estar ativa e otimizará o layout antes de cada etapa do desenho.

Portanto, ele precisa ser ativado antes ou durante a criação de subparcelas, como figure(constrained_layout=True)ou subplots(constrained_layout=True).

Exemplo:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(4,4, constrained_layout=True)

plt.show()

insira a descrição da imagem aqui

constrained_layout também pode ser definido através de rcParams

plt.rcParams['figure.constrained_layout.use'] = True

Veja a entrada de novidades e o Guia de layout restrito

ImportanceOfBeingErnest
fonte
1
vai tentar fazer isso: não tinha visto essa opção - e tight_layoutnão é confiável
javadba javadba 19/06/19
isso soou promissor, mas não me deu espaçamento suficiente (rótulos de eixos e títulos ainda se sobrepunham) e a renderização levou muito mais tempo. tight_layout()funcionou melhor
craq 01/03
2
@craq Correto, em geral contrained_layouté mais lento, porque, como visto nesta resposta, otimiza o layout antes de cada etapa do desenho .
ImportanceOfBeingErnest
para mim, essa foi a resposta mais útil - tight_layout sempre melhora o espaçamento vertical para deixar espaço para o título do painel, mas com o custo de cortar a etiqueta do eixo y de cada vez. Em vez disso, funciona perfeitamente, obrigado.
Adrian Tompkins