Графики Matplotlib: удаление оси, легенд и пробелов

Я новичок в Python и Matplotlib, я хотел бы просто применить colormap к изображению и написать результирующее изображение без использования осей, ярлыков, титров или чего-либо, обычно автоматически добавляемого 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)

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

Ответ 1

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

Обратите внимание, что в более новых версиях matplotlib может потребоваться bbox_inches=0 вместо строки 'tight' thin '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')

enter image description here

Ответ 2

Я узнал этот трюк из 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')

дает

enter image description here

Ответ 3

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

Я просто объединил метод, описанный в вопросе и метод из ответа 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)

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

No whitespaces, axes or frame

Ответ 4

Никто еще не упомянул 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")

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

enter image description here

Ответ 5

Вы также можете указать степень фигуры в аргументе 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)

Ответ 6

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

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)

Ответ 7

Мне понравился ответ 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)

enter image description here

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

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

save_image_fix_dpi(data, dpi=20)

Дисплей становится окаймленным (но сохранение работает): enter image description here

Ответ 8

Во-первых, для определенных форматов изображений (например, 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)

Ответ 9

Ответ с лишним голосом больше не работает. Чтобы заставить его работать, вам нужно вручную добавить ось, установленную в [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. Изображение см. Ниже:

enter image description here

Намного проще сделать это с помощью pyplot.imsave. Для получения дополнительной информации см. Ответ luator ниже

Ответ 10

Ответ с лишним голосом больше не работает. Чтобы заставить его работать, вам нужно вручную добавить ось, установленную в [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. Изображение см. Ниже:

enter image description here

Намного проще сделать это с помощью pyplot.imsave. Для получения дополнительной информации см. Ответ luator ниже

Ответ 11

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

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

В итоге я соединил ответ дэвида с 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