None TP0-D-Matplotlib-Numpy
In [89]:
from IPython.core.display import HTML
css_file = './custom.css'
HTML(open(css_file, "r").read())
Out[89]:
In [90]:
import sys #only needed to determine Python version number
import matplotlib #only needed to determine Matplotlib version number
import numpy #only needed to determine numpy version number

print('Python version ' + sys.version)
print('Matplotlib version ' + matplotlib.__version__ )
print('Numpy version ' + numpy.__version__ )

%reset -f
Python version 3.8.5 (default, Jul 28 2020, 12:59:40) 
[GCC 9.3.0]
Matplotlib version 3.1.2
Numpy version 1.17.4

M62_TP0 Les modules Matplotlib et Numpy

Table of Contents

Dessiner des courbes avec le module matplotlib


Le tracé de courbes scientifiques peut se faire à l'aide du module matplotlib.
Matplotlib est un package complet; pylab et pyplot sont des modules de matplotlib qui sont installés avec matplotlib.
Pylab associe les fonctions de pyplot (pour les tracés) avec les fonctionnalité du module numpy pour obtenir un environnement très proche de celui de MATLAB.

Dans les notebook, pour que les figures s'affichent dans le notebook directement il faudra utiliser la commande magique

%matplotlib inline

Si on veut intéragir avec les figure, on pourra utiliser plutot

%matplotlib notebook

On peut importer le module

  • soit par l'instruction

      from matplotlib.pylab import *

    Cette instruction importe aussi le module numpy sans alias.

  • soit par l'instruction

      import matplotlib.pyplot as plt

Dans le premier cas on pourra utiliser les commande "à la MATLAB", comme par exemple

from matplotlib.pylab import *
x=linspace(-pi,pi,101)
plot(x,cos(x))

dans le deuxième cas il faudra faire précéder toutes les instruction matplotlib par plt et celles numpy par np, comme par exemple

import matplotlib.pyplot as plt
import numpy as np
x=np.linspace(-np.pi,np.pi,101)
plt.plot(x,np.cos(x))

Lorsqu'il n'y a pas de risque de superpositions des namespace on utilisera pylab.

In [1]:
%matplotlib inline
from matplotlib.pylab import *
x=linspace(-pi, pi, 101)
plot(x,cos(x));
# savefig("m01.png")
In [2]:
%matplotlib notebook
from matplotlib.pylab import *
x=linspace(-pi, pi, 101)
plot(x,cos(x));
# savefig("m01.png")

On peut écrire et exécuter des script Python (qui utilisent Matplotlib) en ligne à l'adresse https://trinket.io/python/a8645625fd
Pour l'utiliser, on peut importer le module pylab.

La référence complète de matplotlib est lisible à l'adresse: http://matplotlib.sourceforge.net/matplotlib.pylab.html Il est en particulier recommandé de regarder les screenshots (captures d'écrans), qui sont donnés avec le code utilisé pour les générer.

Vous pouvez consulter aussi

1D

Pour tracer le graphe d'une fonction $f\colon[a,b]\to\mathbb{R}$, Python a besoin d'une grille de points $x_i$ où évaluer la fonction, ensuite il relie entre eux les points $(x_i,f(x_i))$ par des segments. Plus les points sont nombreux, plus le graphe est proche du graphe de la fonction $f$. Pour générer les points $x_i$ on peut utiliser

  • l'instruction linspace(a,b,n+1) qui construit la liste de $n+1$ éléments $$ \left[a,a+h,a+2h,\dots,b=a+nh\right] \quad\text{avec } h=\frac{b-a}{n} $$
  • ou l'instruction arange(a,b,h) qui construit la liste de $n=E(\frac{b-a}{h})+1$ éléments $$ \left[a,a+h,a+2h,\dots,a+nh\right] $$ Dans ce cas, attention au dernier terme: avec des float les erreurs d'arrondis pourrait faire en sort que $b$ ne soit pas pris en compte.

Voici un exemple avec une sinusoïde:

In [92]:
%matplotlib inline
from matplotlib.pylab import *
x = linspace(-5,5,101) # x = [-5,-4.9,-4.8,...,5] with 101 elements
y = sin(x) # operation is broadcasted to all elements of the array
plot(x,y);
#show()
savefig("m02.png")

ou encore

In [93]:
from matplotlib.pylab import *
x = arange(-5,5,0.1) # x = [-5,-4.9,-4.8,...,5] with 101 elements
y = sin(x) # operation is broadcasted to all elements of the array
plot(x,y);
# show()

On obtient une courbe sur laquelle on peut zoomer, modifier les marge et sauvegarder dans différents formats.

Plusieurs courbes sur le même repère

On peut même tracer plusieurs courbes sur la même figure. Par exemple, dans la figure suivante, on a tracé la même fonction: la courbe bleu correspond à la grille la plus grossière, la courbe rouge correspond à la grille la plus fine:

In [94]:
from matplotlib.pylab import *
a = linspace(-5,5,5) 
fa = sin(a) # matplotlib importe numpy qui redefinie les fonctions de base pour pouvoir les appliquer a un vecteur
plot(a,fa,'b-',label="$f(a)$");
b = linspace(-5,5,101) 
fb = sin(b) 
plot(b,fb,'r-.',label="$f(b)$" );
legend();
# savefig("m03.png")

Pour tracer plusieurs courbes sur le même repère, on peut les mettre les unes à la suite des autres en spécifiant la couleur et le type de trait, changer les étiquettes des axes, donner un titre, ajouter une grille, une légende etc.

Par exemple, dans le code ci-dessous "r-" indique que la première courbe est à tracer en rouge (red) avec un trait continu, et "g." que la deuxième est à tracer en vert (green) avec des points.

In [95]:
from matplotlib.pylab import *
x = linspace(-5,5,101) 
y1 = sin(x)            
y2 = cos(x)
plot(x,y1,"r-",x,y2,"g.")
legend(['sinus','cosinus'])
xlabel('abscisses')
ylabel('ordonnees')
title('Comparaison de sin(x) et cos(x)')
grid(True)
# savefig("m04.png")

soit encore

In [96]:
from matplotlib.pylab import *
x = linspace(-5,5,101) 
y1 = sin(x)            
y2 = cos(x)
plot(x,y1,"r-",label=('sinus'))
plot(x,y2,"g.",label=('cosinus'))
legend()
xlabel('abscisses')
ylabel('ordonnees')
title('Comparaison de sin(x) et cos(x)')
grid(True)
# savefig("m05.png")

Quelques options de pylab:

linestyle= color= marker=
- solid line r red . points
-- dashed line g green , pixel
: dotted line b blue o filled circles
-. dash-dot line c cyan v triangle down
(0,(5,1)) densely dashed m magenta ^ triangle up
y yellow > triangle right
w white < triangle left symbols
k black * star
+ plus
s square
p pentagon
x x
X x filled
d thin diamond
D diamond

Voir aussi

Voici un exemple d'utilisation:

In [97]:
from matplotlib.pylab import *
x = linspace(-5,5,101) 
y1 = sin(x)            
y2 = cos(x)          
y3 = sin(x)+cos(x)
plot(x,y1,color='r'         ,ls='-'      ,linewidth=2           ,label=('sinus'))
plot(x,y2,color='tab:purple',ls=' '      ,lw=1       ,marker='.',label=('cosinus'))
plot(x,y3,color='skyblue'   ,ls=(0,(5,1)),lw=1                  ,label=('cos+sin'))
legend();
# savefig("m06.png")

On peut déplacer la légende en spécifiant l'une des valeurs suivantes:

best, upper right, upper left, lower right, lower left, center right, center left, lower center, upper center, center:

In [98]:
from matplotlib.pylab import *
x = arange(-pi,pi,0.05*pi)
plot(x,sin(x),'co',x,cos(x),'mD')
legend(['sinus','cosinus'],loc='upper left')
axis([-pi, pi, -1, 1]); # axis([xmin, xmax, ymin, ymax])
# savefig("m07.png")
In [99]:
from matplotlib.pylab import *

a = linspace(-5,5,5) 
fa = sin(a) 
plot(a,fa,ls='--', lw=3, color="blue", label=r"$f(a)$")
b = linspace(-5,5,10) 
fb = sin(b) 
plot(b,fb,ls='--', lw=2.0, color="orange", label=r"$f(b)$")
c = linspace(-5,5,101) 
fc = sin(c) 
plot(c,fc,ls='-.', lw=0.5, color="green", label=r"$f(c)$")

plot([0], [0.5], lw=0.5, marker='o', color="cyan")
text(0, 0.6,r"$\sigma_i$", horizontalalignment='center', fontsize=20)

xlim(-5, 5)
ylim(-1, 1)
yticks([-1, -0.5, 0, 1])
xticks([-4, -2, 0, 2])

xlabel("$x$", fontsize=18)
ylabel("$y$", fontsize=18)

legend(bbox_to_anchor=(1.04,1),loc='upper left', ncol=1, fontsize=14, frameon=False);
# savefig("m08.png")

Plusieurs "fenêtres" graphiques

On génère deux fenêtres contenant chacune un graphe:

In [100]:
from matplotlib.pylab import *
x = arange(-pi,pi,0.05*pi)
figure(1)
plot(x, sin(x), 'r')
title("sin")
# savefig("m20.png")
figure(2)
plot(x, cos(x), 'g')
title("cos")
# savefig("m21.png")
Out[100]:
Text(0.5, 1.0, 'cos')

Plusieurs repères dans la même fenêtre

La fonction subplot(x,y,z) subdivise la figure sous forme d'une matrice (x,y) et chaque case est numérotée, z étant le numéro de la case où afficher le graphe. La numérotation se fait de gauche à droite, puis de haut en bas, en commençant par $1$.

In [101]:
from matplotlib.pylab import *
x = arange(-pi,pi,0.05*pi)

figure(figsize=(10, 10), facecolor="#f1f1f1")
# axes coordinates as fractions of the canvas width and height
#left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
#axes((left, bottom, width, height), facecolor="#e1e1e1")

subplot(4,3,1)
plot(x, sin(x), 'r')
subplot(4,3,5)
plot(x, cos(x), 'g')
subplot(4,3,9)
plot(x, x*x, 'b')
subplot(4,3,12)
plot(x, exp(-x*x), 'm')
Out[101]:
[<matplotlib.lines.Line2D at 0x7f8f61c50100>]

Personnalisation

Matplotlib est très flexible. Quasiment tous les aspects d'une figure peuvent être configurés par l'utilisateur soit pour y ajouter des données, soit pour améliorer l'aspect esthétique. Plutôt que de vous faire une liste des fonctions qui permettent de faire ces actions, jvoici des exemples.

In [102]:
%matplotlib inline
from matplotlib.pylab import *

xx=linspace(-pi,pi,101)

# Changer la taille de la figure
figure(figsize=(12,8))

# Changer la taille de police par défaut
rcParams.update({'font.size': 15})

# Couleur spécifiée par son nom, ligne solide
plot(xx, sin(xx - 0), color='blue', linestyle='solid', label='bleu')
# Nom court pour la couleur, ligne avec des traits
plot(xx, sin(xx - pi/4), color='g', linestyle='dashed', label='vert')
# Valeur de gris entre 0 et 1, des traits et des points
plot(xx, sin(xx - pi/2), color='0.75', linestyle='dashdot', label='gris')
# Couleur spécifié en RGB, avec des points
plot(xx, sin(xx - 3*pi/4), color='#FF0000', linestyle='dotted', label='rouge')

# Les limites des axes, essayer aussi les arguments 'tight' et 'equal' 
# pour voir leur effet
axis([-pi, pi, -1.5, 1.5]);

# Le titre
title("Un exemple de graphe")

# La légende est générée à partir de l'argument label de la fonction
# plot. L'argument loc spécifie le placement de la légende
legend(loc='lower left');

# Titres des axes
xlabel('x')
ylabel('sin(x)');
In [103]:
%matplotlib inline
from matplotlib.pylab import *

xx=linspace(-pi,pi,101)

stiles_dispo=style.available[:6]
print(stiles_dispo)

# Notez la taille de la figure
figure(figsize=(12,10))
for i in range(len(stiles_dispo)):
    # On peut ajouter des sous graphes ainsi
    subplot(3,2,i+1)
    style.use(stiles_dispo[i])
    plot(xx, cos(xx))    
    # Pour ajouter du texte
    text(s=stiles_dispo[i], x=0, y=1, color='red')
['ggplot', 'grayscale', 'tableau-colorblind10', 'seaborn-dark-palette', 'seaborn-darkgrid', 'bmh']
In [104]:
%matplotlib inline
from matplotlib.pylab import *

# Style
style.use('classic')

# Dimension de la figure
figure(figsize=(5,3))
axes(facecolor='#E6E6E6')

# Cadre en blanc
grid(color='w', linestyle='solid')

# Nous pouvons personnaliser les étiquettes des marqueurs
# et leur appliquer une rotation
marqueurs = [-3, -2, -1, 0, 1, 2, 3]
xtick_labels = ['A', 'B', 'C', 'D', 'E', 'F']
xticks(marqueurs, xtick_labels, rotation=30);

# Chanegr la taille de police par défaut
plt.rcParams.update({'font.size': 25})

# Changer les couleur des barres
x = np.random.randn(1000)
hist(x, edgecolor='#E6E6E6', color='#EE6666');

Animations

Pour afficher une animation on utilisera le module animation de matplotlib. Voici un exemple avec deux méthodes différentes : la première utilise la commande magique %matplotlib inline, la deuxième la commande magique %matplotlib notebook qui permet d'intéragir avec l'animation.

In [1]:
%reset -f
%matplotlib inline

from matplotlib.pylab import *
import matplotlib.animation as animation
from IPython.display import display, clear_output

fig = figure()
axis([0,3,-1,1])
line, = plot([],[],lw=2) 

x = linspace(0,3,100)
animate = lambda i: line.set_data(x, cos(2*pi*(x-0.01*i)))

# CI
plot(x,cos(2*pi*x))

# Marche en temps
for i in range(len(x)):
    animate(i)
    clear_output(wait=True)
    display(fig)
clear_output(wait=True)
In [3]:
%reset -f
%matplotlib notebook
from matplotlib.pylab import *
from matplotlib import animation

x = linspace(0,3,100)

# First set up the figure, the axis, and the plot element we want to animate
fig = figure() # initialise la figure
line, = plot([],[],lw=2) 
axis([0,3,-1,1])

# Define the initialization function, which plots the background of each frame:
# init = lambda : plot([],[]) 
init = lambda : plot(x,cos(2*pi*x))

# Define the animation function, which is called for each new frame:
animate = lambda i: line.set_data(x,cos(2*pi*(x-0.01*i)))

# call the animator. blit=True means only re-draw the parts that have changed. 
ani = animation.FuncAnimation(fig, animate, init_func=init, frames=100, blit=False, interval=20, repeat=False)

# Eventually
# from IPython.display import HTML, Image
# ani.save('animation.gif', writer='imagemagick', fps=60)
# Image(url='animation.gif')

2D

La représentation graphique de l’évolution d’une fonction $f$ de deux variables $x$ et $y$ n'est pas une tâche facile, surtout si le graphique en question est destiné à être imprimé. Dans ce type de cas, un graphe faisant apparaître les lignes de niveaux de la fonction en question peut être une solution intéressante et lisible. Commençons donc par considérer l'exemple simple d'une fonction de la forme: $$ f(x,y)= \frac{\sin(x^2+y^2)}{x^2+y^2} $$

Le tracé de cette fonction en courbes de niveaux va nécessiter la création d’un maillage bidimensionnel permettant de stocker l’intervalle de chacune des variables. La fonction destinée à cela s’appelle meshgrid (incluse dans le module NumPy). On construit donc le maillage en question sur le rectangle $[-5;5]\times[-5;5]$. La fonction meshgrid fait appel dans ce cas à deux fonctions linspace pour chacune des variables. z est ici un objet array qui contient les valeurs de la fonction $f$ sur chaque nœud du maillage.

In [107]:
%matplotlib inline
from matplotlib.pylab import *
In [108]:
xx=linspace(-2*pi,2*pi,101)
yy=linspace(-2*pi,2*pi,101)

X,Y = meshgrid(xx,yy)
Z = X**2+Y**2
In [109]:
from mpl_toolkits import mplot3d
ax = axes(projection='3d')
ax.contour3D(X, Y, Z, 50, cmap='binary')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z');
In [110]:
from mpl_toolkits import mplot3d
ax = axes(projection='3d')
ax.plot_surface(X, Y, Z, rstride=4, cstride=4,cmap='viridis',edgecolor='none', alpha=0.5)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z');
ax.contour(X, Y, Z, zdir='z', offset=0, cmap=cm.coolwarm)
ax.contour(X, Y, Z, zdir='x', offset=-2*pi, cmap=cm.coolwarm)
ax.contour(X, Y, Z, zdir='y', offset=2*pi, cmap=cm.coolwarm)
Out[110]:
<matplotlib.contour.QuadContourSet at 0x7f8f7428a6a0>