Tracer des graphiques dans une interface paramétrable Tkinter

Denis Hulo

Objectif : tracer les graphiques de la loi binomiale et de la loi normale dans une interface Tkinter afin de montrer leur convergence.

Niveau requis : débutant

Commentez cet article : Commentez

- Titre : Tracer des graphiques dans une interface paramétrable Tkinter

- Auteur : Denis Hulo

- Parution : 8 août 2024

- Public visé :

- Licence : Copyright ® 2024 Denis Hulo. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Lois de probabilité

- II-A. Loi binomiale

- II-B. Loi normale

- III. Théorème de Moivre-Laplace

- IV. Implémentation en Python

- IV-A. Fonctions de probabilité

- IV-A-1. Fonction de masse de la loi binomiale

- IV-A-2. Fonction de densité de la loi normale

- IV-B. Représentation graphique : intégration du graphique dans une interface Tkinter

- IV-C. Module Python

- V. Conclusion

- VI. Téléchargement

- VII. Remerciements

I - Introduction

Une loi binomiale peut être utilisée pour modéliser des situations simples de succès ou échec, un jeu de pile ou face par exemple. Le calcul de sa fonction de masse devient rapidement fastidieux lorsque le nombre d'épreuves n est grand, il est alors possible d'utiliser des approximations par d'autres lois de probabilité telle que la loi normale et d'utiliser des tables de valeurs.

Après avoir défini ces lois de probabilité, on va ensuite montrer comment les représenter graphiquement en Python à l'aide de la librairie matplotlib.

Enfin, on va créer une interface paramétrable Tkinter intégrant un graphique afin de montrer la convergence de loi binomiale vers la loi normale conformément au théorème de Moivre-Laplace.

II - Lois de probabilité

II-A - Loi binomiale

D'après Wikipédia, la loi binomiale est une loi de probabilité discrète décrite par deux paramètres : n le nombre d'expériences réalisées, et p la probabilité de succès. Pour chaque expérience appelée épreuve de Bernoulli, on utilise une variable aléatoire qui prend la valeur 1 lors d'un succès et la valeur 0 sinon. La variable aléatoire, somme de toutes ces variables aléatoires, compte le nombre de succès et suit une loi binomiale. Il est alors possible d'obtenir la probabilité de k succès dans une répétition de n expériences :

II-B - Loi normale

La loi normale est une loi de probabilité continue qui dépend de deux paramètres : son espérance, un nombre réel noté μ, et son écart-type, un nombre réel positif noté σ. La densité de probabilité de la loi normale d'espérance μ et d'écart-type σ est donnée par :

Parmi les lois de probabilité, les lois normales prennent une place particulière grâce au théorème central limite. En effet, elles correspondent au comportement, sous certaines conditions, d'une suite d'expériences aléatoires similaires et indépendantes lorsque le nombre d'expériences est très élevé. Grâce à cette propriété, une loi normale permet d'approcher d'autres lois comme la loi binomiale et ainsi de modéliser de nombreuses études scientifiques comme des mesures d'erreurs ou des tests statistiques, en utilisant par exemple les tables de la loi normale centrée réduite.

III - Théorème de Moivre-Laplace

D'après Wikipédia, en théorie des probabilités, selon le théorème de Moivre-Laplace, si la variable Xn suit une loi binomiale d'ordre n et de paramètre p ϵ [0, 1], alors la variable :

converge en loi vers une loi normale centrée et réduite N(0, 1). Cette approximation est bonne en général pour np(1 − p) ≥ 10.

IV - Implémentation en Python

IV-A - Fonctions de probabilité

Les fonctions et les objets décrits par la suite sont issus du module scipy.stats.

IV-A-1 - Fonction de masse de la loi binomiale

L'objet binom représente une variable aléatoire discrète suivant une loi binomiale qui est en fait une instance de la classe rv_discrete avec ses différentes méthodes.

La fonction de masse de la loi binomiale binom.ppf(x, n, p) peut être appelée comme ceci :

x = 10; n = 100; p = 0.5

val = binom.ppf(x, n, p)

Traçons maintenant l'histogramme de la fonction avec la librairie matplotlib :

from scipy.stats import binom
import matplotlib.pyplot as plt
from math import sqrt

# nombre d'épreuves de Bernoulli
n = 80

# probabilité de succès
p = 0.5

# moyenne μ et écart-type σ de la loi binomiale
μ = n*p
σ = sqrt(n*p*(1-p))

# génère la séquence des x : 0 -> n-1
x = range(n)

# nom et dimension de la figure contenant le graphique
plt.figure(num="Figure : Loi binomiale", figsize=(8, 5), dpi=80)

# trace l'histogramme correspondant à la série de valeurs
plt.bar(x, binom.pmf(x,n,p), color="blue")

# limites sur l'axe des x : [μ - 4σ, μ + 4σ]
plt.xlim(μ - 4*σ, μ + 4*σ)

# limite inférieure sur l'axe des y
plt.ylim(0)

plt.title("Histogramme de la loi binomiale B({0}, {1})".format(n,p))

# affiche le graphique
plt.show()

Le code affiche :

Histogramme de la loi binomiale

IV-A-2 - Fonction de densité de la loi normale

L'objet norm représente une variable aléatoire continue suivant une loi normale qui est en fait une instance de la classe rv_continuous avec ses différentes méthodes.

La fonction de densité de la loi normale norm.pdf(x, loc=μ, scale=σ) d'espérance μ et d'écart-type σ peut être invoquée comme ceci :

x = 10; μ = 50; σ = 5

val = norm.pdf(x, loc=μ, scale=σ)

Traçons maintenant la courbe représentative de la fonction :

from scipy.stats import norm
import matplotlib.pyplot as plt
from math import sqrt

# nombre d'épreuves de Bernoulli
n = 80

# probabilité de succès
p = 0.5

# moyenne μ et écart-type σ de la loi normale
μ = n*p
σ = sqrt(n*p*(1-p))

# génère la séquence des x : 0 -> n-1
x = range(n)

# nom et dimension de la figure contenant le graphique
plt.figure(num="Figure : Loi normale", figsize=(8, 5), dpi=80)

# trace la courbe correspondant à la série de valeurs
plt.plot(x, norm.pdf(x,μ,σ), color="red")

# limites sur l'axe des x : [μ - 4σ, μ + 4σ]
plt.xlim(μ - 4*σ, μ + 4*σ)

# limite inférieure sur l'axe des y
plt.ylim(0)

plt.title("Courbe représentative de la loi normale N({0}, {1})".format(round(μ,2),round(σ**2,2)))

# affiche le graphique
plt.show()

Le code affiche :

Courbe de Gauss

IV-B - Représentation graphique : intégration du graphique dans une interface Tkinter

Nous allons maintenant créer une interface paramétrable avec Tkinter sur laquelle nous allons pouvoir choisir le nombre d'expériences n et la probabilité de succès p de la loi binomiale, puis tracer le graphique des deux fonctions.

La classe tkinter.Tk permet de construire un widget Tk de niveau supérieur, qui est généralement la fenêtre principale d'une application, et initialise un interpréteur Tcl pour ce widget. Chaque instance a son propre interpréteur Tcl associé.

Notre interface est ainsi construite à l'aide d'une classe fille InterfaceGraphique qui hérite de la classe mère tkinter.Tk. On peut alors utiliser les attributs et méthodes de cette classe mère :

Héritage

Au moment de créer l'interface Tkinter, c'est-à-dire quand la classe InterfaceGraphique(Tk) est instanciée, on met à jour les zones de texte, puis on trace les graphiques des deux fonctions :

from tkinter import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from math import sqrt

class InterfaceGraphique(Tk):

def __init__(self, n, p, pmf, pdf):

# instantiation de la classe parente
Tk.__init__(self)

# conteneur vertical occupant tout le formulaire et destiné à contenir le widget à canvas
verticalPane = PanedWindow( self, orient=VERTICAL )

# conteneur horizontal placé en haut du formulaire pour les différents contrôles du formulaire
horizontalPane = PanedWindow( verticalPane, orient=HORIZONTAL )

# création des labels et des zones de texte
lblNbreEpreuves = Label( horizontalPane, text = "Nombre d'épreuves (n) :")
self.txtNbreEpreuves= Text(horizontalPane, height = 1, width = 8)

lblProbaSucces = Label( horizontalPane, text = "Proba de succès (p) :")
self.txtProbaSucces= Text(horizontalPane, height = 1, width = 8)

lblMoyenne = Label( horizontalPane, text = "Moyenne (μ) :")
self.txtMoyenne= Text(horizontalPane, height = 1, width = 8, bg="lightgray")

lblEcartType = Label( horizontalPane, text = "Ecart-type (σ) :")
self.txtEcartType = Text(horizontalPane, height = 1, width = 8, bg="lightgray")

# création du bouton de commande pour générer le graphique sur l'interface Tkinter
btnTracer=Button( horizontalPane, text="Tracer", command=self.btnTracerClicked, width = 10)

# ajout des contrôles au conteneur horizontal
horizontalPane.add( lblNbreEpreuves )
horizontalPane.add( self.txtNbreEpreuves )

horizontalPane.add( lblProbaSucces )
horizontalPane.add( self.txtProbaSucces )

horizontalPane.add( lblMoyenne )
horizontalPane.add( self.txtMoyenne )

horizontalPane.add( lblEcartType )
horizontalPane.add( self.txtEcartType )

horizontalPane.add( btnTracer )

# ajout du conteneur horizontal
verticalPane.add( horizontalPane )
verticalPane.pack(expand=True, fill='both')

# ajout de l'objet au conteneur vertical
verticalPane.pack(expand=True, fill='both')

# saisie des valeurs par défaut dans les zones de texte
self.txtNbreEpreuves.insert(END,n)
self.txtProbaSucces.insert(END,p)

# moyenne μ et écart-type σ de la loi binomiale et de la normale
μ = n*p
σ = math.sqrt(n*p*(1-p))

# mise à jour des zones de texte correspondantes
self.txtMoyenne.insert(END,round(μ,2))
self.txtEcartType.insert(END,round(σ,2))

self.pmf = pmf
self.pdf = pdf

# trace le graphique
self.tracer(n, p, μ, σ)

def tracer(self, n, p, μ, σ, new_graph=False):
# méthode permettant de tracer les graphiques sur l'interface

# génère la séquence des x : 0 -> n-1
x = range(n)

# on crée la figure du graphique pour les 2 séries de valeurs
fig = Figure(figsize=(8, 5), dpi=96)
plt = fig.add_subplot(111)

# trace l'histogramme et la courbe correspondant aux 2 séries de valeurs
plt.bar(x, self.pmf(x,n,p), color="blue", label = "B({0}, {1})".format(n,p))
plt.plot(x, self.pdf(x,μ,σ), color="red", label = "N({0}, {1})".format(round(μ,2),round(σ**2,2)))

# limites sur l'axe des x : [μ - 4σ, μ + 4σ]
plt.set_xlim(μ - 4*σ, μ + 4*σ)

# limite inférieure sur l'axe des y
plt.set_ylim(0)

plt.set_title("Représentation graphique de la loi binomiale et de la loi normale")

plt.legend()

if new_graph:
self.graph.get_tk_widget().pack_forget()

self.graph = FigureCanvasTkAgg(fig, master=self)
self.graph.get_tk_widget().pack()

Un bouton de commande btnTracerClicked permet ensuite de tracer le graphique en fonction des choix de paramètres n et p :

class InterfaceGraphique(Tk):

...

def btnTracerClicked(self):
# méthode qui s'exécute quand on clique sur le bouton de commande btnTracer

# copie du contenu des zones de texte dans des variables
n = int(self.txtNbreEpreuves.get("1.0",'end-1c'))
p = float(self.txtProbaSucces.get("1.0",'end-1c'))

# moyenne μ et écart-type σ de la loi binomiale et de la normale
μ = n*p
σ = math.sqrt(n*p*(1-p))

# mise à jour des zones de texte correspondantes
self.txtMoyenne.delete("1.0",'end-1c')
self.txtMoyenne.insert(END,round(μ,2))

self.txtEcartType.delete("1.0",'end-1c')
self.txtEcartType.insert(END,round(σ,2))

# trace le graphique
self.tracer(n,p,μ,σ,True)

Testons maintenant notre interface graphique :

from scipy.stats import binom, norm
from interface_graphique import InterfaceGraphique

# nombre d'épreuves de Bernoulli
n = 80

# probabilité de succès
p = 0.5

# création de l'objet InterfaceGraphique avec les paramètres : n, p, binom.pmf, norm.pdf
InterfaceGraphique = InterfaceGraphique(n, p, binom.pmf, norm.pdf)

# ajout d'un titre à la fenêtre Tkinter
interface_graphique.title("Interface graphique avec Tkinter")

# centre la fenêtre
InterfaceGraphique.eval('tk::PlaceWindow . center')

InterfaceGraphique.mainloop()

Le code affiche :

Interface Tkinter

Le graphique montre bien que la valeur en x de la fonction de densité de la loi normale représente une bonne approximation de la valeur en x de la fonction de masse de la loi binomiale pour n=80 et p=0.5.

IV-C - Module Python

On donne pour finir le code complet du module présent dans le fichier joint dossier_test.zip :

from scipy.stats import binom, norm
from math import sqrt
import matplotlib.pyplot as plt
from interface_graphique import InterfaceGraphique

print("I. Représentation graphique de la loi binomiale..\n")

# nombre d'épreuves de Bernoulli
n = 80

# probabilité de succès
p = 0.5

# moyenne μ et écart-type σ de la loi binomiale et de la normale
μ = n*p
σ = sqrt(n*p*(1-p))

# génère la séquence des x : 0 -> n-1
x = range(n)

# nom et dimension de la figure contenant le graphique
plt.figure(num="Figure : Loi binomiale", figsize=(8, 5), dpi=80)

# trace l'histogramme correspondant à la série de valeurs
plt.bar(x, binom.pmf(x,n,p), color="teal")

# limites sur l'axe des x : [μ - 4σ, μ + 4σ]
plt.xlim(μ - 4*σ, μ + 4*σ)

# limite inférieure sur l'axe des y
plt.ylim(0)

plt.title("Histogramme de la loi binomiale B({0}, {1})".format(n,p))

# affiche le graphique
plt.show()

print("II. Représentation graphique de la loi normale..\n")

# nom et dimension de la figure contenant le graphique
plt.figure(num="Figure : Loi normale", figsize=(8, 5), dpi=80)

# trace la courbe correspondant à la série de valeurs
plt.plot(x, norm.pdf(x,μ,σ), color="red")

# limites sur l'axe des x : [μ - 4σ, μ + 4σ]
plt.xlim(μ - 4*σ, μ + 4*σ)

# limite inférieure sur l'axe des y
plt.ylim(0)

plt.title("Courbe représentative de la loi normale N({0}, {1})".format(round(μ,2),round(σ**2,2)))

# affiche le graphique
plt.show()

print("III. Interface Tkinter : représentation graphique de la loi binomiale et de la loi normale..")

# création de l'objet InterfaceGraphique avec les paramètres : n, p, binom.pmf, norm.pdf
interface_graphique = InterfaceGraphique(n, p, binom.pmf, norm.pdf)

# ajout d'un titre à la fenêtre Tkinter
interface_graphique.title("Interface graphique avec Tkinter")

# centre la fenêtre
interface_graphique.eval('tk::PlaceWindow . center')

interface_graphique.mainloop()

V - Conclusion

Après avoir défini la loi binomiale et la loi normale, on a donc présenté le théorème de Moivre-Laplace comme un cas particulier du théorème central limite.

On a pu ensuite montrer comment représenter graphiquement ces lois à l'aide de la librairie matplotlib, et comment tracer leur graphique dans une interface Tkinter afin de vérifier que la loi binomiale converge bien vers la loi normale quand n augmente.

VI - Téléchargement

Le dossier de test :

- interface_graphique.py : module contenant la classe InterfaceGraphique ;

- representation_graphique.py : module principal.

VII - Remerciements

Je tiens à remercier Malick pour le suivi de cet article, ainsi que f-leb pour sa relecture.

Sources

- https://fr.wikipedia.org/wiki/Loi_binomiale

- https://fr.wikipedia.org/wiki/Loi_normale

- https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_de_Moivre-Laplace

- https://fr.wikipedia.org/wiki/H%C3%A9ritage_(informatique)

- https://docs.scipy.org/doc/scipy/reference/stats.html

- https://matplotlib.org/

- https://docs.python.org/fr/3/library/tkinter.html