Le module Matplotlib

Afficher des points

Les représentations graphiques sont très importantes en science, à la fois pour la compréhension et l’interprétation d’un problème. Pour cela nous allons utiliser le module Matplotlib.

La fonction plot() du module pyplot de Matplotlib permet d’afficher des points sur un graphique à 2 dimensions. Pour cela il faut donner comme argument à la fonction plot(): - argument 1 : liste des abscisses des points à afficher (x) - argument 2 : liste des ordonnées des points à afficher (y)

[1]:
# Importation du module pyplot de Matplotlib, renommé plt
import matplotlib.pyplot as plt

# listes des coordonnées des points à afficher
x = [2, -9, -5, 6, 1] # abscisses
y = [6, -3, 6, 0, -6] # ordonnées

# Graphique
plt.plot(x, y)
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_2_0.png

Par défaut, la fonction plot() relie chaque point par une droite. Cependant, il est possible d’afficher seulement les points avec:

[2]:
plt.plot(x, y, 'o')
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_4_0.png

Exercice

Dessiner un losange grâce à la fonction plot(). Pour cela, il faut déterminer les coordonnées des coins du losange.

[3]:
# Dessiner un losange
x = [-1, 0, 1, 0, -1]
y = [0, -1, 0, 1,  0]
plt.plot(x, y)
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_6_0.png

Représentation graphique d’une fonction mathématique

Pour une fonction réelle d’une variable réelle \(f:\mathbb{R}\rightarrow\mathbb{R}\), l’ensemble des points de coordonnées \((x,f(x))\) définit le graphe de la fonction \(f\). Ce graphe est contenu dans le plan \(\mathbb{R}^2\) et se présente sous la forme d’une courbe appelée courbe représentative. Nous allons tracer cette courbe représentative à l’aide de Matplotlib.

Cependant la courbe représentative contient une infinité de points (courbe continue), alors que Matplotlib nous permet seulement d’afficher un nombre fini de point. Il faut alors discrétiser cette courbe, c’est-à-dire choisir un nombre fini de points pour la représenter. Voici un exemple avec la fonction sinus:

[4]:
# Importation du module Numpy
import numpy as np

# Choix de l'intervalle de représentation
intervalle_min = 0
intervalle_max = 10 * np.pi

# Choix du pas de discrétisation
pas = 0.1

# Calcul du nombre de points
intervalle = intervalle_max - intervalle_min
num_points = int(intervalle / pas) + 1

# Création du tableau contenant les abscisses des points
x = np.linspace(intervalle_min, intervalle_max, num_points)

# Création du tableau contenant l'image du tableau x par la fonction sinus
y = np.sin(x)

# Courbe représentative
plt.plot(x, y)
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_8_0.png

Comme on a choisi un pas petit devant la période de la fonction sinus, on a l’illusion d’avoir tracé une courbe continue. Cependant, ce n’est qu’un nombre fini de points reliés par des droites. On peut s’en persuader en traçant les points sans les relier:

[5]:
plt.plot(x, y, '.')
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_10_0.png

Ainsi, si le pas de discrétisation n’est pas adapté, la représentation de la courbe sera mauvaise. Par exemple, un pas de 1.2 ne permet par de bien représenter la fonction sinus:

[6]:
# Choix du pas de discrétisation
pas = 1.2

# Calcul du nombre de points
intervalle = intervalle_max - intervalle_min
num_points = int(intervalle / pas) + 1

# Création du tableau contenant les abscisses des points
x = np.linspace(intervalle_min, intervalle_max, num_points)

# Création du tableau contenant l'image du tableau x par la fonction sinus
y = np.sin(x)

# Courbe représentative
plt.plot(x, y, '-o')
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_12_0.png

Exercice

Représenter graphiquement la fonction tangente hyperbolique en choisissant un intervalle et un pas de discrétisation appropriés. La fonction se nomme tanh() dans le module Numpy.

[7]:
# Choix de l'intervalle de représentation
intervalle_min = -5
intervalle_max = 5

# Choix du pas de discrétisation
pas = 0.1

# Calcul du nombre de points
intervalle = intervalle_max - intervalle_min
num_points = int(intervalle / pas) + 1

# Création du tableau contenant les abscisses des points
x = np.linspace(intervalle_min, intervalle_max, num_points)

# Création du tableau contenant l'image du tableau x par la fonction tanh
y = np.tanh(x)

# Courbe représentative
plt.plot(x, y)
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_14_0.png

Représentation de données

Il est bien sûr possible de représenter graphiquement des données. Généralement les données sont écrites dans un fichier ou sous la forme d’un tableau. Par exemple, prenons l’évolution de la population mondiale telle que donnée sur la page Wikipédia sous forme d’un tableau:

Année Population
1950 2536431
1955 2773020
1960 3034950
1965 3339584
1970 3700437
1975 4079480
1980 4458003
1985 4870922
1990 5327231
1995 5744213
2000 6143494
2005 6541907
2010 6956824
2015 7379797
2020 7794799

Nous avons vu que Matplotlib est compatible avec les tableaux Numpy. Créons les tableaux suivant:

  • en abscisse: l’année, avec le type datetime64
  • en ordonnée: la population, avec le type int64
[8]:
# Création des tableaux
x = np.arange('1950', '2021', step='5', dtype='datetime64[Y]')
y = np.array([2536431, 2773020, 3034950, 3339584, 3700437, 4079480,
              4458003, 4870922, 5327231, 5744213, 6143494, 6541907,
              6956824, 7379797, 7794799], dtype='int64')

# Représentation des données
plt.plot(x, y, 'o')
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_17_0.png

Cependant, il est d’usage d’ajouter des informations au graphe afin qu’une personne puisse correctement interpréter la signification des différentes données. Voici les commandes usuelles utilisées pour rendre un graphe plus lisible:

fonction description
title() titre du graphique
xlabel() titre de l’axe des abscisses
ylabel() titre de l’axe des ordonnées
grid() affichage d’une grille de coordonnées
xlim(xmin,xmax) limites de l’axe des abscisses
ylim(ymin,ymax) limites de l’axe des ordonnées

Exercice

Reprendre le graphe précédent et utiliser les commandes ci-dessus pour:

  • mettre un titre au graphe,
  • aux axes des abscisses et des ordonnées,
  • choisir l’intervalle pour l’abscisse entre 1950 et 2030,
  • pour l’ordonnée entre 0 et 10 milliards,
  • afficher une grille de coordonnées,
  • de plus, on affichera la population en milliards.

Note: pour créer un objet ``datetime64`` il faut écrire ``np.datetime64(‘1950’,’Y’)``

[9]:
plt.plot(x, y/1e6, 'o')
plt.title('Evolution de la population mondiale')
plt.xlabel('Année')
plt.ylabel('Population (milliard)')
plt.xlim(np.datetime64('1950','Y'), np.datetime64('2030','Y'))
plt.ylim(0,10)
plt.grid()
../../_images/notebooks_01-python-base_06-module-matplotlib_20_0.png

Afficher plusieurs courbes

Il est très simple d’afficher plusieurs courbes sur le même graphe: il suffit d’appeler successivement la commande plot(), ou bien de mettre les tableaux à la suite dans la même fonction plot().

Prenons par exemple l’évolution de la population mondiale selon les calculs de l’Organisation des Nations unies (ONU) jusqu’à 2100. L’ONU définit 3 scénarios possibles, dont les chiffres sont donnés dans le tableau suivant:

Année Variante basse Variante moyenne Variante haute
2020 7 794 779 7 794 799 7 794 799
2030 8 363 453 8 548 487 8 733 522
2040 8 716 310 9 198 847 9 682 332
2050 8 906 797 9 735 034 10 587 774
2060 8 882 880 10 151 470 11 529 222
2070 8 675 770 10 459 240 12 495 987
2080 8 331 397 10 673 904 13 478 079
2090 7 869 840 10 809 892 14 515 851
2100 7 322 116 10 875 394 15 600 369

Reprenons la courbe de l’évolution de la population entre 1950 et 2020, et ajoutons les différentes projections faites par l’ONU:

[10]:
# tableau des abscisses pour les projections
xp = np.arange('2020', '2101', step='10', dtype='datetime64[Y]')

# tableau des différentes projections
proj1 = np.array([7794779, 8363453, 8716310, 8906797, 8882880, 8675770, 8331397, 7869840, 7322116])
proj2 = np.array([7794799, 8548487, 9198847, 9735034, 10151470, 10459240, 10673904, 10809892, 10875394])
proj3 = np.array([7794799, 8733522, 9682332, 10587774, 11529222, 12495987, 13478079, 14515851, 15600369])

# tracé des différentes courbes
plt.plot(x, y / 1e6, label='entre 1950 et 2020')
plt.plot(xp, proj1 / 1e6, label='variante basse')
plt.plot(xp, proj2 / 1e6, label='variante moyenne')
plt.plot(xp, proj3 / 1e6, label='variante haute')

# titres et autres
plt.title('Evolution de la population mondiale')
plt.xlabel('Année')
plt.ylabel('Population (milliard)')
plt.xlim(np.datetime64('1950','Y'), np.datetime64('2100','Y'))
plt.ylim(0,16)
plt.grid()
plt.legend()
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_22_0.png

On a utilisé l’option label de la fonction plot() pour nommer chaque courbe, puis la fonction legend() afin d’afficher la légende. De manière alternative et plus compacte, on aurait pu écrire:

[11]:
# tracé des différentes courbes
plt.plot(x, y / 1e6, xp, proj1 / 1e6, xp, proj2 / 1e6, xp, proj3 / 1e6)

# titres et autres
plt.title('Evolution de la population mondiale')
plt.xlabel('Année')
plt.ylabel('Population (milliard)')
plt.xlim(np.datetime64('1950','Y'), np.datetime64('2100','Y'))
plt.ylim(0,16)
plt.grid()
plt.legend(['entre 1950 et 2020', 'variante basse', 'variante moyenne', 'variante haute'])
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_24_0.png

Une question de style

Plusieurs options de la fonction plot() sont utiles pour contrôler le style de la courbe représentée. Voici quelques options parmi les plus utilisées:

option description valeurs
color couleur de la courbe ‘b’, ‘g’, ‘r’, ‘c’, ‘m’, ‘y’, ‘k’, ‘w’
linewidth épaisseur du trait réel
linestyle style du trait ‘-’, ‘–’, ‘-.’, ‘:’
marker style des points ‘+’, ‘*’, ‘,’, ‘.’, ‘1’, ‘2’, ‘3’, ‘4’, ‘<’, ‘>’

Reprenons la courbe précédente et traçons une courbe plus lisible et plus adaptée pour l’impression en noir et blanc:

[12]:
# tracé des différentes courbes
plt.plot(x, y / 1e6, label='entre 1950 et 2020',   color='k', linestyle='-',  linewidth=3)
plt.plot(xp, proj1 / 1e6, label='variante basse',  color='k', linestyle='--', linewidth=3)
plt.plot(xp, proj2 / 1e6, label='variante moyenne',color='k', linestyle='-.', linewidth=3)
plt.plot(xp, proj3 / 1e6, label='variante haute',  color='k', linestyle=':',  linewidth=3)

# titres et autres
plt.title('Evolution de la population mondiale')
plt.xlabel('Année')
plt.ylabel('Population (milliard)')
plt.xlim(np.datetime64('1950','Y'), np.datetime64('2100','Y'))
plt.ylim(0,16)
plt.grid()
plt.legend()
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_27_0.png

Exercice

On donne une estimation de la population entre 1700 et 1950:

Année population (milliards)
1700 0,640
1750 0,655
1800 0,950
1850 1,270
1900 1,650
1910 1,750
1920 1,860
1930 2,07
1940 2,3
1950 2,5

En reprenant les tableaux définis précédemment et en créant de nouveaux tableaux, tracer la population estimée entre 1700 et 1950, et la population récente entre 1950 et 2020, sur le même graphe. Mettre des titres et une légende.

[13]:
# tableau des dates pour l'estimation
test1 = np.arange('1700', '1900', step='50', dtype='datetime64[Y]')
test2 = np.arange('1900', '1951', step='10', dtype='datetime64[Y]')
test = np.append(test1, test2)

# population estimée
popest = np.array([0.64, 0.655, 0.95, 1.27, 1.65, 1.75, 1.86, 2.07, 2.3, 2.5])

# tracé des différentes courbes
plt.plot(test, popest, label='estimations', color='k', linestyle='--',  linewidth=3)
plt.plot(x, y / 1e6, label='passé récent',   color='k', linestyle='-',   linewidth=3)

# titres et autres
plt.title('Evolution de la population mondiale')
plt.xlabel('Année')
plt.ylabel('Population (milliard)')
plt.xlim(np.datetime64('1700','Y'), np.datetime64('2020','Y'))
plt.ylim(0,8)
plt.grid()
plt.legend()
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_29_0.png

Echelle logarithmique

Il arrive souvent que des quantités varient sur plusieurs ordres de grandeurs. Il peut être pratique alors de tracer le graphe en échelle logarithmique. Voici les différentes fonctions qui permettent de tracer en échelle logarithmique:

fonction description
loglog() échelle log pour les deux axes
semilogx() échelle log pour l’axe des abscisses
semilogy() échelle log pour l’axe des ordonnées

Prenons par exemple l’évolution estimée de la population depuis l’année -100 000 jusqu’à 1950:

Année population (millions)
-100 000 0,5
-10 000 5
-6 500 8
-5 000 12
400 200
1000 300
1250 410
1500 485
1700 640
1750 655
1800 950
1850 1 270
1900 1 650
1910 1 750
1920 1 860
1930 2 070
1940 2 300
1950 2 500

Le type datetime64 ne peut pas être utilisé pour représenter des dates trop anciennes. Nous allons alors utiliser le type integer pour les tableaux de dates:

[14]:
# tableau des dates pour l'estimation
test1 = np.array([-100000, -10000, -6500, -5000, 400,
                  1000, 1250, 1500], dtype='int64')
test2 = np.arange(1700, 1900, step=50, dtype='int64')
test3 = np.arange(1900, 1951, step=10, dtype='int64')
test = np.concatenate((test1, test2, test3))

# population estimée
popest = np.array([5e-1, 5, 8, 12, 200, 300, 410, 485,
                   640, 655, 950, 1270, 1650, 1750, 1860, 2070, 2300, 2500])

# tracé des estimations
plt.semilogy(test, popest, label='estimations', color='k', linestyle='--',  linewidth=3)

# tracé du passé récent
xint = x.astype(int) + 1970 # conversion de datetime64 vers integer
plt.semilogy(xint, y / 1e3, label='passé récent',   color='k', linestyle='-',   linewidth=3)

# titres et autres
plt.title('Evolution de la population mondiale')
plt.xlabel('Année')
plt.ylabel('Population (millions)')
# plt.xlim(-1e5,2020)
#plt.ylim(1e-4,10)
plt.grid()
plt.legend()
plt.show()
../../_images/notebooks_01-python-base_06-module-matplotlib_31_0.png