Skip to content
Thèmes
Matplotlib
Matplotlib Histogram: The Complete Guide to plt.hist() in Python

Histogramme Matplotlib : Le guide complet de plt.hist() en Python

Updated on

Vous avez un jeu de donnees avec des milliers de valeurs numeriques -- ages, notes d'examens, temps de reponse, lectures de capteurs -- et vous devez comprendre comment ces valeurs sont distribuees. Sont-elles regroupees autour d'un point central ? Biaisees vers une extremite ? Suivent-elles une distribution normale ? Un nuage de points ne vous aidera pas. Un diagramme en barres est concu pour les categories, pas pour les donnees continues. Ce dont vous avez besoin est un histogramme, et en Python, matplotlib.pyplot.hist() est la methode standard pour en construire un.

Le probleme est que plt.hist() possede plus d'une douzaine de parametres, et la sortie par defaut est souvent simple ou trompeuse. Choisir le mauvais nombre de bins peut masquer des motifs importants dans vos donnees. Comparer plusieurs distributions sur un seul graphique necessite de connaitre la bonne combinaison d'options. Ce guide couvre chaque parametre important, avec des exemples de code fonctionnels que vous pouvez copier directement dans votre notebook ou script.

📚

Qu'est-ce qu'un histogramme et quand devriez-vous en utiliser un ?

Un histogramme divise une plage de valeurs numeriques en intervalles de largeur egale appeles bins et compte combien de points de donnees tombent dans chaque bin. L'axe x montre la plage de valeurs, et l'axe y montre la frequence (nombre) ou la densite pour chaque bin. Contrairement a un diagramme en barres, qui affiche des donnees categorielles, un histogramme represente la distribution de donnees numeriques continues.

Utilisez un histogramme quand vous devez :

  • Voir la forme d'une distribution (normale, biaisee, bimodale, uniforme)
  • Identifier les valeurs aberrantes ou les lacunes dans les donnees
  • Comparer la dispersion des valeurs entre les groupes
  • Decider des transformations de donnees avant la modelisation

Syntaxe de base de plt.hist()

L'histogramme le plus simple ne necessite qu'un seul argument : le tableau de donnees.

import matplotlib.pyplot as plt
import numpy as np
 
# Generate 1000 normally distributed values
np.random.seed(42)
data = np.random.normal(loc=50, scale=15, size=1000)
 
plt.hist(data)
plt.title('Basic Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

Par defaut, matplotlib divise les donnees en 10 bins. La fonction retourne trois objets : les comptages de bins, les bords de bins et les objets patch (les rectangles dessines). Nous couvrirons ces valeurs de retour en detail plus tard.

Signature complete

plt.hist(x, bins=None, range=None, density=False, weights=None,
         cumulative=False, bottom=None, histtype='bar', align='mid',
         orientation='vertical', rwidth=None, log=False, color=None,
         label=None, stacked=False, edgecolor=None, alpha=None)

Controle des bins

Le parametre bins est le reglage le plus important dans un histogramme. Trop peu de bins masquent les motifs. Trop de bins creent du bruit.

Definir un nombre fixe de bins

fig, axes = plt.subplots(1, 3, figsize=(14, 4))
 
axes[0].hist(data, bins=5, edgecolor='black')
axes[0].set_title('5 Bins')
 
axes[1].hist(data, bins=30, edgecolor='black')
axes[1].set_title('30 Bins')
 
axes[2].hist(data, bins=100, edgecolor='black')
axes[2].set_title('100 Bins')
 
plt.tight_layout()
plt.show()

Avec 5 bins, vous ne voyez qu'une forme approximative. Avec 100 bins, les petites tailles d'echantillon par bin introduisent du bruit visuel. Pour ce jeu de donnees de 1 000 points, 30 bins produit une image claire de la distribution normale.

Bords de bins personnalises

Passez une sequence a bins pour definir des limites exactes :

custom_edges = [0, 20, 35, 50, 65, 80, 100]
plt.hist(data, bins=custom_edges, edgecolor='black', color='steelblue')
plt.title('Histogram with Custom Bin Edges')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

C'est utile lorsque vos donnees ont des seuils significatifs -- notes par lettres, tranches d'age ou niveaux de performance.

Algorithmes automatiques de bins

Matplotlib prend en charge plusieurs algorithmes qui calculent le nombre optimal de bins en fonction des caracteristiques des donnees :

AlgorithmeValeur de bins=MethodeIdeal pour
Sturges'sturges'1 + log2(n)Petits jeux de donnees approximativement normaux
Scott'scott'Base sur l'ecart-type et nDonnees normales ou quasi normales
Freedman-Diaconis'fd'Base sur l'IQR et nRobuste aux valeurs aberrantes
Racine carree'sqrt'sqrt(n)Estimation rapide approximative
Auto'auto'Maximum de Sturges et FDUsage general par defaut
fig, axes = plt.subplots(1, 3, figsize=(14, 4))
 
for ax, method in zip(axes, ['sturges', 'scott', 'fd']):
    ax.hist(data, bins=method, edgecolor='black', color='#4C72B0')
    ax.set_title(f'bins="{method}"')
 
plt.tight_layout()
plt.show()

Pour la plupart des cas, bins='auto' est un bon point de depart. Passez a 'fd' lorsque vos donnees contiennent des valeurs aberrantes, car il utilise l'ecart interquartile au lieu de l'ecart-type.

Histogrammes normalises et de densite

Par defaut, l'axe y montre les comptages bruts. Definissez density=True pour normaliser l'histogramme afin que l'aire totale sous les barres soit egale a 1. Cela convertit l'axe y de la frequence a la densite de probabilite.

fig, axes = plt.subplots(1, 2, figsize=(12, 4))
 
axes[0].hist(data, bins=30, edgecolor='black', color='#55A868')
axes[0].set_title('Frequency (default)')
axes[0].set_ylabel('Count')
 
axes[1].hist(data, bins=30, edgecolor='black', color='#C44E52', density=True)
axes[1].set_title('Density (density=True)')
axes[1].set_ylabel('Probability Density')
 
plt.tight_layout()
plt.show()

La normalisation par densite est essentielle lorsque vous souhaitez superposer une courbe de distribution theorique ou comparer des jeux de donnees de tailles differentes :

from scipy import stats
 
plt.hist(data, bins=30, density=True, edgecolor='black', color='#55A868', alpha=0.7)
 
# Overlay the theoretical normal curve
x_range = np.linspace(data.min(), data.max(), 200)
plt.plot(x_range, stats.norm.pdf(x_range, loc=50, scale=15), 'r-', linewidth=2, label='Normal PDF')
plt.legend()
plt.title('Density Histogram with Normal Curve Overlay')
plt.show()

Personnaliser l'apparence

Couleur, couleur de bordure et transparence

plt.hist(data, bins=30, color='#4C72B0', edgecolor='white', alpha=0.85)
plt.title('Styled Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

Types d'histogrammes

Le parametre histtype change le style visuel :

Valeur de histtypeDescription
'bar'Barres remplies traditionnelles (par defaut)
'barstacked'Barres empilees pour plusieurs jeux de donnees
'step'Contour de ligne non rempli
'stepfilled'Zone remplie avec contour en escalier
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
types = ['bar', 'barstacked', 'step', 'stepfilled']
 
for ax, ht in zip(axes.flat, types):
    ax.hist(data, bins=30, histtype=ht, edgecolor='black', color='#4C72B0')
    ax.set_title(f'histtype="{ht}"')
 
plt.tight_layout()
plt.show()

Le type 'step' est particulierement utile lors de la superposition de plusieurs distributions, car les contours non remplis ne se masquent pas mutuellement.

Plusieurs histogrammes sur un seul graphique

Histogrammes superposes

Utilisez alpha (transparence) pour superposer deux ou plusieurs distributions :

np.random.seed(42)
group_a = np.random.normal(loc=50, scale=10, size=800)
group_b = np.random.normal(loc=65, scale=12, size=800)
 
plt.hist(group_a, bins=30, alpha=0.6, color='#4C72B0', edgecolor='black', label='Group A')
plt.hist(group_b, bins=30, alpha=0.6, color='#C44E52', edgecolor='black', label='Group B')
plt.legend()
plt.title('Overlapping Histograms')
plt.xlabel('Score')
plt.ylabel('Frequency')
plt.show()

Histogrammes cote a cote

Passez une liste de tableaux pour les tracer avec des barres groupees :

plt.hist([group_a, group_b], bins=20, color=['#4C72B0', '#C44E52'],
         edgecolor='black', label=['Group A', 'Group B'])
plt.legend()
plt.title('Side-by-Side Histograms')
plt.xlabel('Score')
plt.ylabel('Frequency')
plt.show()

Lorsque vous passez une liste de tableaux, matplotlib place les barres de chaque jeu de donnees les unes a cote des autres au sein de chaque bin.

Histogrammes empiles

Definissez stacked=True pour empiler un jeu de donnees sur un autre. Cela montre a la fois les distributions individuelles et leur total combine.

np.random.seed(42)
freshmen = np.random.normal(loc=68, scale=8, size=500)
sophomores = np.random.normal(loc=72, scale=7, size=400)
juniors = np.random.normal(loc=75, scale=6, size=300)
 
plt.hist([freshmen, sophomores, juniors], bins=25, stacked=True,
         color=['#4C72B0', '#55A868', '#C44E52'], edgecolor='black',
         label=['Freshmen', 'Sophomores', 'Juniors'])
plt.legend()
plt.title('Stacked Histogram: Exam Scores by Class Year')
plt.xlabel('Score')
plt.ylabel('Frequency')
plt.show()

Les histogrammes empiles fonctionnent bien lorsque vous souhaitez montrer comment les sous-groupes contribuent a une distribution globale. Cependant, ils deviennent difficiles a lire avec plus de trois ou quatre groupes.

Histogrammes cumulatifs

Definissez cumulative=True pour montrer comment les valeurs s'accumulent de gauche a droite. La derniere barre atteint le nombre total (ou 1,0 si density=True).

fig, axes = plt.subplots(1, 2, figsize=(12, 4))
 
axes[0].hist(data, bins=30, cumulative=True, edgecolor='black', color='#DD8452')
axes[0].set_title('Cumulative Histogram (Count)')
axes[0].set_ylabel('Cumulative Count')
 
axes[1].hist(data, bins=30, cumulative=True, density=True, edgecolor='black', color='#8172B3')
axes[1].set_title('Cumulative Histogram (Density)')
axes[1].set_ylabel('Cumulative Probability')
 
plt.tight_layout()
plt.show()

Les histogrammes cumulatifs sont utiles pour repondre a des questions comme "Quel pourcentage de valeurs tombe en dessous de 60 ?" en lisant directement sur l'axe y.

Histogrammes horizontaux

Definissez orientation='horizontal' pour inverser les axes. C'est utile lorsque les etiquettes de valeurs sont longues ou lorsque vous souhaitez placer l'histogramme a cote d'un autre graphique vertical.

plt.hist(data, bins=30, orientation='horizontal', color='#64B5CD', edgecolor='black')
plt.title('Horizontal Histogram')
plt.xlabel('Frequency')
plt.ylabel('Value')
plt.show()

Valeurs de retour de plt.hist()

plt.hist() retourne trois valeurs qui vous donnent un acces programmatique aux donnees de l'histogramme :

n, bin_edges, patches = plt.hist(data, bins=20, edgecolor='black', color='#4C72B0')
plt.show()
 
print(f"Bin counts (n): shape = {n.shape}, first 5 = {n[:5]}")
print(f"Bin edges: shape = {bin_edges.shape}, first 5 = {bin_edges[:5]}")
print(f"Patches: {len(patches)} Rectangle objects")
Valeur de retourTypeDescription
nndarrayNombre (ou densite) pour chaque bin
bin_edgesndarrayValeurs des bords pour chaque bin (longueur = len(n) + 1)
patchesliste de RectanglesLes objets patch matplotlib pour chaque barre

Vous pouvez utiliser patches pour colorer des barres individuelles en fonction de leur hauteur ou position :

n, bin_edges, patches = plt.hist(data, bins=30, edgecolor='black')
 
# Color bars based on height
for count, patch in zip(n, patches):
    if count > 50:
        patch.set_facecolor('#C44E52')
    else:
        patch.set_facecolor('#4C72B0')
 
plt.title('Conditional Bar Coloring')
plt.show()

Reference des parametres courants de plt.hist()

ParametreTypeDescriptionDefaut
xarray-likeDonnees d'entreeRequis
binsint, sequence ou strNombre de bins, bords de bins ou nom d'algorithme10
rangetuplePlage inferieure et superieure des bins(x.min(), x.max())
densityboolNormaliser pour que l'aire soit egale a 1False
weightsarray-likePoids pour chaque point de donneesNone
cumulativeboolCalculer l'histogramme cumulatifFalse
histtypestr'bar', 'barstacked', 'step', 'stepfilled''bar'
orientationstr'vertical' ou 'horizontal''vertical'
colorcolor ou listeCouleur(s) des barresNone
edgecolorcolorCouleur du bord des barresNone
alphafloatTransparence (0 a 1)None
labelstrEtiquette pour la legendeNone
stackedboolEmpiler plusieurs jeux de donneesFalse
logboolAxe y logarithmiqueFalse
rwidthfloatLargeur relative des barres (0 a 1)None
bottomarray-like ou scalaireLigne de base pour chaque barre0

plt.hist() vs sns.histplot() : Quand utiliser lequel

Si vous utilisez seaborn aux cotes de matplotlib, vous vous demandez peut-etre quelle fonction d'histogramme utiliser. Voici une comparaison directe :

Caracteristiqueplt.hist()sns.histplot()
Bibliothequematplotlibseaborn
Types d'entreeArray, liste, SeriesArray, Series, colonne DataFrame
Superposition KDEManuelle (scipy necessaire)Integree (kde=True)
Style par defautMinimalPret pour publication
Groupes multiplesPasser une liste de tableauxParametre hue
Options statistiquesNombre, densiteNombre, densite, frequence, probabilite, pourcentage
Algorithmes de binssturges, scott, fd, sqrt, autoauto, fd, doane, scott, stone, rice, sturges, sqrt
Echelle logarithmiquelog=Truelog_scale=True
Axe categorielNon supporteSupporte via hue
Performance (grandes donnees)Plus rapideLegerement plus lent
Profondeur de personnalisationAPI complete matplotlibAPI seaborn + matplotlib

Utilisez plt.hist() lorsque vous avez besoin d'un controle total sur chaque element visuel, lorsque vous travaillez avec des sous-graphiques, ou lorsque seaborn n'est pas disponible. Utilisez sns.histplot() lorsque vous souhaitez des superpositions KDE, un style par defaut plus propre, ou lorsque vous devez diviser les donnees par une variable categorielle avec un code minimal.

Creez des histogrammes interactifs avec PyGWalker

Les histogrammes statiques sont excellents pour les rapports et les scripts, mais lors de l'analyse exploratoire des donnees, vous devez souvent changer les bins, filtrer les sous-ensembles et basculer rapidement entre les types de graphiques. PyGWalker (opens in a new tab) est une bibliotheque Python open source qui transforme n'importe quel DataFrame pandas ou polars en une interface de visualisation interactive par glisser-deposer directement dans Jupyter Notebook -- sans code frontend necessaire.

pip install pygwalker
import pandas as pd
import pygwalker as pyg
 
# Load your dataset into a DataFrame
df = pd.DataFrame({
    'score': np.random.normal(70, 12, 2000),
    'group': np.random.choice(['A', 'B', 'C'], 2000)
})
 
# Launch the interactive UI
walker = pyg.walk(df)

Une fois l'interface ouverte, faites glisser score sur l'axe x et PyGWalker genere automatiquement un histogramme. Vous pouvez ajuster la taille des bins, diviser par group en utilisant l'encodage couleur, passer en mode densite et exporter le graphique resultant -- le tout sans ecrire de code supplementaire. C'est particulierement utile lorsque vous devez explorer rapidement plusieurs variables avant d'ecrire le code matplotlib final pour un rapport.

Foire aux questions

Comment choisir le bon nombre de bins pour un histogramme matplotlib ?

Commencez avec bins='auto', qui utilise le maximum des methodes Sturges et Freedman-Diaconis. Pour les donnees avec des valeurs aberrantes, utilisez bins='fd'. Pour les petits jeux de donnees (moins de 200 points), bins='sturges' fonctionne bien. Vous pouvez aussi passer un entier et ajuster a l'oeil : augmentez le nombre si la distribution semble trop lisse, diminuez-le si les barres semblent bruitees.

Quelle est la difference entre density=True et cumulative=True dans plt.hist() ?

density=True normalise l'histogramme pour que l'aire totale sous toutes les barres soit egale a 1, convertissant l'axe y en densite de probabilite. cumulative=True fait que chaque barre represente la somme de toutes les barres precedentes plus elle-meme. Vous pouvez combiner les deux : density=True, cumulative=True produit une fonction de distribution cumulative ou la derniere barre atteint 1,0.

Comment superposer deux histogrammes dans matplotlib ?

Appelez plt.hist() deux fois avec la meme valeur de bins et definissez alpha a une valeur inferieure a 1 (par exemple, 0,5 ou 0,6) pour que les deux distributions restent visibles. Ajoutez label a chaque appel et terminez avec plt.legend(). Utiliser histtype='step' comme alternative evite completement le besoin de transparence puisqu'il ne dessine que des contours.

plt.hist() peut-il gerer directement les pandas Series et les colonnes DataFrame ?

Oui. plt.hist() accepte toute entree de type array, y compris les pandas Series. Vous pouvez passer df['column_name'] directement. Pour tracer a partir d'un DataFrame en utilisant la methode integree de pandas, utilisez df['column_name'].plot.hist(bins=30), qui utilise matplotlib en arriere-plan.

Comment sauvegarder un histogramme matplotlib en fichier image ?

Apres avoir appele plt.hist(), utilisez plt.savefig('histogram.png', dpi=150, bbox_inches='tight') avant plt.show(). Le parametre bbox_inches='tight' empeche les etiquettes d'etre coupees. Les formats supportes incluent PNG, PDF, SVG et EPS.

📚