2

I am trying to create a labelled pie chart using ggrepel based on a StackOverflow answer, but I can't seem to get the position of the labels correctly.

Ideally, I would like the segments that connect the labels to the portion of the pies to start in the middle of the pie for it to be more aesthetically pleasing. But this is not what I get, and I am not sure what I should be changing. I have tried setting position = ggplot2::position_fill(vjust = 0.5) in ggrepel call, but that doesn't help either.

data

# setup
set.seed(123)
library(ggplot2)
library(ggrepel)
library(forcats)

# data
(df <- structure(
  list(
    cyl = structure(
      c(1L, 3L, 2L),
      .Label = c("8", "6", "4"),
      class = "factor"
    ),
    counts = c(14L, 11L, 7L),
    perc = c(43.75, 34.375, 21.875),
    label = c("44%", "34%", "22%")
  ),
  row.names = c(NA, -3L),
  class = c("tbl_df", "tbl", "data.frame")
))
#> # A tibble: 3 x 4
#>   cyl   counts  perc label
#>   <fct>  <int> <dbl> <chr>
#> 1 8         14  43.8 44%  
#> 2 4         11  34.4 34%  
#> 3 6          7  21.9 22%

function

# function
foo <- function(df, x) {
  ggplot2::ggplot(
    data = df,
    mapping = ggplot2::aes(x = "", y = counts, fill = forcats::fct_inorder({{ x }}))
  ) +
    ggplot2::geom_bar(
      stat = "identity",
      color = "black",
      width = 1,
      na.rm = TRUE
    ) +
    coord_polar("y", start = 0) +
    ggrepel::geom_label_repel(
      aes(label = label),
      show.legend = FALSE,
      nudge_x = 1
    ) +
    guides(fill = guide_legend(title = rlang::as_name(rlang::ensym(x))))
}

plot

# plot
foo(df, cyl)

plot

Z.Lin
  • 28,055
  • 6
  • 54
  • 94
Indrajeet Patil
  • 4,673
  • 2
  • 20
  • 51

1 Answers1

1

You can calculate the labels' stacked positions manually, instead of relying on ggplot. See if the following works for you:

foo <- function(df, x) {
  df$y.label <- 0.5 * df$counts + rev(cumsum(dplyr::lag(rev(df$counts), default = 0)))
  ggplot2::ggplot(
    data = df,
    mapping = ggplot2::aes(x = "", y = counts, fill = forcats::fct_inorder({{ x }}))
  ) +
    ggplot2::geom_col(
      color = "black",
      width = 1,
      na.rm = TRUE
    ) +
    coord_polar("y", start = 0) +
    ggrepel::geom_label_repel(
      aes(label = label, y = y.label),
      show.legend = FALSE,
      nudge_x = 1
    ) +
    guides(fill = guide_legend(title = rlang::as_name(rlang::ensym(x))))
}

foo(df, cyl)

plot

Z.Lin
  • 28,055
  • 6
  • 54
  • 94
  • Thanks, but I can't reproduce the output you are getting. This is what I see if I run your code: https://gist.github.com/IndrajeetPatil/c74b0e927e24e3f8b0717dfc46906e66#gistcomment-3384546 – Indrajeet Patil Jul 20 '20 at 08:50
  • And I can't reproduce your output either. What do you get when you run `0.5 * df$counts + rev(cumsum(lag(rev(df$counts), default = 0)))`? – Z.Lin Jul 20 '20 at 08:59
  • I see: `c(39.0, 23.5, 10.5)`. I have also added session info to the gist in case that helps explain the discrepancy. – Indrajeet Patil Jul 20 '20 at 09:05
  • Oh I see. Please replace `lag` with `dplyr::lag`. (I have it loaded all the time till I forget it can conflict with `stats::lag`; will update my answer.) – Z.Lin Jul 20 '20 at 09:14