Удаление пробелов вокруг сохраненного изображения в matplotlib

172

Мне нужно взять изображение и сохранить его после некоторого процесса. Фигура выглядит хорошо, когда я ее отображаю, но после сохранения фигуры у меня появилось свободное пространство вокруг сохраненного изображения. Я попробовал 'tight'вариант для savefigметода, тоже не работал. Код:

  import matplotlib.image as mpimg
  import matplotlib.pyplot as plt

  fig = plt.figure(1)
  img = mpimg.imread(path)
  plt.imshow(img)
  ax=fig.add_subplot(1,1,1)

  extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
  plt.savefig('1.png', bbox_inches=extent)

  plt.axis('off') 
  plt.show()

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

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import networkx as nx

G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_edge(1,3)
G.add_edge(1,2)
pos = {1:[100,120], 2:[200,300], 3:[50,75]}

fig = plt.figure(1)
img = mpimg.imread("C:\\images\\1.jpg")
plt.imshow(img)
ax=fig.add_subplot(1,1,1)

nx.draw(G, pos=pos)

extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches = extent)

plt.axis('off') 
plt.show()
Ахмет Тугрул Байрак
источник
1
Возможный дубликат Сохранения фигуры matplotlib / networkx без полей
Джоэл
Что мне действительно помогло, так это обрезать PDF с помощью другого инструмента, такого как pdfcrop.
Толивейра

Ответы:

170

Я не могу утверждать, что точно знаю, почему или как работает мое «решение», но это то, что я должен был сделать, когда хотел построить контур пары секций аэродинамического профиля - без белых полей - в файле PDF. (Обратите внимание, что я использовал matplotlib внутри записной книжки IPython с флагом -pylab.)

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.savefig("filename.pdf", bbox_inches = 'tight',
    pad_inches = 0)

Я пытался деактивировать разные части этого, но это всегда приводило к белым полям где-то. Возможно, вам даже придется изменить это, чтобы жирные линии около границ фигуры не были выбриты из-за отсутствия полей.

Йоханнес С.
источник
6
Наконец то, что работает, большое спасибо! Кстати, в моем случае set_major_locatorнужны были только две линии .
Флориан Брукер
6
Я провел последний час, пробуя разные вещи, и не смог избавиться от белой границы в 1 пиксель. Это было единственное, что сработало, а именно то, pad_inches=0что другие ответы не упоминают.
AnnanFay
1
set_major_locatorбыл ключом для меня.
Kmac
16
pad_inchesпомог мне.
Майлз Бейкер
5
matplotlib.ticker.NullLocator ()
Joop
201

Вы можете удалить заполнение пробелов, установив bbox_inches="tight"в savefig:

plt.savefig("test.png",bbox_inches='tight')

Вы должны будете указать аргумент bbox_inchesв виде строки, возможно, именно поэтому он раньше не работал для вас.


Возможные дубликаты:

Сюжеты Matplotlib: удаление осей, легенд и пробелов

Как установить поля для рисунка matplotlib?

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

Увлеченные
источник
1
Если у вас есть несколько дочерних участков и вы хотите сохранить каждый из них, вы можете использовать это fig.savefig()тоже. ( plt.savefig()не будет работать в этом случае.)
Абхранил Дас
30
Это не совсем верно. Когда вы используете эту bbox_inchesопцию, есть другое значение по умолчанию, которое оставляет некоторое пространство. Если вы действительно хотите избавиться от всего, вам также нужно использовать pad_inches=0.0. Конечно, такие жесткие отступы часто обрезают, например, показатели степени ...
Майк
5
Чтобы убрать и черный край, вам может понадобиться установитьpad_inches=-0.1
lenhhoxung
10
Это просто не работает, вы все еще получаете пробел вокруг фигуры. Установка опции прозрачности (как упоминалось в некоторых ответах) тоже не очень помогает, пробелы все еще есть, она только прозрачна.
BjornW
1
@piperchester - это хороший вопрос, но, вероятно, его следует задать как новый вопрос, чтобы он не терялся в комментариях. Вы должны связать новый вопрос со старым, хотя!
Повесить
21

После безуспешных попыток ответить на вышеизложенные ответы (и множество других сообщений в стеке) у меня наконец получилось просто

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.savefig("myfig.pdf")

Важно отметить, что это не включает аргументы bbox или padding.

SuaveSouris
источник
4
Это должен быть принятый ответ. Кроме того, вам даже не нужно звонить set_axis_off. Это не влияет на сохраненное изображение, так как после того, subplots_adjustкак ось лежит вне экстента фигуры, и в любом случае, черта не будет построена. Однако в записных книжках Jupyter необходимо явно отключить ось, поскольку встроенный сервер перезаписывает эти параметры.
MaxPowers
20

Я нашел что-то от Арвинда Перейры ( http://robotics.usc.edu/~ampereir/wordpress/?p=626 ) и, похоже, работал на меня:

plt.savefig(filename, transparent = True, bbox_inches = 'tight', pad_inches = 0)
unclerico
источник
7
transparent=Trueпокажется, что проблем нет, но он просто скроет пустое пространство, размеры изображения не будут в порядке.
Влады Веселинов
Спасибо за упоминание pad_inches! Я хотел бы знать об этой опции раньше!
ingomueller.net
1
Это работает для большинства графиков, но это убрало правую границу для моей матрицы путаницы. Просто добавьте небольшой отступpad_inches=.25
YTZ
14

Следующая функция включает в себя ответ Йоханнеса выше. Я проверил его plt.figureи plt.subplots()с несколькими осями, и он прекрасно работает.

def save(filepath, fig=None):
    '''Save the current image with no whitespace
    Example filepath: "myfig.png" or r"C:\myfig.pdf" 
    '''
    import matplotlib.pyplot as plt
    if not fig:
        fig = plt.gcf()

    plt.subplots_adjust(0,0,1,1,0,0)
    for ax in fig.axes:
        ax.axis('off')
        ax.margins(0,0)
        ax.xaxis.set_major_locator(plt.NullLocator())
        ax.yaxis.set_major_locator(plt.NullLocator())
    fig.savefig(filepath, pad_inches = 0, bbox_inches='tight')
TomNorway
источник
Работал как шарм. Предыдущий ответ был несколько обязательных команд в моем экспорте.
Кевин С.
11

Я обнаружил, что следующие коды отлично работают для этой работы.

fig = plt.figure(figsize=[6,6])
ax = fig.add_subplot(111)
ax.imshow(data)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.set_frame_on(False)
plt.savefig('data.png', dpi=400, bbox_inches='tight',pad_inches=0)
Ричард Ю Лю
источник
2
Как правило, ответы гораздо полезнее, если они включают в себя объяснение того, для чего предназначен код, и почему это решает проблему, не представляя других.
Тим Дикманн
7

я следовал за этой последовательностью, и это работало как очарование.

plt.axis("off")
fig=plt.imshow(image array,interpolation='nearest')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('destination_path.pdf',
    bbox_inches='tight', pad_inches=0, format='pdf', dpi=1200)
хан
источник
1
На самом деле, я нашел этот ответ более простым и удобным в использовании.
Сикисис
1
Этот работал для меня; принятого ответа нет.
Джо
3

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

Плюс обычный тебе тоже понадобится

from matplotlib.transforms import Bbox

Тогда вы можете использовать следующее:

my_dpi = 100 # Good default - doesn't really matter

# Size of output in pixels
h = 224
w = 224

fig, ax = plt.subplots(1, figsize=(w/my_dpi, h/my_dpi), dpi=my_dpi)

ax.set_position([0, 0, 1, 1]) # Critical!

# Do some stuff
ax.imshow(img)
ax.imshow(heatmap) # 4-channel RGBA
ax.plot([50, 100, 150], [50, 100, 150], color="red")

ax.axis("off")

fig.savefig("saved_img.png",
            bbox_inches=Bbox([[0, 0], [w/my_dpi, h/my_dpi]]),
            dpi=my_dpi)

введите описание изображения здесь

Саймон Томас
источник
Вам не нужно указывать dpi, fig.dpiвместо этого вы можете использовать значение по умолчанию
intsco
1

Я нашел гораздо более простой подход plt.imsave:

    import matplotlib.pyplot as plt
    arr = plt.imread(path)
    plt.imsave('test.png', arr)
Parth92
источник
Недооцененный ответ. Это помогло мне после долгих поисков, как сохранить разрешение и удалить пробелы с помощью plt.savefig().
nihal111
Это работает только в том случае, если вы хотите сохранить массив (!) Как изображение. Это не позволяет сохранить произвольную фигуру.
MaxPowers
Что вы подразумеваете под произвольным изображением? Разве изображение не является массивом значений?
Parth92
0

Вы можете попробовать это. Это решило мою проблему.

import matplotlib.image as mpimg
img = mpimg.imread("src.png")
mpimg.imsave("out.png", img, cmap=cmap)
user1410665
источник
0

Это сработало для меня plt.savefig(save_path,bbox_inches='tight', pad_inches=0, transparent=True)

Мухаммед
источник
Не уверен, что это отличается от других ответов, опубликованных здесь.
BigBen
-1

Если вы хотите отобразить то, что должно быть сохранено, я рекомендую использовать plt.tight_layoutпреобразование, которое на самом деле является более предпочтительным, поскольку оно не приводит к ненужной обрезке при использованииplt.savefig

import matplotlib as plt    
plt.plot([1,2,3], [1,2,3])
plt.tight_layout(pad=0)
plt.savefig('plot.png')
Кето
источник
-4

Это работает для меня, сохраняя массив numpy, построенный с помощью imshow, в файл

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,10))
plt.imshow(img) # your image here
plt.axis("off")
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
        hspace = 0, wspace = 0)
plt.savefig("example2.png", box_inches='tight', dpi=100)
plt.show()
Алехандро Сазо
источник