I need to annotate my plots in a certain way. Following the answer here, I could come up with this,
df = data.frame(y= rep(c(1:20, 1:10), 5), x=c(rep("A", 20), rep("B", 10), rep("C", 20), rep("D", 10), rep("E", 20),
rep("F", 10), rep("G", 20), rep("H", 10), rep("I", 20), rep("J", 10)),
g= c(rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10)))
p <- ggplot(df, aes(factor(x), y)) + geom_boxplot()+ # Base plot
theme(plot.margin = unit(c(3,1,1,1), "lines"), plot.background= element_rect(color= "transparent")) # Make room for the grob
for (i in 1:length(df$g)) {
p <- p + annotation_custom(
grob = textGrob(label = df$g[i], hjust = 0, gp = gpar(cex = 1.5)),
xmin = df$x[i], # Vertical position of the textGrob
xmax = df$x[i],
ymin = 22, # Note: The grobs are positioned outside the plot area
ymax = 22)
}
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)
This generates this plot
.
I want blue triangles with size 0.6 pt instead of 2 in annotation and blue "+" signs instead of 1. Can you please help me out here?
You would have to use pointsGrob instead of the textGrob function. The line you would need to add points instead of text labels would be following.
pointsGrob(pch = ifelse(df$g[i]==1,3,17), gp = gpar(cex = 0.6,col=ifelse(df$g[i]==1,"red","blue")))
Here I'm using 3 for + point and 17 for $\triangle$ shape. The entire code is shown below
df = data.frame(y= rep(c(1:20, 1:10), 5), x=c(rep("A", 20), rep("B", 10), rep("C", 20), rep("D", 10), rep("E", 20),
rep("F", 10), rep("G", 20), rep("H", 10), rep("I", 20), rep("J", 10)),
g= c(rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10)))
p <- ggplot(df, aes(factor(x), y)) + geom_boxplot()+ # Base plot
theme(plot.margin = unit(c(3,1,1,1), "lines"), plot.background= element_rect(color= "transparent")) # Make room for the grob
for (i in 1:length(df$g)) {
p <- p + annotation_custom(
grob = pointsGrob(pch = ifelse(df$g[i]==1,3,17), gp = gpar(cex = 0.6,col=ifelse(df$g[i]==1,"red","blue"))),
xmin = df$x[i], # Vertical position of the textGrob
xmax = df$x[i],
ymin = 22, # Note: The grobs are positioned outside the plot area
ymax = 22)
}
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)
And the plot generated is shown below

I hope this helps.
Turning clipping off should really be a last resort, since it can have unwanted side-effects for other layers. Here it may be easier to add a row to the gtable and place a grob at the required position.
p <- ggplot(df, aes(factor(x), y)) +
geom_boxplot() + ggtitle("this plot has a title")
library(grid)
library(gtable)
gb <- ggplot_build(p)
# get the axis positions
xpos <- gb$panel$ranges[[1]][["x.major"]]
g <- ggplot_gtable(gb)
g <- gtable_add_rows(g, unit(1,"line"), 2)
gl <- pointsGrob(xpos, rep(0.5, length(xpos)), pch=seq_along(xpos),
default.units = "npc")
g <- gtable_add_grob(g, gl, t=3, l=4)
grid.draw(g)

If a more complex grob was needed, or simply to ensure a consistent mapping between annotations and plot, one could place a ggplot plot panel in the same fashion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With