126 votes

Comment afficher correctement plusieurs images dans une même figure?

Je cherche à afficher 20 images aléatoires sur une seule Figure. Les images sont en effet affichées, mais elles sont superposées. J'utilise :

import numpy as np
import matplotlib.pyplot as plt
w=10
h=10
fig=plt.figure()
for i in range(1,20):
    img = np.random.randint(10, size=(h,w))
    fig.add_subplot(i,2,1)
    plt.imshow(img)
plt.show()

Je souhaiterais qu'elles apparaissent naturellement dans une disposition en grille (disons 4x5), chacune de la même taille. Une partie du problème est que je ne sais pas ce que signifient les arguments de add_subplot. La documentation indique que les arguments sont le nombre de lignes, le nombre de colonnes et le numéro de tracé. Il n'y a pas d'argument de positionnement. De plus, le numéro de tracé ne peut être que 1 ou 2. Comment puis-je y parvenir ?

1 votes

Bien que techniquement vrai que cette question est un doublon, cette question a reçu ~10X plus de vues que l'autre.

276voto

swatchai Points 3065

Voici mon approche que vous pouvez essayer:

import numpy as np
import matplotlib.pyplot as plt

w = 10
h = 10
fig = plt.figure(figsize=(8, 8))
columns = 4
rows = 5
for i in range(1, columns*rows +1):
    img = np.random.randint(10, size=(h,w))
    fig.add_subplot(rows, columns, i)
    plt.imshow(img)
plt.show()

L'image résultante:

output_image

(Date de la réponse d'origine: 7 oct. '17 à 4:20)

Éditer 1

Étant donné que cette réponse est populaire au-delà de mes attentes. Et je vois qu'un petit changement est nécessaire pour permettre une flexibilité pour la manipulation des graphiques individuels. Je propose donc cette nouvelle version du code original. Essentiellement, il offre:

  1. accès aux axes individuels des sous-graphiques
  2. possibilité de tracer plus de caractéristiques sur des axes/sous-graphiques sélectionnés

Nouveau code:

import numpy as np
import matplotlib.pyplot as plt

w = 10
h = 10
fig = plt.figure(figsize=(9, 13))
columns = 4
rows = 5

# préparation (x,y) pour le tracé supplémentaire
xs = np.linspace(0, 2*np.pi, 60)  # de 0 à 2pi
ys = np.abs(np.sin(xs))           # valeur absolue du sinus

# ax permet d'accéder à la manipulation de chacun des sous-graphiques
ax = []

for i in range(columns*rows):
    img = np.random.randint(10, size=(h,w))
    # créer un sous-graphique et l'ajouter à ax
    ax.append( fig.add_subplot(rows, columns, i+1) )
    ax[-1].set_title("ax:"+str(i))  # définir le titre
    plt.imshow(img, alpha=0.25)

# faire des tracés supplémentaires sur des axes/sous-graphiques sélectionnés
# note: l'index commence à 0
ax[2].plot(xs, 3*ys)
ax[19].plot(ys**2, xs)

plt.show()  # enfin, afficher le graphique

La figure résultante:

enter image description here

Éditer 2

Dans l'exemple précédent, le code permet d'accéder aux sous-graphiques avec un index unique, ce qui est peu pratique lorsque la figure comporte de nombreuses lignes/colonnes de sous-graphiques. Voici une alternative. Le code ci-dessous permet d'accéder aux sous-graphiques avec [indice_ligne][indice_colonne], ce qui est plus adapté à la manipulation d'un tableau de nombreux sous-graphiques.

import matplotlib.pyplot as plt
import numpy as np

# paramètres
h, w = 10, 10        # pour l'image matricielle
nrows, ncols = 5, 4  # tableau de sous-graphiques
figsize = [6, 8]     # taille de la figure, en pouces

# préparation (x,y) pour des tracés supplémentaires sur des sous-graphiques sélectionnés
xs = np.linspace(0, 2*np.pi, 60)  # de 0 à 2pi
ys = np.abs(np.sin(xs))           # valeur absolue du sinus

# créer la figure (fig) et le tableau d'axes (ax)
fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=figsize)

# tracer une image matricielle simple sur chaque sous-graphique
for i, axi in enumerate(ax.flat):
    # i va de 0 à (nrows*ncols-1)
    # axi est équivalent à ax[indice_ligne][indice_colonne]
    img = np.random.randint(10, size=(h,w))
    axi.imshow(img, alpha=0.25)
    # obtenir les indices de ligne/colonne
    rowid = i // ncols
    colid = i % ncols
    # écrire les indices de ligne/colonne comme titre des axes pour l'identification
    axi.set_title("Ligne:"+str(rowid)+", Colonne:"+str(colid))

# on peut accéder aux axes par ax[indice_ligne][indice_colonne]
# faire des tracés supplémentaires sur ax[indice_ligne][indice_colonne] de votre choix
ax[0][2].plot(xs, 3*ys, color='red', linewidth=3)
ax[4][3].plot(ys**2, xs, color='green', linewidth=3)

plt.tight_layout(True)
plt.show()

La figure résultante:

plot3

Graduations et Étiquettes des graduations pour un Tableau de Sous-Graphiques

Certaines des graduations et des étiquettes de graduation accompagnant les sous-graphiques peuvent être masquées pour obtenir un graphique plus propre si tous les sous-graphiques partagent les mêmes plages de valeurs. Toutes les graduations et étiquettes de graduation peuvent être masquées sauf pour les bords extérieurs à gauche et en bas comme sur ce graphique.

share_ticklabels

Pour obtenir le graphique avec uniquement des étiquettes de graduation partagées sur les bords gauche et en bas, vous pouvez faire ce qui suit:

Ajoutez les options sharex=True, sharey=True dans fig, ax = plt.subplots()

Cette ligne de code deviendra:

fig,ax=plt.subplots(nrows=nrows,ncols=ncols,figsize=figsize,sharex=True,sharey=True)

Pour spécifier le nombre requis de graduations et d'étiquettes à tracer,

à l'intérieur du corps de for i, axi in enumerate(ax.flat):, ajoutez ce code

axi.xaxis.set_major_locator(plt.MaxNLocator(5))
axi.yaxis.set_major_locator(plt.MaxNLocator(4))

les nombres 5 et 4 sont le nombre de graduations/étiquettes à tracer. Vous pouvez avoir besoin d'autres valeurs adaptées à vos graphiques.

3 votes

Pour se débarrasser des chiffres/marques autour des sous-graphiques, vous pouvez faire ax = fig.add_subplot(lignes, colonnes, i) ax.set_xticks([]) ax.set_yticks([])

0 votes

@AnnaVopureta; En fait, on peut manipuler un axe sélectionné, par exemple ax[5], et utiliser quelque chose comme : ax[5].set_xxxx(yyy). C'est une idée plus générale.

0 votes

Et comment pouvez-vous enregistrer ce chiffre?

4voto

P i Points 2860

Vous pourriez essayer ce qui suit:

import matplotlib.pyplot as plt
import numpy as np

def plot_figures(figures, nrows = 1, ncols=1):
    """Trace un dictionnaire de figures.

    Paramètres
    ----------
    figures : dictionnaire 
    ncols : nombre de colonnes de sous-graphiques souhaité dans l'affichage
    nrows : nombre de lignes de sous-graphiques souhaité dans la figure
    """

    fig, axeslist = plt.subplots(ncols=ncols, nrows=nrows)
    for ind,title in zip(range(len(figures)), figures):
        axeslist.ravel()[ind].imshow(figures[title], cmap=plt.jet())
        axeslist.ravel()[ind].set_title(title)
        axeslist.ravel()[ind].set_axis_off()
    plt.tight_layout() # optionnel

# génération d'un dictionnaire de (titre, images)
nombre_de_im = 20
w=10
h=10
figures = {'im'+str(i): np.random.randint(10, size=(h,w)) for i in range(nombre_de_im)}

# tracé des images dans une figure, avec 5 lignes et 4 colonnes
plot_figures(figures, 5, 4)

plt.show()

Cependant, c'est essentiellement juste une copie-colle d'ici: Multiple figures in a single window pour cette raison ce post devrait être considéré comme un doublon.

J'espère que cela vous aide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X