scipy: savefig sem frames, eixos, apenas conteúdo

92

Em numpy / scipy, tenho uma imagem armazenada em uma matriz. Posso exibi-lo, quero salvá-lo usando savefig sem bordas, eixos, rótulos, títulos, ... Apenas imagem pura, nada mais.

Eu quero evitar pacotes como PyPNGou scipy.misc.imsave, eles às vezes são problemáticos (eles nem sempre instalam bem, apenas básicos savefig()para mim

Jakub M.
fonte

Respostas:

118

EDITAR

Alterado aspect='normalpara aspect='auto'desde que mudou nas versões mais recentes do matplotlib (graças a @ Luke19).


Assumindo:

import matplotlib.pyplot as plt

Para fazer uma figura sem moldura:

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

Para fazer o conteúdo preencher a figura inteira

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

Em seguida, desenhe sua imagem nele:

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

O aspectparâmetro altera o tamanho do pixel para garantir que preencham o tamanho da figura especificado em fig.set_size_inches(…). Para ter uma ideia de como brincar com esse tipo de coisa, leia a documentação do matplotlib , particularmente sobre o assunto Axes, Axis e Artist.

matehat
fonte
4
não, ainda tenho uma pequena borda transparente e o que eu quero não é nenhuma borda , imagem pura
Jakub M.
5
Se você definir manualmente os parâmetros we hem fig.set_size_inches(w,h)e o dpiparâmetro em de fig.savefig(fname, dpi)modo que resulte em 24px por 24px, deve funcionar perfeitamente. Por exemplo, w = h = 1edpi = 24
matehat
5
Tive de combinar esta resposta e a resposta abaixo de Mostafa Pakparvar. Você não só precisa desligar os eixos, mas também definir set_visible para false para garantir que o espaço em branco desapareça. (wtf?)
Bryce Guinta
6
Tentei fazer isso usando matplotlib v2.2.2 e funcionou perfeitamente (exceto que imshowa sintaxe foi alterada para em aspect='auto'vez de 'normal').
Luke19
2
Esta é a abordagem certa. ax = plt.Axes(fig, [0., 0., 1., 1.])é o que o faz funcionar.
greatvovan
74

Uma solução mais fácil parece ser:

fig.savefig('out.png', bbox_inches='tight', pad_inches=0)

fonte
2
Isso funcionou muito bem para mim. Além disso, pad_inches podem ser alterados para o tamanho desejado facilmente. Obrigado!
Curious2learn
27
Eu ainda tenho margens brancas com isso.
Fábio Perez
5
Consegui atualizar isso para versões mais novas / problema de margens restantes simplesmente adicionando transparent = True fig.savefig('out.png', bbox_inches='tight',transparent=True, pad_inches=0)
mdoc-2011
2
Ainda tenho machados, marcas de seleção e tudo mais com isto :(
BjornW,
3
Isso não faz absolutamente nada. Ele lhe dará a figura com todos os eixos e rótulos.
1313e
27

Você pode encontrar a bbox da imagem dentro do eixo (usando get_window_extent) e usar o bbox_inchesparâmetro para salvar apenas aquela parte da imagem:

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)

Aprendi esse truque com Joe Kington aqui .

unutbu
fonte
6
apenas plt.axis('off')ajudou. Outras respostas não ajudam muito.
imsrgadich
3
Isso funcionou muito bem. Porém, no meu caso, ainda há uma pequena borda branca. Alguma ideia de como remover essa fronteira?
user3731622
@ user3731622, tente em plt.savefig('/temp/test.png', bbox_inches='tight', transparent=True, pad_inches=0)vez deplt.savefig('/tmp/test.png', bbox_inches=extent)
Cloud Cho
17

Eu tentei várias opções no meu caso, e a melhor solução foi esta:

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

então salve sua figura com savefig

Cagri Sarigoz
fonte
1
De todas essas soluções, esta é a única que funcionou para mim.
Puff de
8

Vou sugerir a resposta heron13 com uma ligeira adição emprestada daqui para remover o preenchimento deixado após definir o bbox para o modo apertado, portanto:

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
fonte
Estou recebendo um erro dizendo que get_xaxis () e get_yaxis () não existem. Alguma ideia de por que isso aconteceria?
Jacob Malachowski
Realizar uma eixos () objeto, então use ax.xaxis e ax.yaxis
perigon
Ocorreu um erro dizendo que o objeto 'list' não tem o atributo 'get_xaxis'
Haozhe Xie
7

Este funciona para mim

plt.savefig('filename',bbox_inches='tight',transparent=True, pad_inches=0)
Cathy Yang
fonte
3

Tive o mesmo problema ao fazer algumas visualizações usando a librosa onde queria extrair o conteúdo da trama sem qualquer outra informação. Portanto, esta é a minha abordagem. resposta unutbu também me ajuda a fazer funcionar.

    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
fonte
Isso me colocou no caminho certo, mas tive dois problemas: 1) Tive que definir o dpi para um número maior do que 1 para evitar um erro de fonte em meu caderno jupyter; e 2) ainda havia uma pequena borda, então eu tenho que alterar manualmente a extensão para Bbox extent.get_points()*np.array([[1.1],[.9]]).
Bob Baxley
obrigado por cumprir a resposta que pode ajudar a outra pessoa.
GPrathap
3

Para quem está tentando fazer isso em Jupyter

 plt.axis('off')

 spec = plt.imshow

 plt.savefig('spec',bbox_inches='tight',transparent=True, pad_inches=0)
Krackle
fonte
2

Embora as respostas acima tratem da remoção de margens e preenchimento, elas não funcionaram para mim na remoção de rótulos. Aqui está o que funcionou, para quem se depara com esta questão mais tarde:

Supondo que você queira uma grade 2x2 de subtramas de quatro imagens armazenadas em 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')
curioso
fonte
1

Tentei me livrar da borda também, usando dicas aqui, mas nada funcionou. Fugindo um pouco e descobri que mudar a cor do rosto não me deu bordas nos laboratórios Jupyter (qualquer cor resultou na eliminação da borda branca). Espero que isto ajude.

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

insira a descrição da imagem aqui

Atom Scott
fonte
1

Para mim, este código tornou semelhante o tamanho da imagem de entrada sem moldura e eixos dos códigos matehat , unutbu e WHZW :

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)

Ambiente de tempo de execução:
Python 3.6.10
Matplotlib 3.2.1
OS Windows 10

Cloud Cho
fonte