Last observation: 2024 (N = 12)
First observation: 1996 (N = 12)
Last data update: 26 oct. 2026, 17:20
Last compile: 03 nov. 2026, 01:52
Niveau de vie moyen annuel par unité de consommation, en euros 2024 constants, France métropolitaine, 1996-2024. « D1- » désigne les 10 % les plus modestes (sous le 1er décile), « D9+ » les 10 % les plus aisés (au-dessus du 9e décile). Les séries ont plusieurs ruptures (2010, 2012, 2020) : les courbes ne sont reliées qu’au sein d’une même série.
pal <- viridisLite::mako(10, begin = 0.1, end = 0.85, direction = -1)
ggplot(deciles |> mutate(decile = factor(decile, levels = ordre_deciles)),
aes(x = year, y = value / 1000, color = decile, group = interaction(decile, segment))) +
geom_line(linewidth = 1) +
geom_text(data = ~ filter(.x, year == max(year)), aes(label = decile), hjust = -0.15, size = 3.3,
show.legend = FALSE) +
scale_color_manual(values = pal, guide = "none") +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.02, 0.1))) +
scale_y_log10(breaks = c(10, 15, 20, 30, 50, 80)) +
theme_nv() +
labs(x = NULL, y = "Milliers d'euros 2024 par an (échelle logarithmique)",
title = "Le niveau de vie progresse à toutes les hauteurs de la distribution",
subtitle = "niveau de vie annuel moyen par tranche de déciles, euros 2024 constants")
Les séries publiées par l’Insee sont en euros 2024 constants au sens de l’IPC (indice des prix à la consommation). Comme dans ipp/indicefp.qmd, on les redéflate par l’IPCH (indice harmonisé, Eurostat) : on retrouve le nominal en multipliant par IPC(année)/IPC(2024), puis on divise par IPCH(année)/IPCH(2024). L’IPCH ayant augmenté plus vite que l’IPC depuis 1996, les niveaux de vie passés sont plus élevés en euros 2024 « IPCH » et la progression apparente est plus faible.
top <- niv |>
filter(decile == "D9+") |>
select(year, segment, `IPC (série publiée)` = value, `IPCH (calculé)` = value_ipch) |>
pivot_longer(starts_with("IPC"), names_to = "deflateur", values_to = "valeur")
cols_def <- c("IPC (série publiée)" = rose, "IPCH (calculé)" = vert)
ggplot(top, aes(x = year, y = valeur / 1000, color = deflateur, group = interaction(deflateur, segment))) +
geom_line(linewidth = 1.2) +
geom_point(data = ~ filter(.x, year %in% c(1996, 2024)), size = 2.6) +
geom_text(data = ~ filter(.x, year == 2024), aes(label = sprintf("%.1f k€", valeur / 1000)),
hjust = -0.15, size = 3.6, show.legend = FALSE) +
geom_text(data = ~ filter(.x, year == 1996), aes(label = sprintf("%.1f k€", valeur / 1000)),
hjust = 1.15, size = 3.6, show.legend = FALSE) +
scale_color_manual(values = cols_def, name = NULL) +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.08, 0.1))) +
theme_nv() +
labs(x = NULL, y = "Milliers d'euros 2024 par an",
title = "Niveau de vie moyen des 10 % les plus aisés, en euros 2024 constants",
subtitle = "déflaté par l'IPC (série Insee) et par l'IPCH (calcul) ; courbes interrompues aux ruptures de série")
base100 <- niv |>
filter(decile == "D9+") |>
group_by(segment) |>
ungroup() |>
select(year, annee_brut, segment, ipc = value, ipch = value_ipch) |>
mutate(ref_ipc = ipc[year == 1996][1], ref_ipch = ipch[year == 1996][1]) |>
transmute(year, segment, `IPC (série publiée)` = 100 * ipc / ref_ipc, `IPCH (calculé)` = 100 * ipch / ref_ipch) |>
pivot_longer(starts_with("IPC"), names_to = "deflateur", values_to = "indice")
ggplot(base100, aes(x = year, y = indice, color = deflateur, group = interaction(deflateur, segment))) +
geom_hline(yintercept = 100, color = "grey60", linetype = "dashed") +
geom_line(linewidth = 1.2) +
geom_text(data = ~ filter(.x, year == 2024), aes(label = sprintf("%.0f", indice)), hjust = -0.3,
fontface = "bold", show.legend = FALSE) +
scale_color_manual(values = cols_def, name = NULL) +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.02, 0.08))) +
theme_nv() +
labs(x = NULL, y = "Indice, base 100 en 1996",
title = "Depuis 1996, le niveau de vie des plus aisés progresse moins avec l'IPCH qu'avec l'IPC",
subtitle = "niveau de vie moyen au-dessus du 9e décile, euros constants, base 100 en 1996")
Même méthode pour les 10 % les plus modestes (en dessous du 1er décile).
bas <- niv |>
filter(decile == "D1-") |>
select(year, segment, `IPC (série publiée)` = value, `IPCH (calculé)` = value_ipch) |>
pivot_longer(starts_with("IPC"), names_to = "deflateur", values_to = "valeur")
ggplot(bas, aes(x = year, y = valeur / 1000, color = deflateur, group = interaction(deflateur, segment))) +
geom_line(linewidth = 1.2) +
geom_point(data = ~ filter(.x, year %in% c(1996, 2024)), size = 2.6) +
geom_text(data = ~ filter(.x, year == 2024), aes(label = sprintf("%.1f k€", valeur / 1000)),
hjust = -0.15, size = 3.6, show.legend = FALSE) +
geom_text(data = ~ filter(.x, year == 1996), aes(label = sprintf("%.1f k€", valeur / 1000)),
hjust = 1.15, size = 3.6, show.legend = FALSE) +
scale_color_manual(values = cols_def, name = NULL) +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.08, 0.1))) +
theme_nv() +
labs(x = NULL, y = "Milliers d'euros 2024 par an",
title = "Niveau de vie moyen des 10 % les moins aisés, en euros 2024 constants",
subtitle = "déflaté par l'IPC (série Insee) et par l'IPCH (calcul) ; courbes interrompues aux ruptures de série")
niv |>
filter(decile == "D1-") |>
mutate(ref_ipc = value[year == 1996][1], ref_ipch = value_ipch[year == 1996][1]) |>
transmute(year, segment, `IPC (série publiée)` = 100 * value / ref_ipc, `IPCH (calculé)` = 100 * value_ipch / ref_ipch) |>
pivot_longer(starts_with("IPC"), names_to = "deflateur", values_to = "indice") |>
ggplot(aes(x = year, y = indice, color = deflateur, group = interaction(deflateur, segment))) +
geom_hline(yintercept = 100, color = "grey60", linetype = "dashed") +
geom_line(linewidth = 1.2) +
geom_text(data = ~ filter(.x, year == 2024), aes(label = sprintf("%.0f", indice)), hjust = -0.3,
fontface = "bold", show.legend = FALSE) +
scale_color_manual(values = cols_def, name = NULL) +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.02, 0.08))) +
theme_nv() +
labs(x = NULL, y = "Indice, base 100 en 1996",
title = "Les plus modestes : un niveau de vie en léger recul depuis 2002, davantage avec l'IPCH",
subtitle = "niveau de vie moyen en dessous du 1er décile, euros constants, base 100 en 1996")
niv |>
filter(decile %in% c("D1-", "D9+")) |>
mutate(groupe = if_else(decile == "D9+", "10 % les plus aisés", "10 % les moins aisés")) |>
group_by(decile) |>
mutate(ref_ipc = value[year == 1996][1], ref_ipch = value_ipch[year == 1996][1]) |>
ungroup() |>
transmute(year, segment, groupe, `IPC (série publiée)` = 100 * value / ref_ipc,
`IPCH (calculé)` = 100 * value_ipch / ref_ipch) |>
pivot_longer(starts_with("IPC"), names_to = "deflateur", values_to = "indice") |>
ggplot(aes(x = year, y = indice, color = deflateur, group = interaction(deflateur, segment))) +
geom_hline(yintercept = 100, color = "grey60", linetype = "dashed") +
geom_line(linewidth = 1.1) +
geom_text(data = ~ filter(.x, year == 2024), aes(label = sprintf("%.0f", indice)), hjust = -0.3,
fontface = "bold", show.legend = FALSE) +
facet_wrap(~ groupe) +
scale_color_manual(values = cols_def, name = NULL) +
scale_x_continuous(breaks = seq(1996, 2024, 8), expand = expansion(mult = c(0.02, 0.15))) +
theme_nv() + theme(strip.text = element_text(face = "bold", hjust = 0)) +
labs(x = NULL, y = "Indice, base 100 en 1996",
title = "Le haut a progressé nettement plus que le bas, avec l'un ou l'autre indice de prix",
subtitle = "niveau de vie moyen, euros 2024 constants, base 100 en 1996")
Les mêmes séries exprimées par mois (niveau de vie annuel ÷ 12), pour être directement comparables aux seuils de pauvreté mensuels (reve-pauv-seuil-mensuel).
mens <- niv |>
filter(decile %in% c("D1-", "D9+")) |>
mutate(groupe = if_else(decile == "D9+", "10 % les plus aisés", "10 % les moins aisés")) |>
select(year, segment, groupe, `IPC (série publiée)` = value, `IPCH (calculé)` = value_ipch) |>
pivot_longer(starts_with("IPC"), names_to = "deflateur", values_to = "annuel") |>
mutate(mensuel = annuel / 12)
ggplot(mens, aes(x = year, y = mensuel, color = deflateur, group = interaction(deflateur, segment))) +
geom_line(linewidth = 1.2) +
geom_text(data = ~ filter(.x, year == 2024), aes(label = paste0(format(round(mensuel), big.mark = " "), " €")),
hjust = -0.2, size = 3.6, show.legend = FALSE) +
facet_wrap(~ groupe, scales = "free_y") +
scale_color_manual(values = cols_def, name = NULL) +
scale_x_continuous(breaks = seq(1996, 2024, 8), expand = expansion(mult = c(0.02, 0.2))) +
scale_y_continuous(labels = ~ format(.x, big.mark = " ")) +
theme_nv() + theme(strip.text = element_text(face = "bold", hjust = 0)) +
labs(x = NULL, y = "Euros 2024 par mois",
title = "Niveau de vie mensuel moyen : 830 € pour les plus modestes, 6 400 € pour les plus aisés",
subtitle = "euros 2024 constants par mois et par unité de consommation, IPC (série Insee) et IPCH (calcul)")
ggplot(deciles |> mutate(decile = factor(decile, levels = ordre_deciles)),
aes(x = year, y = value / 12, color = decile, group = interaction(decile, segment))) +
geom_line(linewidth = 1) +
geom_text(data = ~ filter(.x, year == max(year)),
aes(label = paste0(decile, " : ", format(round(value / 12), big.mark = " "), " €")),
hjust = -0.1, size = 3.2, show.legend = FALSE) +
scale_color_manual(values = pal, guide = "none") +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.02, 0.2))) +
scale_y_log10(breaks = c(800, 1000, 1500, 2000, 3000, 5000)) +
theme_nv() +
labs(x = NULL, y = "Euros 2024 par mois (échelle logarithmique)",
title = "Niveau de vie mensuel moyen par tranche de déciles",
subtitle = "euros 2024 constants par mois, série publiée (IPC)")
# Seuils de pauvreté mensuels (même convention de ruptures que reve-pauv-seuil-mensuel.qmd)
seuils <- read_parquet("reve-pauv-seuil-mensuel.parquet") |>
filter(unite == "Euros 2024 constants", taux %in% c(50, 60)) |>
group_by(taux) |>
mutate(segment = cumsum(str_detect(coalesce(notes, ""), "[1235]"))) |>
ungroup() |>
filter(year >= 1996) |>
transmute(year, segment, serie = paste0("Seuil de pauvreté à ", taux, " %"), mensuel = value)
bas_m <- niv |> filter(decile == "D1-") |>
transmute(year, segment, serie = "Niveau de vie moyen des 10 % les moins aisés", mensuel = value / 12)
ggplot() +
geom_line(data = seuils, aes(x = year, y = mensuel, color = serie, group = interaction(serie, segment)), linewidth = 1.1) +
geom_line(data = bas_m, aes(x = year, y = mensuel, color = serie, group = segment), linewidth = 1.4) +
geom_text(data = bind_rows(seuils, bas_m) |> filter(year == 2024) |> group_by(serie) |> slice_tail(n = 1) |> ungroup(),
aes(x = year, y = mensuel, color = serie, label = paste0(format(round(mensuel), big.mark = " "), " €")),
hjust = -0.2, size = 3.6, show.legend = FALSE) +
scale_color_manual(values = c("Niveau de vie moyen des 10 % les moins aisés" = rose,
"Seuil de pauvreté à 50 %" = jaune, "Seuil de pauvreté à 60 %" = bleu), name = NULL) +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.02, 0.1))) +
scale_y_continuous(labels = ~ format(.x, big.mark = " ")) +
theme_nv() + guides(color = guide_legend(nrow = 2)) +
labs(x = NULL, y = "Euros 2024 par mois",
title = "Les 10 % les moins aisés vivent en moyenne sous le seuil de pauvreté à 60 %",
subtitle = "niveau de vie mensuel moyen du 1er décile et seuils de pauvreté mensuels (euros 2024 constants, IPC)")
niv |>
filter(decile %in% c("D1-", "D4-D5", "D8-D9", "D9+", "Ensemble")) |>
group_by(decile) |>
mutate(indice = 100 * value / value[year == 1996][1]) |>
ungroup() |>
mutate(decile = factor(decile, levels = c("D9+", "D8-D9", "Ensemble", "D4-D5", "D1-"))) |>
ggplot(aes(x = year, y = indice, color = decile, group = interaction(decile, segment))) +
geom_hline(yintercept = 100, color = "grey60", linetype = "dashed") +
geom_line(linewidth = 1.1) +
geom_text(data = ~ filter(.x, year == 2024), aes(label = sprintf("%s : %.0f", decile, indice)),
hjust = -0.1, size = 3.4, show.legend = FALSE) +
scale_color_manual(values = c("D9+" = bleu, "D8-D9" = "#8FB0DE", "Ensemble" = "grey35",
"D4-D5" = jaune, "D1-" = rose), guide = "none") +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.02, 0.18))) +
theme_nv() +
labs(x = NULL, y = "Indice, base 100 en 1996",
title = "Le haut de la distribution décolle, le bas stagne depuis 2002",
subtitle = "niveau de vie moyen en euros 2024 constants (IPC), base 100 en 1996, tranches de déciles choisies")
croissance <- function(df, d, f) {
a <- df |> filter(year == d, annee_brut == as.character(d)) |> select(decile, v0 = value)
b <- df |> filter(year == f, annee_brut == as.character(f)) |> select(decile, v1 = value)
inner_join(a, b, by = "decile") |> mutate(periode = sprintf("%d-%d", d, f), g = (v1 / v0)^(1 / (f - d)) - 1)
}
gains <- bind_rows(croissance(deciles, 1996, 2008), croissance(deciles, 2008, 2019), croissance(deciles, 2019, 2024)) |>
mutate(decile = factor(decile, levels = ordre_deciles))
ggplot(gains, aes(x = decile, y = g, fill = periode)) +
geom_col(position = position_dodge(width = 0.8), width = 0.75) +
geom_hline(yintercept = 0, color = "grey25") +
scale_y_continuous(labels = scales::percent_format(accuracy = 0.1)) +
scale_fill_manual(values = c("1996-2008" = bleu, "2008-2019" = rose, "2019-2024" = vert), name = NULL) +
theme_nv() +
labs(x = NULL, y = "Croissance annuelle moyenne",
title = "Hausse jusqu'en 2008, stagnation ensuite, reprise depuis 2019 sauf pour le 1er décile",
subtitle = "croissance annuelle moyenne du niveau de vie en euros constants, par décile et par période")
croissance(deciles, 1996, 2024) |>
mutate(decile = factor(decile, levels = ordre_deciles)) |>
ggplot(aes(x = decile, y = v1 / v0 - 1)) +
geom_col(fill = bleu, width = 0.7) +
geom_text(aes(label = sprintf("%+.0f %%", 100 * (v1 / v0 - 1))), vjust = -0.4, size = 3.6) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1), expand = expansion(mult = c(0, 0.12))) +
theme_nv() +
labs(x = NULL, y = NULL, title = "Évolution cumulée du niveau de vie moyen entre 1996 et 2024",
subtitle = "en euros constants, par tranche de déciles")
rap <- niv |> filter(type == "Rapport (B)/(A)")
rup <- rap |> filter(!is.na(notes))
ggplot(rap, aes(x = year, y = value)) +
geom_line(aes(group = segment), color = rose, linewidth = 1.2) +
geom_point(color = rose, size = 1.8) +
geom_point(data = rup, shape = 21, size = 3.2, fill = "white", color = "grey25", stroke = 1) +
ggrepel::geom_text_repel(data = rup, aes(label = sprintf("%s (note %s)", year, notes)), size = 3,
color = "grey30", nudge_y = -0.5, segment.color = "grey70") +
scale_x_continuous(breaks = seq(1996, 2024, 4), expand = expansion(mult = c(0.02, 0.05))) +
scale_y_continuous(limits = c(5, NA)) +
theme_nv() +
labs(x = NULL, y = "Rapport (B)/(A)",
title = "Les 10 % les plus aisés ont un niveau de vie\nmoyen près de 8 fois supérieur aux 10 % les plus modestes",
subtitle = "rapport entre le niveau de vie moyen au-dessus du 9e décile (B) et sous le 1er décile (A)\ncercles blancs : points de rupture de série")
niv |>
filter(annee_brut == as.character(year), year %in% c(1996, 2008, 2019, 2024)) |>
select(tranche, year, value) |>
mutate(value = round(value, 1)) |>
pivot_wider(names_from = year, values_from = value) |>
rename(`Tranche de niveau de vie` = tranche) |>
print_table_conditional()| Tranche de niveau de vie | 1996 | 2008 | 2019 | 2024 |
|---|---|---|---|---|
| Inférieur au 1er décile | 8530.0 | 10380.0 | 10020.0 | 9960.0 |
| Entre le 1er et le 2e décile | 12510.0 | 15260.0 | 15300.0 | 15890.0 |
| Entre le 2e et le 3e décile | 15100.0 | 18250.0 | 18530.0 | 19400.0 |
| Entre le 3e et le 4e décile | 17290.0 | 20770.0 | 21410.0 | 22430.0 |
| Entre le 4e et le 5e décile | 19520.0 | 23170.0 | 23980.0 | 25310.0 |
| Entre le 5e et le 6e décile | 21900.0 | 25770.0 | 26730.0 | 28290.0 |
| Entre le 6e et le 7e décile | 24720.0 | 28800.0 | 29870.0 | 31670.0 |
| Entre le 7e et le 8e décile | 28350.0 | 32890.0 | 33990.0 | 36040.0 |
| Entre le 8e et le 9e décile | 34160.0 | 39860.0 | 40610.0 | 43010.0 |
| Supérieur au 9e décile | 52870.0 | 69200.0 | 69200.0 | 76970.0 |
| Ensemble | 23490.0 | 28430.0 | 28960.0 | 30900.0 |
| Rapport (B)/(A) | 6.2 | 6.7 | 6.9 | 7.7 |
`reve-niv-vie-decile` |>
group_by(year, annee_brut) |>
summarise(Nobs = n(), .groups = "drop") |>
arrange(desc(year), annee_brut) |>
print_table_conditional()