user31888 user31888 - 1 year ago 114
R Question

ggplot2 bar plot: hjust depending on bar and label size

Being new to R, I produced very simple horizontal bar plots using ggplot2 and

Notably, I insert the values of the x variable at the left side of the bar by default (or at the right side if the label does not fit) using the following command:

geom_text(aes(x=TYPE, y=COUNT, ymax=COUNT, label=COUNT,
hjust=ifelse(COUNT>1000, 1.5, -0.3)),
size=3.5, position = position_dodge(width=0.8))

The problem is that, depending on the data-sets, the x values can vary significantly (e.g. dataset_1 x values can be between 1 to 200; dataset_2 x values can be between 10,000 to 100,000; ...), which causes the label of the shortest bar to be misplaced with the
statement I am using (see brown bar in figure A below).
In this case I cannot just use a constant
condition for all the datasets.

Figure A:

enter image description here

I could modify manually the value of the
statement for each dataset.
But I was wondering if it is possible to automatically move the label outs of the bar if it does not fit between the axis and the top of the bar without modifying the value of the
condition for each dataset, like in figure B below.

Figure B :

enter image description here


Workaround (not perfect but better):
Placing the label at the right of the bar if the value is less than 5% of the maximum value

MAXI <- max(data[,2])
geom_text(aes(x=TYPE, y=COUNT, ymax=COUNT, label=COUNT,
hjust=ifelse((COUNT/MAXI)<0.05, -0.3, 1.3)))

Answer Source

Having some labels outside the bars and some inside can distort the visual encoding of magnitude as the length of the bar. Another option is to put the values in the middle of the bar but set geom_text to skip values that are small relative to the maximum bar. Or, if you want to include text for all the bar values added, you can put them below the bars in order to keep a clean visual pattern for the bar lengths. Examples of both options are below:

# Fake data
dat = data.frame(x = LETTERS[1:5], y=c(432, 1349, 10819, 5489, 12123))

ggplot(dat, aes(x, y, fill=x)) + 
  geom_bar(stat="identity") +
  geom_text(aes(label=ifelse(y < 0.05*max(dat$y), "", format(y, big.mark=",")), y=0.5*y),
            colour="white") +
  coord_flip(xlim=c(0.4,5.6), ylim=c(0, 1.03*max(dat$y)), expand=FALSE) +

ggplot(dat, aes(x, y, fill=x)) + 
  geom_hline(yintercept=0, lwd=0.3, colour="grey40") + 
  geom_bar(stat="identity") +
  geom_text(aes(label=format(y, big.mark=","), y=-0.01*max(dat$y)), 
            size=3.5, hjust=1) +
  coord_flip(ylim = c(-0.04*max(dat$y), max(dat$y))) + 

enter image description here

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download