web-dev-qa-db-fra.com

Parcelles Matplotlib: suppression des axes, légendes et espaces blancs

Python et Matplotlib nouveaux, 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 remplissage blanc et un cadre autour de l'image réelle. Comment puis-je les supprimer (au moins le rembourrage blanc)? Merci

226
sunmat

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

Notez que les nouvelles versions de matplotlib peuvent nécessiter bbox_inches=0 au lieu 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')

enter image description here

303
Hooked

J'ai appris cette astuce de matehat, here :

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

enter image description here

91
unutbu

Solution la plus simple possible:

J'ai simplement combiné la méthode décrite dans la question et la méthode tirée 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’ya plus d’espace ni de cadre.

No whitespaces, axes or frame

46
Domagoj

Personne n'a mentionné imsave , ce qui en fait 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")

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

enter image description here

25
luator

Vous pouvez également spécifier l'étendue de la figure dans l'argument bbox_inches. 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)
9
Miguel de Val-Borro

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)
6
Vlady Veselinov

J'ai bien aimé d'ubunt répondre, mais cela ne montrait pas explicitement comment définir la taille des images non carrées prêtes à l'emploi, je l'ai donc modifiée pour faciliter le copier-coller:

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 est facile d’enregistrer des images sans bordure, quelle que soit la résolution choisie si pixel_size/dpi = size est conservé.

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

enter image description here

Cependant, l'affichage est fantasmagorique. Si vous choisissez un petit dpi, la taille de votre image peut être supérieure à celle de 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 enregistre les œuvres): enter image description here

2
csnemes

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

Pour enregistrer une image matplotlib réelle, ce 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)
1
David Hoffman

Merci pour les réponses géniales de tout le monde ... J'ai eu exactement le même problème avec le désir de tracer une image sans aucune marge/espace supplémentaire, donc j'étais super heureux de trouver les idées de tout le monde ici.

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

Donc, ce que j'ai fini par faire était de combiner la réponse de David avec 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 quoi que ce soit d'autre:

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

Toutes les anciennes réponses ne fonctionnent plus. Vous devez utiliser bbox_inches=0 pour le faire fonctionner.

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=0)# <= this is where the difference is for newer maptlotlib.

Sinon, vous pouvez utiliser

plt.savefig("test.png", bbox_inches=None)

La présence ou non de cet argument de mot clé a un impact sur la manière dont matplotlib traite les mots clés facultatifs.

Ceci est testé avec la version 3.0.3 le 2019/06/19.

0
episodeyang

La réponse votée ne fonctionne plus. Pour que cela fonctionne, vous devez ajouter manuellement un axe défini sur [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 une sous-parcelle pour supprimer les bourrages. Ceci est simplifié à partir de 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.3 le 2019/06/19. Image voir ci-dessous:

enter image description here

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

0
episodeyang