I am trying to create a horizontal bar chart with category labels using ggplot.
I have been able to create the plot without hassles, and can put labels on, however I suffer issues with the formatting. Ultimately I would like to have my label within the bar if it fits, otherwise just outside the bar without truncating the label.
The following are what I have tried so far.
Data
dt1 <- data.table(x=c("a","b","c","d","e"), y=c(43,52,296,102,157), y2=c(50,10,100,45,80))
Chart 1
ggplot() + geom_bar(data=dt1, aes(x=x, y=y), stat="identity",fill="red") + coord_flip() +
geom_text(data=dt1, aes(x=x, y=y, label=paste0("$",y," from ",y2," records")),hjust=0)
As you can see below the labels get truncated.
Chart 2
I then came across this question which was helpful and made me realise that I was setting the label position based on my y variable so I have hardcoded it now and use hjust to pad it from the axis.
ggplot() + geom_bar(data=dt1, aes(x=x, y=y), stat="identity",fill="red") + coord_flip() +
geom_text(data=dt1, aes(x=x, y=0, label=paste0("$",y," from ",y2," records")),hjust=-0.1)
But you can see below that only 2 of the labels fit within the bar, so I would prefer the others to be placed at the end, on the outside of the bar like in chart 1.
Is there a programatic way I can get the best of both worlds from chart 1 and chart 2?
Move the hjust
into the aes
so we may vary off the value, then move it if the bar is a certain way past the max. It’s a bit hacky still, since it makes assumptions about the scaling, but looks pretty good. Divisor may need tweaking:
library(tidyverse)
dt1 <- data.frame(x=c("a","b","c","d","e"), y=c(43,52,296,102,157), y2=c(50,10,100,45,80))
ggplot() +
geom_bar(data=dt1, aes(x=x, y=y), stat="identity",fill="red") +
coord_flip() +
geom_text(
data=dt1,
aes(
x=x, y=y,
label=paste0("$",y," from ",y2," records"),
hjust=ifelse(y < max(dt1$y) / 1.5, -0.1, 1.1), # <- Here lies the magic
),
)
Results in this plot: