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

285

Я новичок в Python и Matplotlib, я хотел бы просто применить цветовую карту к изображению и написать результирующее изображение, без использования осей, меток, заголовков или чего-то, что обычно автоматически добавляется matplotlib. Вот что я сделал:

def make_image(inputname,outputname):
    data = mpimg.imread(inputname)[:,:,0]
    fig = plt.imshow(data)
    fig.set_cmap('hot')
    fig.axes.get_xaxis().set_visible(False)
    fig.axes.get_yaxis().set_visible(False)
    plt.savefig(outputname)

Он успешно удаляет ось фигуры, но сохраненная фигура представляет собой белые отступы и рамку вокруг фактического изображения. Как я могу удалить их (по крайней мере, белый отступ)? Спасибо

sunmat
источник
2
Все решения по этому вопросу сосредоточены на imshow. Если у вас есть график рассеяния, вам может помочь следующий ответ: stackoverflow.com/a/40727744/4124317
ImportanceOfBeingErnest

Ответы:

374

Я думаю, что команда axis('off')решает одну из проблем более кратко, чем изменение каждой оси и границы в отдельности. Это все еще оставляет белое пространство вокруг границы как бы то ни было. Добавление bbox_inches='tight'к savefigкоманде почти приведет вас туда, вы можете увидеть в примере ниже, что оставшееся пустое пространство намного меньше, но все еще присутствует.

Обратите внимание, что более новые версии matplotlib могут требовать bbox_inches=0вместо строки 'tight'(через @episodeyang и @kadrach)

from numpy import random
import matplotlib.pyplot as plt

data = random.random((5,5))
img = plt.imshow(data, interpolation='nearest')
img.set_cmap('hot')
plt.axis('off')
plt.savefig("test.png", bbox_inches='tight')

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

Увлеченные
источник
4
По предложению unutbu, вы могли бы использовать fig = plt.figure(), ax = plt.axes([0,0,1,1]), то plt.imshow(data,interpolation="nearest". Надеемся plt.axis("off"), что в сочетании с этим он должен избавиться от всего, кроме самого изображения!
PhilMacKay
5
Объединение методов из вопроса ({fig.axes.get_xaxis (). Set_visible (False) и fig.axes.get_yaxis (). Set_visible (False)} с {plt.axis ('off')}) исправило проблему для меня. (Больше нет пробелов). И не забудьте установить для {pad_inches} в savefig значение 0.
Domagoj
3
Я только что натолкнулся на эту проблему, ни одно из решений в этой теме, и связанных с ними, не работало. Однако явно указав bbox_inches=0сделали свое дело.
Кадрах
1
Обратите внимание, что если вы «чертите» материал над plt.imshow, как в plt.plot (x, y), вам нужно убедиться, что вы установили xlim и ylim в размер матрицы.
Математический
1
это больше не работает. Мне потребовался час, чтобы понять это. Смотрите ответ ниже.
Эпизодиян
108

Я узнал этот трюк от matehat, здесь :

import matplotlib.pyplot as plt
import numpy as np

def make_image(data, outputname, size=(1, 1), dpi=80):
    fig = plt.figure()
    fig.set_size_inches(size)
    ax = plt.Axes(fig, [0., 0., 1., 1.])
    ax.set_axis_off()
    fig.add_axes(ax)
    plt.set_cmap('hot')
    ax.imshow(data, aspect='equal')
    plt.savefig(outputname, dpi=dpi)

# data = mpimg.imread(inputname)[:,:,0]
data = np.arange(1,10).reshape((3, 3))

make_image(data, '/tmp/out.png')

доходность

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

unutbu
источник
3
Я почти уверен, что у вас есть правильный ответ (хотя, возможно, есть несколько способов сделать это), но мне интересно, можете ли вы объяснить, почему это правильный ответ? А как насчет вашего кода убирает пробел?
Янв
4
@ Ян, в дополнение к документации, я считаю очень полезным закомментировать по одной строке за раз, чтобы увидеть, какой эффект имеет каждая команда. Это эмпирический путь!
unutbu
4
Линия, которая удаляет белую границу, является plt.Axes(fig, [0,0,1,1]). Это говорит matplotlib создать набор осей с левым нижним углом в точке, расположенной в (0%, 0%), с шириной и высотой (100%, 100%).
PhilMacKay
Это более правильный ответ, поскольку он удаляет не только пустое пространство для сохраненного изображения, но и для экранных графиков.
MaxNoe
Спасибо, это ЕДИНСТВЕННОЕ решение отлично работает на моем Ubuntu :)
AlphaGoMK
56

Возможное простейшее решение:

Я просто объединил метод, описанный в вопросе, и метод из ответа Hooked.

fig = plt.imshow(my_data)
plt.axis('off')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('pict.png', bbox_inches='tight', pad_inches = 0)

После этого кода нет пробелов и фрейма.

Нет пробелов, осей или рамки

Domagoj
источник
3
Ваш метод действительно удалил все пробелы вокруг этого изображения, хорошая работа, но я все еще не знаю, почему добавление команды fig.axes.get_xaxis().set_visible(False)решает проблему. Спасибо
ollydbg23
5
Да, если вы не вызовете эту команду, большинство пробелов будут удалены. Однако в моем случае между моим сюжетом и краем изображения .png все еще оставалось некоторое пространство (возможно, шириной 2 пикселя). Вызвав следующие команды, я избавился от этих упрямых мест.
Домагой,
3
Тем не менее, обратите внимание, что вышеупомянутое потерпит неудачу при наличии нескольких осей на одном и том же рисунке (в моем случае это встроенное изображение на графике). Решение: fig.axes[0]и вообще все или выбранные оси.
Иоаннис Филиппидис
29

Никто imsaveеще не упомянул , что делает это однострочным:

import matplotlib.pyplot as plt
import numpy as np

data = np.arange(10000).reshape((100, 100))
plt.imsave("/tmp/foo.png", data, format="png", cmap="hot")

Он напрямую сохраняет изображение как есть, то есть не добавляет никаких осей или границ / отступов.

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

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

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

def make_image(inputname,outputname):
    data = mpimg.imread(inputname)[:,:,0]
    fig = plt.imshow(data)
    fig.set_cmap('hot')
    ax = fig.gca()
    ax.set_axis_off()
    ax.autoscale(False)
    extent = ax.get_window_extent().transformed(plt.gcf().dpi_scale_trans.inverted())
    plt.savefig(outputname, bbox_inches=extent)
Gypaetus
источник
8

Это должно удалить все отступы и границы:

from matplotlib import pyplot as plt

fig = plt.figure()
fig.patch.set_visible(False)

ax = fig.add_subplot(111)

plt.axis('off')
plt.imshow(data)

extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig("../images/test.png", bbox_inches=extent)
Влады Веселинов
источник
Недооцененный ответ! Это дало мне 99% пути. Должно быть больше голосов, потому что это самое современное
Натан
Это также работает, если у вас нет объекта Axes ( ax) с extent = plt.gca().get_window_extent().transformed(fig.dpi_scale_trans.inverted()).
Тост
3

Ответ с лишним голосом больше не работает. Чтобы заставить его работать, вам нужно вручную добавить ось, установленную в [0, 0, 1, 1], или удалить патч под рисунком.

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(5, 5), dpi=20)
ax = plt.Axes(fig, [0., 0., 1., 1.])
fig.add_axes(ax)
plt.imshow([[0, 1], [0.5, 0]], interpolation="nearest")
plt.axis('off')                                # same as: ax.set_axis_off()

plt.savefig("test.png")

Кроме того, вы можете просто удалить патч. Вам не нужно добавлять подзаговор, чтобы удалить отступы. Это упрощено из ответа Влады ниже

fig = plt.figure(figsize=(5, 5))
fig.patch.set_visible(False)                   # turn off the patch

plt.imshow([[0, 1], [0.5, 0]], interpolation="nearest")
plt.axis('off')

plt.savefig("test.png", cmap='hot')

Это проверено с версией 3.0.3на 2019/06/19. Изображение см. Ниже:

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

Гораздо проще сделать это pyplot.imsave. Подробнее см. Ответ Луатора ниже

episodeyang
источник
у меня работает только версия Axes. я получаю заполнение с выключенной версией патча. спасибо в любом случае!
save_jeff
2

Мне понравился ответ Ubuntu , но он не показывал явно, как установить размер для неквадратных изображений из коробки, поэтому я изменил его для легкой копирования-вставки:

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

def save_image_fix_dpi(data, dpi=100):
    shape=np.shape(data)[0:2][::-1]
    size = [float(i)/dpi for i in shape]

    fig = plt.figure()
    fig.set_size_inches(size)
    ax = plt.Axes(fig,[0,0,1,1])
    ax.set_axis_off()
    fig.add_axes(ax)
    ax.imshow(data)
    fig.savefig('out.png', dpi=dpi)
    plt.show()

Сохранять изображения без рамки легко, независимо от того, какое значение dpi вы выберете, если сохранить pixel_size / dpi = size.

data = mpimg.imread('test.png')
save_image_fix_dpi(data, dpi=100)

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

Однако показ жуткий. Если вы выберете маленькое dpi, размер вашего изображения может быть больше, чем у экрана, и вы получите границы во время отображения. Тем не менее, это не влияет на экономию.

Таким образом, для

save_image_fix_dpi(data, dpi=20)

Дисплей становится граничным (но сохранение работает): введите описание изображения здесь

csnemes
источник
1

Во-первых, для определенных форматов изображений (например, TIFF ) вы можете сохранить цветовую карту в заголовке, и большинство зрителей покажет ваши данные с помощью цветной карты.

Для сохранения реального matplotlibизображения, которое может быть полезно для добавления аннотаций или других данных к изображениям, я использовал следующее решение:

fig, ax = plt.subplots(figsize=inches)
ax.matshow(data)  # or you can use also imshow
# add annotations or anything else
# The code below essentially moves your plot so that the upper
# left hand corner coincides with the upper left hand corner
# of the artist
fig.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
# now generate a Bbox instance that is the same size as your
# single axis size (this bbox will only encompass your figure)
bbox = matplotlib.transforms.Bbox(((0, 0), inches))
# now you can save only the part of the figure with data
fig.savefig(savename, bbox_inches=bbox, **kwargs)
Дэвид Хоффман
источник
0

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

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

Так что я закончил тем, что соединил ответ Дэвида с csnemes, чтобы сделать простую обертку во время создания фигуры. Когда вы используете это, вам не нужны никакие изменения позже с imsave () или чем-то еще:

def get_img_figure(image, dpi):
    """
    Create a matplotlib (figure,axes) for an image (numpy array) setup so that
        a) axes will span the entire figure (when saved no whitespace)
        b) when saved the figure will have the same x/y resolution as the array, 
           with the dpi value you pass in.

    Arguments:
        image -- numpy 2d array
        dpi -- dpi value that the figure should use

    Returns: (figure, ax) tuple from plt.subplots
    """

    # get required figure size in inches (reversed row/column order)
    inches = image.shape[1]/dpi, image.shape[0]/dpi

    # make figure with that size and a single axes
    fig, ax = plt.subplots(figsize=inches, dpi=dpi)

    # move axes to span entire figure area
    fig.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)

    return fig, ax
Ричард
источник