Уменьшите левые и правые поля в сюжете matplotlib

178

Я изо всех сил пытаюсь разобраться с моими полями заговора в matplotlib. Я использовал приведенный ниже код для создания своей диаграммы:

plt.imshow(g)
c = plt.colorbar()
c.set_label("Number of Slabs")
plt.savefig("OutputToUse.png")

Тем не менее, я получаю выходную фигуру с большим количеством пустого пространства по обе стороны от графика. Я искал в Google и прочитал документацию по matplotlib, но, похоже, не могу найти, как это уменьшить.

robintw
источник
Является ли эта проблема количества пробелов в extentчасти imshowрисунка, или количество границ пробелов в результирующем PNG, вокруг фигуры, генерируется savefig?
unutbu
Я думаю, что и то и другое - кажется, много места как в окне просмотра, так и в PNG. Тем не менее, важным выводом является файл png, созданный savefig- так что это то, что я хотел бы отсортировать.
robintw
Я только потом обрезал их в GIMP. : /
Эндолит

Ответы:

251

Один из способов сделать это автоматически - это bbox_inches='tight'kwarg plt.savefig.

Например

import matplotlib.pyplot as plt
import numpy as np
data = np.arange(3000).reshape((100,30))
plt.imshow(data)
plt.savefig('test.png', bbox_inches='tight')

Другой способ заключается в использовании fig.tight_layout()

import matplotlib.pyplot as plt
import numpy as np

xs = np.linspace(0, 1, 20); ys = np.sin(xs)

fig = plt.figure()
axes = fig.add_subplot(1,1,1)
axes.plot(xs, ys)

# This should be called after all axes have been added
fig.tight_layout()
fig.savefig('test.png')
Джо Кингтон
источник
5
Есть ли способ сделать это по умолчанию?
эндолит
1
Если у вас есть несколько дочерних участков и вы хотите сохранить каждый из них, вы можете использовать это fig.savefig()тоже. ( plt.savefig()не будет работать в этом случае.)
Abhranil Das
1
Все, что это делает, это обрезает изображение после его рендеринга; если вы пытаетесь установить конкретное разрешение, изображение будет меньше .
детально
5
@ детально - Да. Это именно то, что он делает (хотя он также может обрезать и увеличивать изображение). Для того, что вы хотите, посмотрите fig.tight_layout(). Та функция не существовала, когда этот ответ был первоначально написан, иначе я упомянул бы это более заметно.
Джо Кингтон
2
Если у кого-то есть проблемы, используйтеfig = plt.gcf()
KyungHoon Kim
148

Вы можете настроить интервал вокруг рисунков matplotlib с помощью функции subplots_adjust ():

import matplotlib.pyplot as plt
plt.plot(whatever)
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)

Это будет работать как для фигуры на экране, так и для сохранения в файл, и это правильная функция для вызова, даже если у вас нет нескольких графиков на одной фигуре.

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

DaveP
источник
8
Значения, назначенные параметрам, а не то, насколько их нужно изменить, это то, где нужно установить маржу. Другими словами, если вы хотите увеличить
drootang
1
Имеет смысл указать, что очевидно, что вы можете указывать отрицательные значения в plt.subplots_adjust (). Это позволяет даже рисовать вне области фигуры, а также справляться с раздражающими полями.
Surchs
Это также работает с GridSpecобъектами, вызывая updateметод (см. Stackoverflow.com/a/20058199/1030876 ).
Аарон
57

Все, что тебе нужно

plt.tight_layout()

до вашего выхода.

В дополнение к сокращению полей это также плотно группирует пространство между любыми подсюжетами:

x = [1,2,3]
y = [1,4,9]
import matplotlib.pyplot as plt
fig = plt.figure()
subplot1 = fig.add_subplot(121)
subplot1.plot(x,y)
subplot2 = fig.add_subplot(122)
subplot2.plot(y,x)
fig.tight_layout()
plt.show()
user2065406
источник
7
Я думаю, что это действительно лучший метод. Он не требует сохранения фигуры, такой как `bbox = 'inj', и устраняет все другие проблемы с компоновкой в ​​узких фигурах.
dshepherd
2
это должен быть правильный ответ, потому что он ведет себя так, как вы ожидаете, так как он относится к фигуре, а не к изображению.
Маджид альДосари
Как ни странно, это также изменяет ширину фактического графика (т. Е. Пики располагаются ближе друг к другу) по сравнению с тем bbox_inches='tight', что просто обрезает пустое пространство по краям, но оставляет график в покое. Я создал фигуру с plt.figure(figsize=(10,3)).
Фриц
9

Просто используйте, ax = fig.add_axes([left, bottom, width, height]) если вы хотите точный контроль над макетом фигуры. например.

left = 0.05
bottom = 0.05
width = 0.9
height = 0.9
ax = fig.add_axes([left, bottom, width, height])
каменщик
источник
6

Если кому-то интересно, как избавиться от остальной части белого поля после применения plt.tight_layout()или fig.tight_layout(): с помощью параметра pad(который 1.08по умолчанию), вы можете сделать его еще более плотным: субплоты, как часть размера шрифта. " Так например

plt.tight_layout(pad=0.05)

уменьшит его до очень небольшого запаса. Помещение 0не работает для меня, так как это делает коробку подзаголовка также немного отрезанной.

Oberwaschlappen
источник
4
plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)
Тянь Чу
источник
1
"pad_inches = -1", потому что мой savefig производит только часть рисунка.
Ю Шен
Использование параметра в savefigфункции элегантно, однако отрицательное значение pad_inchesне обязательно необходимо в каждом случае.
MichaelHuelsen
установите его на 0, помогает
Joop
4

Проблема с matplotlibs subplots_adjust заключается в том, что введенные вами значения относятся к размеру фигуры x и y на рисунке. Этот пример для правильного определения размеров для печати PDF:

Для этого я пересчитываю относительный интервал в абсолютные значения, например:

pyplot.subplots_adjust(left = (5/25.4)/figure.xsize, bottom = (4/25.4)/figure.ysize, right = 1 - (1/25.4)/figure.xsize, top = 1 - (3/25.4)/figure.ysize)

для фигуры дюймов figure.xsize в x-измерении и дюймов figure.ysize в y-измерении. Таким образом, вся цифра имеет левое поле 5 мм, нижнее поле 4 мм, правое поле 1 мм и верхнее 3 мм внутри меток. Преобразование (x / 25.4) сделано потому, что мне нужно было преобразовать мм в дюймы.

Обратите внимание, что чистый размер диаграммы x будет «figure.xsize - левое поле - правое поле», а чистый размер диаграммы y будет «figure.ysize - нижнее поле - верхнее поле» в дюймах.

Другие фрагменты (не уверен насчет этих, я просто хотел предоставить другие параметры)

pyplot.figure(figsize = figureSize, dpi = None)

и

pyplot.savefig("outputname.eps", dpi = 100)
Сэмми
источник
3
Откуда ты взял xsizeи ysizeоткуда. Я использую эти свойства и получаюAttributeError: 'Figure' object has no attribute 'xsize'
cj5
4

вдохновленный ответом Sammys выше:

margins = {  #     vvv margin in inches
    "left"   :     1.5 / figsize[0],
    "bottom" :     0.8 / figsize[1],
    "right"  : 1 - 0.3 / figsize[0],
    "top"    : 1 - 1   / figsize[1]
}
fig.subplots_adjust(**margins)

Где figsize - это кортеж, который вы использовали в fig = pyplot.figure(figsize=...)

michaelosthege
источник
2

Для меня ответы выше не работали matplotlib.__version__ = 1.4.3на Win7. Итак, если нас интересует только само изображение (т. Е. Если нам не нужны аннотации, ось, метки, заголовок, ylabel и т. Д.), То лучше просто сохранить массив Numpy в качестве изображения, а не savefig.

from pylab import *

ax = subplot(111)
ax.imshow(some_image_numpyarray)
imsave('test.tif', some_image_numpyarray)

# or, if the image came from tiff or png etc
RGBbuffer = ax.get_images()[0].get_array()
imsave('test.tif', RGBbuffer)

Кроме того, используя функции рисования opencv (cv2.line, cv2.polylines), мы можем сделать некоторые рисунки непосредственно в массиве numpy. http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html

otterb
источник