126 votes

Comment afficher correctement plusieurs images dans une figure ?

J'essaie d'afficher 20 images aléatoires sur une seule figure. Les images sont bien 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 voudrais qu'elles apparaissent naturellement dans une grille (disons 4x5), chacune ayant 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 du graphique. Il n'y a pas d'argument de positionnement. De plus, le numéro du tracé ne peut être que 1 ou 2. Comment puis-je obtenir ce résultat ?

1 votes

Bien qu'il soit 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 qui en résulte :

output_image

(Date de la réponse originale : 7 Oct '17 à 4:20)

Edit 1

Puisque cette réponse est populaire au-delà de mes espérances. Et je vois qu'un petit changement est nécessaire pour permettre la flexibilité pour la manipulation des parcelles individuelles. De sorte que je propose cette nouvelle version au code original. En substance, il fournit :-

  1. accès aux axes individuels des sous-plans
  2. possibilité de tracer plus d'éléments sur les axes sélectionnés/sous-tracer

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

# prep (x,y) for extra plotting
xs = np.linspace(0, 2*np.pi, 60)  # from 0 to 2pi
ys = np.abs(np.sin(xs))           # absolute of sine

# ax enables access to manipulate each of subplots
ax = []

for i in range(columns*rows):
    img = np.random.randint(10, size=(h,w))
    # create subplot and append to ax
    ax.append( fig.add_subplot(rows, columns, i+1) )
    ax[-1].set_title("ax:"+str(i))  # set title
    plt.imshow(img, alpha=0.25)

# do extra plots on selected axes/subplots
# note: index starts with 0
ax[2].plot(xs, 3*ys)
ax[19].plot(ys**2, xs)

plt.show()  # finally, render the plot

La parcelle qui en résulte :

enter image description here

Edit 2

Dans l'exemple précédent, le code permet d'accéder aux sous-plans avec un seul index, ce qui est peu pratique lorsque la figure comporte de nombreuses lignes/colonnes de sous-plans. Voici une alternative. Le code ci-dessous permet d'accéder aux sous-plots avec un index unique. [row_index][column_index] qui convient mieux à la manipulation de tableaux contenant de nombreux sous-plans.

import matplotlib.pyplot as plt
import numpy as np

# settings
h, w = 10, 10        # for raster image
nrows, ncols = 5, 4  # array of sub-plots
figsize = [6, 8]     # figure size, inches

# prep (x,y) for extra plotting on selected sub-plots
xs = np.linspace(0, 2*np.pi, 60)  # from 0 to 2pi
ys = np.abs(np.sin(xs))           # absolute of sine

# create figure (fig), and array of axes (ax)
fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=figsize)

# plot simple raster image on each sub-plot
for i, axi in enumerate(ax.flat):
    # i runs from 0 to (nrows*ncols-1)
    # axi is equivalent with ax[rowid][colid]
    img = np.random.randint(10, size=(h,w))
    axi.imshow(img, alpha=0.25)
    # get indices of row/column
    rowid = i // ncols
    colid = i % ncols
    # write row/col indices as axes' title for identification
    axi.set_title("Row:"+str(rowid)+", Col:"+str(colid))

# one can access the axes by ax[row_id][col_id]
# do additional plotting on ax[row_id][col_id] of your choice
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 parcelle qui en résulte :

plot3

Ticks et Tick-labels pour un tableau de sous-plans

Certains des tics et des étiquettes de tics accompagnant les sous-plans peuvent être masqués pour obtenir un graphique plus net si tous les sous-plans partagent les mêmes plages de valeurs. Tous les tics et les étiquettes peuvent être cachés, à l'exception des bords extérieurs à gauche et en bas, comme dans ce graphique.

share_ticklabels

Pour obtenir un tracé avec uniquement des étiquettes à cocher partagées sur les bords gauche et inférieur, vous pouvez procéder de la manière suivante :-

Ajouter des options sharex=True, sharey=True en 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 ticks, et les étiquettes à tracer,

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

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

le nombre 5, et 4 sont le nombre de ticks/tick_labels à tracer. Vous pouvez avoir besoin d'autres valeurs en fonction de vos tracés.

3 votes

Pour se débarrasser des chiffres/marques autour des sous-points, vous pouvez faire ax = fig.add_subplot(rows, columns, 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 sauver ce chiffre ?

4voto

P i Points 2860

Vous pouvez essayer ce qui suit :

import matplotlib.pyplot as plt
import numpy as np

def plot_figures(figures, nrows = 1, ncols=1):
    """Plot a dictionary of figures.

    Parameters
    ----------
    figures : <title, figure> dictionary
    ncols : number of columns of subplots wanted in the display
    nrows : number of rows of subplots wanted in the 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() # optional

# generation of a dictionary of (title, images)
number_of_im = 20
w=10
h=10
figures = {'im'+str(i): np.random.randint(10, size=(h,w)) for i in range(number_of_im)}

# plot of the images in a figure, with 5 rows and 4 columns
plot_figures(figures, 5, 4)

plt.show()

Cependant, il s'agit essentiellement d'un copier-coller d'ici : Plusieurs chiffres dans une seule fenêtre pour cette raison, ce message doit être considéré comme un doublon.

J'espère que cela vous aidera.

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