When plotting a bar chart, I often add labels to bars to signify the y-value for each bar. However, I run into trouble when the bar becomes too low, making the label unreadable or simply ugly.
Example
library(ggplot2)
df_blood <- data.frame(blood_type = c("O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"),
frequency = c(0.13, 0.35, 0.08, 0.3, 0.02, 0.08, 0.01, 0.02))
ggplot(df_blood, aes(x = blood_type, y = frequency, fill = blood_type)) +
geom_bar(stat = "identity") +
geom_text(aes(label = frequency), color = "blue", vjust = 1, size = 7)
Created on 2021-01-25 by the reprex package (v0.3.0)
Looking at the bar of AB-
we can see that the 0.01
text is exceeding the bar height (at the bar's bottom). In such cases, I'd like to change the vjust
of geom_text()
to 0
.
Another Example with different y scale
Here I'm using the same size = 7
as above for geom_text()
:
library(ggplot2)
df_something <- data.frame(something = c("a", "b", "c"),
quantity = c(10000, 7800, 500))
ggplot(df_something, aes(x = something, y = quantity)) +
geom_bar(stat = "identity", fill = "black") +
geom_text(aes(label = quantity), color = "red", vjust = 1, size = 7)
Created on 2021-01-25 by the reprex package (v0.3.0)
Here we see that the bar for c
has the 500
text exceeding the bottom of the bar. So in such case, I'd also like to change geom_text()
's vjust
to 0
, for bar c
only.
To sum up
Although there are solutions to change vjust
conditionally with a simple ifelse
(see this SO solution) based on the y-value, I'm trying to figure out how to condition vjust
such that it would work regardless of the values on the y scale. Rather, the rule should be that if the bar's height is lower than size of geom_text()
, the text position will move to be on top. Thanks!
EDIT
Based on the discussion below with @Paul, I wonder whether it could be easier to condition vjust
on whether geom_text()
position overlies y = 0
, and if it does, change vjust
to 0
.
EDIT 2
This SO solution (credit to @Paul for finding) seems close enough to what I'm asking. It dynamically changes the size
of geom_text()
to fit bar width, and is working even when resizing the plot. So I think this provides basis to what I'm after, just instead of tweaking size
I need to tweak vjust
, and instead of conditioning it on bar width I need to condition it on bar height. Unfortunately it is too complex for my understanding of ggproto
and alike, so I don't know how to adapt it to my case.
size
value intoy
axis value? Then it might be possible to achieve your goal withvjust = ifelse()
insideaes()
– Trictracsize
of text is measured in mm." Then, the text will remain of the same size even if you change the "final" size of your plot. Then I think we need to know the final size of your plot to find a solution. Is it an explicit style requirement or you can set it as you like? – Trictracvjust
not on thesize
ofgeom_text()
but on whethergeom_text()
overliesy = 0
? I think this will achieve the same desired output., just by a different (and perhaps more attainable) condition – Amendatory