8. TP - Matplotlib



8.1. Introduction

Dans ce TP, on s'intéresse à la librairie matplotlib qui permet de réaliser des graphiques et dont la documentation peut être trouvée à cette adresse matplotlib.org.

8.2. Tracé d'une fonction (plot)

On désire tracer une fonction réelle. On utilise pour cela la fonction plot.

On peut également utiliser la fonction savefig afin de sauvegarder un graphique.

8.2.1. Sans numpy

Voici une première version sans numpy pour l'évaluation de la fonction. On utilise la fonction sinus et il est donc nécessaire de faire appel au module math :

  1. # import des libraries / packages
  2. import matplotlib.pyplot as plt
  3. import math
  4.  
  5. # fonction à dessiner
  6. def f(x):
  7.     return x*x-3*x+6*math.sin(x)
  8.  
  9.  
  10. # valeurs pour x, on utilise pas numpy
  11. # On génère 10 valeurs entières de 0 à 9
  12. x_values = range(0, 10)
  13. print(x_values)
  14.  
  15. # on calcule les valeurs de y pour chaque x
  16. y_values = [f(x) for x in x_values]
  17. print(y_values)
  18.  
  19. # on dessine la fonction
  20. plt.plot(x_values, y_values, color='orange')
  21. plt.grid(color='grey', linestyle='-', linewidth=1)
  22. plt.ylabel('f(x)')
  23. plt.savefig('img/plot_function_without_numpy.png')
  24. plt.show()
  25.  
  26.  

On calcule les valeurs pour x (x_values) puis celles de y(y_values) et enfin on dessine la courbe en utilisant ces valeurs.

8.2.2. Avec numpy

Voici une seconde version avec numpy pour l'évaluation de la fonction ce qui permet de simplifier la génération des valeurs à la fois pour x et pour y. On notera l'utilisation de np.sin(x) au lieu de math.sin(x) dans le calcul de la fonction $f$ :

  1. # import des libraries / packages
  2. import matplotlib.pyplot as plt
  3. import math
  4. import numpy as np
  5.  
  6. # fonction à dessiner
  7. def f(x):
  8.     return x * x - 3 * x + 6 * np.sin(x)
  9.  
  10. # valeurs pour x, on utilise numpy
  11. # On génére 100 valeurs etre 0 à 100 (compris)
  12. x_values = np.linspace(0, 10, 100)
  13. print(x_values)
  14.  
  15. # on génère y_values avec la fonction f
  16. y_values = f(x_values)
  17. print(y_values)
  18.  
  19. # on dessine la fonction
  20. plt.plot(x_values, y_values, color='green')
  21. plt.grid()
  22. plt.ylabel('f(x)')
  23. plt.show()
  24.  
  25.  

On remarquera que l'on utilise la fonction linspace de numpy afin de générer des valeurs dans l'intervalle [0,10].

Exercice 8.1

Afficher le graphique de la fonction :

$$ f1(x) = (√|x -3|) × x $$

dans l'intervalle $[-10,10]$ en générant une centaine de valeurs (utiliser numpy).

Exercice 8.2

Afficher sur le même graphique les fonctions :

$$\{\table f1(x) = x; f2(x) = x × \log(x); f3(x) = x × x; $$

dans l'intervalle $[1,10]$ en générant une centaine de valeurs (utiliser numpy)

Afficher chacune des fonctions avec une couleur différence (red, green, blue) et une légende (plt.legend()).

Exercice 8.3

Créez dans le fichier lemniscate.py, le graphique paramètrique suivant pour $t ∈ [0,2π ]$ qui correspond au Lemniscate de Bernoulli (Courbe en forme de huit) :

$$\{\table x(t) = (4 × cos(t)) / (1 +sin^2(t)); y(t) = (8 × cos(t) × sin(t)) / (1 +sin^2(t)); $$

Vous devriez obtenir l'image suivante :

graphique paramétrique lemniscate Bernoulli

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3.  
  4. t = np.linspace(0, 2 * np.pi, 250)
  5. # x =
  6. # y =
  7.  
  8. # Tracer le graphique
  9. plt.figure(figsize=(10, 8))
  10. plt.plot(x, y, label='x(t),y(t)', color='blue')
  11.  
  12. plt.ylim(-10, 10)
  13.  
  14. #....
  15.  
  16. # Afficher le graphique
  17. plt.grid(True, linestyle='--', alpha=0.6)
  18. plt.show()
  19.  

8.3. Données en barres (bar, barh)

Il est parfois nécessaire de modéliser les données sous forme graphique et les graphes qui utilisent des barres permettent de rendre compte d'une donnée numérique associée à une catégorie.

A titre d'exemple, considérons que nous avons interrogé 75 personnes et que nous leur avons demandé quel langage de programmation elles utilisent le plus souvent. Voici les résultats de ce sondage :

8.3.1. Barres verticales (bar)

On peut représenter ces données sous forme de barres verticales ce qui permet tout de suite de voir quel langage est le plus utilisé et quel langage est le moins utilisé, est-ce qu'un langage se démarque des autres, etc. Sur quatre données cela est inutile mais sur des dizaines de données cela est beaucoup plus pratique.

Voici le code correspondant à ce graphique :

  1. import matplotlib.pyplot as plt
  2. from matplotlib import cm
  3. import math
  4. import numpy as np
  5.  
  6. # langages de programmation
  7. y_labels = [ 'C++', 'Ruby', 'Python', 'Php' ]
  8.  
  9. # x_values indique sur l'axe des x où on doit situer
  10. # la barre verticale
  11. x_values = [ 1, 2, 3, 4 ]
  12.  
  13. # y_values représentent les données associées à chaque langage
  14. y_values = [ 20, 10, 30, 15 ]
  15.  
  16. plt.bar(x=x_values, height=y_values, width=0.9,
  17.     color='#7788aa', tick_label = y_labels)
  18. plt.savefig('img/plot_bar_chart.png')
  19. plt.show()
  20.  
  21.  

8.3.2. Barres horizontales (barh)

On peut procéder de la même manière mais avec des barres horizontales.

  1. import matplotlib.pyplot as plt
  2. from matplotlib import cm
  3. import math
  4. import numpy as np
  5.  
  6. # langages de programmation
  7. x_labels = [ 'C++', 'Ruby', 'Python', 'Php' ]
  8.  
  9. x_values = [ 1, 2, 3, 4 ]
  10. y_values = [ 20, 10, 30, 15 ]
  11.  
  12. plt.barh(y=x_values, width=y_values, height=0.9,
  13.     color=['#be7733', '#138ABc', '#89bf76', '#4A987f'],
  14.     tick_label = x_labels, hatch="/",
  15.     edgecolor='#888888')
  16. plt.savefig('img/plot_barh_chart.png')
  17. plt.show()
  18.  
  19.  

8.4. Camembert (pie)

Le camembert ou (pie chart en anglais) permet également, tout comme les graphes de barres, de donner une idée de la répartition des données mais sous forme de pourcentage.

  1. import matplotlib.pyplot as plt
  2. from matplotlib import cm
  3. import math
  4. import numpy as np
  5.  
  6. x_labels = [ 'C++', 'Ruby', 'Python', 'Php' ]
  7. x_values = [ 20, 10, 30, 15 ]
  8. x_explode = (0, 0, 0.1, 0)
  9.  
  10. plt.pie(x_values, labels=x_labels, autopct='%1.1f%%', explode=x_explode)
  11. plt.title("Utilisation des langages de programmation")
  12. plt.savefig('img/plot_pie_chart.png')
  13. plt.show()
  14.  
  15.  

Exercice 8.4
Afficher un graphique sous forme de camembert pour un ensemble de valeurs générées aléatoirement avec une dizaine de valeurs. Faire en sorte que la valeur la plus grande soit détachée du graphique.

8.5. Graphe de points (scatter)

8.5.1. Exemple classique

Dans certains cas, on dispose de données éparses et on désire les afficher afin de savoir si elle sont corrélées.

Voici un premier exemple généré de manière aléatoire en utilisant numpy :

  1. import matplotlib.pyplot as plt
  2. import math
  3. import numpy as np
  4.  
  5. x_values = np.random.uniform(-1.0, 1.0, 50)
  6. y_values = np.random.uniform(-1.0, 1.0, 50)
  7.  
  8. plt.scatter(x_values, y_values)
  9. plt.savefig('img/plot_scatter_random.png')
  10. plt.show()
  11.  
  12.  

Le deuxième exemple utilise une fonction linéaire pour associer les données :

  1. import matplotlib.pyplot as plt
  2. import math
  3. import numpy as np
  4.  
  5. def f(x):
  6.     return 2*x+5
  7.    
  8. x_values = np.random.uniform(-1.0, 1.0, 50)
  9. y_values = f(x_values) + np.random.uniform(-0.2, 0.3, 50)
  10.  
  11. plt.scatter(x_values, y_values)
  12. plt.savefig('img/plot_scatter_correlated.png')
  13. plt.show()
  14.  
  15.  

Exercice 8.5
Afficher un graphique sous forme "scatter plot" pour des valeurs de $x$ dans l'intervalle $[0,10]$ et qui correspondent à une fonction $f(x) = x*x$ pour laquelle on aura introduit de petites variations par rapport à la fonction entre -2 et +2.

Faire en sorte d'afficher la courbe en vert et de modifier le marker en '+'.

8.5.2. Exemple des étudiants de l'université de Malibu

On dispose d'un fichier mu.csv qui contient pour différents étudiants qui sont inscrits en première année à l'université de Malibu en Californie, trois champs : provenance (état), moyenne en mathématiques, moyenne en informatique

arizona,14,13
california,18,17
nevada,8,19
other,6,3
arizona,14,12
arizona,12,13
...

Quatre états sont représentés : Californie, Arizona, Nevada et Other pour les étudiants en provenances d'autres états.

On désire réaliser un graphique représentatif comme celui-ci:

Notes

Exercice 8.6

Etudiez le contenu du fichier malibu.py qui réalise le graphique précédent.

  • on récupère le fichier et on extrait les données suivants trois colonnes : etats, notes_math, notes_info
  • on affiche la moyenne de notes_math et notes_info
  • on remplace les noms des états par des chiffres, par exemple si on prend l'ordre alphabétique :
    • arizona : 0
    • california : 1
    • nevada : 2
    • other : 3

Voici le code du fichier :

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. import matplotlib.colors as col
  4. from matplotlib.colors import ListedColormap
  5. import matplotlib.patches as mpatches
  6.  
  7. # définition de couleurs
  8. colors = ['orangered', 'dodgerblue', 'chartreuse', 'peru' ]
  9. # création d'une colormap : 0 correspond à 'orangered', 1 à 'dodgerblue', etc.
  10. jmr_cmap = ListedColormap(colors)
  11.  
  12.  
  13.  
  14. def lire_fichier(nom_fichier):
  15.     """
  16.    Lit un fichier et retourne ses lignes sous forme de liste.
  17.    
  18.    Args:
  19.        chemin_fichier (str): Le chemin du fichier à lire.
  20.        
  21.    Returns:
  22.        list: Liste contenant les lignes du fichier.
  23.    """
  24.     try:
  25.         with open(nom_fichier, 'r', encoding='utf-8') as fichier:
  26.             lignes = fichier.read()
  27.         return lignes
  28.     except FileNotFoundError:
  29.         print(f"Erreur : Le fichier '{nom_fichier}' n'existe pas.")
  30.         return []
  31.     except Exception as e:
  32.         print(f"Erreur inattendue : {e}")
  33.         return []
  34.  
  35.  
  36. def main():
  37.     # Lecture du fichier
  38.     nom_fichier = "mu.csv"  
  39.     texte = lire_fichier(nom_fichier)
  40.     lignes = texte.split('\n')
  41.     print(lignes)
  42.  
  43.  
  44.     # Créer les vecteurs de données
  45.     notes_math = []
  46.     notes_info = []
  47.     etats = []
  48.  
  49.     for ligne in lignes:
  50.         if len(ligne) != 0:
  51.             colonnes = ligne.split(',')
  52.             notes_math.append(float(colonnes[1]))
  53.             notes_info.append(float(colonnes[2]))
  54.             etats.append(colonnes[0])
  55.                
  56.  
  57.     etats = np.array(etats, dtype=str)
  58.     etats, indices_etats = np.unique(etats, return_inverse=True)
  59.     # ['arizona' 'california' 'nevada' 'other']
  60.     print(f"etats={etats}")
  61.     # [0 1 2 3 1 0 ... 3 3 3 3]
  62.     print(f"indices etats={indices_etats}")
  63.     # [13.0, 17.0, 19, ... 5.0, 4.0, 7.0]
  64.     print(f"notes en informatique={notes_info}")
  65.     # [14.0, 18.0, ... 2.0, 6.0, 8.0]
  66.     print(f"notes en mathématiques={notes_math}")
  67.  
  68.     moyenne_info = np.average(notes_info)
  69.     moyenne_math = np.average(notes_math)
  70.     # 13.53
  71.     print(f"moyenne info={moyenne_info:5.2f}")
  72.     # 12.56
  73.     print(f"moyenne math={moyenne_math:5.2f}")
  74.  
  75.  
  76.     plt.figure(figsize=(10, 8))
  77.  
  78.     # Graphique pour la répartition des notes en informatique
  79.     plt.xlabel(f"notes informatiques, moyenne={moyenne_info:5.2f}")
  80.     plt.ylabel("notes")
  81.     plt.xlim(0,21)
  82.     # retourne les valeurs uniques et leur nombre d'occurrences
  83.     notes_info_echantillon, notes_info_occurrences = np.unique(notes_info, return_counts=True)
  84.     plt.ylim(0,np.max(notes_info_occurrences)+1)
  85.     plt.bar(notes_info_echantillon, notes_info_occurrences, color='skyblue', edgecolor='black')
  86.     plt.show()
  87.  
  88.     # Graphique pour la répartition des notes en mathématiques
  89.     plt.figure(figsize=(10, 8))
  90.     plt.xlabel(f"notes mathématiques, moyenne={moyenne_math:5.2f}")
  91.     plt.ylabel("notes")
  92.     plt.xlim(0,21)
  93.     # retourne les valeurs uniques et leur nombre d'occurrences
  94.     notes_math_echantillon, notes_math_occurrences = np.unique(notes_math, return_counts=True)
  95.     plt.ylim(0,np.max(notes_math_occurrences)+1)
  96.     plt.bar(notes_math_echantillon, notes_math_occurrences, color='lightgreen', edgecolor='black')
  97.     plt.show()
  98.  
  99.     # Graphique avec notes en informatique et notes en mathématiques
  100.     plt.figure(figsize=(10, 8))
  101.     ax = plt.axes()
  102.     ax.set_facecolor("cornsilk")
  103.  
  104.     plt.xlabel("notes math")
  105.     plt.ylabel("notes info")
  106.     plt.xlim(0,22)
  107.     plt.ylim(0,22)
  108.     x=np.arange(1,20)
  109.     y1=x
  110.     y2=20-x
  111.     plt.plot(x, y1, "silver", linestyle='--', alpha=0.6)
  112.     plt.plot(x, y2, "silver", linestyle='--', alpha=0.6)
  113.     # Création de la légende
  114.     plt.scatter(notes_math, notes_info, c=indices_etats, cmap=jmr_cmap, s=50)
  115.     patches = [mpatches.Patch(color=jmr_cmap(i), label=etats[i]) for i in range(len(etats))]
  116.     plt.legend(handles=patches, title="État d'origine")
  117.  
  118.     plt.show()
  119.  
  120.  
  121. if __name__ == "__main__":
  122.     main()
  123.