Home > Software engineering >  Controlling the position of geom_text labels in a bar plot with positive and negative values and fac
Controlling the position of geom_text labels in a bar plot with positive and negative values and fac

Time:03-01

I want labels to appear outside of both positive and negative bars, so I can't simply use hjust to move the location. Right now I have this, which is close...

score <- c(1, 2, 3, 4, 5, "X")
group1 <- c(0,0,5,-0.2,-4.9,0)
group2 <- c(0.1,0,-1.2,0.4,0.6,0.1)
group3 <- c(0.1,0,3.4,2.9,-6.4,0)
group4 <-c(0,0,-0.9,-0.3,1.3,0)

data <- data.frame(score=as.factor(score), Group1=group1, Group2=group2, Group3=group3, Group4=group4)

data_long <- pivot_longer(data, c(Group1, Group2, Group3, Group4))
data_long$label <- paste(round(data_long$value,1),"%",sep="")
data_long$value <- data_long$value/100

sig <- rep(0, 24)
sig[c(3, 9, 11, 15, 17, 19)] <- 1
sig <- as.factor(sig)
data_long <- cbind(data_long, sig)


bars <- data_long %>% filter(score != 2,
                             score != "X") %>%
  ggplot(aes(x = value, y=name, fill=sig))  
  geom_bar(stat="identity")  
  scale_fill_manual(values=c("grey", "firebrick"))  
  scale_x_continuous(limits = ~ c(-1, 1) * max(abs(.x)),
                     labels = scales::percent)  
  facet_wrap(~score, scales = "free_x")  
  theme(legend.position = "none")  
  geom_text(aes(label=label,
                x = value   (0.005 * sign(value))),  size = 3)  
  labs(x = "Deviation From Expected Value",
       y = "Group",
       title = "Deviations From Expected Value by Score",
       caption = "Red bars statistically significant")

print(bars)

This produces the following chart enter image description here

But notice how in the top left facet, where the scale is REALLY small, the labels are very far removed from the non-zero bars. I'm assuming this is because the multiplicative factor I use in the geom_text x aesthetic is large for that scale. I took a stab at some sort of function in there that took the limits into account but I got an error

Aesthetics must be valid data columns. Problematic aesthetic(s): x = ~(value   (0.005 * max(abs(.x)) * sign(value)))

Any advice on how to proceed would be appreciated.

CodePudding user response:

You can use hjust as an aesthetic mapping. If you set it to 0.5 - sign(value)/2 it will be 0 for the positive bars and 1 for the negative bars, as desired.

data_long %>% filter(score != 2,
                             score != "X") %>%
  ggplot(aes(x = value, y=name, fill=sig))  
  geom_bar(stat="identity")  
  scale_fill_manual(values=c("grey", "firebrick"))  
  scale_x_continuous(limits = ~ c(-1, 1) * max(abs(.x)),
                     labels = scales::percent)  
  facet_wrap(~score, scales = "free_x")  
  theme(legend.position = "none")  
  geom_text(aes(label=label,
                x = value, hjust = 0.5 - sign(value)/2),  size = 3)  
  labs(x = "Deviation From Expected Value",
       y = "Group",
       title = "Deviations From Expected Value by Score",
       caption = "Red bars statistically significant")

enter image description here

  • Related