Zmniejsz lewy i prawy margines na wykresie matplotlib

178

Staram się poradzić sobie z moimi marginesami działki w matplotlib. Użyłem poniższego kodu do stworzenia mojego wykresu:

plt.imshow(g)
c = plt.colorbar()
c.set_label("Number of Slabs")
plt.savefig("OutputToUse.png")

Jednak otrzymuję wynik z dużą ilością białych znaków po obu stronach wykresu. Przeszukałem google i przeczytałem dokumentację matplotlib, ale nie mogę znaleźć sposobu, jak to zmniejszyć.

robintw
źródło
Czy problem ilość białych znaków w extentna imshowrysunku, lub ilość granicznego spacji w otrzymanej png, wokół rysunku, generowane przez savefig?
unutbu
Myślę, że jedno i drugie - wydaje się, że jest dużo miejsca zarówno w oknie podglądu, jak iw PNG. Jednak ważnym wynikiem jest plik png utworzony przez savefig- więc to właśnie chciałbym posortować.
robintw
Dopiero potem przyciąłem je w GIMP. : /
endolith

Odpowiedzi:

251

Jednym ze sposobów automatycznego zrobienia tego jest bbox_inches='tight'kwarg to plt.savefig.

Na przykład

import matplotlib.pyplot as plt
import numpy as np
data = np.arange(3000).reshape((100,30))
plt.imshow(data)
plt.savefig('test.png', bbox_inches='tight')

Innym sposobem jest użycie fig.tight_layout()

import matplotlib.pyplot as plt
import numpy as np

xs = np.linspace(0, 1, 20); ys = np.sin(xs)

fig = plt.figure()
axes = fig.add_subplot(1,1,1)
axes.plot(xs, ys)

# This should be called after all axes have been added
fig.tight_layout()
fig.savefig('test.png')
Joe Kington
źródło
5
Czy jest jakiś sposób, aby ustawić to jako domyślne?
endolit
1
Jeśli masz wiele działek podrzędnych i chcesz zapisać każdy z nich, możesz użyć tego fig.savefig()również. ( plt.savefig()nie zadziała w tym przypadku.)
Abhranil Das
1
Wszystko to polega na przycięciu obrazu po jego wyrenderowaniu; jeśli próbujesz wymusić określoną rozdzielczość, obraz będzie mniejszy .
detly
5
@detly - tak. To jest dokładnie to, co robi (chociaż może również „wyciąć” i powiększyć obraz). Na to, czego chcesz, spójrz fig.tight_layout(). Ta funkcja nie istniała, gdy pierwotnie pisano tę odpowiedź, w przeciwnym razie wspomniałbym o niej bardziej wyraźnie.
Joe Kington
2
Jeśli ktoś ma problem, użyjfig = plt.gcf()
KyungHoon Kim
148

Możesz dostosować odstępy wokół figur matplotlib za pomocą funkcji subplots_adjust ():

import matplotlib.pyplot as plt
plt.plot(whatever)
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)

Będzie to działać zarówno dla figury na ekranie, jak i zapisanej w pliku, i jest to właściwa funkcja do wywołania, nawet jeśli nie masz wielu wykresów na jednej figurze.

Liczby są ułamkami wymiarów figury i należy je dostosować, aby uwzględnić etykiety figur.

DaveP
źródło
8
Wartości przypisane do parametrów, a nie to, o ile je zmienić, to miejsce, w którym należy ustawić margines. Innymi słowy, jeśli chcesz zwiększyć margines prawej krawędzi o 10%, powinieneś ustawić right = 0,9, a nie prawo = 0,1 matplotlib.sourceforge.net/api/ ...
drootang
1
Warto zaznaczyć, że oczywiście można określić wartości ujemne w plt.subplots_adjust (). Dzięki temu możesz nawet rysować poza obszarem rysunku, a także radzić sobie z irytującymi marginesami.
rośnie
Działa to również na GridSpecobiektach przez wywołanie updatemetody (patrz stackoverflow.com/a/20058199/1030876 ).
Aaron Voelker
57

Wszystko czego potrzebujesz to

plt.tight_layout()

przed wyjściem.

Oprócz zmniejszenia marginesów powoduje to również ścisłe zgrupowanie przestrzeni między dowolnymi działkami pomocniczymi:

x = [1,2,3]
y = [1,4,9]
import matplotlib.pyplot as plt
fig = plt.figure()
subplot1 = fig.add_subplot(121)
subplot1.plot(x,y)
subplot2 = fig.add_subplot(122)
subplot2.plot(y,x)
fig.tight_layout()
plt.show()
user2065406
źródło
7
Myślę, że to naprawdę najlepsza metoda. Nie wymaga zapisywania figury jak `bbox = 'tight' i naprawia wszelkiego rodzaju inne problemy z układem w ciasnych figurach.
dshepherd
2
to powinna być prawidłowa odpowiedź, ponieważ zachowuje się tak, jak można by oczekiwać, ponieważ odnosi się do FIGURKI zamiast do obrazu.
Majid alDosari
O dziwo, zmienia to również szerokość faktycznego wykresu (tj. Szczyty są bliżej siebie) w porównaniu z bbox_inches='tight', który po prostu przycina białą przestrzeń wokół krawędzi, ale pozostawia wykres sam. Stworzyłem figurę za pomocą plt.figure(figsize=(10,3)).
Fritz
9

Po prostu użyj, ax = fig.add_axes([left, bottom, width, height]) jeśli chcesz mieć dokładną kontrolę nad układem figury. na przykład.

left = 0.05
bottom = 0.05
width = 0.9
height = 0.9
ax = fig.add_axes([left, bottom, width, height])
mason
źródło
6

W przypadku gdyby ktoś zastanawiał się, jak pozbyć się reszty białego marginesu po zastosowaniu plt.tight_layout()lub fig.tight_layout(): Za pomocą parametru pad(który jest 1.08domyślnie) możesz go jeszcze bardziej zacisnąć: „Wypełnienie między krawędzią figury a krawędziami podploty, jako ułamek rozmiaru czcionki. " Na przykład

plt.tight_layout(pad=0.05)

zredukuje go do bardzo małego marginesu. Umieszczanie 0nie działa dla mnie, ponieważ powoduje też, że pole wątku cząstkowego jest trochę odcięte.

Oberwaschlappen
źródło
4
plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)
Tian Chu
źródło
1
"pad_inches = -1", ponieważ moje savefig tworzy tylko część figury.
Yu Shen,
Użycie parametru w savefigfunkcji jest eleganckie, jednak wartość ujemna dla pad_inchesniekoniecznie jest potrzebna w każdym przypadku.
MichaelHuelsen
ustaw na 0, pomaga
Joop
4

Problem z matplotlibs subplots_adjust polega na tym, że wartości, które wprowadzasz, odnoszą się do xiy wielkości figury. Ten przykład dotyczy poprawnego rysowania przy drukowaniu pliku PDF:

W tym celu ponownie obliczam względne odstępy na wartości bezwzględne w następujący sposób:

pyplot.subplots_adjust(left = (5/25.4)/figure.xsize, bottom = (4/25.4)/figure.ysize, right = 1 - (1/25.4)/figure.xsize, top = 1 - (3/25.4)/figure.ysize)

dla figury „figure.xsize” w calach w wymiarze x i „figure.ysize” w calach w wymiarze y. Tak więc cała figura ma lewy margines 5 mm, dolny 4 mm, prawy 1 mm i górny 3 mm wewnątrz etykiet. Konwersja (x / 25,4) jest wykonywana, ponieważ potrzebowałem przeliczyć mm na cale.

Zwróć uwagę, że czysty rozmiar wykresu x będzie miał postać „figure.xsize - lewy margines - prawy margines”, a czysty rozmiar wykresu y będzie równy „figura.ysize - dolny margines - górny margines” w calach

Inne sniplety (nie jestem pewien co do tych, chciałem tylko podać pozostałe parametry)

pyplot.figure(figsize = figureSize, dpi = None)

i

pyplot.savefig("outputname.eps", dpi = 100)
Sammy
źródło
3
Skąd wziąłeś xsizei ysizeod. Korzystam z tych właściwości i otrzymujęAttributeError: 'Figure' object has no attribute 'xsize'
cj5
4

zainspirowany powyższą odpowiedzią Sammysa:

margins = {  #     vvv margin in inches
    "left"   :     1.5 / figsize[0],
    "bottom" :     0.8 / figsize[1],
    "right"  : 1 - 0.3 / figsize[0],
    "top"    : 1 - 1   / figsize[1]
}
fig.subplots_adjust(**margins)

Gdzie figsize to krotka, której użyłeś fig = pyplot.figure(figsize=...)

michaelosthege
źródło
2

Dla mnie powyższe odpowiedzi nie działały matplotlib.__version__ = 1.4.3na Win7. Tak więc, jeśli interesuje nas tylko sam obraz (tj. Jeśli nie potrzebujemy adnotacji, osi, znaczników, tytułu, ylabel itp.), Lepiej jest po prostu zapisać tablicę numpy jako obraz zamiast savefig.

from pylab import *

ax = subplot(111)
ax.imshow(some_image_numpyarray)
imsave('test.tif', some_image_numpyarray)

# or, if the image came from tiff or png etc
RGBbuffer = ax.get_images()[0].get_array()
imsave('test.tif', RGBbuffer)

Ponadto, używając funkcji rysowania opencv (cv2.line, cv2.polylines), możemy wykonać kilka rysunków bezpośrednio na tablicy numpy. http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html

wydra
źródło
2

W przypadku ostatnich wersji matplotlib możesz chcieć wypróbować układ ograniczony .

Michel de Ruiter
źródło