Search code examples
rggplot2labelgeom-textgeom-col

Position labels in geom_col() outside of bars


Code for my bar plot:

library(ggplot2)
data <- data.frame(vars = c("pos1", "neg1", "pos2", "neg2", "pos3", "pos4"), 
                   values = c(164182, -72705, 1023777, -75002, 756206, 564523),
                   sign = c("p", "n", "p", "n", "p", "p"))
ggplot(data, aes(x = values, y = vars, fill = sign)) + geom_col() + 
  geom_text(aes(label = format(round(values), big.mark = ",")))

Result I got:

Not bad, but I want labels to be just outside of the bars and be fully visible. In the example above I have them "half in half out", label for pos2 is not fully visible.

So I added hjust = "outward" in the last line:

library(ggplot2)
data <- data.frame(vars = c("pos1", "neg1", "pos2", "neg2", "pos3", "pos4"), 
                   values = c(164182, -72705, 1023777, -75002, 756206, 564523),
                   sign = c("p", "n", "p", "n", "p", "p"))
ggplot(data, aes(x = values, y = vars, fill = sign)) + geom_col() + 
  geom_text(aes(label = format(round(values), big.mark = ",")), hjust = "outward")

Result

Now all labels except pos1 (and why is that?) are exactly as I want them (outside) but three of them are out of bounds which is not good. Changing "outward" to "inward" solves "out of bounds" problem, but labels are now inside of bars(except pos1, what's wrong with it?) "inward" option

So how do I combine second and third solution so all labels are outside of the bars and visible?


Solution

  • A conditional hjust might help. Note that hjust = "inward/outward" means "relative to the centre of the plot" - see Hadley's comment in this discussion

    scale expansion = this is manual labour. For a programmatic approach, you would need to access the geom_text dimensions, which seems very difficult - see this unanswered question

    library(ggplot2)
    data <- data.frame(vars = c("pos1", "neg1", "pos2", "neg2", "pos3", "pos4"), 
                       values = c(164182, -72705, 1023777, -75002, 756206, 564523),
                       sign = c("p", "n", "p", "n", "p", "p"))
    ggplot(data, aes(x = values, y = vars, fill = sign)) + geom_col() + 
      geom_text(aes(label = values),
                hjust = ifelse(data$values>0,0,1))+
      scale_x_continuous(expand = c(.3,0))
    

    Created on 2021-03-07 by the reprex package (v1.0.0)