Automatically adjust x axis text to just above or just below y=0 depending on whether bar is positive or negative

55 Views Asked by At

waterfall

What line of code can I add to this plot so that the x-axis labels appear just below height y=0 if the bars are positive, and just above y=0 if the bars are negative?

I have another plot that I need to produce that will only have 4 bars (different x-axis labels) and I'd like the code to work for that one as well, i.e. not specific to the labels in this plot, so that I can facet them.

I'm thinking it would be great if there was something like if y >0 then x-axis label at y=-1 else x-axis label at y=1...

2

There are 2 best solutions below

0
r2evans On BEST ANSWER

Just add a new y value for the text that is based on the sign of the real y value of the bar.

library(ggplot2)
# original data
data.frame(x=1:5, y=c(20,10,2,-4,-9), lbl=letters[1:5]) |>
  # add a new `y` that is based on the sign of the real data
  transform(label_y = 2 * -sign(y)) |>
  ggplot(aes(x, y)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = label_y, label = lbl))

enter image description here

The use of 2* is up to your real values, feel free to play with that.

As an alternative, in case you want the on-top/below values to be asymmetric, you can replace 2*sign(y) with ifelse(y < 0, 3, -2).

0
L Tyrone On

One way is to use two annotate(), one for positive and one for negative:

library(ggplot2)

df <- data.frame(x = 1:6,
                 y = c(21, 12, 1, -10, -12, -22))

ggplot(df, aes(x = x, y = y)) +
  geom_col() +
  annotate("text", 
           x = df[df$y >= 0,1], 
           y = 0,
           label = df[df$y >= 0,1],
           hjust = 0.5,
           vjust = 1.2,
           colour = "black",
           size = 4) +
  annotate("text", 
           x = df[df$y < 0,1], 
           y = 0,
           label = df[df$y < 0,1],
           hjust = 0.5,
           vjust = -0.2,
           colour = "black",
           size = 4) +
  theme(axis.title = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank())

result