and python matplotlib

python - and - Matplotlib tight_layout() no tiene en cuenta figura suptitle



matplotlib subplot size (5)

Si agrego un subtítulo a mi figura matplotlib, se superpone con los títulos de la subtrama. ¿Alguien sabe cómo cuidarlo fácilmente? tight_layout() función tight_layout() , pero solo empeora las cosas.

Ejemplo:

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


He luchado con los métodos de recorte matplotlib, así que acabo de hacer una función para hacer esto a través de una llamada bash al comando mogrify de ImageMagick , que funciona bien y saca todo el espacio en blanco de la figura. Esto requiere que esté usando UNIX / Linux, esté utilizando el shell bash y tenga instalado ImageMagick .

Simplemente savefig() una llamada a esto después de su llamada a savefig() .

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)


Puede ajustar la geometría de la subtrama en la llamada muy tight_layout siguiente manera:

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

Como se afirma en la documentación ( https://matplotlib.org/users/tight_layout_guide.html ):

tight_layout() solo considera ticklabels, etiquetas de ejes y títulos. Por lo tanto, otros artistas pueden ser recortados y también pueden superponerse.

La comunidad de PS me recomendó que publicara mi comentario como respuesta.


Puede ajustar manualmente el espaciado usando 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()


Una cosa que podrías cambiar fácilmente en tu código es el fontsize fuente que estás usando para los títulos. Sin embargo, voy a suponer que no solo quieres hacer eso.

Algunas alternativas al uso de fig.subplots_adjust(top=0.85) :

Por tight_layout() general, tight_layout() hace un buen trabajo al colocar todo en buenas ubicaciones para que no se superpongan. La razón por la cual tight_layout() no ayuda en este caso es porque tight_layout() no tiene en cuenta fig.suptitle (). Hay un problema abierto sobre esto en GitHub: https://github.com/matplotlib/matplotlib/issues/829 [se cerró en 2014 debido a que se requiere un administrador de geometría completo - se cambió a https://github.com/matplotlib/matplotlib/issues/1109 ].

Si lee el hilo, hay una solución para su problema que involucra a GridSpec . La clave es dejar algo de espacio en la parte superior de la figura al llamar a tight_layout , usando el rect kwarg. Para su problema, el código se convierte en:

Usando GridSpec

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

El resultado:

Tal vez GridSpec sea ​​un poco exagerado para usted, o su problema real involucrará muchas más subtramas en un lienzo mucho más grande u otras complicaciones. Un simple truco es simplemente usar annotate() y bloquear las coordenadas a la ''figure fraction'' para imitar un suptitle . Sin embargo, es posible que necesite hacer algunos ajustes más finos una vez que eche un vistazo a la salida. Tenga en cuenta que esta segunda solución no usa tight_layout() .

Solución más simple (aunque puede ser necesario ajustarla)

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

El resultado:

[Usando Python 2.7.3 (64-bit) y matplotlib 1.2.0]


Una solución alternativa y fácil de usar es ajustar las coordenadas del texto del subtítulo en la figura usando el argumento y en la llamada de suptitle (ver los docs ):

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