scipy: savefig bez ramek, osi, tylko zawartość

92

W numpy / scipy mam obraz przechowywany w tablicy. Mogę to wyświetlić, chcę zapisać savefig bez żadnych ramek, osi, etykiet, tytułów, ... Tylko czysty obraz, nic więcej.

Chcę uniknąć pakietów takich jak PyPNGlub scipy.misc.imsave, czasami są problematyczne (nie zawsze dobrze się instalują, tylko podstawowe savefig()dla mnie

Jakub M.
źródło

Odpowiedzi:

115

EDYTOWAĆ

Zmieniono aspect='normalna, aspect='auto'ponieważ zmieniło się to w nowszych wersjach matplotlib (dzięki @ Luke19).


Zakładając:

import matplotlib.pyplot as plt

Aby zrobić figurę bez ramy:

fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)

Aby treść wypełniła całą figurę

ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)

Następnie narysuj na nim swój obraz:

ax.imshow(your_image, aspect='auto')
fig.savefig(fname, dpi)

aspectParametr zmienia rozmiar obrazu, aby upewnić się, że wypełnienie wielkości liczbę wymienioną w fig.set_size_inches(…). Aby poczuć, jak bawić się tego typu rzeczami, przeczytaj dokumentację matplotlib , szczególnie na temat Axes, Axis i Artist.

matehat
źródło
4
nie, wciąż mam jakąś małą przezroczystą ramkę, a nie chcę żadnej ramki , czysty obraz
Jakub M.
5
Jeśli ręcznie ustawisz parametry wi hin fig.set_size_inches(w,h)i dpiparametr in fig.savefig(fname, dpi)tak, aby uzyskać 24 na 24 piksele, powinno działać dobrze. Na przykład w = h = 1idpi = 24
matehat
5
Musiałem połączyć zarówno tę odpowiedź, jak i poniższą odpowiedź Mostafy Pakparvara. Nie tylko musisz wyłączyć osie, ale musisz ustawić_visible na false, aby upewnić się, że biała przestrzeń zniknie. (wtf?)
Bryce Guinta
6
Właśnie wypróbowałem to przy użyciu matplotlib v2.2.2 i działało idealnie (z wyjątkiem tego imshow, że składnia została zmieniona na aspect='auto'zamiast 'normal').
Łukasz
2
To jest właściwe podejście. ax = plt.Axes(fig, [0., 0., 1., 1.])jest tym, co sprawia, że ​​to działa.
greatvovan
73

Wydaje się, że łatwiejszym rozwiązaniem jest:

fig.savefig('out.png', bbox_inches='tight', pad_inches=0)
żaba
źródło
2
Wyszło mi świetnie. Ponadto można łatwo zmienić rozmiar pad_inches na żądany rozmiar. Dzięki!
Curious2learn
27
Nadal mam z tym białe marginesy.
Fábio Perez
3
Udało mi się zaktualizować to dla nowszych wersji / problemu z pozostałymi marginesami, po prostu dodając transparent = True fig.savefig('out.png', bbox_inches='tight',transparent=True, pad_inches=0)
mdoc-2011
2
Nadal mam topory, znaczniki i wszystko z tym :(
BjornW,
3
To w ogóle nic nie robi. Da ci figurę ze wszystkimi osiami i etykietami.
1313e
27

Możesz znaleźć bbox obrazu wewnątrz osi (za pomocą get_window_extent) i użyć bbox_inchesparametru, aby zapisać tylko tę część obrazu:

import numpy as np
import matplotlib.pyplot as plt

data=np.arange(9).reshape((3,3))
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
plt.axis('off')
plt.imshow(data)

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

Nauczyłem się tej sztuczki od Joe Kingtona tutaj .

unutbu
źródło
6
właśnie plt.axis('off')pomogłem. Inne odpowiedzi niewiele pomagają.
imsrgadich
3
To działało całkiem nieźle. Jednak w moim przypadku nadal jest mała biała obwódka. Jakieś pomysły, jak usunąć tę granicę?
user3731622
@ user3731622, spróbuj plt.savefig('/temp/test.png', bbox_inches='tight', transparent=True, pad_inches=0)zamiastplt.savefig('/tmp/test.png', bbox_inches=extent)
Cloud Cho
17

Wypróbowałem kilka opcji w moim przypadku i najlepszym rozwiązaniem było to:

fig.subplots_adjust(bottom = 0)
fig.subplots_adjust(top = 1)
fig.subplots_adjust(right = 1)
fig.subplots_adjust(left = 0)

następnie zapisz swoją figurę za pomocą savefig

Cagri Sarigoz
źródło
1
Spośród wszystkich tych rozwiązań tylko to działało dla mnie.
Puff
8

Zasugeruję odpowiedź herona13 z lekkim dodatkiem pożyczonym stąd, aby usunąć obicie pozostałe po ustawieniu bbox w tryb tight, dlatego:

axes = fig.axes()
axes.get_xaxis().set_visible(False)
axes.get_yaxis().set_visible(False)
fig.savefig('out.png', bbox_inches='tight', pad_inches=0)
Mostafa Pakparvar
źródło
Otrzymuję błąd informujący, że metody get_xaxis () i get_yaxis () nie istnieją. Masz pojęcie, dlaczego tak się stało?
Jacob Małachowski
Utwórz obiekt axes (), a następnie użyj ax.xaxis i ax.yaxis
perigon.
Wystąpił błąd informujący, że obiekt „lista” nie ma atrybutu „get_xaxis”
Haozhe Xie
7

Ten działa dla mnie

plt.savefig('filename',bbox_inches='tight',transparent=True, pad_inches=0)
Cathy Yang
źródło
3

Miałem ten sam problem podczas wykonywania wizualizacji w bibliotece librosa, gdzie chciałem wyodrębnić zawartość działki bez żadnych innych informacji. Więc to moje podejście. Odpowiedź unutbu pomaga mi również pracować.

    figure = plt.figure(figsize=(500, 600), dpi=1)
    axis = plt.subplot(1, 1, 1)
    plt.axis('off')
    plt.tick_params(axis='both', left='off', top='off', right='off', bottom='off', labelleft='off', labeltop='off',
                    labelright='off', labelbottom='off')

     # your code goes here. e.g: I used librosa function to draw a image
    result = np.array(clip.feature_list['fft'].get_logamplitude()[0:2])
    librosa.display.specshow(result, sr=api.Clip.RATE, x_axis='time', y_axis='mel', cmap='RdBu_r')


    extent = axis.get_window_extent().transformed(figure.dpi_scale_trans.inverted())
    plt.savefig((clip.filename + str("_.jpg")), format='jpg', bbox_inches=extent, pad_inches=0)
    plt.close()
GPrathap
źródło
To zaprowadziło mnie na właściwą ścieżkę, ale miałem dwa problemy: 1) musiałem ustawić rozdzielczość na liczbę większą niż 1, aby uniknąć błędu czcionki w moim notatniku jupyter; i 2) nadal była mała ramka, więc muszę ręcznie zmienić zakres Bbox na extent.get_points()*np.array([[1.1],[.9]]).
Bob Baxley
dzięki za spełnienie odpowiedzi, która może pomóc komuś innemu.
GPrathap
3

Dla każdego, kto próbuje to zrobić w Jupyter

 plt.axis('off')

 spec = plt.imshow

 plt.savefig('spec',bbox_inches='tight',transparent=True, pad_inches=0)
Krackle
źródło
2

Chociaż powyższe odpowiedzi dotyczą usuwania marginesów i dopełnienia, nie zadziałały one w przypadku usuwania etykiet. Oto, co zadziałało dla każdego, kto później natknie się na to pytanie:

Zakładając, że chcesz mieć siatkę 2x2 wykresów podrzędnych z czterech obrazów przechowywanych w images:

matplotlib.pyplot.figure(figsize = (16,12)) # or whatever image size you require
for i in range(4):
    ax = matplotlib.pyplot.subplot(2,2,i+1)
    ax.axis('off')
    imshow(images[i])
matplotlib.pyplot.savefig(path, bbox_inches='tight')
ciekawy
źródło
1

Próbowałem też pozbyć się granicy, używając tutaj wskazówek, ale nic tak naprawdę nie działało. Trochę się bawiąc i stwierdziłem, że zmiana koloru twarzy nie dawała mi żadnej granicy w laboratoriach jupyter (każdy kolor powodował pozbycie się białej ramki). Mam nadzieję że to pomoże.

def show_num(data):
data = np.rot90(data.reshape((16,16)), k=3)
data = np.fliplr(data)
fig = plt.figure(frameon=False, facecolor='white')
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(data)
plt.show()

wprowadź opis obrazu tutaj

Atom Scott
źródło
0

Dla mnie ten kod sprawił, że rozmiar obrazu wejściowego bez ramki i osi z kodów matehat , unutbu i WHZW był podobny :

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
plt.axis('off')
viridis = cm.get_cmap('gist_gray', 256)
plt.imshow(data, aspect='auto', cmap=viridis)
plt.tight_layout()
plt.savefig(out_file, bbox_inches='tight', transparent=True, pad_inches=0)

Środowisko wykonawcze:
Python 3.6.10
Matplotlib 3.2.1
OS Windows 10

Cloud Cho
źródło