Сюжети 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)

Він успішно видаляє вісь фігури, але збережена фігура представляє білу підкладку та рамку навколо фактичного зображення. Як я можу їх видалити (принаймні білу підкладку)? Дякую


2
Усі рішення цього питання зосереджені на цьому imshow. Якщо натомість у вас є розсипник, вам може допомогти наступна відповідь: stackoverflow.com/a/40727744/4124317
ВажливістьOfBeingErnest

Відповіді:


373

Я думаю, що команда 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 (помилкове) & fig.axes.get_yaxis (). Set_visible (помилкове)} з {plt.axis ('off')}) вирішило проблему для я. (Білих просторів більше немає). І не забудьте встановити {pad_inches} в savefig до 0.
Domagoj

3
Я просто натрапив на цю проблему, жодне з рішень у цій темі та пов'язаних з ними не працювало. Однак чітко вказуючи, bbox_inches=0чи зробив трюк.
кадрач

1
Зауважте, що якщо ви «плануєте» речі через plt.imshow, як у plt.plot (x, y), вам потрібно переконатися, що ви встановили xlim та ylim на розмір матриці.
Матхусалем

1
це вже не працює. Мені потрібна година, щоб це зрозуміти. Дивіться відповідь нижче.
епізод

107

Я навчився цієї хитрості від 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')

врожайність

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


3
Я впевнений, що ви маєте правильну відповідь (хоча, мабуть, існує більше, ніж один спосіб зробити це), але мені цікаво, чи можете ви пояснити, чому це правильна відповідь? Що з вашим кодом видаляє пробіл?
Янв

4
@Yann, крім документації, мені дуже корисно коментувати по одному рядку, щоб побачити, який ефект має кожна команда. Це емпіричний шлях!
unutbu

4
Лінія, яка видаляє білу межу, є plt.Axes(fig, [0,0,1,1]). Це сповіщає matplotlib створити набір осей з лівим нижнім кутом у точці, розташованій у (0%, 0%) та з шириною та висотою (100%, 100%).
PhilMacKay

Це більш правильна відповідь, оскільки вона не тільки видаляє простір для збереженого зображення, але й екранні графіки.
MaxNoe

Дякую, це
ТІЛЬКЕ

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)

Після цього коду немає пробілів і кадру.

Без пробілів, осей чи рами


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")

Він безпосередньо зберігає зображення таким, яким він є, тобто не додає жодних осей, ані рамки / прокладки.

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


Це те, що я роблю більшу частину часу, але є випадки, коли мені потрібна кольорова смуга, і в цих випадках 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)

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. Детальніше див. Нижче у відповіді луатора


для мене працює лише версія Axes. Я отримую прокладку з виправленою патчем версії. THX все одно!
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()

Збереження зображень без меж легко, незалежно від значення, який ви вибрали, якщо зберігається pixel_size / dpi = size.

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

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

Однак показ моторошний. Якщо ви вибрали невеликий dpi, розмір зображення може бути більшим, ніж ваш екран, і ви отримаєте межу під час відображення. Тим не менш, це не впливає на економію.

Так для

save_image_fix_dpi(data, dpi=20)

Дисплей стає межею (але збереження працює): введіть тут опис зображення


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.