Matplotlib tight_layout() не учитывает цифру suptitle
Если я добавлю субтитры к фигуре matplotlib, он будет наложен заголовками подзаголовков. Кто-нибудь знает, как легко позаботиться об этом? Я попробовал функцию tight_layout()
, но это только ухудшает ситуацию.
Пример:
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()
Ответы
Ответ 1
Вы можете настроить геометрию подзаговора в самом вызове tight_layout
следующим образом:
fig.tight_layout(rect=[0, 0.03, 1, 0.95])
Как указано в документации (https://matplotlib.org/users/tight_layout_guide.html):
tight_layout()
учитывает только метки, метки осей и заголовки. Таким образом, другие художники могут быть обрезаны, а также могут перекрываться.
Ответ 2
Вы можете вручную отрегулировать интервал с помощью 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()
Ответ 3
Одна вещь, которую вы можете легко изменить в коде, - это fontsize
, который вы используете для названий. Тем не менее, я собираюсь предположить, что вы не просто хотите это сделать!
Некоторые альтернативы использованию fig.subplots_adjust(top=0.85)
:
Обычно tight_layout()
выполняет довольно хорошую работу по позиционированию всего в хороших местах, чтобы они не перекрывались. Причина tight_layout()
в этом случае не помогает, потому что tight_layout()
не учитывает значение fig.suptitle(). В GitHub есть открытая проблема: https://github.com/matplotlib/matplotlib/issues/829 [закрыт в 2014 году из-за необходимости полного менеджера геометрии - сдвинут на https://github.com/matplotlib/matplotlib/issues/1109].
Если вы читаете поток, есть решение вашей проблемы с участием GridSpec
. Ключ должен оставить некоторое пространство в верхней части рисунка при вызове tight_layout
, используя rect
kwarg. Для вашей проблемы код будет выглядеть следующим образом:
Использование 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()
Результат:
![using gridspec]()
Может быть, GridSpec
немного переборщит для вас, или ваша настоящая проблема будет включать в себя гораздо больше подзаговоров на гораздо большем холсте или других осложнениях. Простой взлом - просто использовать annotate()
и заблокировать координаты для 'figure fraction'
, чтобы имитировать a suptitle
. Однако, возможно, вам потребуется внести некоторые более тонкие корректировки, если вы посмотрите на результат. Обратите внимание, что это второе решение использует не tight_layout()
.
Упрощенное решение (хотя, возможно, его необходимо настроить)
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()
Результат:
![simple]()
[Использование Python
2.7.3 (64-бит) и matplotlib
1.2.0]
Ответ 4
Альтернативным и простым в использовании решением является настройка координат текста suptitle на рисунке с использованием аргумента y в вызове suptitle (см. 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()
Ответ 5
Я боролся с методами обрезки matplotlib, поэтому теперь я просто сделал функцию, чтобы сделать это с помощью вызова bash
ImageMagick
mogrify команда, которая хорошо работает и получает все лишнее свободное пространство от края фигуры. Для этого вам необходимо использовать UNIX/Linux, использовать оболочку bash
и установить ImageMagick
.
Просто вызовите вызов после вашего вызова 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)
Ответ 6
Плотная компоновка не работает с suptitle, но constrained_layout
работает. Посмотрите этот вопрос. Увеличьте размер/интервал подзаговоров с помощью множества подзаговоров в matplotlib.
Я обнаружил, что добавление участков сразу выглядело лучше, т.е.
fig, axs = plt.subplots(rows, cols, contrained_layout=True)
# then iterating over the axes to fill in the plots
Но его также можно добавить в момент создания фигуры:
fig = plt.figure(constrained_layout=True)
ax1 = fig.add_subplot(cols, rows, 1)
# etc
Ответ 7
Как уже упоминалось, по умолчанию плотный макет не учитывает субтитры. Однако я обнаружил, что можно использовать аргумент bbox_extra_artists
для передачи субтитра в качестве ограничивающего прямоугольника, который следует учитывать:
st = fig.suptitle("My Super Title")
plt.savefig("figure.png", bbox_extra_artists=[st], bbox_inches='tight')
Это заставляет расчет suptitle
компоновки принимать во внимание suptitle
, и это выглядит так, как вы ожидаете.
Ответ 8
У меня была похожая проблема, которая возникла при использовании tight_layout
для очень большой сетки графиков (более 200 дополнительных графиков) и рендеринга в блокноте Jupyter. Я сделал быстрое решение, которое всегда размещает ваш suptitle
на определенном расстоянии над вашим верхним субплотом:
import matplotlib.pyplot as plt
n_rows = 50
n_col = 4
fig, axs = plt.subplots(n_rows, n_cols)
#make plots ...
# define y position of suptitle to be ~20% of a row above the top row
y_title_pos = axs[0][0].get_position().get_points()[1][1]+(1/n_rows)*0.2
fig.suptitle('My Sup Title', y=y_title_pos)
Для субплотов переменного размера вы все еще можете использовать этот метод, чтобы получить верхнюю часть самого верхнего субплота, а затем вручную определить дополнительную сумму для добавления в субтитр.