How can I add text on top the stacked bar with totals? The number should be equal to the "Revenue" in col metric. I have searched everywhere but have not seen a thread for stacked col bars. Any help is appreciated
Current code:
prof %>%
filter(metric != "Revenue") %>%
pivot_longer(!1:2, names_to = "group") %>%
mutate(total_2024 = sum(value * (year == 2024)), .by = group) %>%
mutate(group = reorder(group, -total_2024)) %>%
mutate(year_group_total = sum(value), .by = c(year, group)) %>%
ggplot() +
aes(x = factor(year), y = value, fill = metric) +
geom_bar(stat = "identity", position = "stack") +
geom_text(aes(label = round(value, 0)),
position = position_stack(vjust = 0.5),
size = 3, color = "white") +
facet_wrap(~ group, nrow = 1)
Data:
structure(list(metric = c("Semi-direct/Indirect OPEX", "Direct OPEX",
"Cogs", "EBITDA", "Semi-direct/Indirect OPEX", "Direct OPEX",
"Cogs", "EBITDA", "Revenue", "Revenue"), year = c(2024, 2024,
2024, 2024, 2023, 2023, 2023, 2023, 2023, 2024), `B2C Mobile` = c(897.784296273134,
1553.75734792605, 2174.93374732592, 5755.54423659222, 998.273127452503,
1491.49788927451, 2577.32537561267, 5188.04527286322, 10255.1416652029,
10382.0196281173), `B2B Mobile` = c(556.814329695538, 910.678821511126,
1206.88678722175, 2974.74324198596, 551.422958887446, 886.952093722743,
1291.87657757128, 3091.66275796777, 5821.91438814924, 5649.12318041437
), `B2C Fiber` = c(517.558827512705, 495.164268332664, 2047.61667685037,
471.94510699589, 412.859413724063, 454.877885907187, 1936.82417093636,
500.145306066416, 3304.70677663402, 3532.28487969163), `HFC B2C` = c(252.327289621926,
194.055038683145, 892.79869969144, 305.281096059764, 183.864737312406,
177.365375913805, 1020.84928874347, 403.547767116329, 1785.62716908601,
1644.46212405627), `B2B Fiber` = c(130.704875738789, 181.150718557421,
315.08402928116, 259.876581766672, 184.022162044549, 203.280264535604,
290.095491871566, 288.017740790265, 965.415659241984, 886.816205344042
), Wholesale = c(335.66507766929, 81.3907132734683, 359.637328238667,
726.393721768013, 606.085398971104, -161.245692311656, 379.926654798916,
721.092000854812, 1545.85836231318, 1503.08684094944), Other = c(582.212942299726,
460.192151400037, 486.308969368716, 660.596166217528, 884.601699952072,
349.083787813294, 545.586302785773, 509.765926491606, 2289.03771704274,
2189.31022928601)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA,
-10L))
You can achieve your desired result using a second geom_text/label
where you use stat="summary"
to compute the sum on the fly and use after_stat()
to map the computed value on the label
aes:
library(tidyverse)
prof %>%
filter(metric != "Revenue") %>%
pivot_longer(!1:2, names_to = "group") %>%
mutate(total_2024 = sum(value * (year == 2024)), .by = group) %>%
mutate(group = reorder(group, -total_2024)) %>%
mutate(year_group_total = sum(value), .by = c(year, group)) %>%
ggplot() +
aes(x = factor(year), y = value, fill = metric) +
geom_col() +
geom_text(aes(label = round(value, 0)),
position = position_stack(vjust = 0.5),
size = 3, color = "white"
) +
geom_label(
aes(label = after_stat(round(y, 0)), group = 1),
size = 3, color = "black",
stat = "summary",
fun = sum,
vjust = 0,
fill = NA,
label.size = 0
) +
facet_wrap(~group, nrow = 1)
Created on 2025-03-19 with reprex v2.1.1