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 :
| Algorithme | Valeur de bins= | Methode | Ideal pour |
|---|---|---|---|
| Sturges | 'sturges' | 1 + log2(n) | Petits jeux de donnees approximativement normaux |
| Scott | 'scott' | Base sur l'ecart-type et n | Donnees normales ou quasi normales |
| Freedman-Diaconis | 'fd' | Base sur l'IQR et n | Robuste aux valeurs aberrantes |
| Racine carree | 'sqrt' | sqrt(n) | Estimation rapide approximative |
| Auto | 'auto' | Maximum de Sturges et FD | Usage 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 histtype | Description |
|---|---|
'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 retour | Type | Description |
|---|---|---|
n | ndarray | Nombre (ou densite) pour chaque bin |
bin_edges | ndarray | Valeurs des bords pour chaque bin (longueur = len(n) + 1) |
patches | liste de Rectangles | Les 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()
| Parametre | Type | Description | Defaut |
|---|---|---|---|
x | array-like | Donnees d'entree | Requis |
bins | int, sequence ou str | Nombre de bins, bords de bins ou nom d'algorithme | 10 |
range | tuple | Plage inferieure et superieure des bins | (x.min(), x.max()) |
density | bool | Normaliser pour que l'aire soit egale a 1 | False |
weights | array-like | Poids pour chaque point de donnees | None |
cumulative | bool | Calculer l'histogramme cumulatif | False |
histtype | str | 'bar', 'barstacked', 'step', 'stepfilled' | 'bar' |
orientation | str | 'vertical' ou 'horizontal' | 'vertical' |
color | color ou liste | Couleur(s) des barres | None |
edgecolor | color | Couleur du bord des barres | None |
alpha | float | Transparence (0 a 1) | None |
label | str | Etiquette pour la legende | None |
stacked | bool | Empiler plusieurs jeux de donnees | False |
log | bool | Axe y logarithmique | False |
rwidth | float | Largeur relative des barres (0 a 1) | None |
bottom | array-like ou scalaire | Ligne de base pour chaque barre | 0 |
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 :
| Caracteristique | plt.hist() | sns.histplot() |
|---|---|---|
| Bibliotheque | matplotlib | seaborn |
| Types d'entree | Array, liste, Series | Array, Series, colonne DataFrame |
| Superposition KDE | Manuelle (scipy necessaire) | Integree (kde=True) |
| Style par defaut | Minimal | Pret pour publication |
| Groupes multiples | Passer une liste de tableaux | Parametre hue |
| Options statistiques | Nombre, densite | Nombre, densite, frequence, probabilite, pourcentage |
| Algorithmes de bins | sturges, scott, fd, sqrt, auto | auto, fd, doane, scott, stone, rice, sturges, sqrt |
| Echelle logarithmique | log=True | log_scale=True |
| Axe categoriel | Non supporte | Supporte via hue |
| Performance (grandes donnees) | Plus rapide | Legerement plus lent |
| Profondeur de personnalisation | API complete matplotlib | API 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 pygwalkerimport 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.