9
votes

I have checked the other questions in here but I couldn't see this problem. I have a labeling problem. Weird thing is that code is working quite OK for all labels except for one. When I checked the data set (which is something really simple), everything seems quite fine (one column with factor variables, another with numerical).

It is weird because it works OK for some other data with the same structure. However, I tried/checked everything but couldn't solve this issue. Here is the problem:

library(ggplot2)
library(ggrepel)

df = data.frame(
  status = c("Oak", "maple", "walnut", "Pine"),
  value = c( 47.54, 37.70, 11.48, 3.28))

ggplot(df, aes(x = "" , y = value, fill = fct_inorder(status))) +
  geom_bar(width = 1, stat = "identity") +
  coord_polar(theta = "y", start = 0 ) +
  scale_fill_brewer(palette = "Set3", direction = -4) +
  geom_label_repel(aes(label = paste0(value, "%")), size=4, show.legend = F, nudge_x = 1) +
  guides(fill = guide_legend(title = "Status")) +
  theme_void()

One of the labels came up with an issue

It would be great if I have at least a suggestion to try or explanation of this weird behaviour.

Apparently, with the new ggplot2 update they figured the position problem out without giving any extra position data but somehow, If you are unable to use it because of technical limitations, this might help to solve this kind of issues.

1
I think the problem is that geom_bar is using position = "stack", but geom_text_repel isn't. Adding position = "stack" changes the problem. Probably best to pre-calculate the midpoint of each slice of the pie.Richard Telford
@RichardTelford yep that's what I have tried to define for geom_label_repel, but neither that nor geom_text_repel doesn't get the "position". Thanks anyway.DSA

1 Answers

9
votes

I think the problem is that the geom_bar (or better geom_col) defaults to position = stack whereas geom_text_repel doesn't. Setting geom_text_repel to position= "stack" puts the labels at the end of each section of the pie rather than the midpoint.

It is possible to pre-calculate the positions. The code below works for the data shown, but might not be general as it depends on the order of the rows.

library(ggplot2)
library(ggrepel)

df = data.frame(
  status = c("Oak", "maple", "walnut", "Pine"),
  value = c( 47.54, 37.70, 11.48, 3.28))

df2 <- df %>% 
  mutate(
    cs = rev(cumsum(rev(value))), 
    pos = value/2 + lead(cs, 1),
    pos = if_else(is.na(pos), value/2, pos))

ggplot(df, aes(x = "" , y = value, fill = fct_inorder(status))) +
  geom_col(width = 1) +
  coord_polar(theta = "y", start = 0 ) +
  scale_fill_brewer(palette = "Set3", direction = -4) +
  geom_label_repel(aes(y = pos, label = paste0(value, "%")), data = df2, size=4, show.legend = F, nudge_x = 1) +
  guides(fill = guide_legend(title = "Status")) +
  theme_void()