Average annual wages
Data - OECD
Info
Last observation: Annual: 2024 (N = 109)
First observation: Annual: 1990 (N = 67)
Last data update: 16 avr 2026, 03:39. Last compile**: 16 avr 2026, 03:42
Structure
Example: France
Code
ig_b("oecd", "AV_AN_WAGE_FR")
Example: 1995-2023
Code
ig_b("oecd", "average-annual-wages-for-oecd-countries-in-us-constant-1995-2023")
USD_PPP - US dollars, PPP converted
Replicate 1995-2023 graph
Original
Code
ig_b("oecd", "average-annual-wages-for-oecd-countries-in-us-constant-1995-2023")
Replication
Code
df <- AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
obsTime %in% c("1995", "2024"),
UNIT_MEASURE == "USD_PPP") %>%
select(REF_AREA, Ref_area, obsTime, obsValue) %>%
spread(obsTime, obsValue) %>%
arrange(desc(`2024`)) %>%
filter(!is.na(`2024`)) %>%
setNames(c("REF_AREA", "country", "w1995", "w2024")) |>
mutate(
pct_change = round((w2024 - w1995) / w1995 * 100),
pct_label = paste0(ifelse(pct_change >= 0, "+", ""), pct_change, "%"),
# Keep countries in descending order of 2024 wage
country = fct_reorder(country, w2024)
)
# Colour palette matching the original
col_1995 <- "#3a7ebf" # steel blue
col_2024 <- "#2e8b57" # sea green
col_neg <- "#c0392b" # red for negative change
ggplot(df) +
# ── segment connecting the two dots ──────────────────────────────────────
geom_segment(
aes(x = w1995, xend = w2024, y = country, yend = country),
colour = "#a8d8c8", linewidth = 1.2, lineend = "round"
) +
# ── 1995 dot ─────────────────────────────────────────────────────────────
geom_point(
aes(x = w1995, y = country),
colour = "white", fill = col_1995, shape = 21, size = 4.5, stroke = 1.4
) +
# ── 2024 dot ─────────────────────────────────────────────────────────────
geom_point(
aes(x = w2024, y = country),
colour = "white", fill = col_2024, shape = 21, size = 4.5, stroke = 1.4
) +
# ── 1995 value label (left of dot) ───────────────────────────────────────
geom_text(
aes(x = w1995, y = country,
label = paste0(scales::number(w1995/1000, accuracy = 0.1), "K")),
hjust = 1.35, size = 2.8, colour = "grey40"
) +
# ── 2024 value label (right of dot) ──────────────────────────────────────
geom_text(
aes(x = w2024, y = country,
label = paste0(scales::number(w2024/1000, accuracy = 0.1), "K")),
hjust = -0.35, size = 2.8, colour = "grey40"
) +
# ── % change label (far right) ───────────────────────────────────────────
geom_text(
aes(x = 100000, y = country, label = pct_label,
colour = ifelse(pct_change < 0, col_neg, "#2e8b57")),
hjust = 0, size = 3, fontface = "bold"
) +
scale_colour_identity() +
# ── axes & scales ─────────────────────────────────────────────────────────
scale_x_continuous(
labels = scales::label_dollar(scale = 1/1000, suffix = "K"),
breaks = seq(10000, 100000, by = 10000),
limits = c(5000, 108000),
expand = c(0, 0)
) +
# ── legend ────────────────────────────────────────────────────────────────
annotate("point", x = 88000, y = nlevels(df$country) + 0.7,
colour = "white", fill = col_1995, shape = 21, size = 4, stroke = 1.2) +
annotate("text", x = 89500, y = nlevels(df$country) + 0.7,
label = "1995", hjust = 0, size = 3) +
annotate("point", x = 93000, y = nlevels(df$country) + 0.7,
colour = "white", fill = col_2024, shape = 21, size = 4, stroke = 1.2) +
annotate("text", x = 94500, y = nlevels(df$country) + 0.7,
label = "2024", hjust = 0, size = 3) +
# ── titles ────────────────────────────────────────────────────────────────
labs(
title = "Average Annual Wages for OECD Countries",
subtitle = "(in US$, Constant Prices, PPP Converted)",
caption = "Source: Average annual wages (OECD)",
x = NULL, y = NULL
) +
# ── theme ─────────────────────────────────────────────────────────────────
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(size = 16, face = "bold", margin = margin(b = 2)),
plot.subtitle = element_text(size = 11, colour = "grey40", margin = margin(b = 12)),
plot.caption = element_text(size = 8, colour = "grey55", hjust = 1),
axis.text.x = element_text(colour = "grey50"),
axis.text.y = element_text(size = 9),
panel.grid.major.x = element_line(colour = "grey92", linewidth = 0.4),
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
plot.margin = margin(12, 20, 12, 12),
legend.position = "bottom"
)
Replication 2
Code
df <- AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
obsTime %in% c("1995", "2024"),
UNIT_MEASURE == "USD_PPP") %>%
select(REF_AREA, Ref_area, obsTime, obsValue) %>%
spread(obsTime, obsValue) %>%
arrange(desc(`2024`)) %>%
filter(!is.na(`2024`)) %>%
setNames(c("REF_AREA", "country", "w1995", "w2024")) |>
mutate(
pct_change = round((w2024 - w1995) / w1995 * 100),
pct_label = paste0(ifelse(pct_change >= 0, "+", ""), pct_change, "%"),
# Keep countries in descending order of 2024 wage
country = fct_reorder(country, w2024)
)
# Colour palette matching the original
col_1995 <- "#3a7ebf" # steel blue
col_2024 <- "#2e8b57" # sea green
col_neg <- "#c0392b" # red for negative change
# ── Supprime les annotate() de légende existants ──────────────────────────
# (retire les 4 lignes annotate "point"/"text" pour 1995 et 2024)
# ── Ajoute la légende via scale + guides ──────────────────────────────────
# Transforme le dataframe en format long pour pouvoir utiliser une aesthetic fill
df_long <- df |>
pivot_longer(cols = c(w1995, w2024), names_to = "year", values_to = "wage") |>
mutate(year = case_match(year, "w1995" ~ "1995", "w2024" ~ "2024"))
ggplot() +
# segment
geom_segment(
data = df,
aes(x = w1995, xend = w2024, y = country, yend = country),
colour = "#a8d8c8", linewidth = 1.2, lineend = "round"
) +
# points (avec fill mappé pour la légende)
geom_point(
data = df_long,
aes(x = wage, y = country, fill = year),
colour = "white", shape = 21, size = 4.5, stroke = 1.4
) +
scale_fill_manual(
values = c("1995" = "#3a7ebf", "2024" = "#2e8b57"),
name = NULL
) +
# value labels 1995
geom_text(
data = df,
aes(x = w1995, y = country,
label = paste0(scales::number(w1995/1000, accuracy = 0.1), "K")),
hjust = 1.35, size = 2.8, colour = "grey40"
) +
# value labels 2024
geom_text(
data = df,
aes(x = w2024, y = country,
label = paste0(scales::number(w2024/1000, accuracy = 0.1), "K")),
hjust = -0.35, size = 2.8, colour = "grey40"
) +
# % change
geom_text(
data = df,
aes(x = 100000, y = country, label = pct_label,
colour = ifelse(pct_change < 0, "#c0392b", "#2e8b57")),
hjust = 0, size = 3, fontface = "bold"
) +
scale_colour_identity() +
scale_x_continuous(
labels = scales::label_dollar(scale = 1/1000, suffix = "K"),
breaks = seq(10000, 100000, by = 10000),
limits = c(5000, 108000),
expand = c(0, 0)
) +
labs(
title = "Average Annual Wages for OECD Countries",
subtitle = "(in US$, Constant Prices, PPP Converted)",
caption = "Source: Average annual wages (OECD)",
x = NULL, y = NULL
) +
guides(
fill = guide_legend(
direction = "horizontal",
override.aes = list(size = 4, stroke = 1.2, colour = "white"),
label.position = "right"
)
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(size = 16, face = "bold", margin = margin(b = 2)),
plot.subtitle = element_text(size = 11, colour = "grey40", margin = margin(b = 12)),
plot.caption = element_text(size = 8, colour = "grey55", hjust = 1),
axis.text.x = element_text(colour = "grey50"),
axis.text.y = element_text(size = 9),
panel.grid.major.x = element_line(colour = "grey92", linewidth = 0.4),
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "bottom", # ← légende en bas
legend.spacing.x = unit(6, "pt"),
plot.margin = margin(12, 20, 12, 12)
)
France, Germany, Italy, Spain, USA
Tous
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
UNIT_MEASURE == "USD_PPP",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA")) %>%
year_to_date() %>%
#filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_5flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Current prices in NCU") + xlab("")
1996-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
UNIT_MEASURE == "USD_PPP",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA")) %>%
year_to_date() %>%
filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_5flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Current prices in NCU") + xlab("")
Current Prices
France, Germany, Italy, Spain, USA
Tous
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "V",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA")) %>%
year_to_date() %>%
#filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_5flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Current prices in NCU") + xlab("")
1992-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "V",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA")) %>%
year_to_date() %>%
filter(date >= as.Date("1992-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_5flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Current prices in NCU") + xlab("")
1996-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "V",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA")) %>%
year_to_date() %>%
filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_5flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Current prices in NCU") + xlab("")
2008-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "V",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA")) %>%
year_to_date() %>%
filter(date >= as.Date("2008-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_5flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Current prices in NCU") + xlab("")
Constant Prices
France, Germany, Italy, Spain, USA
Tous
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA"),
UNIT_MEASURE == "EUR") %>%
year_to_date() %>%
#filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_4flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Constant prices in NCU") + xlab("")
1992-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA"),
UNIT_MEASURE == "EUR") %>%
year_to_date() %>%
filter(date >= as.Date("1992-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 5)) +
ylab("Constant prices in NCU") + xlab("")
1996-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA"),
UNIT_MEASURE == "EUR") %>%
year_to_date() %>%
filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 5)) +
ylab("Current prices in NCU") + xlab("")
2008-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE == "Q",
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA"),
UNIT_MEASURE == "EUR") %>%
year_to_date() %>%
filter(date >= as.Date("2008-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_4flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 2)) +
ylab("Current prices in NCU") + xlab("")
Implicit Price
France, Germany, Italy, Spain, USA
Tous
Code
AV_AN_WAGE %>%
filter(PRICE_BASE %in% c("Q", "V"),
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA"),
UNIT_MEASURE == "EUR") %>%
year_to_date() %>%
select_if(~ n_distinct(.) > 1) %>%
select(-BASE_PER, -`Price base`) %>%
spread(PRICE_BASE, obsValue) %>%
mutate(obsValue = V/Q) %>%
#filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_4flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Implicit price: V/Q") + xlab("")
1996-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE %in% c("Q", "V"),
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA"),
UNIT_MEASURE == "EUR") %>%
year_to_date() %>%
select_if(~ n_distinct(.) > 1) %>%
select(-BASE_PER, -`Price base`) %>%
spread(PRICE_BASE, obsValue) %>%
mutate(obsValue = V/Q) %>%
filter(date >= as.Date("1996-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_4flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Implicit price: V/Q") + xlab("")
1999-
Code
AV_AN_WAGE %>%
filter(PRICE_BASE %in% c("Q", "V"),
REF_AREA %in% c("FRA", "DEU", "ITA", "ESP", "USA"),
UNIT_MEASURE == "EUR") %>%
year_to_date() %>%
select_if(~ n_distinct(.) > 1) %>%
select(-BASE_PER, -`Price base`) %>%
spread(PRICE_BASE, obsValue) %>%
mutate(obsValue = V/Q) %>%
filter(date >= as.Date("1999-01-01")) %>%
group_by(Ref_area) %>%
arrange(date) %>%
mutate(obsValue = 100*obsValue/obsValue[1]) %>%
left_join(colors, by = c("Ref_area" = "country")) %>%
ggplot(.) + geom_line(aes(x = date, y = obsValue, color = color)) +
scale_color_identity() + add_4flags + theme_minimal() +
scale_x_date(breaks = seq(1920, 2100, 2) %>% paste0("-01-01") %>% as.Date,
labels = date_format("%Y")) +
scale_y_log10(breaks = seq(10, 500, 10)) +
ylab("Implicit price: V/Q") + xlab("")
Methodology
Main
Average annual wages are the annual rates paid per employee in full-time equivalent unit in the total economy. Average annual wages are calculated by dividing the national-accounts-based total wage bill by the average number of employees in the total economy, which is then converted in full-time equivalent unit by applying the ratio of average usual weekly hours per full-time employee to that of all employees. This calculation helps to gauge the general level of income by economy. Average wages are often used for comparison purposes, to track changes in income levels over time, or to analyse disparities in earnings among different groups. This indicator is measured in US dollars, PPP converted.
OECD Data Explorer
This dataset contains data on average annual wages per employee in full-time equivalent unit in the total economy. Average annual wages per full-time equivalent dependent employee are obtained by dividing the national-accounts-based total wage bill by the average number of employees in the total economy, which is then converted in full-time equivalent unit by applying the ratio of average usual weekly hours per full-time employee to that of all employees. For more details, see: http://www.oecd.org/els/oecd-employment-outlook-19991266.htm and http://www.oecd.org/employment/emp/onlineoecdemploymentdatabase.htm The data are available in Current prices in NCU, in 2024 constant prices and NCU, in 2024 USD PPPs and 2024 constant prices. NCU: National currency units. For further details on these estimates, please see http://www.oecd.org/els/emp/AVERAGE_WAGES.pdf