user31888 user31888 - 26 days ago 11
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

coord_flip()
.
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
ifelse
statement I am using (see brown bar in figure A below).
In this case I cannot just use a constant
COUNT>1000
condition for all the datasets.

Figure A:

enter image description here

I could modify manually the value of the
hjust=ifelse(COUNT>1000,...
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
ifelse
condition for each dataset, like in figure B below.

Figure B :

enter image description here

EDIT

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

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) +
  guides(fill=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))) + 
  guides(fill=FALSE)

enter image description here

Comments