Retour au tutoriel général
La documentation complète est disponible à l'adresse https://matplotlib.org/. Une bonne présentation est disponible à l'adresse http://www.python-simple.com/python-matplotlib/matplotlib-intro.php
import matplotlib.pyplot as plt
x = [1,3,5,7,9]
y = [j**2 for j in x]
plt.plot(x,y)
plt.show()
En fait ce résultat est trompeur. Ce que l'on trace effectivement ce sont des points dans le plan. La fonction $\mathtt{plot}$ se charge de relier ces points. Un tracé plus approprié dans ce cas serait
import matplotlib.pyplot as plt
x = [1,3,5,7,9]
y = [j**2 for j in x]
plt.plot(x,y,'*') # on spécifie le marqueur pour les points (*, s, ^, o)
plt.show()
import matplotlib.pyplot as plt
x = range(10)
y = [j**2 for j in x]
plt.plot(x,y,'*') # on spécifie le marqueur pour les points (*, s, ^, o)
plt.plot(x,y,'red')
plt.show()
import matplotlib.pyplot as plt
x = range(10)
y = [j**2 for j in x]
# Taille de la figure (à placer avant le tracé)
plt.figure(figsize=(10,10))
plt.plot(x,y, '*')
plt.axis([-1, 15, 0, 100]) # on spécifie la taille de la fenêtre
p2=plt.plot(x,y)
plt.setp(p2, color='red', linewidth=2.0) # on spécifie la couleur et la taille des lignes
# Légende
plt.legend(["Des points","Trait plein"],loc='center right')
# Titre et noms des axes
plt.title("Un exemple de tracé")
plt.xlabel("Abscisses",fontsize=14)
plt.ylabel("Ordonnées")
# Ecrire sur la figure
plt.text(0, 80, r'Fonction $x \mapsto x^2$',fontsize=16,color='blue')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,100) # on a 100 points entre 0 et 10
y = x**2
plt.plot(x,y)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,100) # on a 100 points entre 0 et 10
y = x**2
plt.figure(1)
plt.plot(x[:50],y[:50])
# On ne trace qu'une partie de la figure
plt.figure(2)
z = [1/j for j in x if j != 0]
plt.plot(x[1:],z,'rs') # on enlève le 1er élément de x pour que les deux listes aient la même taille
plt.figure(1)
# on revient sur la figure et on trace d'autres points
plt.plot(x[75:],y[75:],'b*')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,2,100) # on a 100 points entre 0 et 10
y = np.exp(-3*x**2 + 1)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8,4)) # on utilise subplot pour mettre deux figures côte à côte
ax1.plot(x,y)
ax1.title.set_text("Tracé de la fonction")
ax2.semilogy(x,y)
ax2.title.set_text("Tracé de la fonction en échelle logarithmique")
plt.subplots_adjust(wspace=0.75) # Pour espacer les deux graphiques
import matplotlib.pyplot as plt
c = ['Candidat A', 'Candidat B', 'Candidat C']
vote = [0.35, 0.45, 0.2]
vote_2 = [0.37, 0.43, 0.2]
print(vote_2)
plt.bar(c,vote,align='center')
plt.bar(c,vote_2,color='red',width=0.5)
plt.show()
[0.37, 0.43, 0.2]
ou des diagrammes en secteurs (i.e. des camenberts)
import matplotlib.pyplot as plt
c = ['Candidat A', 'Candidat B', 'Candidat C']
vote = [0.35, 0.45, 0.2]
vote_2 = [0.37, 0.43, 0.2]
plt.pie(vote, labels = c, # valeurs et labels
#colors = ['blue', 'yellow', 'red'], # si l'on veut choisir les couleurs
explode = [0, 0.2, 0], # si l'on veut "écarter" un secteur
autopct = lambda z: str(round(z, 2)) + '%', # affichage des pourcentages dans les secteurs
pctdistance = 0.7, # distance au centre pour l'affichage des pourcentages
labeldistance = 1.2, # distance au centre pour l'affichage des labels
normalize=False) # normalisation des données (ici déjà normalisées = somme à 1)
plt.title('Diagramme en secteurs')
#plt.legend(loc='upper left')
plt.show()
Un nuage de points peut être tracé avec la fonction $\mathtt{scatter}$.
import numpy as np
import matplotlib.pyplot as plt
x = [np.random.rand() for i in range(100)]
y = [np.random.rand() for i in range(100)]
plt.scatter(x,y)
plt.show()
import matplotlib.pyplot as plt
import numpy as np
# Création d'un échantillon de valeurs de 1000 entiers compris entre 10 et 14
x= [np.random.randint(10, 15) for i in range(1000)]
# On trace le diagramme des effectifs obtenus
plt.hist(x)
plt.show()
Dans le diagramme ci-dessus nous n'avons pas précisé quel est le découpage de l'intervalle $[0,14]$ qu'il faut considérer. Par défaut, pour le calcul des effectifs de chaque classe, l'intervalle considéré $[\min, \max]$ est découpé en $10$ sous-intervalles. Il est donc préférable de préciser l'intervalle considéré avec le paramètre $\mathtt{range}$ et le nombre de sous-intervalles avec l'argument $\mathtt{bins}$.
L'appel de la fonction $$ \mathtt{plt.hist(x , range=[a,b], bins=n)} $$ trace le diagramme des effectifs associé au découpage de l'intervalle $[a,b]$ donné par $$ \left[ a , a+ \frac{b-a}{n} \right[, \quad \left[ a+ \frac{b-a}{n}, a + 2 \frac{b-a}{n} \right[, \quad \dots, \quad \left[ a+ (n-1) \frac{b-a}{n} , b \right].$$ Noter que tous les intervalles sont ouverts à droite, sauf le dernier qui est fermé.
Comparer le diagramme précédent avec les deux suivants.
plt.hist(x, range=[10,15], bins=5, # on découpe notre intervalle [10,15] en 5 sous intervalles
# donc des sous-intervalles de longueur 1 : [10, 11[, [11,12[, ..., [14,15].
rwidth= 0.5, # on réduit la largeur des barres pour améliorer la lisibilité
align='left' # position de la barre par rapport au sous-intervalle
)
plt.show()
On peut aussi spécifier directement les bornes du découpage en sous-intervalles:
plt.hist(x, range=[10,16], bins=[10,12,13.5,16], edgecolor='black',align='mid')
plt.show()
Le dernier diagramme ne contient que $3$ sous-intervalles : $$ [10,12[, \quad [12, 13.5[ \quad \text{ et } \quad [13.5, 16]. $$ Dans le premier on prend donc en compte les occurrences de $10$ et $11$ ; dans le deuxième les occurrences de $12$ et $13$ ; dans le troisième seulement les occurrences de $14$.
Attention. Pour être précis, les tracés précédents ne sont pas des histogrammes à proprement parler. Dans un histogramme, c'est l'aire du rectangle qui donne les informations (ce qui est particulièrement important lorsque les rectangles ont des largeurs différentes). Pour cela, on utilise l'option $\mathtt{density=True}$ qui permet de tracer les histogrammes des fréquences : l'aire totale des rectangles est alors égale à $1$.
fig, (ax1,ax2) = plt.subplots(1,2)
ax1.hist(x, range=[10,15], bins=5, edgecolor='black', align='left', density=True)
ax2.hist(x, bins=[10,10.5,11,12,13,14,15], edgecolor='black', align='left', density=True)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
M = [[0,1,2],[3,4,5],[6,7,8]]
f, (ax1, ax2) = plt.subplots(1, 2) # on utilise subplot pour mettre deux figures côte à côte
ax1.imshow(M)
ax1.axis(False) # enlever les graduations des axes
#plt.show()
ax2.imshow(M, cmap='seismic') # le même en changeant la ColorMap
ax2.axis(False)
plt.show()
ou des polygones
import matplotlib.pyplot as plt
x = [3.53525079574969e-16 ,-0.5555555555555551 ,-1.666666666666666 ,-1.1111111111111105 ,-1.666666666666666 ,-2.7777777777777772 ,-3.333333333333333 ,-3.8888888888888884 ,-5.0 ,-4.444444444444445 ,-5.0 ,-3.8888888888888884 ,-3.3333333333333326 ,-3.8888888888888884 ,-5.0 ,-4.444444444444445 ,-5.0 ,-3.8888888888888893 ,-3.333333333333334 ,-2.777777777777778 ,-1.666666666666667 ,-1.1111111111111116 ,-1.6666666666666674 ,-0.5555555555555562 ,-8.881784197001252e-16 ,0.5555555555555547 ,1.666666666666666 ,1.1111111111111103 ,1.666666666666666 ,2.777777777777777 ,3.333333333333332 ,3.888888888888888 ,4.999999999999999 ,4.444444444444444 ,5.0 ,3.8888888888888884 ,3.333333333333333 ,3.8888888888888884 ,5.0 ,4.444444444444445 ,5.0 ,3.888888888888889 ,3.3333333333333335 ,2.7777777777777777 ,1.6666666666666665 ,1.1111111111111112 ,1.6666666666666674 ,0.5555555555555558]
y = [5.773502691896258 ,4.811252243246882 ,4.811252243246882 ,3.8490017945975055 ,2.886751345948129 ,2.886751345948129 ,3.8490017945975055 ,2.886751345948129 ,2.886751345948129 ,1.9245008972987527 ,0.9622504486493761 ,0.9622504486493764 ,0.0 ,-0.9622504486493765 ,-0.9622504486493764 ,-1.924500897298753 ,-2.8867513459481295 ,-2.88675134594813 ,-3.8490017945975064 ,-2.88675134594813 ,-2.8867513459481304 ,-3.849001794597507 ,-4.811252243246884 ,-4.811252243246884 ,-5.77350269189626 ,-4.811252243246884 ,-4.811252243246884 ,-3.8490017945975072 ,-2.886751345948131 ,-2.8867513459481313 ,-3.8490017945975072 ,-2.8867513459481313 ,-2.8867513459481318 ,-1.9245008972987554 ,-0.962250448649379 ,-0.9622504486493788 ,-2.220446049250313e-15 ,0.9622504486493739 ,0.9622504486493739 ,1.92450089729875 ,2.8867513459481264 ,2.886751345948127 ,3.8490017945975032 ,2.886751345948127 ,2.8867513459481273 ,3.849001794597504 ,4.811252243246881 ,4.811252243246881]
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(9, 3),
subplot_kw={'aspect': 'equal'})
ax1.fill(x, y)
ax2.fill(x, y, facecolor='lightsalmon', edgecolor='orangered', linewidth=3)
ax3.fill(x, y, facecolor='none', edgecolor='blue', linewidth=1)
plt.show()
Selon l'éditeur utilisé (et ses paramètres), il est possible de devoir modifier le back-end en tapant la commande $\mathtt{\%matplotlib}$ $\mathtt{qt}$ pour visualiser sans enregistrer la vidéo obtenue.
%matplotlib qt
Pour revenir à l'affichage dans la console IPython : $\mathtt{\%matplotlib}$ $\mathtt{inline}$
%matplotlib inline
La fonction $\mathtt{ArtistAnimation}$ permet de faire un effet d'animation à partir d'une liste d'images.
# Utilisation de ArtistAnimation : on anime les oscillations d'un sinus à partir d'une liste d'images.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import rc
fig = plt.figure(1)
plt.axis([0,2*np.pi,-1,1])
N = 40 # nombre d'images
x = np.linspace(0,2*np.pi,100) # ce sera notre tableau d'abscisse pour le tracé.
liste_images = [] # on va stocker toutes nos images dans cette liste
for i in range(N):
im = plt.plot(x,np.sin(x-i*(2*np.pi)/N),'b')
liste_images.append(im)
# liste_images contient toutes les images que l'on souhaite animer
anim = animation.ArtistAnimation(fig, liste_images, interval=150, repeat_delay=1000)
# si l'on veut enregistrer
#anim.save("oscillation.mp4")
# si l'on veut un joli affichage dans cette page HTML
#plt.show() # à décommenter si on ne fait pas l'affichage HTML
rc('animation', html='jshtml')
anim
Les deux exemples ci-dessous plus complets sont issus de la documentation de $\mathtt{matplotlib}$.
Le premier anime une fonction "point par point" en utilisant $\mathtt{FuncAnimation}$. La fonction $\mathtt{update}$ indique ce qu'il faut rajouter d'une frame à l'autre.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
#ani.save("movie.mp4")
#plt.show()
ani
Le second anime une liste d'images stockées dans $\mathtt{ims}$.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
# ims is a list of lists, each row is a list of artists to draw in the
# current frame; here we are just animating one artist, the image, in
# each frame
ims = []
for i in range(60):
x += np.pi / 15.
y += np.pi / 20.
im = ax.imshow(f(x, y), animated=True)
if i == 0:
ax.imshow(f(x, y)) # show an initial one first
ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True,
repeat_delay=1000)
# To save the animation, use e.g.
#
#ani.save("movie2.mp4")
#
# or
#
# writer = animation.FFMpegWriter(
# fps=15, metadata=dict(artist='Me'), bitrate=1800)
# ani.save("movie.mp4", writer=writer)
plt.show()