Mejore el tamaño/espaciado de las subparcelas con muchas subparcelas

5 minutos de lectura

avatar de usuario
mcstrother

Necesito generar un montón de gráficos apilados verticalmente en matplotlib. El resultado se guardará usando savefig y visto en una página web, por lo que no me importa la altura de la imagen final, siempre que las subparcelas estén espaciadas para que no se superpongan.

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

Mi código actualmente se parece a

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)

  • Esta pregunta también se aplica a pandas.DataFrame.plot con subparcelas, y a las parcelas a nivel de ejes marinos (aquellas con el parámetro ax): sns.lineplot(..., ax=ax)

    –Trenton McKinney

    2 de mayo a las 17:34

avatar de usuario
jose kington

Por favor revise matplotlib: guía de diseño ajustado e intenta usar matplotlib.pyplot.tight_layouto matplotlib.figure.Figure.tight_layout

Como un ejemplo rápido:

import matplotlib.pyplot as plt

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

plt.show()

Sin diseño ajustado

ingrese la descripción de la imagen aquí


Con diseño ajustado

ingrese la descripción de la imagen aquí

avatar de usuario
torre cian

Puedes usar plt.subplots_adjust para cambiar el espacio entre las subparcelas.

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 están controlados por el archivo rc

avatar de usuario
Alexa Halford

Usando subplots_adjust(hspace=0) o un número muy pequeño (hspace=0.001) eliminará por completo los espacios en blanco entre las subparcelas, mientras que hspace=None no es.

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

fig = plt.figure(figsize=(8, 8))

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

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

plt.show()

hspace=0 o hspace=0.001

ingrese la descripción de la imagen aquí

hspace=None

ingrese la descripción de la imagen aquí

avatar de usuario
La Importancia De SerErnest

Similar a tight_layout matplotlib ahora (a partir de la versión 2.2) proporciona constrained_layout. En contraste con tight_layoutque se puede llamar en cualquier momento en el código para un único diseño optimizado, constrained_layout es 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 subparcelas, 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í

constrained_layout también se puede configurar a través de rcParams

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

Ver el ¿Qué hay de nuevo? y el Guía de diseño restringido

avatar de usuario
El Demz

import matplotlib.pyplot as plt

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

los plt.subplots_adjust método:

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 importa.

“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 la trama secundaria, la imagen total debe ser más grande.

avatar de usuario
trenton mckinney

Podrías probar el .subplot_tool()

plt.subplot_tool()

  • Resolviendo este problema al trazar un marco de datos con pandas.DataFrame.plotque utiliza matplotlib como back-end predeterminado.
    • Lo siguiente funciona para lo que sea kind= se especifica (por ejemplo 'bar', 'scatter', 'hist'etc.).
  • Probado en python 3.8.12, pandas 1.3.4, matplotlib 3.4.3

Importaciones y datos de muestra

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# sinusoidal sample data
sample_length = range(1, 15+1)
rads = np.arange(0, 2*np.pi, 0.01)
data = np.array([np.sin(t*rads) for t in sample_length])
df = pd.DataFrame(data.T, index=pd.Series(rads.tolist(), name="radians"), columns=[f'freq: {i}x' for i in sample_length])

# default plot with subplots; each column is a subplot
axes = df.plot(subplots=True)

ingrese la descripción de la imagen aquí

Ajustar el espaciado

  • Ajuste los parámetros predeterminados en pandas.DataFrame.plot
    1. Cambio figsize: un ancho de 5 y una altura de 4 para cada subparcela es un buen lugar para comenzar.
    2. Cambio layout: (filas, columnas) para el diseño de subparcelas.
    3. sharey=True y sharex=True por lo que no se ocupa espacio para etiquetas redundantes en cada subparcela.
  • los .plot método devuelve una matriz numpy de matplotlib.axes.Axesque debe aplanarse para trabajar fácilmente.
  • Usar .get_figure() para extraer el DataFrame.plot figura objeto de uno de los Axes.
  • Usar fig.tight_layout() Si es deseado.
axes = df.plot(subplots=True, layout=(3, 5), figsize=(25, 16), sharex=True, sharey=True)

# flatten the axes array to easily access any subplot
axes = axes.flat

# extract the figure object
fig = axes[0].get_figure()

# use tight_layout
fig.tight_layout()

ingrese la descripción de la imagen aquí

df

# display(df.head(3))
         freq: 1x  freq: 2x  freq: 3x  freq: 4x  freq: 5x  freq: 6x  freq: 7x  freq: 8x  freq: 9x  freq: 10x  freq: 11x  freq: 12x  freq: 13x  freq: 14x  freq: 15x
radians                                                                                                                                                            
0.00     0.000000  0.000000  0.000000  0.000000  0.000000  0.000000  0.000000  0.000000  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000
0.01     0.010000  0.019999  0.029996  0.039989  0.049979  0.059964  0.069943  0.079915  0.089879   0.099833   0.109778   0.119712   0.129634   0.139543   0.149438
0.02     0.019999  0.039989  0.059964  0.079915  0.099833  0.119712  0.139543  0.159318  0.179030   0.198669   0.218230   0.237703   0.257081   0.276356   0.295520

¿Ha sido útil esta solución?