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