Removendo o espaço em branco ao redor de uma imagem salva no matplotlib

172

Preciso tirar uma foto e salvá-la após algum processo. A figura fica bem quando a exibo, mas depois de salvá-la, fiquei com um espaço em branco ao redor da imagem salva. Eu tentei a 'tight'opção pelo savefigmétodo, também não funcionou. O código:

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

  fig = plt.figure(1)
  img = mpimg.imread(path)
  plt.imshow(img)
  ax=fig.add_subplot(1,1,1)

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

  plt.axis('off') 
  plt.show()

Estou tentando desenhar um gráfico básico usando o NetworkX em uma figura e salvá-lo. Percebi que sem o gráfico ele funciona, mas quando adicionado um gráfico, recebo espaço em branco ao redor da imagem salva;

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import networkx as nx

G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_edge(1,3)
G.add_edge(1,2)
pos = {1:[100,120], 2:[200,300], 3:[50,75]}

fig = plt.figure(1)
img = mpimg.imread("C:\\images\\1.jpg")
plt.imshow(img)
ax=fig.add_subplot(1,1,1)

nx.draw(G, pos=pos)

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

plt.axis('off') 
plt.show()
Ahmet Tuğrul Bayrak
fonte
O que realmente funcionou para mim foi cortar o pdf usando outra ferramenta, como o pdfcrop.
toliveira 12/06

Respostas:

169

Não posso afirmar que sei exatamente por que ou como minha “solução” funciona, mas era isso que eu precisava fazer quando quis plotar o esboço de algumas seções de aerofólio - sem margens brancas - em um arquivo PDF. (Observe que eu usei o matplotlib dentro de um notebook IPython, com o sinalizador -pylab.)

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.savefig("filename.pdf", bbox_inches = 'tight',
    pad_inches = 0)

Tentei desativar partes diferentes disso, mas isso sempre leva a uma margem branca em algum lugar. Você pode até modificar isso para impedir que linhas gordas próximas aos limites da figura sejam raspadas pela falta de margens.

Johannes S.
fonte
6
Finalmente, algo que funciona, muito obrigado! By the way, no meu caso, apenas as duas linhas usando set_major_locatoreram necessárias.
Florian Brucker
6
Passei a última hora tentando várias coisas e não consegui me livrar de uma borda branca de 1px. Essa foi a única coisa que funcionou - especificamente a pad_inches=0que outras respostas não mencionam.
AnnanFay
1
set_major_locatorfoi a chave para mim.
achou
16
pad_inchesme ajudou.
Myles Baker
5
matplotlib.ticker.NullLocator ()
Joop
200

Você pode remover o preenchimento de espaço em branco, definindo bbox_inches="tight"em savefig:

plt.savefig("test.png",bbox_inches='tight')

Você terá que colocar o argumento bbox_inchescomo uma string, talvez seja por isso que não funcionou anteriormente para você.


Possíveis duplicatas:

Gráficos Matplotlib: removendo eixos, legendas e espaços em branco

Como definir as margens para uma figura do matplotlib?

Reduzir as margens esquerda e direita no gráfico matplotlib

Hooked
fonte
1
Se você possui várias subparcelas e deseja salvar cada uma delas, também pode usar isso fig.savefig(). ( plt.savefig()não funcionará nesse caso).
Abhranil Das 21/04
30
Isso não está certo. Quando você usa essa bbox_inchesopção, há outro padrão que deixa algum espaço. Se você realmente quer se livrar de tudo, também precisa usá-lo pad_inches=0.0. Claro, tal preenchimento apertado freqüentemente corta, por exemplo, expoentes ...
Mike
5
Para remover a borda preta, bem, você pode precisar de setpad_inches=-0.1
lenhhoxung
10
Isso simplesmente não funciona, você ainda tem espaço em branco ao redor da figura. Definir a opção transparente (como mencionado em algumas respostas) também não ajuda muito, o espaço em branco ainda está lá, é apenas transparente.
precisa saber é o seguinte
1
@piperchester é uma boa pergunta, mas provavelmente deve ser feita como uma nova pergunta, para que não se perca nos comentários. Você deve vincular a nova pergunta à antiga!
Hooked
21

Depois de tentar as respostas acima sem sucesso (e várias outras postagens de pilha), o que finalmente funcionou para mim foi apenas

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.savefig("myfig.pdf")

É importante ressaltar que isso não inclui os argumentos bbox ou padding.

SuaveSouris
fonte
4
Essa deve ser a resposta aceita. Além disso, você nem precisa ligar set_axis_off. Isso não afeta a imagem salva, pois após subplots_adjusto eixo ficar fora da extensão da figura e a henve não será obtida de qualquer maneira. Nos blocos de anotações Jupyter, no entanto, é necessário desativar explicitamente o eixo, pois o back-end embutido substitui essas configurações.
MaxPowers
20

Encontrei algo de Arvind Pereira ( http://robotics.usc.edu/~ampereir/wordpress/?p=626 ) e parecia funcionar para mim:

plt.savefig(filename, transparent = True, bbox_inches = 'tight', pad_inches = 0)
unclerico
fonte
7
transparent=Truefará parecer que não há problema, mas apenas ocultará o espaço em branco, as dimensões da imagem não serão aceitáveis.
Vlady Veselinov
Obrigado por mencionar pad_inches! Eu gostaria de ter conhecido essa opção anteriormente!
ingomueller.net 19/02
1
Isso funciona para a maioria dos gráficos, mas removeu a borda direita da minha matriz de confusão. Basta adicionar um pequeno preenchimentopad_inches=.25
YTZ
14

A função a seguir incorpora a resposta de johannes-s acima. Eu testei com plt.figuree plt.subplots()com vários eixos, e funciona muito bem.

def save(filepath, fig=None):
    '''Save the current image with no whitespace
    Example filepath: "myfig.png" or r"C:\myfig.pdf" 
    '''
    import matplotlib.pyplot as plt
    if not fig:
        fig = plt.gcf()

    plt.subplots_adjust(0,0,1,1,0,0)
    for ax in fig.axes:
        ax.axis('off')
        ax.margins(0,0)
        ax.xaxis.set_major_locator(plt.NullLocator())
        ax.yaxis.set_major_locator(plt.NullLocator())
    fig.savefig(filepath, pad_inches = 0, bbox_inches='tight')
TomNorway
fonte
Funcionou como um encanto. A resposta anterior foram alguns comandos necessários na minha exportação.
Kevin S
11

Eu achei os seguintes códigos funcionar perfeitamente para o trabalho.

fig = plt.figure(figsize=[6,6])
ax = fig.add_subplot(111)
ax.imshow(data)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.set_frame_on(False)
plt.savefig('data.png', dpi=400, bbox_inches='tight',pad_inches=0)
Richard Yu Liu
fonte
2
Geralmente, as respostas são muito mais úteis se incluem uma explicação sobre o que o código pretende fazer e por que isso resolve o problema sem a introdução de outros.
Tim Diekmann
7

Eu segui essa sequência e funcionou como um encanto.

plt.axis("off")
fig=plt.imshow(image array,interpolation='nearest')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('destination_path.pdf',
    bbox_inches='tight', pad_inches=0, format='pdf', dpi=1200)
Khan
fonte
1
Na verdade, achei esta resposta fácil e conveniente de usar.
Sikisis
1
Este funcionou para mim; a resposta aceita não.
8109 Joe
3

Para quem quer trabalhar em pixels em vez de polegadas, isso funcionará.

Além do habitual, você também precisará

from matplotlib.transforms import Bbox

Então você pode usar o seguinte:

my_dpi = 100 # Good default - doesn't really matter

# Size of output in pixels
h = 224
w = 224

fig, ax = plt.subplots(1, figsize=(w/my_dpi, h/my_dpi), dpi=my_dpi)

ax.set_position([0, 0, 1, 1]) # Critical!

# Do some stuff
ax.imshow(img)
ax.imshow(heatmap) # 4-channel RGBA
ax.plot([50, 100, 150], [50, 100, 150], color="red")

ax.axis("off")

fig.savefig("saved_img.png",
            bbox_inches=Bbox([[0, 0], [w/my_dpi, h/my_dpi]]),
            dpi=my_dpi)

insira a descrição da imagem aqui

Simon Thomas
fonte
Você não tem que especificar dpi, você pode usar o padrão fig.dpiem vez
intsco
1

Uma abordagem muito mais simples que encontrei é usar plt.imsave:

    import matplotlib.pyplot as plt
    arr = plt.imread(path)
    plt.imsave('test.png', arr)
Parth92
fonte
Resposta subestimada. Isso me ajudou depois de uma longa pesquisa sobre como manter a resolução e remover o espaço em branco plt.savefig().
Nihal111
Isso funciona apenas no caso de você querer salvar uma matriz (!) Como imagem. Isso não permite salvar uma figura arbitrária.
MaxPowers
O que você quer dizer com imagem arbitrária? Uma imagem não é uma matriz de valores?
Parth92
0

Você pode tentar isso. Resolveu o meu problema.

import matplotlib.image as mpimg
img = mpimg.imread("src.png")
mpimg.imsave("out.png", img, cmap=cmap)
user1410665
fonte
-1

Se você deseja exibir o que deve ser salvo, recomendo usar a plt.tight_layouttransformação, que é realmente mais preferível, pois não faz cortes desnecessários ao usarplt.savefig

import matplotlib as plt    
plt.plot([1,2,3], [1,2,3])
plt.tight_layout(pad=0)
plt.savefig('plot.png')
Keto
fonte
-4

Isso funciona para mim, salvando uma matriz numpy plotada com imshow para arquivar

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,10))
plt.imshow(img) # your image here
plt.axis("off")
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
        hspace = 0, wspace = 0)
plt.savefig("example2.png", box_inches='tight', dpi=100)
plt.show()
Alejandro Sazo
fonte