I'm trying to recreate a figure but am unable to get the positioning of the labels inside the pie charts right.
This is my current code:
ggplot(flying63, aes(x = '', y = percentage, fill = baby_on_plane)) +
geom_col(width = 1, position = position_fill()) +
coord_polar('y') +
facet_grid(gender ~ age) +
geom_label_repel(aes(label = sprintf("%.2f%%", percentage)),
position = position_fill(), size = 3, max.time = 8) +
theme(axis.text = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank())
However, I want the labels to look as follows:

Update:
input data:
flying63 <- structure(list(gender = c("Female", "Female", "Female", "Female",
"Male", "Male", "Male", "Male", "Female", "Female", "Female",
"Female", "Male", "Male", "Male", "Male", "Female", "Female",
"Female", "Female", "Male", "Male", "Male", "Male"), age = structure(c(1L,
2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L,
2L, 3L, 4L, 1L, 2L, 3L, 4L), levels = c("18-29", "30-44", "45-60",
"> 60"), class = c("ordered", "factor")), baby_on_plane = c("Yes, very rude",
"Yes, very rude", "Yes, very rude", "Yes, very rude", "Yes, very rude",
"Yes, very rude", "Yes, very rude", "Yes, very rude", "Yes, somewhat rude",
"Yes, somewhat rude", "Yes, somewhat rude", "Yes, somewhat rude",
"Yes, somewhat rude", "Yes, somewhat rude", "Yes, somewhat rude",
"Yes, somewhat rude", "No, not at all rude", "No, not at all rude",
"No, not at all rude", "No, not at all rude", "No, not at all rude",
"No, not at all rude", "No, not at all rude", "No, not at all rude"
), n = c(5L, 5L, 6L, 6L, 8L, 11L, 15L, 5L, 23L, 11L, 14L, 10L,
19L, 34L, 19L, 17L, 47L, 62L, 75L, 71L, 35L, 50L, 74L, 55L),
percentage = c(6.66666666666667, 6.41025641025641, 6.31578947368421,
6.89655172413793, 12.9032258064516, 11.5789473684211, 13.8888888888889,
6.49350649350649, 30.6666666666667, 14.1025641025641, 14.7368421052632,
11.4942528735632, 30.6451612903226, 35.7894736842105, 17.5925925925926,
22.0779220779221, 62.6666666666667, 79.4871794871795, 78.9473684210526,
81.6091954022989, 56.4516129032258, 52.6315789473684, 68.5185185185185,
71.4285714285714), label_position = c(3.33333333333333, 3.2051282051282,
3.1578947368421, 3.44827586206896, 6.4516129032258, 5.78947368421055,
6.94444444444445, 3.24675324675324, 15.3333333333333, 7.05128205128205,
7.3684210526316, 5.7471264367816, 15.3225806451613, 17.8947368421052,
8.7962962962963, 11.038961038961, 31.3333333333333, 39.7435897435898,
39.4736842105263, 40.8045977011494, 28.2258064516129, 26.3157894736842,
34.2592592592593, 35.7142857142857)), class = c("grouped_df",
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -24L), groups = structure(list(
gender = c("Female", "Female", "Female", "Female", "Female",
"Female", "Female", "Female", "Female", "Female", "Female",
"Female", "Male", "Male", "Male", "Male", "Male", "Male",
"Male", "Male", "Male", "Male", "Male", "Male"), age = structure(c(1L,
1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L, 1L, 1L, 1L, 2L,
2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L), levels = c("18-29", "30-44",
"45-60", "> 60"), class = c("ordered", "factor")), baby_on_plane = c("No, not at all rude",
"Yes, somewhat rude", "Yes, very rude", "No, not at all rude",
"Yes, somewhat rude", "Yes, very rude", "No, not at all rude",
"Yes, somewhat rude", "Yes, very rude", "No, not at all rude",
"Yes, somewhat rude", "Yes, very rude", "No, not at all rude",
"Yes, somewhat rude", "Yes, very rude", "No, not at all rude",
"Yes, somewhat rude", "Yes, very rude", "No, not at all rude",
"Yes, somewhat rude", "Yes, very rude", "No, not at all rude",
"Yes, somewhat rude", "Yes, very rude"), .rows = structure(list(
17L, 9L, 1L, 18L, 10L, 2L, 19L, 11L, 3L, 20L, 12L, 4L,
21L, 13L, 5L, 22L, 14L, 6L, 23L, 15L, 7L, 24L, 16L, 8L), ptype = integer(0), class = c("vctrs_list_of",
"vctrs_vctr", "list"))), row.names = c(NA, -24L), .drop = TRUE, class = c("tbl_df",
"tbl", "data.frame")))



I fudged up some data so I could work on this. I think what you are looking for is the
box.padding = ...argument. You can play with the value to change the length of the offsets.