Matplotlib sharp_layout () не принимает во внимание фигуры - PullRequest
142 голосов
/ 24 ноября 2011

Если я добавлю субтитры к моей фигуре 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()

Ответы [ 8 ]

114 голосов
/ 18 июля 2017

Вы можете настроить геометрию подзаговора в самом вызове tight_layout следующим образом:

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

Как указано в документации (https://matplotlib.org/users/tight_layout_guide.html):

tight_layout() учитывает только метки, метки осей и заголовки. Таким образом, другие художники могут быть обрезаны, а также могут перекрываться.

P.S. Сообщество рекомендовало мне оставить свой комментарий в качестве ответа.

103 голосов
/ 24 ноября 2011

Вы можете вручную настроить интервал, используя 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()
49 голосов
/ 28 октября 2013

Одна вещь, которую вы можете очень легко изменить в своем коде - это 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, используя kwarg rect, оставить место в верхней части фигуры. Для вашей проблемы код становится:

Использование 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', чтобы имитировать 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]

18 голосов
/ 09 февраля 2015

Альтернативное и простое в использовании решение - настроить координаты текста субтитра на рисунке, используя аргумент y в вызове suptitle (см. документы ):

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()
4 голосов
/ 27 августа 2014

Я боролся с методами обрезки 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)
0 голосов
/ 09 июля 2019

Tight layout не работает с 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
0 голосов
/ 23 июня 2019

Как уже упоминалось, по умолчанию плотный макет не учитывает субтитры.Тем не менее, я обнаружил, что можно использовать аргумент bbox_extra_artists для передачи субтитра в качестве ограничивающего прямоугольника, который следует учитывать:

st = fig.suptitle("My Super Title")
plt.savefig("figure.png", bbox_extra_artists=[st], bbox_inches='tight')

Это вынуждает вычисление точного макета принять1005 *, и выглядит так, как вы ожидаете.

0 голосов
/ 12 марта 2019

У меня была похожая проблема, которая возникла при использовании 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)

Для дочерних участков переменного размера вы все равно можете использовать этот метод, чтобы получить верхнюю часть верхнего сюжета, а затем вручную определить дополнительную сумму для добавления в субтитр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...