Consider the following data.frame
and chart:
library(ggplot2)
library(scales)
df <- data.frame(L=rep(LETTERS[1:2],each=4),
l=rep(letters[1:4],2),
val=c(96.5,1,2,0.5,48,0.7,0.3,51))
# L l val
# 1 A a 96.5
# 2 A b 1.0
# 3 A c 2.0
# 4 A d 0.5
# 5 B a 48.0
# 6 B b 0.7
# 7 B c 0.3
# 8 B d 51.0
ggplot(df,aes(x=L,y=val,fill=l)) +
geom_bar(stat="identity") +
geom_text(aes(label=percent(val/100)),position=position_stack(vjust =0.5))
Some labels are hard to read due to small values. I'd like to jitter those vertically. I'm aware of position_jitter
but it doesn't seem compatible with a stacked bar chart.
I found 2 solutions that involve computing the base position of labels beforehand, one using
position_jitter
and one usingggrepel
(suggested by user @gfgm in deleted answer)create positions:
Note that I need to put
NAs
first here so I used: How to have NA's displayed first using arrange()position_jitter
solutionggrepel
solutioncomparison of both
ggrepel
solution doesn't require manual calibration, the output isn't perfect but it's consistent, it also has great flexibility though and would be the solution of choice for most variants of my issue. Note thatgeom_text_repel
has aseed
parameter, but in my case it doesn't affect the results.position_jitter
doesn't give consistent result, positions are randomized, and for most cases it's a less good solution as text overlays (I think it's jittering as if we were dealing with points). For a given chart though it can give a better solution thanggrepel
usingset.seed
beforehand, so maybe better for some reporting, worse the rest of the time.If
geom_text_repel
supportedposition_stack
I wouldn't have to go through the pain of the first step, but it doesn't unfortunately.Both solutions have the slightly annoying effect of jittering isolated labels that shouldn't be jittered at all (this issue is handled by @erocoar's solution).
We can create a new
Position
,position_jitter_stack()
.And plot it ...
Alternatively, we could write a very simple repel function.
Plot it: