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.
 
    

 
     
    


 
    
