Tracés de Matplotlib: suppression de l'axe, des légendes et des espaces blancs

285

Je suis nouveau sur Python et Matplotlib, je voudrais simplement appliquer une palette de couleurs à une image et écrire l'image résultante, sans utiliser d'axes, d'étiquettes, de titres ou quoi que ce soit habituellement ajouté automatiquement par matplotlib. Voici ce que j'ai fait:

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)

Il supprime avec succès l'axe de la figure, mais la figure enregistrée présente un rembourrage blanc et un cadre autour de l'image réelle. Comment puis-je les retirer (au moins le rembourrage blanc)? Merci

tapis de soleil
la source
2
Toutes les solutions sur cette question sont focalisées imshow. Si vous avez un nuage de points à la place, la réponse suivante pourrait vous aider: stackoverflow.com/a/40727744/4124317
ImportanceOfBeingErnest

Réponses:

374

Je pense que la commande axis('off')s'occupe de l'un des problèmes plus succinctement que de changer chaque axe et la frontière séparément. Il laisse cependant l'espace blanc autour de la frontière. L'ajout bbox_inches='tight'à la savefigcommande vous y mène presque, vous pouvez voir dans l'exemple ci-dessous que l'espace blanc laissé est beaucoup plus petit, mais toujours présent.

Notez que les nouvelles versions de matplotlib peuvent nécessiter à la bbox_inches=0place de la chaîne 'tight'(via @episodeyang et @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')

entrez la description de l'image ici

Accroché
la source
4
Suite à la suggestion de unutbu, vous pouvez utiliser fig = plt.figure(), ax = plt.axes([0,0,1,1])puis plt.imshow(data,interpolation="nearest". Combiné avec plt.axis("off"), il devrait se débarrasser de tout à côté de l'image elle-même, espérons-le!
PhilMacKay
5
La combinaison des méthodes de la question ({fig.axes.get_xaxis (). Set_visible (False) & fig.axes.get_yaxis (). Set_visible (False)} avec {plt.axis ('off')}) a résolu le problème de moi. (Plus d'espaces blancs). Et n'oubliez pas de mettre votre {pad_inches} dans savefig à 0.
Domagoj
3
Je viens de rencontrer ce problème, aucune des solutions de ce fil, et des solutions liées, n'a fonctionné. Cependant, spécifier explicitement a bbox_inches=0fait l'affaire.
kadrach
1
Notez que si vous `` tracez '' des trucs sur le plt.imshow, comme dans plt.plot (x, y), vous devez vous assurer que vous définissez xlim et ylim à la taille de la matrice.
Mathusalem
1
cela ne fonctionne plus. Ça m'a pris une heure pour le comprendre. Voir la réponse ci-dessous.
episodeyang
108

J'ai appris cette astuce de matehat, ici :

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

les rendements

entrez la description de l'image ici

unutbu
la source
3
Je suis sûr que vous avez la bonne réponse (bien qu'il y ait probablement plus d'une façon de le faire), mais je me demande si vous pouvez expliquer pourquoi c'est la bonne réponse? Qu'en est-il de votre code supprime l'espace blanc?
Yann
4
@Yann, en plus de la documentation, je trouve très utile de commenter une ligne à la fois pour voir quel effet chaque commande a. C'est la voie empirique!
unutbu
4
La ligne qui supprime la bordure blanche est plt.Axes(fig, [0,0,1,1]). Cela indique à matplotlib de créer un ensemble d'axes avec le coin inférieur gauche au point situé à (0%, 0%), et avec une largeur et une hauteur de (100%, 100%).
PhilMacKay
C'est la réponse la plus correcte, car elle supprime non seulement l'espace blanc pour l'image enregistrée mais aussi pour les tracés à l'écran.
MaxNoe
Merci, c'est la SEULE solution qui fonctionne bien sur mon Ubuntu :)
AlphaGoMK
56

Solution la plus simple possible:

J'ai simplement combiné la méthode décrite dans la question et la méthode de la réponse de 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)

Après ce code, il n'y a ni espace ni cadre.

Pas d'espaces, d'axes ou de cadre

Domagoj
la source
3
Votre méthode a supprimé tous les espaces blancs autour de cette image, bon travail, mais je ne sais toujours pas pourquoi l'ajout de la commande fig.axes.get_xaxis().set_visible(False)résout le problème. Merci
ollydbg23
5
Oui, si vous n'appelez pas cette commande, la plupart des espaces blancs seront supprimés. Cependant, dans mon cas, il y avait encore des espaces entre mon tracé et le bord de l'image .png (peut-être 2px de large). En appelant les commandes suivantes, je me suis débarrassé de ces espaces tenaces.
Domagoj
3
Notez, cependant, que ce qui précède échouera en présence de plusieurs axes dans la même figure (dans mon cas, une image intégrée dans le tracé). Solution:, fig.axes[0]et en général tous ou certains axes.
Ioannis Filippidis
29

Personne imsaveencore mentionné , ce qui en fait une ligne unique:

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

Il stocke directement l'image telle qu'elle est, c'est-à-dire n'ajoute aucun axe ni bordure / remplissage.

entrez la description de l'image ici

luator
la source
C'est ce que je fais la plupart du temps, mais il y a des cas où j'ai besoin de la barre de couleurs, et dans ces cas, imsave ne peut pas me sauver.
Elias
9

Vous pouvez également spécifier l'étendue de la figure à l' bbox_inchesargument. Cela éliminerait le rembourrage blanc autour de la figure.

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
la source
8

Cela devrait supprimer tout le rembourrage et les bordures:

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
la source
Réponse sous-estimée! Cela m'a donné 99% du chemin. Devrait être plus voté parce que c'est le plus à jour
Nathan
Cela fonctionne également si vous n'avez pas d'objet Axes ( ax) avec extent = plt.gca().get_window_extent().transformed(fig.dpi_scale_trans.inverted()).
Toast
3

La réponse votée ne fonctionne plus. Pour le faire fonctionner, vous devez ajouter manuellement un jeu d'axes à [0, 0, 1, 1], ou supprimer le patch sous la figure.

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

Alternativement, vous pouvez simplement supprimer le patch. Vous n'avez pas besoin d'ajouter un sous-tracé pour supprimer les rembourrages. Ceci est simplifié de la réponse de Vlady ci-dessous

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

Ceci est testé avec la version 3.0.3du 2019/06/19. Image voir ci-dessous:

entrez la description de l'image ici

Une chose beaucoup plus simple à faire est d'utiliser pyplot.imsave. Pour plus de détails, voir la réponse du luator ci-dessous

episodeyang
la source
pour moi, seule la version Axes fonctionne. j'obtiens le rembourrage avec le patch désactivé. merci quand même!
save_jeff
2

J'ai aimé la réponse d'ubuntu , mais elle ne montrait pas explicitement comment définir la taille des images non carrées hors de la boîte, donc je l'ai modifiée pour un copier-coller facile:

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

L'enregistrement d'images sans bordure est facile quel que soit le dpi que vous choisissez si pixel_size / dpi = la taille est conservée.

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

entrez la description de l'image ici

Cependant, l'affichage est effrayant. Si vous choisissez un petit dpi, la taille de votre image peut être plus grande que votre écran et vous obtenez une bordure pendant l'affichage. Néanmoins, cela n'affecte pas l'épargne.

Donc pour

save_image_fix_dpi(data, dpi=20)

L'affichage devient bordé (mais la sauvegarde fonctionne): entrez la description de l'image ici

csnemes
la source
1

Tout d'abord, pour certains formats d'image (par exemple TIFF ), vous pouvez réellement enregistrer la palette de couleurs dans l'en-tête et la plupart des téléspectateurs afficheront vos données avec la palette de couleurs.

Pour enregistrer une matplotlibimage réelle , qui peut être utile pour ajouter des annotations ou d'autres données aux images, j'ai utilisé la solution suivante:

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
la source
0

Merci pour les réponses impressionnantes de tout le monde ... J'ai eu exactement le même problème avec le fait de vouloir tracer juste une image sans rembourrage / espace supplémentaire, etc., donc j'étais super heureux de trouver les idées de tout le monde ici.

Outre l'image sans remplissage, je voulais également pouvoir ajouter facilement des annotations, etc., au-delà d'un simple tracé d'image.

J'ai donc fini par combiner la réponse de David avec celle de csnemes pour créer un simple wrapper au moment de la création de la figure. Lorsque vous utilisez cela, vous n'avez besoin d'aucune modification plus tard avec imsave () ou autre chose:

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
la source