Grafici matplotlib: rimozione di assi, legende e spazi bianchi


285

Sono nuovo di Python e Matplotlib, vorrei semplicemente applicare la mappa colori a un'immagine e scrivere l'immagine risultante, senza usare assi, etichette, titoli o qualsiasi cosa normalmente aggiunta automaticamente da Matplotlib. Ecco cosa ho fatto:

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)

Rimuove correttamente l'asse della figura, ma la figura salvata presenta un'imbottitura bianca e una cornice attorno all'immagine reale. Come posso rimuoverli (almeno l'imbottitura bianca)? Grazie


2
Tutte le soluzioni su questa domanda sono focalizzate su imshow. Se invece hai un diagramma a dispersione, la seguente risposta potrebbe aiutarti: stackoverflow.com/a/40727744/4124317
ImportanceOfBeingErnest

Risposte:


373

Penso che il comando axis('off')si occupi di uno dei problemi in modo più succinto che cambiare ciascun asse e il bordo separatamente. Lascia comunque lo spazio bianco attorno al bordo. Aggiungendo bbox_inches='tight'al savefigcomando quasi ti arriva lì, puoi vedere nell'esempio qui sotto che lo spazio bianco rimasto è molto più piccolo, ma ancora presente.

Si noti che potrebbero essere necessarie versioni più recenti di matplotlib bbox_inches=0anziché la stringa 'tight'(tramite @episodeyang e @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')

inserisci qui la descrizione dell'immagine


4
Seguendo il suggerimento di unutbu, si potrebbe usare fig = plt.figure(), ax = plt.axes([0,0,1,1])allora plt.imshow(data,interpolation="nearest". In combinazione con plt.axis("off"), dovrebbe sbarazzarsi di tutto ciò che è accanto all'immagine stessa, si spera!
PhilMacKay,

5
Combinando i metodi della domanda ({fig.axes.get_xaxis (). Set_visible (False) & fig.axes.get_yaxis (). Set_visible (False)} con {plt.axis ('off')}) risolto il problema per me. (Non ci sono più spazi bianchi). E non dimenticare di impostare {pad_inches} in savefig su 0.
Domagoj,

3
Ho appena incontrato questo problema, nessuna delle soluzioni in questo thread, e quelle collegate, ha funzionato. Tuttavia, è stato esplicitamente specificato bbox_inches=0il trucco.
Kadrach,

1
Nota che se stai "tramando" cose su plt.imshow, come in plt.plot (x, y), devi assicurarti di impostare xlim e ylim sulla dimensione della matrice.
Mathusalem,

1
questo non funziona più. Mi ci è voluta un'ora per capirlo. Vedi la risposta sotto.
episodeyang

108

Ho imparato questo trucco da Mateate, qui :

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

i rendimenti

inserisci qui la descrizione dell'immagine


3
Sono abbastanza sicuro che tu abbia la risposta corretta (anche se probabilmente c'è più di un modo per farlo), ma mi chiedo se puoi spiegare perché è la risposta giusta? Che dire del tuo codice rimuove lo spazio bianco?
Yann,

4
@Yann, oltre alla documentazione, trovo molto utile commentare una riga alla volta per vedere quale effetto ha ciascun comando. È il modo empirico!
unutbu,

4
La linea che rimuove il bordo bianco è plt.Axes(fig, [0,0,1,1]). Questo dice a matplotlib di creare una serie di assi con l'angolo in basso a sinistra nel punto situato a (0%, 0%) e con una larghezza e un'altezza di (100%, 100%).
PhilMacKay,

Questa è la risposta più corretta, in quanto non solo rimuove lo spazio bianco per l'immagine salvata ma anche per i grafici su schermo.
MaxNoe

Grazie, questa è l'UNICA soluzione che funziona bene sul mio Ubuntu :)
AlphaGoMK

56

Possibile soluzione più semplice:

Ho semplicemente combinato il metodo descritto nella domanda e il metodo dalla risposta di 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)

Dopo questo codice non ci sono spazi bianchi né frame.

Nessuno spazio bianco, ascia o cornice


3
Il tuo metodo ha rimosso tutti gli spazi bianchi attorno a questa immagine, buon lavoro, ma non so ancora perché aggiungere il comando fig.axes.get_xaxis().set_visible(False)risolva il problema. Grazie
ollydbg23 il

5
Sì, se non si chiama questo comando, la maggior parte degli spazi bianchi verrà rimossa. Comunque nel mio caso c'erano ancora degli spazi tra la mia trama e il bordo dell'immagine .png (forse 2px di larghezza). Chiamando i seguenti comandi mi sono sbarazzato di quegli spazi testardi.
Domagoj,

3
Si noti, tuttavia, che quanto sopra fallirà in presenza di più assi nella stessa figura (nel mio caso un'immagine incorporata nella trama). Soluzione: fig.axes[0]e in generale tutti o gli assi selezionati.
Ioannis Filippidis,

29

Nessuno imsaveancora menzionato , il che rende questo un one-liner:

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

Memorizza direttamente l'immagine così com'è, ovvero non aggiunge alcun asse o bordo / riempimento.

inserisci qui la descrizione dell'immagine


Questo è ciò che faccio la maggior parte delle volte, ma ci sono casi in cui ho bisogno della barra dei colori e in questi casi imsave non può salvarmi.
Elias,

9

Puoi anche specificare l'estensione della figura bbox_inchesall'argomento. Ciò eliminerebbe l'imbottitura bianca attorno alla figura.

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

Questo dovrebbe rimuovere tutte le imbottiture e i bordi:

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)

Risposta sottovalutata! Questo mi ha fatto guadagnare il 99% del percorso lì. Dovrebbe essere più votato perché è il più aggiornato
Nathan

Funziona anche se non hai un oggetto Axes ( ax) con extent = plt.gca().get_window_extent().transformed(fig.dpi_scale_trans.inverted()).
Brindisi il


3

La risposta votata non funziona più. Per farlo funzionare è necessario aggiungere manualmente un asse impostato su [0, 0, 1, 1] o rimuovere la patch sotto la figura.

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

In alternativa, puoi semplicemente rimuovere la patch. Non è necessario aggiungere una sottotrama per rimuovere le imbottiture. Questo è semplificato dalla risposta di Vlady di seguito

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

Questo è testato con la versione 3.0.32019/06/19. L'immagine vedi sotto:

inserisci qui la descrizione dell'immagine

Una cosa molto più semplice da fare è usare pyplot.imsave. Per i dettagli, vedere la risposta di luator sotto


per me funziona solo la versione Axes. ottengo il riempimento con la patch disattivata versione. grazie comunque!
save_jeff

2

Mi è piaciuta la risposta di Ubuntu , ma non stava mostrando esplicitamente come impostare immediatamente le dimensioni per le immagini non quadrate, quindi l'ho modificata per un facile copia-incolla:

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

Il salvataggio delle immagini senza bordo è semplice qualunque sia il dpi che scegli se pixel_size / dpi = size è mantenuto.

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

inserisci qui la descrizione dell'immagine

Tuttavia la visualizzazione è inquietante. Se si sceglie un piccolo dpi, la dimensione dell'immagine può essere più grande dello schermo e si ottiene il bordo durante la visualizzazione. Tuttavia, ciò non influisce sul salvataggio.

Così per

save_image_fix_dpi(data, dpi=20)

Il display diventa delimitato (ma il salvataggio funziona): inserisci qui la descrizione dell'immagine


1

Innanzitutto, per alcuni formati di immagine (ad es. TIFF ) puoi effettivamente salvare la mappa colori nell'intestazione e la maggior parte dei visualizzatori mostrerà i tuoi dati con la mappa colori.

Per salvare matplotlibun'immagine reale , che può essere utile per aggiungere annotazioni o altri dati alle immagini, ho usato la seguente soluzione:

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

Grazie per le fantastiche risposte di tutti ... Ho avuto esattamente lo stesso problema con la voglia di tracciare solo un'immagine senza spazio / imbottitura extra ecc., Quindi sono stato molto felice di trovare le idee di tutti qui.

Oltre all'immagine senza imbottitura, volevo anche essere in grado di aggiungere facilmente annotazioni ecc., Oltre a una semplice trama dell'immagine.

Quindi quello che ho finito è stato combinare la risposta di David con csnemes ' per creare un semplice wrapper al momento della creazione della figura. Quando lo usi, non hai bisogno di modifiche in seguito con imsave () o qualsiasi altra cosa:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.