Reputation: 7948
I would like to add some more annotations to this graph i generated in my previous question.
set.seed(40816)
library(ggplot2)
library(grid)
df.plot <- data.frame(x = rnorm(100, 0, 1))
strainerGrob <- function(pos=unit(4,"mm"), gp=gpar(lty=2, lwd=2))
segmentsGrob(0, unit(1,"npc") - pos, 1, unit(1,"npc") - pos, gp=gp)
ggplot(df.plot, aes(x = x)) + geom_density() +
annotation_custom(strainerGrob(), xmin = -1, xmax = 1, ymin=-Inf, ymax=0)
I would like to add -1
to the left of the segment, 1
to the right, a dot at 0
and 0 above the dot. All this while not having to use absolute distance for y
. Is this possible? Right now I can do it hard coding y
ggplot(df.plot, aes(x = x)) + geom_density() +
annotation_custom(strainerGrob(), xmin = -1, xmax = 1, ymin=-Inf, ymax=0) +
geom_point(aes(x=0, y=-0.01)) +
annotate("text", x = -1, y = -0.01, label = -1, hjust = 1.5) +
annotate("text", x = 1, y = -0.01, label = 1, hjust = -1) +
annotate("text", x = 0, y = 0, label = 0, vjust = 2.75)
But if I change the data the point and other annotations end up in the wrong place.
df.plot <- data.frame(x = rnorm(100, 0, 4))
ggplot(df.plot, aes(x = x)) + geom_density() +
annotation_custom(strainerGrob(), xmin = -1, xmax = 1, ymin=-Inf, ymax=0) +
geom_point(aes(x=0, y=-0.01)) +
annotate("text", x = -1, y = -0.01, label = -1, hjust = 1.5) +
annotate("text", x = 1, y = -0.01, label = 1, hjust = -1) +
annotate("text", x = 0, y = 0, label = 0, vjust = 2.75)
Upvotes: 0
Views: 613
Reputation: 77116
the grob can be a gTree with multiple children, e.g
set.seed(40816)
library(ggplot2)
df.plot <- data.frame(x = rnorm(100, 0, 1))
strainerGrob <- function(range = c(-1,2), midpoint=0.35,
vpos=unit(5,"mm"),
pad = unit(1.5,"mm"),
gp=gpar(lty=2, lwd=2)){
labels <- as.character(c(range[1], midpoint, range[2]))
xpos <- c(0, scales::rescale(midpoint, from=range, to=c(0,1)), 1)
sg <- segmentsGrob(0, unit(1,"npc") - vpos, 1, unit(1,"npc") - vpos, gp=gp)
tg <- textGrob(labels, x = unit(xpos, "npc") + c(-1,0,1)*pad,
hjust = c(1,0.5,0),
vjust=c(0.5,0,0.5), y=unit(1,"npc") - vpos + c(0,1,0)*pad)
pg <- pointsGrob(x=xpos[2], y=unit(1,"npc") - vpos, pch = 19, gp = gpar(cex=0.5))
grobTree(sg, pg, tg)
}
# wrapper to ensure that both geom and grob are in sync with x values
custom_range <- function(range = c(-1,2), midpoint=0.35, ...){
sg <- strainerGrob(range=range, midpoint=midpoint, ...)
annotation_custom(sg, xmin = range[1], xmax = range[2], ymin=-Inf, ymax=0)
}
ggplot(df.plot, aes(x = x)) + geom_density() +
custom_range(c(-1, 2), 0.35) +
expand_limits(y=-0.1)
If it's something you're going to use in a variety of graphs, e.g. with facets, or at multiple locations, I would recommend you write a custom geom instead. For a one-off, annotation_custom is probably OK.
Upvotes: 1