Mejore el tamaño / espacio de la subtrama con muchas subtramas en matplotlib

313

Muy similar a esta pregunta, pero con la diferencia de que mi figura puede ser tan grande como debe ser.

Necesito generar un montón de parcelas apiladas verticalmente en matplotlib. El resultado se guardará usando figsave y se verá en una página web, por lo que no me importa qué tan alta sea la imagen final siempre que las subtramas estén espaciadas para que no se superpongan.

No importa cuán grande permita que sea la figura, las subtramas siempre parecen superponerse.

Mi código actualmente se ve así

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
fuente

Respuestas:

413

Intenta usar plt.tight_layout

Como un ejemplo 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()

Sin diseño apretado

ingrese la descripción de la imagen aquí


Con diseño apretado ingrese la descripción de la imagen aquí

Joe Kington
fuente
21
Sería un poco más claro si muestra que debe ejecutar esto después de su código de trama, pero justo antes de show ()
pyj
55
tight_layout()es impredecible. He estado tratando de entender lo que es diferente cuando se tiene ningún efecto (grandes márgenes entre la trama se mantienen) - que a menudo es
javadba
3
Esto funcionó bastante bien para mí, excepto que superpuso mi título de figura ( suptitle) con mi título de subtrama. En caso de que alguien encuentre un problema similar, esto es lo que ayudó en mi caso stackoverflow.com/a/45161551/11740420 . A saber, el rectparámetro detight_layout()
Siyana Pavlova
285

Puede usar plt.subplots_adjustpara cambiar el espacio entre las subtramas (fuente)

firma de llamada:

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

Los significados de los parámetros (y los valores predeterminados sugeridos) son:

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

Los valores predeterminados reales son controlados por el archivo rc

CyanRook
fuente
3
He intentado jugar con hspace, pero aumentarlo solo parece hacer que todos los gráficos sean más pequeños sin resolver el problema de superposición. También he intentado jugar con los otros parámetros, pero no sé qué izquierda, derecha, abajo y arriba están especificando allí.
mcstrother 01 de
52
@mcstrother puede cambiar interactivamente los 6 parámetros si hace clic en el botón de 'ajuste' después de mostrar un diagrama, luego cópielos en el código una vez que encuentre lo que funciona.
Nick T
1
No veo un botón de ajuste. Aunque estoy en un cuaderno Jupyter. Probé% matplotlib en línea y% matplotlib notebook.
Matt Kleinsmith
1
@MattKleinsmith: el botón de ajuste tiene el texto emergente "Configurar subtramas" y aparece en usos regulares de Matplotlib que no son portátiles. Es el botón a la izquierda del botón de guardar "disquete" aquí: pythonspot-9329.kxcdn.com/wp-content/uploads/2016/07/… - tenga en cuenta que el botón se ve diferente dependiendo del sistema de ventanas que esté usando usando, pero siempre está a la izquierda del botón Guardar.
John Zwinck
@JohnZwinck, el enlace en su comentario está muerto ahora.
user4015990
56

Descubrí que subplots_adjust (hspace = 0.001) es lo que terminó funcionando para mí. Cuando uso space = None, todavía hay espacio en blanco entre cada parcela. Sin embargo, establecerlo en algo muy cercano a cero parece obligarlos a alinearse. Lo que he subido aquí no es el código más elegante, pero puedes ver cómo funciona el espacio h.

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()

ingrese la descripción de la imagen aquí

Alexa Halford
fuente
31
import matplotlib.pyplot as plt

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

El 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()

o

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

El tamaño de la imagen es importante.

"He intentado jugar con hspace, pero aumentarlo solo parece hacer que todos los gráficos sean más pequeños sin resolver el problema de superposición".

Por lo tanto, para hacer más espacio en blanco y mantener el tamaño de subtrama, la imagen total debe ser más grande.

El demz
fuente
2
El tamaño de la imagen es importante, ¡un tamaño de imagen más grande puede resolver este problema! establecido plt.figure(figsize=(10, 7)), el tamaño de la imagen sería 2000 x 1400pix
Belter
20

Similar a tight_layoutmatplotlib ahora (a partir de la versión 2.2) proporciona constrained_layout. En contraste con tight_layout, que se puede llamar en cualquier momento en el código para un diseño optimizado único, constrained_layoutes una propiedad, que puede estar activa y optimizará el diseño antes de cada paso de dibujo.

Por lo tanto, debe activarse antes o durante la creación de la subtrama, como figure(constrained_layout=True)o subplots(constrained_layout=True).

Ejemplo:

import matplotlib.pyplot as plt

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

plt.show()

ingrese la descripción de la imagen aquí

restricined_layout también se puede establecer a través de rcParams

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

Vea la entrada de novedades y la Guía de diseño restringido

Importancia de ser ernesto
fuente
1
voy a probar esto: no había visto esta opción - y tight_layoutno es confiable
javadba
esto sonaba prometedor, pero no me dio suficiente espacio (las etiquetas de los ejes y los títulos todavía se superponían) y el renderizado tomó mucho más tiempo. tight_layout()funcionó mejor
craq
2
@craq Correcto, en general contrained_layoutes más lento, porque como se ve en esta respuesta, optimiza el diseño antes de cada paso de dibujo .
ImportanceOfBeingErnest
para mí esta fue la respuesta más útil: tight_layout para mí siempre mejora el espacio vertical para dejar espacio para el título del panel, pero a costa de cortar la etiqueta del eje y cada vez. Esto, en cambio, funciona perfectamente, gracias.
Adrian Tompkins