Matplotlib-Diagramme: Entfernen von Achsen, Legenden und Leerzeichen

285

Ich bin neu in Python und Matplotlib. Ich möchte einfach eine Farbkarte auf ein Bild anwenden und das resultierende Bild schreiben, ohne Achsen, Beschriftungen, Titel oder irgendetwas zu verwenden, das normalerweise automatisch von matplotlib hinzugefügt wird. Folgendes habe ich getan:

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)

Die Achse der Figur wird erfolgreich entfernt, aber die gespeicherte Figur zeigt eine weiße Polsterung und einen Rahmen um das eigentliche Bild. Wie kann ich sie entfernen (zumindest die weiße Polsterung)? Vielen Dank

Sonnenmatte
quelle
2
Alle Lösungen zu dieser Frage sind fokussiert imshow. Wenn Sie stattdessen ein Streudiagramm
ImportanceOfBeingErnest

Antworten:

373

Ich denke, dass der Befehl axis('off')eines der Probleme prägnanter behandelt, als jede Achse und den Rand separat zu ändern. Es bleibt jedoch immer noch der weiße Raum um die Grenze. Wenn Sie bbox_inches='tight'den savefigBefehl hinzufügen, gelangen Sie fast dorthin. Im folgenden Beispiel sehen Sie, dass der verbleibende Leerraum viel kleiner ist, aber immer noch vorhanden ist.

Beachten Sie, dass neuere Versionen von matplotlib möglicherweise bbox_inches=0anstelle der Zeichenfolge erforderlich sind 'tight'(über @episodeyang und @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')

Geben Sie hier die Bildbeschreibung ein

Süchtig
quelle
4
Nach unutbu Vorschlag, könnten Sie verwenden fig = plt.figure(), ax = plt.axes([0,0,1,1])dann plt.imshow(data,interpolation="nearest". In Kombination mit plt.axis("off")sollte es hoffentlich alles außer dem Bild selbst loswerden!
PhilMacKay
5
Das Kombinieren der Methoden aus der Frage ({fig.axes.get_xaxis (). Set_visible (False) & fig.axes.get_yaxis (). Set_visible (False)} mit {plt.axis ('off')}) hat das Problem für behoben mich. (Keine Leerzeichen mehr). Und vergessen Sie nicht, Ihre {pad_inches} in savefig auf 0 zu setzen.
Domagoj
3
Ich bin gerade auf dieses Problem gestoßen, keine der Lösungen in diesem Thread und die verknüpften haben funktioniert. Die explizite Angabe hat bbox_inches=0jedoch den Trick getan.
Kadrach
1
Beachten Sie, dass Sie, wenn Sie wie in plt.plot (x, y) Dinge über die plt.imshow 'plotten', sicherstellen müssen, dass Sie xlim und ylim auf die Größe der Matrix einstellen.
Mathusalem
1
das funktioniert nicht mehr. Ich habe eine Stunde gebraucht, um es herauszufinden. Siehe Antwort unten.
Folgeyang
107

Diesen Trick habe ich hier von matehat gelernt :

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

ergibt

Geben Sie hier die Bildbeschreibung ein

unutbu
quelle
3
Ich bin mir ziemlich sicher, dass Sie die richtige Antwort haben (obwohl es wahrscheinlich mehr als einen Weg gibt, dies zu tun), aber ich frage mich, ob Sie erklären können, warum es die richtige Antwort ist. Was ist mit Ihrem Code, der den Leerraum entfernt?
Yann
4
@Yann, zusätzlich zur Dokumentation finde ich es sehr hilfreich, jeweils eine Zeile zu kommentieren, um zu sehen, welche Auswirkungen jeder Befehl hat. Es ist der empirische Weg!
Unutbu
4
Die Linie, die den weißen Rand entfernt, ist plt.Axes(fig, [0,0,1,1]). Dies weist matplotlib an, einen Satz von Achsen mit einer unteren linken Ecke an dem Punkt bei (0%, 0%) und einer Breite und Höhe von (100%, 100%) zu erstellen.
PhilMacKay
Dies ist die richtigere Antwort, da nicht nur Leerzeichen für das gespeicherte Bild, sondern auch für Bildschirmdiagramme entfernt werden.
MaxNoe
Danke, dies ist die EINZIGE Lösung, die auf meinem Ubuntu gut funktioniert :)
AlphaGoMK
56

Mögliche einfachste Lösung:

Ich habe einfach die in der Frage beschriebene Methode und die Methode aus der Antwort von Hooked kombiniert.

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)

Nach diesem Code gibt es keine Leerzeichen und keinen Frame.

Keine Leerzeichen, Achsen oder Rahmen

Domagoj
quelle
3
Ihre Methode hat alle Leerzeichen um dieses Bild entfernt, gute Arbeit, aber ich weiß immer noch nicht, warum das Hinzufügen des Befehls fig.axes.get_xaxis().set_visible(False)das Problem löst. Danke
ollydbg23
5
Ja, wenn Sie diese Befehle nicht aufrufen, werden die meisten Leerzeichen entfernt. In meinem Fall gab es jedoch noch einige Leerzeichen zwischen meinem Plot und dem Rand des PNG-Bildes (möglicherweise 2 Pixel breit). Durch das Aufrufen der folgenden Befehle habe ich diese hartnäckigen Leerzeichen beseitigt.
Domagoj
3
Beachten Sie jedoch, dass das oben Gesagte fehlschlägt, wenn mehrere Achsen in derselben Abbildung vorhanden sind (in meinem Fall ein eingebettetes Bild im Diagramm). Lösung: fig.axes[0]und im Allgemeinen alle oder ausgewählte Achsen.
Ioannis Filippidis
29

imsaveNoch niemand erwähnt , was dies zu einem Einzeiler macht:

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

Das Bild wird direkt so gespeichert, wie es ist, dh es werden keine Achsen oder Rahmen / Auffüllungen hinzugefügt.

Geben Sie hier die Bildbeschreibung ein

luator
quelle
Dies ist, was ich die meiste Zeit mache, aber es gibt Fälle, in denen ich die Farbleiste benötige, und in diesen Fällen kann mich imsave nicht retten.
Elias
9

Sie können auch den Umfang der Abbildung für das bbox_inchesArgument angeben . Dies würde die weiße Polsterung um die Figur herum beseitigen.

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)
Gypaetus
quelle
8

Dies sollte alle Polster und Ränder entfernen:

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)
Vlady Veselinov
quelle
Unterschätzte Antwort! Das hat mich zu 99% dorthin gebracht. Sollte besser bewertet werden, da es das aktuellste ist
Nathan
Es funktioniert auch, wenn Sie kein Axes-Objekt ( ax) mit haben extent = plt.gca().get_window_extent().transformed(fig.dpi_scale_trans.inverted()).
Toast
2

Ich mochte die Antwort von Ubuntu , aber sie zeigte nicht explizit, wie die Größe für nicht quadratische Bilder sofort eingestellt werden kann. Deshalb habe ich sie für einfaches Kopieren und Einfügen geändert:

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

Das Speichern von Bildern ohne Rahmen ist unabhängig von der gewählten Auflösung einfach, wenn pixel_size / dpi = size beibehalten wird.

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

Geben Sie hier die Bildbeschreibung ein

Die Anzeige ist jedoch gruselig. Wenn Sie eine kleine Auflösung wählen, kann Ihre Bildgröße größer als Ihr Bildschirm sein und Sie erhalten während der Anzeige einen Rand. Dies hat jedoch keinen Einfluss auf das Speichern.

So für

save_image_fix_dpi(data, dpi=20)

Die Anzeige wird eingefasst (aber das Speichern funktioniert): Geben Sie hier die Bildbeschreibung ein

csnemes
quelle
2

Die optimierte Antwort funktioniert nicht mehr. Damit es funktioniert, müssen Sie manuell eine Achse hinzufügen, die auf [0, 0, 1, 1] eingestellt ist, oder den Patch unter der Abbildung entfernen.

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

Alternativ können Sie den Patch auch einfach entfernen. Sie müssen keine Nebenhandlung hinzufügen, um die Auffüllungen zu entfernen. Dies wird durch die Antwort von Vlady unten vereinfacht

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

Dies wird mit der Version 3.0.3am 19.06.2019 getestet . Bild siehe unten:

Geben Sie hier die Bildbeschreibung ein

Eine viel einfachere Sache ist die Verwendung pyplot.imsave. Für Details, Sie in der Antwort von luator unten

Folgeyang
quelle
1

Erstens für bestimmte Bildformate (z. B. TIFF) ) die Farbkarte tatsächlich in der Kopfzeile speichern, und die meisten Betrachter zeigen Ihre Daten mit der Farbkarte an.

Zum Speichern eines tatsächlichen matplotlibBildes, das zum Hinzufügen von Anmerkungen oder anderen Daten zu Bildern hilfreich sein kann, habe ich die folgende Lösung verwendet:

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)
David Hoffman
quelle
0

Vielen Dank für die tollen Antworten von allen ... Ich hatte genau das gleiche Problem damit, nur ein Bild ohne zusätzliche Polsterung / Platz usw. zeichnen zu wollen, also war ich super glücklich, hier alle Ideen zu finden.

Abgesehen von Bildern ohne Auffüllung wollte ich auch einfach Anmerkungen usw. hinzufügen können, die über ein einfaches Bilddiagramm hinausgehen.

Am Ende kombinierte ich Davids Antwort mit der von csnemes, um zur Zeit der Figurenerstellung einen einfachen Wrapper zu erstellen . Wenn Sie das verwenden, brauchen Sie später keine Änderungen mit imsave () oder irgendetwas anderem:

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
Richard
quelle